fix: apply shadcn violet OKLCH theme and fix SelectItem empty value crash
- Replace HSL-based indigo theme with official shadcn violet OKLCH theme in globals.css for proper contrast in both light and dark mode - Update tailwind.config.ts to use var(--...) instead of hsl(var(--...)) for OKLCH color space compatibility - Fix Radix UI crash: replace SelectItem value="" with "__none__" sentinel in HostDialogs.tsx and L4HostDialogs.tsx (empty string value is invalid) Form action parsers already return null for non-numeric values Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,48 +4,48 @@
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 4%;
|
||||
--card: 0 0% 98%;
|
||||
--card-foreground: 240 10% 4%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 240 10% 4%;
|
||||
--primary: 239 84% 67%;
|
||||
--primary-foreground: 0 0% 100%;
|
||||
--secondary: 192 91% 43%;
|
||||
--secondary-foreground: 0 0% 100%;
|
||||
--muted: 240 5% 96%;
|
||||
--muted-foreground: 240 4% 46%;
|
||||
--accent: 240 5% 96%;
|
||||
--accent-foreground: 240 10% 4%;
|
||||
--destructive: 0 84% 60%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 240 6% 90%;
|
||||
--input: 240 6% 90%;
|
||||
--ring: 239 84% 67%;
|
||||
--radius: 0.5rem;
|
||||
--radius: 0.65rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.141 0.005 285.823);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.141 0.005 285.823);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.141 0.005 285.823);
|
||||
--primary: oklch(0.541 0.281 293.009);
|
||||
--primary-foreground: oklch(0.969 0.016 293.756);
|
||||
--secondary: oklch(0.967 0.001 286.375);
|
||||
--secondary-foreground: oklch(0.21 0.006 285.885);
|
||||
--muted: oklch(0.967 0.001 286.375);
|
||||
--muted-foreground: oklch(0.552 0.016 285.938);
|
||||
--accent: oklch(0.967 0.001 286.375);
|
||||
--accent-foreground: oklch(0.21 0.006 285.885);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--destructive-foreground: oklch(1 0 0);
|
||||
--border: oklch(0.92 0.004 286.32);
|
||||
--input: oklch(0.92 0.004 286.32);
|
||||
--ring: oklch(0.702 0.183 293.541);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 240 10% 4%;
|
||||
--foreground: 240 5% 96%;
|
||||
--card: 240 6% 10%;
|
||||
--card-foreground: 240 5% 96%;
|
||||
--popover: 240 6% 10%;
|
||||
--popover-foreground: 240 5% 96%;
|
||||
--primary: 239 84% 67%;
|
||||
--primary-foreground: 0 0% 100%;
|
||||
--secondary: 192 91% 43%;
|
||||
--secondary-foreground: 0 0% 100%;
|
||||
--muted: 240 4% 16%;
|
||||
--muted-foreground: 240 5% 65%;
|
||||
--accent: 240 4% 16%;
|
||||
--accent-foreground: 240 5% 96%;
|
||||
--destructive: 0 63% 31%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 240 4% 16%;
|
||||
--input: 240 4% 16%;
|
||||
--ring: 239 84% 67%;
|
||||
--background: oklch(0.141 0.005 285.823);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.21 0.006 285.885);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.21 0.006 285.885);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.606 0.25 292.717);
|
||||
--primary-foreground: oklch(0.969 0.016 293.756);
|
||||
--secondary: oklch(0.274 0.006 286.033);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.274 0.006 286.033);
|
||||
--muted-foreground: oklch(0.705 0.015 286.067);
|
||||
--accent: oklch(0.274 0.006 286.033);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--destructive-foreground: oklch(0.985 0 0);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.38 0.189 293.745);
|
||||
}
|
||||
|
||||
* {
|
||||
|
||||
@@ -226,13 +226,13 @@ function L4HostForm({
|
||||
</Label>
|
||||
<Select
|
||||
name="proxy_protocol_version"
|
||||
defaultValue={initialData?.proxy_protocol_version ?? ""}
|
||||
defaultValue={initialData?.proxy_protocol_version ?? "__none__"}
|
||||
>
|
||||
<SelectTrigger id="proxy_protocol_version">
|
||||
<SelectValue placeholder="None" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="">None</SelectItem>
|
||||
<SelectItem value="__none__">None</SelectItem>
|
||||
<SelectItem value="v1">v1</SelectItem>
|
||||
<SelectItem value="v2">v2</SelectItem>
|
||||
</SelectContent>
|
||||
|
||||
@@ -100,12 +100,12 @@ export function CreateHostDialog({
|
||||
<UpstreamInput defaultUpstreams={initialData?.upstreams} />
|
||||
<div>
|
||||
<label className="text-sm font-medium mb-1 block">Certificate</label>
|
||||
<Select name="certificate_id" defaultValue={String(initialData?.certificate_id ?? "")}>
|
||||
<Select name="certificate_id" defaultValue={String(initialData?.certificate_id ?? "__none__")}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Managed by Caddy (Auto)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="">Managed by Caddy (Auto)</SelectItem>
|
||||
<SelectItem value="__none__">Managed by Caddy (Auto)</SelectItem>
|
||||
{certificates.map((cert) => (
|
||||
<SelectItem key={cert.id} value={String(cert.id)}>
|
||||
{cert.name}
|
||||
@@ -116,12 +116,12 @@ export function CreateHostDialog({
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium mb-1 block">Access List</label>
|
||||
<Select name="access_list_id" defaultValue={String(initialData?.access_list_id ?? "")}>
|
||||
<Select name="access_list_id" defaultValue={String(initialData?.access_list_id ?? "__none__")}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="None" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="">None</SelectItem>
|
||||
<SelectItem value="__none__">None</SelectItem>
|
||||
{accessLists.map((list) => (
|
||||
<SelectItem key={list.id} value={String(list.id)}>
|
||||
{list.name}
|
||||
@@ -229,12 +229,12 @@ export function EditHostDialog({
|
||||
<UpstreamInput defaultUpstreams={host.upstreams} />
|
||||
<div>
|
||||
<label className="text-sm font-medium mb-1 block">Certificate</label>
|
||||
<Select name="certificate_id" defaultValue={String(host.certificate_id ?? "")}>
|
||||
<Select name="certificate_id" defaultValue={String(host.certificate_id ?? "__none__")}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Managed by Caddy (Auto)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="">Managed by Caddy (Auto)</SelectItem>
|
||||
<SelectItem value="__none__">Managed by Caddy (Auto)</SelectItem>
|
||||
{certificates.map((cert) => (
|
||||
<SelectItem key={cert.id} value={String(cert.id)}>
|
||||
{cert.name}
|
||||
@@ -245,12 +245,12 @@ export function EditHostDialog({
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium mb-1 block">Access List</label>
|
||||
<Select name="access_list_id" defaultValue={String(host.access_list_id ?? "")}>
|
||||
<Select name="access_list_id" defaultValue={String(host.access_list_id ?? "__none__")}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="None" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="">None</SelectItem>
|
||||
<SelectItem value="__none__">None</SelectItem>
|
||||
{accessLists.map((list) => (
|
||||
<SelectItem key={list.id} value={String(list.id)}>
|
||||
{list.name}
|
||||
|
||||
@@ -10,38 +10,38 @@ const config: Config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
border: 'var(--border)',
|
||||
input: 'var(--input)',
|
||||
ring: 'var(--ring)',
|
||||
background: 'var(--background)',
|
||||
foreground: 'var(--foreground)',
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))'
|
||||
DEFAULT: 'var(--primary)',
|
||||
foreground: 'var(--primary-foreground)'
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))'
|
||||
DEFAULT: 'var(--secondary)',
|
||||
foreground: 'var(--secondary-foreground)'
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))'
|
||||
DEFAULT: 'var(--destructive)',
|
||||
foreground: 'var(--destructive-foreground)'
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))'
|
||||
DEFAULT: 'var(--muted)',
|
||||
foreground: 'var(--muted-foreground)'
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))'
|
||||
DEFAULT: 'var(--accent)',
|
||||
foreground: 'var(--accent-foreground)'
|
||||
},
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))'
|
||||
DEFAULT: 'var(--card)',
|
||||
foreground: 'var(--card-foreground)'
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))'
|
||||
DEFAULT: 'var(--popover)',
|
||||
foreground: 'var(--popover-foreground)'
|
||||
}
|
||||
},
|
||||
borderRadius: {
|
||||
|
||||
Reference in New Issue
Block a user