mirror of
https://github.com/JefferyHcool/BiliNote.git
synced 2026-09-06 16:16:56 +08:00
refactor(chat): 全屏/半屏切换移入 ChatPanel 内部
- Header 恢复单个"AI 问答"按钮,点击默认打开半屏模式 - ChatPanel 头部新增全屏/半屏切换按钮(Maximize2/Minimize2 图标) - 半屏:markdown 与问答并排各占一半 - 全屏:问答占满内容区,隐藏 markdown Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
dea393e713
commit
d8fbceaadf
@@ -3,14 +3,18 @@ import { Bubble, Sender } from '@ant-design/x'
|
|||||||
import type { BubbleProps } from '@ant-design/x'
|
import type { BubbleProps } from '@ant-design/x'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Badge } from '@/components/ui/badge'
|
import { Badge } from '@/components/ui/badge'
|
||||||
import { Loader2, Trash2, ChevronDown, ChevronUp, BookOpen, UserRound, Bot } from 'lucide-react'
|
import { Loader2, Trash2, ChevronDown, ChevronUp, BookOpen, UserRound, Bot, Maximize2, Minimize2 } from 'lucide-react'
|
||||||
import { toast } from 'react-hot-toast'
|
import { toast } from 'react-hot-toast'
|
||||||
import { useChatStore } from '@/store/chatStore'
|
import { useChatStore } from '@/store/chatStore'
|
||||||
import { useTaskStore } from '@/store/taskStore'
|
import { useTaskStore } from '@/store/taskStore'
|
||||||
import { askQuestion, getChatStatus, indexTask, type ChatSource, type IndexStatus } from '@/services/chat'
|
import { askQuestion, getChatStatus, indexTask, type ChatSource, type IndexStatus } from '@/services/chat'
|
||||||
|
|
||||||
|
type ChatMode = 'half' | 'full'
|
||||||
|
|
||||||
interface ChatPanelProps {
|
interface ChatPanelProps {
|
||||||
taskId: string
|
taskId: string
|
||||||
|
mode: ChatMode
|
||||||
|
onModeChange: (mode: ChatMode) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function SourceBadges({ sources }: { sources: ChatSource[] }) {
|
function SourceBadges({ sources }: { sources: ChatSource[] }) {
|
||||||
@@ -43,7 +47,7 @@ function SourceBadges({ sources }: { sources: ChatSource[] }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ChatPanel({ taskId }: ChatPanelProps) {
|
export default function ChatPanel({ taskId, mode, onModeChange }: ChatPanelProps) {
|
||||||
const [input, setInput] = useState('')
|
const [input, setInput] = useState('')
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [indexStatus, setIndexStatus] = useState<IndexStatus | null>(null)
|
const [indexStatus, setIndexStatus] = useState<IndexStatus | null>(null)
|
||||||
@@ -218,6 +222,20 @@ export default function ChatPanel({ taskId }: ChatPanelProps) {
|
|||||||
{/* 头部 */}
|
{/* 头部 */}
|
||||||
<div className="flex items-center justify-between border-b px-3 py-2">
|
<div className="flex items-center justify-between border-b px-3 py-2">
|
||||||
<span className="text-sm font-medium">AI 问答</span>
|
<span className="text-sm font-medium">AI 问答</span>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="h-7 px-2 text-neutral-400 hover:text-neutral-600"
|
||||||
|
onClick={() => onModeChange(mode === 'half' ? 'full' : 'half')}
|
||||||
|
title={mode === 'half' ? '全屏' : '半屏'}
|
||||||
|
>
|
||||||
|
{mode === 'half' ? (
|
||||||
|
<Maximize2 className="h-3.5 w-3.5" />
|
||||||
|
) : (
|
||||||
|
<Minimize2 className="h-3.5 w-3.5" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
{messages.length > 0 && (
|
{messages.length > 0 && (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -229,6 +247,7 @@ export default function ChatPanel({ taskId }: ChatPanelProps) {
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 消息列表 */}
|
{/* 消息列表 */}
|
||||||
<div className="flex-1 overflow-hidden">
|
<div className="flex-1 overflow-hidden">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { Copy, Download, BrainCircuit, MessageSquare, PanelRight, Maximize2 } from 'lucide-react'
|
import { Copy, Download, BrainCircuit, MessageSquare } from 'lucide-react'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select'
|
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select'
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
|
||||||
@@ -188,40 +188,22 @@ export function MarkdownHeader({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
{setShowChat && (
|
{setShowChat && (
|
||||||
<div className="flex items-center gap-0.5 ml-1">
|
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setShowChat(showChat === 'half' ? false : 'half')}
|
onClick={() => setShowChat(showChat ? false : 'half')}
|
||||||
variant={showChat === 'half' ? 'default' : 'ghost'}
|
variant={showChat ? 'default' : 'ghost'}
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-8 px-2"
|
className="h-8 px-2"
|
||||||
>
|
>
|
||||||
<PanelRight className="mr-1.5 h-4 w-4" />
|
<MessageSquare className="mr-1.5 h-4 w-4" />
|
||||||
<span className="text-sm">问答</span>
|
<span className="text-sm">AI 问答</span>
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>侧边问答(半屏)</TooltipContent>
|
<TooltipContent>基于笔记内容的 AI 问答</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
<TooltipProvider>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Button
|
|
||||||
onClick={() => setShowChat(showChat === 'full' ? false : 'full')}
|
|
||||||
variant={showChat === 'full' ? 'default' : 'ghost'}
|
|
||||||
size="sm"
|
|
||||||
className="h-8 px-2"
|
|
||||||
>
|
|
||||||
<Maximize2 className="mr-1.5 h-4 w-4" />
|
|
||||||
<span className="text-sm">全屏问答</span>
|
|
||||||
</Button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>全屏问答</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -221,10 +221,9 @@ const MarkdownViewer: FC<MarkdownViewerProps> = ({ status }) => {
|
|||||||
<div className="flex flex-1 overflow-hidden bg-white py-2">
|
<div className="flex flex-1 overflow-hidden bg-white py-2">
|
||||||
{selectedContent && selectedContent !== 'loading' && selectedContent !== 'empty' ? (
|
{selectedContent && selectedContent !== 'loading' && selectedContent !== 'empty' ? (
|
||||||
<>
|
<>
|
||||||
{/* 全屏问答模式:隐藏 markdown,ChatPanel 占满 */}
|
|
||||||
{showChat === 'full' && currentTask ? (
|
{showChat === 'full' && currentTask ? (
|
||||||
<div className="h-full w-full">
|
<div className="h-full w-full">
|
||||||
<ChatPanel taskId={currentTask.id} />
|
<ChatPanel taskId={currentTask.id} mode="full" onModeChange={setShowChat} />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@@ -486,7 +485,7 @@ const MarkdownViewer: FC<MarkdownViewerProps> = ({ status }) => {
|
|||||||
{/* 侧边问答模式:markdown + ChatPanel 各占一半 */}
|
{/* 侧边问答模式:markdown + ChatPanel 各占一半 */}
|
||||||
{showChat === 'half' && currentTask && (
|
{showChat === 'half' && currentTask && (
|
||||||
<div className="ml-2 h-full w-1/2 shrink-0">
|
<div className="ml-2 h-full w-1/2 shrink-0">
|
||||||
<ChatPanel taskId={currentTask.id} />
|
<ChatPanel taskId={currentTask.id} mode="half" onModeChange={setShowChat} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user