Appearance
Theme, density and accent colour.
Built with
Appearance
Only changes how Northwind looks for you, on this account.
Theme
System follows your device's light or dark setting.
Density
How much fits on tables and lists.Accent colour
Used for your calendar events and highlights. Selected: Emerald.
Emerald, #04855D
Blue, #2563EB
Violet, #7C3AED
Pink, #DB2777
Amber, #D97706
Cyan, #0E7490
appearance.tsx
"use client";
import { useState } from "react";
import { LuLayoutList, LuMonitor, LuMoon, LuRows3, LuSun } from "react-icons/lu";
import {
Button,
RadioCard,
RadioGroup,
Segment,
SegmentedControl,
Swatch,
SwatchPicker,
} from "@nexera-ui/react";
/** Accent colours are data the person picks, so they are plain values with names (not styling). */
const ACCENTS = [
{ hex: "#04855D", name: "Emerald" },
{ hex: "#2563EB", name: "Blue" },
{ hex: "#7C3AED", name: "Violet" },
{ hex: "#DB2777", name: "Pink" },
{ hex: "#D97706", name: "Amber" },
{ hex: "#0E7490", name: "Cyan" },
];
/** Appearance: theme, density and accent colour for the person's own view of Northwind. */
export default function Appearance() {
const [theme, setTheme] = useState("system");
const [accent, setAccent] = useState("#04855D");
const [saved, setSaved] = useState(false);
const accentName =
ACCENTS.find((item) => item.hex.toLowerCase() === accent.toLowerCase())?.name ?? accent;
return (
<div className="@container min-h-[560px] bg-page px-4 py-8 @3xl:px-8">
<div className="mx-auto grid max-w-3xl gap-6">
<header className="grid gap-1">
<h2 className="text-heading-h2 text-primary">Appearance</h2>
<p className="text-body-default text-secondary">
Only changes how Northwind looks for you, on this account.
</p>
</header>
<section
aria-labelledby="theme-heading"
className="grid gap-3 rounded-xl border border-default bg-surface p-5"
>
<div className="grid gap-0.5">
<h3 id="theme-heading" className="text-heading-h4 text-primary">
Theme
</h3>
<p className="text-body-small text-secondary">
System follows your device's light or dark setting.
</p>
</div>
<SegmentedControl
aria-labelledby="theme-heading"
className="justify-self-start"
selectedKeys={[theme]}
onSelectionChange={(keys) => {
const [key] = [...keys];
if (key !== undefined) setTheme(String(key));
}}
>
<Segment id="light" label="Light" icon={<LuSun />} />
<Segment id="dark" label="Dark" icon={<LuMoon />} />
<Segment id="system" label="System" icon={<LuMonitor />} />
</SegmentedControl>
</section>
<section className="grid gap-3 rounded-xl border border-default bg-surface p-5">
<RadioGroup
type="card"
label="Density"
description="How much fits on tables and lists."
name="density"
defaultValue="comfortable"
>
<RadioCard
value="comfortable"
icon={<LuRows3 />}
title="Comfortable"
description="More space between rows. Easier to scan and tap."
/>
<RadioCard
value="compact"
icon={<LuLayoutList />}
title="Compact"
description="Fits about 40% more rows. Good for payroll and big teams."
/>
</RadioGroup>
</section>
<section
aria-labelledby="accent-heading"
className="grid gap-3 rounded-xl border border-default bg-surface p-5"
>
<div className="grid gap-0.5">
<h3 id="accent-heading" className="text-heading-h4 text-primary">
Accent colour
</h3>
<p className="text-body-small text-secondary">
Used for your calendar events and highlights. Selected: {accentName}.
</p>
</div>
<SwatchPicker
aria-labelledby="accent-heading"
value={accent}
onChange={(color) => {
setAccent(color.toString("hex"));
}}
className="gap-3"
>
{ACCENTS.map((item) => (
<Swatch key={item.hex} size="md" color={item.hex} colorName={item.name} />
))}
</SwatchPicker>
</section>
<div className="flex flex-wrap items-center justify-end gap-3">
<p role="status" className="text-body-small text-status-success-fg empty:hidden">
{saved ? "Appearance saved." : ""}
</p>
<Button
size="md"
onPress={() => {
setSaved(true);
}}
>
Save changes
</Button>
</div>
</div>
</div>
);
}
More settings and preferences blocks
- Notification preferencesChoose which alerts arrive by email, push or not at all.
- SecurityPassword, two-step verification and active sessions.
- Team members and rolesInvite, change roles and remove members.
- Billing and planCurrent plan, payment method and invoices.
- IntegrationsConnect and configure other apps.
- Delete accountA clear warning and a confirmation step.