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:
@@ -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 3–5 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`).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user