样式修改

This commit is contained in:
董宏凯 committed 2026-05-20 17:13:59 +08:00
1 parent 03dff2ce77
commit 556d23ade5
5 files changed
+160 -56

No files matched your search

@@ -516,7 +516,12 @@ 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] dark:bg-slate-800 dark:border-slate-700 dark:ring-slate-700 dark:shadow-none",
"transition-all duration-300 ease-out *:data-[slot='input-group']:rounded-3xl",
// landing 态:透明,让外层 gemini-gradient-border 提供白卡 + 旋转描边
// 对话态:常规白卡 + 中性边框 + 轻阴影
isNewThread
? "rounded-3xl bg-transparent border-0 shadow-none ring-0"
: "rounded-3xl bg-background border border-border shadow-sm dark:bg-slate-800 dark:border-slate-700",
className,
)}
disabled={disabled}
@@ -531,7 +536,8 @@ 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] dark:placeholder:text-slate-500",
"size-full px-2 py-1 text-[15px] leading-7 placeholder:text-muted-foreground/60",
isNewThread && "min-h-[110px]!",
)}
disabled={disabled}
placeholder={t.inputBox.placeholder}
@@ -539,7 +545,7 @@ export function InputBox({
defaultValue={initialValue}
/>
</PromptInputBody>
<PromptInputFooter className="flex items-center border-t border-[#f4ede4] dark:border-slate-700 px-2 pt-2.5 pb-1.5">
<PromptInputFooter className="flex items-center border-t border-border/40 dark:border-slate-700 px-2 pt-2.5 pb-1.5">
<PromptInputTools className="gap-1.5">
{/* TODO: Add more connectors here
<PromptInputActionMenu>
@@ -550,7 +556,7 @@ export function InputBox({
/>
</PromptInputActionMenuContent>
</PromptInputActionMenu> */}
<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" />
<AddAttachmentsButton className="rounded-full border border-border bg-muted/50 px-2.5! shadow-none text-muted-foreground hover:bg-muted hover:text-foreground dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700" />
<Tooltip
content={
context.writing_mode
@@ -562,8 +568,8 @@ export function InputBox({
className={cn(
"gap-1.5! rounded-full border px-3! shadow-none",
context.writing_mode
? "border-[#d8b878] bg-[#fff3cf] text-[#6d5625] hover:bg-[#ffedbd]"
: "border-[#eee3d5] bg-[#fffaf5] text-[#7e6a57] hover:bg-white",
? "border-amber-300 bg-amber-50 text-amber-700 hover:bg-amber-100 dark:border-amber-700 dark:bg-amber-950/40 dark:text-amber-200"
: "border-border bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700",
)}
onClick={handleWritingModeToggle}
>
@@ -582,7 +588,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 dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700">
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-border bg-muted/50 px-3! text-muted-foreground shadow-none hover:bg-muted hover:text-foreground 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" && (
@@ -744,7 +750,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 dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700">
<PromptInputActionMenuTrigger className="gap-1.5! rounded-full border border-border bg-muted/50 px-3! text-muted-foreground shadow-none hover:bg-muted hover:text-foreground 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" &&
@@ -875,15 +881,15 @@ export function InputBox({
className={cn(
"rounded-full border px-3 shadow-none transition-colors",
promptPrefix.on
? "border-[#d6a868] bg-[#fff3df] text-[#7a5417] hover:bg-[#ffe8c4]"
: "border-[#eee3d5] bg-[#fffaf5] text-[#8a7558] hover:bg-white",
? "border-amber-300 bg-amber-50 text-amber-700 hover:bg-amber-100 dark:border-amber-700 dark:bg-amber-950/40 dark:text-amber-200"
: "border-border bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground",
)}
>
<span className="max-w-[160px] truncate text-xs font-normal">
{promptPrefix.label}
</span>
{promptPrefix.on && (
<CheckIcon className="ml-1 size-3.5 text-[#7a5417]" />
<CheckIcon className="ml-1 size-3.5 text-amber-700 dark:text-amber-200" />
)}
</PromptInputButton>
</Tooltip>
@@ -893,7 +899,7 @@ export function InputBox({
onOpenChange={setModelDialogOpen}
>
<ModelSelectorTrigger asChild>
<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">
<PromptInputButton className="rounded-full border border-border bg-muted/50 px-3 shadow-none text-muted-foreground hover:bg-muted hover:text-foreground 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}
@@ -927,7 +933,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)] dark:bg-blue-500 dark:border-blue-500 dark:text-white dark:hover:bg-blue-400 dark:shadow-none"
className="rounded-full border-border bg-background shadow-sm hover:bg-muted 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}
@@ -935,7 +941,7 @@ export function InputBox({
</PromptInputTools>
</PromptInputFooter>
{!isNewThread && (
<div className="absolute right-0 -bottom-[17px] left-0 z-0 h-4 bg-[#fffdfa] dark:bg-background"></div>
<div className="absolute right-0 -bottom-[17px] left-0 z-0 h-4 bg-background"></div>
)}
</PromptInput>
@@ -158,15 +158,15 @@ export function RecentChatList() {
}
return (
<>
<SidebarGroup className="px-2">
<SidebarGroupLabel className="text-muted-foreground/90 px-2 text-[11px] font-semibold tracking-wide uppercase">
<SidebarGroup className="px-2 pt-3 mt-2 border-t border-sidebar-border/60">
<SidebarGroupLabel className="text-muted-foreground/70 px-3 mb-1 text-[10px] font-semibold tracking-[0.12em] uppercase">
{env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true"
? t.sidebar.recentChats
: t.sidebar.demoChats}
</SidebarGroupLabel>
<SidebarGroupContent className="group-data-[collapsible=icon]:pointer-events-none group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0">
<SidebarMenu>
<div className="flex w-full flex-col gap-1">
<div className="flex w-full flex-col gap-0.5">
{visibleThreads.map((thread) => {
const isActive = pathOfThread(thread) === pathname;
return (
@@ -174,9 +174,17 @@ export function RecentChatList() {
key={thread.thread_id}
className="group/side-menu-item"
>
<SidebarMenuButton isActive={isActive} asChild>
<SidebarMenuButton
isActive={isActive}
asChild
className={
"rounded-lg h-7 px-3 text-[13px] text-muted-foreground hover:text-foreground hover:bg-sidebar-accent/60 " +
"data-[active=true]:bg-white data-[active=true]:text-foreground data-[active=true]:shadow-[0_1px_2px_rgba(15,23,42,0.05)] " +
"dark:data-[active=true]:bg-slate-700/80 dark:data-[active=true]:text-slate-100 dark:data-[active=true]:shadow-none"
}
>
<Link
className="text-muted-foreground block w-full whitespace-nowrap group-hover/side-menu-item:overflow-hidden"
className="block w-full whitespace-nowrap group-hover/side-menu-item:overflow-hidden"
href={pathOfThread(thread)}
>
{titleOfThread(thread)}
@@ -15,26 +15,43 @@ import { useI18n } from "@/core/i18n/hooks";
// import { BotIcon, BrainIcon, ListChecks, MessageSquarePlus, MessagesSquare, SparklesIcon, UsersIcon } from "lucide-react";
import { BotIcon, BrainIcon, CalendarClock, ListChecks, MessageSquarePlus, MessagesSquare, SparklesIcon, UsersIcon } from "lucide-react";
// 普通导航项:放大圆角到 xl、增加内边距,激活态用白底+柔阴影(参考 Gemini 风格的胶囊)
const NAV_ITEM_CLASS =
"text-sidebar-foreground/80 hover:text-sidebar-foreground rounded-xl h-9 px-3 transition-colors " +
"data-[active=true]:bg-white data-[active=true]:text-foreground data-[active=true]:shadow-[0_1px_2px_rgba(15,23,42,0.06),0_1px_3px_rgba(15,23,42,0.04)] " +
"dark:data-[active=true]:bg-slate-700/80 dark:data-[active=true]:text-slate-100 dark:data-[active=true]:shadow-none";
// 「新对话」专属:始终主色 chip,让它在导航里更显眼
const NEW_CHAT_CLASS =
"rounded-xl h-9 px-3 bg-primary/10 text-primary hover:bg-primary/15 hover:text-primary " +
"data-[active=true]:bg-primary/15 data-[active=true]:text-primary data-[active=true]:shadow-none " +
"dark:bg-primary/15 dark:text-primary-foreground dark:hover:bg-primary/25 dark:data-[active=true]:bg-primary/25";
export function WorkspaceNavChatList() {
const { t } = useI18n();
const pathname = usePathname();
return (
<SidebarGroup className="px-2 pt-2">
<SidebarMenu>
<SidebarMenu className="gap-1">
<SidebarMenuItem>
<SidebarMenuButton
isActive={pathname === "/page/workspace/chats/new"}
asChild
className={NEW_CHAT_CLASS}
>
<Link className="text-sidebar-foreground" href="/page/workspace/chats/new">
<Link href="/page/workspace/chats/new">
<MessageSquarePlus />
<span>{t.sidebar.newChat}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton isActive={pathname === "/page/workspace/chats"} asChild>
<Link className="text-sidebar-foreground" href="/page/workspace/chats">
<SidebarMenuButton
isActive={pathname === "/page/workspace/chats"}
asChild
className={NAV_ITEM_CLASS}
>
<Link href="/page/workspace/chats">
<MessagesSquare />
<span>{t.sidebar.chats}</span>
</Link>
@@ -44,8 +61,9 @@ export function WorkspaceNavChatList() {
<SidebarMenuButton
isActive={pathname.startsWith("/page/workspace/agents")}
asChild
className={NAV_ITEM_CLASS}
>
<Link className="text-sidebar-foreground" href="/page/workspace/agents">
<Link href="/page/workspace/agents">
<BotIcon />
<span>{t.sidebar.agents}</span>
</Link>
@@ -55,8 +73,9 @@ export function WorkspaceNavChatList() {
<SidebarMenuButton
isActive={pathname.startsWith("/page/workspace/skills")}
asChild
className={NAV_ITEM_CLASS}
>
<Link className="text-sidebar-foreground" href="/page/workspace/skills">
<Link href="/page/workspace/skills">
<SparklesIcon />
<span>技能</span>
</Link>
@@ -66,8 +85,9 @@ export function WorkspaceNavChatList() {
<SidebarMenuButton
isActive={pathname.startsWith("/page/workspace/memory")}
asChild
className={NAV_ITEM_CLASS}
>
<Link className="text-sidebar-foreground" href="/page/workspace/memory">
<Link href="/page/workspace/memory">
<BrainIcon />
<span>记忆</span>
</Link>
@@ -77,8 +97,9 @@ export function WorkspaceNavChatList() {
<SidebarMenuButton
isActive={pathname === "/page/workspace/scheduled/tasks"}
asChild
className={NAV_ITEM_CLASS}
>
<Link className="text-sidebar-foreground" href="/page/workspace/scheduled/tasks">
<Link href="/page/workspace/scheduled/tasks">
<ListChecks />
<span>任务管理</span>
</Link>
+39 -29
View File
@@ -229,40 +229,50 @@ export default function ChatPage() {
/>
</div>
</div>
{mounted ? (
<InputBox
className={cn("bg-background/5 w-full -translate-y-4")}
isNewThread={isLandingState}
threadId={threadId}
autoFocus={isLandingState}
status={
thread.error
? "error"
: thread.isLoading
? "streaming"
: "ready"
}
context={settings.context}
extraHeader={
isLandingState && <Welcome mode={settings.context.mode} />
}
disabled={
env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true" ||
isUploading
}
onContextChange={(context) =>
setSettings("context", context)
}
promptPrefix={promptPrefixProp}
onFollowupsVisibilityChange={setShowFollowups}
onSubmit={handleSubmit}
onStop={handleStop}
{isLandingState && mounted && (
<Welcome
mode={settings.context.mode}
className="mb-6 -translate-y-4"
/>
)}
{mounted ? (
<div
className={cn(
"w-full -translate-y-4",
isLandingState && "gemini-gradient-border gemini-shadow",
)}
>
<InputBox
className="w-full"
isNewThread={isLandingState}
threadId={threadId}
autoFocus={isLandingState}
status={
thread.error
? "error"
: thread.isLoading
? "streaming"
: "ready"
}
context={settings.context}
disabled={
env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true" ||
isUploading
}
onContextChange={(context) =>
setSettings("context", context)
}
promptPrefix={promptPrefixProp}
onFollowupsVisibilityChange={setShowFollowups}
onSubmit={handleSubmit}
onStop={handleStop}
/>
</div>
) : (
<div
aria-hidden="true"
className={cn(
"bg-background/5 h-32 w-full -translate-y-4 rounded-2xl border",
"bg-background/5 h-32 w-full -translate-y-4 rounded-3xl border",
)}
/>
)}
+59
View File
@@ -752,3 +752,62 @@
--container-width-md: calc(var(--spacing) * 204);
--container-width-lg: calc(var(--spacing) * 256);
}
/* ── Landing 态输入框 Gemini 风格:旋转彩色描边 + 多色柔光阴影 ───────── */
/* 关键:::before 转动的彩色锥形渐变 + ::after 内嵌白板遮罩中央,只在 1.5px 边缘可见模糊彩光 */
.gemini-shadow {
box-shadow:
0 0 20px rgba(66, 133, 244, 0.10),
0 0 40px rgba(219, 68, 55, 0.05),
0 0 60px rgba(244, 180, 0, 0.05),
0 0 80px rgba(15, 157, 88, 0.05);
}
.dark .gemini-shadow {
box-shadow:
0 0 24px rgba(66, 133, 244, 0.20),
0 0 48px rgba(219, 68, 55, 0.10),
0 0 72px rgba(244, 180, 0, 0.10),
0 0 96px rgba(15, 157, 88, 0.10);
}
.gemini-gradient-border {
position: relative;
background: var(--background);
border-radius: 1.5rem;
z-index: 0;
overflow: hidden;
}
.gemini-gradient-border::before {
content: '';
position: absolute;
width: 200%;
height: 200%;
top: -50%;
left: -50%;
background: conic-gradient(
from 0deg,
#4285F4 0deg,
#DB4437 90deg,
#F4B400 180deg,
#0F9D58 270deg,
#4285F4 360deg
);
z-index: -2;
animation: gemini-rotate 4s linear infinite;
filter: blur(10px);
pointer-events: none;
}
.gemini-gradient-border::after {
content: '';
position: absolute;
inset: 2.5px;
background: var(--background);
border-radius: calc(1.5rem - 2px);
z-index: -1;
}
@keyframes gemini-rotate {
to {
transform: rotate(360deg);
}
}