ui-svelte: add Svelte port of React UI (#487)
Trying out svelte for the UI. The port was done by Claude Code on the iOS app w/ Opus 4.5. --- * ui: add Svelte port of React UI Port the React-based UI to Svelte 5 with the following changes: - Create new ui-svelte directory with complete Svelte 5 implementation - Use Svelte stores instead of React contexts for state management - Implement custom ResizablePanels component to replace react-resizable-panels - Port all pages: LogViewer, Models, Activity - Port all components: Header, ConnectionStatus, LogPanel, ModelsPanel, etc. - Use svelte-spa-router for client-side routing - Same build output directory (proxy/ui_dist) and base path (/ui/) - Tailwind CSS 4 with same theme configuration https://claude.ai/code/session_01F3xXLYsd62gePVSFv7aboP * ui-svelte: simplify state management - Remove redundant state syncing pattern in LogPanel and ModelsPanel - Use store values directly with $ syntax instead of manual subscriptions - Consolidate duplicate title sync logic in App.svelte - Use existing syncTitleToDocument() from theme.ts https://claude.ai/code/session_01F3xXLYsd62gePVSFv7aboP * ui-svelte: use idiomatic Svelte 5 patterns - Use $effect for document side effects (theme, title) instead of store subscriptions - Use class: directive for active nav links in Header - Remove SSR guards (unnecessary for client-only SPA) - Remove leaked subscription in syncThemeToDocument - Simplify theme.ts by removing sync functions https://claude.ai/code/session_01F3xXLYsd62gePVSFv7aboP * ui-svelte: fix build warnings and improve accessibility Fix Svelte build warnings and add proper accessibility support to interactive components. - add aria-labels to buttons for screen readers - implement keyboard navigation for resizable separator - suppress intentional state initialization warnings - update Makefile to use ui-svelte build directory - add peer:true to package-lock.json dependencies * ui-svelte: reorganize navigation and add log view toggle Make Models the default landing page and add view mode toggle to the Logs page with persistent state. - set Models as default route at / - move Logs to /logs route - reorder navigation: Models, Activity, Logs - add view toggle with three modes: Panels, Proxy only, Upstream only - fix horizontal overflow with width constraints
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { writable, derived } from "svelte/store";
|
||||
import { persistentStore } from "./persistent";
|
||||
import type { ScreenWidth } from "../lib/types";
|
||||
|
||||
// Persistent stores
|
||||
export const isDarkMode = persistentStore<boolean>("theme", false);
|
||||
export const appTitle = persistentStore<string>("app-title", "llama-swap");
|
||||
|
||||
// Non-persistent stores
|
||||
export const screenWidth = writable<ScreenWidth>("md");
|
||||
export const connectionState = writable<"connected" | "connecting" | "disconnected">("disconnected");
|
||||
|
||||
// Derived store for narrow screens
|
||||
export const isNarrow = derived(screenWidth, ($screenWidth) => {
|
||||
return $screenWidth === "xs" || $screenWidth === "sm" || $screenWidth === "md";
|
||||
});
|
||||
|
||||
// Function to toggle theme
|
||||
export function toggleTheme(): void {
|
||||
isDarkMode.update((current) => !current);
|
||||
}
|
||||
|
||||
// Function to check and update screen width
|
||||
export function checkScreenWidth(): void {
|
||||
const innerWidth = window.innerWidth;
|
||||
let newWidth: ScreenWidth;
|
||||
|
||||
if (innerWidth < 640) {
|
||||
newWidth = "xs";
|
||||
} else if (innerWidth < 768) {
|
||||
newWidth = "sm";
|
||||
} else if (innerWidth < 1024) {
|
||||
newWidth = "md";
|
||||
} else if (innerWidth < 1280) {
|
||||
newWidth = "lg";
|
||||
} else if (innerWidth < 1536) {
|
||||
newWidth = "xl";
|
||||
} else {
|
||||
newWidth = "2xl";
|
||||
}
|
||||
|
||||
screenWidth.set(newWidth);
|
||||
}
|
||||
|
||||
// Initialize screen width and set up resize listener
|
||||
export function initScreenWidth(): () => void {
|
||||
checkScreenWidth();
|
||||
window.addEventListener("resize", checkScreenWidth);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", checkScreenWidth);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user