This commit is contained in:
parent
11fa3d1558
commit
ad01868a9f
23 changed files with 328 additions and 97 deletions
|
|
@ -90,12 +90,12 @@
|
|||
tabindex="0" @click="onRowClicked(result[0])" @keypress="onRowClicked(result[0])"
|
||||
>
|
||||
<th class="name" scope="row">
|
||||
{{ result[1].original_result_index }}
|
||||
{{ result[1].originalResultIndex }}
|
||||
</th>
|
||||
<th class="name" scope="row">
|
||||
{{ result[1].original_title }}
|
||||
{{ result[1].originalTitle }}
|
||||
</th>
|
||||
<td class="release-date">{{ result[1].release_date }}</td>
|
||||
<td class="release-date">{{ result[1].releaseDate }}</td>
|
||||
<td class="popularite">{{ result[1].popularity }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -1,37 +1,62 @@
|
|||
<script setup lang="ts">
|
||||
import type { MergedTmdbLocalData } from "@/libs/search/schemas";
|
||||
import type { ComputedRef, Ref, ShallowRef } from "vue";
|
||||
|
||||
import ImposterBox from "@/components/dialogs/ImposterBox.vue";
|
||||
import { Images } from "@/services/images.ts";
|
||||
import { RuntimeClient } from "@/services/runtime-client";
|
||||
import { Url } from "@effect/platform";
|
||||
import { Effect } from "effect";
|
||||
import { onMounted } from "vue";
|
||||
import { ref } from "vue";
|
||||
import { watchEffect } from "vue";
|
||||
import { useTemplateRef } from "vue";
|
||||
import { Effect, pipe } from "effect";
|
||||
import { isTruthy } from "effect/Predicate";
|
||||
import { onMounted, ref, useTemplateRef, watch } from "vue";
|
||||
import { computed } from "vue";
|
||||
|
||||
// Émissions et props
|
||||
const emit = defineEmits(["dialog-hidden"]);
|
||||
const { entryData } = defineProps<{ entryData: MergedTmdbLocalData }>();
|
||||
|
||||
const ditheredPoster = ref<HTMLCanvasElement>();
|
||||
const imageContainer = useTemplateRef("imageContainer");
|
||||
const imageContainer: Readonly<ShallowRef<HTMLDivElement | null>> = useTemplateRef("imageContainer");
|
||||
const ditheredPoster: Ref<HTMLCanvasElement | undefined> = ref<HTMLCanvasElement>();
|
||||
const isFirstTimeEntryEditing: Ref<boolean> = ref<boolean>(false);
|
||||
|
||||
const closeDialog = () => {
|
||||
const hasEntry: ComputedRef<boolean> = computed(() => isTruthy(entryData.entryId));
|
||||
const hasUniqueOriginalTitle: ComputedRef<boolean> = computed(() =>
|
||||
entryData.originalTitle.toLowerCase() !== entryData.title.toLowerCase()
|
||||
);
|
||||
|
||||
const firstTimeEditingButtonText: ComputedRef<"Ajouter" | "Annuler"> = computed(() =>
|
||||
isFirstTimeEntryEditing.value ? "Annuler" : "Ajouter"
|
||||
);
|
||||
|
||||
// Gestionnaires d'événements
|
||||
const closeDialog = (event?: Event): void => {
|
||||
event?.preventDefault();
|
||||
emit("dialog-hidden");
|
||||
};
|
||||
const toggleFirstTimeEditing = (event?: Event): void => {
|
||||
event?.preventDefault();
|
||||
isFirstTimeEntryEditing.value = !isFirstTimeEntryEditing.value;
|
||||
};
|
||||
|
||||
watchEffect(async () => {
|
||||
// Cycles
|
||||
watch(() => entryData, async (): Promise<void> => {
|
||||
ditheredPoster.value = await RuntimeClient.runPromise(Effect.gen(function*() {
|
||||
if (!entryData.artWorkCoverPath || !imageContainer.value) return undefined;
|
||||
const imageService: Images = yield* Images;
|
||||
const originalUrl = yield* Url.fromString(`https://image.tmdb.org/t/p/w500/${entryData.artWorkCoverPath}`);
|
||||
const originalImage = yield* imageService.imageFromUrl(originalUrl);
|
||||
const ditheredImage = yield* imageService.ditherImage(originalImage, imageContainer.value);
|
||||
if (!entryData.posterUrl) return undefined;
|
||||
console.debug("dithering");
|
||||
|
||||
return ditheredImage;
|
||||
const imageService: Images = yield* Images;
|
||||
|
||||
return yield* pipe(
|
||||
Url.fromString(`https://image.tmdb.org/t/p/w500/${entryData.posterUrl}`),
|
||||
Effect.andThen((url: URL) => imageService.imageFromUrl(url)),
|
||||
Effect.andThen((img: HTMLImageElement) => imageService.ditherImage(img, imageContainer.value ?? undefined)),
|
||||
Effect.andThen(dithered => dithered.canvas),
|
||||
);
|
||||
|
||||
// const base64 = encodeBase64Url(ditheredImage.buffer.data);
|
||||
// console.debug(base64.length);
|
||||
}));
|
||||
});
|
||||
}, { immediate: true });
|
||||
|
||||
onMounted(() => {
|
||||
console.debug("EditEntryDialog mounted");
|
||||
|
|
@ -43,13 +68,47 @@
|
|||
<template #title>Éditer une entrée</template>
|
||||
|
||||
<template #content>
|
||||
<section aria-labelledby="media-title" class="switcher">
|
||||
<section aria-labelledby="media-title" class="switcher container">
|
||||
<div ref="imageContainer" class="canvas-container"> </div>
|
||||
|
||||
<div class="stack">
|
||||
<h3 id="media-title">{{ entryData.original_title }}</h3>
|
||||
<p class="center">{{ entryData.release_date }} | {{ entryData.original_language }} </p>
|
||||
<h3 id="media-title">{{ entryData.originalTitle }}</h3>
|
||||
<p class="original-metadata">
|
||||
<span v-if="hasUniqueOriginalTitle">{{ entryData.title }} | </span>
|
||||
{{ entryData.releaseDate }} | {{ entryData.originalLanguage }} | {{ entryData.popularity }}
|
||||
</p>
|
||||
|
||||
<p class="overview">{{ entryData.overview }}</p>
|
||||
|
||||
<h3>Journal</h3>
|
||||
<div class="cluster entry-state">
|
||||
<p>
|
||||
<strong>État : </strong>
|
||||
<span v-if="hasEntry"></span>
|
||||
<span v-else>Pas encore dans le journal.</span>
|
||||
</p>
|
||||
|
||||
<button v-if="!hasEntry" :class="{ invert: isFirstTimeEntryEditing }" @click="toggleFirstTimeEditing">
|
||||
{{ firstTimeEditingButtonText }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form v-if="hasEntry || isFirstTimeEntryEditing" class="cluster entry-metadata">
|
||||
<div class="field stack">
|
||||
<label for="date-created">Date de création</label>
|
||||
<input id="date-created" type="datetime-local">
|
||||
</div>
|
||||
|
||||
<div class="field stack">
|
||||
<label for="date-created">Date de modification</label>
|
||||
<input id="date-created" type="datetime-local">
|
||||
</div>
|
||||
|
||||
<div class="field stack">
|
||||
<label for="date-created">Date d'obtention</label>
|
||||
<input id="date-created" type="datetime-local">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
|
@ -72,7 +131,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
inline-size: 85vi;
|
||||
max-inline-size: 74rem;
|
||||
}
|
||||
|
||||
.overview {
|
||||
max-inline-size: 40rem;
|
||||
}
|
||||
|
||||
.entry-metadata {
|
||||
--layout-cluster-gap: var(--s0);
|
||||
margin-block-start: var(--s2);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
4
src/components/loading/LoadingBox.vue
Normal file
4
src/components/loading/LoadingBox.vue
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<script lang="ts">
|
||||
</script>
|
||||
|
||||
<template></template>
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
CREATE TABLE `diary_entries` (
|
||||
`appreciation` text NOT NULL,
|
||||
`art_work_id` integer NOT NULL,
|
||||
`commentary` text,
|
||||
`date_created` integer NOT NULL,
|
||||
`date_modified` integer NOT NULL,
|
||||
`date_obtained` integer NOT NULL,
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`state_id` integer NOT NULL,
|
||||
FOREIGN KEY (`art_work_id`) REFERENCES `art_works`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
|
|
@ -59,4 +62,10 @@ CREATE TABLE `media_types` (
|
|||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `media_types_name_unique` ON `media_types` (`name`);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `media_types_slug_unique` ON `media_types` (`slug`);
|
||||
CREATE UNIQUE INDEX `media_types_slug_unique` ON `media_types` (`slug`);--> statement-breakpoint
|
||||
CREATE TABLE `posters` (
|
||||
`art_work_id` integer NOT NULL,
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`image` blob NOT NULL,
|
||||
FOREIGN KEY (`art_work_id`) REFERENCES `art_works`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
|
|
@ -1,12 +1,19 @@
|
|||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "8b217318-7662-4f81-bc55-92d5c6ddf2b2",
|
||||
"id": "01d72a44-6bdd-4f2a-b1dd-34546aa1b734",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"tables": {
|
||||
"diary_entries": {
|
||||
"name": "diary_entries",
|
||||
"columns": {
|
||||
"appreciation": {
|
||||
"name": "appreciation",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"art_work_id": {
|
||||
"name": "art_work_id",
|
||||
"type": "integer",
|
||||
|
|
@ -14,6 +21,13 @@
|
|||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"commentary": {
|
||||
"name": "commentary",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"date_created": {
|
||||
"name": "date_created",
|
||||
"type": "integer",
|
||||
|
|
@ -28,6 +42,13 @@
|
|||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"date_obtained": {
|
||||
"name": "date_obtained",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
|
|
@ -404,6 +425,51 @@
|
|||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"posters": {
|
||||
"name": "posters",
|
||||
"columns": {
|
||||
"art_work_id": {
|
||||
"name": "art_work_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"image": {
|
||||
"name": "image",
|
||||
"type": "blob",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"posters_art_work_id_art_works_id_fk": {
|
||||
"name": "posters_art_work_id_art_works_id_fk",
|
||||
"tableFrom": "posters",
|
||||
"tableTo": "art_works",
|
||||
"columnsFrom": [
|
||||
"art_work_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
{
|
||||
"idx": 0,
|
||||
"version": "6",
|
||||
"when": 1740814587298,
|
||||
"tag": "0000_unusual_karen_page",
|
||||
"when": 1741093519331,
|
||||
"tag": "0000_goofy_vanisher",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -20,3 +20,14 @@ export const DIARY_ENTRY_STATES = {
|
|||
/** Un média ayant été regardé au mois une fois. */
|
||||
WATCHED: "watched",
|
||||
} as const;
|
||||
|
||||
export const APPRECIATION_STATES = {
|
||||
/** Oeuvre appréciée. */
|
||||
APPRECIATED: "appreciated",
|
||||
/** Oeuvre non appréciée (détestée). */
|
||||
DISLIKED: "disliked",
|
||||
/** Oeuvre laissant de marbre. */
|
||||
NEUTRAL: "neutral",
|
||||
/** Appréciation inconnue. */
|
||||
UNKNOWN: "unknown",
|
||||
} as const;
|
||||
|
|
|
|||
|
|
@ -5,15 +5,18 @@ import * as t from "drizzle-orm/sqlite-core";
|
|||
import { sqliteTable as table } from "drizzle-orm/sqlite-core";
|
||||
import { Schema } from "effect";
|
||||
|
||||
import { DIARY_ENTRY_STATES } from "./constants";
|
||||
import { APPRECIATION_STATES, DIARY_ENTRY_STATES } from "./constants";
|
||||
import { ArtWorks, Genres } from "./works";
|
||||
|
||||
// Tables
|
||||
|
||||
export const DiaryEntries = table("diary_entries", {
|
||||
appreciation: t.text("appreciation").$type<Values<typeof APPRECIATION_STATES>>().notNull(),
|
||||
artWorkId: t.integer("art_work_id").references((): AnySQLiteColumn => ArtWorks.id).notNull(),
|
||||
commentary: t.text("commentary").notNull(),
|
||||
dateCreated: t.integer("date_created", { mode: "timestamp" }).notNull(),
|
||||
dateModified: t.integer("date_modified", { mode: "timestamp" }).notNull(),
|
||||
dateObtained: t.integer("date_obtained", { mode: "timestamp" }).notNull(),
|
||||
id: t.integer("id").primaryKey({ autoIncrement: true }),
|
||||
stateId: t.integer("state_id").references((): AnySQLiteColumn => DiaryEntriesStates.id).notNull(),
|
||||
});
|
||||
|
|
@ -38,9 +41,12 @@ export const Viewings = table("viewings", {
|
|||
// Schémas
|
||||
|
||||
export const DiaryEntrySchema = Schema.Struct({
|
||||
appreciation: Schema.Enums(APPRECIATION_STATES),
|
||||
artWorkId: Schema.NonNegativeInt,
|
||||
commentary: Schema.String.pipe(Schema.optional),
|
||||
dateCreated: Schema.Number,
|
||||
dateModified: Schema.Number,
|
||||
dateObtained: Schema.Number,
|
||||
id: Schema.NonNegativeInt,
|
||||
stateId: Schema.NonNegativeInt,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@ export const MediaTypes = table("media_types", {
|
|||
slug: t.text("slug").$type<Values<typeof MEDIA_TYPES>>().notNull().unique(),
|
||||
});
|
||||
|
||||
export const Posters = table("posters", {
|
||||
artWorkId: t.integer("art_work_id").references((): AnySQLiteColumn => ArtWorks.id).notNull(),
|
||||
id: t.integer("id").primaryKey({ autoIncrement: true }),
|
||||
image: t.blob("image", { mode: "buffer" }).notNull(),
|
||||
});
|
||||
|
||||
export const ArtWorks = table("art_works", {
|
||||
coverPath: t.text("cover_path").unique(),
|
||||
dateCreated: t.integer("date_created", { mode: "timestamp" }).notNull(),
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export const getTmdbSortFunction = (sortData: TmdbSortData) =>
|
|||
|
||||
export const byOriginalIndexAscending = Order.mapInput(
|
||||
Order.number,
|
||||
(data: [number, MergedTmdbLocalData]) => data[1].original_result_index,
|
||||
(data: [number, MergedTmdbLocalData]) => data[1].originalResultIndex,
|
||||
);
|
||||
export const byPopularityAscending = Order.mapInput(
|
||||
Order.number,
|
||||
|
|
@ -55,7 +55,7 @@ export const byPopularityAscending = Order.mapInput(
|
|||
);
|
||||
export const byReleaseDateAscending = Order.mapInput(
|
||||
Order.string,
|
||||
(data: [number, MergedTmdbLocalData]) => data[1].release_date,
|
||||
(data: [number, MergedTmdbLocalData]) => data[1].releaseDate,
|
||||
);
|
||||
export const byTitleAscending = Order.mapInput(
|
||||
Order.string,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { MEDIA_TYPES } from "@/db/schemas/constants";
|
||||
import { APPRECIATION_STATES, MEDIA_TYPES } from "@/db/schemas/constants";
|
||||
import { Schema } from "effect";
|
||||
|
||||
export class SearchPageQueryParams extends Schema.Class<SearchPageQueryParams>("SearchPageQueryParams")({
|
||||
|
|
@ -8,20 +8,24 @@ export class SearchPageQueryParams extends Schema.Class<SearchPageQueryParams>("
|
|||
}) {}
|
||||
|
||||
export class MergedTmdbLocalData extends Schema.Class<MergedTmdbLocalData>("MergedTmdbLocalData")({
|
||||
artWorkCoverPath: Schema.Union(Schema.String, Schema.Null),
|
||||
artWorkId: Schema.NonNegativeInt.pipe(Schema.optional),
|
||||
artWorkMediumTypeId: Schema.NonNegativeInt.pipe(Schema.optional),
|
||||
entryAppreciation: Schema.Enums(APPRECIATION_STATES).pipe(Schema.optional),
|
||||
entryCommentary: Schema.String.pipe(Schema.optional),
|
||||
entryDateCreated: Schema.Date.pipe(Schema.optional),
|
||||
entryDateModified: Schema.Date.pipe(Schema.optional),
|
||||
entryDateObtained: Schema.Date.pipe(Schema.optional),
|
||||
entryId: Schema.NonNegativeInt.pipe(Schema.optional),
|
||||
entryStateId: Schema.NonNegativeInt.pipe(Schema.optional),
|
||||
genre_ids: Schema.Array(Schema.NonNegativeInt),
|
||||
original_language: Schema.String,
|
||||
original_result_index: Schema.Int,
|
||||
original_title: Schema.String,
|
||||
genreIds: Schema.Array(Schema.NonNegativeInt),
|
||||
originalLanguage: Schema.String,
|
||||
originalResultIndex: Schema.Int,
|
||||
originalTitle: Schema.String,
|
||||
overview: Schema.String,
|
||||
popularity: Schema.Number,
|
||||
release_date: Schema.String,
|
||||
posterBlob: Schema.Unknown.pipe(Schema.optional),
|
||||
posterUrl: Schema.Union(Schema.String, Schema.Null),
|
||||
releaseDate: Schema.String,
|
||||
title: Schema.String,
|
||||
tmdbId: Schema.NonNegativeInt,
|
||||
}) {}
|
||||
|
|
|
|||
|
|
@ -153,20 +153,23 @@
|
|||
result.id,
|
||||
yield* Schema.decodeUnknown(MergedTmdbLocalData)(
|
||||
{
|
||||
artWorkCoverPath: result.poster_path,
|
||||
artWorkId: artWork?.id,
|
||||
artWorkMediumTypeId: artWork?.mediumTypeId,
|
||||
entryAppreciation: entry?.appreciation,
|
||||
entryCommentary: entry?.commentary,
|
||||
entryDateCreated: entry?.dateCreated,
|
||||
entryDateModified: entry?.dateModified,
|
||||
entryDateObtained: entry?.dateObtained,
|
||||
entryId: entry?.id,
|
||||
entryStateId: entry?.stateId,
|
||||
genre_ids: result.genre_ids,
|
||||
original_language: result.original_language,
|
||||
original_result_index: index,
|
||||
original_title: result.original_title,
|
||||
genreIds: result.genre_ids,
|
||||
originalLanguage: result.original_language,
|
||||
originalResultIndex: index,
|
||||
originalTitle: result.original_title,
|
||||
overview: result.overview,
|
||||
popularity: result.popularity,
|
||||
release_date: result.release_date,
|
||||
posterUrl: result.poster_path,
|
||||
releaseDate: result.release_date,
|
||||
title: result.title,
|
||||
tmdbId: result.id,
|
||||
} satisfies MergedTmdbLocalData,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,13 @@
|
|||
import { asInt } from "@thi.ng/color-palettes";
|
||||
import { ARGB8888, canvasFromPixelBuffer, defIndexed, imageFromURL, intBufferFromImage } from "@thi.ng/pixel";
|
||||
import {
|
||||
ARGB8888,
|
||||
canvasFromPixelBuffer,
|
||||
defIndexed,
|
||||
imageFromURL,
|
||||
IntBuffer,
|
||||
intBufferFromImage,
|
||||
type IntFormat,
|
||||
} from "@thi.ng/pixel";
|
||||
import { ATKINSON, ditherWith } from "@thi.ng/pixel-dither";
|
||||
import { Data, Effect, pipe } from "effect";
|
||||
|
||||
|
|
@ -10,12 +18,12 @@ export class Images extends Effect.Service<Images>()("Images", {
|
|||
return {
|
||||
ditherImage: (image: HTMLImageElement, parent?: HTMLElement) =>
|
||||
Effect.gen(function*() {
|
||||
const buf = intBufferFromImage(image, ARGB8888).scale(0.8, "cubic");
|
||||
const theme = defIndexed(asInt(["salmon", "black"]));
|
||||
const ditheredBuf = ditherWith(ATKINSON, buf.copy(), {}).as(theme);
|
||||
const buf: IntBuffer = intBufferFromImage(image, ARGB8888).scale(0.8, "cubic");
|
||||
const theme: IntFormat = defIndexed(asInt(["salmon", "black"]));
|
||||
const ditheredBuffer: IntBuffer = ditherWith(ATKINSON, buf.copy(), {}).as(theme);
|
||||
|
||||
const canvas = canvasFromPixelBuffer(ditheredBuf, parent, { pixelated: true });
|
||||
return canvas;
|
||||
const canvas = canvasFromPixelBuffer(ditheredBuffer, parent, { pixelated: true });
|
||||
return { buffer: ditheredBuffer, canvas: canvas };
|
||||
}),
|
||||
imageFromUrl: (url: URL) =>
|
||||
pipe(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { SQLocalDrizzle } from "sqlocal/drizzle";
|
||||
|
||||
import v0000 from "@/db/drizzle/0000_unusual_karen_page.sql?raw";
|
||||
import v0000 from "@/db/drizzle/0000_goofy_vanisher.sql?raw";
|
||||
import { Data, Effect } from "effect";
|
||||
|
||||
import { LocalSqlite } from "./db";
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: var(--brkly-font-weight-semibold);
|
||||
}
|
||||
|
||||
.container {
|
||||
--layout-center-max-width: 100%;
|
||||
--layout-center-inline-padding: var(--s1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue