v1.1.1: second integration-feedback release
Readout legibility (the #1 ask): - bold own-cell decimal point + colon in seven/fourteen-seg (not hairlines) - weight prop thickens strokes; gap controls inter-cell kerning Display colors: - SegmentDisplay defaults to theme.ledGreen, AlphaDisplay to theme.ledAmber - valueColor fn + value-space zones on SegmentDisplay (self-coloring readouts) - charset: colon in both, $ and % in 14-seg; disabled + data-disabled Knob captions: sublabel (second line) + labelSize (independent of dial size). New components: - ToggleSwitch (rocker/slider boolean, role=switch) - Gauge (read-only radial arc meter, round sibling of Meter) - TransportButton (play/stop/record/pause/panic, record blinks) - LampRow (console-print lamp bank), LabeledField, Rack (panel chrome) Responsiveness: fill on Meter + Fader (stretch to container). Niceties: PushButton leadingIcon; theme ledGreen/ledAmber/panel tokens. 54 -> 63 exports. 38 unit tests. Browser-verified.
This commit is contained in:
parent
d8b7b55505
commit
5b97091902
32 changed files with 1535 additions and 133 deletions
|
|
@ -5,10 +5,13 @@ import {
|
|||
DreamknobProvider,
|
||||
Fader,
|
||||
FlatKnob,
|
||||
Gauge,
|
||||
ImageKnob,
|
||||
Knob,
|
||||
KnobValue,
|
||||
IndicatorLamp,
|
||||
LabeledField,
|
||||
LampRow,
|
||||
LEDFader,
|
||||
LEDKnob,
|
||||
MetalKnob,
|
||||
|
|
@ -17,12 +20,15 @@ import {
|
|||
NeonKnob,
|
||||
Pointer,
|
||||
PushButton,
|
||||
Rack,
|
||||
RubberKnob,
|
||||
ScrubField,
|
||||
SegmentSwitch,
|
||||
SegmentDisplay,
|
||||
SteppedKnob,
|
||||
Ticks,
|
||||
ToggleSwitch,
|
||||
TransportButton,
|
||||
VintageKnob,
|
||||
XYPad,
|
||||
logTaper,
|
||||
|
|
@ -197,6 +203,95 @@ const CommitModeDemo: React.FC = () => {
|
|||
);
|
||||
};
|
||||
|
||||
const RESOURCE_ZONES = [
|
||||
{ upTo: 0.75, color: '#3df2ad' },
|
||||
{ upTo: 0.9, color: '#ffd23e' },
|
||||
{ upTo: 1, color: '#ff4d6b' },
|
||||
];
|
||||
|
||||
const GaugeDemo: React.FC = () => {
|
||||
const [load, setLoad] = React.useState<[number, number]>([38, 61]);
|
||||
React.useEffect(() => {
|
||||
let t = 0;
|
||||
const id = setInterval(() => {
|
||||
t += 0.12;
|
||||
setLoad([
|
||||
Math.max(2, Math.min(100, 45 + Math.sin(t) * 30 + Math.random() * 12)),
|
||||
Math.max(2, Math.min(100, 62 + Math.sin(t * 0.7 + 2) * 26 + Math.random() * 10)),
|
||||
]);
|
||||
}, 140);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: 18, alignItems: 'center' }}>
|
||||
<Gauge value={load[0]} min={0} max={100} size={104} unit="%" label="CPU" zones={RESOURCE_ZONES} />
|
||||
<Gauge value={load[1]} min={0} max={100} size={104} unit="%" label="GPU" zones={RESOURCE_ZONES} needle={false} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const SmallReadoutDemo: React.FC = () => {
|
||||
const [t, setT] = React.useState(0);
|
||||
React.useEffect(() => {
|
||||
const id = setInterval(() => setT(v => v + 1), 1000);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
const hh = String(Math.floor(t / 3600) % 100).padStart(2, '0');
|
||||
const mm = String(Math.floor(t / 60) % 60).padStart(2, '0');
|
||||
const ss = String(t % 60).padStart(2, '0');
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 14, alignItems: 'center' }}>
|
||||
<div style={{ display: 'flex', gap: 16, alignItems: 'center' }}>
|
||||
<SegmentDisplay value={17.5} digits={3} decimals={1} height={13} weight={1.5} />
|
||||
<SegmentDisplay value={`${hh}:${mm}:${ss}`} height={13} weight={1.4} />
|
||||
</div>
|
||||
<div style={{ display: 'flex', gap: 16, alignItems: 'center' }}>
|
||||
<SegmentDisplay value={82} digits={3} height={16} weight={1.4} zones={[
|
||||
{ upTo: 74, color: '#3df2ad' },
|
||||
{ upTo: 89, color: '#ffd23e' },
|
||||
{ upTo: Infinity, color: '#ff4d6b' },
|
||||
]} />
|
||||
<AlphaDisplay value="$4.20" height={15} weight={1.3} />
|
||||
<AlphaDisplay value="47%" height={15} weight={1.3} color="#3df2ad" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const PanelDemo: React.FC = () => {
|
||||
const [fresh, setFresh] = React.useState(true);
|
||||
const [mode, setMode] = React.useState(0);
|
||||
const [playing, setPlaying] = React.useState(false);
|
||||
const [armed, setArmed] = React.useState(false);
|
||||
return (
|
||||
<Rack orientation="column" title="Performer" accentColor="#c9a6ff">
|
||||
<div style={{ display: 'flex', gap: 16, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<FlatKnob size={62} defaultValue={7} min={0} max={64} step={1} color="#c9a6ff"
|
||||
label="Seed" sublabel="world #7" labelSize={9} aria-label="Seed" />
|
||||
<FlatKnob size={62} defaultValue={40} min={0} max={100} color="#c9a6ff"
|
||||
label="Refresh" sublabel="every 40" labelSize={9} aria-label="Refresh" />
|
||||
</div>
|
||||
<div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
|
||||
<TransportButton kind="play" active={playing} onClick={() => setPlaying(p => !p)} size={34} />
|
||||
<TransportButton kind="stop" onClick={() => setPlaying(false)} size={34} />
|
||||
<TransportButton kind="record" active={armed} onClick={() => setArmed(a => !a)} size={34} />
|
||||
<TransportButton kind="panic" onClick={() => { setPlaying(false); setArmed(false); }} size={34} />
|
||||
</div>
|
||||
<LabeledField label="Fresh seed" labelWidth={78}>
|
||||
<ToggleSwitch on={fresh} onChange={setFresh} color="#c9a6ff" showStateLabel aria-label="Fresh seed" />
|
||||
</LabeledField>
|
||||
<SegmentSwitch options={['SOLID', 'GRAD', 'NOISE']} value={mode} onChange={setMode} color="#c9a6ff" aria-label="Fill mode" />
|
||||
<LampRow
|
||||
lamps={[
|
||||
{ label: 'Cue', on: playing, color: '#3df2ad' },
|
||||
{ label: 'Rec', on: armed, color: '#ff4d6b' },
|
||||
{ label: 'Seed', on: fresh, color: '#c9a6ff' },
|
||||
]}
|
||||
/>
|
||||
</Rack>
|
||||
);
|
||||
};
|
||||
|
||||
const ImageKnobDemo: React.FC = () => {
|
||||
const src = useGeneratedStrip();
|
||||
if (!src) return null;
|
||||
|
|
@ -429,6 +524,18 @@ export const Gallery: React.FC = () => (
|
|||
<CommitModeDemo />
|
||||
</Card>
|
||||
|
||||
<Card title="Gauge" desc="Read-only radial arc meter — the round sibling of Meter. Colors itself green→amber→red as load climbs." tag="<Gauge />">
|
||||
<GaugeDemo />
|
||||
</Card>
|
||||
|
||||
<Card title="Small readouts" desc="Bold own-cell decimal + colon, weight to thicken strokes, and value-colored zones — legible at status-bar sizes. Colons and $/% are in the charset." tag="weight · zones · : $ %">
|
||||
<SmallReadoutDemo />
|
||||
</Card>
|
||||
|
||||
<Card title="Panel: strip + switches" desc="Rack chrome, ToggleSwitch, TransportButton, SegmentSwitch and a LampRow — a console section, declarative." tag="<Rack /> · <ToggleSwitch /> · <TransportButton />">
|
||||
<PanelDemo />
|
||||
</Card>
|
||||
|
||||
<Card title="Gradient arc" desc="Position-anchored gradient — the red zone stays at the top of travel." tag="<Arc gradient={...} />">
|
||||
<Knob size={96} min={-60} max={6} step={0.5} defaultValue={-8} aria-label="Gradient arc demo">
|
||||
<Arc
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue