diff --git a/tests/helpers/data-validation.mjs b/tests/helpers/data-validation.mjs index b55ae53..5fbb588 100644 --- a/tests/helpers/data-validation.mjs +++ b/tests/helpers/data-validation.mjs @@ -81,10 +81,12 @@ export function validateSiteContent(site) { "home.stats.toolboxPlural", "home.stats.toolSingular", "home.stats.toolPlural", - "home.orientation.ariaLabel", - "home.startMap.eyebrow", - "home.startMap.title", - "home.startMap.description", + "home.onboarding.eyebrow", + "home.onboarding.title", + "home.onboarding.description", + "home.onboarding.stepsTitle", + "home.onboarding.sliderLabel", + "home.onboarding.slideButtonLabel", "home.origin.eyebrow", "home.origin.title", "home.origin.visualAlt", @@ -531,27 +533,39 @@ export function validateSiteContent(site) { assertNonEmptyString({ tool }, "tool.description"); }); - const orientationCards = valueAt(site, "home.orientation.cards"); - assert.ok(Array.isArray(orientationCards), "home.orientation.cards must be an array"); - assert.ok(orientationCards.length >= 2, "home.orientation.cards must contain at least 2 items"); - orientationCards.forEach((card, index) => { - assert.equal(typeof card, "object", `home.orientation.cards[${index}] must be an object`); + const onboardingCards = valueAt(site, "home.onboarding.cards"); + assert.ok(Array.isArray(onboardingCards), "home.onboarding.cards must be an array"); + assert.ok(onboardingCards.length >= 2, "home.onboarding.cards must contain at least 2 items"); + onboardingCards.forEach((card, index) => { + assert.equal(typeof card, "object", `home.onboarding.cards[${index}] must be an object`); assertNonEmptyString({ card }, "card.icon"); + assertNonEmptyString({ card }, "card.image"); assertNonEmptyString({ card }, "card.title"); assertNonEmptyString({ card }, "card.text"); assertNonEmptyString({ card }, "card.action"); assertNonEmptyString({ card }, "card.href"); }); - const startMapSteps = valueAt(site, "home.startMap.steps"); - assert.ok(Array.isArray(startMapSteps), "home.startMap.steps must be an array"); - assert.ok(startMapSteps.length >= 1, "home.startMap.steps must contain at least 1 item"); - startMapSteps.forEach((step, index) => { - assert.equal(typeof step, "object", `home.startMap.steps[${index}] must be an object`); + const onboardingSteps = valueAt(site, "home.onboarding.steps"); + assert.ok(Array.isArray(onboardingSteps), "home.onboarding.steps must be an array"); + assert.ok(onboardingSteps.length >= 1, "home.onboarding.steps must contain at least 1 item"); + onboardingSteps.forEach((step, index) => { + assert.equal(typeof step, "object", `home.onboarding.steps[${index}] must be an object`); assertNonEmptyString({ step }, "step.title"); assertNonEmptyString({ step }, "step.text"); }); + const onboardingSlides = valueAt(site, "home.onboarding.slides"); + assert.ok(Array.isArray(onboardingSlides), "home.onboarding.slides must be an array"); + assert.equal(onboardingSlides.length, 4, "home.onboarding.slides must contain 4 items"); + onboardingSlides.forEach((slide, index) => { + assert.equal(typeof slide, "object", `home.onboarding.slides[${index}] must be an object`); + assertNonEmptyString({ slide }, "slide.src"); + assertNonEmptyString({ slide }, "slide.alt"); + assertNonEmptyString({ slide }, "slide.title"); + assertNonEmptyString({ slide }, "slide.text"); + }); + const lines = valueAt(site, "home.origin.lines"); assert.ok(Array.isArray(lines), "home.origin.lines must be an array"); assert.ok(lines.length >= 2, "home.origin.lines must contain at least 2 items"); diff --git a/tests/static-app.test.mjs b/tests/static-app.test.mjs index a9bef9a..124f41d 100644 --- a/tests/static-app.test.mjs +++ b/tests/static-app.test.mjs @@ -14,6 +14,7 @@ test("vite entrypoint and app shell are wired", async () => { const imageViewer = await readFile("website/src/components/ImageViewer.jsx", "utf8"); const richText = await readFile("website/src/components/RichText.jsx", "utf8"); const homePage = await readFile("website/src/pages/HomePage.jsx", "utf8"); + const homeOnboarding = await readFile("website/src/pages/HomeOnboardingSection.jsx", "utf8"); const aboutPage = await readFile("website/src/pages/AboutPage.jsx", "utf8"); const libraryPage = await readFile("website/src/pages/LibraryPage.jsx", "utf8"); const hashRouter = await readFile("website/src/router/hashRouter.js", "utf8"); @@ -60,8 +61,15 @@ test("vite entrypoint and app shell are wired", async () => { assert.match(richText, /value\.split\("\\n"\)/); assert.match(richText, /
{ await readFile("website/public/static/icons/zoom.svg", "utf8"); await readFile("website/public/favicon.ico"); await readFile("website/public/static/img/dragon.png"); + await readFile("website/public/static/img/dragon-gameguide.png"); + await readFile("website/public/static/img/dragon-toolbox.png"); + await readFile("website/public/static/img/onboarding/toolbox-overview.png"); + await readFile("website/public/static/img/onboarding/toolbox-tools.png"); + await readFile("website/public/static/img/onboarding/toolbox-save.png"); + await readFile("website/public/static/img/onboarding/toolbox-game-link.png"); await readFile("website/public/static/img/toolbox-icons/toolbox.png"); await readFile("website/public/static/img/toolbox-icons/sword.png"); await readFile("website/public/static/img/toolbox-icons/puzzle.png"); diff --git a/tests/static-styles.test.mjs b/tests/static-styles.test.mjs index 3fcae2b..4e949b7 100644 --- a/tests/static-styles.test.mjs +++ b/tests/static-styles.test.mjs @@ -37,6 +37,9 @@ test("style entrypoint and theme layers are wired", async () => { assert.match(styleHome, /font-style: italic/); assert.match(styleHome, /\.about-page/); assert.match(styleHome, /\.nebula-panel/); + assert.match(styleHome, /\.home-onboarding-layout/); + assert.match(styleHome, /\.home-onboarding-slider figcaption/); + assert.match(styleHome, /\.home-onboarding-dots/); assert.match(styleHome, /\.about-story-section/); assert.match(styleHome, /\.about-tools-list/); assert.match(styleHome, /\.about-tool-item \.module-icon/); diff --git a/website/public/data/site.json b/website/public/data/site.json index 51c05c5..e954990 100644 --- a/website/public/data/site.json +++ b/website/public/data/site.json @@ -1182,29 +1182,13 @@ "toolSingular": "outil disponible", "toolPlural": "outils disponibles" }, - "orientation": { - "ariaLabel": "Accès rapides de la page d'accueil", - "cards": [ - { - "icon": "toolbox", - "title": "Toolboxes", - "text": "Votre espace personnel : notes, listes, images, liens et outils pratiques enregistrés dans ce navigateur.", - "action": "Gérer mes toolboxes", - "href": "#/toolboxes" - }, - { - "icon": "controller", - "title": "Jeux", - "text": "Les pages de référence disponibles. Vous pouvez ensuite y associer votre toolbox pour garder vos infos à côté.", - "action": "Voir les jeux", - "href": "#/games" - } - ] - }, - "startMap": { - "eyebrow": "Première toolbox", - "title": "Comment démarrer ?", - "description": "Vous n'avez pas encore de toolbox dans ce navigateur. Créez votre premier espace en quelques étapes, ou récupérez une sauvegarde si quelqu'un vous en a partagé une.", + "onboarding": { + "eyebrow": "Prise en main", + "title": "Prise en main", + "description": "Une toolbox est votre espace personnel pour garder vos notes, listes, images, liens et outils utiles dans ce navigateur.", + "stepsTitle": "Créer votre première toolbox", + "sliderLabel": "Aperçu de la prise en main", + "slideButtonLabel": "Afficher l'aperçu", "steps": [ { "title": "Créez une toolbox", @@ -1222,6 +1206,50 @@ "title": "Exportez pour sauvegarder", "text": "Les données restent dans ce navigateur. Exportez vos toolboxes avant un nettoyage, un changement de machine ou une réinstallation." } + ], + "slides": [ + { + "src": "/static/img/onboarding/toolbox-overview.png", + "alt": "Aperçu d'une toolbox Sokko G", + "title": "Un espace unique", + "text": "Regroupez les informations utiles à votre session dans une interface locale." + }, + { + "src": "/static/img/onboarding/toolbox-tools.png", + "alt": "Aperçu des outils disponibles dans une toolbox", + "title": "Des outils à choisir", + "text": "Ajoutez seulement les outils dont vous avez besoin pour votre jeu ou votre objectif." + }, + { + "src": "/static/img/onboarding/toolbox-save.png", + "alt": "Aperçu d'une sauvegarde de toolbox", + "title": "Des sauvegardes simples", + "text": "Exportez vos toolboxes pour les conserver ou les partager." + }, + { + "src": "/static/img/onboarding/toolbox-game-link.png", + "alt": "Aperçu d'une toolbox associée à une page jeu", + "title": "Jeu et notes côte à côte", + "text": "Associez une toolbox à une page jeu pour garder vos repères personnels à proximité." + } + ], + "cards": [ + { + "icon": "toolbox", + "image": "/static/img/dragon-toolbox.png", + "title": "Toolboxes", + "text": "Votre espace personnel : notes, listes, images, liens et outils pratiques enregistrés dans ce navigateur.", + "action": "Gérer mes toolboxes", + "href": "#/toolboxes" + }, + { + "icon": "controller", + "image": "/static/img/dragon-gameguide.png", + "title": "Guides de jeux", + "text": "Les pages de référence disponibles. Vous pouvez ensuite y associer votre toolbox pour garder vos infos à côté.", + "action": "Voir les jeux", + "href": "#/games" + } ] }, "origin": { diff --git a/website/public/static/img/dragon-gameguide.png b/website/public/static/img/dragon-gameguide.png new file mode 100644 index 0000000..edc1e9c Binary files /dev/null and b/website/public/static/img/dragon-gameguide.png differ diff --git a/website/public/static/img/dragon-toolbox.png b/website/public/static/img/dragon-toolbox.png new file mode 100644 index 0000000..bc5c361 Binary files /dev/null and b/website/public/static/img/dragon-toolbox.png differ diff --git a/website/public/static/img/dragon.png b/website/public/static/img/dragon.png index 160cc68..e023ce8 100644 Binary files a/website/public/static/img/dragon.png and b/website/public/static/img/dragon.png differ diff --git a/website/public/static/img/onboarding/toolbox-game-link.png b/website/public/static/img/onboarding/toolbox-game-link.png new file mode 100644 index 0000000..77e90e6 Binary files /dev/null and b/website/public/static/img/onboarding/toolbox-game-link.png differ diff --git a/website/public/static/img/onboarding/toolbox-overview.png b/website/public/static/img/onboarding/toolbox-overview.png new file mode 100644 index 0000000..5876e24 Binary files /dev/null and b/website/public/static/img/onboarding/toolbox-overview.png differ diff --git a/website/public/static/img/onboarding/toolbox-save.png b/website/public/static/img/onboarding/toolbox-save.png new file mode 100644 index 0000000..653ed81 Binary files /dev/null and b/website/public/static/img/onboarding/toolbox-save.png differ diff --git a/website/public/static/img/onboarding/toolbox-tools.png b/website/public/static/img/onboarding/toolbox-tools.png new file mode 100644 index 0000000..1e83a84 Binary files /dev/null and b/website/public/static/img/onboarding/toolbox-tools.png differ diff --git a/website/src/features/toolboxes/modules/TableModule.jsx b/website/src/features/toolboxes/modules/TableModule.jsx index eac4053..95af690 100644 --- a/website/src/features/toolboxes/modules/TableModule.jsx +++ b/website/src/features/toolboxes/modules/TableModule.jsx @@ -461,8 +461,7 @@ export function TableModule({ toolboxId, moduleId, context, editing }) { const bounds = getSelectionBounds(selection); copiedSelectionRef.current = getCellBlock(data.cells, bounds); const text = getTsv(bounds); - if (!await context.copyText(text)) return; - context.notify?.(textContent.copiedTitle || "Tableau copié"); + await context.copyText(text); } function pasteBlock(block, rowIndex, columnIndex) { diff --git a/website/src/pages/AboutPage.jsx b/website/src/pages/AboutPage.jsx index 04e1b6c..a885e1c 100644 --- a/website/src/pages/AboutPage.jsx +++ b/website/src/pages/AboutPage.jsx @@ -2,6 +2,7 @@ import React, { useEffect } from "react"; import { Icon } from "../components/Icon.jsx"; import { RichText } from "../components/RichText.jsx"; +import { HomeOnboardingSection } from "./HomeOnboardingSection.jsx"; export function AboutPage({ siteContent }) { const content = siteContent.about; @@ -60,6 +61,7 @@ export function AboutPage({ siteContent }) { ))} +
diff --git a/website/src/pages/HomeOnboardingSection.jsx b/website/src/pages/HomeOnboardingSection.jsx new file mode 100644 index 0000000..62507a2 --- /dev/null +++ b/website/src/pages/HomeOnboardingSection.jsx @@ -0,0 +1,100 @@ +// Rôle : affiche la section de prise en main de la home avec étapes, slider et accès rapides. +import React, { useEffect, useMemo, useState } from "react"; + +const SLIDE_INTERVAL_MS = 4500; + +function prefersReducedMotion() { + return typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches; +} + +export function HomeOnboardingSection({ content, className = "" }) { + const slides = useMemo(() => content?.slides || [], [content]); + const [activeSlide, setActiveSlide] = useState(0); + const [isPaused, setIsPaused] = useState(false); + + useEffect(() => { + if (slides.length <= 1 || isPaused || prefersReducedMotion()) return undefined; + const intervalId = window.setInterval(() => { + setActiveSlide((current) => (current + 1) % slides.length); + }, SLIDE_INTERVAL_MS); + return () => window.clearInterval(intervalId); + }, [isPaused, slides.length]); + + if (!content) return null; + + const currentSlide = slides[activeSlide] || slides[0]; + + return ( +
+
+

{content.eyebrow}

+

{content.title}

+

{content.description}

+
+
+
+

{content.stepsTitle}

+
    + {content.steps.map((step, index) => ( +
  1. + {index + 1} +
    + {step.title} +

    {step.text}

    +
    +
  2. + ))} +
+
+
setIsPaused(true)} + onMouseLeave={() => setIsPaused(false)} + onFocus={() => setIsPaused(true)} + onBlur={() => setIsPaused(false)} + > + {currentSlide && ( +
+ {currentSlide.alt} +
+ {currentSlide.title} + {currentSlide.text} +
+
+ )} + {slides.length > 1 && ( +
+ {slides.map((slide, index) => ( +
+ )} +
+
+
+ {content.cards.map((card) => ( + + + + + + + + {card.text} + {card.action} + + + ))} +
+
+ ); +} diff --git a/website/src/pages/HomePage.jsx b/website/src/pages/HomePage.jsx index 38ec6b3..7ca8ea8 100644 --- a/website/src/pages/HomePage.jsx +++ b/website/src/pages/HomePage.jsx @@ -2,11 +2,12 @@ import React from "react"; import { TOOLBOX_MODULES } from "../features/toolboxes/modules/index.jsx"; import { RichText } from "../components/RichText.jsx"; +import { HomeOnboardingSection } from "./HomeOnboardingSection.jsx"; export function HomePage({ siteContent, toolboxes }) { const content = siteContent.home; const toolCount = Object.keys(TOOLBOX_MODULES).length; - const showStartMap = import.meta.env.DEV || toolboxes.length === 0; + const showOnboarding = import.meta.env.DEV || toolboxes.length === 0; return ( <>
@@ -24,40 +25,7 @@ export function HomePage({ siteContent, toolboxes }) {
{toolCount}{toolCount > 1 ? content.stats.toolPlural : content.stats.toolSingular}
-
- {showStartMap && ( -
-
-

{content.startMap.eyebrow}

-

{content.startMap.title}

-

{content.startMap.description}

-
-
    - {content.startMap.steps.map((step, index) => ( -
  1. - {index + 1} -
    - {step.title} -

    {step.text}

    -
    -
  2. - ))} -
-
- )} -
-
- {content.orientation.cards.map((card) => ( - - - ))} -
-
-
+ {showOnboarding && }

{content.origin.eyebrow}

diff --git a/website/src/styles/_home.scss b/website/src/styles/_home.scss index 3560128..069e290 100644 --- a/website/src/styles/_home.scss +++ b/website/src/styles/_home.scss @@ -199,112 +199,38 @@ span { max-width: 980px; } -.home-orientation { +.home-onboarding { display: grid; - gap: var(--space-5); + gap: var(--space-6); margin-top: var(--space-6); - padding: var(--space-5); + padding: var(--space-6); } -.home-orientation-main { +.home-onboarding-heading { + max-width: 980px; +} + +.home-onboarding-layout { display: grid; + grid-template-columns: minmax(280px, 0.85fr) minmax(360px, 1.15fr); + align-items: stretch; + gap: var(--space-5); } -.home-orientation-main.has-start-map { - padding-top: var(--space-5); - border-top: 1px solid rgba(150, 165, 205, 0.12); -} - -.home-orientation-grid { +.home-onboarding-steps { display: grid; - grid-template-columns: repeat(2, minmax(280px, 440px)); + align-content: start; gap: var(--space-4); - justify-content: center; -} - -.home-orientation-card { - position: relative; - isolation: isolate; - display: grid; min-width: 0; - justify-items: center; - gap: var(--space-3); - overflow: hidden; - min-height: 220px; - padding: var(--space-4); - border: 1px solid transparent; - border-radius: var(--radius-md); - background: - linear-gradient(rgba(10, 13, 27, 0.92), rgba(10, 13, 27, 0.92)) padding-box, - radial-gradient(circle at 100% 0%, rgba(246, 196, 83, 0.2), transparent 28%) border-box, - linear-gradient(135deg, rgba(246, 196, 83, 0.44), rgba(139, 92, 246, 0.22) 66%, rgba(34, 211, 238, 0.16)) border-box; - box-shadow: var(--shadow-sm); - text-decoration: none; - transition: - border-color var(--duration-fast) var(--ease-standard), - background var(--duration-fast) var(--ease-standard), - box-shadow var(--duration-fast) var(--ease-standard); } -.home-orientation-card > * { - position: relative; - z-index: 1; -} - -.home-orientation-card .module-icon-svg { - width: 36px; - height: 36px; - background: var(--color-accent-gold); -} - -.home-orientation-card strong { - text-align: center; +.home-onboarding-steps h3 { + margin: 0; color: var(--color-text-primary); font-size: var(--font-size-lg); } -.home-orientation-card span:not(.module-icon-svg) { - max-width: 620px; - text-align: center; - font-size: var(--font-size-sm); -} - -.home-orientation-card em { - display: inline-flex; - min-height: 38px; - align-items: center; - justify-content: center; - width: fit-content; - margin-top: auto; - padding: 0 var(--space-3); - border: 1px solid rgba(246, 196, 83, 0.28); - border-radius: var(--radius-md); - background: rgba(246, 196, 83, 0.08); - color: var(--color-accent-gold); - font-style: normal; - font-size: var(--font-size-sm); - font-weight: 800; -} - -.home-orientation-card:hover, -.home-orientation-card:focus-visible { - transform: none; - border-color: transparent; - background: - linear-gradient(rgba(18, 23, 44, 0.96), rgba(18, 23, 44, 0.96)) padding-box, - radial-gradient(circle at 100% 0%, rgba(246, 196, 83, 0.26), transparent 28%) border-box, - linear-gradient(135deg, rgba(246, 196, 83, 0.58), rgba(196, 181, 253, 0.34) 62%, rgba(34, 211, 238, 0.2)) border-box; - box-shadow: - var(--shadow-sm), - 0 0 18px rgba(139, 92, 246, 0.16); -} - -.home-start-map { - display: grid; - gap: var(--space-5); -} - -.home-start-steps { +.home-onboarding-steps ol { display: grid; gap: 0; margin: 0; @@ -312,7 +238,7 @@ span { list-style: none; } -.home-start-steps li { +.home-onboarding-steps li { display: flex; min-width: 0; gap: var(--space-3); @@ -320,16 +246,16 @@ span { border-top: 1px solid rgba(150, 165, 205, 0.1); } -.home-start-steps li:first-child { +.home-onboarding-steps li:first-child { padding-top: 0; border-top: 0; } -.home-start-steps li:last-child { +.home-onboarding-steps li:last-child { padding-bottom: 0; } -.home-start-steps li > span { +.home-onboarding-steps li > span { display: grid; width: 28px; min-width: 28px; @@ -343,41 +269,241 @@ span { font-weight: 900; } -.home-start-steps div { +.home-onboarding-steps div { display: grid; gap: 4px; min-width: 0; } -.home-start-steps strong, -.home-start-steps p { +.home-onboarding-steps strong, +.home-onboarding-steps p { margin: 0; } -.home-start-steps strong { +.home-onboarding-steps strong { color: var(--color-text-primary); } -.home-start-steps p { +.home-onboarding-steps p { font-size: var(--font-size-sm); } +.home-onboarding-slider { + position: relative; + display: grid; + min-width: 0; + overflow: hidden; + border: 1px solid rgba(150, 165, 205, 0.14); + border-radius: var(--radius-md); + background: rgba(5, 7, 17, 0.38); + box-shadow: var(--shadow-sm); +} + +.home-onboarding-slider figure { + position: relative; + display: grid; + min-height: 340px; + margin: 0; +} + +.home-onboarding-slider img { + display: block; + width: 100%; + height: 100%; + min-height: 340px; + object-fit: cover; +} + +.home-onboarding-slider figcaption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + display: grid; + min-height: 4.8em; + align-content: center; + gap: 2px; + padding: var(--space-3) var(--space-4); + background: rgba(0, 0, 0, 0.56); + backdrop-filter: blur(8px); +} + +.home-onboarding-slider figcaption strong, +.home-onboarding-slider figcaption span { + margin: 0; +} + +.home-onboarding-slider figcaption strong { + color: var(--color-text-primary); + font-size: var(--font-size-md); +} + +.home-onboarding-slider figcaption span { + color: var(--color-text-secondary); + font-size: var(--font-size-sm); +} + +.home-onboarding-dots { + position: absolute; + right: var(--space-3); + bottom: calc(4.8em + var(--space-3)); + display: flex; + gap: 7px; +} + +.home-onboarding-dots button { + width: 10px; + min-width: 10px; + height: 10px; + min-height: 10px; + padding: 0; + border-color: rgba(246, 196, 83, 0.36); + border-radius: var(--radius-pill); + background: rgba(5, 7, 17, 0.68); +} + +.home-onboarding-dots button.active, +.home-onboarding-dots button:hover, +.home-onboarding-dots button:focus-visible { + background: var(--color-accent-gold); + box-shadow: 0 0 10px rgba(246, 196, 83, 0.26); +} + +.home-onboarding-cards { + display: grid; + grid-template-columns: repeat(2, minmax(260px, 320px)); + gap: var(--space-4); + justify-content: center; + padding-top: var(--space-6); + border-top: 1px solid rgba(150, 165, 205, 0.12); +} + +.home-onboarding-card { + position: relative; + isolation: isolate; + display: grid; + min-width: 0; + overflow: hidden; + align-content: start; + padding: 0; + border: 1px solid transparent; + border-radius: var(--radius-md); + background: + linear-gradient(rgba(16, 20, 38, 0.88), rgba(16, 20, 38, 0.88)) padding-box, + radial-gradient(circle at 100% 0%, rgba(34, 211, 238, 0.42), transparent 28%) border-box, + linear-gradient(135deg, rgba(246, 196, 83, 0.62) 0%, rgba(246, 196, 83, 0.42) 72%, rgba(34, 211, 238, 0.24) 100%) border-box; + box-shadow: var(--shadow-sm); + text-decoration: none; + transition: + border-color var(--duration-fast) var(--ease-standard), + background var(--duration-fast) var(--ease-standard), + box-shadow var(--duration-fast) var(--ease-standard); +} + +@supports (corner-shape: scoop) { + .home-onboarding-card { + corner-shape: scoop; + } +} + +.home-onboarding-card-visual { + position: relative; + display: grid; + aspect-ratio: 3 / 2; + min-height: 0; + place-items: center; + overflow: hidden; + border-bottom: 1px solid rgba(246, 196, 83, 0.42); + background: + radial-gradient(circle at 50% 15%, rgba(246, 196, 83, 0.12), transparent 34%), + rgba(5, 7, 17, 0.28); +} + +.home-onboarding-card-visual img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; + filter: drop-shadow(0 14px 22px rgba(0, 0, 0, 0.3)); +} + +.home-onboarding-card-body { + display: grid; + gap: var(--space-3); + justify-items: center; + padding: var(--space-4); +} + +.home-onboarding-card-title { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 9px; + min-width: 0; + color: var(--color-text-primary); +} + +.home-onboarding-card-title .module-icon-svg { + width: 20px; + min-width: 20px; + height: 20px; + background: var(--color-accent-gold); +} + +.home-onboarding-card strong { + color: var(--color-text-primary); + font-size: var(--font-size-lg); + line-height: 1.2; +} + +.home-onboarding-card-text { + max-width: 30ch; + text-align: center; + font-size: var(--font-size-sm); +} + +.home-onboarding-card em { + display: inline-flex; + min-height: 38px; + align-items: center; + justify-content: center; + width: fit-content; + padding: 0 var(--space-3); + border: 1px solid rgba(246, 196, 83, 0.28); + border-radius: var(--radius-md); + background: rgba(246, 196, 83, 0.08); + color: var(--color-accent-gold); + font-style: normal; + font-size: var(--font-size-sm); + font-weight: 800; +} + +.home-onboarding-card:hover, +.home-onboarding-card:focus-visible { + transform: none; + border-color: transparent; + background: + linear-gradient(rgba(18, 23, 44, 0.96), rgba(18, 23, 44, 0.96)) padding-box, + radial-gradient(circle at 100% 0%, rgba(246, 196, 83, 0.26), transparent 28%) border-box, + linear-gradient(135deg, rgba(246, 196, 83, 0.58), rgba(196, 181, 253, 0.34) 62%, rgba(34, 211, 238, 0.2)) border-box; + box-shadow: + var(--shadow-sm), + 0 0 18px rgba(139, 92, 246, 0.16); +} + .home-visual { display: grid; align-self: center; - justify-self: stretch; - width: 100%; - height: 100%; - min-height: 320px; + justify-self: center; + width: min(100%, 640px); place-items: center; } .home-visual img { display: block; width: 100%; - height: 100%; + height: auto; max-height: 520px; - object-fit: cover; border-radius: var(--radius-lg); filter: drop-shadow(0 22px 36px rgba(0, 0, 0, 0.34)); } @@ -1019,7 +1145,7 @@ span { .origin-section { display: grid; - grid-template-columns: minmax(0, 1.1fr) minmax(300px, 0.65fr); + grid-template-columns: minmax(0, 1fr) minmax(360px, 0.78fr); gap: var(--space-6); margin-top: var(--space-6); padding: var(--space-6); @@ -1081,6 +1207,10 @@ span { gap: var(--space-6); } +.about-onboarding-section { + margin-top: 0; +} + .about-story-section { display: grid; grid-template-columns: minmax(210px, 260px) minmax(0, 1fr); diff --git a/website/src/styles/_responsive.scss b/website/src/styles/_responsive.scss index fbeb39a..7a2459f 100644 --- a/website/src/styles/_responsive.scss +++ b/website/src/styles/_responsive.scss @@ -76,7 +76,8 @@ .game-hero, .page-hero, .origin-section, - .home-orientation-grid, + .home-onboarding-layout, + .home-onboarding-cards, .about-story-section, .about-contribute-section, .about-tools-list, @@ -121,13 +122,7 @@ } .home-visual { - justify-self: center; width: min(320px, 100%); - min-height: 240px; - } - - .home-visual img { - object-fit: contain; } .origin-section {