feat: core layout, UI atoms, homepage + behaviour modules

- UI atoms: Chip, Button, SplitCvButton, LangSwitch, ThemeToggle, Card,
  SectionLabel, TraceMotif, FramedImage
- core: Base/Seo/Header/MobileNav/Footer/HintBar/SkipLink/ThemeScript
- homepage sections: Hero, ProofStrip, SkillsGrid, ProjectCards,
  ExperienceTimeline, AboutTeaser, ContactBand + Homepage composition (EN/NO)
- behaviour modules: theme, nav (overlay/hint/copy/header), observer (reveal/spy),
  lightbox, form — progressive enhancement, fail-silent
- SEO head component: meta, hreflang from slug map, JSON-LD, OG references
- move content data to src/data (avoid Astro reserved content-collection folder)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cesnimda
2026-07-04 01:20:46 +02:00
parent 2184a1892f
commit 1fce1b3cec
45 changed files with 1891 additions and 27 deletions
+67
View File
@@ -0,0 +1,67 @@
---
import '@fontsource-variable/space-grotesk';
import '@fontsource-variable/inter';
import '@fontsource-variable/jetbrains-mono';
import '@styles/global.css';
import type { Locale } from '@i18n/locales';
import { HTML_LANG } from '@i18n/locales';
import type { PageId } from '@i18n/slugMap';
import Seo from '@components/core/Seo.astro';
import ThemeScript from '@components/core/ThemeScript.astro';
import SkipLink from '@components/core/SkipLink.astro';
import Header from '@components/core/Header.astro';
import HintBar from '@components/core/HintBar.astro';
import Footer from '@components/core/Footer.astro';
interface Props {
locale: Locale;
pageId: PageId;
title: string;
description: string;
ogType?: 'website' | 'profile' | 'article';
jsonLdOpts?: {
projectName?: string;
projectType?: 'SoftwareApplication' | 'SoftwareSourceCode';
};
mainClass?: string;
}
const { locale, pageId, title, description, ogType, jsonLdOpts, mainClass } = Astro.props;
---
<!doctype html>
<html lang={HTML_LANG[locale]} data-theme="dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<ThemeScript />
<Seo
locale={locale}
pageId={pageId}
title={title}
description={description}
ogType={ogType}
jsonLdOpts={jsonLdOpts}
/>
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<meta name="theme-color" content="#0B0E14" />
<slot name="head" />
</head>
<body>
<div id="scroll-sentinel" aria-hidden="true" class="pointer-events-none absolute top-0 h-24 w-px"></div>
<SkipLink locale={locale} />
<Header locale={locale} pageId={pageId} />
{locale === 'en' && <HintBar locale={locale} pageId={pageId} />}
<main id="main" class={mainClass}>
<slot />
</main>
<Footer locale={locale} pageId={pageId} />
{/* Global progressive-enhancement modules (deferred, fail-silent). */}
<script>
import '@scripts/theme';
import '@scripts/nav';
import '@scripts/observer';
</script>
</body>
</html>