mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-12 21:02:17 +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-foreground: var(--text-color, oklch(0.145 0 0));
|
||||||
--sidebar-primary: var(--main-color, oklch(0.205 0 0));
|
--sidebar-primary: var(--main-color, oklch(0.205 0 0));
|
||||||
--sidebar-primary-foreground: var(--bg-color, oklch(0.985 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-accent-foreground: var(--text-color, oklch(0.205 0 0));
|
||||||
--sidebar-border: var(--sub-alt-color, oklch(0.922 0 0));
|
--sidebar-border: var(--sub-alt-color, oklch(0.922 0 0));
|
||||||
--sidebar-ring: var(--main-color, oklch(0.708 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-foreground: var(--text-color, oklch(0.985 0 0));
|
||||||
--sidebar-primary: var(--main-color, oklch(0.488 0.243 264.376));
|
--sidebar-primary: var(--main-color, oklch(0.488 0.243 264.376));
|
||||||
--sidebar-primary-foreground: var(--bg-color, oklch(0.985 0 0));
|
--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-accent-foreground: var(--text-color, oklch(0.985 0 0));
|
||||||
--sidebar-border: var(--sub-alt-color, oklch(1 0 0 / 10%));
|
--sidebar-border: var(--sub-alt-color, oklch(1 0 0 / 10%));
|
||||||
--sidebar-ring: var(--main-color, oklch(0.556 0 0));
|
--sidebar-ring: var(--main-color, oklch(0.556 0 0));
|
||||||
|
|
|
||||||
|
|
@ -1124,7 +1124,7 @@ function App() {
|
||||||
{/* Chat sidebar - shown when viewing files/graph */}
|
{/* Chat sidebar - shown when viewing files/graph */}
|
||||||
{isChatSidebarOpen && (selectedPath || isGraphOpen) && (
|
{isChatSidebarOpen && (selectedPath || isGraphOpen) && (
|
||||||
<ChatSidebar
|
<ChatSidebar
|
||||||
width={400}
|
defaultWidth={400}
|
||||||
onClose={() => setIsChatSidebarOpen(false)}
|
onClose={() => setIsChatSidebarOpen(false)}
|
||||||
conversation={conversation}
|
conversation={conversation}
|
||||||
currentAssistantMessage={currentAssistantMessage}
|
currentAssistantMessage={currentAssistantMessage}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
import { useCallback, useRef, useState } from 'react'
|
||||||
import { X } from 'lucide-react'
|
import { X } from 'lucide-react'
|
||||||
import type { ChatStatus, LanguageModelUsage, ToolUIPart } from 'ai'
|
import type { ChatStatus, LanguageModelUsage, ToolUIPart } from 'ai'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
import {
|
import {
|
||||||
Conversation,
|
Conversation,
|
||||||
ConversationContent,
|
ConversationContent,
|
||||||
|
|
@ -105,8 +107,12 @@ const normalizeToolOutput = (output: ToolCall['result'] | undefined, status: Too
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MIN_WIDTH = 300
|
||||||
|
const MAX_WIDTH = 700
|
||||||
|
const DEFAULT_WIDTH = 400
|
||||||
|
|
||||||
interface ChatSidebarProps {
|
interface ChatSidebarProps {
|
||||||
width?: number
|
defaultWidth?: number
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
conversation: ConversationItem[]
|
conversation: ConversationItem[]
|
||||||
currentAssistantMessage: string
|
currentAssistantMessage: string
|
||||||
|
|
@ -121,7 +127,7 @@ interface ChatSidebarProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ChatSidebar({
|
export function ChatSidebar({
|
||||||
width = 400,
|
defaultWidth = DEFAULT_WIDTH,
|
||||||
onClose,
|
onClose,
|
||||||
conversation,
|
conversation,
|
||||||
currentAssistantMessage,
|
currentAssistantMessage,
|
||||||
|
|
@ -134,6 +140,33 @@ export function ChatSidebar({
|
||||||
maxTokens,
|
maxTokens,
|
||||||
usedTokens,
|
usedTokens,
|
||||||
}: ChatSidebarProps) {
|
}: 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 hasConversation = conversation.length > 0 || currentAssistantMessage || currentReasoning
|
||||||
const submitStatus: ChatStatus = isProcessing ? 'streaming' : 'ready'
|
const submitStatus: ChatStatus = isProcessing ? 'streaming' : 'ready'
|
||||||
const canSubmit = Boolean(message.trim()) && !isProcessing
|
const canSubmit = Boolean(message.trim()) && !isProcessing
|
||||||
|
|
@ -188,9 +221,19 @@ export function ChatSidebar({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<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 }}
|
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 */}
|
||||||
<header className="flex h-12 shrink-0 items-center justify-between border-b border-border px-3">
|
<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>
|
<span className="text-sm font-medium">Chat</span>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import {
|
||||||
HelpCircle,
|
HelpCircle,
|
||||||
Plug,
|
Plug,
|
||||||
Settings,
|
Settings,
|
||||||
Ship,
|
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
|
|
@ -36,11 +35,6 @@ export function SidebarIcon() {
|
||||||
|
|
||||||
return (
|
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">
|
<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 */}
|
{/* Main navigation */}
|
||||||
<nav className="flex flex-1 flex-col items-center gap-1">
|
<nav className="flex flex-1 flex-col items-center gap-1">
|
||||||
{navItems.map((item) => (
|
{navItems.map((item) => (
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue