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
+36
View File
@@ -0,0 +1,36 @@
---
import { useDict } from '@i18n/t';
import type { Locale } from '@i18n/locales';
interface Props {
locale: Locale;
}
const { locale } = Astro.props;
const d = useDict(locale);
---
<button
id="theme-toggle"
type="button"
class="inline-flex h-9 w-9 items-center justify-center rounded-full border border-line text-ink-muted transition-colors duration-[--dur-quick] hover:text-ink"
aria-label={d.theme.toLight}
data-to-light={d.theme.toLight}
data-to-dark={d.theme.toDark}
>
{/* Moon (shown in dark) / Sun (shown in light) — swapped by CSS on [data-theme]. */}
<svg class="icon-moon" width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8Z"
stroke="currentColor"
stroke-width="1.6"
stroke-linejoin="round"></path>
</svg>
<svg class="icon-sun" width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<circle cx="12" cy="12" r="4" stroke="currentColor" stroke-width="1.6"></circle>
<path
d="M12 2v2M12 20v2M2 12h2M20 12h2M5 5l1.5 1.5M17.5 17.5 19 19M19 5l-1.5 1.5M6.5 17.5 5 19"
stroke="currentColor"
stroke-width="1.6"
stroke-linecap="round"></path>
</svg>
</button>