Files
pinkudex/components/settings/AccentColorPickers.tsx
T
2026-05-26 22:46:00 +02:00

94 lines
3.2 KiB
TypeScript

"use client";
import { RotateCcw } from "lucide-react";
import { useSettings } from "./SettingsProvider";
const DEFAULT_PRIMARY_HEX = "#4dc4d4";
const DEFAULT_SECONDARY_HEX = "#b772f0";
export function AccentColorPickers() {
const { settings, set } = useSettings();
return (
<div className="space-y-3">
<ColorRow
label="Primary Accent"
description="Used for buttons, toggles, focus rings, and the cyan side of accent gradients."
value={settings.accentPrimary}
fallback={DEFAULT_PRIMARY_HEX}
onChange={(v) => set("accentPrimary", v)}
onReset={() => set("accentPrimary", "")}
/>
<ColorRow
label="Secondary Accent"
description="Used for the violet side of accent gradients, glows, and ambient page lighting."
value={settings.accentSecondary}
fallback={DEFAULT_SECONDARY_HEX}
onChange={(v) => set("accentSecondary", v)}
onReset={() => set("accentSecondary", "")}
/>
</div>
);
}
function ColorRow({
label,
description,
value,
fallback,
onChange,
onReset,
}: {
label: string;
description?: string;
value: string;
fallback: string;
onChange: (v: string) => void;
onReset: () => void;
}) {
const isDefault = value === "";
const display = value || fallback;
return (
<div className="flex items-start justify-between gap-4 py-2">
<div className="min-w-0">
<div className="text-sm font-medium">{label}</div>
{description && (
<div className="text-xs text-[var(--color-fg-muted)] mt-0.5">{description}</div>
)}
<div className="text-[10px] font-mono uppercase tracking-wider text-[var(--color-fg-muted)] mt-1">
{isDefault ? "default" : display}
</div>
</div>
<div className="flex items-center gap-2 flex-shrink-0">
<label
className="relative w-9 h-9 rounded-lg border border-[var(--color-glass-border-strong)] bg-[var(--color-glass)] cursor-pointer overflow-hidden grid place-items-center hover:border-[color-mix(in_oklch,var(--color-cyan)_50%,var(--color-glass-border))] transition-colors"
title={`Change ${label.toLowerCase()}`}
>
<span
className="absolute inset-1 rounded-md"
style={{ background: display }}
aria-hidden
/>
<input
type="color"
value={display}
onChange={(e) => onChange(e.target.value.toLowerCase())}
className="absolute inset-0 opacity-0 cursor-pointer"
aria-label={label}
/>
</label>
<button
type="button"
onClick={onReset}
disabled={isDefault}
aria-label={`Reset ${label.toLowerCase()}`}
title="Reset to default"
className="w-9 h-9 grid place-items-center rounded-lg border border-[var(--color-glass-border-strong)] bg-[var(--color-glass)] text-[var(--color-fg-dim)] hover:text-[var(--color-fg)] hover:border-[color-mix(in_oklch,var(--color-cyan)_50%,var(--color-glass-border))] transition-colors disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:border-[var(--color-glass-border-strong)]"
>
<RotateCcw className="w-4 h-4" />
</button>
</div>
</div>
);
}