feat: add plain palette option and update related components and styles
This commit is contained in:
@@ -49,6 +49,40 @@
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
--radius: 0.65rem;
|
--radius: 0.65rem;
|
||||||
|
--background: oklch(0.985 0 0);
|
||||||
|
--foreground: oklch(0.205 0 0);
|
||||||
|
--card: oklch(1 0 0);
|
||||||
|
--card-foreground: oklch(0.205 0 0);
|
||||||
|
--popover: oklch(1 0 0);
|
||||||
|
--popover-foreground: oklch(0.205 0 0);
|
||||||
|
--primary: oklch(0.32 0 0);
|
||||||
|
--primary-foreground: oklch(0.985 0 0);
|
||||||
|
--secondary: oklch(0.96 0 0);
|
||||||
|
--secondary-foreground: oklch(0.24 0 0);
|
||||||
|
--muted: oklch(0.96 0 0);
|
||||||
|
--muted-foreground: oklch(0.48 0 0);
|
||||||
|
--accent: oklch(0.94 0 0);
|
||||||
|
--accent-foreground: oklch(0.24 0 0);
|
||||||
|
--destructive: oklch(0.59 0.225 25);
|
||||||
|
--border: oklch(0.89 0 0);
|
||||||
|
--input: oklch(0.89 0 0);
|
||||||
|
--ring: oklch(0.56 0 0);
|
||||||
|
--chart-1: oklch(0.44 0 0);
|
||||||
|
--chart-2: oklch(0.56 0 0);
|
||||||
|
--chart-3: oklch(0.68 0 0);
|
||||||
|
--chart-4: oklch(0.76 0 0);
|
||||||
|
--chart-5: oklch(0.84 0 0);
|
||||||
|
--sidebar: oklch(0.96 0 0);
|
||||||
|
--sidebar-foreground: oklch(0.24 0 0);
|
||||||
|
--sidebar-primary: oklch(0.32 0 0);
|
||||||
|
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||||
|
--sidebar-accent: oklch(0.92 0 0);
|
||||||
|
--sidebar-accent-foreground: oklch(0.24 0 0);
|
||||||
|
--sidebar-border: oklch(0.87 0 0);
|
||||||
|
--sidebar-ring: oklch(0.56 0 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-palette="green"] {
|
||||||
--background: oklch(0.973 0.011 112);
|
--background: oklch(0.973 0.011 112);
|
||||||
--foreground: oklch(0.22 0.021 210);
|
--foreground: oklch(0.22 0.021 210);
|
||||||
--card: oklch(0.996 0.004 105);
|
--card: oklch(0.996 0.004 105);
|
||||||
@@ -151,6 +185,40 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
|
--background: oklch(0.18 0 0);
|
||||||
|
--foreground: oklch(0.94 0 0);
|
||||||
|
--card: oklch(0.225 0 0);
|
||||||
|
--card-foreground: oklch(0.94 0 0);
|
||||||
|
--popover: oklch(0.225 0 0);
|
||||||
|
--popover-foreground: oklch(0.94 0 0);
|
||||||
|
--primary: oklch(0.82 0 0);
|
||||||
|
--primary-foreground: oklch(0.18 0 0);
|
||||||
|
--secondary: oklch(0.285 0 0);
|
||||||
|
--secondary-foreground: oklch(0.94 0 0);
|
||||||
|
--muted: oklch(0.285 0 0);
|
||||||
|
--muted-foreground: oklch(0.7 0 0);
|
||||||
|
--accent: oklch(0.32 0 0);
|
||||||
|
--accent-foreground: oklch(0.94 0 0);
|
||||||
|
--destructive: oklch(0.68 0.19 25);
|
||||||
|
--border: oklch(1 0 0 / 10%);
|
||||||
|
--input: oklch(1 0 0 / 14%);
|
||||||
|
--ring: oklch(0.62 0 0);
|
||||||
|
--chart-1: oklch(0.82 0 0);
|
||||||
|
--chart-2: oklch(0.72 0 0);
|
||||||
|
--chart-3: oklch(0.62 0 0);
|
||||||
|
--chart-4: oklch(0.52 0 0);
|
||||||
|
--chart-5: oklch(0.42 0 0);
|
||||||
|
--sidebar: oklch(0.16 0 0);
|
||||||
|
--sidebar-foreground: oklch(0.93 0 0);
|
||||||
|
--sidebar-primary: oklch(0.82 0 0);
|
||||||
|
--sidebar-primary-foreground: oklch(0.18 0 0);
|
||||||
|
--sidebar-accent: oklch(0.27 0 0);
|
||||||
|
--sidebar-accent-foreground: oklch(0.94 0 0);
|
||||||
|
--sidebar-border: oklch(1 0 0 / 9%);
|
||||||
|
--sidebar-ring: oklch(0.62 0 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark[data-palette="green"] {
|
||||||
--background: oklch(0.18 0.016 190);
|
--background: oklch(0.18 0.016 190);
|
||||||
--foreground: oklch(0.94 0.009 155);
|
--foreground: oklch(0.94 0.009 155);
|
||||||
--card: oklch(0.225 0.018 190);
|
--card: oklch(0.225 0.018 190);
|
||||||
|
|||||||
+2
-2
@@ -26,9 +26,9 @@ const geistMono = Geist_Mono({
|
|||||||
const paletteScript = `
|
const paletteScript = `
|
||||||
try {
|
try {
|
||||||
var palette = window.localStorage.getItem("dashboard_palette");
|
var palette = window.localStorage.getItem("dashboard_palette");
|
||||||
document.documentElement.dataset.palette = palette === "blue" || palette === "gray" ? palette : "green";
|
document.documentElement.dataset.palette = palette === "plain" || palette === "blue" || palette === "green" || palette === "gray" ? palette : "plain";
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
document.documentElement.dataset.palette = "green";
|
document.documentElement.dataset.palette = "plain";
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import assert from "node:assert/strict"
|
||||||
|
import { readFile } from "node:fs/promises"
|
||||||
|
import test from "node:test"
|
||||||
|
|
||||||
|
const paletteSource = await readFile(
|
||||||
|
new URL("./palette-toggle.tsx", import.meta.url),
|
||||||
|
"utf8",
|
||||||
|
)
|
||||||
|
const layoutSource = await readFile(new URL("../app/layout.tsx", import.meta.url), "utf8")
|
||||||
|
const zhMessages = JSON.parse(
|
||||||
|
await readFile(new URL("../messages/zh-CN.json", import.meta.url), "utf8"),
|
||||||
|
)
|
||||||
|
const enMessages = JSON.parse(
|
||||||
|
await readFile(new URL("../messages/en-US.json", import.meta.url), "utf8"),
|
||||||
|
)
|
||||||
|
|
||||||
|
test("plain palette is the default dashboard palette", () => {
|
||||||
|
assert.match(paletteSource, /type PaletteMode = "plain" \| "blue" \| "green" \| "gray"/)
|
||||||
|
assert.match(paletteSource, /const DEFAULT_PALETTE: PaletteMode = "plain"/)
|
||||||
|
assert.match(layoutSource, /palette === "plain"/)
|
||||||
|
assert.match(layoutSource, /: "plain"/)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("plain palette is available in the palette menu and messages", () => {
|
||||||
|
assert.match(paletteSource, /value: "plain"[\s\S]*labelKey: "palette\.plain"/)
|
||||||
|
assert.equal(zhMessages.palette.plain, "朴素默认")
|
||||||
|
assert.equal(enMessages.palette.plain, "Plain Default")
|
||||||
|
})
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { DropletsIcon, PaletteIcon } from "lucide-react"
|
import { CircleIcon, DropletsIcon, PaletteIcon } from "lucide-react"
|
||||||
|
|
||||||
import { useI18n } from "@/i18n/provider"
|
import { useI18n } from "@/i18n/provider"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
@@ -13,16 +13,21 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu"
|
} from "@/components/ui/dropdown-menu"
|
||||||
|
|
||||||
type PaletteMode = "blue" | "green" | "gray"
|
type PaletteMode = "plain" | "blue" | "green" | "gray"
|
||||||
|
|
||||||
const PALETTE_STORAGE_KEY = "dashboard_palette"
|
const PALETTE_STORAGE_KEY = "dashboard_palette"
|
||||||
const DEFAULT_PALETTE: PaletteMode = "green"
|
const DEFAULT_PALETTE: PaletteMode = "plain"
|
||||||
|
|
||||||
const paletteOptions: Array<{
|
const paletteOptions: Array<{
|
||||||
value: PaletteMode
|
value: PaletteMode
|
||||||
labelKey: string
|
labelKey: string
|
||||||
swatch: string
|
swatch: string
|
||||||
}> = [
|
}> = [
|
||||||
|
{
|
||||||
|
value: "plain",
|
||||||
|
labelKey: "palette.plain",
|
||||||
|
swatch: "bg-zinc-700",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: "green",
|
value: "green",
|
||||||
labelKey: "palette.green",
|
labelKey: "palette.green",
|
||||||
@@ -46,7 +51,10 @@ function readPalette(): PaletteMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const stored = window.localStorage.getItem(PALETTE_STORAGE_KEY)
|
const stored = window.localStorage.getItem(PALETTE_STORAGE_KEY)
|
||||||
return stored === "blue" || stored === "green" || stored === "gray"
|
return stored === "plain" ||
|
||||||
|
stored === "blue" ||
|
||||||
|
stored === "green" ||
|
||||||
|
stored === "gray"
|
||||||
? stored
|
? stored
|
||||||
: DEFAULT_PALETTE
|
: DEFAULT_PALETTE
|
||||||
}
|
}
|
||||||
@@ -68,12 +76,19 @@ export function PaletteToggle() {
|
|||||||
|
|
||||||
function handleChange(value: string) {
|
function handleChange(value: string) {
|
||||||
const nextPalette: PaletteMode =
|
const nextPalette: PaletteMode =
|
||||||
value === "blue" || value === "gray" ? value : "green"
|
value === "blue" || value === "green" || value === "gray"
|
||||||
|
? value
|
||||||
|
: "plain"
|
||||||
setPalette(nextPalette)
|
setPalette(nextPalette)
|
||||||
applyPalette(nextPalette)
|
applyPalette(nextPalette)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ActiveIcon = palette === "green" ? DropletsIcon : PaletteIcon
|
const ActiveIcon =
|
||||||
|
palette === "plain"
|
||||||
|
? CircleIcon
|
||||||
|
: palette === "green"
|
||||||
|
? DropletsIcon
|
||||||
|
: PaletteIcon
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
|
|||||||
@@ -2364,6 +2364,7 @@
|
|||||||
},
|
},
|
||||||
"palette": {
|
"palette": {
|
||||||
"toggle": "Change accent color",
|
"toggle": "Change accent color",
|
||||||
|
"plain": "Default",
|
||||||
"green": "Service Green",
|
"green": "Service Green",
|
||||||
"gray": "Neutral Gray",
|
"gray": "Neutral Gray",
|
||||||
"blue": "Clear Blue"
|
"blue": "Clear Blue"
|
||||||
|
|||||||
@@ -2364,6 +2364,7 @@
|
|||||||
},
|
},
|
||||||
"palette": {
|
"palette": {
|
||||||
"toggle": "切换主题色",
|
"toggle": "切换主题色",
|
||||||
|
"plain": "默认",
|
||||||
"green": "温润服务绿",
|
"green": "温润服务绿",
|
||||||
"gray": "中性精密灰",
|
"gray": "中性精密灰",
|
||||||
"blue": "清透科技蓝"
|
"blue": "清透科技蓝"
|
||||||
|
|||||||
Reference in New Issue
Block a user