layout.tsx
Raw
1import { OWNER_DISPLAY_NAME } from "../config.ts";
2import { displayName } from "../lib/users.ts";
3import type { SessionUser } from "../middleware/session.ts";
4import { Avatar } from "./Avatar.tsx";
5
6interface LayoutProps {
7 user: SessionUser | null;
8 title?: string;
9 children?: JSX.Element | JSX.Element[] | string | null;
10}
11
12export function Layout({ user, title, children }: LayoutProps) {
13 const pageTitle = title ? `${title} — Hearthforge` : "Hearthforge";
14 return (
15 <html lang="en">
16 <head>
17 <meta charset="UTF-8" />
18 <meta name="viewport" content="width=500" />
19 <title>{pageTitle}</title>
20 <script src="/assets/theme.js"></script>
21 <link
22 rel="icon"
23 type="image/svg+xml"
24 href="/assets/favicon.svg"
25 />
26 <link rel="stylesheet" href="/assets/main.css" />
27 <script src="/assets/jxl-polyfill.js" defer></script>
28 </head>
29 <body>
30 <header class="site-header">
31 <nav class="site-nav">
32 <a href="/" class="site-logo">
33 <img
34 src="/assets/favicon.svg"
35 class="logo-icon"
36 alt=""
37 aria-hidden="true"
38 />
39 <span class="logo-text">Hearthforge</span>
40 </a>
41 <div class="nav-links">
42 {user ? (
43 <>
44 <a href="/settings" class="nav-user">
45 <Avatar
46 userId={user.id}
47 version={user.avatar_version}
48 size={24}
49 />
50 {displayName(user.username)}
51 </a>
52 <form
53 method="POST"
54 action="/logout"
55 class="inline-form"
56 >
57 <button
58 type="submit"
59 class="btn btn-sm btn-ghost"
60 >
61 Sign out
62 </button>
63 </form>
64 </>
65 ) : (
66 <>
67 <a
68 href="/login"
69 class="btn btn-sm btn-ghost"
70 >
71 Sign in
72 </a>
73 <a
74 href="/register"
75 class="btn btn-sm btn-primary"
76 >
77 Register
78 </a>
79 </>
80 )}
81 </div>
82 </nav>
83 </header>
84 <main class="site-main">{children}</main>
85 <footer class="site-footer">
86 <p>Hearthforge — hosted by {OWNER_DISPLAY_NAME}</p>
87 </footer>
88 </body>
89 </html>
90 );
91}
92