WIP! A BB-style forum, on the ATmosphere!
We're still working... we'll be back soon when we have something to show off!
node
typescript
hono
htmx
atproto
1import type { FC, PropsWithChildren } from "hono/jsx";
2import { tokensToCss } from "../lib/theme.js";
3import neobrutalLight from "../styles/presets/neobrutal-light.json";
4import type { WebSession } from "../lib/session.js";
5
6const ROOT_CSS = `:root { ${tokensToCss(neobrutalLight as Record<string, string>)} }`;
7
8const NavContent: FC<{ auth?: WebSession }> = ({ auth }) => (
9 <>
10 {auth?.authenticated ? (
11 <>
12 <span class="site-header__handle">{auth.handle}</span>
13 <form action="/logout" method="post" class="site-header__logout-form">
14 <button type="submit" class="site-header__logout-btn">
15 Log out
16 </button>
17 </form>
18 </>
19 ) : (
20 <a href="/login" class="site-header__login-link">
21 Log in
22 </a>
23 )}
24 </>
25);
26
27export const BaseLayout: FC<
28 PropsWithChildren<{ title?: string; auth?: WebSession }>
29> = (props) => {
30 const { auth } = props;
31 return (
32 <html lang="en">
33 <head>
34 <meta charset="UTF-8" />
35 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
36 <title>{props.title ?? "atBB Forum"}</title>
37 <style>{ROOT_CSS}</style>
38 <link rel="preconnect" href="https://fonts.googleapis.com" />
39 <link
40 rel="stylesheet"
41 href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;700&display=swap"
42 />
43 <link rel="stylesheet" href="/static/css/reset.css" />
44 <link rel="stylesheet" href="/static/css/theme.css" />
45 <link rel="icon" type="image/svg+xml" href="/static/favicon.svg" />
46 <script src="https://unpkg.com/htmx.org@2.0.4" defer />
47 </head>
48 <body>
49 <a href="#main-content" class="skip-link">
50 Skip to main content
51 </a>
52 <header class="site-header">
53 <div class="site-header__inner">
54 <a href="/" class="site-header__title">
55 atBB Forum
56 </a>
57 <nav class="desktop-nav" aria-label="Main navigation">
58 <NavContent auth={auth} />
59 </nav>
60 <details class="mobile-nav">
61 <summary class="mobile-nav__toggle" aria-label="Menu">
62 ☰
63 </summary>
64 <nav class="mobile-nav__menu" aria-label="Mobile navigation">
65 <NavContent auth={auth} />
66 </nav>
67 </details>
68 </div>
69 </header>
70 <main id="main-content" class="content-container">
71 {props.children}
72 </main>
73 <footer class="site-footer">
74 <p>Powered by atBB on the ATmosphere</p>
75 </footer>
76 </body>
77 </html>
78 );
79};