mirror of
https://github.com/JefferyHcool/BiliNote.git
synced 2026-05-06 20:42:52 +08:00
fix(layout): 优化首页布局并添加可调整面板 fixes #123
- 使用 react-resizable-panels 实现可调整大小的面板 - 重新布局首页结构,分为左、中、右三个可调整区域 - 更新 NoteForm 和 NoteHistory 组件以适应新布局 - 调整 History 组件样式,优化滚动体验 - 更新项目依赖,添加 react-resizable-panels
This commit is contained in:
@@ -39,6 +39,7 @@
|
|||||||
"react-hook-form": "^7.55.0",
|
"react-hook-form": "^7.55.0",
|
||||||
"react-hot-toast": "^2.5.2",
|
"react-hot-toast": "^2.5.2",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
|
"react-resizable-panels": "^2.1.8",
|
||||||
"react-router-dom": "^7.5.1",
|
"react-router-dom": "^7.5.1",
|
||||||
"react-syntax-highlighter": "^15.6.1",
|
"react-syntax-highlighter": "^15.6.1",
|
||||||
"remark-gfm": "1.0.0",
|
"remark-gfm": "1.0.0",
|
||||||
|
|||||||
54
BillNote_frontend/src/components/ui/resizable.tsx
Normal file
54
BillNote_frontend/src/components/ui/resizable.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { GripVerticalIcon } from "lucide-react"
|
||||||
|
import * as ResizablePrimitive from "react-resizable-panels"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function ResizablePanelGroup({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) {
|
||||||
|
return (
|
||||||
|
<ResizablePrimitive.PanelGroup
|
||||||
|
data-slot="resizable-panel-group"
|
||||||
|
className={cn(
|
||||||
|
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ResizablePanel({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof ResizablePrimitive.Panel>) {
|
||||||
|
return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function ResizableHandle({
|
||||||
|
withHandle,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
|
||||||
|
withHandle?: boolean
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<ResizablePrimitive.PanelResizeHandle
|
||||||
|
data-slot="resizable-handle"
|
||||||
|
className={cn(
|
||||||
|
"bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{withHandle && (
|
||||||
|
<div className="bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border">
|
||||||
|
<GripVerticalIcon className="size-2.5" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</ResizablePrimitive.PanelResizeHandle>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
@import 'tw-animate-css';
|
@import 'tw-animate-css';
|
||||||
|
|
||||||
@custom-variant dark (&:is(.dark *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
html,body{
|
html, body, #root {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 修改滚动条轨道颜色 */
|
/* 修改滚动条轨道颜色 */
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 8px; /* 控制滚动条的宽度 */
|
width: 8px; /* 控制滚动条的宽度 */
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
|
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
|
import { ResizablePanel, ResizablePanelGroup, ResizableHandle } from '@/components/ui/resizable'
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
NoteForm: React.ReactNode
|
NoteForm: React.ReactNode
|
||||||
@@ -19,59 +20,53 @@ const HomeLayout: FC<IProps> = ({ NoteForm, Preview, History }) => {
|
|||||||
const [, setShowSettings] = useState(false)
|
const [, setShowSettings] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen flex-col overflow-hidden bg-white">
|
<div className="flex h-screen flex-col overflow-hidden">
|
||||||
<div className="flex flex-1">
|
<ResizablePanelGroup direction="horizontal" className="h-full w-full">
|
||||||
{/* 左侧部分:Header + 表单 */}
|
{/* 左边表单 */}
|
||||||
<aside className="flex w-[340px] flex-col border-r border-neutral-200 bg-white">
|
<ResizablePanel defaultSize={18} minSize={10} maxSize={35}>
|
||||||
{/* Header */}
|
<aside className="flex h-full flex-col overflow-hidden border-r border-neutral-200 bg-white">
|
||||||
<header className="flex h-16 items-center justify-between px-6">
|
<header className="flex h-16 items-center justify-between px-6">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex h-10 w-10 items-center justify-center overflow-hidden rounded-2xl">
|
<div className="flex h-10 w-10 items-center justify-center overflow-hidden rounded-2xl">
|
||||||
<img src="/icon.svg" alt="logo" className="h-full w-full object-contain" />
|
<img src="/icon.svg" alt="logo" className="h-full w-full object-contain" />
|
||||||
|
</div>
|
||||||
|
<div className="text-2xl font-bold text-gray-800">BiliNote</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-2xl font-bold text-gray-800">BiliNote</div>
|
<div>
|
||||||
</div>
|
<TooltipProvider>
|
||||||
<div>
|
<Tooltip>
|
||||||
<TooltipProvider>
|
<TooltipTrigger onClick={() => setShowSettings(true)}>
|
||||||
<Tooltip>
|
<Link to={'/settings'}>
|
||||||
<TooltipTrigger onClick={() => setShowSettings(true)}>
|
<SlidersHorizontal className="text-muted-foreground hover:text-primary cursor-pointer" />
|
||||||
<Link to={'/settings'}>
|
</Link>
|
||||||
<SlidersHorizontal className="text-muted-foreground hover:text-primary cursor-pointer" />
|
</TooltipTrigger>
|
||||||
</Link>
|
<TooltipContent>
|
||||||
</TooltipTrigger>
|
<span>全局配置</span>
|
||||||
<TooltipContent>
|
</TooltipContent>
|
||||||
<span>全局配置</span>
|
</Tooltip>
|
||||||
</TooltipContent>
|
</TooltipProvider>
|
||||||
</Tooltip>
|
</div>
|
||||||
</TooltipProvider>
|
</header>
|
||||||
</div>
|
<div className="flex-1 overflow-auto p-4">{NoteForm}</div>
|
||||||
</header>
|
</aside>
|
||||||
|
</ResizablePanel>
|
||||||
|
|
||||||
{/* 表单内容 */}
|
<ResizableHandle />
|
||||||
<div className="flex-1 overflow-auto p-4">
|
|
||||||
{/*<NoteForm />*/}
|
|
||||||
{NoteForm}
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
<aside className="flex h-full w-[300px] flex-col border-r border-neutral-200 bg-white">
|
|
||||||
{/* Header */}
|
|
||||||
|
|
||||||
{/* 表单内容 */}
|
{/* 中间历史 */}
|
||||||
{/*<NoteForm />*/}
|
<ResizablePanel defaultSize={16} minSize={10} maxSize={30}>
|
||||||
{History}
|
<aside className="flex h-full flex-col overflow-hidden border-r border-neutral-200 bg-white">
|
||||||
</aside>
|
<div className="flex-1 overflow-auto p-4">{History}</div>
|
||||||
|
</aside>
|
||||||
|
</ResizablePanel>
|
||||||
|
|
||||||
{/* 右侧预览区域 */}
|
<ResizableHandle />
|
||||||
<main className="h-screen flex-1 overflow-hidden bg-white p-6">
|
|
||||||
{/*<Outlet />*/}
|
|
||||||
{Preview}
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 页脚 */}
|
{/* 右边预览 */}
|
||||||
{/*<footer className="h-12 bg-white shadow-inner flex items-center justify-center text-sm text-neutral-600">*/}
|
<ResizablePanel defaultSize={55} minSize={30}>
|
||||||
{/* © 2025 BiliNote. All rights reserved.*/}
|
<main className="flex h-full flex-col overflow-hidden bg-white p-6">{Preview}</main>
|
||||||
{/*</footer>*/}
|
</ResizablePanel>
|
||||||
|
</ResizablePanelGroup>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const History = () => {
|
|||||||
<Clock className="h-4 w-4 text-neutral-500" />
|
<Clock className="h-4 w-4 text-neutral-500" />
|
||||||
<h2 className="text-base font-medium text-neutral-900">生成历史</h2>
|
<h2 className="text-base font-medium text-neutral-900">生成历史</h2>
|
||||||
</div>
|
</div>
|
||||||
<ScrollArea className="h-[800px] w-full">
|
<ScrollArea className="w-full sm:h-[480px] md:h-[720px] lg:h-[92%]">
|
||||||
{/*<div className="w-full flex-1 overflow-y-auto">*/}
|
{/*<div className="w-full flex-1 overflow-y-auto">*/}
|
||||||
<NoteHistory onSelect={setCurrentTask} selectedId={currentTaskId} />
|
<NoteHistory onSelect={setCurrentTask} selectedId={currentTaskId} />
|
||||||
{/*</div>*/}
|
{/*</div>*/}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import NoteHistory from '@/pages/HomePage/components/NoteHistory.tsx'
|
|||||||
import { useModelStore } from '@/store/modelStore'
|
import { useModelStore } from '@/store/modelStore'
|
||||||
import { Alert } from 'antd'
|
import { Alert } from 'antd'
|
||||||
import { Textarea } from '@/components/ui/textarea.tsx'
|
import { Textarea } from '@/components/ui/textarea.tsx'
|
||||||
|
import { ScrollArea } from '@/components/ui/scroll-area.tsx'
|
||||||
// ✅ 定义表单 schema
|
// ✅ 定义表单 schema
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
video_url: z.string().url('请输入正确的视频链接'),
|
video_url: z.string().url('请输入正确的视频链接'),
|
||||||
@@ -150,263 +151,269 @@ const NoteForm = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full w-full flex-col overflow-hidden p-4">
|
||||||
<Form {...form}>
|
<div className="flex w-full items-center gap-2 py-1.5">
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
<Button type="submit" className="bg-primary w-full sm:w-full" disabled={isGenerating()}>
|
||||||
<div className="space-y-2">
|
{isGenerating() && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||||
<div className="my-3 flex items-center justify-between">
|
{isGenerating() ? '正在生成…' : '生成笔记'}
|
||||||
<h2 className="block">视频链接</h2>
|
</Button>
|
||||||
<TooltipProvider>
|
</div>
|
||||||
<Tooltip>
|
<ScrollArea className="sm:h-[400px] md:h-[800px]">
|
||||||
<TooltipTrigger asChild>
|
<Form {...form}>
|
||||||
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-2">
|
||||||
</TooltipTrigger>
|
<div className="space-y-2">
|
||||||
<TooltipContent>
|
<div className="my-3 flex items-center justify-between">
|
||||||
<p className="text-xs">输入视频链接,支持哔哩哔哩、YouTube等平台</p>
|
<h2 className="block">视频链接</h2>
|
||||||
</TooltipContent>
|
<TooltipProvider>
|
||||||
</Tooltip>
|
<Tooltip>
|
||||||
</TooltipProvider>
|
<TooltipTrigger asChild>
|
||||||
</div>
|
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p className="text-xs">输入视频链接,支持哔哩哔哩、YouTube等平台</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{/* 平台选择 */}
|
{/* 平台选择 */}
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="platform"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
|
||||||
<FormControl>
|
|
||||||
<SelectTrigger className="w-32">
|
|
||||||
<SelectValue placeholder="选择平台" />
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="bilibili">哔哩哔哩</SelectItem>
|
|
||||||
<SelectItem value="youtube">Youtube</SelectItem>
|
|
||||||
{/*<SelectItem value="local">本地视频</SelectItem>*/}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* 视频地址 */}
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="video_url"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="flex-1">
|
|
||||||
<FormControl>
|
|
||||||
<Input placeholder="视频链接" {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/*<p className="text-xs text-neutral-500">*/}
|
|
||||||
{/* 支持哔哩哔哩视频链接,例如:*/}
|
|
||||||
{/* https://www.bilibili.com/video/BV1vc25YQE9X/*/}
|
|
||||||
{/*</p>*/}
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="quality"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<div className="my-3 flex items-center justify-between">
|
|
||||||
<h2 className="block">音频质量</h2>
|
|
||||||
<TooltipProvider>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p className="max-w-[200px] text-xs">质量越高,下载体积越大,速度越慢</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
</div>
|
|
||||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
|
||||||
<FormControl>
|
|
||||||
<SelectTrigger className="w-full">
|
|
||||||
<SelectValue placeholder="选择质量" />
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="fast">快速(压缩)</SelectItem>
|
|
||||||
<SelectItem value="medium">中等(推荐)</SelectItem>
|
|
||||||
<SelectItem value="slow">高质量(清晰)</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
{/*<FormDescription className="text-xs text-neutral-500">*/}
|
|
||||||
{/* 质量越高,下载体积越大,速度越慢*/}
|
|
||||||
{/*</FormDescription>*/}
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="model_name"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<div className="my-3 flex items-center justify-between">
|
|
||||||
<h2 className="block">模型选择</h2>
|
|
||||||
<TooltipProvider>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p className="max-w-[200px] text-xs">不同模型返回质量不同,可自行测试</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
</div>
|
|
||||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
|
||||||
<FormControl>
|
|
||||||
<SelectTrigger className="w-full">
|
|
||||||
<SelectValue placeholder="选择配置好的模型" />
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent>
|
|
||||||
{modelList.map(item => {
|
|
||||||
return <SelectItem value={item.model_name}>{item.model_name}</SelectItem>
|
|
||||||
})}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
{/*<FormDescription className="text-xs text-neutral-500">*/}
|
|
||||||
{/* 质量越高,下载体积越大,速度越慢*/}
|
|
||||||
{/*</FormDescription>*/}
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="style"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<div className="my-3 flex items-center justify-between">
|
|
||||||
<h2 className="block">笔记风格</h2>
|
|
||||||
<TooltipProvider>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p className="max-w-[200px] text-xs">选择你希望生成的笔记风格</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
|
||||||
<FormControl>
|
|
||||||
<SelectTrigger className="w-full">
|
|
||||||
<SelectValue placeholder="选择笔记风格" />
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent>
|
|
||||||
{noteStyles.map(item => (
|
|
||||||
<SelectItem key={item.value} value={item.value}>
|
|
||||||
{item.label}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="format"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<div className="my-3 flex items-center justify-between">
|
|
||||||
<h2 className="block">笔记格式</h2>
|
|
||||||
<TooltipProvider>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p className="text-xs">选择要包含的笔记元素,比如时间戳、截图提示或总结</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<FormControl>
|
|
||||||
<div className="flex flex-wrap space-x-1.5">
|
|
||||||
{noteFormats.map(item => (
|
|
||||||
<label key={item.value} className="flex items-center space-x-2">
|
|
||||||
<Checkbox
|
|
||||||
checked={field.value?.includes(item.value)}
|
|
||||||
onCheckedChange={checked => {
|
|
||||||
const currentValue = field.value ?? [] // ✨ 保底是数组
|
|
||||||
if (checked) {
|
|
||||||
field.onChange([...currentValue, item.value])
|
|
||||||
} else {
|
|
||||||
field.onChange(currentValue.filter(v => v !== item.value))
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<span>{item.label}</span>
|
|
||||||
</label>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</FormControl>
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="extras"
|
name="platform"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<div className="my-3 flex items-center justify-between">
|
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||||
<h2 className="block">备注</h2>
|
<FormControl>
|
||||||
<TooltipProvider>
|
<SelectTrigger className="w-32">
|
||||||
<Tooltip>
|
<SelectValue placeholder="选择平台" />
|
||||||
<TooltipTrigger asChild>
|
</SelectTrigger>
|
||||||
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
</FormControl>
|
||||||
</TooltipTrigger>
|
<SelectContent>
|
||||||
<TooltipContent>
|
<SelectItem value="bilibili">哔哩哔哩</SelectItem>
|
||||||
<p className="text-xs">会把这段加入到Prompt最后 可自行测试</p>
|
<SelectItem value="youtube">Youtube</SelectItem>
|
||||||
</TooltipContent>
|
{/*<SelectItem value="local">本地视频</SelectItem>*/}
|
||||||
</Tooltip>
|
</SelectContent>
|
||||||
</TooltipProvider>
|
</Select>
|
||||||
</div>
|
|
||||||
<Textarea placeholder={'笔记需要罗列出 xxx 关键点'} {...field} />
|
|
||||||
|
|
||||||
{/*<FormDescription className="text-xs text-neutral-500">*/}
|
|
||||||
{/* 质量越高,下载体积越大,速度越慢*/}
|
|
||||||
{/*</FormDescription>*/}
|
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormMessage />
|
{/* 视频地址 */}
|
||||||
</FormItem>
|
<FormField
|
||||||
)}
|
control={form.control}
|
||||||
/>
|
name="video_url"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="flex-1">
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="视频链接" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/*<p className="text-xs text-neutral-500">*/}
|
||||||
|
{/* 支持哔哩哔哩视频链接,例如:*/}
|
||||||
|
{/* https://www.bilibili.com/video/BV1vc25YQE9X/*/}
|
||||||
|
{/*</p>*/}
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="quality"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<div className="my-3 flex items-center justify-between">
|
||||||
|
<h2 className="block">音频质量</h2>
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p className="max-w-[200px] text-xs">
|
||||||
|
质量越高,下载体积越大,速度越慢
|
||||||
|
</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||||
|
<FormControl>
|
||||||
|
<SelectTrigger className="w-full">
|
||||||
|
<SelectValue placeholder="选择质量" />
|
||||||
|
</SelectTrigger>
|
||||||
|
</FormControl>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="fast">快速(压缩)</SelectItem>
|
||||||
|
<SelectItem value="medium">中等(推荐)</SelectItem>
|
||||||
|
<SelectItem value="slow">高质量(清晰)</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
{/*<FormDescription className="text-xs text-neutral-500">*/}
|
||||||
|
{/* 质量越高,下载体积越大,速度越慢*/}
|
||||||
|
{/*</FormDescription>*/}
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className={'flex w-full items-center gap-2 py-1.5'}>
|
<FormField
|
||||||
{/* 提交按钮 */}
|
control={form.control}
|
||||||
<Button type="submit" className="bg-primary w-full" disabled={isGenerating()}>
|
name="model_name"
|
||||||
{isGenerating() && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
render={({ field }) => (
|
||||||
{isGenerating() ? '正在生成…' : '生成笔记'}
|
<FormItem>
|
||||||
</Button>
|
<div className="my-3 flex items-center justify-between">
|
||||||
</div>
|
<h2 className="block">模型选择</h2>
|
||||||
</form>
|
<TooltipProvider>
|
||||||
</Form>
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p className="max-w-[200px] text-xs">
|
||||||
|
不同模型返回质量不同,可自行测试
|
||||||
|
</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||||
|
<FormControl>
|
||||||
|
<SelectTrigger className="w-full">
|
||||||
|
<SelectValue placeholder="选择配置好的模型" />
|
||||||
|
</SelectTrigger>
|
||||||
|
</FormControl>
|
||||||
|
<SelectContent>
|
||||||
|
{modelList.map(item => {
|
||||||
|
return <SelectItem value={item.model_name}>{item.model_name}</SelectItem>
|
||||||
|
})}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
{/*<FormDescription className="text-xs text-neutral-500">*/}
|
||||||
|
{/* 质量越高,下载体积越大,速度越慢*/}
|
||||||
|
{/*</FormDescription>*/}
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="style"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<div className="my-3 flex items-center justify-between">
|
||||||
|
<h2 className="block">笔记风格</h2>
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p className="max-w-[200px] text-xs">选择你希望生成的笔记风格</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||||
|
<FormControl>
|
||||||
|
<SelectTrigger className="w-full">
|
||||||
|
<SelectValue placeholder="选择笔记风格" />
|
||||||
|
</SelectTrigger>
|
||||||
|
</FormControl>
|
||||||
|
<SelectContent>
|
||||||
|
{noteStyles.map(item => (
|
||||||
|
<SelectItem key={item.value} value={item.value}>
|
||||||
|
{item.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="format"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<div className="my-3 flex items-center justify-between">
|
||||||
|
<h2 className="block">笔记格式</h2>
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p className="text-xs">
|
||||||
|
选择要包含的笔记元素,比如时间戳、截图提示或总结
|
||||||
|
</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormControl>
|
||||||
|
<div className="flex flex-wrap space-x-1.5">
|
||||||
|
{noteFormats.map(item => (
|
||||||
|
<label key={item.value} className="flex items-center space-x-2">
|
||||||
|
<Checkbox
|
||||||
|
checked={field.value?.includes(item.value)}
|
||||||
|
onCheckedChange={checked => {
|
||||||
|
const currentValue = field.value ?? [] // ✨ 保底是数组
|
||||||
|
if (checked) {
|
||||||
|
field.onChange([...currentValue, item.value])
|
||||||
|
} else {
|
||||||
|
field.onChange(currentValue.filter(v => v !== item.value))
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span>{item.label}</span>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="extras"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<div className="my-3 flex items-center justify-between">
|
||||||
|
<h2 className="block">备注</h2>
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Info className="hover:text-primary h-4 w-4 cursor-pointer text-neutral-400" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p className="text-xs">会把这段加入到Prompt最后 可自行测试</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
<Textarea placeholder={'笔记需要罗列出 xxx 关键点'} {...field} />
|
||||||
|
|
||||||
|
{/*<FormDescription className="text-xs text-neutral-500">*/}
|
||||||
|
{/* 质量越高,下载体积越大,速度越慢*/}
|
||||||
|
{/*</FormDescription>*/}
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</ScrollArea>
|
||||||
|
|
||||||
{/* 添加一些额外的说明或功能介绍 */}
|
{/* 添加一些额外的说明或功能介绍 */}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const NoteHistory: FC<NoteHistoryProps> = ({ onSelect, selectedId }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2 overflow-hidden">
|
||||||
{tasks.map(task => (
|
{tasks.map(task => (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
Reference in New Issue
Block a user