diff --git a/ui-svelte/src/App.svelte b/ui-svelte/src/App.svelte index 4ba3b478..895a057f 100644 --- a/ui-svelte/src/App.svelte +++ b/ui-svelte/src/App.svelte @@ -13,6 +13,7 @@ import { enableAPIEvents, checkPerformanceEnabled } from "./stores/api"; import { initScreenWidth, initSystemThemeListener, isDarkMode, appTitle, connectionState } from "./stores/theme"; import { currentRoute } from "./stores/route"; + import { selectedPlaygroundTab, playgroundTabs } from "./stores/playground"; const routes = { "/": PlaygroundStub, @@ -31,7 +32,13 @@ "/performance": "Performance", }; - let sectionTitle = $derived(routeTitles[$currentRoute] ?? "Playground"); + let sectionTitle = $derived.by(() => { + if ($currentRoute === "/") { + const tab = playgroundTabs.find((t) => t.id === $selectedPlaygroundTab); + return `Playground / ${tab?.label ?? ""}`; + } + return routeTitles[$currentRoute] ?? "Playground"; + }); function handleRouteLoaded(event: { detail: { route: string | RegExp } }) { const route = event.detail.route; diff --git a/ui-svelte/src/components/AppSidebar.svelte b/ui-svelte/src/components/AppSidebar.svelte index 3e9f56db..356981f7 100644 --- a/ui-svelte/src/components/AppSidebar.svelte +++ b/ui-svelte/src/components/AppSidebar.svelte @@ -1,12 +1,14 @@ + + + {@render children?.()} + diff --git a/ui-svelte/src/lib/components/ui/collapsible/collapsible-trigger.svelte b/ui-svelte/src/lib/components/ui/collapsible/collapsible-trigger.svelte new file mode 100644 index 00000000..5f0f915f --- /dev/null +++ b/ui-svelte/src/lib/components/ui/collapsible/collapsible-trigger.svelte @@ -0,0 +1,19 @@ + + + + {@render children?.()} + diff --git a/ui-svelte/src/lib/components/ui/collapsible/collapsible.svelte b/ui-svelte/src/lib/components/ui/collapsible/collapsible.svelte new file mode 100644 index 00000000..7ad7e756 --- /dev/null +++ b/ui-svelte/src/lib/components/ui/collapsible/collapsible.svelte @@ -0,0 +1,19 @@ + + + + {@render children?.()} + diff --git a/ui-svelte/src/lib/components/ui/collapsible/index.ts b/ui-svelte/src/lib/components/ui/collapsible/index.ts new file mode 100644 index 00000000..60c0938c --- /dev/null +++ b/ui-svelte/src/lib/components/ui/collapsible/index.ts @@ -0,0 +1,13 @@ +import Root from "./collapsible.svelte"; +import Trigger from "./collapsible-trigger.svelte"; +import Content from "./collapsible-content.svelte"; + +export { + Root, + Trigger, + Content, + // + Root as Collapsible, + Trigger as CollapsibleTrigger, + Content as CollapsibleContent, +}; diff --git a/ui-svelte/src/lib/components/ui/sidebar/sidebar-menu-button.svelte b/ui-svelte/src/lib/components/ui/sidebar/sidebar-menu-button.svelte index e0c9c25e..d8e7f78e 100644 --- a/ui-svelte/src/lib/components/ui/sidebar/sidebar-menu-button.svelte +++ b/ui-svelte/src/lib/components/ui/sidebar/sidebar-menu-button.svelte @@ -2,7 +2,7 @@ import { tv, type VariantProps } from "tailwind-variants"; export const sidebarMenuButtonVariants = tv({ - base: "ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground gap-2 rounded-md p-2 text-left text-sm transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 data-active:font-medium peer/menu-button group/menu-button flex w-full items-center overflow-hidden outline-hidden disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate", + base: "ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-active:font-medium data-active:text-sidebar-accent-foreground data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground gap-2 rounded-md p-2 text-left text-sm transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 peer/menu-button group/menu-button flex w-full items-center overflow-hidden outline-hidden disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate", variants: { variant: { default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", diff --git a/ui-svelte/src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte b/ui-svelte/src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte index 09ff228f..4a805973 100644 --- a/ui-svelte/src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte +++ b/ui-svelte/src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte @@ -19,7 +19,7 @@ const mergedProps = $derived({ class: cn( - "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground h-7 gap-2 rounded-md px-2 focus-visible:ring-2 data-[size=md]:text-sm data-[size=sm]:text-xs [&>svg]:size-4 flex min-w-0 -translate-x-px items-center overflow-hidden outline-hidden group-data-[collapsible=icon]:hidden disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:shrink-0", + "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground data-active:font-medium data-active:text-sidebar-accent-foreground h-7 gap-2 rounded-md px-2 focus-visible:ring-2 data-[size=md]:text-sm data-[size=sm]:text-xs [&>svg]:size-4 flex min-w-0 -translate-x-px items-center overflow-hidden outline-hidden group-data-[collapsible=icon]:hidden disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:shrink-0", className ), "data-slot": "sidebar-menu-sub-button", diff --git a/ui-svelte/src/lib/components/ui/sidebar/sidebar.svelte b/ui-svelte/src/lib/components/ui/sidebar/sidebar.svelte index 9c90d4f8..dc9bf743 100644 --- a/ui-svelte/src/lib/components/ui/sidebar/sidebar.svelte +++ b/ui-svelte/src/lib/components/ui/sidebar/sidebar.svelte @@ -25,7 +25,7 @@ {#if collapsible === "none"}
button]:hidden", + "bg-background text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden", className )} style="--sidebar-width: {SIDEBAR_WIDTH_MOBILE};" @@ -99,7 +99,7 @@
{@render children?.()}
diff --git a/ui-svelte/src/routes/Playground.svelte b/ui-svelte/src/routes/Playground.svelte index b4ba7b47..edfd2c24 100644 --- a/ui-svelte/src/routes/Playground.svelte +++ b/ui-svelte/src/routes/Playground.svelte @@ -1,5 +1,4 @@ - -
- $selectedTabStore, (v) => selectedTabStore.set(v as Tab)}> - - {#each tabs as tab (tab.id)} - {tab.label} - {/each} - - -
- - +
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/ui-svelte/src/stores/playground.ts b/ui-svelte/src/stores/playground.ts new file mode 100644 index 00000000..3e2b92b3 --- /dev/null +++ b/ui-svelte/src/stores/playground.ts @@ -0,0 +1,16 @@ +import { persistentStore } from "./persistent"; + +export type PlaygroundTab = "chat" | "images" | "speech" | "audio" | "rerank" | "concurrency"; + +export const playgroundTabs: { id: PlaygroundTab; label: string }[] = [ + { id: "chat", label: "Chat" }, + { id: "images", label: "Images" }, + { id: "speech", label: "Speech" }, + { id: "audio", label: "Transcription" }, + { id: "rerank", label: "Rerank" }, + { id: "concurrency", label: "Load Test" }, +]; + +export const selectedPlaygroundTab = persistentStore("playground-selected-tab", "chat"); + +export const playgroundMenuOpen = persistentStore("playground-menu-open", true);