layout.tsx
Raw
1import config 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"
60 >
61 Sign out
62 </button>
63 </form>
64 </>
65 ) : (
66 <>
67 <a href="/login" class="btn btn-sm">
68 Sign in
69 </a>
70 <a
71 href="/register"
72 class="btn btn-sm btn-primary"
73 >
74 Register
75 </a>
76 </>
77 )}
78 </div>
79 </nav>
80 </header>
81 <main class="site-main">{children}</main>
82 <footer class="site-footer">
83 <p>Hearthforge — hosted by {config.OWNER_DISPLAY_NAME}</p>
84 </footer>
85 </body>
86 </html>
87 );
88}
89