This commit is contained in:
熊潇 2025-05-28 19:39:50 +08:00
parent 22cb48b9f3
commit 26be3b85e8
24 changed files with 356 additions and 301 deletions

View File

@ -1,3 +1,6 @@
{
"workbench.editorAssociations": {
// "*.md": "vscode.markdown.preview.editor" //
"*.md": "default" //
}
}

View File

@ -1,4 +1,4 @@
import { DragModal, DragModalTitle, getComputedHeight } from '@/components/a/drag-modal/index.tsx';
import { DragModal, DragModalTitle, getComputedHeight, useDragSize } from '@/components/a/drag-modal/index.tsx';
import { useChatStore } from '../store';
import { useShallow } from 'zustand/shallow';
import { Button } from '@/components/a/button.tsx';
@ -68,6 +68,7 @@ export const ChatContextDialog = () => {
setShowContext(false);
};
const [role, setRole] = useState<string>('user');
const dragSize = useDragSize();
return (
<DragModal
focus={modelId === 'chat-context'}
@ -111,14 +112,8 @@ export const ChatContextDialog = () => {
</div>
</div>
}
defaultSize={{
width: 600,
height: 400,
}}
style={{
left: computedHeight.width / 2 - 300,
top: computedHeight.height / 2 - 200,
}}
defaultSize={dragSize.defaultSize}
style={dragSize.style}
/>
);
};

View File

@ -1,4 +1,4 @@
import { DragModal, DragModalTitle, getComputedHeight } from '@/components/a/drag-modal/index.tsx';
import { DragModal, DragModalTitle, getComputedHeight, useDragSize } from '@/components/a/drag-modal/index.tsx';
import { useChatStore } from '../store';
import { useShallow } from 'zustand/shallow';
import { ChatCopyList } from './List';
@ -16,6 +16,7 @@ export const ChatCopyDialog = () => {
if (!store.showCopy) {
return null;
}
const dragSize = useDragSize();
return (
<DragModal
focus={store.modelId === 'chat-copy'}
@ -33,14 +34,8 @@ export const ChatCopyDialog = () => {
<ChatCopyList />
</div>
}
defaultSize={{
width: 600,
height: 400,
}}
style={{
left: computedHeight.width / 2 - 300,
top: computedHeight.height / 2 - 200,
}}
defaultSize={dragSize.defaultSize}
style={dragSize.style}
/>
);
};

View File

@ -1,16 +1,17 @@
import { DragModal, DragModalTitle, getComputedHeight } from '@/components/a/drag-modal/index.tsx';
import { DragModal, DragModalTitle, getComputedHeight, useDragSize } from '@/components/a/drag-modal/index.tsx';
import { useChatStore } from '../store';
import { useShallow } from 'zustand/shallow';
import { ChatHistoryList } from './List';
export const ChatHistoryDialog = ({ storeId }: { storeId: string }) => {
const { showList, setShowList, setModelId, modelId } = useChatStore(
useShallow((state) => ({ showList: state.showList, setShowList: state.setShowList, setModelId: state.setModelId, modelId: state.modelId })),
useShallow((state) => ({ showList: state.showList, setShowList: state.setShowList, setModelId: state.setModelId, modelId: state.modelId })),
);
const computedHeight = getComputedHeight();
if (!showList) {
return null;
}
const dragSize = useDragSize();
return (
<DragModal
focus={modelId === 'chat-history'}
@ -28,14 +29,7 @@ export const ChatHistoryDialog = ({ storeId }: { storeId: string }) => {
<ChatHistoryList storeId={storeId} />
</div>
}
defaultSize={{
width: 600,
height: 400,
}}
style={{
left: computedHeight.width / 2 - 300,
top: computedHeight.height / 2 - 200,
}}
{...dragSize}
/>
);
};

View File

@ -1,4 +1,4 @@
import { DragModal, DragModalTitle, getComputedHeight } from '@/components/a/drag-modal/index.tsx';
import { DragModal, DragModalTitle, getComputedHeight, useDragSize } from '@/components/a/drag-modal/index.tsx';
import { useChatStore } from '../store';
import { useShallow } from 'zustand/shallow';
import { ChatSettingList } from './List';
@ -16,6 +16,7 @@ export const ChatModelSettingDialog = () => {
if (!showChatSetting) {
return null;
}
const dragSize = useDragSize();
return (
<DragModal
focus={modelId === 'chat-model-setting'}
@ -33,14 +34,7 @@ export const ChatModelSettingDialog = () => {
<ChatSettingList />
</div>
}
defaultSize={{
width: 600,
height: 400,
}}
style={{
left: computedHeight.width / 2 - 300,
top: computedHeight.height / 2 - 200,
}}
{...dragSize}
/>
);
};

