web: the RECIPES chip hands the phone's bar to the list, not a second row over it — IMPORT .RECIPE stays the tab's own chip, and the path says TABS > PRESETS > RECIPES

On a phone the bar holds one level: the tab's chips, or the strip a chip of
theirs opened. The RECIPES list was the exception — it stood over the bar
with the bar still under it, so the level the finger had just asked for was
drawn twice, once as the list and once as its own row of chips.

The list now displaces the bar, beside the option groups and the watermark,
and wears the bar's slot and skin: that row IS the bar now.

IMPORT .RECIPE is not one of the looks the list holds, so it does not go
into the list — the way in belongs to the chip that opens it, not to the
content it fills. It stands in the tab's own row, one chip over from RECIPES
and at the same level, which is where it already stood on a wide screen. It
stands down with the bar while the list is open, as every chip of that row
does.

With the bar gone the tab's chip is gone too, so the path under the strip
grows the level: TABS > PRESETS > RECIPES, and PRESETS in it returns to the
tab's own chips. A wide screen is untouched — the bar never stands down
there; it simply gains the chip in its own row.

Checked on the running bundle (390x844 and 1280x900): the bar holds the
three chips in one row, the list takes the bar's slot under the ceiling
holding looks and nothing else, IMPORT is not among them, the path reads and
walks back, and a wide screen keeps its bar.
This commit is contained in:
2026-10-01 14:39:40 +07:00
parent e53d6264ca
commit 9b24ce7bbc
2 changed files with 24 additions and 19 deletions
+13 -13
View File
@@ -2864,9 +2864,13 @@ export function Workspace() {
setShowRecipes((v) => !v);
},
},
// IMPORT is not a look to open but the way a look gets into the list,
// so it stands at the tab's own level, beside the chip that opens the
// list — the list itself is a level down, and the way in is not one of
// the things it holds.
{ key: 'recipes-import', label: 'IMPORT .RECIPE', onClick: pickRecipeFile },
// ponytail: no CREATE chip — making a recipe and filing the look on
// the stage are their own rail tabs (SAVE RECENT, CREATE RECIPES).
// IMPORT is the chip under RECIPES in the tab's own column.
];
case 'favorited':
return saved.length === 0
@@ -3215,11 +3219,6 @@ export function Workspace() {
// but never filed + the bundled presets. A CREATE that a signed-in account
// stored lands in `saved` too, so it is dropped from `created` by name here.
//
// IMPORT is not one of them: it is not a look to open but the way a look gets
// into the list, so it stands in the tab's own column under the RECIPES chip
// that opens the list — the file the phone (or another account) exports, same
// envelope, same parser, so a look crosses devices intact.
const importChip: ChipDef = { key: 'recipes-import', label: 'IMPORT .RECIPE', onClick: pickRecipeFile };
const recipeStrip: ChipDef[] = [
...saved.map((entry) => ({
key: `saved-${entry.id}`,
@@ -3385,8 +3384,15 @@ export function Workspace() {
onClick: () => {
setOpenGroup(null);
setOpenParam(null);
setShowRecipes(false);
},
},
// The RECIPES list is a level of its own, though no group holds it: on a
// phone it takes the bar's slot (see .col-sub[data-col="recipes"]), so the
// name here is the only way back to the tab's own chips.
...(tab === 'presets' && showRecipes
? [{ key: 'recipes', label: t('sec.recipes'), onClick: () => setShowRecipes(false) }]
: []),
...(openGroup ? [{ key: 'strip', label: stripLabel(openGroup), onClick: () => setOpenParam(null) }] : []),
// A ruler is a row, not a strip: its name is the knob's, and the strip it
// came from is the level above — COLOR TEMP under WB.
@@ -3557,13 +3563,7 @@ export function Workspace() {
/>
</>
) : (
<>
<ChipRow chips={chips} />
{/* IMPORT stands under the chip that opens the RECIPES
list: a look is imported INTO that list, so the way in
belongs to the chip, not to the list it fills. */}
{tab === 'presets' && showRecipes ? <ChipRow chips={[importChip]} /> : null}
</>
<ChipRow chips={chips} />
)}
</>
)}
+11 -6
View File
@@ -1647,12 +1647,16 @@ input[type="range"] { width: 100%; accent-color: var(--accent); }
them is the path under the bar (.crumb), which names the strip they are —
so a second row of chips over the first would only repeat where the finger
already is, and charge the photo a row for it while a knob is being moved.
Only the two columns that ARE a strip a chip opened displace the bar: the
RECIPES list, a photo's history and the mask's own column are an open
chip's content, not the strip its chip opened, and they keep the bar in
sight under them. Both wear the bar's slot and the bar's own skin, not the
Only the columns that ARE a strip a chip opened displace the bar: the
option groups, the watermark, and RECIPES. Each of those is what a chip of
theirs opened, so the bar would draw the level the finger just asked for
twice — once as the chip that opened it, once as the strip itself — and the
second is the one the finger is reaching into. A photo's history and the
mask's own column are not that: they are an open chip's content, not the
strip its chip opened, and they keep the bar in sight under them. The
displacing three wear the bar's slot and the bar's own skin, not the
sub-column's — this row IS the bar now. */
.col-sub[data-col="options"], .col-sub[data-col="wm"] {
.col-sub[data-col="options"], .col-sub[data-col="wm"], .col-sub[data-col="recipes"] {
order: 3;
background: var(--bg);
max-height: 46vh;
@@ -1661,7 +1665,8 @@ input[type="range"] { width: 100%; accent-color: var(--accent); }
the slot, with the bar's rule over it and the same ceiling. */
.col-sub[data-col="wm"] { border-top: 1px solid var(--border-soft); overflow-y: auto; }
.workspace:has(.chips > .col-sub[data-col="options"]) .col-main,
.workspace:has(.chips > .col-sub[data-col="wm"]) .col-main { display: none; }
.workspace:has(.chips > .col-sub[data-col="wm"]) .col-main,
.workspace:has(.chips > .col-sub[data-col="recipes"]) .col-main { display: none; }
/* One strip at a time holds here too: the ruler a knob opens is the last
strip of the walk, so it takes the place of the strip that opened it. The