Add Tauri launcher with Svelte UI
- Accounts: panel login/sign-up, Microsoft device-code sign-in, offline play; tokens encrypted with a key kept in the OS credential store - Home: instance rail, live server status, news feed, social links, Play button with download progress, speed and ETA - Full settings: accounts, memory/resolution/after-launch behaviour, Java and GC presets, Minecraft keybind editor applied to options.txt, theme overrides, storage manager, self-update via GitHub releases - Game console, crash dialog with hints, per-instance overrides - Live admin branding (colours, fonts, backgrounds, custom CSS) - Online install tests for vanilla/Fabric/Quilt/Forge/NeoForge (CI) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011ARcGWxLx21FwXJ3yfGriS
This commit is contained in:
60 files changed
+9424
-47
No files matched your search
@@ -0,0 +1,57 @@
|
||||
// Thin wrapper over Tauri IPC. When the UI runs in a normal browser
|
||||
// (vite dev / screenshots), calls go to an in-memory mock instead.
|
||||
import { invoke as tauriInvoke } from '@tauri-apps/api/core';
|
||||
import { listen as tauriListen, type UnlistenFn } from '@tauri-apps/api/event';
|
||||
|
||||
export const inTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window;
|
||||
|
||||
type Handler = (payload: any) => void;
|
||||
const mockListeners = new Map<string, Set<Handler>>();
|
||||
|
||||
export function mockEmit(event: string, payload: unknown) {
|
||||
mockListeners.get(event)?.forEach((h) => h(payload));
|
||||
}
|
||||
|
||||
export async function invoke<T>(cmd: string, args?: Record<string, unknown>): Promise<T> {
|
||||
if (inTauri) return tauriInvoke<T>(cmd, args);
|
||||
const { mockInvoke } = await import('./mock');
|
||||
return mockInvoke(cmd, args ?? {}) as Promise<T>;
|
||||
}
|
||||
|
||||
export async function listen<T>(event: string, handler: (payload: T) => void): Promise<UnlistenFn> {
|
||||
if (inTauri) return tauriListen<T>(event, (e) => handler(e.payload));
|
||||
const set = mockListeners.get(event) ?? new Set();
|
||||
set.add(handler as Handler);
|
||||
mockListeners.set(event, set);
|
||||
return () => set.delete(handler as Handler);
|
||||
}
|
||||
|
||||
export async function windowAction(action: 'minimize' | 'maximize' | 'close' | 'drag') {
|
||||
if (!inTauri) return;
|
||||
const { getCurrentWindow } = await import('@tauri-apps/api/window');
|
||||
const w = getCurrentWindow();
|
||||
if (action === 'minimize') await w.minimize();
|
||||
else if (action === 'maximize') await w.toggleMaximize();
|
||||
else if (action === 'close') await w.close();
|
||||
else await w.startDragging();
|
||||
}
|
||||
|
||||
export async function openUrl(url: string) {
|
||||
if (!inTauri) {
|
||||
window.open(url, '_blank');
|
||||
return;
|
||||
}
|
||||
const { openUrl } = await import('@tauri-apps/plugin-opener');
|
||||
await openUrl(url);
|
||||
}
|
||||
|
||||
export async function pickFile(title: string, filters?: { name: string; extensions: string[] }[]): Promise<string | null> {
|
||||
if (!inTauri) return null;
|
||||
const { open } = await import('@tauri-apps/plugin-dialog');
|
||||
const r = await open({ title, multiple: false, directory: false, filters });
|
||||
return typeof r === 'string' ? r : null;
|
||||
}
|
||||
|
||||
export function errorText(e: unknown): string {
|
||||
return typeof e === 'string' ? e : e instanceof Error ? e.message : JSON.stringify(e);
|
||||
}
|
||||
Reference in new issue
Block a user