214f3c13d7
Implements multi-mode footswitch system for the Helix Stadium-inspired pedal UI: - Footswitch mode context provider with 4 modes: stomp, preset, snapshot, combo - ModeSelector in status bar (collapsed cycling mode for mobile) - Stomp mode: footswitches toggle individual blocks on/off, scribble strips show block name + status - Preset mode: footswitches show Bank Up/Down + preset selection, scribble strips show preset name + number - Snapshot mode: footswitches recall 8 snapshots, scribble strips show snapshot name - Combo mode: first 4 stomp + bank nav + preset select + global bypass - ScribbleStrip LCD component with LED indicator and double-tap support - Double-tap gesture hook for secondary actions (tuner, snapshot save, etc.) - FootswitchBar container with 8 capacitive-touch footswitch buttons and LED rings - usePedalState hook (WebSocket + API polling, ported from frontend-react/App.jsx) - Dark pedal theme CSS (Helix-inspired) with responsive mobile layout - Full App.tsx rewrite with status bar, footswitch bar, tab bar, and all screens
61 lines
1.6 KiB
TypeScript
61 lines
1.6 KiB
TypeScript
/**
|
|
* ScribbleStrip — the LCD-like label display above each footswitch.
|
|
*
|
|
* Shows block/preset/snapshot name and status, mimicking the
|
|
* Helix / Line 6 scribble strip LCDs.
|
|
*/
|
|
|
|
import type { ScribbleStripData, ScribbleColor } from '../types';
|
|
import { SCRIBBLE_COLORS } from '../types';
|
|
import { useDoubleTap } from '../hooks/useDoubleTap';
|
|
|
|
interface ScribbleStripProps {
|
|
data: ScribbleStripData;
|
|
onPress: () => void;
|
|
onSecondary: () => void;
|
|
}
|
|
|
|
export function ScribbleStrip({ data, onPress, onSecondary }: ScribbleStripProps) {
|
|
const { handleTap } = useDoubleTap({
|
|
onSingleTap: onPress,
|
|
onDoubleTap: onSecondary,
|
|
});
|
|
|
|
const color = SCRIBBLE_COLORS[data.color ?? 'off'];
|
|
const isActive = data.active ?? false;
|
|
const isBypassed = data.bypassed ?? false;
|
|
|
|
return (
|
|
<div
|
|
className="scribble-strip"
|
|
data-active={isActive}
|
|
data-bypassed={isBypassed}
|
|
onClick={handleTap}
|
|
style={{
|
|
'--scribble-color': color,
|
|
} as React.CSSProperties}
|
|
>
|
|
{/* LED indicator */}
|
|
<div
|
|
className="scribble-led"
|
|
style={{
|
|
background: color,
|
|
boxShadow: isActive ? `0 0 6px ${color}` : 'none',
|
|
opacity: isActive ? 1 : 0.25,
|
|
}}
|
|
/>
|
|
|
|
{/* Label area — LCD-style */}
|
|
<div className="scribble-label-wrap">
|
|
<span className="scribble-label">{data.label || '—'}</span>
|
|
{data.sublabel && (
|
|
<span className="scribble-sublabel">{data.sublabel}</span>
|
|
)}
|
|
</div>
|
|
|
|
{/* Icon (optional) */}
|
|
{data.icon && <span className="scribble-icon">{data.icon}</span>}
|
|
</div>
|
|
);
|
|
}
|