feat(ui): UI 样式调整

- sonner.tsx: 修改 toast 为灰色圆角样式,禁用图标
- globals.css: 添加 toast 居中样式
- layout.tsx: 使用本地 Toaster 组件
- dev-dialog.tsx: 添加 singleColumn 属性支持单列布局
- prompt-input.tsx: 提交按钮添加 tooltip 提示
- suggestion.tsx: 修改建议按钮样式为 ghost + 浅灰背景
- input-box.tsx: 调整输入框高度200px样式
- zh-CN.ts: 更新建议列表文案和 skill_id
This commit is contained in:
肖应宇 2026-03-18 11:32:21 +08:00
parent 7342cc08d3
commit 83511dee5f
8 changed files with 76 additions and 41 deletions

View File

@ -2,9 +2,9 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useCallback, useEffect, useLayoutEffect, useState } from "react"; import { useCallback, useEffect, useLayoutEffect, useState } from "react";
import { Toaster } from "sonner";
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"; import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
import { Toaster } from "@/components/ui/sonner";
import { WorkspaceSidebar } from "@/components/workspace/workspace-sidebar"; import { WorkspaceSidebar } from "@/components/workspace/workspace-sidebar";
import { getLocalSettings, useLocalSettings } from "@/core/settings"; import { getLocalSettings, useLocalSettings } from "@/core/settings";
@ -40,7 +40,7 @@ export default function WorkspaceLayout({
{/* <WorkspaceSidebar className="" /> */} {/* <WorkspaceSidebar className="" /> */}
<SidebarInset className="min-w-0">{children}</SidebarInset> <SidebarInset className="min-w-0">{children}</SidebarInset>
</SidebarProvider> </SidebarProvider>
<Toaster position="top-center" /> <Toaster />
</QueryClientProvider> </QueryClientProvider>
); );
} }

View File

