Openstatus www.openstatus.dev

feat: support dashboard appearance setting (#514)

* feat: support dashboard appearance setting

* chore: add future todo

authored by

Maximilian Kaske and committed by
GitHub
45ade72c 9692c3db

+102
+97
apps/web/src/app/app/[workspaceSlug]/(dashboard)/settings/appearance/page.tsx
··· 1 + "use client"; 2 + 3 + import * as React from "react"; 4 + import { useTheme } from "next-themes"; 5 + 6 + import { cn } from "@/lib/utils"; 7 + 8 + // TODO: improve keyboard navigation 9 + 10 + export default function AppearancePage() { 11 + const { setTheme, theme } = useTheme(); 12 + 13 + return ( 14 + <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4"> 15 + <button onClick={() => setTheme("light")}> 16 + <LightModeCard active={theme === "light"} /> 17 + <span className="text-muted-foreground mt-2 text-sm font-light"> 18 + Light 19 + </span> 20 + </button> 21 + <button onClick={() => setTheme("dark")}> 22 + <DarkModeCard active={theme === "dark"} /> 23 + <span className="text-muted-foreground mt-2 text-sm font-light"> 24 + Dark 25 + </span> 26 + </button> 27 + <button onClick={() => setTheme("system")}> 28 + <div className="relative"> 29 + <LightModeCard active={theme === "system"} /> 30 + <div 31 + className="absolute bottom-0 left-0 right-0 top-0" 32 + style={{ 33 + clipPath: "polygon(100% 0, 0 0, 100% 100%)", 34 + }} 35 + > 36 + <DarkModeCard active={theme === "system"} /> 37 + </div> 38 + </div> 39 + <span className="text-muted-foreground mt-2 text-sm font-light"> 40 + System 41 + </span> 42 + </button> 43 + </div> 44 + ); 45 + } 46 + 47 + function LightModeCard({ active }: { active: boolean }) { 48 + return ( 49 + <div 50 + className={cn( 51 + "border-muted items-center rounded-md border-2 p-1", 52 + active && "ring-ring ring-offset-background ring-2 ring-offset-2", 53 + )} 54 + > 55 + <div className="space-y-2 rounded-sm bg-[#ecedef] p-2"> 56 + <div className="space-y-2 rounded-md bg-white p-2 shadow-sm"> 57 + <div className="h-2 w-[80px] rounded-lg bg-[#ecedef]" /> 58 + <div className="h-2 w-[100px] rounded-lg bg-[#ecedef]" /> 59 + </div> 60 + <div className="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm"> 61 + <div className="h-4 w-4 rounded-full bg-[#ecedef]" /> 62 + <div className="h-2 w-[100px] rounded-lg bg-[#ecedef]" /> 63 + </div> 64 + <div className="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm"> 65 + <div className="h-4 w-4 rounded-full bg-[#ecedef]" /> 66 + <div className="h-2 w-[100px] rounded-lg bg-[#ecedef]" /> 67 + </div> 68 + </div> 69 + </div> 70 + ); 71 + } 72 + 73 + function DarkModeCard({ active }: { active: boolean }) { 74 + return ( 75 + <div 76 + className={cn( 77 + "border-muted bg-popover items-center rounded-md border-2 p-1", 78 + active && "ring-ring ring-offset-background ring-2 ring-offset-2", 79 + )} 80 + > 81 + <div className="space-y-2 rounded-sm bg-slate-950 p-2"> 82 + <div className="space-y-2 rounded-md bg-slate-800 p-2 shadow-sm"> 83 + <div className="h-2 w-[80px] rounded-lg bg-slate-400" /> 84 + <div className="h-2 w-[100px] rounded-lg bg-slate-400" /> 85 + </div> 86 + <div className="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm"> 87 + <div className="h-4 w-4 rounded-full bg-slate-400" /> 88 + <div className="h-2 w-[100px] rounded-lg bg-slate-400" /> 89 + </div> 90 + <div className="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm"> 91 + <div className="h-4 w-4 rounded-full bg-slate-400" /> 92 + <div className="h-2 w-[100px] rounded-lg bg-slate-400" /> 93 + </div> 94 + </div> 95 + </div> 96 + ); 97 + }
+5
apps/web/src/app/app/[workspaceSlug]/(dashboard)/settings/layout.tsx
··· 29 29 href: `/app/${params.workspaceSlug}/settings/billing`, 30 30 segment: "billing", 31 31 }, 32 + { 33 + label: "Appearance", 34 + href: `/app/${params.workspaceSlug}/settings/appearance`, 35 + segment: "appearance", 36 + }, 32 37 ]; 33 38 34 39 return (