feat(kon): scaffold hybrid modular workspace
- Cargo workspace with 6 domain crates: core, audio, transcription, ai-formatting, storage, cloud-providers - Minimal Tauri shell (lib.rs + main.rs) with plugin registration - Svelte 5 frontend copied from Ramble v0.2 - All crates compile as empty stubs - App identifier: uk.co.corbel.kon Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
98
src/routes/+layout.svelte
Normal file
98
src/routes/+layout.svelte
Normal file
@@ -0,0 +1,98 @@
|
||||
<script>
|
||||
import "../app.css";
|
||||
import { onDestroy } from "svelte";
|
||||
import Sidebar from "$lib/Sidebar.svelte";
|
||||
import TaskSidebar from "$lib/components/TaskSidebar.svelte";
|
||||
import Titlebar from "$lib/components/Titlebar.svelte";
|
||||
import { page, settings } from "$lib/stores/page.svelte.js";
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
// Recording indicator dot (follows mouse)
|
||||
let mouseX = $state(0);
|
||||
let mouseY = $state(0);
|
||||
|
||||
function handleMouseMove(e) {
|
||||
mouseX = e.clientX;
|
||||
mouseY = e.clientY;
|
||||
}
|
||||
|
||||
// Theme application
|
||||
$effect(() => {
|
||||
const theme = settings.theme;
|
||||
if (theme === "Light") {
|
||||
document.documentElement.classList.add("light");
|
||||
return;
|
||||
}
|
||||
if (theme === "Dark") {
|
||||
document.documentElement.classList.remove("light");
|
||||
return;
|
||||
}
|
||||
// System mode
|
||||
const mq = window.matchMedia("(prefers-color-scheme: light)");
|
||||
const apply = () => document.documentElement.classList.toggle("light", mq.matches);
|
||||
apply();
|
||||
mq.addEventListener("change", apply);
|
||||
return () => mq.removeEventListener("change", apply);
|
||||
});
|
||||
|
||||
// Global hotkey registration
|
||||
let registeredHotkey = null;
|
||||
|
||||
async function registerGlobalHotkey(hotkey) {
|
||||
try {
|
||||
const mod = await import("@tauri-apps/plugin-global-shortcut");
|
||||
if (registeredHotkey) {
|
||||
await mod.unregister(registeredHotkey).catch(() => {});
|
||||
}
|
||||
await mod.register(hotkey, () => {
|
||||
if (page.current !== "dictation") page.current = "dictation";
|
||||
requestAnimationFrame(() => {
|
||||
window.dispatchEvent(new CustomEvent("ramble:toggle-recording"));
|
||||
});
|
||||
});
|
||||
registeredHotkey = hotkey;
|
||||
} catch (err) {
|
||||
console.error("Hotkey registration failed:", err);
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
registerGlobalHotkey(settings.globalHotkey);
|
||||
});
|
||||
|
||||
// Apply font size setting as CSS variable
|
||||
$effect(() => {
|
||||
document.documentElement.style.setProperty("--font-size-transcript", `${settings.fontSize}px`);
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (registeredHotkey) {
|
||||
import("@tauri-apps/plugin-global-shortcut")
|
||||
.then((mod) => mod.unregister(registeredHotkey))
|
||||
.catch(() => {});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:window onmousemove={handleMouseMove} />
|
||||
|
||||
{#if page.recording}
|
||||
<div
|
||||
class="fixed w-3 h-3 rounded-full bg-danger animate-pulse-soft pointer-events-none"
|
||||
style="left: {mouseX + 18}px; top: {mouseY + 18}px; z-index: 100;"
|
||||
></div>
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-col h-screen w-screen overflow-hidden grain">
|
||||
<Titlebar />
|
||||
<div class="flex flex-1 min-h-0">
|
||||
<Sidebar />
|
||||
<div class="flex-1 overflow-hidden bg-bg">
|
||||
{@render children()}
|
||||
</div>
|
||||
{#if page.taskSidebarOpen}
|
||||
<TaskSidebar />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user