v1.1.4: light-theme support (LED wells, panel buttons, readouts)

The controls whose chrome was hardcoded dark now adapt to a light base —
previously they rendered as dark chips/holes on light themes. (Flat knobs and
faders already adapted: their face is the `face` token.)

- `ledWell` theme token — the recessed screen behind LED segments (LEDKnob,
  LEDFader, Meter) and the default well of SegmentDisplay / AlphaDisplay now
  comes from the theme. Dark base keeps #0b0d0e; light base is `transparent`,
  so LED controls and readouts render as clean flat rings / bars / digits on
  the light panel. faceColor / background props still override.
- `scheme` theme token ('dark' | 'light', set by base) + a shared
  panelButtonChrome() helper drive the raised gradient/border/shadow of
  PushButton (and Button), TransportButton and SegmentSwitch — light raised
  buttons on light themes instead of dark chips; unlit LED pips flip to a
  faint dark so they still read.
- Docs: a "Light theme" gallery card showing the panel family under
  base="light"; ledWell/scheme documented; install URLs bumped to v1.1.4.

Library + docs typecheck and build; 46 tests pass.
This commit is contained in:
Dreamodus 2026-07-14 13:06:16 -07:00
parent d183d7d16b
commit 8b462dfb83
17 changed files with 180 additions and 44 deletions

View file

@ -195,6 +195,7 @@ export const ApiDocs: React.FC = () => (
ledGreen: '#3df2ad', // SegmentDisplay default lit color
ledAmber: '#ffb84d', // AlphaDisplay default lit color
panel: 'rgba(255,255,255,0.03)', // Rack / panel chrome
ledWell: '#0b0d0e', // LED display well (LEDKnob/LEDFader/Meter)
}}
>
<FlatKnob ... /> <Fader ... /> <LEDKnob ... />

View file

@ -352,6 +352,42 @@ const PanDemo: React.FC = () => (
</div>
);
const LightThemeDemo: React.FC = () => {
const [play, setPlay] = React.useState(false);
const [mute, setMute] = React.useState(true);
return (
<DreamknobProvider base="light" theme={{ accent: '#0868c8' }}>
<div
style={{
background: '#eceef2',
borderRadius: 12,
padding: 18,
display: 'flex',
flexDirection: 'column',
gap: 16,
alignItems: 'center',
}}
>
<div style={{ display: 'flex', gap: 18, alignItems: 'center' }}>
<LEDKnob size={74} min={20} max={2000} defaultValue={440} taper={logTaper} label="Freq" unit="Hz" aria-label="Light freq" />
<SegmentDisplay value={128.4} digits={4} decimals={1} height={22} />
<Meter value={[62, 44]} min={0} max={100} length={92} breadth={14} aria-label="Light meter" />
</div>
<div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
<PushButton pressed={mute} onChange={setMute} color="#d92546" size={32} aria-label="Mute">
Mute
</PushButton>
<Button color="#0868c8" size={32} onClick={() => undefined} aria-label="Apply">
Apply
</Button>
<TransportButton kind="play" active={play} onClick={() => setPlay(p => !p)} size={32} />
<SegmentSwitch options={['LP', 'BP', 'HP']} defaultValue={1} aria-label="Light filter" />
</div>
</div>
</DreamknobProvider>
);
};
const ImageKnobDemo: React.FC = () => {
const src = useGeneratedStrip();
if (!src) return null;
@ -565,6 +601,10 @@ export const Gallery: React.FC = () => (
</div>
</Card>
<Card title="Light theme" desc="base='light' adapts the whole panel — LED wells go transparent so readouts and meters read as flat segments, and the buttons/switches become light raised chrome instead of dark chips." tag="<DreamknobProvider base='light' />">
<LightThemeDemo />
</Card>
<Card title="Meters" desc="Stereo metering from one component (value={[l, r]}), or a full labeled bridge with per-channel peak text. Click the clip LED to clear it." tag="<Meter /> · <MeterBridge />">
<MeterDemo />
</Card>

View file

@ -30,12 +30,12 @@ export const GettingStarted: React.FC = () => (
<Step n={1} title="Install">
<CodeBlock
code={`pnpm add https://git.dreamodus.software/Dreamodus/DreamKnob/releases/download/v1.1.3/dreamknob-1.1.3.tgz\n# (or npm install <same url>) · peer deps: react >= 18, react-dom >= 18`}
code={`pnpm add https://git.dreamodus.software/Dreamodus/DreamKnob/releases/download/v1.1.4/dreamknob-1.1.4.tgz\n# (or npm install <same url>) · peer deps: react >= 18, react-dom >= 18`}
/>
<p className="api-note" style={{ marginTop: 10 }}>
Installs straight from the{' '}
<a href="https://git.dreamodus.software/Dreamodus/DreamKnob/releases">
v1.1.3 release
v1.1.4 release
</a>{' '}
on our Forgejo. Zero runtime dependencies, ESM + CJS, full TypeScript types. No
CSS file to import everything is SVG and inline styles.

View file

@ -25,10 +25,10 @@ export const Hero: React.FC = () => {
range, any decimal precision, and colors you fully control.
</p>
<div className="install">
<span>pnpm add https://git.dreamodus.software/Dreamodus/DreamKnob/releases/download/v1.1.3/dreamknob-1.1.3.tgz</span>
<span>pnpm add https://git.dreamodus.software/Dreamodus/DreamKnob/releases/download/v1.1.4/dreamknob-1.1.4.tgz</span>
<button
onClick={() => {
navigator.clipboard.writeText('pnpm add https://git.dreamodus.software/Dreamodus/DreamKnob/releases/download/v1.1.3/dreamknob-1.1.3.tgz');
navigator.clipboard.writeText('pnpm add https://git.dreamodus.software/Dreamodus/DreamKnob/releases/download/v1.1.4/dreamknob-1.1.4.tgz');
setCopied(true);
setTimeout(() => setCopied(false), 1400);
}}