1---
2import Header from '../components/Header.astro';
3import Footer from '../components/Footer.astro';
4import '../styles/footer.css';
5
6interface Props {
7 title: string;
8 description?: string;
9 activeNav?: 'home' | 'designing' | 'docs' | 'slop' | 'live';
10 canonicalPath?: string;
11 bodyClass?: string;
12 noIndex?: boolean;
13 mainId?: string;
14 mainClass?: string;
15 hideHeader?: boolean;
16 hideFooter?: boolean;
17 ogTitle?: string;
18 ogDescription?: string;
19 ogImage?: string;
20 twitterSite?: string;
21 twitterCreator?: string;
22}
23
24const {
25 title,
26 description = 'Design fluency for AI-assisted frontend development.',
27 activeNav,
28 canonicalPath,
29 bodyClass,
30 noIndex = false,
31 mainId = 'main',
32 mainClass,
33 hideHeader = false,
34 hideFooter = false,
35 ogTitle,
36 ogDescription,
37 ogImage,
38 twitterSite,
39 twitterCreator,
40} = Astro.props;
41
42const canonical = canonicalPath
43 ? `https://impeccable.style${canonicalPath}`
44 : undefined;
45---
46
47<!DOCTYPE html>
48<html lang="en">
49<head>
50 <meta charset="UTF-8">
51 <meta name="viewport" content="width=device-width, initial-scale=1.0">
52 <title>{title}</title>
53 <meta name="description" content={description}>
54 <meta name="theme-color" content="#fafafa">
55 {noIndex && <meta name="robots" content="noindex">}
56 {canonical && <link rel="canonical" href={canonical}>}
57
58 {ogTitle && (
59 <>
60 <meta property="og:type" content="website">
61 <meta property="og:url" content={canonical || 'https://impeccable.style'}>
62 <meta property="og:title" content={ogTitle}>
63 <meta property="og:description" content={ogDescription || description}>
64 {ogImage && <meta property="og:image" content={ogImage}>}
65 </>
66 )}
67
68 {twitterSite && (
69 <>
70 <meta name="twitter:card" content="summary_large_image">
71 <meta name="twitter:site" content={twitterSite}>
72 {twitterCreator && <meta name="twitter:creator" content={twitterCreator}>}
73 <meta name="twitter:title" content={ogTitle || title}>
74 <meta name="twitter:description" content={ogDescription || description}>
75 {ogImage && <meta name="twitter:image" content={ogImage}>}
76 </>
77 )}
78
79 <link rel="icon" type="image/svg+xml" href="/favicon.svg">
80 <link rel="preconnect" href="https://fonts.googleapis.com">
81 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
82 <link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;0,700;1,300;1,400&family=Instrument+Sans:wght@400;500;600;700&family=Inter:wght@400;500;600&family=Space+Grotesk:wght@400;500;600&display=swap" rel="stylesheet">
83 <slot name="head" />
84</head>
85<body class={bodyClass}>
86 <a href={`#${mainId}`} class="skip-link">Skip to content</a>
87 <slot name="before-header" />
88 {!hideHeader && <Header activeNav={activeNav} />}
89 <slot name="after-header" />
90 <main id={mainId} class={mainClass}>
91 <slot />
92 </main>
93 {!hideFooter && <Footer />}
94 <slot name="scripts" />
95</body>
96</html>