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
|
- [ ] **[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
|
before May 26 setup day. Verify: file copies to tmp correctly, script fires, app opens in
|
||||||
slideshow mode, error fallback works.
|
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 ?? '')
|
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_data = result as Record<string, unknown>;
|
||||||
linux_test_popup_open = true;
|
linux_test_popup_open = true;
|
||||||
return { success: true, linux_test: true };
|
return { success: true, linux_test: true };
|
||||||
@@ -227,20 +227,18 @@ const section_description = $derived(
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="flex flex-col gap-2.5">
|
<div class="flex flex-col gap-3">
|
||||||
|
|
||||||
<!-- Primary display -->
|
<!-- Primary display -->
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1.5">
|
||||||
<p class="text-[9px] font-bold uppercase opacity-50">Primary Display</p>
|
<p class="text-[10px] font-bold uppercase opacity-50">Primary Display</p>
|
||||||
<div class="flex flex-wrap gap-1">
|
<div class="flex flex-wrap gap-1.5">
|
||||||
{#each PRIMARY_PRESETS as preset (preset.value)}
|
{#each PRIMARY_PRESETS as preset (preset.value)}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onclick={() => (url_input = preset.value)}
|
onclick={() => (url_input = preset.value)}
|
||||||
title={preset.value}
|
title={preset.value}
|
||||||
class="btn btn-xs h-6 px-2 text-[9px]"
|
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'}">
|
||||||
class:preset-filled-primary={url_input === preset.value}
|
|
||||||
class:preset-tonal-surface={url_input !== preset.value}>
|
|
||||||
{preset.label}
|
{preset.label}
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -249,27 +247,25 @@ const section_description = $derived(
|
|||||||
type="url"
|
type="url"
|
||||||
bind:value={url_input}
|
bind:value={url_input}
|
||||||
placeholder="https://… or select a preset above"
|
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}
|
{#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}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- External / projector display -->
|
<!-- External / projector display -->
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1.5">
|
||||||
<p class="text-[9px] font-bold uppercase opacity-50">
|
<p class="text-[10px] font-bold uppercase opacity-50">
|
||||||
External / Projector
|
External / Projector
|
||||||
<span class="font-normal normal-case opacity-75">(optional)</span>
|
<span class="font-normal normal-case opacity-75">(optional)</span>
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-wrap gap-1">
|
<div class="flex flex-wrap gap-1.5">
|
||||||
{#each EXTERNAL_PRESETS as preset (preset.value)}
|
{#each EXTERNAL_PRESETS as preset (preset.value)}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onclick={() => (url_external_input = preset.value)}
|
onclick={() => (url_external_input = preset.value)}
|
||||||
title={preset.value}
|
title={preset.value}
|
||||||
class="btn btn-xs h-6 px-2 text-[9px]"
|
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'}">
|
||||||
class:preset-filled-primary={url_external_input === preset.value}
|
|
||||||
class:preset-tonal-surface={url_external_input !== preset.value}>
|
|
||||||
{preset.label}
|
{preset.label}
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -278,18 +274,18 @@ const section_description = $derived(
|
|||||||
type="url"
|
type="url"
|
||||||
bind:value={url_external_input}
|
bind:value={url_external_input}
|
||||||
placeholder="Blank = use primary on all displays"
|
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>
|
</div>
|
||||||
|
|
||||||
<!-- Actions: single Save & Apply + icon-only Restore -->
|
<!-- Actions: single Save & Apply + icon-only Restore -->
|
||||||
<div class="flex gap-2 pt-0.5">
|
<div class="flex gap-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onclick={handle_save_and_apply}
|
onclick={handle_save_and_apply}
|
||||||
disabled={!get_device_id() || (!url_input.trim() && !url_external_input.trim())}
|
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">
|
class="btn preset-filled-primary h-10 flex-1 text-sm font-bold">
|
||||||
<Save size="0.8em" class="mr-1" />
|
<Save size={16} class="mr-1" />
|
||||||
<Zap size="0.8em" class="mr-0.5" />
|
<Zap size={16} class="mr-0.5" />
|
||||||
Save & Apply
|
Save & Apply
|
||||||
</button>
|
</button>
|
||||||
{#if $ae_loc.is_native || $ae_loc.edit_mode}
|
{#if $ae_loc.is_native || $ae_loc.edit_mode}
|
||||||
@@ -297,15 +293,15 @@ const section_description = $derived(
|
|||||||
type="button"
|
type="button"
|
||||||
onclick={handle_restore_default}
|
onclick={handle_restore_default}
|
||||||
title="Restore macOS default wallpaper"
|
title="Restore macOS default wallpaper"
|
||||||
class="btn btn-sm preset-tonal-surface h-8 px-2.5 opacity-60 hover:opacity-100">
|
class="btn preset-tonal-surface ring-surface-500/50 h-10 w-10 ring-1 opacity-75 hover:opacity-100">
|
||||||
<RotateCcw size="0.85em" />
|
<RotateCcw size={18} />
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if status}
|
{#if status}
|
||||||
<div
|
<div
|
||||||
class="text-center text-[9px] italic"
|
class="text-center text-[10px] italic"
|
||||||
class:text-success-500={status.includes('✓')}
|
class:text-success-500={status.includes('✓')}
|
||||||
class:text-primary-500={status.includes('Saving') || status.includes('Applying') || status.includes('dev')}
|
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')}>
|
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
|
<!-- Shows what WOULD have been applied; actual gsettings call is skipped to avoid
|
||||||
resetting the dev workstation monitors on every test cycle. -->
|
resetting the dev workstation monitors on every test cycle. -->
|
||||||
{#if linux_test_popup_open && linux_test_popup_data}
|
{#if linux_test_popup_open && linux_test_popup_data}
|
||||||
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
|
|
||||||
<div
|
<div
|
||||||
class="fixed inset-0 z-9999 flex items-center justify-center bg-black/70 p-4"
|
class="fixed inset-0 z-9999 flex items-center justify-center bg-black/70 p-4"
|
||||||
role="presentation"
|
role="presentation"
|
||||||
onclick={() => (linux_test_popup_open = false)}>
|
onclick={() => (linux_test_popup_open = false)}
|
||||||
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
|
onkeydown={(e) => e.key === 'Escape' && (linux_test_popup_open = false)}>
|
||||||
<div
|
<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"
|
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"
|
role="dialog"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
aria-label="Linux Dev Mode — Wallpaper not applied"
|
aria-label="Linux Dev Mode — Wallpaper not applied"
|
||||||
tabindex="-1"
|
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">
|
<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">
|
<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">
|
<div class="flex flex-col gap-1">
|
||||||
<span class="text-[9px] font-bold uppercase opacity-50">Would Have Run</span>
|
<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">
|
<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>
|
<div class="mb-1">{cmd}</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user