Extend NDS patterns and migrate shared UI surfaces
All checks were successful
Deploy Sokko G / deploy (push) Successful in 17s
All checks were successful
Deploy Sokko G / deploy (push) Successful in 17s
This commit is contained in:
parent
fef7735a1d
commit
9aa98c892d
41 changed files with 1035 additions and 405 deletions
|
|
@ -22,7 +22,7 @@ export function GameFiltersPanel({
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="filter-panel">
|
||||
<div className="filter-panel nds-filter-panel">
|
||||
<div className="filter-panel-head">
|
||||
<div>
|
||||
<p className="eyebrow">Filtres</p>
|
||||
|
|
@ -63,7 +63,7 @@ export function GameFiltersPanel({
|
|||
{options.map((option) => {
|
||||
const optionId = getOptionId(option);
|
||||
return (
|
||||
<label className={`filter-chip ${getOptionClassName(option)} ${selected.has(optionId) ? "active" : ""}`} key={optionId}>
|
||||
<label className={`filter-chip nds-chip ${getOptionClassName(option)} ${selected.has(optionId) ? "active" : ""}`} key={optionId}>
|
||||
<input
|
||||
className="nds-checkbox"
|
||||
data-size="sm"
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export function GameListsPage({ game, lists, selectedListId, onSelectList, linke
|
|||
</section>
|
||||
</>
|
||||
) : (
|
||||
<section className="empty">
|
||||
<section className="empty nds-empty-state">
|
||||
<h2>Aucune liste</h2>
|
||||
<p>Aucune liste n’est encore disponible pour ce jeu.</p>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ export function GamesPage({ siteContent, games, gamesError }) {
|
|||
|
||||
return (
|
||||
<>
|
||||
<section className="page-hero">
|
||||
<section className="page-hero nds-page-hero">
|
||||
<div>
|
||||
<p className="eyebrow">{content.eyebrow}</p>
|
||||
<h1>{content.title}</h1>
|
||||
|
|
@ -13,9 +13,9 @@ export function GamesPage({ siteContent, games, gamesError }) {
|
|||
</section>
|
||||
<section className="game-list">
|
||||
{games.length ? games.map((game) => (
|
||||
<article className="card game-card" key={game.id}>
|
||||
<article className="card nds-card game-card" data-variant="interactive" key={game.id}>
|
||||
<a
|
||||
className="card-cover game-card-cover game-card-cover-link"
|
||||
className="card-cover nds-card-cover game-card-cover game-card-cover-link"
|
||||
href={`#/games/${game.id}`}
|
||||
aria-label={`Ouvrir ${game.title}`}
|
||||
title={`Ouvrir ${game.title}`}
|
||||
|
|
@ -27,17 +27,17 @@ export function GamesPage({ siteContent, games, gamesError }) {
|
|||
<span className="game-card-placeholder" aria-hidden="true">{game.title}</span>
|
||||
)}
|
||||
</a>
|
||||
<div className="card-body">
|
||||
<div className="card-body nds-card-body">
|
||||
<p className="eyebrow">{game.eyebrow || "Guide de jeu"}</p>
|
||||
<h2>{game.title}</h2>
|
||||
<p>{game.summary}</p>
|
||||
<div className="card-actions">
|
||||
<div className="card-actions nds-card-actions nds-toolbar">
|
||||
<a className="nds-button" data-size="sm" data-variant="primary" href={`#/games/${game.id}`}>Ouvrir</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
)) : (
|
||||
<div className="empty">
|
||||
<div className="empty nds-empty-state">
|
||||
<h2>{content.emptyTitle}</h2>
|
||||
<p>{gamesError || content.emptyText}</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ import { getCategoryIconStyle, getCategoryLabel } from "./utils.js";
|
|||
|
||||
export function Diablo4AffixCard({ affix, categoryMap }) {
|
||||
return (
|
||||
<article className="compact-data-card diablo4-affix-card">
|
||||
<article className="compact-data-card nds-card diablo4-affix-card" data-variant="interactive">
|
||||
<div className="diablo4-affix-card-body">
|
||||
<h2>{affix.label}</h2>
|
||||
<div className="diablo4-category-list" aria-label="Catégories">
|
||||
{(affix.categories || []).map((categoryId) => {
|
||||
const category = categoryMap[categoryId] || categoryId;
|
||||
return (
|
||||
<span className={`tone-${category.tone || "default"}`} key={categoryId}>
|
||||
<span className={`nds-badge tone-${category.tone || "default"}`} key={categoryId}>
|
||||
<span className="diablo4-category-icon" aria-hidden="true" style={getCategoryIconStyle(category)} />
|
||||
{getCategoryLabel(category)}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export function Diablo4Listing({ game, diablo4, filters, setFilters }) {
|
|||
{visible.length ? visible.map((affix) => (
|
||||
<Diablo4AffixCard key={affix.id} affix={affix} categoryMap={diablo4.categoryMap} />
|
||||
)) : (
|
||||
<div className="empty">
|
||||
<div className="empty nds-empty-state">
|
||||
<h2>Aucun résultat</h2>
|
||||
<p>Ajustez la recherche ou réinitialisez les filtres actifs.</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export function Diablo4Page({ category, game, diablo4, filters, setFilters }) {
|
|||
<p>Chargement des affixes et filtres associés.</p>
|
||||
</div>
|
||||
</section>
|
||||
<section className="empty">
|
||||
<section className="empty nds-empty-state">
|
||||
<h2>Chargement</h2>
|
||||
<p>Préparation des données locales...</p>
|
||||
</section>
|
||||
|
|
@ -26,7 +26,7 @@ export function Diablo4Page({ category, game, diablo4, filters, setFilters }) {
|
|||
|
||||
if (diablo4.error) {
|
||||
return (
|
||||
<section className="empty">
|
||||
<section className="empty nds-empty-state">
|
||||
<h1>Impossible de charger Diablo IV</h1>
|
||||
<p>{diablo4.error}</p>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ export function MhwildsListing({ category, game, mhwilds, filters, setFilters, t
|
|||
? <MonsterCard key={item.name} monster={item} t={t} />
|
||||
: <EndemicCard key={item.name} item={item} t={t} />
|
||||
)) : (
|
||||
<div className="empty">
|
||||
<div className="empty nds-empty-state">
|
||||
<h2>Aucun résultat</h2>
|
||||
<p>Ajustez la recherche ou réinitialisez les filtres actifs.</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export function MhwildsPage({ category, game, mhwilds, filters, setFilters, t, l
|
|||
<p>Chargement des données de chasse, faune endémique et filtres associés.</p>
|
||||
</div>
|
||||
</section>
|
||||
<section className="empty">
|
||||
<section className="empty nds-empty-state">
|
||||
<h2>Chargement</h2>
|
||||
<p>Préparation des données locales...</p>
|
||||
</section>
|
||||
|
|
@ -27,7 +27,7 @@ export function MhwildsPage({ category, game, mhwilds, filters, setFilters, t, l
|
|||
|
||||
if (mhwilds.error) {
|
||||
return (
|
||||
<section className="empty">
|
||||
<section className="empty nds-empty-state">
|
||||
<h1>Impossible de charger MH Wilds</h1>
|
||||
<p>{mhwilds.error}</p>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export function ToolboxCard({ toolbox, game, actions, reorder }) {
|
|||
const coverImage = gameCoverImage || toolbox.icon || DEFAULT_TOOLBOX_ICON;
|
||||
const className = [
|
||||
"card",
|
||||
"nds-card",
|
||||
"toolbox-card",
|
||||
reorder.isItemDragging(toolbox.id) ? "is-dragging" : "",
|
||||
reorder.isItemDropTarget(toolbox.id) ? "is-drop-target" : "",
|
||||
|
|
@ -32,7 +33,7 @@ export function ToolboxCard({ toolbox, game, actions, reorder }) {
|
|||
].filter(Boolean).join(" ");
|
||||
|
||||
return (
|
||||
<article className={className} {...reorder.getItemProps({ itemId: toolbox.id })}>
|
||||
<article className={className} data-variant="interactive" {...reorder.getItemProps({ itemId: toolbox.id })}>
|
||||
<button
|
||||
className="toolbox-card-drag-handle nds-icon-button"
|
||||
data-size="md"
|
||||
|
|
@ -45,7 +46,7 @@ export function ToolboxCard({ toolbox, game, actions, reorder }) {
|
|||
<Icon name="drag" />
|
||||
</button>
|
||||
<a
|
||||
className={`card-cover toolbox-card-cover-link ${gameCoverImage ? "toolbox-card-cover" : "toolbox-icon-cover"}`}
|
||||
className={`card-cover nds-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}`}
|
||||
|
|
@ -53,11 +54,11 @@ export function ToolboxCard({ toolbox, game, actions, reorder }) {
|
|||
>
|
||||
<img src={coverImage} alt={game ? game.title : `Icône de ${toolbox.name}`} loading="lazy" />
|
||||
</a>
|
||||
<div className="card-body">
|
||||
<div className="card-body nds-card-body">
|
||||
<p className="eyebrow">{game ? game.title : "Toolbox libre"}</p>
|
||||
<h2>{toolbox.name}</h2>
|
||||
<small>Modifiée le {formatDate(toolbox.updatedAt)}</small>
|
||||
<div className="card-actions">
|
||||
<div className="card-actions nds-card-actions nds-toolbar">
|
||||
<a className="card-icon-button nds-icon-button" data-size="md" href={`#/toolbox/${toolbox.id}`} aria-label={`Ouvrir ${toolbox.name}`} title="Ouvrir"><Icon name="open" /></a>
|
||||
<button className="card-icon-button nds-icon-button" data-size="md" onClick={() => actions.exportToolbox(toolbox.id)} aria-label={`Exporter ${toolbox.name}`} title="Exporter"><Icon name="export" /></button>
|
||||
<button className="card-icon-button nds-icon-button" data-size="md" data-variant="danger" onClick={() => actions.setConfirmModal({
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ export function ToolboxesPage({ siteContent, toolboxes, getToolboxGame, actions,
|
|||
|
||||
return (
|
||||
<div className="toolbox-page">
|
||||
<section className="page-hero">
|
||||
<section className="page-hero nds-page-hero">
|
||||
<div>
|
||||
<p className="eyebrow">{content.eyebrow}</p>
|
||||
<h1>{content.title}</h1>
|
||||
|
|
@ -107,7 +107,7 @@ export function ToolboxesPage({ siteContent, toolboxes, getToolboxGame, actions,
|
|||
<a className="hero-library-button library-link-button nds-button" data-size="sm" href="#/library"><Icon name="book" />{content.libraryLink}</a>
|
||||
</div>
|
||||
</section>
|
||||
<section className="toolbar toolbox-actions-row">
|
||||
<section className="toolbar nds-toolbar toolbox-actions-row">
|
||||
<div>
|
||||
<button className="nds-button" data-size="sm" data-variant="primary" onClick={() => actions.setCreateModal({})}>{content.newButton}</button>
|
||||
<ImportButton className="nds-button" data-size="sm" label={content.importOne} onFile={actions.importToolbox} />
|
||||
|
|
@ -143,7 +143,7 @@ export function ToolboxesPage({ siteContent, toolboxes, getToolboxGame, actions,
|
|||
reorder={{ itemReorder, getItemProps, isItemDragging, isItemDropTarget, getDropPlacement }}
|
||||
/>
|
||||
)) : (
|
||||
<div className="empty"><h2>{content.emptyTitle}</h2><p>{content.emptyText}</p></div>
|
||||
<div className="empty nds-empty-state"><h2>{content.emptyTitle}</h2><p>{content.emptyText}</p></div>
|
||||
)}
|
||||
</section>
|
||||
<StorageQuota usage={storageUsage} />
|
||||
|
|
@ -153,8 +153,8 @@ export function ToolboxesPage({ siteContent, toolboxes, getToolboxGame, actions,
|
|||
|
||||
function StorageHelpCard({ help }) {
|
||||
return (
|
||||
<article className="card storage-help-card" aria-labelledby="storage-help-title">
|
||||
<div className="card-body">
|
||||
<article className="card nds-card storage-help-card" aria-labelledby="storage-help-title">
|
||||
<div className="card-body nds-card-body">
|
||||
<div className="storage-help-heading">
|
||||
<span className="storage-help-mark" aria-hidden="true" />
|
||||
<div><p className="eyebrow">IndexedDB</p><h2 id="storage-help-title">{help.title}</h2></div>
|
||||
|
|
@ -171,7 +171,7 @@ function StorageHelpCard({ help }) {
|
|||
export function ToolboxPage(props) {
|
||||
const { toolboxId, toolboxes, getToolboxGame } = props;
|
||||
const toolbox = toolboxes.find((item) => item.id === toolboxId);
|
||||
if (!toolbox) return <div className="empty"><h1>Toolbox introuvable</h1><a className="nds-button" data-size="sm" href="#/toolboxes">Retour</a></div>;
|
||||
if (!toolbox) return <div className="empty nds-empty-state"><h1>Toolbox introuvable</h1><a className="nds-button" data-size="sm" href="#/toolboxes">Retour</a></div>;
|
||||
return <ToolboxView {...props} toolbox={toolbox} toolboxGame={getToolboxGame(toolbox)} embedded={false} />;
|
||||
}
|
||||
|
||||
|
|
@ -257,7 +257,7 @@ function ToolboxView({ siteContent, toolbox, toolboxGame, embedded, actions, sto
|
|||
|
||||
return (
|
||||
<div className={embedded ? "toolbox-embedded" : "toolbox-page"}>
|
||||
<section className={embedded ? "toolbox-head page-hero toolbox-head-embedded" : "toolbox-head page-hero"}>
|
||||
<section className={embedded ? "toolbox-head page-hero nds-page-hero toolbox-head-embedded" : "toolbox-head page-hero nds-page-hero"}>
|
||||
<div>
|
||||
<p className="eyebrow">Toolbox</p>
|
||||
<div className="toolbox-title-row">
|
||||
|
|
@ -279,7 +279,7 @@ function ToolboxView({ siteContent, toolbox, toolboxGame, embedded, actions, sto
|
|||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div className="actions">
|
||||
<div className="actions nds-toolbar">
|
||||
<AddToolControls onAdd={addModule} />
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -385,13 +385,13 @@ export function ToolboxDrawer({ gameId, game, siteContent, toolboxes, links, act
|
|||
return (
|
||||
<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}>
|
||||
<span className="drawer-resize-handle nds-drawer-resize-handle" aria-hidden="true" onPointerDown={startResize} />
|
||||
<section className="drawer-panel nds-drawer-panel legacy-scrollbar" ref={panelRef} style={width ? { width } : undefined}>
|
||||
<div className="drawer-content">
|
||||
<header>
|
||||
<div>
|
||||
<p className="eyebrow">Toolbox liée</p>
|
||||
<div className="drawer-toolbox-actions" aria-label="Actions toolbox liée">
|
||||
<div className="drawer-toolbox-actions nds-toolbar" aria-label="Actions toolbox liée">
|
||||
<button className="drawer-action-button nds-icon-button" data-size="sm" onClick={() => actions.setLinkModalGameId(gameId)} aria-label="Lier une toolbox" title="Lier"><Icon name="link" /></button>
|
||||
<ImportButton className="drawer-action-button nds-icon-button import-icon-button" data-size="sm" ariaLabel="Importer une toolbox" title="Importer" icon="import" onFile={(file) => actions.importToolbox(file, gameId)} />
|
||||
<button className="drawer-action-button nds-icon-button" data-size="sm" onClick={() => actions.exportToolbox(selectedId)} disabled={!selectedId} aria-label="Exporter la toolbox liée" title="Exporter"><Icon name="export" /></button>
|
||||
|
|
@ -400,7 +400,7 @@ export function ToolboxDrawer({ gameId, game, siteContent, toolboxes, links, act
|
|||
<button className="drawer-close-button nds-icon-button" data-size="sm" onClick={() => actions.setDrawerGameId("")} aria-label="Fermer" title="Fermer"><Icon name="close" /></button>
|
||||
</header>
|
||||
{toolbox ? <ToolboxView siteContent={siteContent} toolbox={toolbox} toolboxGame={game} embedded actions={actions} storageUsage={storageUsage} storageReady={storageReady} getModuleData={getModuleData} updateToolbox={updateToolbox} updateModuleData={updateModuleData} addImageFiles={addImageFiles} /> : (
|
||||
<div className="empty"><p>Aucune toolbox associée à cette page jeu.</p><button className="nds-button" data-size="sm" data-variant="primary" onClick={() => actions.setCreateModal({ gameId })}>Créer et associer</button></div>
|
||||
<div className="empty nds-empty-state"><p>Aucune toolbox associée à cette page jeu.</p><button className="nds-button" data-size="sm" data-variant="primary" onClick={() => actions.setCreateModal({ gameId })}>Créer et associer</button></div>
|
||||
)}
|
||||
<StorageQuota usage={storageUsage} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -85,8 +85,8 @@ export function AddToolControls({ onAdd }) {
|
|||
</div>
|
||||
{open && createPortal(
|
||||
<div className="tool-add-modal-root" role="dialog" aria-modal="true" aria-labelledby="tool-add-modal-title">
|
||||
<div className="confirm-backdrop" onClick={() => setOpen(false)} />
|
||||
<section className="confirm-modal tool-add-modal">
|
||||
<div className="confirm-backdrop nds-modal-backdrop" onClick={() => setOpen(false)} />
|
||||
<section className="confirm-modal nds-modal tool-add-modal">
|
||||
<header>
|
||||
<h2 id="tool-add-modal-title">Ajouter un outil</h2>
|
||||
<button className="drawer-close-button nds-icon-button" data-size="sm" type="button" onClick={() => setOpen(false)} aria-label="Fermer" title="Fermer">
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ export function TextImportModal({ title, value, placeholder, submitLabel, readOn
|
|||
|
||||
return createPortal(
|
||||
<div className="confirm-modal-root text-import-modal-root">
|
||||
<div className="confirm-backdrop" onClick={onClose} />
|
||||
<section className="confirm-modal text-import-modal-dialog" role="dialog" aria-modal="true" aria-labelledby="text-import-title">
|
||||
<div className="confirm-backdrop nds-modal-backdrop" onClick={onClose} />
|
||||
<section className="confirm-modal nds-modal text-import-modal-dialog" role="dialog" aria-modal="true" aria-labelledby="text-import-title">
|
||||
<header>
|
||||
<h2 id="text-import-title">{title}</h2>
|
||||
<button className="drawer-close-button nds-icon-button" data-size="sm" type="button" onClick={onClose} aria-label="Fermer" title="Fermer">
|
||||
|
|
@ -42,18 +42,18 @@ export function TextImportModal({ title, value, placeholder, submitLabel, readOn
|
|||
aria-describedby={error ? "text-import-error" : undefined}
|
||||
/>
|
||||
{info && (
|
||||
<p className="text-import-info">
|
||||
<p className="text-import-info nds-inline-notice">
|
||||
<Icon name="info" />
|
||||
<span>{info}</span>
|
||||
</p>
|
||||
)}
|
||||
{error && (
|
||||
<p className="text-import-error" id="text-import-error" role="alert">
|
||||
<p className="text-import-error nds-inline-notice" data-variant="danger" id="text-import-error" role="alert">
|
||||
<Icon name="close" />
|
||||
<span>{error}</span>
|
||||
</p>
|
||||
)}
|
||||
<footer>
|
||||
<footer className="nds-modal-footer">
|
||||
<button className="nds-button" data-size="sm" type="button" onClick={onClose}>Annuler</button>
|
||||
{readOnly ? (
|
||||
<button className="nds-button" data-size="sm" data-variant="primary" type="button" onClick={onCopy}>{submitLabel}</button>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue