diff --git a/DESIGN_SYSTEM.md b/DESIGN_SYSTEM.md index 5ba82b2..27605ca 100644 --- a/DESIGN_SYSTEM.md +++ b/DESIGN_SYSTEM.md @@ -816,6 +816,7 @@ Date picker et menus compacts : - le verso occupe exactement la même surface que le recto ; garder son en-tête fixe et faire défiler les détails dans une zone NDS accessible au clavier ; masquer la face inactive aux technologies d'assistance ; - réduire l'animation selon `prefers-reduced-motion` ; - les filtres se cumulent par famille et sont évalués sur chaque variante avant regroupement ; +- la chip « Prismana uniquement », sous le nom, garde 12 px de marge inférieure, utilise une étoile SVG arc-en-ciel et limite les résultats à `prismana_form` avant regroupement ; inactive par défaut, elle se cumule avec tous les autres critères et se désactive à la réinitialisation ; - les catégories Rôles, Éléments et Compétences de logis partagent un défilement unique via `filter-options`, comme MHW ; des séparateurs discrets délimitent les catégories et leurs en-têtes permettent de les replier sans désactiver leurs sélections ; - rôles et éléments sont sur deux colonnes de chips `sm` ; les compétences élémentaires précèdent les autres sans séparation interne, avec icône, texte, curseur et valeur sur une ligne ; un seuil à 0 reste visible mais ne participe pas aux opérations ET/OU ; - garder le nombre de critères sélectionnés visible dans l'en-tête, même replié. diff --git a/e2e/aniimo.spec.js b/e2e/aniimo.spec.js index 8e093b9..9bc515f 100644 --- a/e2e/aniimo.spec.js +++ b/e2e/aniimo.spec.js @@ -5,6 +5,38 @@ const route = "/#/games/aniimo/aniimos"; const cards = (page) => page.locator(".aniimo-result"); const section = (page, name) => page.getByRole("group", { name, exact: true }).filter({ has: page.locator("legend") }); +for (const width of [1280, 390]) { + test(`Prismana filter combines with search and survives grouping and navigation at ${width}px`, async ({ page }) => { + test.setTimeout(45000); + await page.setViewportSize({ width, height: 900 }); + await page.goto(route); + const prismana = page.getByRole("checkbox", { name: "Prismana uniquement", exact: true }); + await expect(prismana).toBeVisible({ timeout: 30000 }); + await expect(prismana).not.toBeChecked(); + await prismana.focus(); + await prismana.press("Space"); + await expect(cards(page)).toHaveCount(27); + await expect(page.locator('.aniimo-result:not([data-form="prismana_form"])')).toHaveCount(0); + await expect(page.getByRole("tablist")).toHaveCount(0); + expect(await page.locator('img[src="/static/icons/prismana.svg"]').evaluate((image) => image.complete && image.naturalWidth > 0)).toBe(true); + await page.getByRole("searchbox").fill("iris"); + await expect(cards(page)).toHaveCount(3); + await page.locator('.game-breadcrumb a[href="#/games/aniimo"]').click(); + await page.locator('a[href="#/games/aniimo/aniimos"]').click(); + await expect(prismana).toBeChecked(); + await expect(cards(page)).toHaveCount(3); + await page.getByRole("button", { name: "Regrouper les variantes", exact: true }).click(); + await expect(cards(page)).toHaveCount(3); + await page.getByRole("searchbox").fill("emberpup"); + await expect(page.getByRole("heading", { name: "Aucun résultat" })).toBeVisible(); + await page.getByRole("button", { name: "Réinitialiser les filtres", exact: true }).click(); + await expect(prismana).not.toBeChecked(); + await expect(cards(page)).toHaveCount(208); + await expect(page.getByRole("button", { name: "Regrouper les variantes", exact: true })).toHaveAttribute("aria-pressed", "false"); + expect(await page.evaluate(() => globalThis.document.documentElement.scrollWidth <= globalThis.innerWidth)).toBe(true); + }); +} + test("Aniimo matches MHW card motion, surfaces and filter controls", async ({ page }) => { test.setTimeout(45000); async function styles(locator, properties) { diff --git a/tests/aniimo.test.mjs b/tests/aniimo.test.mjs index 8ad368d..a90f4b9 100644 --- a/tests/aniimo.test.mjs +++ b/tests/aniimo.test.mjs @@ -54,6 +54,19 @@ test("name searches accept French, English, accents and case", () => { assert.deepEqual(filter({ name: "inexistant-xyz" }), []); }); +test("Prismana-only filtering combines with other criteria before grouping", () => { + assert.equal(createAniimoFilters().prismanaOnly, false); + const expected = data.variants.filter((variant) => variant.form === "prismana_form"); + assert.ok(expected.length > 0); + assert.deepEqual(filter({ prismanaOnly: true }), expected); + const variant = expected[0]; + const criteria = { name: variant.name, elements: variant.elements, roles: [variant.role], abilities: Object.fromEntries(variant.homeland_abilities.map(({ type, level }) => [type, level])) }; + assert.deepEqual(filter({ ...criteria, prismanaOnly: true }), [variant]); + assert.equal(groupAniimoVariants(expected).length, expected.length); + assert.deepEqual(filter({ prismanaOnly: true, name: "emberpup" }), []); + assert.equal(filter({ prismanaOnly: false }).length, data.variants.length); +}); + test("Prismana remains the final variation in data and grouped results", () => { for (const group of groupAniimoVariants(data.variants)) { if (group.some((variant) => variant.form === "prismana_form")) assert.equal(group.at(-1).form, "prismana_form"); diff --git a/tests/helpers/data-validation.mjs b/tests/helpers/data-validation.mjs index 2899047..36e0e44 100644 --- a/tests/helpers/data-validation.mjs +++ b/tests/helpers/data-validation.mjs @@ -112,6 +112,7 @@ export function validateSiteContent(site) { "aniimo.filters", "aniimo.name", "aniimo.searchPlaceholder", + "aniimo.prismanaOnly", "aniimo.elements", "aniimo.roles", "aniimo.role", diff --git a/website/public/data/site.json b/website/public/data/site.json index 4132657..bb2737c 100644 --- a/website/public/data/site.json +++ b/website/public/data/site.json @@ -2740,6 +2740,7 @@ "filters": "Filtres", "name": "Nom", "searchPlaceholder": "Nom français ou anglais…", + "prismanaOnly": "Prismana uniquement", "elements": "Éléments", "roles": "Rôles", "role": "Rôle", diff --git a/website/public/static/icons/prismana.svg b/website/public/static/icons/prismana.svg new file mode 100644 index 0000000..e7a18b1 --- /dev/null +++ b/website/public/static/icons/prismana.svg @@ -0,0 +1,13 @@ + + diff --git a/website/src/features/games/aniimo/AniimoFilters.jsx b/website/src/features/games/aniimo/AniimoFilters.jsx index d68451f..7ac4206 100644 --- a/website/src/features/games/aniimo/AniimoFilters.jsx +++ b/website/src/features/games/aniimo/AniimoFilters.jsx @@ -31,6 +31,11 @@ export function AniimoFilters({ filters, onChange, options, t, content }) { {content.name} onChange({ ...filters, name: event.target.value })} /> +