Feat: footer reveal + refactor page About
All checks were successful
Deploy / Deploy to Production (push) Successful in 24s

- Footer global fixé en bas (App.svelte), masqué par le contenu des slides
- margin-bottom sur .page-scrollable pour l'effet footer reveal (about, blog, article)
- About : champ intro remplacé par heading (text) + subtitle (writer), blueprint + API + vue mis à jour
- LanguageSwitcher : div → button avec hitbox élargie
- i18n : clé our_team (fr: NOTRE ÉQUIPE / en: OUR TEAM)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
isUnknown 2026-03-17 10:00:53 +01:00
parent 61607f8cd7
commit b3b0580ab1
10 changed files with 148 additions and 130 deletions

View file

@ -18,23 +18,14 @@ tabs:
content: content:
type: fields type: fields
fields: fields:
intro: heading:
type: writer type: text
marks: label: Titre
- bold help: Titre principal de la section intro.
- italic subtitle:
- green type: text
- pixel
- underline
- strike
- clear
- link
nodes:
- heading
headings:
- 1
buttons: false buttons: false
help: Section de texte centrée. help: Texte d'accroche sous le titre.
body: body:
label: Corps label: Corps
type: blocks type: blocks
@ -77,6 +68,6 @@ tabs:
image: image:
ratio: 3/5 ratio: 3/5
cover: true cover: true
back: '#0e1e43' back: "#0e1e43"
text: "{{ file.memberName }}" text: "{{ file.memberName }}"
info: "{{ file.role }}" info: "{{ file.role }}"

View file