View File

@ -1,4 +1,4 @@
import { DragModal, DragModalTitle, getComputedHeight } from '@/components/a/drag-modal/index.tsx';
import { DragModal, DragModalTitle, getComputedHeight, useDragSize } from '@/components/a/drag-modal/index.tsx';
import { useChatStore } from '../store';
import { useShallow } from 'zustand/shallow';
import { ChatSettingList } from './List';
@ -16,6 +16,7 @@ export const ChatSettingDialog = () => {
if (!showSetting) {
return null;
}
const dragSize = useDragSize();
return (
<DragModal
focus={modelId === 'chat-setting'}
@ -33,14 +34,7 @@ export const ChatSettingDialog = () => {
<ChatSettingList />
</div>
}
defaultSize={{
width: 600,
height: 400,
}}
style={{
left: computedHeight.width / 2 - 300,
top: computedHeight.height / 2 - 200,
}}
{...dragSize}
/>
);
};

View File

@ -75,7 +75,7 @@ export const Chat = ({ storeId }: { storeId: string }) => {
}, []);
return (
<div className='w-full h-full relative'>
<div className='w-full h-full relative flex flex-col lg:flex-row'>
{!id && (
<div className='w-full h-full flex flex-col justify-center items-center'>
<ChatHistoryList storeId={storeId} />

View File

@ -41,7 +41,7 @@ export const ModelNav = () => {
return (
<div className='flex gap-2 items-center'>
<div className='hidden lg:block font-bold text-gray-600'></div>
<div className='flex gap-2 items-center' onClick={() => setShowChatSetting(true)}>
{/* <div className='flex gap-2 items-center' onClick={() => setShowChatSetting(true)}>
{currentUserModel && (
<Tooltip
title={
@ -58,7 +58,7 @@ export const ModelNav = () => {
</Tooltip>
)}
{!currentUserModel && <div className='text-sm text-gray-500 cursor-pointer'>Not Selected Model</div>}
</div>
</div> */}
<div className='flex gap-2 items-center'>
{/* <Tooltip title=''>
<IconButton

View File

@ -0,0 +1,18 @@
import { ToastProvider } from '@/modules/toast/Provider';
export const App = () => {
return (
<ToastProvider>
<AIEditor />
</ToastProvider>
);
};
export const AIEditor = () => {
return (
<div className='flex h-full w-full flex-col items-center justify-center'>
<div className='text-2xl font-bold'>AI Editor</div>
<div className='mt-4 text-gray-500'>This is a placeholder for the AI Editor application.</div>
</div>
);
};

View File

@ -5,14 +5,35 @@ import { Tooltip } from '@/components/a/tooltip';
export const queryMark = new QueryMark({ query: query, markType: 'md' });
import Fuse from 'fuse.js';
import { debounce } from 'lodash-es';
import { SquareArrowOutUpRight } from 'lucide-react';
import { Plus, SquareArrowOutUpRight } from 'lucide-react';
import { Pencil, Trash2 } from 'lucide-react';
import { Button } from '@/components/a/button';
import { Confirm } from '@/components/a/confirm';
import { toast } from 'react-toastify';
import { ToastProvider } from '@/modules/toast/Provider';
import { Modal } from '@/components/a/modal';
import { useForm, Controller } from 'react-hook-form'; // 添加此行
export const App = () => {
return (
<ToastProvider>
<AiMark />
</ToastProvider>
);
};
const AiMark = () => {
const [list, setList] = useState<Mark[]>([]);
const [searchTerm, setSearchTerm] = useState('');
const [searchResults, setSearchResults] = useState<Mark[]>([]);
const fuseRef = useRef<Fuse<Mark>>(null);
const [open, setOpen] = useState(false);
const [formData, setFormData] = useState<Mark>();
const onOpenEdit = (data: Mark) => {
setOpen(true);
setFormData(data);
};
// 实际执行搜索的函数
const performSearch = (term: string) => {
if (!term.trim()) {
@ -47,6 +68,7 @@ export const App = () => {
if (res.code === 200) {
const list = res.data?.list || [];
setList(list!);
const fuse = new Fuse(list, {
keys: ['title', 'description', 'tags', 'summary'],
});
@ -65,13 +87,23 @@ export const App = () => {
const link = item.link;
window.open(link);
};
const refresh = () => {
init();
};
// 确定要显示的列表:有搜索内容时显示搜索结果,否则显示全部
const displayList = searchTerm.trim() ? searchResults : list;
return (
<div className='w-full h-full overflow-auto'>
<div className='sticky top-0 p-4 bg-white z-10 shadow-sm'>
<div className='w-full h-full overflow-auto scrollbar'>
<div className='sticky top-0 p-4 bg-white z-10 shadow-sm flex gap-2'>
<Button
size='icon'
onClick={() => {
setFormData(undefined);
setOpen(true);
}}>
<Plus />
</Button>
<input
type='text'
value={searchTerm}
@ -102,11 +134,141 @@ export const App = () => {
</span>
))}
</div>
<Action data={item} onEdit={onOpenEdit} refresh={refresh} />
</div>
);
})
)}
</div>
<Modal open={open} setOpen={setOpen}>
<MarkForm
data={formData}
onCancel={() => setOpen(false)}
onSuccess={() => {
setOpen(false);
init();
}}
/>
</Modal>
</div>
);
};
export const MarkForm = (props?: { data?: Mark; onSuccess?: () => void; onCancel?: () => void }) => {
const {
register,
handleSubmit,
control,
formState: { errors },
} = useForm<Mark>({
defaultValues: props?.data || {
title: '',
summary: '',
link: '',
tags: [],
},
});
const onSubmit = async (data: Mark) => {
try {
const res = await queryMark.updateMark(data);
if (res.code === 200) {
toast.success(data.id ? '更新成功' : '创建成功');
props?.onSuccess?.();
} else {
toast.error(res?.message || '操作失败');
}
} catch (error) {
toast.error('操作失败');
}
};
return (
<form onSubmit={handleSubmit(onSubmit)} className='space-y-4 p-2'>
{props?.data?.id && <input type='hidden' {...register('id')} />}
<div>
<label className='block text-sm font-medium mb-1'></label>
<input
type='text'
{...register('title', { required: '标题是必填项' })}
className='w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-300'
/>
{errors.title && <p className='text-red-500 text-xs mt-1'>{errors.title.message}</p>}
</div>
<div>
<label className='block text-sm font-medium mb-1'></label>
<input
type='text'
{...register('link', { required: '链接是必填项' })}
className='w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-300'
/>
{errors.link && <p className='text-red-500 text-xs mt-1'>{errors.link.message}</p>}
</div>
<div>
<label className='block text-sm font-medium mb-1'></label>
<textarea {...register('summary')} rows={3} className='w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-300' />
</div>
<div>
<label className='block text-sm font-medium mb-1'></label>
<Controller
name='tags'
control={control}
render={({ field }) => (
<input
type='text'
value={field.value?.join(', ') || ''}
onChange={(e) => {
const value = e.target.value;
field.onChange(
value
.split(',')
.map((tag) => tag.trim())
.filter((tag) => tag !== ''),
);
}}
className='w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-300'
placeholder='用逗号分隔多个标签'
/>
)}
/>
</div>
<div className='flex justify-end space-x-2 mt-4'>
<Button onClick={props?.onCancel} type='button'>
</Button>
<Button type='submit'></Button>
</div>
</form>
);
};
export const Action = (props: { data: Mark; onEdit?: (data: Mark) => any; refresh?: any }) => {
const onDelete = async () => {
const res = await queryMark.deleteMark(props.data.id);
if (res.code === 200) {
toast.success('删除成功');
props?.refresh?.();
} else {
toast.error(res?.message || '请求失败');
}
};
return (
<div className='flex gap-2 mt-2'>
<Button className='flex items-center gap-1 transition' onClick={() => props?.onEdit?.(props.data)} title='编辑'>
<Pencil className='w-4 h-4' />
</Button>
<Confirm onOk={onDelete}>
<Button className='flex items-center gap-1 text-red-600 transition' title='删除'>
<Trash2 className='w-4 h-4' />
</Button>
</Confirm>
</div>
);
};

View File

@ -0,0 +1,13 @@
type LayoutProps = {
children?: React.ReactNode;
className?: string;
style?: React.CSSProperties;
};
export const Layout = (props: LayoutProps) => {
const { children, className, style } = props;
return (
<div className={className} style={style}>
{children}
</div>
);
};

View File

@ -4,9 +4,10 @@ export interface Props {
}
---
<html lang='zh'>
<header>
<html lang='zh-CN'>
<head>
<meta charset='UTF-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
<title>Docs</title>
<link
rel='stylesheet'
@ -15,13 +16,23 @@ export interface Props {
crossorigin='anonymous'
referrerpolicy='no-referrer'
/>
</header>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<header>
<div>
<slot name='header'>
<h1>My Site Header</h1>
</slot>
</header>
</div>
<main class='markdown-body' style='padding: 1rem'>
<slot />
</main>

View File

@ -115,3 +115,18 @@ export const useComputedHeight = () => {
}, []);
return computedHeight;
};
export const useDragSize = (width = 600, heigth = 400) => {
const computedHeight = getComputedHeight();
const isMin = computedHeight.width < width;
return {
defaultSize: {
width: isMin ? computedHeight.width : 600,
height: 400,
},
style: {
left: isMin ? 0 : computedHeight.width / 2 - width / 2,
top: computedHeight.height / 2 - heigth / 2,
},
};
};

View File

@ -0,0 +1,24 @@
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '../ui/dialog';
import React, { Dispatch, SetStateAction } from 'react';
type ModalProps = {
open?: boolean;
setOpen?: (open: boolean) => any;
title?: string;
children?: React.ReactNode;
};
export const Modal = (props: ModalProps) => {
const { open = false, setOpen, title, children } = props;
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
</DialogHeader>
{children}
</DialogContent>
</Dialog>
);
};

View File

@ -5,6 +5,7 @@
<html lang='zh-CN'>
<head>
<meta charset='UTF-8' />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI Pages</title>
<style>
html,

View File

@ -12,4 +12,15 @@ const blog = defineCollection({
// updatedDate: z.coerce.date().optional(),
}),
});
export const collections = { blog };
const kevisual = defineCollection({
// loader: glob({ pattern: '**/*.md', base: './src/data/blogs' }),
loader: glob({ pattern: '**/[^_]*.md', base: './src/data/kevisual' }),
schema: z.object({
title: z.string().optional(),
description: z.string().optional(),
// pubDate: z.coerce.date(),
// updatedDate: z.coerce.date().optional(),
}),
});
export const collections = { blog, kevisual };

View File

@ -0,0 +1,12 @@
---
title: router
tags: ['kevisual', 'lib']
---
# @kevisual/router
在使用 node 开发的时候http 服务和 api 是首要关注的内容。但是真实的在开发的时候,发现一件事情,开发应该只关注于对应的内容的东西。
## 介绍

View File

@ -0,0 +1,27 @@
---
import '@/styles/global.css';
import '@/styles/theme.css';
import { getCollection, render } from 'astro:content';
import Main from '@/astro/layouts/mdx/main.astro';
// import Blank from '@/components/html/blank.astro';
// 1. 为每个集合条目生成一个新路径
export async function getStaticPaths() {
const posts = await getCollection('kevisual');
return posts.map((post) => ({
params: { id: post.id },
props: { post },
}));
}
type Post = {
data: { title: string };
};
// 2. 对于你的模板,你可以直接从 prop 获取条目
const { post } = Astro.props as { post: Post };
const { Content } = await render(post);
---
<Main>
<meta charset='UTF-8' slot='head' />
<div slot={'header'}>{post.data.title}</div>
<Content />
</Main>

View File

@ -0,0 +1,21 @@
---
import { getCollection } from 'astro:content';
const posts = await getCollection('kevisual');
console.log('post', posts);
import { basename } from '@/modules/basename';
import Blank from '@/components/html/blank.astro';
---
<Blank>
<h1>kevisual posts</h1>
<ul>
{
posts.map((post) => (
<li>
{/* <a href={`${basename}/demo/${post.id}`}>{post.data.title}</a> */}
<a href={`/docs/kevisual/${post.id}`}>{post.data.title}</a>
</li>
))
}
</ul>
</Blank>

View File

@ -1,4 +1,5 @@
---
import '@/styles/theme.css';
import '@/styles/global.css';
import Blank from '@/components/html/blank.astro';
import { App } from '@/apps/ai-mark';

View File

@ -1,4 +1,5 @@
---
import '@/styles/theme.css';
import '@/styles/global.css';
import Blank from '@/components/html/blank.astro';
import { App as AIChat } from '@/apps/ai-chat/index.tsx';

View File

@ -1,119 +0,0 @@
@import 'tailwindcss';
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
@theme inline {
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--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.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}

View File

@ -1,119 +0,0 @@
@import 'tailwindcss';
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
@theme inline {
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--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.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}

View File

@ -1,15 +1,16 @@
@import 'tailwindcss';
@theme {
--color-primary: #ffc107;
/* --color-primary: #ffc107;
--color-secondary: #ffa000;
--color-text-primary: #000000;
--color-text-secondary: #000000;
--color-success: #28a745;
--color-success: #28a745; */
--color-scrollbar-thumb: #999999;
--color-scrollbar-track: rgba(0, 0, 0, 0.1);
--color-scrollbar-thumb-hover: #666666;
--scrollbar-color: #ffc107; /* 滚动条颜色 */
--scrollbar-color: #ffc107;
}
html,