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