This commit is contained in:
Tomas Dvorak
2026-02-24 10:33:08 +01:00
parent b083dac3f0
commit 55d0284b2a
90 changed files with 27855 additions and 1940 deletions
+11 -25
View File
@@ -164,16 +164,11 @@ export function AIChatPanel(props: AIChatPanelProps) {
onClick={() => setShowModelPicker(!showModelPicker())}
class="flex items-center gap-2 px-3 py-1.5 bg-muted hover:bg-muted/80 rounded-full text-xs transition-colors"
>
<Show when={aiModels.find(m => m.id === selectedModel())?.iconId}>
<AIProviderIcon
providerId={aiModels.find(m => m.id === selectedModel())?.iconId || 'longcat'}
size="1rem"
class="rounded-full"
/>
</Show>
<Show when={!aiModels.find(m => m.id === selectedModel())?.iconId}>
<div class="w-4 h-4 rounded-full bg-gradient-to-r from-blue-500 to-purple-500"></div>
</Show>
<AIProviderIcon
providerId={aiModels.find(m => m.id === selectedModel())?.iconId || 'longcat'}
size="1rem"
class="rounded-full"
/>
<span class="text-muted-foreground">
{aiModels.find(m => m.id === selectedModel())?.name?.split(' ')[0] || 'AI'}
</span>
@@ -196,20 +191,11 @@ export function AIChatPanel(props: AIChatPanelProps) {
}`}
>
<div class="flex items-center gap-2">
<Show when={model.iconId}>
<AIProviderIcon
providerId={model.iconId!}
size="0.75rem"
class="rounded-full flex-shrink-0"
/>
</Show>
<Show when={!model.iconId}>
<div class={`w-3 h-3 rounded-full flex-shrink-0 ${
model.provider === 'LongCat' ? 'bg-gradient-to-r from-orange-500 to-red-500' :
model.provider === 'OpenAI' ? 'bg-gradient-to-r from-green-500 to-emerald-500' :
'bg-gradient-to-r from-purple-500 to-pink-500'
}`}></div>
</Show>
<AIProviderIcon
providerId={model.iconId!}
size="0.75rem"
class="rounded-full flex-shrink-0"
/>
<div class="flex-1 min-w-0">
<div class="font-medium truncate">{model.name}</div>
<div class="text-muted-foreground text-xs truncate">{model.description}</div>
@@ -224,7 +210,7 @@ export function AIChatPanel(props: AIChatPanelProps) {
<div class="flex items-center gap-3 text-xs text-muted-foreground">
<span>{aiModels.find(m => m.id === selectedModel())?.provider || 'LongCat'}</span>
<a href="/app/settings" class="text-primary hover:underline">
<a href="/app/settings#ai" class="text-primary hover:underline">
AI settings
</a>
</div>
@@ -79,7 +79,7 @@ export function FloatingAI(props: FloatingAIProps) {
{/* AI Chat Modal */}
<Show when={props.isChatOpen}>
<div class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 mt-0 p-4">
<div class="bg-card border border-border rounded-lg shadow-xl max-w-md w-full max-h-[600px] flex flex-col" style="width: 420px;">
{/* Header */}
<div class="flex items-center justify-between p-4 border-b border-border bg-gradient-to-r from-primary/10 to-primary/5">
+14 -6
View File
@@ -15,9 +15,10 @@ import { useAuth } from '@/lib/auth'
export interface HeaderProps {
class?: string
title?: string
onMenuClick?: () => void
}
export function Header(_props: HeaderProps) {
export function Header(props: HeaderProps) {
const [showUploadModal, setShowUploadModal] = createSignal(false);
const { authState, updateProfile } = useAuth();
@@ -55,8 +56,15 @@ export function Header(_props: HeaderProps) {
<div class="flex justify-between px-6 pt-4 pb-4">
{/* Left side */}
<div class="flex items-center">
{/* Mobile menu button */}
<button type="button" aria-haspopup="dialog" aria-expanded="false" data-closed="" class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-shadow focus-visible:outline-none focus-visible:ring-1.5 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-inherit hover:bg-accent/50 hover:text-accent-foreground h-9 w-9 md:hidden mr-2">
{/* Menu button */}
<button
type="button"
onClick={props.onMenuClick}
aria-haspopup="dialog"
aria-expanded="false"
data-closed=""
class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-shadow focus-visible:outline-none focus-visible:ring-1.5 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-inherit hover:bg-accent/50 hover:text-accent-foreground h-9 w-9 mr-2"
>
<IconMenu2 class="size-6" />
</button>
@@ -79,10 +87,10 @@ export function Header(_props: HeaderProps) {
<button
type="button"
onClick={() => setShowUploadModal(true)}
class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-shadow focus-visible:outline-none focus-visible:ring-1.5 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground shadow hover:bg-primary/90 h-9 px-4 py-2"
class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-shadow focus-visible:outline-none focus-visible:ring-1.5 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground shadow hover:bg-primary/90 h-10 px-4 py-2 text-base"
>
<IconUpload class="size-4" />
<span class="hidden sm:inline ml-2">Import a document</span>
<IconUpload class="size-4 mr-2" />
Import a document
</button>
{/* Color switcher dropdown */}
+20 -6
View File
@@ -2,7 +2,6 @@ import { children, createSignal, onMount } from 'solid-js'
import { Sidebar } from './Sidebar'
import { Header } from './Header'
import { AIChatPanel } from './AIChatPanel'
import { UpdateNotification } from '../ui/UpdateNotification'
import { IconBrain } from '@tabler/icons-solidjs'
export interface LayoutProps {
@@ -15,6 +14,7 @@ export interface LayoutProps {
export function Layout(props: LayoutProps) {
const resolved = children(() => props.children)
const [isChatOpen, setIsChatOpen] = createSignal(false)
const [isSidebarOpen, setIsSidebarOpen] = createSignal(false)
onMount(() => {
// Initialize dark mode from localStorage or system preference
@@ -142,19 +142,33 @@ export function Layout(props: LayoutProps) {
setIsChatOpen(!isChatOpen())
}
const toggleSidebar = () => {
setIsSidebarOpen(!isSidebarOpen())
}
const closeSidebar = () => {
setIsSidebarOpen(false)
}
return (
<div class="min-h-screen font-sans text-sm font-400 bg-background text-foreground">
{/* Update Notification - Above everything */}
<UpdateNotification />
<div class="flex flex-row h-screen min-h-0">
<div class="flex flex-row h-screen min-h-0 relative">
{/* Mobile Sidebar Overlay */}
{isSidebarOpen() && (
<div
class="fixed inset-0 bg-black/50 z-40"
onClick={closeSidebar}
/>
)}
{/* Sidebar */}
<Sidebar />
<Sidebar isOpen={isSidebarOpen()} onClose={closeSidebar} />
{/* Main Content */}
<div class="flex-1 min-h-0 flex flex-col">
{/* Header */}
<Header title={props.title} />
<Header title={props.title} onMenuClick={toggleSidebar} />
{/* Page Content */}
<main class="flex-1 overflow-auto max-w-screen">
+23 -6
View File
@@ -20,7 +20,8 @@ import {
IconCalendar,
IconLogout,
IconBuilding,
IconPlus
IconPlus,
IconX
} from '@tabler/icons-solidjs'
import { UpdateChecker } from '../ui/UpdateChecker'
@@ -48,9 +49,11 @@ const mockWorkspaces = [
export interface SidebarProps {
class?: string
isOpen?: boolean
onClose?: () => void
}
export function Sidebar(_props: SidebarProps) {
export function Sidebar(props: SidebarProps) {
const location = useLocation()
const [isWorkspaceDropdownOpen, setIsWorkspaceDropdownOpen] = createSignal(false)
const [selectedWorkspace, setSelectedWorkspace] = createSignal(mockWorkspaces[0])
@@ -84,10 +87,23 @@ export function Sidebar(_props: SidebarProps) {
})
return (
<div class="w-280px border-r border-r-border flex-shrink-0 hidden md:block bg-card">
<div class="flex h-full">
<div class="h-full flex flex-col pb-6 flex-1 min-w-0">
{/* Organization Selector */}
<>
{/* Mobile Close Button - Above sidebar */}
<Show when={props.isOpen}>
<button
onClick={props.onClose}
class="fixed top-4 right-4 z-50 md:hidden inline-flex items-center justify-center rounded-md text-sm font-medium transition-shadow focus-visible:outline-none focus-visible:ring-1.5 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-inherit hover:bg-accent/50 hover:text-accent-foreground h-8 w-8"
>
<IconX class="size-4" />
</button>
</Show>
<div class={`fixed inset-y-0 left-0 z-50 w-280px border-r border-r-border flex-shrink-0 bg-card transform transition-transform duration-300 ease-in-out md:relative md:translate-x-0 ${
props.isOpen ? 'translate-x-0' : '-translate-x-full'
}`}>
<div class="flex h-full">
<div class="h-full flex flex-col pb-6 flex-1 min-w-0">
{/* Organization Selector */}
<div class="p-4 pb-0 min-w-0 max-w-full" id="workspace-selector">
<div role="group" class="w-full relative">
<button
@@ -261,5 +277,6 @@ export function Sidebar(_props: SidebarProps) {
</div>
</div>
</div>
</>
)
}