Skip to content

Commit 95191e2

Browse files
committed
Modal dialogs follow macOS layout: left-aligned title and text, right-aligned buttons
Reworks every modal dialog to the macOS convention so the app reads native and consistent: titles and body text left-aligned, action buttons right-aligned with the primary action rightmost. - `ModalDialog` gains a central `footer` snippet that renders action buttons in a right-aligned `.modal-footer` (owning the alignment, gap, and bottom padding), and left-aligns the title `<h2>`. Callers pass buttons via `footer` and drop their bespoke button-row CSS, so alignment can't drift per dialog. - Title bar is vertically balanced: top padding matches the footer's bottom (`--spacing-xl`), with `--spacing-md` of breathing room below the title. Bodies use `0 var(--spacing-xl)` side padding so title, text, and buttons line up flush at one left inset (several dialogs were inset further at `2xl`). - Migrates the full set: alert, delete, transfer (confirm + error), new file/folder, rename-conflict, extension-change, feedback, crash/error reporters, go-to-path, connect-to-server, licensing (key/expiration/reminder), MTP permission/ptpcamerad, stale-drive, what's new, viewer copy, AI-model delete, and the Debug components catalog. - Copy/move and delete dialogs are fully left-aligned (scan stats, throughput, conflict-policy radios, segmented Trash/Delete and Copy/Move controls, overflow note, and the source->destination direction indicator). - Deliberately centered surfaces stay centered: the About hero, the progress dialog's live readouts, spinners, and icon glyphs. - Fixes a pre-existing a11y bug in the viewer copy dialogs (a nested `<h2>` carrying a duplicate `id`). - Documents the layout convention in `lib/ui/DETAILS.md`.
1 parent ce96d80 commit 95191e2

26 files changed

Lines changed: 214 additions & 356 deletions