@ -1,6 +1,7 @@
"use client"; "use client";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Tooltip } from "@/components/workspace/tooltip";
import { import {
Command, Command,
CommandEmpty, CommandEmpty,
@ -1097,6 +1098,7 @@ export const PromptInputSubmit = ({
} }
return ( return (
<Tooltip content="请注意此功能将消耗token请保证账户余额大于200可学豆。">
<InputGroupButton <InputGroupButton
aria-label="Submit" aria-label="Submit"
// 被button{bgc:#fff}覆盖了,只能加"!" // 被button{bgc:#fff}覆盖了,只能加"!"
@ -1116,6 +1118,7 @@ export const PromptInputSubmit = ({
{/* {children ?? Icon} */} {/* {children ?? Icon} */}
{text} {text}
</InputGroupButton> </InputGroupButton>
</Tooltip>
); );
}; };

View File

@ -49,7 +49,7 @@ export const Suggestion = ({
onClick, onClick,
className, className,
icon: Icon, icon: Icon,
variant = "outline", variant = "ghost",
size = "sm", size = "sm",
children, children,
...props ...props
@ -61,7 +61,7 @@ export const Suggestion = ({
return ( return (
<Button <Button
className={cn( className={cn(
"text-muted-foreground cursor-pointer rounded-full px-[20px] py-[15px] text-xs font-normal", "text-muted-foreground cursor-pointer bg-[#F9F8FA] rounded-full px-[20px] py-[15px] text-xs font-normal",
className, className,
)} )}
onClick={handleClick} onClick={handleClick}

View File

@ -90,13 +90,17 @@ function DevDialogHeader({ className, ...props }: React.ComponentProps<"div">) {
); );
} }
function DevDialogFooter({ className, ...props }: React.ComponentProps<"div">) { function DevDialogFooter({
className,
singleColumn = false,
...props
}: React.ComponentProps<"div"> & { singleColumn?: boolean }) {
return ( return (
<div <div
data-slot="dev-dialog-footer" data-slot="dev-dialog-footer"
className={cn( className={cn(
// sm:justify-end "grid w-full justify-between gap-[30px] sm:flex-row",
"grid w-full grid-cols-2 justify-between gap-[30px] sm:flex-row", singleColumn ? "grid-cols-1" : "grid-cols-2",
className, className,
)} )}
{...props} {...props}

View File

@ -1,35 +1,42 @@
"use client"; "use client";
import {
CircleCheckIcon,
InfoIcon,
Loader2Icon,
OctagonXIcon,
TriangleAlertIcon,
} from "lucide-react";
import { useTheme } from "next-themes";
import { Toaster as Sonner, type ToasterProps } from "sonner"; import { Toaster as Sonner, type ToasterProps } from "sonner";
const Toaster = ({ ...props }: ToasterProps) => { const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme();
return ( return (
<Sonner <Sonner
theme={theme as ToasterProps["theme"]} theme="dark"
className="toaster group" className="toaster group "
position="top-center"
icons={{ icons={{
success: <CircleCheckIcon className="size-4" />, success: null,
info: <InfoIcon className="size-4" />, info: null,
warning: <TriangleAlertIcon className="size-4" />, warning: null,
error: <OctagonXIcon className="size-4" />, error: null,
loading: <Loader2Icon className="size-4 animate-spin" />, loading: null,
}}
toastOptions={{
style: {
background: "#4a4a4a",
color: "#ffffff",
border: "none",
borderRadius: "12px",
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
fontSize: "14px",
fontWeight: 400,
padding: "12px 20px",
textAlign: "center",
maxWidth: "320px",
minWidth:"300px",
justifyContent:"center"
},
}} }}
style={ style={
{ {
"--normal-bg": "var(--popover)", "--normal-bg": "#4a4a4a",
"--normal-text": "var(--popover-foreground)", "--normal-text": "#ffffff",
"--normal-border": "var(--border)", "--normal-border": "transparent",
"--border-radius": "var(--radius)", "--border-radius": "12px",
} as React.CSSProperties } as React.CSSProperties
} }
{...props} {...props}

View File

@ -430,10 +430,10 @@ export function InputBox({
<PromptInput <PromptInput
className={cn("w-full", className)} className={cn("w-full", className)}
inputGroupClassName={cn( inputGroupClassName={cn(
"border-0 backdrop-blur-sm w-[720px] rounded-[20px]", "border-0 backdrop-blur-sm w-[720px] rounded-[20px]",
"transition-[height] duration-300 ease-out", "transition-[height] duration-300 ease-out",
!isNewThread && "shadow-[0_0_20px_2px_rgba(0,0,0,0.10)]", !isNewThread && "shadow-[0_0_20px_2px_rgba(0,0,0,0.10)]",
effectiveIsFocused ? "h-[200px]" : "h-[80px]", effectiveIsFocused ? "!h-[200px]" : "h-[80px]",
)} )}
disabled={disabled} disabled={disabled}
globalDrop globalDrop
@ -963,7 +963,7 @@ function SuggestionList({
onClick={() => handleSuggestionClick(suggestion)} onClick={() => handleSuggestionClick(suggestion)}
/> />
))} ))}
<DropdownMenu> {/* <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<Suggestion icon={PlusIcon} suggestion={t.common.create} /> <Suggestion icon={PlusIcon} suggestion={t.common.create} />
</DropdownMenuTrigger> </DropdownMenuTrigger>
@ -986,7 +986,7 @@ function SuggestionList({
)} )}
</DropdownMenuGroup> </DropdownMenuGroup>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu> */}
</Suggestions> </Suggestions>
); );
} }

View File

@ -102,36 +102,42 @@ export const zhCN: Translations = {
followupConfirmReplace: "替换并发送", followupConfirmReplace: "替换并发送",
suggestions: [ suggestions: [
{ {
suggestion: "论文写作", suggestion: "自媒体文案",
prompt: prompt:
"撰写一篇关于[主题]的学术论文,包含摘要、引言、正文和参考文献。", "撰写一篇关于[主题]的学术论文,包含摘要、引言、正文和参考文献。",
icon: PenLineIcon, icon: PenLineIcon,
skill_id: "1", skill_id: "432",
}, },
{ {
suggestion: "报告生成", suggestion: "需求文档",
prompt: "深入分析[主题],生成一份结构清晰的调研报告。", prompt: "深入分析[主题],生成一份结构清晰的调研报告。",
icon: MicroscopeIcon, icon: MicroscopeIcon,
skill_id: "2", skill_id: "521",
}, },
{ {
suggestion: "策划文案", suggestion: "使用指南",
prompt: "为[项目/活动]撰写一份完整的策划方案和宣传文案。", prompt: "为[项目/活动]撰写一份完整的策划方案和宣传文案。",
icon: ShapesIcon, icon: ShapesIcon,
skill_id: "3", skill_id: "410",
}, },
{ {
suggestion: "PPT生成", suggestion: "PPT生成",
prompt: "生成一个关于[主题]的PPT演示文稿大纲和内容。", prompt: "生成一个关于[主题]的PPT演示文稿大纲和内容。",
icon: GraduationCapIcon, icon: GraduationCapIcon,
skill_id: "4", skill_id: "180",
}, },
{ {
suggestion: "文档处理", suggestion: "Excel数据分析",
prompt: "对[文档]进行阅读、总结、翻译或格式转换等处理。", prompt: "对[文档]进行阅读、总结、翻译或格式转换等处理。",
icon: CompassIcon, icon: CompassIcon,
skill_id: "5", skill_id: "5",
}, },
{
suggestion: "市场调研",
prompt: "对[文档]进行阅读、总结、翻译或格式转换等处理。",
icon: CompassIcon,
skill_id: "31",
},
], ],
suggestionsCreate: [ suggestionsCreate: [
{ {

View File

@ -244,7 +244,7 @@
--muted: #1500331a; --muted: #1500331a;
--muted-foreground: oklch(0.556 0 0); --muted-foreground: oklch(0.556 0 0);
/* --accent: oklch(0.94 0.0098 87.47); */ /* --accent: oklch(0.94 0.0098 87.47); */
--accent: #1500331a; --accent: #EAE9EB;
--accent-foreground: oklch(0.205 0 0); --accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325); --destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0.0098 87.47); --border: oklch(0.922 0.0098 87.47);
@ -453,3 +453,18 @@ p {
.cm-line { .cm-line {
font-size: calc(14px * var(--zoom-scale)); font-size: calc(14px * var(--zoom-scale));
} }
/* Sonner Toast 居中样式 */
[data-sonner-toaster] {
left: 50% !important;
transform: translateX(-50%);
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center;
}
[data-sonner-toast] {
margin: 0 auto;
}