main
1---
2import { Font } from "astro:assets";
3import { getIntlayer, type Locale } from "intlayer";
4import Footer from "@/components/Footer.astro";
5import Header from "@/components/Header.astro";
6import { DEFAULT_LOCALE, SITE_CONFIG } from "@/config";
7import {
8 getLocaleFeedUrl,
9 getPathWithoutLocale,
10 getRelativeLocaleUrl,
11 url,
12} from "@/utils/url.ts";
13
14import "sanitize.css/sanitize.css";
15import "@/styles/global.scss";
16
17interface Props {
18 title?: string;
19 author?: string;
20 description?: string;
21 availableLocales?: Locale[];
22 ogType?: "website" | "article";
23}
24
25const locale = Astro.currentLocale;
26const globalI18n = getIntlayer("global", locale);
27
28const {
29 title = SITE_CONFIG.title,
30 author = SITE_CONFIG.author,
31 description = globalI18n.description,
32 availableLocales = SITE_CONFIG.locales,
33 ogType = "website",
34} = Astro.props;
35
36const pageLocales = SITE_CONFIG.locales.filter((candidate) =>
37 availableLocales.includes(candidate),
38);
39
40if (!pageLocales.includes(DEFAULT_LOCALE)) {
41 throw new Error(
42 `Page ${Astro.url.pathname} must be built for the default locale "${DEFAULT_LOCALE}".`,
43 );
44}
45
46const getAbsoluteLocaleUrl = (path: string, locale: Locale) =>
47 new URL(getRelativeLocaleUrl(path, locale), Astro.site).toString();
48---
49
50<!doctype html>
51<html lang={locale}>
52 <head>
53 <meta charset="utf-8">
54 <meta name="viewport" content="width=device-width">
55 <meta name="generator" content={Astro.generator}>
56
57 <link rel="icon" type="image/svg+xml" href="/favicon.svg">
58 <link rel="icon" href="/favicon.ico">
59 <link rel="sitemap" href="/sitemap-index.xml">
60 <link
61 rel="alternate"
62 type="application/atom+xml"
63 hreflang={locale ?? DEFAULT_LOCALE}
64 title="Atom Feed"
65 href={getLocaleFeedUrl(locale ?? DEFAULT_LOCALE)}
66 >
67 <link
68 rel="alternate"
69 type="application/atom+xml"
70 title="Atom Feed"
71 href={url("/feed.atom")}
72 >
73
74 <title>{title}</title>
75 <meta name="title" content={title}>
76 <meta name="description" content={description}>
77 <meta name="author" content={author}>
78
79 {pageLocales.map((target) => (
80 <link
81 rel="alternate"
82 hreflang={target}
83 href={getAbsoluteLocaleUrl(
84 getPathWithoutLocale(Astro.url.pathname),
85 target,
86 )}
87 >
88 ))}
89 <link
90 rel="alternate"
91 hreflang="x-default"
92 href={getAbsoluteLocaleUrl(
93 getPathWithoutLocale(Astro.url.pathname),
94 DEFAULT_LOCALE,
95 )}
96 >
97
98 <meta property="og:url" content={Astro.url}>
99 <meta property="og:site_name" content={SITE_CONFIG.title}>
100 <meta property="og:title" content={title}>
101 <meta property="og:description" content={description}>
102 <meta property="og:locale" content={locale}>
103 <meta property="og:type" content={ogType}>
104
105 <meta name="robots" content="noindex, nofollow">
106
107 <Font cssVariable="--font-stix-two-math" />
108 </head>
109 <body>
110 <Header availableLocales={pageLocales} />
111 <main>
112 <slot />
113 </main>
114 <Footer />
115 </body>
116</html>
117
118<style lang="scss" is:global>
119body {
120 min-height: 100dvh;
121 max-width: 67rem;
122 margin-inline: auto;
123 padding-inline: 1rem;
124 display: flex;
125 flex-direction: column;
126
127 > main {
128 flex: 1;
129 }
130}
131</style>