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) <noreply@anthropic.com>
111 lines
3.5 KiB
TypeScript
111 lines
3.5 KiB
TypeScript
// Cross-platform OS info for the Svelte frontend. Single async fetch,
|
|
// cached in memory, exposes synchronous helpers after first await.
|
|
//
|
|
// Backed by the `get_os_info` Tauri command (commands/diagnostics.rs).
|
|
// In browser-preview mode (no Tauri runtime), falls back to a sensible
|
|
// default based on navigator.platform.
|
|
//
|
|
// Usage:
|
|
// import { loadOsInfo, osInfo, modKeyLabel, isMac } from '$lib/utils/osInfo.js';
|
|
// await loadOsInfo(); // call once at app startup
|
|
// modKeyLabel(); // "Cmd" on macOS, "Ctrl" elsewhere
|
|
// if (isMac()) { ... }
|
|
//
|
|
// The store version (osInfo) is reactive — Svelte components can read it
|
|
// directly with `$osInfo` once Svelte 5 runes are everywhere, or via
|
|
// destructuring on a non-reactive read.
|
|
|
|
import { invoke } from '@tauri-apps/api/core';
|
|
import { hasTauriRuntime } from './runtime.js';
|
|
|
|
interface OsInfo {
|
|
os: string;
|
|
arch: string;
|
|
family: string;
|
|
usesCmd: boolean;
|
|
isWayland: boolean;
|
|
customHotkeyBackend: boolean;
|
|
primaryModifierLabel: string;
|
|
}
|
|
|
|
let cached: OsInfo | null = null;
|
|
|
|
const FALLBACK_BROWSER_INFO = {
|
|
os: detectBrowserOs(),
|
|
arch: 'unknown',
|
|
family: detectBrowserFamily(),
|
|
usesCmd: detectBrowserOs() === 'macos',
|
|
isWayland: false,
|
|
customHotkeyBackend: false,
|
|
primaryModifierLabel: detectBrowserOs() === 'macos' ? 'Cmd' : 'Ctrl',
|
|
};
|
|
|
|
function detectBrowserOs() {
|
|
if (typeof navigator === 'undefined') return 'unknown';
|
|
const ua = (navigator.userAgent || '').toLowerCase();
|
|
const platform = (navigator.platform || '').toLowerCase();
|
|
if (platform.includes('mac') || ua.includes('mac os')) return 'macos';
|
|
if (platform.includes('win') || ua.includes('windows')) return 'windows';
|
|
if (platform.includes('linux') || ua.includes('linux')) return 'linux';
|
|
return 'unknown';
|
|
}
|
|
|
|
function detectBrowserFamily() {
|
|
switch (detectBrowserOs()) {
|
|
case 'macos': return 'macOS';
|
|
case 'windows': return 'Windows';
|
|
case 'linux': return 'Linux';
|
|
default: return 'Unknown';
|
|
}
|
|
}
|
|
|
|
/** Fetch OS info from the Tauri backend. Idempotent — call multiple times,
|
|
* only the first does the round-trip. Browser-preview mode returns the
|
|
* navigator-detected fallback. */
|
|
export async function loadOsInfo(): Promise<OsInfo> {
|
|
if (cached) return cached;
|
|
if (!hasTauriRuntime()) {
|
|
cached = FALLBACK_BROWSER_INFO;
|
|
return cached;
|
|
}
|
|
try {
|
|
cached = await invoke<OsInfo>("get_os_info");
|
|
} catch (err) {
|
|
console.warn('loadOsInfo: get_os_info failed, using browser fallback', err);
|
|
cached = FALLBACK_BROWSER_INFO;
|
|
}
|
|
return cached;
|
|
}
|
|
|
|
/** Synchronous accessor. Returns null if loadOsInfo has not been awaited
|
|
* yet. Components that need the value at first render should await
|
|
* loadOsInfo() in onMount before reading. */
|
|
export function osInfo(): OsInfo | null {
|
|
return cached;
|
|
}
|
|
|
|
export function isMac(): boolean {
|
|
return cached?.os === 'macos';
|
|
}
|
|
|
|
export function isWindows(): boolean {
|
|
return cached?.os === 'windows';
|
|
}
|
|
|
|
export function isLinux(): boolean {
|
|
return cached?.os === 'linux';
|
|
}
|
|
|
|
/** Localised label for the primary keyboard modifier. "Cmd" on macOS,
|
|
* "Ctrl" everywhere else. Use in hotkey display strings:
|
|
* `${modKeyLabel()}+Shift+R` */
|
|
export function modKeyLabel(): string {
|
|
return cached?.primaryModifierLabel ?? 'Ctrl';
|
|
}
|
|
|
|
/** True if the current Linux session is Wayland. False on Windows/macOS.
|
|
* Useful for Settings → Audio "PipeWire detected" status display. */
|
|
export function isWayland(): boolean {
|
|
return !!cached?.isWayland;
|
|
}
|