Add custom toolbox card covers
All checks were successful
Deploy Sokko G / deploy (push) Successful in 18s

This commit is contained in:
Shinuwa 2026-09-05 15:41:56 +02:00
parent 25889a23ba
commit 06de3a3a6e
13 changed files with 7480 additions and 38 deletions

View file

@ -10,6 +10,7 @@ import {
validateSiteContent,
validateTranslationKeys
} from "./helpers/data-validation.mjs";
import { compactModuleDataForStorage, normalizeToolbox } from "../website/src/features/toolboxes/storage/toolboxStorage.js";
test("site content json is complete", async () => {
const site = JSON.parse(await readFile("website/public/data/site.json", "utf8"));
@ -25,6 +26,27 @@ test("library examples are available", async () => {
assert.equal(notepadModule?.title, "Bloc Note");
});
test("library toolbox export is import-compatible", async () => {
const library = JSON.parse(await readFile("website/public/data/library.json", "utf8"));
const payload = JSON.parse(await readFile("website/public/data/library-toolbox-export.json", "utf8"));
const toolbox = normalizeToolbox(payload.toolbox);
const moduleIds = new Set(toolbox.modules.map((module) => module.id));
assert.equal(toolbox.name, "Librairie");
assert.equal(toolbox.modules.length, library.toolbox.modules.length);
assert.deepEqual(toolbox.modules.map((module) => module.type), library.toolbox.modules.map((module) => module.type));
assert.deepEqual(new Set(Object.keys(payload.modules)), moduleIds);
toolbox.modules.forEach((module) => {
const exportedModule = payload.toolbox.modules.find((item) => item.id === module.id);
assert.ok(exportedModule, `module ${module.id} must be declared`);
assert.equal(exportedModule.controls, undefined, `${module.id} must not include library docs controls`);
assert.equal(exportedModule.features, undefined, `${module.id} must not include library docs features`);
assert.equal(exportedModule.importFormat, undefined, `${module.id} must not include library docs import format`);
assert.ok(compactModuleDataForStorage(module.type, payload.modules[module.id]), `${module.id} data must be compactable`);
});
});
test("mhwilds data and assets are available", async () => {
const site = JSON.parse(await readFile("website/public/data/site.json", "utf8"));
const games = JSON.parse(await readFile("website/public/data/games.json", "utf8"));

View file

@ -68,6 +68,7 @@ test("style entrypoint and theme layers are wired", async () => {
"website/src/styles/toolboxes/_layout.scss",
"website/src/styles/toolboxes/layout/_header.scss",
"website/src/styles/toolboxes/layout/_icon-picker.scss",
"website/src/styles/toolboxes/layout/_cover-editor.scss",
"website/src/styles/toolboxes/layout/_tutorial.scss",
"website/src/styles/toolboxes/layout/_add-tools.scss",
"website/src/styles/toolboxes/layout/_preferences.scss",
@ -197,6 +198,13 @@ test("style entrypoint and theme layers are wired", async () => {
assert.match(styleToolboxCalendar, /\.calendar-alert-mode-switch/);
assert.match(styles, /@use "design-system\/attributes"/);
assert.match(styleToolboxLayout, /\.toolbox-icon-picker/);
assert.match(styleToolboxLayout, /border-radius: inherit/);
assert.match(styleToolboxLayout, /\.toolbox-icon-picker-button\.has-custom-cover img/);
assert.match(styleToolboxLayout, /grid-column: 1 \/ -1/);
assert.match(styleToolboxLayout, /@use "layout\/cover-editor"/);
assert.match(styleToolboxLayout, /\.toolbox-cover-editor/);
assert.match(styleToolboxLayout, /\.toolbox-cover-crop-frame/);
assert.match(styleToolboxLayout, /aspect-ratio: 620 \/ 248/);
assert.match(styleToolboxLayout, /\.toolbox-game-icon/);
assert.match(styleToolboxLayout, /\.toolbox-hero-link/);
assert.match(styleToolboxLayout, /\.toolbox-actions-row/);

View file

@ -19,6 +19,7 @@ test("toolbox storage, cards and pages are wired", async () => {
const source = await readFile("website/src/main.jsx", "utf8");
const toolboxCard = await readFile("website/src/features/toolboxes/ToolboxCard.jsx", "utf8");
const toolboxPages = await readFile("website/src/features/toolboxes/ToolboxPages.jsx", "utf8");
const toolboxCoverEditor = await readFile("website/src/features/toolboxes/ToolboxCoverEditor.jsx", "utf8");
const toolboxActions = await readFile("website/src/features/toolboxes/useToolboxActions.js", "utf8");
const toolboxStorage = await readFile("website/src/features/toolboxes/storage/toolboxStorage.js", "utf8");
const storageCompactorRegistry = await readFile("website/src/features/toolboxes/storage/modules/index.js", "utf8");
@ -55,6 +56,9 @@ test("toolbox storage, cards and pages are wired", async () => {
assert.match(`${source}\n${toolboxActions}`, /features\/toolboxes\/storage\/toolboxStorage\.js/);
assert.match(toolboxStorage, /TOOLBOX_ICON_FILES/);
assert.match(toolboxStorage, /export function normalizeToolboxIcon/);
assert.match(toolboxStorage, /export function normalizeToolboxCustomCover/);
assert.match(toolboxStorage, /customCover: normalizeToolboxCustomCover/);
assert.match(toolboxStorage, /compact\.customCover = normalized\.customCover/);
assert.match(toolboxStorage, /export function createGlobalExportPayload/);
assert.match(checklistStorage, /qtyTarget/);
assert.match(checklistStorage, /qtyCurrent/);
@ -84,6 +88,19 @@ test("toolbox storage, cards and pages are wired", async () => {
assert.match(calendarStorage, /normalizeCalendarData/);
assert.match(toolboxStorage, /nextId\("calendar"\)/);
assert.match(toolboxCard, /DEFAULT_TOOLBOX_ICON/);
assert.match(toolboxCard, /toolbox\.customCover/);
assert.match(toolboxCard, /customCoverImage = !gameCoverImage/);
assert.match(toolboxCard, /triggerImage = toolbox\.customCover \|\| icon/);
assert.match(toolboxCard, /has-custom-cover/);
assert.match(toolboxCard, /toolbox-cover-menu-action nds-button/);
assert.match(toolboxCard, /!toolbox\.customCover && path === icon/);
assert.match(toolboxCard, /aria-pressed=\{Boolean\(toolbox\.customCover\)\}/);
assert.match(toolboxCard, /<span>Image personnalisée<\/span>/);
assert.match(toolboxCard, /onChange\(path, ""\)/);
assert.match(toolboxCard, /ToolboxCoverEditor/);
assert.match(toolboxCard, /accept="image\/\*"/);
assert.doesNotMatch(toolboxCard, /Modifier l'image de card/);
assert.doesNotMatch(toolboxCoverEditor, /Supprimer l'image/);
assert.match(toolboxCard, /export function ToolboxCard/);
assert.match(toolboxCard, /export function ToolboxIconPicker/);
assert.match(toolboxCard, /export function ToolboxGameIcon/);
@ -92,6 +109,7 @@ test("toolbox storage, cards and pages are wired", async () => {
assert.match(toolboxCard, /toolbox-card-cover-link/);
assert.match(toolboxCard, /toolbox-icon-cover/);
assert.match(toolboxPages, /\.\/ToolboxCard\.jsx/);
assert.match(toolboxPages, /customCover = toolbox\.customCover/);
assert.match(toolboxPages, /updateToolboxOrder/);
assert.match(toolboxPages, /useGroupedReorder/);
assert.match(toolboxPages, /useInlineEdit/);
@ -141,6 +159,12 @@ test("toolbox storage, cards and pages are wired", async () => {
assert.match(draftFormHook, /getFieldProps/);
assert.match(draftFormHook, /handleSubmit/);
assert.match(draftFormHook, /preventDefault/);
assert.match(toolboxCoverEditor, /createImageBitmap/);
assert.match(toolboxCoverEditor, /image\/webp/);
assert.match(toolboxCoverEditor, /OUTPUT_WIDTH = 620/);
assert.match(toolboxCoverEditor, /OUTPUT_HEIGHT = 248/);
assert.match(toolboxCoverEditor, /getCoverCropSourceRect/);
assert.doesNotMatch(toolboxCoverEditor, /react-easy-crop|react-image-crop/);
});
test("toolbox module registry and modules expose expected behavior", async () => {