diff --git a/site/blueprints/pages/white-paper.yml b/site/blueprints/pages/white-paper.yml deleted file mode 100644 index 57d1c52..0000000 --- a/site/blueprints/pages/white-paper.yml +++ /dev/null @@ -1,108 +0,0 @@ -title: Livre blanc -icon: file -status: - draft: - label: Brouillon - text: Non visible - listed: - label: Publié - text: Visible publiquement -tabs: - content: - label: Contenu - icon: text - columns: - main: - width: 2/3 - sections: - header: - type: fields - fields: - intro: - label: Description courte - type: writer - nodes: false - marks: - - bold - - italic - - link - maxlength: 200 - sidebar: - width: 1/3 - sections: - meta: - type: fields - fields: - published: - label: Date de publication - type: date - display: DD/MM/YYYY - required: true - default: today - translate: false - cover: - label: Image de couverture - type: files - layout: cards - max: 1 - accept: image/* - translate: false - image: - cover: true - ratio: 3/4 - uploads: - template: image - downloadFile: - label: Fichier PDF - type: files - max: 1 - accept: application/pdf - translate: false - help: Fichier téléchargé après soumission du formulaire - leads: - label: Contacts intéressés - icon: users - sections: - contactDatabase: - type: fields - fields: - contactDatabase: - label: Visiteurs ayant téléchargé - type: structure - translate: false - columns: - firstName: - label: Prénom - width: 1/4 - lastName: - label: Nom - width: 1/4 - email: - label: Email - width: 1/4 - company: - label: Entreprise - width: 1/4 - role: - label: Fonction - downloadedAt: - label: Date - fields: - firstName: - type: text - label: Prénom - lastName: - type: text - label: Nom - email: - type: email - label: Email - company: - type: text - label: Entreprise - role: - type: text - label: Fonction - downloadedAt: - type: text - label: Date diff --git a/site/blueprints/pages/white-papers.yml b/site/blueprints/pages/white-papers.yml deleted file mode 100644 index 816c625..0000000 --- a/site/blueprints/pages/white-papers.yml +++ /dev/null @@ -1,43 +0,0 @@ -title: Livres blancs -icon: book -status: - draft: - label: Brouillon - text: La page est accessible uniquement pour les éditeurs connectés - listed: - label: Public - text: La page est accessible par tout le monde -tabs: - content: - label: Contenu - icon: text - sections: - content: - type: fields - fields: - intro: - type: writer - marks: - - bold - - italic - - green - - pixel - - underline - - strike - - clear - - link - nodes: - - heading - headings: - - 1 - help: Section de texte centrée (optionnelle). - items: - label: Livres blancs - type: pages - layout: cards - sortBy: published desc - template: white-paper - image: - ratio: 3/4 - cover: true - info: "{{ page.published.toDate('d/m/Y') }}" diff --git a/site/blueprints/site.yml b/site/blueprints/site.yml index f4a3748..f5a74b9 100644 --- a/site/blueprints/site.yml +++ b/site/blueprints/site.yml @@ -1,113 +1,85 @@ title: World Game -tabs: - mainTab: - label: Principal - columns: - - width: 1/2 - sections: - navigation: - type: pages - label: Menu - help: Accédez aux pages et réordonnez-les - layout: list - size: small - sortable: true - create: false - status: listed +columns: + - width: 1/2 + sections: + navigation: + type: pages + label: Menu + help: Accédez aux pages et réordonnez-les + layout: list + size: small + sortable: true + create: false + status: listed - - width: 1/2 - fields: - siteTitle: - label: Titre du site - type: text - translate: true - siteTagline: - label: Tagline - type: text - translate: true - siteDescription: - label: Description - type: textarea - translate: true - footerLogo: - label: Logo - type: files - layout: cards - max: 1 - help: Utilisé en pied de page (page À propos, Blog et Article). - - - width: 1/2 - fields: - contactEmail: - label: Email - type: email - width: 1/2 - translate: false - contactAddress: - label: Adresse - type: writer - buttons: false - nodes: false - width: 1/2 - placeholder: 33 rue Jean Dupont - socialLinks: - label: Liens réseaux sociaux - type: structure - translate: false - fields: - label: - label: Nom - required: true - type: text - width: 1/3 - placeholder: "Ex: LinkedIn, Instagram..." - url: - label: URL - required: true - type: url - width: 1/3 - picto: - label: Icône SVG - type: textarea - width: 1/3 - buttons: false - size: small - help: Collez le code SVG de l'icône - - - width: 1/2 - sections: - contact: - type: fields - fields: - legalNotices: - label: Mentions légales (PDF) - type: files - max: 1 - accept: application/pdf - translate: false - dataTab: - label: Données d'usage - icon: chart + - width: 1/2 fields: - contactDatabase: - label: Ont téléchargé un livre blanc + siteTitle: + label: Titre du site + type: text + translate: true + siteTagline: + label: Tagline + type: text + translate: true + siteDescription: + label: Description + type: textarea + translate: true + footerLogo: + label: Logo + type: files + layout: cards + max: 1 + help: Utilisé en pied de page (page À propos, Blog et Article). + + - width: 1/2 + fields: + contactEmail: + label: Email + type: email + width: 1/2 + translate: false + contactAddress: + label: Adresse + type: writer + buttons: false + nodes: false + width: 1/2 + placeholder: 33 rue Jean Dupont + socialLinks: + label: Liens réseaux sociaux type: structure + translate: false fields: - firstName: - label: Prénom - type: text - required: true - lastName: + label: label: Nom - type: text required: true - company: - label: Société type: text - role: - label: Fonction - type: text - email: - type: email + width: 1/3 + placeholder: "Ex: LinkedIn, Instagram..." + url: + label: URL required: true + type: url + width: 1/3 + picto: + label: Icône SVG + type: textarea + width: 1/3 + buttons: false + size: small + help: Collez le code SVG de l'icône + + - width: 1/2 + sections: + contact: + type: fields + fields: + legalNotices: + label: Mentions légales (PDF) + type: files + max: 1 + accept: application/pdf + translate: false diff --git a/site/config/config.php b/site/config/config.php index 40b0846..c556463 100644 --- a/site/config/config.php +++ b/site/config/config.php @@ -11,8 +11,4 @@ return [ ], 'thumbs' => require __DIR__ . '/thumbs.php', - - 'routes' => [ - require(__DIR__ . '/routes/download-white-paper.php') - ], ]; diff --git a/site/config/menu.php b/site/config/menu.php index c88dcc5..ab988d0 100644 --- a/site/config/menu.php +++ b/site/config/menu.php @@ -29,8 +29,7 @@ return [ 'portfolio' => menuItem('portfolio', 'Portfolio','images', 'pages/portfolio'), 'jouer' => menuItem('jouer', 'Jouer', 'play', 'pages/jouer'), 'a-propos' => menuItem('a-propos', 'À propos', 'users', 'pages/a-propos'), - 'blog' => menuItem('blog', 'Blog', 'text', 'pages/blog'), - 'white-papers' => menuItem('livres-blancs', 'Livres blancs', 'book', 'pages/livres-blancs'), + 'blog' => menuItem('blog', 'Blog', 'text', 'pages/blog'), '-', 'users', 'system', diff --git a/site/config/routes/download-white-paper.php b/site/config/routes/download-white-paper.php deleted file mode 100644 index 41d93aa..0000000 --- a/site/config/routes/download-white-paper.php +++ /dev/null @@ -1,93 +0,0 @@ - $message]); - exit; -} - -return [ - 'pattern' => ['(:any)/(:any)/download', 'en/(:any)/(:any)/download'], - 'method' => 'POST', - 'action' => function (string $parent, string $slug) { - - $page = page($parent . '/' . $slug); - if (!$page || $page->intendedTemplate()->name() !== 'white-paper') { - wpReject(404, 'Not found'); - } - - $body = kirby()->request()->body()->toArray(); - - // ── Honeypot ────────────────────────────────────────────── - if (!empty($body['_hp'])) { - wpReject(400, 'Bad request'); - } - - // ── Rate limiting (5 req / hour / IP) ───────────────────── - $ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? 'unknown'; - $cacheKey = 'wp-dl-' . md5($ip); - $cache = kirby()->cache('pages'); - $hits = (int)($cache->get($cacheKey) ?? 0); - if ($hits >= 5) { - wpReject(429, 'Too many requests'); - } - $cache->set($cacheKey, $hits + 1, 60); // TTL 60 min - - // ── Validation des champs requis ────────────────────────── - $firstName = trim($body['firstName'] ?? ''); - $lastName = trim($body['lastName'] ?? ''); - $email = trim($body['email'] ?? ''); - - if ($firstName === '' || $lastName === '' || $email === '') { - wpReject(422, 'Missing required fields'); - } - - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { - wpReject(422, 'Invalid email'); - } - - // ── Stocker le lead dans contactDatabase ────────────────── - $company = trim($body['company'] ?? ''); - $role = trim($body['role'] ?? ''); - $entries = $page->contactDatabase()->toStructure()->toArray(); - - $existingIndex = null; - foreach ($entries as $i => $entry) { - if (strtolower($entry['email'] ?? '') === strtolower($email)) { - $existingIndex = $i; - break; - } - } - - if ($existingIndex !== null) { - // Contact déjà présent — on enrichit les champs vides uniquement - if ($company !== '' && empty($entries[$existingIndex]['company'])) { - $entries[$existingIndex]['company'] = $company; - } - if ($role !== '' && empty($entries[$existingIndex]['role'])) { - $entries[$existingIndex]['role'] = $role; - } - } else { - $entries[] = [ - 'firstName' => $firstName, - 'lastName' => $lastName, - 'email' => $email, - 'company' => $company, - 'role' => $role, - 'downloadedAt' => date('d/m/Y H:i'), - ]; - } - - kirby()->impersonate('kirby', function () use ($page, $entries) { - $page->update(['contactDatabase' => \Kirby\Data\Data::encode($entries, 'yaml')]); - }); - - header('Content-Type: application/json'); - echo json_encode([ - 'success' => true, - 'fileUrl' => $page->downloadFile()->toFile()?->url(), - ]); - exit; - } -]; diff --git a/site/templates/white-paper.json.php b/site/templates/white-paper.json.php deleted file mode 100644 index 11ea537..0000000 --- a/site/templates/white-paper.json.php +++ /dev/null @@ -1,13 +0,0 @@ - $page->published()->toDate('d/m/Y'), - 'intro' => $page->intro()->inline()->value(), - 'cover' => $page->cover()->toFile()?->url(), - 'fileUrl' => $page->downloadFile()->toFile()?->url(), -]; - -$pageData = array_merge($genericData, $specificData); - -header('Content-Type: application/json'); -echo json_encode($pageData); diff --git a/site/templates/white-paper.php b/site/templates/white-paper.php deleted file mode 100644 index f31b64d..0000000 --- a/site/templates/white-paper.php +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/site/templates/white-papers.json.php b/site/templates/white-papers.json.php deleted file mode 100644 index cfdce03..0000000 --- a/site/templates/white-papers.json.php +++ /dev/null @@ -1,26 +0,0 @@ -children()->listed()->sortBy('published', 'desc'); - -$mapItem = function ($item) { - return [ - 'title' => $item->title()->value(), - 'slug' => $item->slug(), - 'published' => $item->published()->toDate('d/m/Y'), - 'intro' => $item->intro()->value(), - 'cover' => $item->cover()->toFile()?->url(), - ]; -}; - -$singleSlug = $items->count() === 1 ? $items->first()->slug() : null; - -$specificData = [ - 'intro' => $page->intro()->value(), - 'items' => $items->map($mapItem)->values(), - 'singleSlug' => $singleSlug, -]; - -$pageData = array_merge($genericData, $specificData); - -header('Content-Type: application/json'); -echo json_encode($pageData); diff --git a/site/templates/white-papers.php b/site/templates/white-papers.php deleted file mode 100644 index f31b64d..0000000 --- a/site/templates/white-papers.php +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/App.svelte b/src/App.svelte index 719d74d..daa35b0 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -16,7 +16,6 @@ import Game from '@views/Game.svelte' import Blog from '@views/Blog.svelte' import Article from '@views/Article.svelte' - import WhitePapers from '@views/WhitePapers.svelte' import Default from '@views/Default.svelte' const templates = { @@ -29,7 +28,6 @@ game: Game, blog: Blog, article: Article, - 'white-papers': WhitePapers, default: Default } @@ -58,22 +56,10 @@ window.addEventListener('resize', handleResize) const handleKeydown = (e) => { - if (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return - - // Si on est sur une sous-page (ex: /livres-blancs/slug), ne pas changer de slide - const activePath = slides.active?.path ?? '' - const currentPath = window.location.pathname.replace(/^\/en/, '') || '/' - const isSubPage = activePath && currentPath.startsWith(activePath + '/') - - if (isSubPage) { - if (e.key === 'ArrowLeft') history.back() - return - } - if (e.key === 'ArrowRight') { const next = slides.all[slides.activeIndex + 1] if (next) slideTo(next.path) - } else { + } else if (e.key === 'ArrowLeft') { const prev = slides.all[slides.activeIndex - 1] if (prev) slideTo(prev.path) } diff --git a/src/components/layout/Cursor.svelte b/src/components/layout/Cursor.svelte index f2d9e53..ac57847 100644 --- a/src/components/layout/Cursor.svelte +++ b/src/components/layout/Cursor.svelte @@ -14,7 +14,7 @@ } const handleMouseOver = (e) => { - onTarget = !!e.target.closest('a, button:not([disabled]), [role="button"]:not([disabled]), [tabindex]') + onTarget = !!e.target.closest('a, button, [role="button"], [tabindex]') } const handleMouseOut = () => { diff --git a/src/components/layout/Footer.svelte b/src/components/layout/Footer.svelte index 2fe610c..767047e 100644 --- a/src/components/layout/Footer.svelte +++ b/src/components/layout/Footer.svelte @@ -124,7 +124,7 @@ margin-left: -16.6vw; } - :global(.collection .page-scrollable-footer) { + :global(.blog .page-scrollable-footer) { margin-left: -12.4vw; margin-top: 5rem; } diff --git a/src/i18n/index.js b/src/i18n/index.js index 4e6dd2d..21f2f6d 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -47,31 +47,6 @@ const dict = { privacy: { fr: "Confidentialité", en: "Privacy" }, // About our_team: { fr: "NOTRE ÉQUIPE", en: "OUR TEAM" }, - // White Papers - white_paper_label: { fr: "LIVRE BLANC", en: "WHITE PAPER" }, - read_wp: { fr: "Télécharger", en: "Download" }, - wp_form_intro: { - fr: "Renseignez vos informations pour télécharger notre livre blanc.", - en: "Fill in your information to download our white paper.", - }, - wp_firstname: { fr: "Prénom*", en: "First name*" }, - wp_lastname: { fr: "Nom*", en: "Last name*" }, - wp_company: { fr: "Société", en: "Company" }, - wp_role: { fr: "Fonction", en: "Role" }, - wp_email: { fr: "E-mail*", en: "E-mail*" }, - wp_consent: { - fr: "En cochant cette case, j'accepte d'être recontacté par la société World Game. Mes données ne seront ni vendues, ni partagées.", - en: "By checking this box, I agree to be contacted by World Game. My data will not be sold or shared.", - }, - wp_download: { fr: "TÉLÉCHARGER", en: "DOWNLOAD" }, - wp_success: { - fr: "Votre demande a été enregistrée. Le téléchargement devrait démarrer.", - en: "Your request has been registered. The download should start.", - }, - wp_error: { - fr: "Une erreur est survenue, veuillez réessayer.", - en: "An error occurred, please try again.", - }, // Menu menu: { fr: "MENU", en: "MENU" }, connect: { fr: "CONNECT", en: "CONNECT" }, diff --git a/src/styles/buttons.css b/src/styles/buttons.css index c578ba5..5ab2b9b 100644 --- a/src/styles/buttons.css +++ b/src/styles/buttons.css @@ -2,10 +2,6 @@ button { border: none; } -button[disabled] { - cursor: none; -} - /* Button */ .button { width: 14vmax; @@ -30,7 +26,7 @@ button[disabled] { outline: 2px solid #04fea0; } -.button:not([disabled]):hover { +.button:hover { background-color: initial; background-position: 0; outline: 2px solid #04fea0; @@ -68,5 +64,6 @@ button[disabled] { /* Clickable elements */ .clickable { + cursor: pointer; user-select: none; } diff --git a/src/styles/collection.css b/src/styles/collection.css deleted file mode 100644 index 1312a19..0000000 --- a/src/styles/collection.css +++ /dev/null @@ -1,180 +0,0 @@ -/* Shared styles for collection pages (Blog, WhitePapers) */ - -/* --- Header / Intro --- */ -.collection-header { - text-align: center; - padding: 6rem 0 3rem; - max-width: 40rem; - margin: auto; -} - -.collection-header h1 { - font-size: var(--font-size-title-main); - text-transform: uppercase; - margin-bottom: 2rem; -} - -.collection-header p { - font-size: var(--font-size-subtitle); - font-weight: 400; -} - -.collection-header :global(h1) { - font-family: "Terminal", sans-serif; - font-size: var(--font-size-title-main); - text-transform: uppercase; - margin-bottom: 1.5rem; -} - -.collection-header :global(p) { - font-size: var(--font-size-subtitle); - line-height: 1.6; - max-width: 640px; - margin: 0 auto; - opacity: 0.9; -} - -/* --- Card --- */ -.collection-card { - display: flex; - justify-content: space-between; - align-items: flex-start; - gap: 2rem; - padding: 1.5rem 0; -} - -.collection-card-text { - flex: 1; - display: flex; - flex-direction: column; - gap: 1rem; - max-width: 640px; -} - -.collection-card-date { - color: #d9d9d9; - font-size: var(--font-size-paragraph); -} - -.collection-card-title { - font-family: "Danzza", sans-serif; - font-size: 40px; - max-width: 80%; - font-weight: 700; -} - -.collection-card-title a { - transition: color 0.2s; -} - -.collection-card-title a:hover { - color: var(--color-primary); -} - -.collection-card-description { - color: #d9d9d9; - font-family: "Danzza", sans-serif; - font-size: var(--font-size-paragraph); - font-weight: 400; -} - -.collection-card-readmore { - color: var(--color-primary); - font-family: "Danzza", sans-serif; - font-size: var(--font-size-paragraph); - font-weight: 500; - text-transform: uppercase; -} - -.collection-card-readmore .arrow { - margin-left: 5px; -} - -/* --- Image --- */ -.collection-card-image img { - width: 300px; - height: 169px; - object-fit: cover; - transition: transform 0.3s; -} - -.collection-card-image img:hover { - transform: scale(1.05); -} - -.collection-card-image--featured img { - width: auto; - height: 300px; -} - -/* --- Divider --- */ -.collection-divider { - border: none; - border-top: 1px solid rgba(255, 255, 255, 0.15); - margin: 0; -} - -/* --- Featured --- */ -.collection-card--featured .collection-card-title { - font-size: 36px; - line-height: 1.3; -} - -/* --- Loading --- */ -.collection-loading { - text-align: center; - padding: 4rem 0; - opacity: 0.6; -} - -/* --- Mobile --- */ -@media (max-width: 700px) { - .collection-header { - padding: 4rem 0 2rem; - } - - .collection-header :global(h1) { - font-size: var(--font-size-title-main-mobile); - } - - .collection-header :global(p) { - font-size: var(--font-size-subtitle-mobile); - } - - .collection-card { - flex-direction: column; - } - - .collection-card-image img, - .collection-card-image--featured img { - width: 100%; - height: auto; - aspect-ratio: 16/9; - } - - .collection-card--featured .collection-card-title { - font-size: var(--font-size-title-section-mobile); - } - - .collection-card-title { - font-size: var(--font-size-title-section-mobile); - } -} - -/* --- Tablet --- */ -@media (min-width: 701px) and (max-width: 912px) { - .collection-header :global(h1) { - font-size: var(--font-size-title-main-tablet); - } - - .collection-card { - flex-direction: column; - } - - .collection-card-image img, - .collection-card-image--featured img { - width: 100%; - height: auto; - aspect-ratio: 16/9; - } -} diff --git a/src/styles/fonts.css b/src/styles/fonts.css index 33a5c1d..6b34a2a 100644 --- a/src/styles/fonts.css +++ b/src/styles/fonts.css @@ -65,7 +65,3 @@ background-clip: text; -webkit-background-clip: text; } - -.pixel { - font-family: "Terminal", sans-serif; -} diff --git a/src/styles/index.css b/src/styles/index.css index 0db6dc0..d437c36 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -3,7 +3,6 @@ @import './reset.css'; @import './fonts.css'; @import './layout.css'; -@import './collection.css'; @import './buttons.css'; @import './cursor.css'; @import './utils.css'; diff --git a/src/views/Blog.svelte b/src/views/Blog.svelte index aeb0029..d4295b6 100644 --- a/src/views/Blog.svelte +++ b/src/views/Blog.svelte @@ -95,11 +95,10 @@ } }) - // Reset après la fin de la transition de slide (1100ms) pour éviter le flash + // Reset article view when leaving the blog slide $effect(() => { if (!isActive && articleData) { - const timer = setTimeout(() => { articleData = null }, 1100) - return () => clearTimeout(timer) + articleData = null } }) @@ -107,7 +106,7 @@
{#if data?.intro} -
+
{@html data.intro}
{/if} {#if featured} -