feat(panel): cascading columns, WB colour swatches, stronger HDF glow
Layout - the panel is a cascade of columns: the rail's tabs, the tab's chips, the open chip's sub-chips, then the ruler. A child column no longer hides the column it came from (TEMP -> COLOR TEMP keeps TEMP visible); chips stack one per row instead of wrapping - FRAME's WATERMARK opens its own column, so the frame chips stay put - CREATE RECIPES gets the wide column its two-up form needs WB colour swatches - the ruler draws a colour box under the slider that follows the value: COLOR TEMP is the Kelvin colour (Tanner Helland), TINT runs green -10 -> neutral 0 -> magenta +10 HDF EFFECT - knee 0.55..0.85 -> 0.45..0.75, blur 0.004+0.015n -> 0.006+0.024n of the width, screen alpha 0.15+0.35n -> 0.28+0.52n: a wide halo on the highlights instead of a hairline glow. Web copy of toneShader only — the phone keeps its own tuning. Tabs - rail order is PRESETS, FAVORITED, WB, LIGHT, FX, FRAME, CREATE RECIPES
This commit is contained in:
@@ -27,6 +27,9 @@ export interface SliderDef {
|
||||
display: string;
|
||||
// amber value readout once the knob leaves its default (phone's ruler row)
|
||||
edited: boolean;
|
||||
// CSS colour the knob is currently driving (WB's temperature/tint), drawn as a
|
||||
// swatch under the ruler so the hue moves with the number. Absent = no swatch.
|
||||
swatch?: string;
|
||||
onChange: (value: number) => void;
|
||||
// "<" — closes the ruler and reopens the strip it was launched from.
|
||||
onBack: () => void;
|
||||
@@ -90,6 +93,17 @@ export function SliderRow({ slider }: { slider: SliderDef }) {
|
||||
value={slider.value}
|
||||
onChange={(e) => slider.onChange(Number(e.target.value))}
|
||||
/>
|
||||
{slider.swatch ? (
|
||||
<div
|
||||
className="swatch"
|
||||
data-key={`swatch-${slider.key}`}
|
||||
data-color={slider.swatch}
|
||||
style={{ background: slider.swatch }}
|
||||
title={slider.swatch}
|
||||
>
|
||||
<span>{slider.swatch}</span>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import type { MsgKey } from '../i18n/vi';
|
||||
import { useI18n } from '../i18n/I18nProvider';
|
||||
|
||||
// The app's six tabs, in the same order as the phone rail. The rail is vertical
|
||||
// on desktop and becomes the bottom bar under 860px (see styles/app.css).
|
||||
export type TabId = 'presets' | 'favorited' | 'light' | 'wb' | 'fx' | 'frame' | 'create';
|
||||
// The app's seven tabs. WB leads LIGHT — white balance is the first thing the
|
||||
// eye corrects, and the web rail draws them in the order the panel opens. The
|
||||
// rail is a single column on desktop and becomes the bottom bar under 860px
|
||||
// (see styles/app.css).
|
||||
export type TabId = 'presets' | 'favorited' | 'wb' | 'light' | 'fx' | 'frame' | 'create';
|
||||
|
||||
export const TABS: { id: TabId; label: MsgKey; glyph: string }[] = [
|
||||
{ id: 'presets', label: 'tab.presets', glyph: '◉' },
|
||||
{ id: 'favorited', label: 'tab.favorited', glyph: '★' },
|
||||
{ id: 'light', label: 'tab.light', glyph: '☀' },
|
||||
{ id: 'wb', label: 'tab.wb', glyph: '◐' },
|
||||
{ id: 'light', label: 'tab.light', glyph: '☀' },
|
||||
{ id: 'fx', label: 'tab.fx', glyph: '✦' },
|
||||
{ id: 'frame', label: 'tab.frame', glyph: '▣' },
|
||||
{ id: 'create', label: 'tab.create', glyph: '✎' },
|
||||
|
||||
Reference in New Issue
Block a user