feat(setup): flush action bar, global dbl-click maximize, open maximized (#318)

- First-run action bar is now a pinned flex sibling below a dedicated
  scroll region (.frs__scroll) — flush to the window's bottom edge, with
  nothing rendering beneath it; only the content above scrolls.
- Double-click-to-maximize is wired once in main.jsx, delegated across
  every data-tauri-drag-region (splash, first-run, wizard, main header)
  on all platforms, skipping interactive controls. Replaces the
  wizard-only handler in App.jsx.
- Main window opens maximized (tauri.conf.json).
- Setup wizard preflight checks flow into responsive columns on wide
  windows instead of one tall single column.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Palash Debnath
2026-06-11 01:34:55 +05:30
committed by GitHub
co-authored by Claude Fable 5
parent bfc90e90f5
commit 9cc55ef75e
7 changed files with 62 additions and 25 deletions
+2 -1
View File
@@ -23,7 +23,8 @@
"resizable": true,
"fullscreen": false,
"titleBarStyle": "Overlay",
"hiddenTitle": true
"hiddenTitle": true,
"maximized": true
},
{
"label": "widget",
+2 -7
View File
@@ -846,15 +846,10 @@ function App() {
{/* Invisible drag strip across the top 28 px of the wizard —
matches the macOS traffic-light zone so the window can be
dragged / double-click-zoomed from anywhere along the top. */}
{/* Double-click-to-maximize is handled globally in main.jsx for every
drag region (splash, first-run, wizard, main) on all platforms. */}
<div
data-tauri-drag-region
onDoubleClick={() => {
if ('__TAURI_INTERNALS__' in window) {
import('@tauri-apps/api/window').then(m =>
m.getCurrentWindow().toggleMaximize()
).catch(() => {});
}
}}
className="app-wizard-dragstrip"
/>
<Suspense fallback={<LazyFallback />}>
+28 -17
View File
@@ -22,8 +22,11 @@
position: fixed;
inset: 0;
/* Flex column: the deck fills the height and the action bar pins flush to the
bottom edge; only the inner .frs__scroll region scrolls. */
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
background: var(--frs-bg);
color: var(--frs-ink);
font-family: var(--font-sans, 'Inter Variable', system-ui, sans-serif);
@@ -31,8 +34,9 @@
/* Extra top clearance: the native titlebar (GTK headerbar / macOS
traffic lights / Windows controls) overlays the top of the window —
content must start below it, never under it. */
padding: 3.4rem 2.5rem 2rem;
overflow-y: auto;
/* No bottom padding: the action bar sits flush to the window's bottom edge. */
padding: 3.4rem 2.5rem 0;
overflow: hidden; /* the inner .frs__scroll region scrolls, not this */
}
/* No backdrop decoration: the journey sits on a clean flat surface — corner
@@ -46,16 +50,24 @@
position: relative;
width: 100%;
max-width: 1240px;
/* Top-anchored: the waveform opens the page right under the titlebar —
vertical centering left a dead zone above it on tall windows. */
margin: 0;
flex: 1 1 auto; /* fill the column height; the inner region scrolls */
min-height: 0; /* let the inner scroll region shrink + scroll */
display: flex;
flex-direction: column;
min-width: 0;
}
/* Scrollable region: masthead + decision grid. Only this scrolls — the action
bar (.frs__foot) is a sibling below it, so it stays flush at the bottom with
nothing rendering beneath it on small windows. */
.frs__scroll {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 1.1rem;
min-width: 0;
/* Fill the viewport (minus the shell's padding) so the sticky footer's
margin-top:auto hugs the bottom even when content is short. */
min-height: calc(100dvh - 5.4rem);
}
.frs__loading {
@@ -552,18 +564,17 @@
/* ── Footer: gate + armed button ───────────────────────────────────────── */
.frs__foot {
position: sticky;
bottom: 0;
z-index: 5;
/* Pinned action bar: the last flex item below the scroll region, so it sits
flush at the window's bottom edge while only the content above scrolls —
nothing renders beneath it. */
flex-shrink: 0;
display: flex;
flex-direction: column;
gap: 0.55rem;
padding-top: 0.6rem;
padding-bottom: 0.5rem;
margin-top: auto; /* hug the bottom when content is short */
padding-top: 0.7rem;
padding-bottom: 1.6rem;
background: var(--frs-bg);
/* soft top fade so scrolled content slips under, not against, the bar */
box-shadow: 0 -14px 14px -8px var(--frs-bg);
border-top: 1px solid var(--frs-line);
}
.frs__foot-row {
@@ -349,6 +349,7 @@ export default function FirstRunSetup() {
<div className="frs">
<div className="frs__atmo" aria-hidden="true" />
<div className="frs__deck">
<div className="frs__scroll">
{/* ── Masthead: waveform + serif headline + serial plate ────────── */}
<header className="frs__mast frs-rise" style={{ '--rise': 0 }} data-tauri-drag-region>
@@ -568,6 +569,7 @@ export default function FirstRunSetup() {
</Panel>
</div>
</div>
</div>
{/* ── Footer: gate + arm ────────────────────────────────────────── */}
<footer className="frs__foot frs-rise" style={{ '--rise': 5 }}>
+15
View File
@@ -9,3 +9,18 @@ if (import.meta.env.DEV && !window.__vite_plugin_react_preamble_installed__) {
const { bootstrapApp } = await import('./main-app.jsx');
bootstrapApp();
// Global double-click-to-maximize for the custom titlebar (all platforms).
// The window is borderless (decorations:false), so the OS won't zoom on a
// title-bar double-click — wire it ourselves once, delegated across every
// `data-tauri-drag-region` (splash, first-run, wizard, main header). Skips
// interactive controls inside the bar (selects/buttons), and no-ops in a
// plain browser (doubleClickMaximize guards on tauriWindow).
const { doubleClickMaximize } = await import('./utils/media');
window.addEventListener('dblclick', (e) => {
const t = e.target;
if (!t || typeof t.closest !== 'function') return;
if (!t.closest('[data-tauri-drag-region]')) return;
if (t.closest('button, a, input, select, textarea, label, [role="button"], [contenteditable]')) return;
doubleClickMaximize();
});
+11
View File
@@ -25,6 +25,17 @@
/* Recheck action lives inside the engraved panel title row. */
.swiz-recheck { letter-spacing: 0; text-transform: none; }
/* Preflight checks flow into responsive columns so the list stays short on a
wide/maximized window instead of one tall single column. Collapses to a
single column on narrow windows. */
.swiz-checks {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
column-gap: 1.6rem;
row-gap: 0.55rem;
align-items: start;
}
.swiz-loading {
display: flex;
align-items: center;
+2
View File
@@ -79,6 +79,7 @@ function PreflightPanel({ report, loading, onRecheck }) {
{t('setup.recheck')}
</button>
</h2>
<div className="swiz-checks">
{report.checks.map((c) => (
<div key={c.id} className={`frs-check frs-check--${c.status}`}>
<span className="frs-check__led" aria-hidden="true" />
@@ -91,6 +92,7 @@ function PreflightPanel({ report, loading, onRecheck }) {
</div>
</div>
))}
</div>
</section>
);
}