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 <script src="/assets/app.js" defer></script>
29 </head>
30 <body>
31 <header class="site-header">
32 <nav class="site-nav">
33 <a href="/" class="site-logo">
34 <img
35 src="/assets/favicon.svg"
36 class="logo-icon"
37 alt=""
38 aria-hidden="true"
39 />
40 <span class="logo-text">Hearthforge</span>
41 </a>
42 <div class="nav-links">
43 {user ? (
44 <>
45 <a href="/settings" class="nav-user">
46 <Avatar
47 userId={user.id}
48 version={user.avatar_version}
49 size={24}
50 />
51 {displayName(user.username)}
52 </a>
53 <form
54 method="POST"
55 action="/logout"
56 class="inline-form"
57 >
58 <button
59 type="submit"
60 class="btn btn-sm"
61 >
62 Sign out
63 </button>
64 </form>
65 </>
66 ) : (
67 <>
68 <a href="/login" class="btn btn-sm">
69 Sign in
70 </a>
71 <a
72 href="/register"
73 class="btn btn-sm btn-primary"
74 >
75 Register
76 </a>
77 </>
78 )}
79 </div>
80 </nav>
81 </header>
82 <main class="site-main">{children}</main>
83 <footer class="site-footer">
84 <p>Hearthforge — hosted by {config.OWNER_DISPLAY_NAME}</p>
85 </footer>
86 </body>
87 </html>
88 );
89}
90