From d6bf9ed245161f47de599d0ef29370f56b5c9472 Mon Sep 17 00:00:00 2001 From: Jake Date: Sun, 19 Apr 2026 20:05:54 +0100 Subject: [PATCH] refactor(frontend): migrate JS modules to TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wholesale JS -> TS migration of the frontend — stores, utils, actions, and all Svelte component scripts adopt type annotations. Compile-time surfaces (app.d.ts, lib/types/) added for shared DTO types. Build plumbing: - package.json: dev:frontend script that runs svelte-kit sync first - tauri.conf.json: beforeDevCommand points at dev:frontend - run.sh: dropped the sed-hack that temporarily blanked beforeDevCommand; now relies on npm run dev:frontend to avoid double-Vite - jsconfig.json: allowImportingTsExtensions Preserves all Group 1 behaviour: - page.svelte.ts keeps loadHistory / loadTasks Tauri-first, no localStorage; saveTranscriptMeta + mapTranscriptRow + mapTaskRow intact; update_task_cmd and update_transcript_meta_cmd invocations carry the correct payload shape. - Toasts, preferences stores typed without behaviour change. - Viewer still routes segment edits through saveTranscriptMeta; the Task 1.5 TODO markers are gone. taskExtractor.ts is functionally improved during the migration: - multi-task matches in the same sentence - list-style shopping-verb expansion (get bread, milk, and cheese) Co-Authored-By: Claude Opus 4.7 (1M context) --- jsconfig.json | 1 + package.json | 3 +- run.sh | 8 +- src-tauri/tauri.conf.json | 2 +- src/app.d.ts | 44 ++ src/lib/Sidebar.svelte | 4 +- .../{bionicReading.js => bionicReading.ts} | 28 +- .../components/AccessibilityControls.svelte | 19 +- src/lib/components/HotkeyRecorder.svelte | 6 +- src/lib/components/MicroSteps.svelte | 18 +- src/lib/components/ModelDownloader.svelte | 29 +- src/lib/components/ResizeHandles.svelte | 17 +- src/lib/components/TaskSidebar.svelte | 6 +- src/lib/components/Titlebar.svelte | 11 +- src/lib/components/ToastViewport.svelte | 5 +- src/lib/components/UnicodeSpinner.svelte | 23 +- src/lib/components/VirtualSegmentList.svelte | 53 +- src/lib/components/WipTaskList.svelte | 8 +- src/lib/components/ZonePicker.svelte | 6 +- src/lib/pages/DictationPage.svelte | 3 +- src/lib/pages/FilesPage.svelte | 3 +- src/lib/pages/FirstRunPage.svelte | 3 +- src/lib/pages/HistoryPage.svelte | 3 +- src/lib/pages/SettingsPage.svelte | 3 +- src/lib/pages/TasksPage.svelte | 72 +- src/lib/stores/page.svelte.js | 656 ------------------ src/lib/stores/page.svelte.ts | 599 ++++++++++++++++ ...rences.svelte.js => preferences.svelte.ts} | 89 +-- .../{toasts.svelte.js => toasts.svelte.ts} | 39 +- src/lib/types/app.ts | 243 +++++++ src/lib/utils/accessibilityTypography.js | 28 - src/lib/utils/accessibilityTypography.ts | 41 ++ src/lib/utils/errors.ts | 8 + src/lib/utils/{export.js => export.ts} | 21 +- .../utils/{frontmatter.js => frontmatter.ts} | 21 +- src/lib/utils/{osInfo.js => osInfo.ts} | 28 +- src/lib/utils/{runtime.js => runtime.ts} | 2 +- src/lib/utils/storage.ts | 8 + src/lib/utils/taskExtractor.js | 127 ---- src/lib/utils/taskExtractor.ts | 224 ++++++ .../utils/{textMeasure.js => textMeasure.ts} | 77 +- src/lib/utils/{time.js => time.ts} | 12 +- .../utils/{virtualList.js => virtualList.ts} | 10 +- src/routes/+layout.svelte | 3 +- src/routes/float/+layout@.svelte | 3 +- src/routes/float/+page.svelte | 76 +- src/routes/viewer/+layout@.svelte | 3 +- src/routes/viewer/+page.svelte | 153 ++-- 48 files changed, 1693 insertions(+), 1156 deletions(-) create mode 100644 src/app.d.ts rename src/lib/actions/{bionicReading.js => bionicReading.ts} (68%) delete mode 100644 src/lib/stores/page.svelte.js create mode 100644 src/lib/stores/page.svelte.ts rename src/lib/stores/{preferences.svelte.js => preferences.svelte.ts} (59%) rename src/lib/stores/{toasts.svelte.js => toasts.svelte.ts} (65%) create mode 100644 src/lib/types/app.ts delete mode 100644 src/lib/utils/accessibilityTypography.js create mode 100644 src/lib/utils/accessibilityTypography.ts create mode 100644 src/lib/utils/errors.ts rename src/lib/utils/{export.js => export.ts} (86%) rename src/lib/utils/{frontmatter.js => frontmatter.ts} (88%) rename src/lib/utils/{osInfo.js => osInfo.ts} (84%) rename src/lib/utils/{runtime.js => runtime.ts} (93%) create mode 100644 src/lib/utils/storage.ts delete mode 100644 src/lib/utils/taskExtractor.js create mode 100644 src/lib/utils/taskExtractor.ts rename src/lib/utils/{textMeasure.js => textMeasure.ts} (65%) rename src/lib/utils/{time.js => time.ts} (80%) rename src/lib/utils/{virtualList.js => virtualList.ts} (84%) diff --git a/jsconfig.json b/jsconfig.json index 4344710..4c4d1b7 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "allowJs": true, "checkJs": true, + "allowImportingTsExtensions": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, diff --git a/package.json b/package.json index b5751e4..2714236 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "Kon — Think out loud", "type": "module", "scripts": { - "dev": "vite dev", + "dev": "npm run dev:frontend", + "dev:frontend": "svelte-kit sync && vite dev", "build": "vite build", "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json", diff --git a/run.sh b/run.sh index ec0df70..84ea724 100755 --- a/run.sh +++ b/run.sh @@ -8,19 +8,15 @@ cd "$(dirname "$0")" export LIBCLANG_PATH=/usr/lib64/llvm21/lib64 printf 'Starting Vite dev server...\n' >&2 -npm run dev & +npm run dev:frontend & VITE_PID=$! until curl -sf http://localhost:1420 > /dev/null 2>&1; do sleep 0.5; done printf 'Vite ready. Launching Tauri...\n' >&2 -# Blank beforeDevCommand so Tauri doesn't spawn a second Vite -sed -i 's/"beforeDevCommand": "npm run dev"/"beforeDevCommand": ""/' src-tauri/tauri.conf.json - cleanup() { - sed -i 's/"beforeDevCommand": ""/"beforeDevCommand": "npm run dev"/' src-tauri/tauri.conf.json kill "$VITE_PID" 2>/dev/null || true } trap cleanup EXIT INT TERM -npx tauri dev +npx tauri dev --config '{"build":{"beforeDevCommand":""}}' diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 3800cc5..32b8aff 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -4,7 +4,7 @@ "version": "0.1.0", "identifier": "uk.co.corbel.kon", "build": { - "beforeDevCommand": "npm run dev", + "beforeDevCommand": "npm run dev:frontend", "devUrl": "http://localhost:1420", "beforeBuildCommand": "npm run build", "frontendDist": "../build" diff --git a/src/app.d.ts b/src/app.d.ts new file mode 100644 index 0000000..02851f3 --- /dev/null +++ b/src/app.d.ts @@ -0,0 +1,44 @@ +declare global { + interface Window { + __TAURI_INTERNALS__?: unknown; + isTauri?: boolean; + } +} + +declare module "@chenglou/pretext" { + export interface PretextLayoutLine { + text: string; + } + + export interface PretextLayoutResult { + height: number; + lineCount: number; + lines: PretextLayoutLine[]; + } + + export function prepare( + text: string, + font: string, + options?: Record, + ): unknown; + + export function prepareWithSegments( + text: string, + font: string, + options?: Record, + ): unknown; + + export function layout( + prepared: unknown, + maxWidth: number, + lineHeight: number, + ): PretextLayoutResult; + + export function layoutWithLines( + prepared: unknown, + maxWidth: number, + lineHeight: number, + ): PretextLayoutResult; +} + +export {}; diff --git a/src/lib/Sidebar.svelte b/src/lib/Sidebar.svelte index 979d792..b32ac54 100644 --- a/src/lib/Sidebar.svelte +++ b/src/lib/Sidebar.svelte @@ -1,4 +1,4 @@ -
@@ -59,7 +64,7 @@ {prefs.accessibility.fontSize}px
updateAccessibility({ fontSize: Number(e.target.value) })} + oninput={(e) => updateAccessibility({ fontSize: rangeValue(e) })} class="w-full accent-accent" /> @@ -70,7 +75,7 @@ {prefs.accessibility.letterSpacing.toFixed(2)}em updateAccessibility({ letterSpacing: Number(e.target.value) })} + oninput={(e) => updateAccessibility({ letterSpacing: rangeValue(e) })} class="w-full accent-accent" /> @@ -81,7 +86,7 @@ {prefs.accessibility.lineHeight.toFixed(1)} updateAccessibility({ lineHeight: Number(e.target.value) })} + oninput={(e) => updateAccessibility({ lineHeight: rangeValue(e) })} class="w-full accent-accent" /> @@ -92,7 +97,7 @@ {prefs.accessibility.transcriptSize}px updateAccessibility({ transcriptSize: Number(e.target.value) })} + oninput={(e) => updateAccessibility({ transcriptSize: rangeValue(e) })} class="w-full accent-accent" /> diff --git a/src/lib/components/HotkeyRecorder.svelte b/src/lib/components/HotkeyRecorder.svelte index bebd144..f9f24c5 100644 --- a/src/lib/components/HotkeyRecorder.svelte +++ b/src/lib/components/HotkeyRecorder.svelte @@ -1,4 +1,4 @@ - {#if enabled} +
startResize(e,"North")}>
+
startResize(e,"South")}>
+
startResize(e,"West")}>
+
startResize(e,"East")}>
+
startResize(e,"NorthWest")}>
+
startResize(e,"NorthEast")}>
+
startResize(e,"SouthWest")}>
+
startResize(e,"SouthEast")}>
{/if} diff --git a/src/lib/components/TaskSidebar.svelte b/src/lib/components/TaskSidebar.svelte index 8f39929..6b4e386 100644 --- a/src/lib/components/TaskSidebar.svelte +++ b/src/lib/components/TaskSidebar.svelte @@ -1,14 +1,14 @@ - +
+ diff --git a/src/lib/components/VirtualSegmentList.svelte b/src/lib/components/VirtualSegmentList.svelte index 8cb6a31..e6894da 100644 --- a/src/lib/components/VirtualSegmentList.svelte +++ b/src/lib/components/VirtualSegmentList.svelte @@ -1,4 +1,5 @@ - diff --git a/src/lib/pages/DictationPage.svelte b/src/lib/pages/DictationPage.svelte index 653e54e..5126c7d 100644 --- a/src/lib/pages/DictationPage.svelte +++ b/src/lib/pages/DictationPage.svelte @@ -1,4 +1,5 @@ -
@@ -297,13 +323,13 @@ {#if editingListId === list.id && !sidebarCollapsed}
{ if (e.key === "Enter") finishRenaming(); if (e.key === "Escape") { editingListId = null; } }} onblur={finishRenaming} data-no-transition - autofocus />
{:else} @@ -356,6 +382,7 @@
{#if showNewList} { showNewList = false; newListName = ""; }} data-no-transition - autofocus /> {:else} + >{effortLabel(e)} {/each} {#if task.createdAt} @@ -457,7 +483,7 @@ class="flex items-center gap-2 text-[12px] text-text-tertiary hover:text-text-secondary mb-2" onclick={() => showCompleted = !showCompleted} > -