fix(launcher): larger, ring-bordered preset chips for VNC readability; fix lint errors

Bumps chip buttons h-6→h-8 with text-xs and ring-1 borders so active/inactive
states are clearly distinct at VNC/remote scale. Save & Apply bumped to h-10
text-sm. Fixes: /50 opacity modifier in class: directives (uses class expression
instead), stale svelte-ignore comments replaced with onkeydown handlers, each
block key added. Documents wallpaper repeat-apply macOS caching bug in TODO with
workaround and fix location (Electron temp filename).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-05-20 14:29:34 -04:00
parent 6042095147
commit a59e53aec5
2 changed files with 35 additions and 29 deletions

View File

@@ -63,6 +63,16 @@ guessing defaults.
- [ ] **[Launcher] End-to-end test on macOS** — test pptx and key opens on a real podium Mac
before May 26 setup day. Verify: file copies to tmp correctly, script fires, app opens in
slideshow mode, error fallback works.
- [ ] **[Launcher/Electron] Wallpaper stops applying after several changes (post-CMSC)** —
After setting the wallpaper 35 times in a session, macOS silently ignores further `set desktop
picture` calls even though the SvelteKit side reports "Saved & Applied ✓". Restore Default
(`restore_macos_default_wallpaper`) immediately unblocks it; closing/reopening Electron does
not. **Workaround:** use Restore Default, then re-apply. **Root cause:** macOS caches the
current wallpaper path and skips the AppleScript call when the downloaded file lands at the
same temp path. **Fix (post-CMSC):** in the Electron `set_wallpaper` handler
(`aether_app_native_electron`), append a timestamp or random suffix to the temp filename on
every download so macOS always sees a new path (e.g. `wallpaper_1748123456.jpg` instead of
`wallpaper.jpg`).
---

View File

