/** * MarkdownFormatToolbar — contextual toolbar for selected markdown cards. * Shows name, color picker (sets accent + auto-derives bg), and width presets. */ import React, { useState, useEffect } from 'react'; interface MarkdownFormatToolbarProps { x: number; y: number; accentColor: string; width: number; name: string; onColorChange: (accent: string, bg: string) => void; onWidthChange: (width: number) => void; onNameChange: (name: string) => void; } /** Derive a dark card background from an accent color. */ function deriveBg(accent: string): string { // Parse hex to RGB, then darken heavily const hex = accent.replace('#', ''); const r = parseInt(hex.substring(0, 2), 16) || 0; const g = parseInt(hex.substring(2, 4), 16) || 0; const b = parseInt(hex.substring(4, 6), 16) || 0; // Mix ~15% accent into a dark base const mix = (c: number) => Math.round(28 + c * 0.12); return `#${mix(r).toString(16).padStart(2, '0')}${mix(g).toString(16).padStart(2, '0')}${mix(b).toString(16).padStart(2, '0')}`; } const CARD_COLORS = [ { accent: '#7950f2', label: 'Purple' }, { accent: '#4dabf7', label: 'Blue' }, { accent: '#69db7c', label: 'Green' }, { accent: '#ffd43b', label: 'Yellow' }, { accent: '#ff6b6b', label: 'Red' }, { accent: '#e64980', label: 'Pink' }, { accent: '#ffa94d', label: 'Orange' }, { accent: '#868e96', label: 'Gray' }, { accent: '#f783ac', label: 'Rose' }, { accent: '#20c997', label: 'Teal' }, ]; const WIDTH_PRESETS = [ { label: 'S', value: 300 }, { label: 'M', value: 450 }, { label: 'L', value: 650 }, ]; export default function MarkdownFormatToolbar(props: MarkdownFormatToolbarProps) { const { x, y, accentColor, width, name, onColorChange, onWidthChange, onNameChange } = props; const [showPicker, setShowPicker] = useState(false); useEffect(() => { const onDown = () => setShowPicker(false); window.addEventListener('pointerdown', onDown); return () => window.removeEventListener('pointerdown', onDown); }, []); const btnStyle: React.CSSProperties = { display: 'flex', alignItems: 'center', justifyContent: 'center', height: '26px', background: 'transparent', border: 'none', borderRadius: '5px', color: '#999', cursor: 'pointer', padding: '0 6px', fontSize: '11px', fontFamily: 'system-ui, sans-serif', whiteSpace: 'nowrap', transition: 'all 0.1s', }; return (
e.stopPropagation()} > {/* Title / name */} onNameChange(e.target.value)} style={{ background: 'transparent', border: '1px solid transparent', borderRadius: '5px', color: '#ccc', fontSize: '11px', padding: '2px 8px', width: '120px', outline: 'none', fontFamily: 'system-ui, sans-serif', }} onFocus={(e) => { (e.target as HTMLInputElement).style.borderColor = '#555'; }} onBlur={(e) => { (e.target as HTMLInputElement).style.borderColor = 'transparent'; }} onKeyDown={(e) => { if (e.key === 'Enter') (e.target as HTMLInputElement).blur(); }} />
{/* Card color */}
{showPicker && (
e.stopPropagation()} >
{CARD_COLORS.map((c) => (
)}
{/* Width presets */}
{WIDTH_PRESETS.map((p) => ( ))}
); }