feat: UI
This commit is contained in:
parent
5468fd03e3
commit
6ec8aa9c6e
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -179,7 +179,7 @@
|
|||
/>
|
||||
</Sidebar.Header>
|
||||
|
||||
<Sidebar.Group class="mt-2 space-y-2 p-0 px-3">
|
||||
<Sidebar.Group class="mt-2 h-[calc(100vh-21rem)] space-y-2 p-0 px-3">
|
||||
{#if (filteredConversations.length > 0 && isSearchModeActive) || !isSearchModeActive}
|
||||
<Sidebar.GroupLabel>
|
||||
{isSearchModeActive ? 'Search results' : 'Conversations'}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/state';
|
||||
import { ActionIcon } from '$lib/components/app/actions';
|
||||
import { McpLogo } from '$lib/components/app/mcp';
|
||||
import { Database, Settings, Search, SquarePen } from '@lucide/svelte';
|
||||
|
||||
interface Props {
|
||||
sidebarOpen: boolean;
|
||||
onSearchClick: () => void;
|
||||
}
|
||||
|
||||
let { sidebarOpen, onSearchClick }: Props = $props();
|
||||
|
||||
let isMcpActive = $derived(page.route.id === '/settings/mcp');
|
||||
let isImportExportActive = $derived(page.route.id === '/settings/import-export');
|
||||
let isSettingsActive = $derived(page.route.id === '/settings/chat');
|
||||
</script>
|
||||
|
||||
<!-- Spacer to reserve space for icon strip in the flex layout -->
|
||||
<div
|
||||
class="hidden shrink-0 transition-[width] duration-200 ease-linear md:block {sidebarOpen
|
||||
? 'w-0'
|
||||
: 'w-[calc(var(--sidebar-width-icon)+1.5rem)]'}"
|
||||
></div>
|
||||
<!-- Desktop: icon strip, fixed position so it stays stationary and only fades -->
|
||||
<aside
|
||||
class="fixed top-0 bottom-0 left-0 z-10 hidden w-[calc(var(--sidebar-width-icon)+1.5rem)] flex-col items-center justify-between py-3 transition-opacity duration-200 ease-linear md:flex {sidebarOpen
|
||||
? 'pointer-events-none opacity-0'
|
||||
: 'opacity-100'}"
|
||||
>
|
||||
<div class="mt-12 flex flex-col items-center gap-1">
|
||||
<ActionIcon
|
||||
icon={SquarePen}
|
||||
tooltip="New Chat"
|
||||
size="lg"
|
||||
iconSize="h-4 w-4"
|
||||
class="h-9 w-9 rounded-full hover:bg-accent!"
|
||||
onclick={() => goto('?new_chat=true#/')}
|
||||
/>
|
||||
|
||||
<ActionIcon
|
||||
icon={Search}
|
||||
tooltip="Search"
|
||||
size="lg"
|
||||
iconSize="h-4 w-4"
|
||||
class="h-9 w-9 rounded-full hover:bg-accent!"
|
||||
onclick={onSearchClick}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-1">
|
||||
<ActionIcon
|
||||
icon={McpLogo}
|
||||
tooltip="MCP Servers"
|
||||
size="lg"
|
||||
iconSize="h-4 w-4"
|
||||
class="h-9 w-9 rounded-full hover:bg-accent! {isMcpActive
|
||||
? 'bg-accent text-accent-foreground'
|
||||
: ''}"
|
||||
onclick={() => goto('#/settings/mcp')}
|
||||
/>
|
||||
<ActionIcon
|
||||
icon={Database}
|
||||
tooltip="Import / Export"
|
||||
size="lg"
|
||||
iconSize="h-4 w-4"
|
||||
class="h-9 w-9 rounded-full hover:bg-accent! {isImportExportActive
|
||||
? 'bg-accent text-accent-foreground'
|
||||
: ''}"
|
||||
onclick={() => goto('#/settings/import-export')}
|
||||
/>
|
||||
<ActionIcon
|
||||
icon={Settings}
|
||||
tooltip="Settings"
|
||||
size="lg"
|
||||
iconSize="h-4 w-4"
|
||||
class="h-9 w-9 rounded-full hover:bg-accent! {isSettingsActive
|
||||
? 'bg-accent text-accent-foreground'
|
||||
: ''}"
|
||||
onclick={() => goto('#/settings/chat')}
|
||||
/>
|
||||
</div>
|
||||
</aside>
|
||||
|
|
@ -63,3 +63,11 @@ export { default as DropdownMenuSearchable } from './DropdownMenuSearchable.svel
|
|||
* ```
|
||||
*/
|
||||
export { default as DropdownMenuActions } from './DropdownMenuActions.svelte';
|
||||
|
||||
/**
|
||||
* **DesktopIconStrip** - Fixed icon strip for desktop sidebar
|
||||
*
|
||||
* Vertical icon strip shown on desktop when the sidebar is collapsed.
|
||||
* Contains navigation shortcuts for new chat, search, MCP, import/export, and settings.
|
||||
*/
|
||||
export { default as DesktopIconStrip } from './DesktopIconStrip.svelte';
|
||||
|
|
|
|||
|
|
@ -7,12 +7,10 @@
|
|||
import {
|
||||
ChatSidebar,
|
||||
ChatSettings,
|
||||
McpLogo,
|
||||
DesktopIconStrip,
|
||||
DialogConversationTitleUpdate,
|
||||
DialogChatSettingsImportExport
|
||||
} from '$lib/components/app';
|
||||
import { Database, Settings, Search, SquarePen } from '@lucide/svelte';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { conversationsStore } from '$lib/stores/conversations.svelte';
|
||||
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
|
||||
import * as Tooltip from '$lib/components/ui/tooltip';
|
||||
|
|
@ -46,9 +44,6 @@
|
|||
let titleUpdateResolve: ((value: boolean) => void) | null = null;
|
||||
|
||||
let activePanel = $state<'chat' | 'settings' | 'mcp'>('chat');
|
||||
let isMcpActive = $derived(page.route.id === '/settings/mcp');
|
||||
let isImportExportActive = $derived(page.route.id === '/settings/import-export');
|
||||
let isSettingsActive = $derived(page.route.id === '/settings/chat');
|
||||
let isSettingsRoute = $derived(!!page.route.id?.startsWith('/settings'));
|
||||
let chatSettingsRef: ChatSettings | undefined = $state();
|
||||
let importExportDialogOpen = $state(false);
|
||||
|
|
@ -255,62 +250,15 @@
|
|||
{/if}
|
||||
|
||||
{#if isDesktop && !alwaysShowSidebarOnDesktop}
|
||||
<!-- Desktop: icon strip, always rendered, transitions width/opacity -->
|
||||
<aside
|
||||
class="hidden shrink-0 flex-col items-center justify-between overflow-hidden py-3 transition-[width,opacity] duration-200 ease-linear md:flex {sidebarOpen
|
||||
? 'pointer-events-none w-0 opacity-0'
|
||||
: '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/import-export"
|
||||
class="rounded-full {isImportExportActive ? 'bg-accent text-accent-foreground' : ''}"
|
||||
>
|
||||
<Database class="h-4 w-4" />
|
||||
<span class="sr-only">Import / Export</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>
|
||||
<DesktopIconStrip
|
||||
{sidebarOpen}
|
||||
onSearchClick={() => {
|
||||
if (chatSidebar?.activateSearchMode) {
|
||||
chatSidebar.activateSearchMode();
|
||||
}
|
||||
sidebarOpen = true;
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<Sidebar.Inset class="flex flex-1 flex-col overflow-auto">
|
||||
|
|
|
|||
Loading…
Reference in New Issue