@@ -145,7 +145,7 @@ async function handle_apply(): Promise<{ success: boolean; linux_test?: boolean
account_id: String($ae_api.account_id ?? '')
});
if (result?.success && (result as any).linux_test_mode) {
if (result?.success && (result as { linux_test_mode?: boolean }).linux_test_mode) {
linux_test_popup_data = result as Record<string, unknown>;
linux_test_popup_open = true;
return { success: true, linux_test: true };
@@ -227,20 +227,18 @@ const section_description = $derived(
</div>
{/if}
<div class="flex flex-col gap-2.5">
<div class="flex flex-col gap-3">
<!-- Primary display -->
<div class="flex flex-col gap-1">
<p class="text-[9px] font-bold uppercase opacity-50">Primary Display</p>
<div class="flex flex-wrap gap-1">
<div class="flex flex-col gap-1.5">
<p class="text-[10px] font-bold uppercase opacity-50">Primary Display</p>
<div class="flex flex-wrap gap-1.5">
{#each PRIMARY_PRESETS as preset (preset.value)}
<button
type="button"
onclick={() => (url_input = preset.value)}
title={preset.value}
class="btn btn-xs h-6 px-2 text-[9px]"
class:preset-filled-primary={url_input === preset.value}
class:preset-tonal-surface={url_input !== preset.value}>
class="btn btn-sm h-8 px-3 text-xs ring-1 {url_input === preset.value ? 'preset-filled-primary ring-primary-500' : 'preset-tonal-surface ring-surface-500/50'}">
{preset.label}
</button>
{/each}
@@ -249,27 +247,25 @@ const section_description = $derived(
type="url"
bind:value={url_input}
placeholder="https://… or select a preset above"
class="input input-sm preset-tonal-surface h-7 w-full text-[10px]" />
class="input input-sm preset-tonal-surface h-8 w-full text-[10px]" />
{#if is_applied}
<p class="text-success-500 pl-0.5 text-[9px]">Applied ✓</p>
<p class="text-success-500 pl-0.5 text-[10px]">Applied ✓</p>
{/if}
</div>
<!-- External / projector display -->
<div class="flex flex-col gap-1">
<p class="text-[9px] font-bold uppercase opacity-50">
<div class="flex flex-col gap-1.5">
<p class="text-[10px] font-bold uppercase opacity-50">
External / Projector
<span class="font-normal normal-case opacity-75">(optional)</span>
</p>
<div class="flex flex-wrap gap-1">
<div class="flex flex-wrap gap-1.5">
{#each EXTERNAL_PRESETS as preset (preset.value)}
<button
type="button"
onclick={() => (url_external_input = preset.value)}
title={preset.value}
class="btn btn-xs h-6 px-2 text-[9px]"
class:preset-filled-primary={url_external_input === preset.value}
class:preset-tonal-surface={url_external_input !== preset.value}>
class="btn btn-sm h-8 px-3 text-xs ring-1 {url_external_input === preset.value ? 'preset-filled-primary ring-primary-500' : 'preset-tonal-surface ring-surface-500/50'}">
{preset.label}
</button>
{/each}
@@ -278,18 +274,18 @@ const section_description = $derived(
type="url"
bind:value={url_external_input}
placeholder="Blank = use primary on all displays"
class="input input-sm preset-tonal-surface h-7 w-full text-[10px]" />
class="input input-sm preset-tonal-surface h-8 w-full text-[10px]" />
</div>
<!-- Actions: single Save & Apply + icon-only Restore -->
<div class="flex gap-2 pt-0.5">
<div class="flex gap-2">
<button
type="button"
onclick={handle_save_and_apply}
disabled={!get_device_id() || (!url_input.trim() && !url_external_input.trim())}
class="btn btn-sm preset-filled-primary h-8 flex-1 text-[10px] font-bold">
<Save size="0.8em" class="mr-1" />
<Zap size="0.8em" class="mr-0.5" />
class="btn preset-filled-primary h-10 flex-1 text-sm font-bold">
<Save size={16} class="mr-1" />
<Zap size={16} class="mr-0.5" />
Save & Apply
</button>
{#if $ae_loc.is_native || $ae_loc.edit_mode}
@@ -297,15 +293,15 @@ const section_description = $derived(
type="button"
onclick={handle_restore_default}
title="Restore macOS default wallpaper"
class="btn btn-sm preset-tonal-surface h-8 px-2.5 opacity-60 hover:opacity-100">
<RotateCcw size="0.85em" />
class="btn preset-tonal-surface ring-surface-500/50 h-10 w-10 ring-1 opacity-75 hover:opacity-100">
<RotateCcw size={18} />
</button>
{/if}
</div>
{#if status}
<div
class="text-center text-[9px] italic"
class="text-center text-[10px] italic"
class:text-success-500={status.includes('✓')}
class:text-primary-500={status.includes('Saving') || status.includes('Applying') || status.includes('dev')}
class:text-error-500={status.includes('failed') || status.includes('No device') || status.includes('Restore failed')}>
@@ -320,19 +316,19 @@ const section_description = $derived(
<!-- Shows what WOULD have been applied; actual gsettings call is skipped to avoid
resetting the dev workstation monitors on every test cycle. -->
{#if linux_test_popup_open && linux_test_popup_data}
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
<div
class="fixed inset-0 z-9999 flex items-center justify-center bg-black/70 p-4"
role="presentation"
onclick={() => (linux_test_popup_open = false)}>
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
onclick={() => (linux_test_popup_open = false)}
onkeydown={(e) => e.key === 'Escape' && (linux_test_popup_open = false)}>
<div
class="bg-surface-50/95 dark:bg-surface-900/95 border-warning-500/40 relative flex max-h-[90vh] w-full max-w-lg flex-col gap-0 overflow-hidden rounded-xl border shadow-2xl"
role="dialog"
aria-modal="true"
aria-label="Linux Dev Mode — Wallpaper not applied"
tabindex="-1"
onclick={(e) => e.stopPropagation()}>
onclick={(e) => e.stopPropagation()}
onkeydown={(e) => e.stopPropagation()}>
<div class="bg-warning-500/10 border-warning-500/30 flex items-center gap-2 border-b px-4 py-3">
<span class="text-warning-600 dark:text-warning-400 font-mono text-xs font-bold uppercase tracking-wider">
@@ -375,7 +371,7 @@ const section_description = $derived(
<div class="flex flex-col gap-1">
<span class="text-[9px] font-bold uppercase opacity-50">Would Have Run</span>
<div class="bg-surface-500/10 text-success-600 dark:text-success-400 rounded px-3 py-2 leading-relaxed whitespace-pre-wrap">
{#each (linux_test_popup_data.would_run as string[]) as cmd}
{#each (linux_test_popup_data.would_run as string[]) as cmd, i (i)}
<div class="mb-1">{cmd}</div>
{/each}
</div>