Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

theme.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

theme.tsBlame64 lines · 1 contributor
6fc53bdClaude1/**
2 * Theme toggle — flips a "theme" cookie between dark and light.
3 * Cookie is read by both the SSR layout (via middleware-injected prop) and
4 * a pre-paint inline script to avoid FOUC.
5 */
6
7import { Hono } from "hono";
8import { getCookie, setCookie } from "hono/cookie";
9
10const theme = new Hono();
11
12function readTheme(c: any): "dark" | "light" {
13 const v = getCookie(c, "theme");
14 return v === "light" ? "light" : "dark";
15}
16
17function writeTheme(c: any, value: "dark" | "light") {
18 setCookie(c, "theme", value, {
19 path: "/",
20 maxAge: 60 * 60 * 24 * 365, // 1 year
21 sameSite: "Lax",
22 httpOnly: false, // must be readable by the pre-paint script
23 });
24}
25
26function redirectBack(c: any): Response {
27 const ref = c.req.header("referer");
28 // Only follow same-origin referers — anything else falls back to /.
29 try {
30 if (ref) {
31 const u = new URL(ref);
32 const host = c.req.header("host");
33 if (u.host === host) return c.redirect(u.pathname + u.search);
34 }
35 } catch {
36 // fall through
37 }
38 return c.redirect("/");
39}
40
41// GET /theme/toggle — flip current value, redirect back.
42// Lives outside /settings/* so it doesn't get blocked by the settings
43// auth middleware — theme should work for logged-out visitors too.
44theme.get("/theme/toggle", (c) => {
45 const next = readTheme(c) === "light" ? "dark" : "light";
46 writeTheme(c, next);
47 return redirectBack(c);
48});
49
50// GET /theme/set?mode=dark|light — explicit setter (for tests + API).
51theme.get("/theme/set", (c) => {
52 const mode = c.req.query("mode");
53 if (mode !== "dark" && mode !== "light") {
54 return c.json({ ok: false, error: "mode must be 'dark' or 'light'" }, 400);
55 }
56 writeTheme(c, mode);
57 if ((c.req.header("accept") || "").includes("application/json")) {
58 return c.json({ ok: true, theme: mode });
59 }
60 return redirectBack(c);
61});
62
63export { readTheme };
64export default theme;