diff --git a/docker/frontend/src/App.tsx b/docker/frontend/src/App.tsx
index ba63c69..3c8eec8 100644
--- a/docker/frontend/src/App.tsx
+++ b/docker/frontend/src/App.tsx
@@ -175,6 +175,13 @@ function hslToHex(h: number, s: number, l: number): string {
return `#${chan(0)}${chan(8)}${chan(4)}`;
}
+// The way back: a band chip hands the eyedropper's readout the colour it is
+// named after, and that readout is RGB bytes.
+function hexToRgb(hex: string): { r: number; g: number; b: number } {
+ const n = parseInt(hex.slice(1), 16);
+ return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
+}
+
// The knobs that drive a colour get a swatch under their ruler, so the hue is
// visible next to the number. TEMP is the only one left on this path: TINT's row
// lives in the sidebar's WB panel now, so its ±10 axis draws no ruler here.
@@ -2862,7 +2869,16 @@ export function Workspace() {
color: hslToHex(b.hue, 70, 50),
active: hslBand === b.id,
amberValue: hslBand !== b.id && moved,
- onClick: () => setHslBand(b.id),
+ // A band chip aims the mixer AND opens its panel, the same panel
+ // the eyedropper opens: the colour it starts from is the colour
+ // the chip is named after, and this band's knobs push it from
+ // there. A pick already on the photo keeps its spot — only a
+ // mixer with nowhere to hang takes the middle of the frame.
+ onClick: () => {
+ setHslBand(b.id);
+ setSample(hexToRgb(hslToHex(b.hue, 70, 50)));
+ setPickedAt((at) => at ?? { fx: 0.5, fy: 0.5 });
+ },
};
}),
// The divider keeps the three image-wide sliders out of the colour
@@ -3249,7 +3265,7 @@ export function Workspace() {
aria-pressed={recipe.name === entry.name}
onClick={() => applyRecipe({ ...(entry.recipe as Recipe), name: entry.name })}
>
- {entry.name}
+ {entry.name}
{/* Only this account can delete its own file — the API
scopes the delete by user, the button mirrors it. */}
@@ -3261,7 +3277,7 @@ export function Workspace() {
aria-label={t('save.delete')}
onClick={() => void deleteRecipeEntry(entry)}
>
- ✕
+ ✕
))}
@@ -3359,7 +3375,7 @@ export function Workspace() {
disabled={locating}
onClick={() => locateMe()}
>
- {locating ? t('wm.locating') : t('wm.useLocation')}
+ {locating ? t('wm.locating') : t('wm.useLocation')}
{/* The same colour groups the workspace offers; the page's own
@@ -642,7 +642,7 @@ export function Landing() {
className={`chip${accent === entry.id ? ' on' : ''}`}
onClick={() => setAccent(entry.id)}
>
- {entry.label}
+ {entry.label}
))}
diff --git a/docker/frontend/src/Library.tsx b/docker/frontend/src/Library.tsx
index ca8c82f..8aff98c 100644
--- a/docker/frontend/src/Library.tsx
+++ b/docker/frontend/src/Library.tsx
@@ -684,7 +684,7 @@ export function Library() {
title={t('lib.subsHint')}
onClick={() => setDeep((prev) => !prev)}
>
- {t(deep ? 'lib.subsHide' : 'lib.subsShow')}
+ {t(deep ? 'lib.subsHide' : 'lib.subsShow')}
>
) : null}
diff --git a/docker/frontend/src/ui/ChipColumn.tsx b/docker/frontend/src/ui/ChipColumn.tsx
index 19558e7..d6d3966 100644
--- a/docker/frontend/src/ui/ChipColumn.tsx
+++ b/docker/frontend/src/ui/ChipColumn.tsx
@@ -99,7 +99,12 @@ export function ChipRow({ chips, grid }: { chips: ChipDef[]; grid?: boolean }) {
}}
>
{chip.color ? : null}
- {chip.label}
+ {/* The name is a box, not the bare text node it used to be: a flex
+ container turns a loose text node into an anonymous item of its
+ own, and on iOS that item stops being painted until the column
+ it sits in is touched. Same fault, same shape as the panel head
+ (see `dev-panel-label` in DevelopPanels). No rule of its own. */}
+ {chip.label}
{chip.value ? {chip.value} : null}
{chip.pro ? PRO : null}
diff --git a/docker/frontend/src/ui/ToolRail.tsx b/docker/frontend/src/ui/ToolRail.tsx
index 6963c3b..2a9b923 100644
--- a/docker/frontend/src/ui/ToolRail.tsx
+++ b/docker/frontend/src/ui/ToolRail.tsx
@@ -72,7 +72,10 @@ export function ToolRail({
}}
>
{entry.glyph}
- {t(entry.label)}
+ {/* A box, not a bare text node: on a phone the glyph is display:none
+ and the name would be the button's only child — an anonymous flex
+ item, which is the one thing iOS stops painting until a touch. */}
+ {t(entry.label)}
))}
{/* The build this page came off, at the foot of the rail: an image on the
diff --git a/docker/frontend/src/ui/TopBar.tsx b/docker/frontend/src/ui/TopBar.tsx
index d63a675..1edf55f 100644
--- a/docker/frontend/src/ui/TopBar.tsx
+++ b/docker/frontend/src/ui/TopBar.tsx
@@ -155,9 +155,13 @@ export function TopBar({
{menu === 'theme' ? (
-
-
-
+ {/* The name is a span, not a bare text node: a chip is a flex row,
+ and a loose text node in one is an anonymous item — the shape
+ iOS stops painting until the page is touched (same as the
+ panel heads and ChipRow's chips). */}
+
+
+