Badges: fix button layout \u2014 Revert/Save/X always in fixed positions
This commit is contained in:
@@ -399,46 +399,54 @@
|
||||
|
||||
<!-- Save/cancel row (inside accordion edit forms).
|
||||
on_revert is optional — shown only when a saved override exists.
|
||||
is_dirty: Save is hidden when clean (unchanged), warning-styled when dirty.
|
||||
Layout when dirty: [Revert?] [⚠ Save] [X] / when clean: [Revert?] [X] -->
|
||||
is_dirty: Save uses warning style when changed, invisible when clean.
|
||||
Layout always fixed: [Revert (or gap)] [Save] [X]
|
||||
Buttons are always rendered to keep X pinned at the right end. -->
|
||||
{#snippet field_actions(field_key: string, on_save: () => void, on_cancel: () => void, on_revert?: () => void, is_dirty = false)}
|
||||
{@const status = field_save_status[field_key]}
|
||||
{@const show_save = is_dirty || (status && status !== 'idle')}
|
||||
{@const save_visible = is_dirty || (status && status !== 'idle')}
|
||||
<div class="flex gap-2 mt-2">
|
||||
{#if on_revert}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm preset-tonal-warning shrink-0"
|
||||
onclick={on_revert}
|
||||
disabled={status === 'saving'}
|
||||
title="Remove override — restore original imported value"
|
||||
aria-label="Revert to original value"
|
||||
><RotateCcw size="13" /></button>
|
||||
{/if}
|
||||
{#if show_save}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm flex-1 transition-colors"
|
||||
class:preset-filled-warning={is_dirty && (!status || status === 'idle')}
|
||||
class:preset-tonal-surface={status === 'saving'}
|
||||
class:preset-filled-success={status === 'done'}
|
||||
class:preset-tonal-error={status === 'error'}
|
||||
disabled={status === 'saving'}
|
||||
onclick={on_save}
|
||||
title="Save changes"
|
||||
aria-label="Save changes"
|
||||
>
|
||||
{#if status === 'saving'}
|
||||
<LoaderCircle size="14" class="animate-spin mr-1" /> Saving…
|
||||
{:else if status === 'done'}
|
||||
<Check size="14" class="mr-1" /> Saved
|
||||
{:else if status === 'error'}
|
||||
Error — retry
|
||||
{:else}
|
||||
<Check size="14" class="mr-1" /> Save
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
<!-- Revert: always occupies left slot; invisible when no override exists -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm preset-tonal-warning shrink-0"
|
||||
class:invisible={!on_revert}
|
||||
class:pointer-events-none={!on_revert}
|
||||
onclick={on_revert}
|
||||
disabled={!on_revert || status === 'saving'}
|
||||
tabindex={on_revert ? 0 : -1}
|
||||
title="Remove override — restore original imported value"
|
||||
aria-label="Revert to original value"
|
||||
aria-hidden={!on_revert}
|
||||
><RotateCcw size="13" /></button>
|
||||
<!-- Save: always in centre slot; invisible+inert when clean -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm flex-1 transition-colors"
|
||||
class:invisible={!save_visible}
|
||||
class:pointer-events-none={!save_visible}
|
||||
class:preset-filled-warning={save_visible && is_dirty && (!status || status === 'idle')}
|
||||
class:preset-tonal-surface={status === 'saving'}
|
||||
class:preset-filled-success={status === 'done'}
|
||||
class:preset-tonal-error={status === 'error'}
|
||||
disabled={!save_visible || status === 'saving'}
|
||||
tabindex={save_visible ? 0 : -1}
|
||||
onclick={on_save}
|
||||
title="Save changes"
|
||||
aria-label="Save changes"
|
||||
aria-hidden={!save_visible}
|
||||
>
|
||||
{#if status === 'saving'}
|
||||
<LoaderCircle size="14" class="animate-spin mr-1" /> Saving…
|
||||
{:else if status === 'done'}
|
||||
<Check size="14" class="mr-1" /> Saved
|
||||
{:else if status === 'error'}
|
||||
Error — retry
|
||||
{:else}
|
||||
<Check size="14" class="mr-1" /> Save
|
||||
{/if}
|
||||
</button>
|
||||
<!-- Cancel: always visible at right end -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm preset-tonal-surface"
|
||||
@@ -749,32 +757,34 @@
|
||||
<span class="text-xs">Allow exhibitor lead scanning</span>
|
||||
</label>
|
||||
<!-- Inline actions — not shared snippet because this field adds a TC info button.
|
||||
Save hidden until the checkbox value differs from the saved value. -->
|
||||
Layout always fixed: [Save] [X] [ⓘ] — Save invisible when clean. -->
|
||||
<div class="flex gap-2 mt-2">
|
||||
{#if is_dirty_allow_tracking || (field_save_status['allow_tracking'] && field_save_status['allow_tracking'] !== 'idle')}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm flex-1 transition-colors"
|
||||
class:preset-filled-warning={is_dirty_allow_tracking && (!field_save_status['allow_tracking'] || field_save_status['allow_tracking'] === 'idle')}
|
||||
class:preset-tonal-surface={field_save_status['allow_tracking'] === 'saving'}
|
||||
class:preset-filled-success={field_save_status['allow_tracking'] === 'done'}
|
||||
class:preset-tonal-error={field_save_status['allow_tracking'] === 'error'}
|
||||
disabled={field_save_status['allow_tracking'] === 'saving'}
|
||||
onclick={() => save_field('allow_tracking', { allow_tracking: edit_allow_tracking })}
|
||||
title="Save changes"
|
||||
aria-label="Save changes"
|
||||
>
|
||||
{#if field_save_status['allow_tracking'] === 'saving'}
|
||||
<LoaderCircle size="14" class="animate-spin mr-1" /> Saving…
|
||||
{:else if field_save_status['allow_tracking'] === 'done'}
|
||||
<Check size="14" class="mr-1" /> Saved
|
||||
{:else if field_save_status['allow_tracking'] === 'error'}
|
||||
Error — retry
|
||||
{:else}
|
||||
<Check size="14" class="mr-1" /> Save
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm flex-1 transition-colors"
|
||||
class:invisible={!is_dirty_allow_tracking && (!field_save_status['allow_tracking'] || field_save_status['allow_tracking'] === 'idle')}
|
||||
class:pointer-events-none={!is_dirty_allow_tracking && (!field_save_status['allow_tracking'] || field_save_status['allow_tracking'] === 'idle')}
|
||||
class:preset-filled-warning={is_dirty_allow_tracking && (!field_save_status['allow_tracking'] || field_save_status['allow_tracking'] === 'idle')}
|
||||
class:preset-tonal-surface={field_save_status['allow_tracking'] === 'saving'}
|
||||
class:preset-filled-success={field_save_status['allow_tracking'] === 'done'}
|
||||
class:preset-tonal-error={field_save_status['allow_tracking'] === 'error'}
|
||||
disabled={!is_dirty_allow_tracking || field_save_status['allow_tracking'] === 'saving'}
|
||||
tabindex={is_dirty_allow_tracking ? 0 : -1}
|
||||
onclick={() => save_field('allow_tracking', { allow_tracking: edit_allow_tracking })}
|
||||
title="Save changes"
|
||||
aria-label="Save changes"
|
||||
aria-hidden={!is_dirty_allow_tracking && (!field_save_status['allow_tracking'] || field_save_status['allow_tracking'] === 'idle')}
|
||||
>
|
||||
{#if field_save_status['allow_tracking'] === 'saving'}
|
||||
<LoaderCircle size="14" class="animate-spin mr-1" /> Saving…
|
||||
{:else if field_save_status['allow_tracking'] === 'done'}
|
||||
<Check size="14" class="mr-1" /> Saved
|
||||
{:else if field_save_status['allow_tracking'] === 'error'}
|
||||
Error — retry
|
||||
{:else}
|
||||
<Check size="14" class="mr-1" /> Save
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm preset-tonal-surface"
|
||||
|
||||
Reference in New Issue
Block a user