feat(studio): move UNDO and REDO icons to mobile topbar outside hamburger menu

This commit is contained in:
2026-10-14 15:43:01 +07:00
parent 70a7e7ad6f
commit 91d7d8d471
2 changed files with 48 additions and 31 deletions
+22 -4
View File
@@ -41,6 +41,7 @@
children of the row — and the phone, which has not, gets the panel under the
hamburger (see the narrow-screen rules below). */
.bar-menu { display: contents; }
.topbar-history { display: inline-flex; align-items: center; gap: 4px; }
.bar-toggle { display: none; }
/* The word a button keeps for that panel: the icon-only rules below take the
words out of the row, and the panel is where they are read again. */
@@ -2139,14 +2140,14 @@ form[data-key='immich-modal'] {
/* The bar stays at the top of the screen: the page itself never scrolls (the
stage does), but the declaration is what makes that a promise rather than a
coincidence. Sticky, not fixed — a positioned box still anchors the menus. */
.header { position: sticky; top: 0; z-index: 5; }
.header { position: sticky; top: 0; z-index: 5; flex-wrap: nowrap; gap: 8px; }
.menu-wrap { position: static; }
.popover { right: 8px; max-width: calc(100vw - 16px); }
/* --- the phone's bar: one line and one panel -----------------------------
The row of controls is what wraps the bar onto a second and a third line
here, so it is taken out of the row and hung under a hamburger in the
corner: brand, page name, the button — and every control one tap away,
each wearing the name the icon-only rules below took from it. */
corner: brand, page name, undo/redo icons, the button — and every control
one tap away, each wearing the name the icon-only rules below took from it. */
.bar-menu { display: none; }
.bar-menu.open {
display: flex;
@@ -2165,11 +2166,28 @@ form[data-key='immich-modal'] {
}
/* Nothing for the spacer to push against in a panel. */
.bar-menu.open .spacer { display: none; }
.topbar-history {
display: inline-flex;
align-items: center;
gap: 4px;
margin-left: auto;
}
.topbar-history .btn.icon {
width: 32px;
height: 30px;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 16px;
line-height: 1;
border-radius: 6px;
}
.bar-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: auto;
margin-left: 0;
font-size: 15px;
line-height: 1.2;
padding: 4px 10px;
+26 -27
View File
@@ -95,6 +95,32 @@ export function TopBar({
<b className="page-name">{t('nav.studio')}</b>
<span className="recipe-name">{recipeName}</span>
{/* Topbar history controls (Undo/Redo): located directly on topbar with icons only, no text */}
<div className="topbar-history">
<button
type="button"
className="btn ghost icon"
data-key="undo"
disabled={!canUndo}
title={t('act.undo')}
aria-label={t('act.undo')}
onClick={onUndo}
>
<span aria-hidden="true">↺</span>
</button>
<button
type="button"
className="btn ghost icon"
data-key="redo"
disabled={!canRedo}
title={t('act.redo')}
aria-label={t('act.redo')}
onClick={onRedo}
>
<span aria-hidden="true">↻</span>
</button>
</div>
{/* Everything the bar carries, in one box so a phone can fold it away:
see `.bar-menu` — `display: contents` wherever the row has the room
for the buttons, a panel under the hamburger where it has not. */}
@@ -139,33 +165,6 @@ export function TopBar({
</button>
) : null}
{/* Both arrows are one icon wide, so the pair reads as one control: the
counter-clockwise arrow steps back, the clockwise one forward. They sit
with the name they would take back — after the mark and the preset. */}
<button
type="button"
className="btn ghost icon"
data-key="undo"
disabled={!canUndo}
title={t('act.undo')}
aria-label={t('act.undo')}
onClick={onUndo}
>
<span aria-hidden="true">↺</span>
<span className="mob-label">{t('act.undo')}</span>
</button>
<button
type="button"
className="btn ghost icon"
data-key="redo"
disabled={!canRedo}
title={t('act.redo')}
aria-label={t('act.redo')}
onClick={onRedo}
>
<span aria-hidden="true">↻</span>
<span className="mob-label">{t('act.redo')}</span>
</button>
<span className="spacer" />
{/* The catalogue's own reading runs in this tab whatever screen is up, so