diff --git a/package-lock.json b/package-lock.json index 66f8cba..dfb3898 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,100 +16,7 @@ "vite": "7.0.4" }, "devDependencies": { - "fs-extra": "^11.3.3", - "postcss": "^8.5.8", - "postcss-custom-media": "^12.0.1" - } - }, - "node_modules/@csstools/cascade-layer-name-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-3.0.0.tgz", - "integrity": "sha512-/3iksyevwRfSJx5yH0RkcrcYXwuhMQx3Juqf40t97PeEy2/Mz2TItZ/z/216qpe4GgOyFBP8MKIwVvytzHmfIQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" - } - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", - "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^4.0.0" - } - }, - "node_modules/@csstools/css-tokenizer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", - "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/@csstools/media-query-list-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-5.0.0.tgz", - "integrity": "sha512-T9lXmZOfnam3eMERPsszjY5NK0jX8RmThmmm99FZ8b7z8yMaFZWKwLWGZuTwdO3ddRY5fy13GmmEYZXB4I98Eg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" + "fs-extra": "^11.3.3" } }, "node_modules/@esbuild/aix-ppc64": { @@ -1254,9 +1161,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "funding": [ { "type": "opencollective", @@ -1281,35 +1188,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-custom-media": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-12.0.1.tgz", - "integrity": "sha512-66syE14+VeqkUf0rRX0bvbTCbNRJF132jD+ceo8th1dap2YJEAqpdh5uG98CE3IbgHT7m9XM0GIlOazNWqQdeA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/cascade-layer-name-parser": "^3.0.0", - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0", - "@csstools/media-query-list-parser": "^5.0.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, "node_modules/regexparam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-1.3.0.tgz", diff --git a/package.json b/package.json index b90e052..75793d2 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,6 @@ "vite": "7.0.4" }, "devDependencies": { - "fs-extra": "^11.3.3", - "postcss": "^8.5.8", - "postcss-custom-media": "^12.0.1" + "fs-extra": "^11.3.3" } } diff --git a/postcss.config.js b/postcss.config.js deleted file mode 100644 index 63af7d8..0000000 --- a/postcss.config.js +++ /dev/null @@ -1,5 +0,0 @@ -import customMedia from 'postcss-custom-media' - -export default { - plugins: [customMedia()] -} diff --git a/site/blueprints/pages/game.yml b/site/blueprints/pages/game.yml index 824cd3a..cf3b2e9 100644 --- a/site/blueprints/pages/game.yml +++ b/site/blueprints/pages/game.yml @@ -55,10 +55,9 @@ columns: - strike - clear - link - playLink: + playLinks: label: Lien(s) pour jouer help: Laissez vide pour afficher "à venir / coming soon" - translate: false type: url - width: 3/10 @@ -72,7 +71,6 @@ columns: language: css size: custom-size default: radial-gradient(circle at 20% 80%, rgb(240, 154, 110) 0%, rgb(233, 101, 122) 100%) - translate: false help: À remplir avec la valeur de la propriété CSS `background-color` souhaitée preview: label: Aperçu diff --git a/src/components/layout/Header.svelte b/src/components/layout/Header.svelte index 12288c5..d2b54e4 100644 --- a/src/components/layout/Header.svelte +++ b/src/components/layout/Header.svelte @@ -166,7 +166,7 @@ } /* Mobile — var(--breakpoint-mobile) = 700px */ - @media (--mobile) { + @media screen and (max-width: 700px) { .navbar { min-height: 8vh; padding: 10vh 0 1vh; @@ -179,7 +179,7 @@ } /* Tablet — var(--breakpoint-tablet) = 912px */ - @media (--tablet-only) { + @media screen and (min-width: 701px) and (max-width: 912px) { .navbar-item { font-size: var(--font-size-paragraph-tablet); padding: 1vmax 1.8vmax; diff --git a/src/components/layout/Menu.svelte b/src/components/layout/Menu.svelte index 73fb9d3..ac08a0e 100644 --- a/src/components/layout/Menu.svelte +++ b/src/components/layout/Menu.svelte @@ -244,7 +244,7 @@ } /* Mobile — var(--breakpoint-mobile) = 700px */ - @media (--mobile) { + @media screen and (max-width: 700px) { .menu-list { font-size: var(--font-size-subtitle-mobile); grid-area: 6/4 / span 8 / span 8; @@ -269,7 +269,7 @@ } /* Tablet — var(--breakpoint-tablet) = 912px */ - @media (--tablet-only) { + @media screen and (min-width: 701px) and (max-width: 912px) { .menu-list { font-size: var(--font-size-title-section-tablet); } diff --git a/src/styles/buttons.css b/src/styles/buttons.css index 5ab2b9b..2b48c15 100644 --- a/src/styles/buttons.css +++ b/src/styles/buttons.css @@ -1,7 +1,3 @@ -button { - border: none; -} - /* Button */ .button { width: 14vmax; diff --git a/src/styles/variables.css b/src/styles/variables.css index f9ac8e3..3402246 100644 --- a/src/styles/variables.css +++ b/src/styles/variables.css @@ -1,8 +1,3 @@ -/* Custom media queries — utilisables dans @media (--mobile) / @media (--tablet) */ -@custom-media --mobile (max-width: 700px); -@custom-media --tablet (max-width: 912px); -@custom-media --tablet-only (min-width: 701px) and (max-width: 912px); - /* CSS Variables */ :root { /* Colors */ @@ -11,6 +6,10 @@ --color-background: #000; --color-text: #fff; + /* BREAKPOINTS (référence — non utilisables directement dans @media) + * --breakpoint-mobile : 700px + * --breakpoint-tablet : 912px + */ --breakpoint-mobile: 700px; --breakpoint-tablet: 912px; diff --git a/src/views/Expertise.svelte b/src/views/Expertise.svelte index 4e7922e..3856aed 100644 --- a/src/views/Expertise.svelte +++ b/src/views/Expertise.svelte @@ -363,7 +363,7 @@ } /* Mobile (≤ 700px) */ - @media (--mobile) { + @media screen and (max-width: 700px) { .expertise-title { grid-area: 5/4 / span 1 / span 7; font-size: var(--font-size-title-main-mobile); @@ -379,7 +379,7 @@ } /* Tablet (701–912px) */ - @media (--tablet-only) { + @media screen and (min-width: 701px) and (max-width: 912px) { .expertise-title { grid-area: 5/6 / span 4 / span 12; font-size: var(--font-size-title-main-tablet); diff --git a/src/views/Home.svelte b/src/views/Home.svelte index f19145e..9777b12 100644 --- a/src/views/Home.svelte +++ b/src/views/Home.svelte @@ -175,7 +175,7 @@ } } - @media (--tablet-only) { + @media screen and (min-width: 701px) and (max-width: 912px) { .home-subtitle { font-size: var(--font-size-subtitle-tablet); width: 70%; diff --git a/src/views/Play.svelte b/src/views/Play.svelte index bb0d57e..8c25c97 100644 --- a/src/views/Play.svelte +++ b/src/views/Play.svelte @@ -10,45 +10,25 @@ const games = $derived(data?.games ?? []) // --- State --- - let currentIndex = $state(0) - let displayedIndex = $state(0) + let currentIndex = $state(0) // index actif (carousel + bg) + let displayedIndex = $state(0) // index du contenu affiché let phase = $state('idle') // 'idle' | 'exiting' | 'entering' - let slideDir = $state(1) // 1 = exit gauche, -1 = exit droite + let slideDir = $state(1) // 1 = click droite (exit gauche), -1 = click gauche (exit droite) // Bg crossfade - let prevBgColor = $state(null) - let bgFading = $state(false) + let prevBgColor = $state(null) + let bgFading = $state(false) const displayedGame = $derived(games[displayedIndex] ?? null) - // Capture du hash synchrone avant que tout effect puisse le modifier - const initialHash = window.location.hash.slice(1) - let t1 = null let t2 = null let t3 = null - // --- Ancres --- - function setAnchor(index) { - const slug = games[index]?.slug - if (!slug) return - history.replaceState(null, '', '#' + slug) - } - - function clearAnchor() { - history.replaceState(null, '', window.location.pathname + window.location.search) - } - - // Restauration depuis l'ancre URL — une seule fois quand games est prêt - $effect(() => { - if (games.length === 0 || !initialHash) return - const idx = games.findIndex(g => g.slug === initialHash) - if (idx > 0) currentIndex = idx - }) - function selectGame(i) { if (i === currentIndex || phase !== 'idle' || !games.length) return + // slideDir = 1 → clic à droite → content sort par la gauche, entre par la droite slideDir = i > currentIndex ? 1 : -1 phase = 'exiting' @@ -56,36 +36,22 @@ clearTimeout(t2) clearTimeout(t3) + // Phase 2 (300ms) : swap contenu + carousel + bg simultanés t1 = setTimeout(() => { prevBgColor = displayedGame?.backgroundColor ?? null displayedIndex = i currentIndex = i phase = 'entering' bgFading = true - setAnchor(i) + // Fin du bg fade t3 = setTimeout(() => { bgFading = false }, 500) + + // Fin de l'entrée t2 = setTimeout(() => { phase = 'idle' }, 350) }, 300) } - // --- Clavier --- - // Enregistré en capture pour s'exécuter avant le handler global de App.svelte. - // Si la navigation reste dans Play (pas aux limites), on bloque App via - // stopImmediatePropagation. Aux limites, on ne fait rien : App navigue normalement. - function onKeyDown(e) { - if (!isActive) return - if (e.key === 'ArrowRight' && currentIndex < games.length - 1) { - e.stopImmediatePropagation() - e.preventDefault() - selectGame(currentIndex + 1) - } else if (e.key === 'ArrowLeft' && currentIndex > 0) { - e.stopImmediatePropagation() - e.preventDefault() - selectGame(currentIndex - 1) - } - } - // Réinitialisation quand on quitte la slide $effect(() => { if (!isActive) { @@ -96,18 +62,13 @@ displayedIndex = 0 phase = 'idle' bgFading = false - clearAnchor() } }) - onMount(() => { - window.addEventListener('keydown', onKeyDown, { capture: true }) - return () => { - window.removeEventListener('keydown', onKeyDown, { capture: true }) - clearTimeout(t1) - clearTimeout(t2) - clearTimeout(t3) - } + onMount(() => () => { + clearTimeout(t1) + clearTimeout(t2) + clearTimeout(t3) }) @@ -393,6 +354,7 @@ display: flex; flex-direction: column; align-items: center; + width: clamp(140px, 15.09vw, 291px); gap: 0.5rem; background: none; cursor: pointer; @@ -400,22 +362,15 @@ transition: all 0.4s var(--ease-standard); } - .play-carousel-item :global(img) { - width: clamp(140px, 15.09vw, 291px); - } - - .play-carousel-item.active :global(img) { + .play-carousel-item.active button { + opacity: 1; width: clamp(170px, 18.41vw, 355px); } - .play-carousel-item.active button { - opacity: 1; - } - - .play-carousel-item button :global(img), + .play-carousel-item button img, .play-carousel-item button :global(picture img) { object-fit: cover; - transition: all 0.4s var(--ease-standard); + transition: border-color 0.4s var(--ease-standard); } .play-carousel-title { @@ -431,7 +386,7 @@ } /* --- Mobile (≤ 700px) --- */ - @media (--mobile) { + @media screen and (max-width: 700px) { .game-preview { display: none; } diff --git a/src/views/Portfolio.svelte b/src/views/Portfolio.svelte index d133a68..42af7e2 100644 --- a/src/views/Portfolio.svelte +++ b/src/views/Portfolio.svelte @@ -291,7 +291,7 @@ } /* Mobile (≤ 700px) */ - @media (--mobile) { + @media screen and (max-width: 700px) { .portfolio-gallery { grid-area: 1/1 / span 20 / span 20; opacity: 0.3;