Skip to content

Commit

Permalink
feat: themes (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
rolznz authored Jul 5, 2024
2 parents 6c44fb8 + 2680d79 commit 32c466e
Show file tree
Hide file tree
Showing 15 changed files with 347 additions and 104 deletions.
6 changes: 5 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ function App() {

return (
<>
<ThemeProvider defaultTheme="system" storageKey="vite-ui-theme">
<ThemeProvider
defaultTheme="default"
defaultDarkMode="system"
storageKey="vite-ui-theme"
>
<Toaster />
<RouterProvider router={router} />
</ThemeProvider>
Expand Down
5 changes: 1 addition & 4 deletions frontend/src/components/layouts/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,6 @@ export default function AppLayout() {
const { hasChannelManagement } = useInfo();
return (
<nav className="grid items-start p-2 text-sm font-medium lg:px-4">
{/* <div className="px-3 py-2 mb-5">
<ModeToggle />
</div> */}
{hasChannelManagement && (
<MenuItem to="/channels">
<FlaskRound className="h-4 w-4" />
Expand Down Expand Up @@ -337,7 +334,7 @@ const MenuItem = ({
}}
className={({ isActive }) =>
cn(
"flex items-center gap-3 rounded-lg px-3 py-2 text-muted-foreground transition-all hover:text-primary",
"flex items-center gap-3 rounded-lg px-3 py-2 text-muted-foreground transition-all hover:text-accent-foreground",
disabled && "cursor-not-allowed",
!disabled && isActive ? "bg-muted" : ""
)
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/layouts/SettingsLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export default function SettingsLayout() {
<div className="flex flex-col space-y-8 lg:flex-row lg:space-x-12 lg:space-y-0">
<aside className="lg:-mx-4 lg:w-1/5">
<nav className="flex space-x-2 lg:flex-col lg:space-x-0 lg:space-y-1">
<MenuItem to="/settings">General</MenuItem>
<MenuItem to="/settings">Theme</MenuItem>
<MenuItem to="/settings/change-unlock-password">
Unlock Password
</MenuItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ export default function TwoColumnFullScreenLayout() {
{info?.version && (
<p className="text-sm text-muted-foreground">{info.version}</p>
)}
{/* <ModeToggle /> */}
</div>
</div>
<div className="flex flex-row gap-5">
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const buttonVariants = cva(
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
link: "text-foreground hover:text-accent-foreground underline-offset-4 hover:underline",
positive:
"bg-positive text-positive-foreground shadow-sm hover:bg-positive/90",
},
Expand Down
22 changes: 0 additions & 22 deletions frontend/src/components/ui/mode-toggle.tsx

This file was deleted.

60 changes: 45 additions & 15 deletions frontend/src/components/ui/theme-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,88 @@
import { createContext, useContext, useEffect, useState } from "react";

type Theme = "dark" | "light" | "system";
export type DarkMode = "system" | "light" | "dark";
export const Themes = ["default", "alby", "bitcoin", "nostr"] as const;
export type Theme = (typeof Themes)[number];

type ThemeProviderProps = {
children: React.ReactNode;
defaultTheme?: Theme;
defaultDarkMode?: DarkMode;
storageKey?: string;
};

type ThemeProviderState = {
theme: Theme;
theme: string;
darkMode: string;
setTheme: (theme: Theme) => void;
setDarkMode: (mode: DarkMode) => void;
};

const initialState: ThemeProviderState = {
theme: "system",
theme: "default",
setTheme: () => null,
darkMode: "system",
setDarkMode: () => null,
};

const ThemeProviderContext = createContext<ThemeProviderState>(initialState);

export function ThemeProvider({
children,
defaultTheme = "system",
defaultTheme = "default",
defaultDarkMode = "system",
storageKey = "vite-ui-theme",
...props
}: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>(() => {
return (localStorage.getItem(storageKey) as Theme) || defaultTheme;
});

const [darkMode, setDarkMode] = useState<DarkMode>(() => {
return (
(localStorage.getItem(storageKey + "-darkmode") as DarkMode) ||
defaultDarkMode
);
});

useEffect(() => {
const root = window.document.documentElement;

root.classList.remove("light", "dark");
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light";
// Find and remove classes that start with 'theme-'
const classList = root.classList;
classList.forEach((className) => {
if (className.startsWith("theme-")) {
classList.remove(className);
}
});

root.classList.add(systemTheme);
setTheme(systemTheme);
return;
classList.add(`theme-${theme}`);

let prefersDark = false;
if (darkMode == "system") {
prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
} else {
prefersDark = darkMode === "dark";
}

root.classList.add(theme);
}, [theme]);
if (prefersDark) {
classList.add("dark");
} else {
classList.remove("dark");
}
}, [theme, darkMode]);

const value = {
theme,
setTheme: (theme: Theme) => {
localStorage.setItem(storageKey, theme);
setTheme(theme);
},
darkMode,
setDarkMode: (darkMode: DarkMode) => {
localStorage.setItem(storageKey + "-darkmode", darkMode);
setDarkMode(darkMode);
},
};

return (
Expand Down
60 changes: 5 additions & 55 deletions frontend/src/index.css
Original file line number Diff line number Diff line change
@@ -1,56 +1,12 @@
@import "themes/default.css";
@import "themes/alby.css";
@import "themes/bitcoin.css";
@import "themes/nostr.css";

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 5.9% 10%;
--radius: 0.5rem;
--positive: 138, 68%, 96%;
--positive-foreground: 142 76% 36%;
}

.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
}
}

@layer base {
* {
@apply border-border;
Expand All @@ -65,9 +21,3 @@
input[type="text"]::-webkit-calendar-picker-indicator {
display: none !important;
}

html {
--bc-color-brand: #000000; /* use a different brand color in dark mode */
--bc-color-brand-dark: #ffffff; /* use a different brand color in dark mode */
--bc-brand-mix: 100%; /* how much to mix the brand color with default foreground color */
}
63 changes: 61 additions & 2 deletions frontend/src/screens/settings/Settings.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,71 @@
import SettingsHeader from "src/components/SettingsHeader";
import { Label } from "src/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "src/components/ui/select";
import {
DarkMode,
Theme,
Themes,
useTheme,
} from "src/components/ui/theme-provider";
import { toast } from "src/components/ui/use-toast";

function Settings() {
const { theme, darkMode, setTheme, setDarkMode } = useTheme();

return (
<>
<SettingsHeader
title="General"
description="Adjust general settings of your Alby Hub"
title="Theme"
description="Alby Hub is your wallet, make it your style."
/>
<form className="w-full flex flex-col gap-3">
<div className="grid gap-1.5">
<Label htmlFor="theme">Theme</Label>
<Select
value={theme}
onValueChange={(value) => {
setTheme(value as Theme);
toast({ title: "Theme updated." });
}}
>
<SelectTrigger className="w-[150px]">
<SelectValue placeholder="Theme" />
</SelectTrigger>
<SelectContent>
{Themes.map((theme) => (
<SelectItem key={theme} value={theme}>
{theme.charAt(0).toUpperCase() + theme.substring(1)}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="grid gap-1.5">
<Label htmlFor="theme">Dark mode</Label>
<Select
value={darkMode}
onValueChange={(value) => {
setDarkMode(value as DarkMode);
toast({ title: "Dark Mode updated." });
}}
>
<SelectTrigger className="w-[150px]">
<SelectValue placeholder="Dark mode" />
</SelectTrigger>
<SelectContent>
<SelectItem value="system">System</SelectItem>
<SelectItem value="light">Light</SelectItem>
<SelectItem value="dark">Dark</SelectItem>
</SelectContent>
</Select>
</div>
</form>
</>
);
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/screens/wallet/OnboardingChecklist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ function ChecklistItem({
<div
className={cn(
"flex flex-col p-3 relative group rounded-lg",
!checked && "hover:bg-primary-foreground"
!checked && "hover:bg-muted"
)}
>
{!checked && (
Expand Down
52 changes: 52 additions & 0 deletions frontend/src/themes/alby.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
.theme-alby {
--background: 0 0% 100%;
--foreground: 0 0% 5%;
--card: 0 0% 100%;
--card-foreground: 0 0% 5%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 5%;
--primary: 47 100% 72%;
--primary-foreground: 0 0% 2%;
--secondary: 0 0% 96%;
--secondary-foreground: 0 0% 5%;
--muted: 0 0% 96%;
--muted-foreground: 0 0% 45%;
--accent: 0 0% 96%;
--accent-foreground: 0 0% 5%;
--destructive: 0 84% 60%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 92%;
--input: 0 0% 85%;
--ring: 0 0% 76%;
--radius: 0.5rem;
}

.theme-alby.dark {
--background: 0 0% 3%;
--foreground: 0 0% 98%;

--card: 0 0% 3%;
--card-foreground: 0 0% 98%;

--popover: 0 0% 0%;
--popover-foreground: 0 0% 98%;

--primary: 47 100% 72%;
--primary-foreground: 0 0% 2%;

--secondary: 0 0% 0%;
--secondary-foreground: 0 0% 98%;

--muted: 0 0% 10%;
--muted-foreground: 0 0% 49%;

--accent: 0 0% 0%;
--accent-foreground: 0 0% 98%;

--destructive: 0 84% 60%;
--destructive-foreground: 0 0% 98%;

--border: 0 0% 15%;
--input: 0 0% 15%;
--ring: 47 100% 40%;
}
Loading

0 comments on commit 32c466e

Please sign in to comment.