Add responsive game filters and hybrid toolbox drawer
All checks were successful
Deploy Sokko G / deploy (push) Successful in 20s
All checks were successful
Deploy Sokko G / deploy (push) Successful in 20s
This commit is contained in:
parent
1ee460b94f
commit
00e73f0062
32 changed files with 1202 additions and 241 deletions
|
|
@ -1,7 +1,10 @@
|
|||
// Rôle : expose en développement un catalogue vivant et interactif des contrôles NDS.
|
||||
import { useState } from "react";
|
||||
import { CompactDropdown } from "../components/CompactDropdown.jsx";
|
||||
import { Icon } from "../components/Icon.jsx";
|
||||
import { MixTagsInput } from "../components/MixTagsInput.jsx";
|
||||
import { Tooltip } from "../components/Tooltip.jsx";
|
||||
import { ActiveFilterBadges } from "../features/games/ActiveFilterBadges.jsx";
|
||||
|
||||
const SIZE_VALUES = {
|
||||
field: ["xs", "sm", "md"],
|
||||
|
|
@ -419,14 +422,9 @@ const PATTERN_COMPONENTS = [
|
|||
name: "Filter Panel",
|
||||
className: "nds-filter-panel",
|
||||
sizes: SIZE_VALUES.none,
|
||||
variants: VARIANT_VALUES.none,
|
||||
attributes: {},
|
||||
render: () => (
|
||||
<aside className="nds-filter-panel design-system-pattern-card">
|
||||
<header className="nds-section-heading"><strong>Filtres</strong><button className="nds-icon-button" data-size="xs" type="button" aria-label="Reset"><Icon name="rubber" /></button></header>
|
||||
<button className="nds-chip" data-size="sm" type="button" aria-pressed="true">Actif</button>
|
||||
</aside>
|
||||
)
|
||||
variants: ["vertical", "horizontal-compact", "horizontal-menu"],
|
||||
attributes: { "data-variant": ["vertical", "horizontal-compact", "horizontal-menu"] },
|
||||
render: ({ attributes, variant }) => <FilterPanelPreview attributes={attributes} variant={variant} />
|
||||
},
|
||||
{
|
||||
id: "nds-reorder-indicator",
|
||||
|
|
@ -714,6 +712,70 @@ function NativeSwitchPreview({ disabled = false, initialChecked = false }) {
|
|||
);
|
||||
}
|
||||
|
||||
function FilterPanelPreview({ attributes, variant }) {
|
||||
const [search, setSearch] = useState("");
|
||||
const [logic, setLogic] = useState("and");
|
||||
const [selected, setSelected] = useState(["fire"]);
|
||||
const options = [
|
||||
{ id: "fire", label: "Feu", icon: "fire" },
|
||||
{ id: "water", label: "Eau", icon: "tear" },
|
||||
{ id: "nature", label: "Nature", icon: "leaf" }
|
||||
];
|
||||
const toggle = (id) => setSelected((current) => current.includes(id) ? current.filter((value) => value !== id) : [...current, id]);
|
||||
const activeBadges = [
|
||||
...(search.trim() ? [{ id: "search", label: `Nom : ${search.trim()}`, onRemove: () => setSearch("") }] : []),
|
||||
...selected.map((id) => ({ id, label: `Éléments : ${options.find((option) => option.id === id)?.label}`, onRemove: () => toggle(id) }))
|
||||
];
|
||||
const reset = () => {
|
||||
setSearch("");
|
||||
setLogic("and");
|
||||
setSelected([]);
|
||||
};
|
||||
|
||||
if (variant === "vertical") {
|
||||
return (
|
||||
<aside className="nds-filter-panel design-system-filter-preview" {...attributes}>
|
||||
<header className="nds-section-heading"><strong>Filtres</strong><button className="nds-icon-button" data-size="xs" type="button" aria-label="Réinitialiser" onClick={reset}><Icon name="rubber" /></button></header>
|
||||
<label className="field compact"><span>Nom</span><input className="nds-input" data-size="sm" type="search" value={search} placeholder="Rechercher..." onChange={(event) => setSearch(event.target.value)} /></label>
|
||||
<div className="filter-options">
|
||||
{options.map((option) => <label className={`filter-chip nds-chip ${selected.includes(option.id) ? "active" : ""}`} data-size="sm" key={option.id}><input className="nds-checkbox" data-size="sm" type="checkbox" checked={selected.includes(option.id)} onChange={() => toggle(option.id)} /><Icon name={option.icon} /><span>{option.label}</span></label>)}
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className="nds-filter-panel design-system-filter-preview" {...attributes}>
|
||||
<label className="nds-filter-search"><span className="sr-only">Nom</span><input className="nds-input" data-size="sm" type="search" value={search} placeholder="Rechercher..." onChange={(event) => setSearch(event.target.value)} /></label>
|
||||
<div className="nds-filter-group">
|
||||
{variant === "horizontal-compact" ? (
|
||||
<>
|
||||
<span className="nds-filter-group-label">Éléments</span>
|
||||
<div className="nds-filter-direct-options" role="group" aria-label="Éléments">
|
||||
{options.map((option) => <Tooltip as="button" className={`nds-filter-option ${selected.includes(option.id) ? "active" : ""}`} content={option.label} key={option.id} type="button" aria-label={option.label} aria-pressed={selected.includes(option.id)} onClick={() => toggle(option.id)}><Icon name={option.icon} /><span className="nds-filter-option-label">{option.label}</span></Tooltip>)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<CompactDropdown
|
||||
className="nds-filter-dropdown"
|
||||
menuClassName="nds-filter-menu nds-popover"
|
||||
menuProps={{ role: "dialog", "aria-label": "Catégories", "data-columns": "2" }}
|
||||
label="Catégories"
|
||||
renderTrigger={({ open, toggle: toggleMenu, triggerRef }) => <button ref={triggerRef} className={`nds-filter-menu-trigger nds-select-trigger ${open ? "active" : ""}`} data-size="sm" type="button" aria-expanded={open} aria-haspopup="dialog" onClick={toggleMenu}><Icon name="checklist" /><span>Catégories</span>{selected.length > 0 && <strong className="nds-filter-count">{selected.length}</strong>}</button>}
|
||||
>
|
||||
{() => <><div className="filter-logic nds-filter-logic"><span>Correspondance</span><div className="filter-logic-group nds-radio-button-group" data-size="xs" role="radiogroup" aria-label="Correspondance">{["and", "or"].map((value) => <button className={logic === value ? "active" : ""} key={value} type="button" role="radio" aria-checked={logic === value} onClick={() => setLogic(value)}>{value === "and" ? "Et" : "Ou"}</button>)}</div></div><div className="nds-filter-menu-options">{options.map((option) => <label className={`filter-chip nds-chip nds-filter-menu-option ${selected.includes(option.id) ? "active" : ""}`} data-size="sm" key={option.id}><input className="nds-checkbox" data-size="sm" type="checkbox" checked={selected.includes(option.id)} onChange={() => toggle(option.id)} /><Icon name={option.icon} /><span>{option.label}</span></label>)}</div></>}
|
||||
</CompactDropdown>
|
||||
)}
|
||||
</div>
|
||||
{variant === "horizontal-compact" && <div className="nds-filter-group">
|
||||
<div className="filter-logic nds-filter-logic"><span>Correspondance</span><div className="filter-logic-group nds-radio-button-group" data-size="xs" role="radiogroup" aria-label="Correspondance">{["and", "or"].map((value) => <button className={logic === value ? "active" : ""} key={value} type="button" role="radio" aria-checked={logic === value} onClick={() => setLogic(value)}>{value === "and" ? "Et" : "Ou"}</button>)}</div></div>
|
||||
</div>}
|
||||
<button className="nds-icon-button nds-filter-reset" data-size="xs" type="button" aria-label="Réinitialiser" onClick={reset}><Icon name="rubber" /></button>
|
||||
<ActiveFilterBadges items={activeBadges} />
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
function DatePickerPreview() {
|
||||
const [activeDay, setActiveDay] = useState(2);
|
||||
const days = Array.from({ length: 35 }, (_, index) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue