feat: WIP
This commit is contained in:
parent
7a13b4191a
commit
ec6302960e
|
|
@ -35,7 +35,7 @@
|
|||
{size}
|
||||
{disabled}
|
||||
{onclick}
|
||||
class="h-6 w-6 p-0 {className} flex"
|
||||
class="h-6 w-6 p-0 {className} flex hover:bg-transparent! data-[state=open]:bg-transparent!"
|
||||
aria-label={ariaLabel || tooltip}
|
||||
>
|
||||
{@const IconComponent = icon}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@
|
|||
Monitor,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
ListRestart
|
||||
ListRestart,
|
||||
|
||||
Sliders
|
||||
|
||||
} from '@lucide/svelte';
|
||||
import { ChatSettingsFooter, ChatSettingsFields } from '$lib/components/app';
|
||||
import { ScrollArea } from '$lib/components/ui/scroll-area';
|
||||
import { config, settingsStore } from '$lib/stores/settings.svelte';
|
||||
import {
|
||||
SETTINGS_SECTION_TITLES,
|
||||
|
|
@ -40,7 +42,7 @@
|
|||
}> = [
|
||||
{
|
||||
title: SETTINGS_SECTION_TITLES.GENERAL,
|
||||
icon: Settings,
|
||||
icon: Sliders,
|
||||
fields: [
|
||||
{
|
||||
key: SETTINGS_KEYS.THEME,
|
||||
|
|
@ -128,13 +130,18 @@
|
|||
type: SettingsFieldType.CHECKBOX
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.AUTO_SHOW_SIDEBAR_ON_NEW_CHAT,
|
||||
label: 'Auto-show sidebar on new chat',
|
||||
key: SETTINGS_KEYS.SHOW_RAW_MODEL_NAMES,
|
||||
label: 'Show raw model names',
|
||||
type: SettingsFieldType.CHECKBOX
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.SHOW_RAW_MODEL_NAMES,
|
||||
label: 'Show raw model names',
|
||||
key: SETTINGS_KEYS.ALWAYS_SHOW_AGENTIC_TURNS,
|
||||
label: 'Always show agentic turns in conversation',
|
||||
type: SettingsFieldType.CHECKBOX
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.SHOW_TOOL_CALL_IN_PROGRESS,
|
||||
label: 'Show tool call in progress',
|
||||
type: SettingsFieldType.CHECKBOX
|
||||
}
|
||||
]
|
||||
|
|
@ -260,20 +267,10 @@
|
|||
label: 'Agentic turns',
|
||||
type: SettingsFieldType.INPUT
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.ALWAYS_SHOW_AGENTIC_TURNS,
|
||||
label: 'Always show agentic turns in conversation',
|
||||
type: SettingsFieldType.CHECKBOX
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.AGENTIC_MAX_TOOL_PREVIEW_LINES,
|
||||
label: 'Max lines per tool preview',
|
||||
type: SettingsFieldType.INPUT
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.SHOW_TOOL_CALL_IN_PROGRESS,
|
||||
label: 'Show tool call in progress',
|
||||
type: SettingsFieldType.CHECKBOX
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -433,17 +430,15 @@
|
|||
</script>
|
||||
|
||||
|
||||
<div class="flex h-full flex-col {className} w-full">
|
||||
<div class="flex items-center gap-2 w-full md:absolute md:top-8">
|
||||
<Settings class="h-6 w-6" />
|
||||
|
||||
<h1 class="text-2xl font-semibold">Settings</h1>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col overflow-hidden md:flex-row gap-4">
|
||||
<div class="flex h-full flex-col overflow-y-auto {className} w-full">
|
||||
<div class="flex flex-1 flex-col md:flex-row gap-4">
|
||||
<!-- Desktop Sidebar -->
|
||||
<div class="hidden w-64 pt-8 mt-16 md:block">
|
||||
<nav class="space-y-1 py-2">
|
||||
<div class="hidden w-64 md:flex flex-col sticky top-0 self-start bg-background pt-8 pb-4">
|
||||
<div class="flex items-center gap-2 pb-6">
|
||||
<Settings class="h-6 w-6" />
|
||||
<h1 class="text-2xl font-semibold">Settings</h1>
|
||||
</div>
|
||||
<nav class="space-y-1">
|
||||
{#each settingSections as section (section.title)}
|
||||
<button
|
||||
class="flex w-full cursor-pointer items-center gap-3 rounded-lg px-3 py-2 text-left text-sm transition-colors hover:bg-accent {activeSection ===
|
||||
|
|
@ -461,8 +456,12 @@
|
|||
</div>
|
||||
|
||||
<!-- Mobile Header with Horizontal Scrollable Menu -->
|
||||
<div class="flex flex-col pt-6 md:hidden">
|
||||
<div class="border-b border-border/30 pt-4 md:py-4">
|
||||
<div class="flex flex-col md:hidden sticky top-0 z-10 bg-background">
|
||||
<div class="flex items-center gap-2 px-4 pt-6 pb-2">
|
||||
<Settings class="h-6 w-6" />
|
||||
<h1 class="text-2xl font-semibold">Settings</h1>
|
||||
</div>
|
||||
<div class="border-b border-border/30 py-2">
|
||||
<!-- Horizontal Scrollable Category Menu with Navigation -->
|
||||
<div class="relative flex items-center" style="scroll-padding: 1rem;">
|
||||
<button
|
||||
|
|
@ -512,8 +511,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<ScrollArea class="flex-1 max-w-5xl mx-auto">
|
||||
<div class="space-y-6 p-4 md:p-6 md:mt-20">
|
||||
<div class="flex-1 max-w-5xl mx-auto">
|
||||
<div class="space-y-6 p-4 md:p-6 md:pt-22">
|
||||
<div class="grid">
|
||||
<div class="mb-6 flex hidden items-center gap-2 border-b border-border/30 pb-6 md:flex">
|
||||
<currentSection.icon class="h-5 w-5" />
|
||||
|
|
@ -537,7 +536,7 @@
|
|||
<p class="text-xs text-muted-foreground">Settings are saved in browser's localStorage</p>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class="flex justify-between p-6">
|
||||
<div class="flex justify-between border-t border-border/30 p-6">
|
||||
<div class="flex gap-2">
|
||||
<Button variant="outline" onclick={handleResetClick}>
|
||||
<RotateCcw class="h-3 w-3" />
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
</Button>
|
||||
</div>
|
||||
|
||||
<Button onclick={handleSave}>Save settings</Button>
|
||||
<Button class="sticky bottom-6 z-10" onclick={handleSave}>Save settings</Button>
|
||||
</div>
|
||||
|
||||
<AlertDialog.Root bind:open={showResetDialog}>
|
||||
|
|
|
|||
|
|
@ -108,10 +108,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
let chatSidebarActions: { activateSearch?: () => void } | undefined = $state();
|
||||
|
||||
export function activateSearchMode() {
|
||||
isSearchModeActive = true;
|
||||
chatSidebarActions?.activateSearch?.();
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if (!sidebar.open) {
|
||||
isSearchModeActive = false;
|
||||
searchQuery = '';
|
||||
}
|
||||
});
|
||||
|
||||
export function editActiveConversation() {
|
||||
if (currentChatId) {
|
||||
const activeConversation = filteredConversations.find((conv) => conv.id === currentChatId);
|
||||
|
|
@ -148,7 +157,7 @@
|
|||
<h1 class="inline-flex items-center gap-1 px-2 text-xl font-semibold">llama.cpp</h1>
|
||||
</a>
|
||||
|
||||
<ChatSidebarActions {handleMobileSidebarItemClick} bind:isSearchModeActive bind:searchQuery />
|
||||
<ChatSidebarActions bind:this={chatSidebarActions} {handleMobileSidebarItemClick} bind:isSearchModeActive bind:searchQuery />
|
||||
</Sidebar.Header>
|
||||
|
||||
<Sidebar.Group class="mt-2 space-y-2 p-0 px-3">
|
||||
|
|
|
|||
|
|
@ -20,17 +20,25 @@
|
|||
}: Props = $props();
|
||||
|
||||
const importExportDialog = getImportExportDialogContext();
|
||||
let searchInputRef = $state<HTMLInputElement | null>(null);
|
||||
|
||||
function handleSearchModeDeactivate() {
|
||||
isSearchModeActive = false;
|
||||
searchQuery = '';
|
||||
}
|
||||
|
||||
export function activateSearch() {
|
||||
isSearchModeActive = true;
|
||||
// Focus after Svelte renders the input
|
||||
queueMicrotask(() => searchInputRef?.focus());
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="my-1 space-y-1">
|
||||
{#if isSearchModeActive}
|
||||
<SearchInput
|
||||
bind:value={searchQuery}
|
||||
bind:ref={searchInputRef}
|
||||
onClose={handleSearchModeDeactivate}
|
||||
onKeyDown={(e) => e.key === 'Escape' && handleSearchModeDeactivate()}
|
||||
placeholder="Search conversations..."
|
||||
|
|
@ -54,9 +62,7 @@
|
|||
|
||||
<Button
|
||||
class="w-full justify-between px-2 backdrop-blur-none! hover:[&>kbd]:opacity-100"
|
||||
onclick={() => {
|
||||
isSearchModeActive = true;
|
||||
}}
|
||||
onclick={activateSearch}
|
||||
variant="ghost"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
|
|
|
|||
|
|
@ -84,22 +84,23 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class="flex items-center gap-2 absolute left-8 top-8">
|
||||
<McpLogo class="h-6 w-6" />
|
||||
|
||||
<h1 class="text-2xl font-semibold">MCP Servers</h1>
|
||||
</div>
|
||||
|
||||
<div class="flex items-start justify-end gap-4 py-4 sticky top-0 z-10 px-8 mt-4">
|
||||
{#if !isAddingServer}
|
||||
<Button variant="outline" size="sm" class="shrink-0" onclick={showAddServerForm}>
|
||||
<Plus class="h-4 w-4" />
|
||||
|
||||
Add New Server
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="grid gap-5 md:space-y-4 {className}">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<McpLogo class="h-6 w-6" />
|
||||
|
||||
<h1 class="text-2xl font-semibold">MCP Servers</h1>
|
||||
</div>
|
||||
|
||||
{#if !isAddingServer}
|
||||
<Button variant="outline" size="sm" class="shrink-0" onclick={showAddServerForm}>
|
||||
<Plus class="h-4 w-4" />
|
||||
|
||||
Add New Server
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if isAddingServer}
|
||||
<Card.Root class="bg-muted/30 p-4">
|
||||
|
|
|
|||
|
|
@ -66,7 +66,8 @@
|
|||
<div
|
||||
data-slot="sidebar-gap"
|
||||
class={cn(
|
||||
'relative w-[calc(var(--sidebar-width)+0.75rem)] bg-transparent transition-[width] duration-200 ease-linear',
|
||||
'relative bg-transparent transition-[width] duration-200 ease-linear',
|
||||
variant === 'floating' ? 'w-[calc(var(--sidebar-width)+0.75rem)]' : 'w-(--sidebar-width)',
|
||||
'group-data-[collapsible=offcanvas]:w-0',
|
||||
'group-data-[side=right]:rotate-180',
|
||||
variant === 'floating' || variant === 'inset'
|
||||
|
|
@ -78,25 +79,36 @@
|
|||
<div
|
||||
data-slot="sidebar-container"
|
||||
class={cn(
|
||||
'fixed inset-y-0 z-999 hidden w-(--sidebar-width) transition-[left,right,width,opacity] duration-200 ease-linear md:z-0 md:flex',
|
||||
side === 'left'
|
||||
? 'left-3 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-0.775)] group-data-[collapsible=offcanvas]:opacity-0'
|
||||
: 'right-1 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-0.775)] group-data-[collapsible=offcanvas]:opacity-0',
|
||||
// Adjust the padding for floating and inset variants.
|
||||
variant === 'floating' || variant === 'inset'
|
||||
'fixed inset-y-0 z-999 hidden w-(--sidebar-width) duration-200 ease-linear md:z-0 md:flex',
|
||||
variant === 'floating'
|
||||
? [
|
||||
'transition-[left,right,width,opacity]',
|
||||
side === 'left'
|
||||
? 'left-3 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-0.775)] group-data-[collapsible=offcanvas]:opacity-0'
|
||||
: 'right-3 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-0.775)] group-data-[collapsible=offcanvas]:opacity-0',
|
||||
'my-3 overflow-hidden rounded-2xl border border-sidebar-border shadow-md',
|
||||
]
|
||||
: [
|
||||
'transition-[left,right,width] h-svh',
|
||||
side === 'left'
|
||||
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
|
||||
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
|
||||
],
|
||||
// Adjust the padding for inset variant.
|
||||
variant === 'inset'
|
||||
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
|
||||
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
|
||||
// Add margin and rounded corners
|
||||
'my-3 overflow-hidden rounded-2xl border border-sidebar-border shadow-md',
|
||||
: variant === 'floating'
|
||||
? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
|
||||
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
|
||||
className
|
||||
)}
|
||||
style="height: calc(100dvh - 1.5rem);"
|
||||
style={variant === 'floating' ? 'height: calc(100dvh - 1.5rem);' : undefined}
|
||||
{...restProps}
|
||||
>
|
||||
<div
|
||||
data-sidebar="sidebar"
|
||||
data-slot="sidebar-inner"
|
||||
class="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow-sm"
|
||||
class="flex h-full w-full flex-col bg-sidebar"
|
||||
>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ export const SETTING_CONFIG_DEFAULT: Record<string, string | number | boolean |
|
|||
disableAutoScroll: false,
|
||||
renderUserContentAsMarkdown: false,
|
||||
alwaysShowSidebarOnDesktop: false,
|
||||
autoShowSidebarOnNewChat: true,
|
||||
autoMicOnEmpty: false,
|
||||
fullHeightCodeBlocks: false,
|
||||
showRawModelNames: false,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ export const SETTINGS_KEYS = {
|
|||
RENDER_USER_CONTENT_AS_MARKDOWN: 'renderUserContentAsMarkdown',
|
||||
DISABLE_AUTO_SCROLL: 'disableAutoScroll',
|
||||
ALWAYS_SHOW_SIDEBAR_ON_DESKTOP: 'alwaysShowSidebarOnDesktop',
|
||||
AUTO_SHOW_SIDEBAR_ON_NEW_CHAT: 'autoShowSidebarOnNewChat',
|
||||
FULL_HEIGHT_CODE_BLOCKS: 'fullHeightCodeBlocks',
|
||||
SHOW_RAW_MODEL_NAMES: 'showRawModelNames',
|
||||
// Sampling
|
||||
|
|
|
|||
|
|
@ -191,12 +191,6 @@ export const SYNCABLE_PARAMETERS: SyncableParameter[] = [
|
|||
type: SyncableParameterType.BOOLEAN,
|
||||
canSync: true
|
||||
},
|
||||
{
|
||||
key: 'autoShowSidebarOnNewChat',
|
||||
serverKey: 'autoShowSidebarOnNewChat',
|
||||
type: SyncableParameterType.BOOLEAN,
|
||||
canSync: true
|
||||
},
|
||||
{
|
||||
key: 'showRawModelNames',
|
||||
serverKey: 'showRawModelNames',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
DialogConversationTitleUpdate,
|
||||
DialogChatSettingsImportExport
|
||||
} from '$lib/components/app';
|
||||
import { Settings } from '@lucide/svelte';
|
||||
import { Settings, Search, SquarePen } from '@lucide/svelte';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { isLoading } from '$lib/stores/chat.svelte';
|
||||
import { conversationsStore, activeMessages } from '$lib/stores/conversations.svelte';
|
||||
|
|
@ -41,7 +41,6 @@
|
|||
let isNewChatMode = $derived(page.url.searchParams.get('new_chat') === 'true');
|
||||
let showSidebarByDefault = $derived(activeMessages().length > 0 || isLoading());
|
||||
let alwaysShowSidebarOnDesktop = $derived(config().alwaysShowSidebarOnDesktop);
|
||||
let autoShowSidebarOnNewChat = $derived(config().autoShowSidebarOnNewChat);
|
||||
let isMobile = new IsMobile();
|
||||
let isDesktop = $derived(!isMobile.current);
|
||||
let sidebarOpen = $state(false);
|
||||
|
|
@ -57,6 +56,8 @@
|
|||
let titleUpdateResolve: ((value: boolean) => void) | null = null;
|
||||
|
||||
let activePanel = $state<'chat' | 'settings' | 'mcp'>('chat');
|
||||
let isMcpActive = $derived(page.route.id === '/settings/mcp');
|
||||
let isSettingsActive = $derived(page.route.id === '/settings/chat');
|
||||
// let chatSettingsInitialSection = $state<SettingsSectionTitle | undefined>(undefined);
|
||||
let chatSettingsRef: ChatSettings | undefined = $state();
|
||||
let importExportDialogOpen = $state(false);
|
||||
|
|
@ -141,23 +142,7 @@
|
|||
sidebarOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isHomeRoute && !isNewChatMode) {
|
||||
// Auto-collapse sidebar when navigating to home route (but not in new chat mode)
|
||||
sidebarOpen = false;
|
||||
} else if (isHomeRoute && isNewChatMode) {
|
||||
// Keep sidebar open in new chat mode
|
||||
sidebarOpen = true;
|
||||
} else if (isChatRoute) {
|
||||
// On chat routes, only auto-show sidebar if setting is enabled
|
||||
if (autoShowSidebarOnNewChat) {
|
||||
sidebarOpen = true;
|
||||
}
|
||||
// If setting is disabled, don't change sidebar state - let user control it manually
|
||||
} else {
|
||||
// Other routes follow default behavior
|
||||
sidebarOpen = showSidebarByDefault;
|
||||
}
|
||||
// Don't auto-open or auto-close sidebar during navigation - user controls it manually
|
||||
});
|
||||
|
||||
// Initialize server properties on app load (run once)
|
||||
|
|
@ -280,7 +265,7 @@
|
|||
|
||||
<Sidebar.Provider bind:open={sidebarOpen}>
|
||||
<div class="flex h-screen w-full" style:height="{innerHeight}px">
|
||||
<Sidebar.Root class="h-full">
|
||||
<Sidebar.Root variant="floating" class="h-full">
|
||||
<ChatSidebar bind:this={chatSidebar} />
|
||||
</Sidebar.Root>
|
||||
|
||||
|
|
@ -293,28 +278,80 @@
|
|||
/>
|
||||
{/if}
|
||||
|
||||
{#if !sidebarOpen}
|
||||
<div class="absolute bottom-3 left-3 z-[900] flex flex-col gap-1 p-2">
|
||||
{#if isDesktop && !alwaysShowSidebarOnDesktop}
|
||||
<!-- Desktop: icon strip, always rendered, transitions width/opacity -->
|
||||
<aside class="hidden md:flex shrink-0 flex-col items-center justify-between overflow-hidden py-3 transition-[width,opacity] duration-200 ease-linear {sidebarOpen ? 'w-0 opacity-0 pointer-events-none' : 'w-[calc(var(--sidebar-width-icon)+1.5rem)] opacity-100'}">
|
||||
<div class="mt-12 flex flex-col items-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-lg"
|
||||
class="rounded-full"
|
||||
href="?new_chat=true#/"
|
||||
>
|
||||
<SquarePen class="h-4 w-4" />
|
||||
<span class="sr-only">New Chat</span>
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-lg"
|
||||
class="rounded-full"
|
||||
onclick={() => {
|
||||
if (chatSidebar?.activateSearchMode) {
|
||||
chatSidebar.activateSearchMode();
|
||||
}
|
||||
sidebarOpen = true;
|
||||
}}
|
||||
>
|
||||
<Search class="h-4 w-4" />
|
||||
<span class="sr-only">Search</span>
|
||||
</Button>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-lg"
|
||||
href="#/settings/mcp"
|
||||
class="rounded-full {isMcpActive ? 'bg-accent text-accent-foreground' : ''}"
|
||||
>
|
||||
<McpLogo class="h-4 w-4" />
|
||||
<span class="sr-only">MCP Servers</span>
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-lg"
|
||||
href="#/settings/chat"
|
||||
class="rounded-full {isSettingsActive ? 'bg-accent text-accent-foreground' : ''}"
|
||||
>
|
||||
<Settings class="h-4 w-4" />
|
||||
<span class="sr-only">Settings</span>
|
||||
</Button>
|
||||
</div>
|
||||
</aside>
|
||||
{/if}
|
||||
|
||||
{#if !sidebarOpen && !isDesktop}
|
||||
<!-- Mobile quick-access buttons -->
|
||||
<div class="absolute bottom-3 left-3 z-[900] flex flex-col gap-1 p-2 md:hidden">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-8 w-8 {activePanel === 'mcp' ? 'bg-accent text-accent-foreground' : ''}"
|
||||
onclick={() => (activePanel = activePanel === 'mcp' ? 'chat' : 'mcp')}
|
||||
size="icon-lg"
|
||||
href="#/settings/mcp"
|
||||
class={isMcpActive ? 'bg-accent text-accent-foreground' : ''}
|
||||
>
|
||||
<McpLogo class="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-8 w-8 {activePanel === 'settings' ? 'bg-accent text-accent-foreground' : ''}"
|
||||
onclick={() => (activePanel = activePanel === 'settings' ? 'chat' : 'settings')}
|
||||
size="icon-lg"
|
||||
href="#/settings/chat"
|
||||
class={isSettingsActive ? 'bg-accent text-accent-foreground' : ''}
|
||||
>
|
||||
<Settings class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<Sidebar.Inset class="flex flex-1 flex-col overflow-hidden">
|
||||
<Sidebar.Inset class="flex flex-1 flex-col overflow-auto">
|
||||
{@render children?.()}
|
||||
</Sidebar.Inset>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue