78 lines
2.2 KiB
TypeScript
78 lines
2.2 KiB
TypeScript
import { cn } from '@/lib/utils';
|
||
|
||
type KeyState = 'idle' | 'active' | 'success';
|
||
|
||
interface OnboardingKeyboardProps {
|
||
/** The key to emphasise. Defaults to the record key. */
|
||
highlightKey?: string;
|
||
state: KeyState;
|
||
/** Hold progress (0–1), fills the emphasised key from the bottom. */
|
||
progress?: number;
|
||
}
|
||
|
||
interface KeyCapProps {
|
||
label: string;
|
||
hero?: boolean;
|
||
state?: KeyState;
|
||
progress?: number;
|
||
className?: string;
|
||
}
|
||
|
||
function KeyCap({
|
||
label,
|
||
hero,
|
||
state = 'idle',
|
||
progress = 0,
|
||
className,
|
||
}: KeyCapProps) {
|
||
return (
|
||
<div
|
||
className={cn(
|
||
'relative flex select-none items-center justify-center overflow-hidden rounded-lg border text-sm font-medium',
|
||
hero ? 'h-14 w-14 text-xl' : 'h-14',
|
||
!hero && 'border-white/10 bg-white/5 text-white/30',
|
||
hero &&
|
||
state === 'idle' &&
|
||
'border-white/25 bg-white/10 text-white motion-safe:animate-pulse',
|
||
hero && state === 'active' && 'border-white/50 bg-white/20 text-white',
|
||
hero &&
|
||
state === 'success' &&
|
||
'border-emerald-400/50 bg-emerald-500/20 text-emerald-200',
|
||
className,
|
||
)}
|
||
>
|
||
{hero && state !== 'success' && progress > 0 && (
|
||
<span
|
||
className="pointer-events-none absolute inset-x-0 bottom-0 bg-white/25"
|
||
style={{ height: `${progress * 100}%` }}
|
||
/>
|
||
)}
|
||
<span className="relative z-10">{label}</span>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Draws the record key in its physical context: Esc above, 1 to its right, and
|
||
* Tab / Q on the row below — so the key is recognisable on a real keyboard.
|
||
*/
|
||
export function OnboardingKeyboard({
|
||
highlightKey = '`',
|
||
state,
|
||
progress = 0,
|
||
}: OnboardingKeyboardProps) {
|
||
return (
|
||
<div className="flex flex-col items-start gap-1.5">
|
||
<KeyCap label="esc" className="w-14 text-xs" />
|
||
<div className="flex gap-1.5">
|
||
<KeyCap label={highlightKey} hero state={state} progress={progress} />
|
||
<KeyCap label="1" className="w-14" />
|
||
</div>
|
||
<div className="flex gap-1.5">
|
||
<KeyCap label="tab" className="w-20 text-xs" />
|
||
<KeyCap label="Q" className="w-12" />
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|