mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-04-28 09:56:23 +02:00
chat-sidebar resizing
This commit is contained in:
parent
74477c772d
commit
35c99cb999
4 changed files with 49 additions and 12 deletions
|
|
@ -116,7 +116,7 @@
|
|||
--sidebar-foreground: var(--text-color, oklch(0.145 0 0));
|
||||
--sidebar-primary: var(--main-color, oklch(0.205 0 0));
|
||||
--sidebar-primary-foreground: var(--bg-color, oklch(0.985 0 0));
|
||||
--sidebar-accent: var(--sub-color, oklch(0.97 0 0));
|
||||
--sidebar-accent: var(--sub-color, oklch(0.90 0 0));
|
||||
--sidebar-accent-foreground: var(--text-color, oklch(0.205 0 0));
|
||||
--sidebar-border: var(--sub-alt-color, oklch(0.922 0 0));
|
||||
--sidebar-ring: var(--main-color, oklch(0.708 0 0));
|
||||
|
|
@ -150,7 +150,7 @@
|
|||
--sidebar-foreground: var(--text-color, oklch(0.985 0 0));
|
||||
--sidebar-primary: var(--main-color, oklch(0.488 0.243 264.376));
|
||||
--sidebar-primary-foreground: var(--bg-color, oklch(0.985 0 0));
|
||||
--sidebar-accent: var(--sub-color, oklch(0.269 0 0));
|
||||
--sidebar-accent: var(--sub-color, oklch(0.35 0 0));
|
||||
--sidebar-accent-foreground: var(--text-color, oklch(0.985 0 0));
|
||||
--sidebar-border: var(--sub-alt-color, oklch(1 0 0 / 10%));
|
||||
--sidebar-ring: var(--main-color, oklch(0.556 0 0));
|
||||
|
|
|
|||
|
|
@ -1124,7 +1124,7 @@ function App() {
|
|||
{/* Chat sidebar - shown when viewing files/graph */}
|
||||
{isChatSidebarOpen && (selectedPath || isGraphOpen) && (
|
||||
<ChatSidebar
|
||||
width={400}
|
||||
defaultWidth={400}
|
||||
onClose={() => setIsChatSidebarOpen(false)}
|
||||
conversation={conversation}
|
||||
currentAssistantMessage={currentAssistantMessage}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { useCallback, useRef, useState } from 'react'
|
||||
import { X } from 'lucide-react'
|
||||
import type { ChatStatus, LanguageModelUsage, ToolUIPart } from 'ai'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { cn } from '@/lib/utils'
|
||||
import {
|
||||
Conversation,
|
||||
ConversationContent,
|
||||
|
|
@ -105,8 +107,12 @@ const normalizeToolOutput = (output: ToolCall['result'] | undefined, status: Too
|
|||
return output
|
||||
}
|
||||
|
||||
const MIN_WIDTH = 300
|
||||
const MAX_WIDTH = 700
|
||||
const DEFAULT_WIDTH = 400
|
||||
|
||||
interface ChatSidebarProps {
|
||||
width?: number
|
||||
defaultWidth?: number
|
||||
onClose: () => void
|
||||
conversation: ConversationItem[]
|
||||
currentAssistantMessage: string
|
||||
|
|
@ -121,7 +127,7 @@ interface ChatSidebarProps {
|
|||
}
|
||||
|
||||
export function ChatSidebar({
|
||||
width = 400,
|
||||
defaultWidth = DEFAULT_WIDTH,
|
||||
onClose,
|
||||
conversation,
|
||||
currentAssistantMessage,
|
||||
|
|
@ -134,6 +140,33 @@ export function ChatSidebar({
|
|||
maxTokens,
|
||||
usedTokens,
|
||||
}: ChatSidebarProps) {
|
||||
const [width, setWidth] = useState(defaultWidth)
|
||||
const [isResizing, setIsResizing] = useState(false)
|
||||
const startXRef = useRef(0)
|
||||
const startWidthRef = useRef(0)
|
||||
|
||||
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
startXRef.current = e.clientX
|
||||
startWidthRef.current = width
|
||||
setIsResizing(true)
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
// Since sidebar is on right, dragging left increases width
|
||||
const delta = startXRef.current - e.clientX
|
||||
const newWidth = Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, startWidthRef.current + delta))
|
||||
setWidth(newWidth)
|
||||
}
|
||||
|
||||
const handleMouseUp = () => {
|
||||
setIsResizing(false)
|
||||
document.removeEventListener('mousemove', handleMouseMove)
|
||||
document.removeEventListener('mouseup', handleMouseUp)
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', handleMouseMove)
|
||||
document.addEventListener('mouseup', handleMouseUp)
|
||||
}, [width])
|
||||
const hasConversation = conversation.length > 0 || currentAssistantMessage || currentReasoning
|
||||
const submitStatus: ChatStatus = isProcessing ? 'streaming' : 'ready'
|
||||
const canSubmit = Boolean(message.trim()) && !isProcessing
|
||||
|
|
@ -188,9 +221,19 @@ export function ChatSidebar({
|
|||
|
||||
return (
|
||||
<div
|
||||
className="flex flex-col border-l border-border bg-background shrink-0"
|
||||
className="relative flex flex-col border-l border-border bg-background shrink-0"
|
||||
style={{ width }}
|
||||
>
|
||||
{/* Resize handle */}
|
||||
<div
|
||||
onMouseDown={handleMouseDown}
|
||||
className={cn(
|
||||
"absolute inset-y-0 left-0 z-20 w-4 -translate-x-1/2 cursor-col-resize",
|
||||
"after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] after:transition-colors",
|
||||
"hover:after:bg-sidebar-border",
|
||||
isResizing && "after:bg-primary"
|
||||
)}
|
||||
/>
|
||||
{/* Header */}
|
||||
<header className="flex h-12 shrink-0 items-center justify-between border-b border-border px-3">
|
||||
<span className="text-sm font-medium">Chat</span>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import {
|
|||
HelpCircle,
|
||||
Plug,
|
||||
Settings,
|
||||
Ship,
|
||||
} from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
|
@ -36,11 +35,6 @@ export function SidebarIcon() {
|
|||
|
||||
return (
|
||||
<div className="bg-sidebar border-r border-sidebar-border flex h-svh w-14 flex-col items-center py-2 fixed left-0 top-0 z-50 shrink-0">
|
||||
{/* Logo */}
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-md bg-sidebar-primary text-sidebar-primary-foreground mb-4">
|
||||
<Ship className="size-5" />
|
||||
</div>
|
||||
|
||||
{/* Main navigation */}
|
||||
<nav className="flex flex-1 flex-col items-center gap-1">
|
||||
{navItems.map((item) => (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue