Modernize Electron Rare mobile header

This commit is contained in:
Clément SAILLANT
2026-03-14 20:15:30 +00:00
parent 6187506c62
commit a3ccc1c92b
7 changed files with 519 additions and 51 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ function resolveBaseUrl() {
}
if (target === 'production' || target === 'prod') {
return process.env.PUBLIC_SITE_URL_PROD || process.env.PUBLIC_SITE_URL;
return process.env['PUBLIC_SITE_URL_PROD'] || process.env.PUBLIC_SITE_URL;
}
throw new Error(`Unknown target "${target}". Use "preview" or "production".`);
+75
View File
@@ -0,0 +1,75 @@
---
interface NavItem {
href: string;
label: string;
current?: boolean;
attrs?: Record<string, string>;
desktopOnly?: boolean;
}
interface Props {
brandHref: string;
items: NavItem[];
kicker?: string;
quickHref?: string;
quickLabel?: string;
quickAttrs?: Record<string, string>;
}
const {
brandHref,
items,
kicker = 'Design électronique · Consulting · Formation',
quickHref,
quickLabel = 'Contact',
quickAttrs = {}
} = Astro.props;
---
<header class="sticky top-0 z-30 site-nav site-header">
<div class="site-shell site-header-shell">
<a href={brandHref} class="site-header-brand figma-lab-nav-title">
<span class="site-header-brand-title">L'électron rare</span>
<span class="site-header-brand-kicker figma-lab-nav-kicker">{kicker}</span>
</a>
<div class="site-header-right">
{
quickHref && (
<a href={quickHref} class="site-header-quick-link figma-lab-nav-link site-navlink" {...quickAttrs}>
{quickLabel}
</a>
)
}
<details class="site-header-menu" data-nav-menu>
<summary class="site-header-menu-toggle" aria-label="Ouvrir la navigation principale">
<span class="site-header-menu-label">Menu</span>
<span class="site-header-menu-icon" aria-hidden="true">
<span></span>
<span></span>
</span>
</summary>
<nav class="site-header-primary" aria-label="Navigation principale">
<ul class="figma-lab-nav-list site-header-list">
{
items.map((item) => (
<li class:list={['site-header-item', item.desktopOnly && 'site-header-item--desktop-only']}>
<a
href={item.href}
class:list={['figma-lab-nav-link', 'site-navlink', item.current && 'is-active']}
aria-current={item.current ? 'page' : undefined}
{...(item.attrs ?? {})}
>
{item.label}
</a>
</li>
))
}
</ul>
</nav>
</details>
</div>
</div>
</header>
+69
View File
@@ -531,6 +531,75 @@ const structuredDataJsonLd = JSON.stringify({
})();
</script>
<script is:inline>
(function () {
var menus = Array.prototype.slice.call(document.querySelectorAll('[data-nav-menu]'));
if (!menus.length) {
return;
}
var syncMenuState = function (menu) {
var summary = menu.querySelector('summary');
if (!summary) {
return;
}
summary.setAttribute('aria-expanded', menu.hasAttribute('open') ? 'true' : 'false');
};
var closeMenu = function (menu) {
if (!menu.hasAttribute('open')) {
return;
}
menu.removeAttribute('open');
syncMenuState(menu);
};
for (var i = 0; i < menus.length; i += 1) {
var menu = menus[i];
syncMenuState(menu);
menu.addEventListener('toggle', function () {
syncMenuState(this);
});
var links = menu.querySelectorAll('a');
for (var l = 0; l < links.length; l += 1) {
links[l].addEventListener('click', function () {
var parentMenu = this.closest('[data-nav-menu]');
if (parentMenu) {
closeMenu(parentMenu);
}
});
}
}
document.addEventListener('click', function (event) {
for (var i = 0; i < menus.length; i += 1) {
if (!menus[i].contains(event.target)) {
closeMenu(menus[i]);
}
}
});
document.addEventListener('keydown', function (event) {
if (event.key !== 'Escape') {
return;
}
for (var i = 0; i < menus.length; i += 1) {
closeMenu(menus[i]);
}
});
window.addEventListener('resize', function () {
if (window.innerWidth >= 768) {
for (var i = 0; i < menus.length; i += 1) {
closeMenu(menus[i]);
}
}
});
})();
</script>
<script is:inline>
(function () {
var items = Array.prototype.slice.call(document.querySelectorAll('[data-reveal]'));
+8 -16
View File
@@ -2,6 +2,7 @@
import BaseLayout from '@/layouts/BaseLayout.astro';
import '@/styles/global.css';
import '@/styles/home-workbench.css';
import SiteHeader from '@/components/SiteHeader.astro';
import { withSiteBase } from '@/lib/site';
import { TRACK_EVENTS, trackAttrs } from '@/lib/tracking';
@@ -14,25 +15,16 @@ const formationHref = withSiteBase('/formation/');
const contactHref = withSiteBase('/#contact');
const labHref = withSiteBase('/lab/');
const mentionsHref = withSiteBase('/mentions-legales/');
const headerItems = [
{ href: homeAboutHref, label: 'Approche' },
{ href: homeMissionsHref, label: 'Missions' },
{ href: formationHref, label: 'Formation', current: true },
{ href: contactHref, label: 'Contact', desktopOnly: true }
];
---
<BaseLayout title={title} description={description} ogDescription="Formations sur mesure en électronique embarquée : PCB, IoT, automatisme industriel. 1 jour, 3 jours ou programme dédié. Écoles, entreprises, centres de formation.">
<header class="sticky top-0 z-30 site-nav">
<div class="site-shell figma-lab-nav-row">
<a href={homeHref} class="figma-lab-nav-title">
<span>L'électron rare</span>
<span class="figma-lab-nav-kicker">Design électronique · Consulting · Formation</span>
</a>
<nav aria-label="Navigation principale">
<ul class="figma-lab-nav-list">
<li><a href={homeAboutHref} class="figma-lab-nav-link site-navlink">Approche</a></li>
<li><a href={homeMissionsHref} class="figma-lab-nav-link site-navlink">Missions</a></li>
<li><a href={formationHref} class="figma-lab-nav-link site-navlink is-active" aria-current="page">Formation</a></li>
<li><a href={contactHref} class="figma-lab-nav-link site-navlink">Contact</a></li>
</ul>
</nav>
</div>
</header>
<SiteHeader brandHref={homeHref} items={headerItems} quickHref={contactHref} />
<main id="main-content" class="site-shell studio-structure pb-12 pt-3">
+10 -18
View File
@@ -2,6 +2,7 @@
import BaseLayout from '@/layouts/BaseLayout.astro';
import '@/styles/global.css';
import '@/styles/home-workbench.css';
import SiteHeader from '@/components/SiteHeader.astro';
import { Hero } from '@/components/sections/Hero';
import { About } from '@/components/sections/About';
import { CaseStudies } from '@/components/sections/CaseStudies';
@@ -14,27 +15,18 @@ import { TRACK_EVENTS, trackAttrs } from '@/lib/tracking';
const formationHref = withSiteBase('/formation/');
const labHref = withSiteBase('/lab/');
const mentionsHref = withSiteBase('/mentions-legales/');
const headerItems = [
{ href: '#a-propos', label: 'Approche' },
{ href: '#graphic-sprints-title', label: 'Missions' },
{ href: formationHref, label: 'Formation' },
{ href: labHref, label: 'Lab', attrs: trackAttrs(TRACK_EVENTS.ctaLabInteractifOpen, labHref) },
{ href: '#faq', label: 'FAQ' },
{ href: '#contact', label: 'Contact', desktopOnly: true }
];
---
<BaseLayout>
<header class="sticky top-0 z-30 site-nav">
<div class="site-shell figma-lab-nav-row">
<a href="#top" class="figma-lab-nav-title">
<span>L'électron rare</span>
<span class="figma-lab-nav-kicker">Design électronique · Consulting · Formation</span>
</a>
<nav aria-label="Navigation principale">
<ul class="figma-lab-nav-list">
<li><a href="#a-propos" class="figma-lab-nav-link site-navlink">Approche</a></li>
<li><a href="#graphic-sprints-title" class="figma-lab-nav-link site-navlink">Missions</a></li>
<li><a href={formationHref} class="figma-lab-nav-link site-navlink">Formation</a></li>
<li><a href={labHref} class="figma-lab-nav-link site-navlink" {...trackAttrs(TRACK_EVENTS.ctaLabInteractifOpen, labHref)}>Lab</a></li>
<li><a href="#faq" class="figma-lab-nav-link site-navlink">FAQ</a></li>
<li><a href="#contact" class="figma-lab-nav-link site-navlink">Contact</a></li>
</ul>
</nav>
</div>
</header>
<SiteHeader brandHref="#top" items={headerItems} quickHref="#contact" />
<main id="main-content" class="site-shell studio-structure pb-12 pt-3">
<section class="structure-grid structure-grid--hero" data-reveal>
+8 -16
View File
@@ -2,6 +2,7 @@
import BaseLayout from '@/layouts/BaseLayout.astro';
import '@/styles/global.css';
import '@/styles/home-workbench.css';
import SiteHeader from '@/components/SiteHeader.astro';
import { withSiteBase } from '@/lib/site';
const title = "Mentions légales — L'électron rare";
@@ -13,25 +14,16 @@ const formationHref = withSiteBase('/formation/');
const contactHref = withSiteBase('/#contact');
const labHref = withSiteBase('/lab/');
const mentionsHref = withSiteBase('/mentions-legales/');
const headerItems = [
{ href: homeAboutHref, label: 'Approche' },
{ href: homeMissionsHref, label: 'Missions' },
{ href: formationHref, label: 'Formation' },
{ href: contactHref, label: 'Contact', desktopOnly: true }
];
---
<BaseLayout title={title} description={description}>
<header class="sticky top-0 z-30 site-nav">
<div class="site-shell figma-lab-nav-row">
<a href={homeHref} class="figma-lab-nav-title">
<span>L'électron rare</span>
<span class="figma-lab-nav-kicker">Design électronique · Consulting · Formation</span>
</a>
<nav aria-label="Navigation principale">
<ul class="figma-lab-nav-list">
<li><a href={homeAboutHref} class="figma-lab-nav-link site-navlink">Approche</a></li>
<li><a href={homeMissionsHref} class="figma-lab-nav-link site-navlink">Missions</a></li>
<li><a href={formationHref} class="figma-lab-nav-link site-navlink">Formation</a></li>
<li><a href={contactHref} class="figma-lab-nav-link site-navlink">Contact</a></li>
</ul>
</nav>
</div>
</header>
<SiteHeader brandHref={homeHref} items={headerItems} quickHref={contactHref} />
<main id="main-content" class="site-shell studio-structure pb-12 pt-3">
+348
View File
@@ -5214,3 +5214,351 @@ input.contact-minitel-textarea:focus {
background: #ffffff;
color: #0b0a09;
}
/* Responsive header system */
.site-header.site-nav {
overflow: visible;
}
.site-header-shell {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 0.75rem;
min-height: 4rem;
padding-top: 0.55rem;
padding-bottom: 0.55rem;
}
.site-header-brand {
min-width: 0;
display: grid;
gap: 0.12rem;
text-decoration: none;
}
.site-header-brand-title {
display: block;
min-width: 0;
}
.site-header-brand-kicker {
display: block;
}
.site-header-right {
display: flex;
align-items: center;
justify-self: end;
gap: 0.5rem;
}
.site-header-quick-link {
display: none;
}
.site-header-menu {
position: relative;
}
.site-header-menu > summary {
list-style: none;
}
.site-header-menu > summary::-webkit-details-marker {
display: none;
}
.site-header-menu-toggle {
min-height: 2.45rem;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.6rem;
padding: 0.45rem 0.88rem;
border: 1px solid rgba(125, 99, 77, 0.18);
border-radius: 999px;
background: rgba(255, 252, 248, 0.92);
color: #241912;
cursor: pointer;
user-select: none;
font-family: "IBM Plex Mono", ui-monospace, Menlo, Consolas, monospace;
font-size: 0.68rem;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
box-shadow: 0 8px 18px rgba(95, 73, 55, 0.08);
transition:
background-color 0.16s ease,
border-color 0.16s ease,
box-shadow 0.16s ease,
transform 0.16s ease;
}
.site-header-menu-toggle:hover,
.site-header-menu-toggle:focus-visible {
border-color: rgba(183, 86, 44, 0.34);
background: rgba(255, 255, 255, 0.98);
box-shadow: 0 12px 24px rgba(95, 73, 55, 0.12);
transform: translateY(-1px);
}
.site-header-menu-label {
white-space: nowrap;
}
.site-header-menu-icon {
width: 1rem;
height: 0.8rem;
display: grid;
align-content: center;
gap: 0.22rem;
}
.site-header-menu-icon span {
display: block;
width: 100%;
height: 2px;
border-radius: 999px;
background: currentColor;
transition:
transform 0.18s ease,
opacity 0.18s ease;
}
.site-header-menu[open] .site-header-menu-icon span:first-child {
transform: translateY(4px) rotate(45deg);
}
.site-header-menu[open] .site-header-menu-icon span:last-child {
transform: translateY(-4px) rotate(-45deg);
}
.site-header-primary {
display: none;
}
.site-header-menu[open] .site-header-primary {
display: block;
}
.site-header-primary {
position: absolute;
top: calc(100% + 0.65rem);
right: 0;
width: min(22rem, calc(100vw - 1rem));
padding: 0.72rem;
border: 1px solid rgba(123, 97, 74, 0.16);
border-radius: 1rem;
background:
linear-gradient(180deg, rgba(255, 252, 247, 0.98), rgba(244, 235, 224, 0.96)),
linear-gradient(135deg, rgba(183, 86, 44, 0.06), transparent 42%);
box-shadow:
0 24px 48px rgba(95, 73, 55, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.55);
backdrop-filter: blur(18px);
}
.site-header-list {
margin: 0;
padding: 0;
list-style: none;
display: grid;
gap: 0.5rem;
}
.site-header-list .figma-lab-nav-link,
.site-header-list .site-navlink {
width: 100%;
justify-content: flex-start;
}
.site-header-item--desktop-only {
display: none;
}
.site-nav.is-compact .site-header-shell {
min-height: 3.5rem;
padding-top: 0.38rem;
padding-bottom: 0.38rem;
}
@media (min-width: 768px) {
.site-header-shell {
grid-template-columns: minmax(0, auto) 1fr;
gap: 1rem;
min-height: 4.15rem;
}
.site-header-right {
min-width: 0;
width: 100%;
}
.site-header-menu {
width: 100%;
}
.site-header-menu-toggle {
display: none;
}
.site-header-primary {
position: static;
display: block;
width: auto;
padding: 0;
border: 0;
border-radius: 0;
background: none;
box-shadow: none;
backdrop-filter: none;
}
.site-header-list {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
gap: 0.65rem;
}
.site-header-list .figma-lab-nav-link,
.site-header-list .site-navlink {
width: auto;
justify-content: center;
}
.site-header-item--desktop-only {
display: list-item;
}
}
@media (max-width: 767px) {
.site-header-shell {
min-height: 3.35rem;
gap: 0.55rem;
padding-top: 0.42rem;
padding-bottom: 0.42rem;
}
.site-header-brand {
gap: 0;
}
.site-header-brand-title {
max-width: 100%;
font-size: 1rem;
line-height: 1.02;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.site-header-brand-kicker {
display: none;
}
.site-header-right {
gap: 0.42rem;
}
.site-header-quick-link {
min-height: 2.45rem;
display: inline-flex;
align-items: center;
justify-content: center;
padding-inline: 0.82rem;
font-size: 0.66rem;
letter-spacing: 0.08em;
white-space: nowrap;
}
.site-header-menu-toggle {
padding-inline: 0.78rem;
}
.site-header-primary {
max-height: min(74vh, 28rem);
overflow: auto;
-webkit-overflow-scrolling: touch;
}
.site-header-list .figma-lab-nav-link,
.site-header-list .site-navlink {
min-height: 2.75rem;
padding-inline: 0.95rem;
font-size: 0.69rem;
}
}
@media (max-width: 420px) {
.site-header-shell {
grid-template-columns: minmax(0, 1fr);
}
.site-header-right {
width: 100%;
justify-content: stretch;
}
.site-header-quick-link,
.site-header-menu {
flex: 1 1 0;
}
.site-header-quick-link,
.site-header-menu-toggle {
width: 100%;
}
.site-header-primary {
width: 100%;
left: 0;
right: auto;
}
}
:root[data-da-variant="v12"] .site-header-brand {
color: #241912;
}
:root[data-da-variant="v12"] .site-header-brand-title {
font-family: "Fraunces", "Times New Roman", serif;
font-size: clamp(1rem, 1.45vw, 1.16rem);
font-weight: 700;
letter-spacing: 0.01em;
text-transform: none;
}
:root[data-da-variant="v12"] .site-header-brand-kicker {
color: #7c6556;
font-family: "IBM Plex Mono", ui-monospace, Menlo, Consolas, monospace;
font-size: 0.62rem;
font-weight: 500;
letter-spacing: 0.08em;
text-transform: uppercase;
}
:root[data-da-variant="v12"][data-theme="high-contrast"] .site-header-menu-toggle {
border-color: rgba(15, 15, 15, 0.14);
background: rgba(255, 255, 255, 0.92);
color: #1e1712;
box-shadow: 0 10px 20px rgba(66, 45, 31, 0.08);
}
:root[data-da-variant="v12"][data-theme="high-contrast"] .site-header-menu-toggle:hover,
:root[data-da-variant="v12"][data-theme="high-contrast"] .site-header-menu-toggle:focus-visible {
border-color: rgba(183, 86, 44, 0.28);
background: rgba(255, 255, 255, 1);
box-shadow: 0 14px 28px rgba(66, 45, 31, 0.12);
}
:root[data-da-variant="v12"][data-theme="high-contrast"] .site-header-primary {
border-color: rgba(80, 61, 46, 0.14);
background:
linear-gradient(180deg, rgba(255, 252, 248, 0.99), rgba(246, 239, 231, 0.98)),
linear-gradient(135deg, rgba(183, 86, 44, 0.04), transparent 46%);
box-shadow:
0 26px 52px rgba(87, 63, 44, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.75);
}