'use client';
import { useState } from 'react';
import { Theme, PlatformTheme } from '@/types/theme';
import tokensJson from '@bytelyst/design-tokens/tokens.json';
function ColorInput({
label,
value,
onChange,
}: {
label: string;
value: string;
onChange: (value: string) => void;
}) {
return (
onChange(e.target.value)}
className="w-12 h-8 border rounded cursor-pointer"
/>
onChange(e.target.value)}
className="flex-1 px-2 py-1 border rounded text-sm font-mono"
placeholder="#00000000"
/>
);
}
function PlatformSection({
title,
colors,
onChange,
}: {
title: string;
colors: PlatformTheme;
onChange: (key: keyof PlatformTheme, value: string) => void;
}) {
return (
{title}
onChange('primary', v)} />
onChange('secondary', v)}
/>
onChange('accent', v)} />
onChange('background', v)}
/>
onChange('surface', v)} />
onChange('error', v)} />
onChange('warning', v)} />
onChange('success', v)} />
{title === 'Desktop' && (
<>
onChange('idle', v)}
/>
>).lysnrai
?.hotkeyActive ??
'#5A8CFF')
}
onChange={v => onChange('listening', v)}
/>
onChange('processing', v)}
/>
onChange('offline', v)}
/>
>
)}
);
}
interface ThemeEditorProps {
theme?: Theme;
onSave: (theme: Partial) => void;
onCancel: () => void;
}
export default function ThemeEditor({ theme, onSave, onCancel }: ThemeEditorProps) {
const [name, setName] = useState(theme?.name || '');
const [description, setDescription] = useState(theme?.description || '');
const [iosColors, setIosColors] = useState(
theme?.ios || {
primary: tokensJson.color.semantic.dark.success,
secondary: tokensJson.color.palette.neutral['700'],
accent: tokensJson.color.semantic.dark.accentPrimary,
background: tokensJson.color.palette.neutral['0'],
surface: tokensJson.color.palette.neutral['50'],
error: tokensJson.color.semantic.dark.danger,
warning: tokensJson.color.semantic.dark.warning,
success: tokensJson.color.semantic.dark.success,
}
);
const [androidColors, setAndroidColors] = useState(theme?.android || iosColors);
const [desktopColors, setDesktopColors] = useState(
theme?.desktop || {
...iosColors,
idle: tokensJson.color.semantic.dark.success,
listening:
(tokensJson.color as unknown as Record>).lysnrai
?.hotkeyActive ?? '#5A8CFF',
processing: tokensJson.color.semantic.dark.warning,
offline: tokensJson.color.semantic.dark.textSecondary,
}
);
const handleColorChange = (
platform: 'ios' | 'android' | 'desktop',
colorKey: keyof PlatformTheme,
value: string
) => {
// Validate hex color format
const hexPattern = /^#[0-9A-Fa-f]{6}$/;
if (value && !hexPattern.test(value)) {
return; // Don't update if invalid
}
const setter =
platform === 'ios'
? setIosColors
: platform === 'android'
? setAndroidColors
: setDesktopColors;
setter(prev => ({ ...prev, [colorKey]: value }));
};
const handleSave = () => {
onSave({
name,
description,
ios: iosColors,
android: androidColors,
desktop: desktopColors,
});
};
return (
{theme ? 'Edit Theme' : 'Create New Theme'}
handleColorChange('ios', key, value)}
/>
handleColorChange('android', key, value)}
/>
handleColorChange('desktop', key, value)}
/>
);
}