agent: dogfood polish 2026/04/19 — Linux native chrome + History redesign + mic picker cleanup
Second dogfood sprint. Headline fix: Linux now uses native KWin/Mutter decorations instead of fragile frameless `startResizeDragging`, which collapsed diagonal corner resize to a single axis and made drag feel laggy. macOS / Windows keep custom chrome via `useCustomChrome` gate. Other changes: - Cross-window preferences sync via `kon:preferences-changed` Tauri event — theme and font changes propagate live to float/viewer. - Hotkey recorder rewritten to use capture-phase document listener gated by $effect; button focus was unreliable in webkit2gtk. - History page redesigned for cognitive-load hygiene: title-first compact row, inline title input, Edit popout opening /viewer in edit mode, clipboard export as .md with YAML frontmatter, manual tag chips + + Add tag input, header tag filter (cap 7), global Starred filter, `tag:xyz` search syntax. - `deriveAutoTags` kept as empty hook for post-Task-7 LLM topic tags; research found all previous auto-tag chips redundant with row UI. - Viewer window adds edit mode with debounced-save textarea; native title renamed to "Kon - Transcription Editor". - Window minimums updated per GNOME HIG + WCAG reflow research: main 960x600, float 360x480, editor 560x520. - Microphone picker filters raw ALSA strings (hw:, plughw:, front:, sysdefault:, null) and dedupes by CARD=X. New `description` field on DeviceInfo reads /proc/asound/cards so Blue Yeti shows as "Blue Microphones" instead of the short "Microphones" card name. - GPU reporting fixed: get_runtime_capabilities now returns accelerators=[cpu,vulkan] and whisper.supports_gpu=true, matching the transcribe-rs whisper-vulkan feature linked unconditionally. - ResizeHandles kept for macOS/Windows frameless: 12px edges, 20px corners via CSS vars, pointerdown + setPointerCapture, corners above edges in z-order, rendered as sibling (not child) of the animated layout root so `position: fixed` is viewport-relative. - Dueling drag-region handlers removed — `data-tauri-drag-region` and manual `startDragging()` were stacked on the same elements; kept the manual handler which has the button/input early-return logic. See HANDOVER.md for the full session log and deferred items. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,10 +6,18 @@
|
||||
import TaskSidebar from "$lib/components/TaskSidebar.svelte";
|
||||
import Titlebar from "$lib/components/Titlebar.svelte";
|
||||
import ToastViewport from "$lib/components/ToastViewport.svelte";
|
||||
import ResizeHandles from "$lib/components/ResizeHandles.svelte";
|
||||
import { hasTauriRuntime } from "$lib/utils/runtime.js";
|
||||
import { loadOsInfo } from "$lib/utils/osInfo.js";
|
||||
import { loadOsInfo, isLinux } from "$lib/utils/osInfo.js";
|
||||
import { page, settings, saveSettings } from "$lib/stores/page.svelte.js";
|
||||
import { getPreferences, updatePreferences } from "$lib/stores/preferences.svelte.js";
|
||||
import {
|
||||
getPreferences,
|
||||
updatePreferences,
|
||||
applyExternalPreferences,
|
||||
PREFERENCES_CHANGED_EVENT,
|
||||
} from "$lib/stores/preferences.svelte.js";
|
||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { toasts } from "$lib/stores/toasts.svelte.js";
|
||||
|
||||
import { page as sveltePage } from "$app/stores";
|
||||
@@ -19,6 +27,12 @@
|
||||
const prefs = getPreferences();
|
||||
const tauriRuntimeAvailable = hasTauriRuntime();
|
||||
|
||||
// On Linux Kon uses native KWin/Mutter decorations (see
|
||||
// src-tauri/tauri.linux.conf.json and windows.rs). Frameless custom
|
||||
// chrome stays for macOS and Windows. Default to false so Linux users
|
||||
// don't see a flash of custom titlebar before loadOsInfo resolves.
|
||||
let useCustomChrome = $state(false);
|
||||
|
||||
|
||||
// Detect secondary windows (float, viewer) — they use +layout@.svelte
|
||||
// but as a fallback, hide chrome if the URL matches
|
||||
@@ -158,6 +172,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Cross-window preference sync: apply updates broadcast by any other
|
||||
// window (float, viewer) while skipping our own echoes.
|
||||
let unlistenPrefs = null;
|
||||
async function setupPreferencesSync() {
|
||||
if (!tauriRuntimeAvailable) return;
|
||||
let ownLabel = null;
|
||||
try { ownLabel = getCurrentWindow().label; } catch {}
|
||||
unlistenPrefs = await listen(PREFERENCES_CHANGED_EVENT, (event) => {
|
||||
const payload = event?.payload;
|
||||
if (!payload || payload.source === ownLabel) return;
|
||||
applyExternalPreferences(payload.prefs);
|
||||
});
|
||||
}
|
||||
|
||||
// Capture global frontend errors and forward to the Rust error_log via
|
||||
// log_frontend_error. Best-effort: never let the error handler itself
|
||||
// throw, never crash the app over a logging failure.
|
||||
@@ -198,12 +226,19 @@
|
||||
handleResize();
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
// Cross-window preference sync (no-op outside Tauri).
|
||||
setupPreferencesSync();
|
||||
|
||||
// Diagnostics: capture every uncaught frontend error to error_log.
|
||||
installGlobalErrorCapture();
|
||||
|
||||
// OS detection: warm the cache so components can use modKeyLabel() /
|
||||
// isMac() / isWayland() synchronously after first render.
|
||||
loadOsInfo().catch(() => { /* fallback already populated */ });
|
||||
// isMac() / isWayland() synchronously after first render. We also
|
||||
// use the result to decide whether to render the custom Titlebar +
|
||||
// ResizeHandles (non-Linux) or rely on native decorations (Linux).
|
||||
loadOsInfo()
|
||||
.then(() => { useCustomChrome = !isLinux(); })
|
||||
.catch(() => { /* fallback already populated */ });
|
||||
|
||||
if (!tauriRuntimeAvailable) {
|
||||
hotkeyBackend = "unavailable";
|
||||
@@ -250,6 +285,9 @@
|
||||
if (unlistenEvdev) {
|
||||
unlistenEvdev();
|
||||
}
|
||||
if (unlistenPrefs) {
|
||||
unlistenPrefs();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -261,7 +299,9 @@
|
||||
{@render children()}
|
||||
{:else}
|
||||
<div class="flex flex-col h-screen w-screen overflow-hidden grain">
|
||||
<Titlebar />
|
||||
{#if useCustomChrome}
|
||||
<Titlebar />
|
||||
{/if}
|
||||
<div class="flex flex-1 min-h-0 relative">
|
||||
{#if page.current !== "first-run"}
|
||||
<Sidebar />
|
||||
@@ -282,3 +322,10 @@
|
||||
can call toasts.error(...), toasts.success(...) etc and have it render
|
||||
in the bottom-right of the viewport. (Day 3 of the upgrade plan) -->
|
||||
<ToastViewport />
|
||||
|
||||
<!-- Invisible resize margins for frameless (macOS/Windows). On Linux we
|
||||
use native decorations, so ResizeHandles would compete with the
|
||||
compositor's own resize and is suppressed. -->
|
||||
{#if useCustomChrome}
|
||||
<ResizeHandles />
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user