@ -11,7 +11,8 @@ foreach ($page->body()->toBlocks() as $block) {
} }
$specificData = [ $specificData = [
'intro' => $page->intro()->value(), 'heading' => $page->heading()->value(),
'subtitle' => $page->subtitle()->value(),
'body' => $bodyBlocks, 'body' => $bodyBlocks,
'team' => $page->files()->template('member')->sort('sort')->map(function ($file) { 'team' => $page->files()->template('member')->sort('sort')->map(function ($file) {
return [ return [

View file

@ -7,6 +7,7 @@
import Cursor from '@components/layout/Cursor.svelte' import Cursor from '@components/layout/Cursor.svelte'
import LanguageSwitcher from '@components/ui/LanguageSwitcher.svelte' import LanguageSwitcher from '@components/ui/LanguageSwitcher.svelte'
import Footer from '@components/layout/Footer.svelte'
import Home from '@views/Home.svelte' import Home from '@views/Home.svelte'
import About from '@views/About.svelte' import About from '@views/About.svelte'
import Expertise from '@views/Expertise.svelte' import Expertise from '@views/Expertise.svelte'
@ -95,6 +96,7 @@
{/each} {/each}
</div> </div>
</main> </main>
<Footer />
<LanguageSwitcher /> <LanguageSwitcher />
<style> <style>
@ -127,6 +129,7 @@
.main { .main {
position: relative; position: relative;
z-index: 1;
overflow: hidden; overflow: hidden;
height: 100vh; height: 100vh;
} }
@ -155,4 +158,12 @@
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
:global(.site-footer) {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 0;
}
</style> </style>

View file

@ -10,9 +10,9 @@
} }
</script> </script>
<div class="lang-switcher font-face-danzza-bold clickable" onclick={switchLanguage}> <button class="lang-switcher font-face-danzza-bold" onclick={switchLanguage}>
<p class="clickable">{locale.current === 'en' ? 'fr' : 'en'}</p> {locale.current === 'en' ? 'fr' : 'en'}
</div> </button>
<style> <style>
.lang-switcher { .lang-switcher {
@ -22,7 +22,9 @@
left: 4vh; left: 4vh;
text-transform: uppercase; text-transform: uppercase;
color: rgb(4, 254, 160); color: rgb(4, 254, 160);
display: block; background: none;
border: none;
cursor: pointer; cursor: pointer;
padding: 0.75rem 1rem;
} }
</style> </style>

View file

@ -45,6 +45,8 @@ const dict = {
legal: { fr: "Mentions légales", en: "Legal notice" }, legal: { fr: "Mentions légales", en: "Legal notice" },
cookies: { fr: "Préférences cookies", en: "Cookie preferences" }, cookies: { fr: "Préférences cookies", en: "Cookie preferences" },
privacy: { fr: "Confidentialité", en: "Privacy" }, privacy: { fr: "Confidentialité", en: "Privacy" },
// About
our_team: { fr: "NOTRE ÉQUIPE", en: "OUR TEAM" },
// Menu // Menu
menu: { fr: "MENU", en: "MENU" }, menu: { fr: "MENU", en: "MENU" },
connect: { fr: "CONNECT", en: "CONNECT" }, connect: { fr: "CONNECT", en: "CONNECT" },

View file

@ -17,12 +17,11 @@
.page-scrollable { .page-scrollable {
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
margin-bottom: var(--footer-height);
} }
.page-container { .page-scrollable .page-container {
max-width: 1200px; margin-bottom: var(--footer-height);
margin: 0 auto;
padding: 0 50px;
} }
/* Vertical Lines */ /* Vertical Lines */

View file

@ -52,6 +52,9 @@
--font-size-button-tablet: 12px; --font-size-button-tablet: 12px;
--font-size-caption-tablet: 11px; --font-size-caption-tablet: 11px;
/* Footer */
--footer-height: 18.75rem;
/* Easing */ /* Easing */
--ease-standard: cubic-bezier(0.65, 0, 0.35, 1); --ease-standard: cubic-bezier(0.65, 0, 0.35, 1);

View file

@ -1,11 +1,13 @@
<script> <script>
import { onMount } from 'svelte' import { onMount } from 'svelte'
import { slides } from '@state/slides.svelte' import { slides } from '@state/slides.svelte'
import Footer from '@components/layout/Footer.svelte'
import { t } from '@i18n'
let { data } = $props() let { data } = $props()
const intro = $derived(data?.intro ?? '') const heading = $derived(data?.heading ?? '')
const subtitle = $derived(data?.subtitle ?? '')
const body = $derived(data?.body ?? []) const body = $derived(data?.body ?? [])
const members = $derived(data?.team ?? []) const members = $derived(data?.team ?? [])
const isActive = $derived(slides.active?.id === 'about') const isActive = $derived(slides.active?.id === 'about')
@ -72,12 +74,13 @@
}) })
</script> </script>
<div class="about page-scrollable" bind:this={sectionEl}> <div class="about golden-grid page-scrollable" bind:this={sectionEl}>
<div class="page-container">
<!-- Intro --> <!-- Intro -->
<section class="about-intro"> <section class="about-intro">
<div class="about-intro-content"> <div class="about-intro-content">
{@html intro} {#if heading}<h1 class="heading">{heading}</h1>{/if}
<p class="subtitle">{subtitle}</p>
</div> </div>
</section> </section>
@ -97,7 +100,7 @@
<!-- Team carousel --> <!-- Team carousel -->
{#if members.length > 0} {#if members.length > 0}
<section class="about-team"> <section class="about-team">
<h2 class="about-team-heading">OUR TEAM</h2> <h2 class="about-team-heading">{t('our_team')}</h2>
<div class="team-carousel-container"> <div class="team-carousel-container">
<div <div
@ -150,8 +153,9 @@
</section> </section>
{/if} {/if}
<Footer />
</div> </div>
</div>
<style> <style>
.about { .about {
@ -161,15 +165,22 @@
overflow-x: hidden; overflow-x: hidden;
} }
.page-container {
grid-area: 6/6/span 7/span 10;
height: 100%;
place-self: center;
text-align: center;
white-space: pre-line;
width: 100%;
}
/* ── Intro ── */ /* ── Intro ── */
.about-intro { .about-intro {
display: flex; display: flex;
justify-content: center; justify-content: center;
padding: 8rem 3rem 2rem;
} }
.about-intro-content { .about-intro-content {
max-width: 800px;
text-align: center; text-align: center;
font-family: "Danzza", sans-serif; font-family: "Danzza", sans-serif;
font-size: var(--font-size-paragraph); font-size: var(--font-size-paragraph);
@ -194,20 +205,17 @@
color: #04fea0; color: #04fea0;
} }
.about-intro-content :global(p) { .about-intro-content .subtitle {
font-size: var(--font-size-subtitle); font-size: var(--font-size-subtitle);
font-weight: normal; font-weight: normal;
margin-top: 1.5rem; margin-top: 1.5rem;
text-align: center; text-align: center;
margin-top: 3.125rem;
padding-left: 1.25rem;
} }
/* ── Body blocks ── */ /* ── Body blocks ── */
.about-body {
max-width: 800px;
margin: 0 auto;
padding: 1rem 3rem 3rem;
}
.about-body-block { .about-body-block {
border-left: 2px solid #04fea0; border-left: 2px solid #04fea0;
padding-left: 20px; padding-left: 20px;
@ -221,12 +229,22 @@
} }
.about-body-block :global(h3) { .about-body-block :global(h3) {
font-family: "Terminal", sans-serif; font-family: Danzza Medium,sans-serif;
font-size: var(--font-size-subtitle); font-size: var(--font-size-paragraph);
color: #04fea0;
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.about-body-block :global(h3::before) {
content: '';
display: inline-block;
width: .6rem;
height: .6rem;
background-color: var(--color-primary);
margin-right: .6rem;
margin-bottom: .1rem;
}
.about-body-block :global(p) { .about-body-block :global(p) {
opacity: 0.9; opacity: 0.9;
margin-bottom: 0.75rem; margin-bottom: 0.75rem;

View file

@ -3,7 +3,7 @@
* Vue article — sous-composant de Blog.svelte. * Vue article — sous-composant de Blog.svelte.
* Reçoit les données article via props, pas via le slide system. * Reçoit les données article via props, pas via le slide system.
*/ */
import Footer from '@components/layout/Footer.svelte'
import { t } from '@i18n' import { t } from '@i18n'
let { data, onBack } = $props() let { data, onBack } = $props()
@ -114,7 +114,6 @@
{/if} {/if}
</article> </article>
<Footer />
</div> </div>
<style> <style>

View file

@ -2,7 +2,7 @@
import { onMount } from 'svelte' import { onMount } from 'svelte'
import { slides } from '@state/slides.svelte' import { slides } from '@state/slides.svelte'
import { locale } from '@state/locale.svelte' import { locale } from '@state/locale.svelte'
import Footer from '@components/layout/Footer.svelte'
import Article from '@views/Article.svelte' import Article from '@views/Article.svelte'
import { t } from '@i18n' import { t } from '@i18n'
@ -178,7 +178,6 @@
</div> </div>
<Footer />
{/if} {/if}
</section> </section>
@ -211,7 +210,6 @@
.page-container { .page-container {
max-width: none; max-width: none;
margin: 0;
padding: 0 10%; padding: 0 10%;
} }
@ -312,12 +310,6 @@
opacity: 0.6; opacity: 0.6;
} }
.blog :global(.site-footer) {
margin-left: -50px;
margin-right: -50px;
margin-top: 4rem;
}
/* --- Mobile --- */ /* --- Mobile --- */
@media (max-width: 700px) { @media (max-width: 700px) {
.blog-header { .blog-header {