页面布局调整

This commit is contained in:
fengxiangdebaozi committed 2026-05-14 16:01:25 +08:00
1 parent 139dfb76e4
commit e6ad3c414f
7 files changed
+144 -49

No files matched your search

+3 -3
View File
@@ -139,7 +139,7 @@ function SidebarProvider({
} as React.CSSProperties
}
className={cn(
"group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
"group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex h-full w-full",
className,
)}
{...props}
@@ -229,7 +229,7 @@ function Sidebar({
<div
data-slot="sidebar-container"
className={cn(
"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
"fixed top-16 bottom-0 z-10 hidden w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
side === "left"
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
@@ -309,7 +309,7 @@ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
<main
data-slot="sidebar-inset"
className={cn(
"bg-[#fffdfa] relative flex w-full flex-1 flex-col",
"bg-background relative flex w-full flex-1 flex-col",
"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
className,
)}
@@ -449,7 +449,7 @@ export function InputBox({
<button
key={q.id}
type="button"
className="rounded-full border border-[#e4e4e7] bg-white px-4 py-2 text-sm text-[#18181b] shadow-none transition-colors hover:bg-[#f4f4f5] cursor-pointer"
className="rounded-full border border-[#e4e4e7] bg-white px-4 py-2 text-sm text-[#18181b] shadow-none transition-colors hover:bg-[#f4f4f5] cursor-pointer dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700"
onClick={() => {
textInput.setInput(q.content);
setFollowupsHidden(true);
@@ -495,7 +495,7 @@ export function InputBox({
)}
<PromptInput
className={cn(
"rounded-[1.85rem] border border-[#eadfce] bg-white shadow-[0_24px_70px_-34px_rgba(120,83,42,0.32)] ring-1 ring-[#f6efe5] transition-all duration-300 ease-out *:data-[slot='input-group']:rounded-[1.85rem]",
"rounded-[1.85rem] border border-[#eadfce] bg-white shadow-[0_24px_70px_-34px_rgba(120,83,42,0.32)] ring-1 ring-[#f6efe5] transition-all duration-300 ease-out *:data-[slot='input-group']:rounded-[1.85rem] dark:bg-slate-800 dark:border-slate-700 dark:ring-slate-700 dark:shadow-none",
className,
)}
disabled={disabled}
@@ -510,7 +510,7 @@ export function InputBox({
<PromptInputBody className="absolute top-0 right-0 left-0 z-3">
<PromptInputTextarea
className={cn(
"size-full px-2 py-1 text-[15px] leading-7 placeholder:text-[#b7ab9a]",
"size-full px-2 py-1 text-[15px] leading-7 placeholder:text-[#b7ab9a] dark:placeholder:text-slate-500",
)}
disabled={disabled}
placeholder={t.inputBox.placeholder}
@@ -518,7 +518,7 @@ export function InputBox({
defaultValue={initialValue}
/>
</PromptInputBody>
<PromptInputFooter className="flex items-center border-t border-[#f4ede4] px-2 pt-2.5 pb-1.5">
<PromptInputFooter className="flex items-center border-t border-[#f4ede4] dark:border-slate-700 px-2 pt-2.5 pb-1.5">
<PromptInputTools className="gap-1.5">
{/* TODO: Add more connectors here
<PromptInputActionMenu>
@@ -529,7 +529,7 @@ export function InputBox({
/>
</PromptInputActionMenuContent>
</PromptInputActionMenu> */}
<AddAttachmentsButton className="rounded-full border border-[#eee3d5] bg-[#fffaf5] px-2.5! shadow-none hover:bg-white" />
<AddAttachmentsButton className="rounded-full border border-[#eee3d5] bg-[#fffaf5] px-2.5! shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700" />
<PromptInputActionMenu>
<ModeHoverGuide
mode={
@@ -541,7 +541,7 @@ export function InputBox({
: "flash"
}
>
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3! text-[#7e6a57] shadow-none hover:bg-white">
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3! text-[#7e6a57] shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700">
<div>
{context.mode === "flash" && <ZapIcon className="size-3" />}
{context.mode === "thinking" && (
@@ -703,7 +703,7 @@ export function InputBox({
</PromptInputActionMenu>
{supportReasoningEffort && context.mode !== "flash" && (
<PromptInputActionMenu>
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3! text-[#7e6a57] shadow-none hover:bg-white">
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3! text-[#7e6a57] shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700">
<div className="text-xs font-normal">
{t.inputBox.reasoningEffort}:
{context.reasoning_effort === "minimal" &&
@@ -824,7 +824,7 @@ export function InputBox({
onOpenChange={setModelDialogOpen}
>
<ModelSelectorTrigger asChild>
<PromptInputButton className="rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3 shadow-none hover:bg-white">
<PromptInputButton className="rounded-full border border-[#eee3d5] bg-[#fffaf5] px-3 shadow-none hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700">
<div className="flex min-w-0 flex-col items-start text-left">
<ModelSelectorName className="text-xs font-normal">
{selectedModel?.display_name}
@@ -858,7 +858,7 @@ export function InputBox({
</ModelSelectorContent>
</ModelSelector>
<PromptInputSubmit
className="rounded-full border-[#e7d9c7] bg-white shadow-[0_10px_24px_-18px_rgba(120,83,42,0.34)]"
className="rounded-full border-[#e7d9c7] bg-white shadow-[0_10px_24px_-18px_rgba(120,83,42,0.34)] dark:bg-blue-500 dark:border-blue-500 dark:text-white dark:hover:bg-blue-400 dark:shadow-none"
disabled={disabled}
variant="outline"
status={status}
@@ -866,7 +866,7 @@ export function InputBox({
</PromptInputTools>
</PromptInputFooter>
{!isNewThread && (
<div className="absolute right-0 -bottom-[17px] left-0 z-0 h-4 bg-[#fffdfa]"></div>
<div className="absolute right-0 -bottom-[17px] left-0 z-0 h-4 bg-[#fffdfa] dark:bg-background"></div>
)}
</PromptInput>
+4 -4
View File
@@ -39,16 +39,16 @@ const themes: Record<ThemeType, ThemeConfig> = {
textSecondary: 'slate-400',
primary: 'blue-500',
primaryHover: 'blue-400',
border: 'blue-800',
accent: 'cyan-400',
border: 'slate-700',
accent: 'blue-600',
success: 'emerald-500',
warning: 'amber-500',
error: 'rose-500',
card: 'slate-800',
cardHover: 'slate-700',
input: 'slate-800',
inputBorder: 'blue-800',
overlay: 'slate-900/50',
inputBorder: 'slate-600',
overlay: 'slate-900/80',
},
},
light: {
+8 -4
View File
@@ -4,6 +4,7 @@ import { Navigate, Route, Routes } from "react-router-dom";
import { PageSidebar } from "@/components/page-sidebar";
import WorkspaceRoutes from "./WorkspaceRoutes";
import Header from "@/strategy-components/Header";
// 设为 true 时隐藏侧边栏(开发中,暂未完成)
const SIDEBAR_ENABLED = false;
@@ -12,18 +13,20 @@ function PageLayout() {
const [collapsed, setCollapsed] = useState(false);
return (
<div className="min-h-screen bg-muted/20">
<div className="h-screen flex bg-muted/20">
{SIDEBAR_ENABLED && (
<PageSidebar
collapsed={collapsed}
onToggleCollapsed={() => setCollapsed((prev) => !prev)}
/>
)}
<main
className={`min-h-screen transition-[padding] duration-300 ${
!SIDEBAR_ENABLED ? "" : collapsed ? "pl-16" : "pl-16 md:pl-64"
<div
className={`flex flex-col flex-1 overflow-hidden transition-[padding] duration-300 ${
!SIDEBAR_ENABLED ? "" : collapsed ? "pl-16" : "pl-64"
}`}
>
<Header />
<main className="flex-1 overflow-hidden">
<Routes>
<Route index element={<Navigate to="workspace" replace />} />
<Route
@@ -38,6 +41,7 @@ function PageLayout() {
</Routes>
</main>
</div>
</div>
);
}
+1 -1
View File
@@ -37,7 +37,7 @@ function WorkspaceLayout({
return (
<SidebarProvider
className="h-screen w-full overflow-x-hidden [&_[data-slot=sidebar-container]]:left-[var(--page-sidebar-width)]"
className="h-full w-full overflow-x-hidden [&_[data-slot=sidebar-container]]:left-[var(--page-sidebar-width)]"
style={
{
"--page-sidebar-width": pageSidebarWidth,
@@ -0,0 +1,83 @@
import React from 'react';
import { Bell, Search, User, ChevronDown, Moon, Sun, Palette } from 'lucide-react';
import { useTheme } from '../contexts/ThemeContext';
const Header: React.FC = () => {
const { theme, toggleTheme } = useTheme();
const isDark = theme === 'dark';
return (
<header className={`h-16 flex items-center justify-between px-6 theme-transition ${
isDark
? 'bg-slate-900/50 backdrop-blur-xl border-b border-blue-800/30'
: 'bg-red-600 border-b border-red-700'
}`}>
{/* 左侧 - 搜索框 */}
<div className="flex items-center gap-4">
<div className="relative">
<Search className={`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 ${isDark ? 'text-slate-500' : 'text-red-200'}`} />
<input
type="text"
placeholder="搜索场景、智能体、任务..."
className={`w-80 pl-10 pr-4 py-2 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-white/20 transition-all duration-200 theme-transition ${
isDark
? 'bg-slate-800/50 border border-blue-800/30 text-white placeholder-slate-500'
: 'bg-red-700 border border-red-800 text-white placeholder-red-200'
}`}
/>
</div>
</div>
{/* 右侧 - 用户信息和通知 */}
<div className="flex items-center gap-4">
{/* 主题切换按钮 */}
<button
onClick={toggleTheme}
className={`p-2 rounded-lg transition-all duration-200 ${
isDark
? 'hover:bg-slate-800/50 text-slate-400 hover:text-white'
: 'hover:bg-red-500 text-white'
}`}
title={isDark ? '切换到红白主题' : '切换到深色主题'}
>
{isDark ? (
<Palette className="w-5 h-5" />
) : (
<Moon className="w-5 h-5" />
)}
</button>
{/* 通知 */}
<button className={`relative p-2 rounded-lg transition-colors ${
isDark ? 'hover:bg-slate-800/50' : 'hover:bg-red-500'
}`}>
<Bell className={`w-5 h-5 ${isDark ? 'text-slate-400' : 'text-white'}`} />
<span className={`absolute top-1 right-1 w-2 h-2 rounded-full ${isDark ? 'bg-cyan-500' : 'bg-white'}`} />
</button>
{/* 分隔线 */}
<div className={`w-px h-8 ${isDark ? 'bg-blue-800/30' : 'bg-red-500'}`} />
{/* 用户信息 */}
<button className={`flex items-center gap-3 px-3 py-1.5 rounded-lg transition-colors ${
isDark ? 'hover:bg-slate-800/50' : 'hover:bg-red-500'
}`}>
<div className={`w-8 h-8 rounded-full flex items-center justify-center ${
isDark
? 'bg-gradient-to-br from-blue-500 to-cyan-400'
: 'bg-white'
}`}>
<User className={`w-4 h-4 ${isDark ? 'text-white' : 'text-red-600'}`} />
</div>
<div className="text-left">
<p className={`text-sm font-medium ${isDark ? 'text-white' : 'text-white'}`}>张策略</p>
<p className={`text-xs ${isDark ? 'text-blue-400/60' : 'text-red-200'}`}>策略分析师</p>
</div>
<ChevronDown className={`w-4 h-4 ${isDark ? 'text-slate-500' : 'text-white'}`} />
</button>
</div>
</header>
);
};
export default Header;
+35 -27
View File
@@ -243,7 +243,7 @@
--workspace-brand: #d92121;
--workspace-brand-foreground: #ffffff;
--radius: 0.75rem;
--background: oklch(0.985 0.004 95);
--background: oklch(1 0 0);
--foreground: oklch(0.22 0.02 25);
--card: oklch(1 0.002 95);
--card-foreground: oklch(0.22 0.02 25);
@@ -277,39 +277,39 @@
}
.dark {
--workspace-brand: #e11d1d;
--workspace-brand: #3b82f6;
--workspace-brand-foreground: #ffffff;
--background: oklch(0.22 0.015 25);
--foreground: oklch(0.96 0.01 95);
--card: oklch(0.26 0.018 25);
--card-foreground: oklch(0.96 0.01 95);
--popover: oklch(0.24 0.018 25);
--popover-foreground: oklch(0.96 0.01 95);
--primary: oklch(0.62 0.17 27);
--primary-foreground: oklch(0.12 0.02 25);
--secondary: oklch(0.32 0.02 25);
--secondary-foreground: oklch(0.96 0.01 95);
--muted: oklch(0.3 0.02 25);
--muted-foreground: oklch(0.72 0.02 95);
--accent: oklch(0.34 0.06 25);
--accent-foreground: oklch(0.96 0.01 95);
--background: oklch(0.208 0.042 264);
--foreground: oklch(0.96 0.005 240);
--card: oklch(0.265 0.04 260);
--card-foreground: oklch(0.96 0.005 240);
--popover: oklch(0.245 0.04 262);
--popover-foreground: oklch(0.96 0.005 240);
--primary: oklch(0.623 0.214 259);
--primary-foreground: oklch(0.99 0 0);
--secondary: oklch(0.32 0.038 260);
--secondary-foreground: oklch(0.96 0.005 240);
--muted: oklch(0.30 0.035 260);
--muted-foreground: oklch(0.68 0.02 240);
--accent: oklch(0.35 0.06 260);
--accent-foreground: oklch(0.96 0.005 240);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 12%);
--input: oklch(1 0 0 / 14%);
--ring: oklch(0.62 0.17 27 / 0.45);
--ring: oklch(0.623 0.214 259 / 0.45);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.2 0.02 25);
--sidebar-foreground: oklch(0.94 0.01 95);
--sidebar-primary: oklch(0.62 0.17 27);
--sidebar: oklch(0.185 0.04 265);
--sidebar-foreground: oklch(0.94 0.005 240);
--sidebar-primary: oklch(0.623 0.214 259);
--sidebar-primary-foreground: oklch(0.99 0 0);
--sidebar-accent: oklch(0.3 0.05 25);
--sidebar-accent-foreground: oklch(0.96 0.01 95);
--sidebar-accent: oklch(0.30 0.055 260);
--sidebar-accent-foreground: oklch(0.96 0.005 240);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.62 0.17 27 / 0.45);
--sidebar-ring: oklch(0.623 0.214 259 / 0.45);
font-weight: 300;
}
@@ -430,19 +430,27 @@
}
.workspace-shell {
background:
radial-gradient(circle at top right, rgb(255 214 214 / 0.72), transparent 18%),
linear-gradient(180deg, #fbf7f4 0%, #f6efea 100%);
background: #ffffff;
}
.dark .workspace-shell {
background: var(--background);
}
.workspace-panel {
border: 1px solid #f0d7d0;
background: linear-gradient(180deg, rgb(255 253 251 / 0.98), rgb(255 247 244 / 0.98));
background: #ffffff;
box-shadow:
0 32px 72px -46px rgb(98 63 42 / 0.35),
0 12px 28px -22px rgb(170 91 75 / 0.24);
}
.dark .workspace-panel {
border: 1px solid oklch(1 0 0 / 10%);
background: var(--card);
box-shadow: none;
}
.workspace-user-bubble {
max-width: min(82%, 42rem);
border: 1px solid rgb(255 255 255 / 0.14);