design refacto
All checks were successful
Deploy Sokko G / deploy (push) Successful in 6s

This commit is contained in:
Shinuwa 2026-07-22 16:07:10 +02:00
parent b8d1829bc7
commit d359fd0a35
25 changed files with 1340 additions and 1023 deletions

View file

@ -166,6 +166,14 @@ function normalizeToolboxIcon(icon) {
return TOOLBOX_ICON_FILES.includes(file) ? `${TOOLBOX_ICON_BASE}${file}` : DEFAULT_TOOLBOX_ICON;
}
function getGameCardCover(game) {
return game?.images?.cardCover || game?.image || "";
}
function getGameCardBackground(game) {
return game?.cover || "var(--gradient-nebula)";
}
function normalizeToolboxModule(module) {
if (!module || typeof module !== "object" || !module.type) return null;
const title = String(module.title || "").trim();
@ -882,7 +890,7 @@ function Shell({ route, content, games, toolboxes, links, actions, children }) {
<aside className="sidebar">
<a className="brand" href="#/" aria-label={content.brand.homeAriaLabel}>
<span className="brand-mark" aria-hidden="true" />
<span>{content.brand.name}</span>
<span className="brand-name"><span className="brand-name-main">Sokko</span> <span className="brand-name-accent">G</span></span>
</a>
<nav className="nav" aria-label="Navigation principale">
<a className={`nav-item ${route === "/" ? "active" : ""}`} href="#/"><span className="nav-icon nav-icon-home" aria-hidden="true" /><strong>{content.navigation.home}</strong></a>
@ -991,23 +999,21 @@ function ToolboxesPage({ siteContent, toolboxes, getToolboxGame, actions }) {
const content = siteContent.toolboxes;
return (
<div className="toolbox-page">
<section className="page-heading">
<section className="page-hero">
<div>
<p className="eyebrow">{content.eyebrow}</p>
<h1>{content.title}</h1>
<p>{content.summary}</p>
</div>
</section>
<section className="toolbar toolbar-stack">
<p className="toolbox-summary">{content.summary}</p>
<div className="toolbox-actions-row">
<div>
<button className="primary" onClick={() => actions.setCreateModal({})}>{content.newButton}</button>
<ImportButton className="import-button" label={content.importOne} onFile={actions.importToolbox} />
</div>
<div>
<ImportButton className="import-button" label={content.importAll} onFile={actions.importAllToolboxes} />
<button onClick={actions.exportAllToolboxes}>{content.exportAll}</button>
</div>
<section className="toolbar toolbox-actions-row">
<div>
<button className="primary" onClick={() => actions.setCreateModal({})}>{content.newButton}</button>
<ImportButton className="import-button" label={content.importOne} onFile={actions.importToolbox} />
</div>
<div>
<ImportButton className="import-button" label={content.importAll} onFile={actions.importAllToolboxes} />
<button onClick={actions.exportAllToolboxes}>{content.exportAll}</button>
</div>
</section>
<section className="cards">
@ -1039,15 +1045,16 @@ function StorageHelpCard({ help }) {
}
function ToolboxCard({ toolbox, game, actions }) {
const coverImage = game?.image || toolbox.icon || DEFAULT_TOOLBOX_ICON;
const gameCoverImage = getGameCardCover(game);
const coverImage = gameCoverImage || toolbox.icon || DEFAULT_TOOLBOX_ICON;
return (
<article className="card toolbox-card">
<a
className={`card-cover toolbox-card-cover-link ${game?.image ? "toolbox-card-cover" : "toolbox-icon-cover"}`}
className={`card-cover toolbox-card-cover-link ${gameCoverImage ? "toolbox-card-cover" : "toolbox-icon-cover"}`}
href={`#/toolbox/${toolbox.id}`}
aria-label={`Ouvrir ${toolbox.name}`}
title={`Ouvrir ${toolbox.name}`}
style={{ "--game-cover": game?.cover || "var(--gradient-nebula)", background: game?.image ? "" : "var(--gradient-nebula)" }}
style={{ "--game-cover": getGameCardBackground(game), background: gameCoverImage ? "" : "var(--gradient-nebula)" }}
>
<img src={coverImage} alt={game ? game.title : `Icône de ${toolbox.name}`} loading="lazy" />
</a>
@ -1141,15 +1148,17 @@ function ToolboxIconPicker({ toolbox, onChange }) {
}
function ToolboxGameIcon({ game }) {
const gameCoverImage = getGameCardCover(game);
return (
<div className="toolbox-game-icon" title={game.title} aria-label={`Jeu associé : ${game.title}`}>
<img src={game.image} alt="" aria-hidden="true" />
<img src={gameCoverImage} alt="" aria-hidden="true" />
</div>
);
}
function ToolboxView({ toolbox, toolboxGame, embedded, actions, updateToolbox, updateModuleData, addScreenshotFiles }) {
const moduleColumns = Number(toolbox.moduleColumns) === 1 ? 1 : 2;
const toolboxGameCover = getGameCardCover(toolboxGame);
const moduleContext = {
getModuleData,
normalizeChecklistData,
@ -1185,12 +1194,12 @@ function ToolboxView({ toolbox, toolboxGame, embedded, actions, updateToolbox, u
return (
<div className={embedded ? "toolbox-embedded" : "toolbox-page"}>
<section className="toolbox-head">
<section className={embedded ? "toolbox-head page-hero toolbox-head-embedded" : "toolbox-head page-hero"}>
<div>
<p className="eyebrow">Toolbox</p>
<div className="toolbox-title-row">
{!embedded && !toolboxGame && <ToolboxIconPicker toolbox={toolbox} onChange={(icon) => updateToolbox({ ...toolbox, icon })} />}
{!embedded && toolboxGame?.image && <ToolboxGameIcon game={toolboxGame} />}
{!embedded && toolboxGameCover && <ToolboxGameIcon game={toolboxGame} />}
{embedded ? <h1>{toolbox.name}</h1> : (
<EditableTitle className="toolbox-title" value={toolbox.name} fallback="Nouvelle toolbox" onSave={(name) => name !== toolbox.name && updateToolbox({ ...toolbox, name })} />
)}
@ -1267,17 +1276,17 @@ function ToolboxDrawer({ gameId, toolboxes, links, actions, updateToolbox, updat
}
return (
<aside className="drawer" id="toolbox-drawer" aria-hidden="false">
<aside className="drawer" id="toolbox-drawer" aria-hidden="false" style={width ? { "--drawer-panel-width": `${width}px` } : undefined}>
<div className="drawer-backdrop" onClick={() => actions.setDrawerGameId("")} />
<span className="drawer-resize-handle" aria-hidden="true" onPointerDown={startResize} />
<section className="drawer-panel legacy-scrollbar" ref={panelRef} style={width ? { width } : undefined}>
<div className="drawer-content">
<span className="drawer-resize-handle" aria-hidden="true" onPointerDown={startResize} />
<header>
<div>
<p className="eyebrow">Toolbox liée</p>
<div className="drawer-toolbox-actions" aria-label="Actions toolbox liée">
<ImportButton className="drawer-action-button import-icon-button" ariaLabel="Importer une toolbox" title="Importer" icon="import" onFile={(file) => actions.importToolbox(file, gameId)} />
<button className="drawer-action-button" onClick={() => actions.setLinkModalGameId(gameId)} aria-label="Lier une toolbox" title="Lier"><Icon name="link" /></button>
<ImportButton className="drawer-action-button import-icon-button" ariaLabel="Importer une toolbox" title="Importer" icon="import" onFile={(file) => actions.importToolbox(file, gameId)} />
<button className="drawer-action-button" onClick={() => actions.exportToolbox(selectedId)} disabled={!selectedId} aria-label="Exporter la toolbox liée" title="Exporter"><Icon name="export" /></button>
</div>
</div>