Add checklist switching and contextual memo ticker
All checks were successful
Deploy Sokko G / deploy (push) Successful in 19s

This commit is contained in:
Shinuwa 2026-09-28 09:40:29 +02:00
parent 273bc5d528
commit bd4059c9c1
16 changed files with 231 additions and 28 deletions

View file

@ -0,0 +1,33 @@
// Rôle : affiche en bas de page les mémos actifs de la toolbox courante ou liée au jeu.
import { useMemo } from "react";
import { moduleStorageKey, normalizeMemosData } from "./storage/toolboxStorage.js";
import { MemosTicker } from "./modules/MemosTicker.jsx";
function getRouteToolboxId(route, links) {
const toolboxMatch = route.match(/^\/toolbox\/([^/]+)/);
if (toolboxMatch) return decodeURIComponent(toolboxMatch[1]);
const gameMatch = route.match(/^\/games\/([^/]+)/);
return gameMatch ? links[gameMatch[1]] || "" : "";
}
export function GlobalMemosTicker({ route, toolboxes, links, moduleData, textContent }) {
const items = useMemo(() => {
const toolboxId = getRouteToolboxId(route, links);
const toolbox = toolboxes.find((item) => item.id === toolboxId);
if (!toolbox) return [];
return toolbox.modules
.filter((module) => module.type === "memos")
.flatMap((module) => {
const data = normalizeMemosData(moduleData[moduleStorageKey(toolbox.id, module.id)]);
if (!data.tickerEnabled) return [];
return data.items.map((memo) => ({ ...memo, id: `${module.id}:${memo.id}` }));
});
}, [route, toolboxes, links, moduleData]);
if (!items.length) return null;
return (
<aside className="global-memos-ticker" aria-label={textContent?.tickerLabel || "Mémos"}>
<MemosTicker items={items} label={textContent?.tickerLabel || "Mémos"} />
</aside>
);
}

View file

@ -4,6 +4,7 @@ import { Icon } from "../../../components/Icon.jsx";
import { moveItem, useGroupedReorder } from "../../../hooks/useGroupedReorder.js";
import { useMemo } from "react";
import { MemoTextEditor } from "./MemoTextEditor.jsx";
import { MemosTicker } from "./MemosTicker.jsx";
import { TextExchangeActions } from "./TextExchangeActions.jsx";
import { TEXT_COLORS } from "./notepadUtils.js";
@ -92,21 +93,12 @@ export function MemosModule({ toolboxId, moduleId, context, editing, textExchang
type="button"
onClick={() => save({ ...data, tickerEnabled: !data.tickerEnabled })}
aria-pressed={data.tickerEnabled}
aria-label={data.tickerEnabled ? textContent.hideTickerTitle || "Masquer la bande" : textContent.showTickerTitle || "Afficher la bande"}
title={data.tickerEnabled ? textContent.hideTickerTitle || "Masquer la bande" : textContent.showTickerTitle || "Afficher la bande"}
>
<Icon name={data.tickerEnabled ? "eye-open" : "eye-closed"} />
</button>
{tickerItems.length > 0 && (
<div className="memos-ticker" aria-label={textContent.tickerLabel || "Mémos"}>
<div className="memos-ticker-track">
{[...tickerItems, ...tickerItems].map((memo, index) => (
<span className="memos-ticker-item" key={`${memo.id}-${index}`} style={{ "--memo-color": memo.color }}>
{memo.text}
</span>
))}
</div>
</div>
)}
<MemosTicker items={tickerItems} label={textContent.tickerLabel || "Mémos"} />
</div>
<div className="memos-list">

View file

@ -0,0 +1,15 @@
// Rôle : affiche la bande déroulante partagée par l'outil Mémos et les pages associées.
export function MemosTicker({ items, label = "Mémos", className = "" }) {
if (!items?.length) return null;
return (
<div className={["memos-ticker", className].filter(Boolean).join(" ")} aria-label={label}>
<div className="memos-ticker-track">
{[...items, ...items].map((memo, index) => (
<span className="memos-ticker-item" key={`${memo.id}-${index}`} style={{ "--memo-color": memo.color }}>
{memo.text}
</span>
))}
</div>
</div>
);
}