feat: FE solid-ui (shadcn port) — Tailwind + 14 components, all pages rewritten
CI / go test + web typecheck (push) Canceled after 0s
CI / build + deploy (Nix) — flowsight (push) Canceled after 0s

This commit is contained in:
asepharyana committed 2026-09-15 17:40:39 +07:00
1 parent debc907188
commit 8392dbe724
34 files changed
+2390 -542

No files matched your search

+15 -11
View File
@@ -1,14 +1,15 @@
import { createResource, createSignal, Show } from "solid-js";
import { api, type AuthUser } from "../lib/api";
import { Button } from "./ui/button";
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar";
// AuthState: loads /api/auth/me once; exposes login/logout + theme toggle.
// Theme: .dark class on <html> (shadcn convention). Default dark.
function theme(): string {
return localStorage.getItem("fs-theme") ||
(matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark");
return localStorage.getItem("fs-theme") || "dark";
}
export function applyTheme(t: string) {
document.documentElement.dataset.theme = t;
document.documentElement.classList.toggle("dark", t === "dark");
localStorage.setItem("fs-theme", t);
}
applyTheme(theme());
@@ -16,12 +17,12 @@ applyTheme(theme());
export function ThemeToggle() {
const [t, setT] = createSignal(theme());
return (
<button class="fs-iconbtn" title="Toggle light/dark" onClick={() => {
<Button variant="ghost" size="icon" title="Toggle light/dark" onClick={() => {
const n = t() === "dark" ? "light" : "dark";
setT(n); applyTheme(n);
}}>
{t() === "dark" ? "☀️" : "🌙"}
</button>
</Button>
);
}
@@ -35,13 +36,16 @@ export function useAuth() {
export function AuthButton(props: { me: AuthUser | null | undefined; onLogout: () => void }) {
return (
<Show when={props.me} fallback={
<a class="fs-btn" href="/api/auth/start">Sign in with Google</a>
<a href="/api/auth/start"><Button>Sign in with Google</Button></a>
}>
{(u) => (
<span class="fs-user">
{u().avatar_url ? <img class="fs-avatar" src={u().avatar_url} alt="" /> : null}
{u().name || u().email}
<button class="fs-iconbtn" onClick={props.onLogout}>Logout</button>
<span class="flex items-center gap-2">
<Avatar class="size-8">
{u().avatar_url ? <AvatarImage src={u().avatar_url} alt="" /> : null}
<AvatarFallback>{(u().name || u().email || "?").slice(0, 1).toUpperCase()}</AvatarFallback>
</Avatar>
<span class="hidden text-sm font-medium md:inline">{u().name || u().email}</span>
<Button variant="ghost" size="sm" onClick={props.onLogout}>Logout</Button>
</span>
)}
</Show>