feat(toolrate): light/dark/system theme toggle with FOUC guard
Build & Push Docker Image / build (push) Successful in 2m30s

- use-theme hook: localStorage (toolrate-theme, default system), matchMedia
  change listener, shared singleton listener, sets .dark + color-scheme
- ThemeToggle: lightbulb quick toggle (light/dark) + dropdown (light/dark/system)
- Sidebar footer + mobile header + standalone login page
- inline script in index.html to apply theme pre-render (no FOUC)
- recharts axis ticks use hsl(var(--foreground)) for dark-mode readability
This commit is contained in:
opencode
2026-08-01 19:47:39 +02:00
parent db397a14bc
commit d244a537ea
7 changed files with 199 additions and 18 deletions
+4 -4
View File
@@ -119,8 +119,8 @@ export default function Analytics() {
<ResponsiveContainer width="100%" height="100%">
<BarChart data={topToolsChartData} margin={{ top: 20, right: 30, left: 0, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="hsl(var(--border))" />
<XAxis dataKey="name" tickLine={false} axisLine={false} />
<YAxis domain={[0, 5]} tickLine={false} axisLine={false} tickFormatter={(v) => `${v}`} />
<XAxis dataKey="name" tickLine={false} axisLine={false} tick={{ fill: 'hsl(var(--foreground))', fontSize: 12 }} />
<YAxis domain={[0, 5]} tickLine={false} axisLine={false} tickFormatter={(v) => `${v}`} tick={{ fill: 'hsl(var(--foreground))', fontSize: 12 }} />
<RechartsTooltip
cursor={{ fill: 'hsl(var(--muted))' }}
contentStyle={{ borderRadius: '8px', border: '1px solid hsl(var(--border))' }}
@@ -175,7 +175,7 @@ export default function Analytics() {
<ResponsiveContainer width="100%" height="100%">
<BarChart data={usefulnessData} margin={{ top: 4, right: 8, left: -20, bottom: 0 }}>
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="hsl(var(--border))" />
<XAxis dataKey="score" tickLine={false} axisLine={false} tick={{ fontSize: 12 }} />
<XAxis dataKey="score" tickLine={false} axisLine={false} tick={{ fill: 'hsl(var(--foreground))', fontSize: 12 }} />
<YAxis hide />
<RechartsTooltip cursor={{ fill: 'hsl(var(--muted))' }} contentStyle={{ borderRadius: '6px', border: '1px solid hsl(var(--border))' }} />
<Bar dataKey="count" fill="hsl(var(--primary))" radius={[4, 4, 0, 0]} maxBarSize={40} />
@@ -189,7 +189,7 @@ export default function Analytics() {
<ResponsiveContainer width="100%" height="100%">
<BarChart data={usabilityData} margin={{ top: 4, right: 8, left: -20, bottom: 0 }}>
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="hsl(var(--border))" />
<XAxis dataKey="score" tickLine={false} axisLine={false} tick={{ fontSize: 12 }} />
<XAxis dataKey="score" tickLine={false} axisLine={false} tick={{ fill: 'hsl(var(--foreground))', fontSize: 12 }} />
<YAxis hide />
<RechartsTooltip cursor={{ fill: 'hsl(var(--muted))' }} contentStyle={{ borderRadius: '6px', border: '1px solid hsl(var(--border))' }} />
<Bar dataKey="count" fill="hsl(var(--chart-3))" radius={[4, 4, 0, 0]} maxBarSize={40} />
+4
View File
@@ -6,6 +6,7 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { ThemeToggle } from "@/components/theme-toggle";
import { Wrench, AlertCircle } from "lucide-react";
export default function Login() {
@@ -40,6 +41,9 @@ export default function Login() {
return (
<div className="min-h-screen bg-background flex items-center justify-center p-4">
<div className="absolute top-4 right-4">
<ThemeToggle />
</div>
<div className="w-full max-w-sm space-y-6">
<div className="flex flex-col items-center gap-2 text-center">
<div className="flex items-center gap-2 text-primary font-bold text-2xl">
+1 -1
View File
@@ -697,7 +697,7 @@ export default function ToolDetail() {
<ResponsiveContainer width="100%" height="100%">
<BarChart data={usefulnessData} layout="vertical" margin={{ top: 0, right: 0, bottom: 0, left: -20 }}>
<XAxis type="number" hide />
<YAxis dataKey="score" type="category" axisLine={false} tickLine={false} tickFormatter={(val) => `${val}`} />
<YAxis dataKey="score" type="category" axisLine={false} tickLine={false} tickFormatter={(val) => `${val}`} tick={{ fill: 'hsl(var(--foreground))', fontSize: 12 }} />
<Tooltip cursor={{ fill: 'transparent' }} />
<Bar dataKey="count" fill="hsl(var(--primary))" radius={[0, 4, 4, 0]} barSize={12} />
</BarChart>