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>
92 lines
2.7 KiB
Svelte
92 lines
2.7 KiB
Svelte
<script>
|
|
import "../../app.css";
|
|
import { onMount, onDestroy } from "svelte";
|
|
import { listen } from "@tauri-apps/api/event";
|
|
import { getCurrentWindow } from "@tauri-apps/api/window";
|
|
import { settings } from "$lib/stores/page.svelte.js";
|
|
import {
|
|
getPreferences,
|
|
updatePreferences,
|
|
applyExternalPreferences,
|
|
PREFERENCES_CHANGED_EVENT,
|
|
} from "$lib/stores/preferences.svelte.js";
|
|
import Titlebar from "$lib/components/Titlebar.svelte";
|
|
import { loadOsInfo, isLinux } from "$lib/utils/osInfo.js";
|
|
|
|
let { children } = $props();
|
|
let glowing = $state(false);
|
|
let unlistenFocus = null;
|
|
let unlistenPrefs = null;
|
|
let useCustomChrome = $state(false);
|
|
|
|
const prefs = getPreferences();
|
|
|
|
// Theme — sync legacy settings to preferences store (same as main layout)
|
|
$effect(() => {
|
|
const legacyTheme = settings.theme;
|
|
const mapped = legacyTheme === "Light" ? "light" : legacyTheme === "Dark" ? "dark" : "system";
|
|
if (prefs.theme !== mapped) {
|
|
updatePreferences({ theme: mapped });
|
|
}
|
|
});
|
|
|
|
// Listen for settings changes from main window
|
|
if (typeof window !== "undefined") {
|
|
window.addEventListener("storage", (e) => {
|
|
if (e.key === "kon_settings" && e.newValue) {
|
|
try {
|
|
Object.assign(settings, JSON.parse(e.newValue));
|
|
} catch {}
|
|
}
|
|
});
|
|
}
|
|
|
|
onMount(async () => {
|
|
loadOsInfo()
|
|
.then(() => { useCustomChrome = !isLinux(); })
|
|
.catch(() => {});
|
|
try {
|
|
unlistenFocus = await listen("task-window-focus", () => {
|
|
glowing = true;
|
|
setTimeout(() => { glowing = false; }, 700);
|
|
// Auto-focus quick-add input
|
|
const input = document.querySelector("[data-quick-add]");
|
|
if (input) input.focus();
|
|
});
|
|
} catch {}
|
|
|
|
try {
|
|
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);
|
|
});
|
|
} catch {}
|
|
});
|
|
|
|
onDestroy(() => {
|
|
if (unlistenFocus) unlistenFocus();
|
|
if (unlistenPrefs) unlistenPrefs();
|
|
});
|
|
|
|
// Escape to close
|
|
function handleKeydown(e) {
|
|
if (e.key === "Escape") {
|
|
getCurrentWindow().close();
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<svelte:window onkeydown={handleKeydown} />
|
|
|
|
<div class="h-screen w-screen overflow-hidden grain border border-border shadow-xl animate-float-enter flex flex-col {glowing ? 'animate-glow-pulse' : ''}">
|
|
{#if useCustomChrome}
|
|
<Titlebar compact />
|
|
{/if}
|
|
<div class="flex-1 min-h-0 overflow-hidden">
|
|
{@render children()}
|
|
</div>
|
|
</div>
|