1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
// @ts-types="corvos/mod.ts"
import { getGenerator, type Select } from "corvos/mod.ts";
import site from "@/corvos.config.ts";
import { SiteFooter } from "../components/SiteFooter.tsx";
import { SiteNav } from "../components/SiteNav.tsx";
import { Lightbox } from "../objects/Lightbox.tsx";
export interface Props {
page: Select<typeof site, ".html">;
pages: readonly Select<typeof site>[];
image?: string;
theme?: "l1" | "l2" | null;
children?: JSX.Element;
class?: unknown;
}
export const BaseLayout = async ({
page,
pages,
theme = "l1",
image: imageUrl,
children,
class: cls,
}: Props) => {
const query = site.$.query(pages);
const stylesheet = await site.load("styles/style.scss");
const script = await site.load("scripts/script.ts");
const fonts = await site.glob("assets/**.woff2");
const favicon = await site.load("assets/favicon.svg");
const image = await site.load(
imageUrl ?? "https://strapi.volpeon.ink/uploads/icon_7999cf625e.png",
);
const feeds = query.type(".rss").many();
return (
<>
{{ __html: "<!DOCTYPE html>" }}
<html lang="en">
<head>
<meta charset="utf-8" />
<meta content="light dark" name="color-scheme" />
<meta content="width=device-width, initial-scale=1" name="viewport" />
<meta content="scale" name="text-scale" />
<link href={site.$.url("sitemap.xml")} rel="sitemap" />
<link href={favicon.url} rel="icon" type="image/svg+xml" />
{fonts.map((font) => (
<link as="font" href={font.url} rel="preload" type="font/woff2" />
))}
<style>@layer scope, theme, object, layout, component, utility;</style>
<link rel="stylesheet" href={stylesheet.url} />
<script src={script.url} defer />
{feeds.map((feed) => (
<link
rel="alternate"
href={feed.url}
title={feed.data.title}
type="application/rss+xml"
/>
))}
<title>
{page.data.title}
{page.data.type === "home" ? "" : " · Corvos"}
</title>
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Corvos" />
<meta property="og:locale" content="en" />
{"description" in page.data && page.data.description && (
<>
<meta property="og:description" content={page.data.description} />
<meta name="description" content={page.data.description} />
</>
)}
<meta property="og:url" content={site.$.url("", true)} />
<meta property="og:image" content={image.url} />
<meta name="twitter:card" content={imageUrl ? "summary_large_image" : "summary"} />
<meta name="generator" content={getGenerator()} />
</head>
<body class:list={["t-no-js", { [`t-${theme}`]: theme }, cls]}>
{children}
<SiteFooter />
<SiteNav url={page.url} />
<Lightbox />
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="u-d-none"
>
<title>Loading indicator</title>
<symbol id="loading-indicator" viewBox="0 0 50 50">
<circle
cx="25"
cy="25"
r="20"
fill="none"
stroke="currentColor"
stroke-width=".4em"
stroke-linecap="round"
stroke-dasharray="1 200"
stroke-dashoffset="0"
stroke-miterlimit="10"
transform-origin="center center"
>
<animate
attributeName="stroke-dasharray"
keyTimes="0;0.5;1"
values="1 200;89 200;89 200"
dur="2s"
repeatCount="indefinite"
/>
<animate
attributeName="stroke-dashoffset"
keyTimes="0;0.5;1"
values="0;-35;-124"
dur="2s"
repeatCount="indefinite"
/>
<animateTransform
attributeName="transform"
type="rotate"
from="0"
to="360"
dur="1.3s"
repeatCount="indefinite"
/>
</circle>
</symbol>
</svg>
</body>
</html>
</>
);
};
|