apps/desktop/src/lib/crash-reporter/CrashReportDialog.svelte

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -128,22 +128,21 @@
128128
<span>{t('crashReporter.dialog.attachEmail', { email: contactEmail })}</span>
129129
</label>
130130
{/if}
131-
132-
<!-- Actions -->
133-
<div class="button-row">
134-
<Button variant="secondary" onclick={handleDismiss} disabled={sending}
135-
>{tString('crashReporter.dialog.dismiss')}</Button
136-
>
137-
<Button variant="primary" onclick={() => void handleSend()} disabled={sending}>
138-
{sending ? tString('crashReporter.dialog.sending') : tString('crashReporter.dialog.send')}
139-
</Button>
140-
</div>
141131
</div>
132+
133+
{#snippet footer()}
134+
<Button variant="secondary" onclick={handleDismiss} disabled={sending}
135+
>{tString('crashReporter.dialog.dismiss')}</Button
136+
>
137+
<Button variant="primary" onclick={() => void handleSend()} disabled={sending}>
138+
{sending ? tString('crashReporter.dialog.sending') : tString('crashReporter.dialog.send')}
139+
</Button>
140+
{/snippet}
142141
</ModalDialog>
143142

144143
<style>
145144
.body {
146-
padding: 0 var(--spacing-xl) var(--spacing-xl);
145+
padding: 0 var(--spacing-xl);
147146
}
148147
149148
.description {
@@ -252,10 +251,4 @@
252251
.always-send input[type='checkbox'] {
253252
accent-color: var(--color-accent);
254253
}
255-
256-
.button-row {
257-
display: flex;
258-
gap: var(--spacing-md);
259-
justify-content: center;
260-
}
261254
</style>

apps/desktop/src/lib/feedback/FeedbackDialog.svelte

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -173,26 +173,19 @@
173173
{#if sendFailedMessage}
174174
<p class="status status-error" role="alert">{sendFailedMessage}</p>
175175
{/if}
176-
177-
<div class="button-row">
178-
<span class="spacer"></span>
179-
<Button variant="secondary" onclick={handleClose} disabled={sending}
180-
>{tString('feedback.dialog.cancel')}</Button
181-
>
182-
<Button
183-
variant="primary"
184-
onclick={() => void handleSend()}
185-
disabled={sending || isEmpty || overLimit}
186-
>
187-
{sending ? tString('feedback.dialog.sending') : tString('feedback.dialog.send')}
188-
</Button>
189-
</div>
190176
</div>
177+
178+
{#snippet footer()}
179+
<Button variant="secondary" onclick={handleClose} disabled={sending}>{tString('feedback.dialog.cancel')}</Button>
180+
<Button variant="primary" onclick={() => void handleSend()} disabled={sending || isEmpty || overLimit}>
181+
{sending ? tString('feedback.dialog.sending') : tString('feedback.dialog.send')}
182+
</Button>
183+
{/snippet}
191184
</ModalDialog>
192185

193186
<style>
194187
.body {
195-
padding: 0 var(--spacing-xl) var(--spacing-xl);
188+
padding: 0 var(--spacing-xl);
196189
}
197190
198191
.description {
@@ -273,14 +266,4 @@
273266
.status-error {
274267
color: var(--color-error);
275268
}
276-
277-
.button-row {
278-
display: flex;
279-
align-items: center;
280-
gap: var(--spacing-md);
281-
}
282-
283-
.spacer {
284-
flex: 1;
285-
}
286269
</style>

apps/desktop/src/lib/file-explorer/network/ConnectToServerDialog.svelte

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -89,23 +89,24 @@
8989
{/if}
9090
</div>
9191

92-
<div class="button-row">
93-
<Button variant="secondary" onclick={onClose}>{tString('fileExplorer.network.cancel')}</Button>
94-
<Button variant="primary" onclick={() => void handleSubmit()} disabled={!canSubmit}>
95-
{#if dialogState === 'connecting'}
96-
<Spinner size="sm" />
97-
{tString('fileExplorer.network.connecting')}
98-
{:else}
99-
{tString('fileExplorer.network.connect')}
100-
{/if}
101-
</Button>
102-
</div>
10392
</div>
93+
94+
{#snippet footer()}
95+
<Button variant="secondary" onclick={onClose}>{tString('fileExplorer.network.cancel')}</Button>
96+
<Button variant="primary" onclick={() => void handleSubmit()} disabled={!canSubmit}>
97+
{#if dialogState === 'connecting'}
98+
<Spinner size="sm" />
99+
{tString('fileExplorer.network.connecting')}
100+
{:else}
101+
{tString('fileExplorer.network.connect')}
102+
{/if}
103+
</Button>
104+
{/snippet}
104105
</ModalDialog>
105106

106107
<style>
107108
.dialog-body {
108-
padding: 0 var(--spacing-xl) var(--spacing-xl);
109+
padding: 0 var(--spacing-xl);
109110
}
110111
111112
.input-group {
@@ -156,10 +157,4 @@
156157
font-size: var(--font-size-sm);
157158
color: var(--color-error);
158159
}
159-
160-
.button-row {
161-
display: flex;
162-
gap: var(--spacing-md);
163-
justify-content: center;
164-
}
165160
</style>

apps/desktop/src/lib/file-explorer/rename/ExtensionChangeDialog.svelte

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@
5050
<span>{tString('fileExplorer.extensionChange.alwaysAllow')}</span>
5151
</label>
5252

53-
<div class="button-row">
53+
{#snippet footer()}
5454
<Button variant="secondary" onclick={onKeepOld}>{tString('fileExplorer.extensionChange.keepOld', { oldExt: oldExtension })}</Button>
5555
<Button variant="primary" onclick={handleUseNew}>{tString('fileExplorer.extensionChange.useNew', { newExt: newExtension })}</Button>
56-
</div>
56+
{/snippet}
5757
</ModalDialog>
5858

5959
<style>
@@ -79,11 +79,4 @@
7979
margin: 0;
8080
cursor: default;
8181
}
82-
83-
.button-row {
84-
display: flex;
85-
gap: var(--spacing-md);
86-
justify-content: center;
87-
padding: 0 var(--spacing-xl) var(--spacing-xl);
88-
}
8982
</style>

apps/desktop/src/lib/file-explorer/rename/RenameConflictDialog.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@
184184
.button-row {
185185
display: flex;
186186
gap: var(--spacing-md);
187-
justify-content: center;
187+
justify-content: flex-end;
188188
padding: 0 var(--spacing-xl) var(--spacing-sm);
189189
}
190190

apps/desktop/src/lib/file-operations/delete/DeleteDialog.svelte

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,10 @@
349349
<div class="scan-current-dir" use:useShortenMiddle={{ text: currentDir, preferBreakAt: '/' }}></div>
350350
{/if}
351351

352-
<!-- Buttons -->
353-
<div class="button-row">
352+
{#snippet footer()}
354353
<Button variant="secondary" onclick={handleCancel}>{tString('fileOperations.button.cancel')}</Button>
355354
<Button variant={confirmVariant} onclick={handleConfirm}>{confirmLabel}</Button>
356-
</div>
355+
{/snippet}
357356
</ModalDialog>
358357

359358
{#snippet size(children: import('svelte').Snippet)}<Size bytes={bytesPerSec ?? 0} />{@render children()}{/snippet}
@@ -364,7 +363,6 @@
364363
margin-bottom: var(--spacing-md);
365364
font-size: var(--font-size-sm);
366365
color: var(--color-text-tertiary);
367-
text-align: center;
368366
}
369367
370368
/* No-trash warning banner */
@@ -445,7 +443,6 @@
445443
font-size: var(--font-size-sm);
446444
color: var(--color-text-tertiary);
447445
font-style: italic;
448-
text-align: center;
449446
}
450447
451448
/* Symlink notice */
@@ -469,7 +466,7 @@
469466
.scan-stats {
470467
display: flex;
471468
align-items: center;
472-
justify-content: center;
469+
justify-content: flex-start;
473470
gap: var(--spacing-sm);
474471
padding: 0 var(--spacing-xl) var(--spacing-lg);
475472
font-size: var(--font-size-sm);
@@ -504,7 +501,7 @@
504501
505502
.scan-throughput {
506503
display: flex;
507-
justify-content: center;
504+
justify-content: flex-start;
508505
gap: var(--spacing-xs);
509506
padding: 0 var(--spacing-xl);
510507
margin-bottom: var(--spacing-sm);
@@ -531,18 +528,10 @@
531528
border-radius: var(--radius-sm);
532529
}
533530
534-
/* Buttons */
535-
.button-row {
536-
display: flex;
537-
gap: var(--spacing-md);
538-
justify-content: center;
539-
padding: 0 var(--spacing-xl) var(--spacing-xl);
540-
}
541-
542531
/* Trash/Delete segmented control */
543532
.operation-toggle {
544533
display: flex;
545-
justify-content: center;
534+
justify-content: flex-start;
546535
gap: 0;
547536
padding: 0 var(--spacing-xl) var(--spacing-md);
548537
}

apps/desktop/src/lib/file-operations/mkdir/NewFolderDialog.svelte

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -305,28 +305,27 @@
305305
{/if}
306306
</div>
307307
{/if}
308-
309-
<div class="button-row">
310-
<Button variant="secondary" onclick={onCancel}>{tString('fileOperations.button.cancel')}</Button>
311-
<Button variant="primary" onclick={() => void handleConfirm()} disabled={!isValid || isChecking}
312-
>{tString('fileOperations.button.ok')}</Button
313-
>
314-
</div>
315308
</div>
309+
310+
{#snippet footer()}
311+
<Button variant="secondary" onclick={onCancel}>{tString('fileOperations.button.cancel')}</Button>
312+
<Button variant="primary" onclick={() => void handleConfirm()} disabled={!isValid || isChecking}
313+
>{tString('fileOperations.button.ok')}</Button
314+
>
315+
{/snippet}
316316
</ModalDialog>
317317

318318
{#snippet dir(children: import('svelte').Snippet)}<span class="dir-name">{@render children()}</span>{/snippet}
319319

320320
<style>
321321
.dialog-body {
322-
padding: 0 var(--spacing-xl) var(--spacing-xl);
322+
padding: 0 var(--spacing-xl);
323323
}
324324
325325
.subtitle {
326326
margin: 0 0 var(--spacing-lg);
327327
font-size: var(--font-size-md);
328328
color: var(--color-text-secondary);
329-
text-align: center;
330329
}
331330
332331
.dir-name {
@@ -394,12 +393,6 @@
394393
justify-content: flex-end;
395394
}
396395
397-
.button-row {
398-
display: flex;
399-
gap: var(--spacing-md);
400-
justify-content: center;
401-
}
402-
403396
.ai-suggestions {
404397
margin-bottom: var(--spacing-lg);
405398
min-height: 52px;

apps/desktop/src/lib/file-operations/mkfile/NewFileDialog.svelte

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -179,27 +179,27 @@
179179
{/if}
180180
</div>
181181

182-
<div class="button-row">
183-
<Button variant="secondary" onclick={onCancel}>{tString('fileOperations.button.cancel')}</Button>
184-
<Button variant="primary" onclick={() => void handleConfirm()} disabled={!isValid || isChecking}
185-
>{tString('fileOperations.button.ok')}</Button
186-
>
187-
</div>
188182
</div>
183+
184+
{#snippet footer()}
185+
<Button variant="secondary" onclick={onCancel}>{tString('fileOperations.button.cancel')}</Button>
186+
<Button variant="primary" onclick={() => void handleConfirm()} disabled={!isValid || isChecking}
187+
>{tString('fileOperations.button.ok')}</Button
188+
>
189+
{/snippet}
189190
</ModalDialog>
190191

191192
{#snippet dir(children: import('svelte').Snippet)}<span class="dir-name">{@render children()}</span>{/snippet}
192193

193194
<style>
194195
.dialog-body {
195-
padding: 0 var(--spacing-xl) var(--spacing-xl);
196+
padding: 0 var(--spacing-xl);
196197
}
197198
198199
.subtitle {
199200
margin: 0 0 var(--spacing-lg);
200201
font-size: var(--font-size-md);
201202
color: var(--color-text-secondary);
202-
text-align: center;
203203
}
204204
205205
.dir-name {
@@ -245,10 +245,4 @@
245245
font-size: var(--font-size-sm);
246246
color: var(--color-error);
247247
}
248-
249-
.button-row {
250-
display: flex;
251-
gap: var(--spacing-md);
252-
justify-content: center;
253-
}
254248
</style>

0 commit comments

Comments
 (0)