572 lines
21 KiB
TypeScript
572 lines
21 KiB
TypeScript
import React, { useState } from "react";
|
||
import { Link, useLocation } from "react-router-dom";
|
||
import {
|
||
BarChart3,
|
||
Bot,
|
||
Brain,
|
||
ChevronLeft,
|
||
ChevronRight,
|
||
CircleHelp,
|
||
Compass,
|
||
Database,
|
||
FileBox,
|
||
FileOutput,
|
||
FileText,
|
||
Folder,
|
||
FolderOpen,
|
||
Grid3X3,
|
||
HelpCircle,
|
||
History,
|
||
Layers,
|
||
Layout,
|
||
Library,
|
||
ListTodo,
|
||
MessageSquare,
|
||
MoreHorizontal,
|
||
Network,
|
||
PlayCircle,
|
||
Plus,
|
||
Scale,
|
||
Target,
|
||
TrendingUp,
|
||
Users,
|
||
Workflow,
|
||
} from "lucide-react";
|
||
import { useTheme } from "../contexts/ThemeContext";
|
||
|
||
export type PageType = string;
|
||
|
||
type MenuItem = {
|
||
id: PageType;
|
||
label: string;
|
||
icon: React.ElementType;
|
||
children?: MenuItem[];
|
||
path?: string;
|
||
activePath?: string;
|
||
};
|
||
type Props = {
|
||
currentPage: PageType;
|
||
isCollapsed?: boolean;
|
||
onToggleCollapse?: () => void;
|
||
};
|
||
type Level1MenuId =
|
||
| "qa-center"
|
||
| "light-app-center"
|
||
| "task-management"
|
||
| "agent-list"
|
||
| "result-management"
|
||
| "resource-management";
|
||
type TaskGroupId = string;
|
||
|
||
const taskGroups: TaskGroupId[] = [
|
||
"xk-task",
|
||
"plan-task",
|
||
"mnty-task",
|
||
"effect-task",
|
||
];
|
||
const collapsibleMenus = new Set<PageType>([
|
||
"qa-center",
|
||
"light-app-center",
|
||
"task-management",
|
||
"agent-list",
|
||
"result-management",
|
||
"resource-management",
|
||
]);
|
||
const taskPages = new Set([
|
||
"dashboard",
|
||
"task-create",
|
||
"task-single",
|
||
"task-scene",
|
||
"task-consult-create",
|
||
"task-consult",
|
||
"task-consult-result",
|
||
"task-list",
|
||
]);
|
||
const qaPages = new Set([
|
||
"new-qa",
|
||
"general-qa",
|
||
"agent-qa",
|
||
"multi-agent-qa",
|
||
"qa-records",
|
||
"sixstep-chat",
|
||
"topic-research",
|
||
"task-chat",
|
||
"action-chat",
|
||
"qa-from",
|
||
"qa-from-6bf"
|
||
]);
|
||
const lightAppPages = new Set([
|
||
"light-app-square",
|
||
"light-app-records",
|
||
"light-app-run",
|
||
]);
|
||
const agentPages = new Set(["agent-trial"]);
|
||
const resultPages = new Set([
|
||
"result-planning",
|
||
"result-mnty",
|
||
"result-effect-pg",
|
||
"result-xk",
|
||
"result-dq",
|
||
"result-other",
|
||
"result-detail",
|
||
]);
|
||
const resourcePages = new Set([
|
||
"resource-zz",
|
||
"resource-network-actor",
|
||
"resource-knowledge-base",
|
||
"resource-evaluation-index",
|
||
]);
|
||
|
||
const menuItems: MenuItem[] = [
|
||
{
|
||
id: "qa-center",
|
||
label: "问答管理",
|
||
icon: HelpCircle,
|
||
children: [
|
||
{ id: "qa-from", label: "通用问答", icon: Bot }, // general-qa
|
||
// { id: 'sixstep-chat', label: 'zz决策支持', icon: Layers },
|
||
{ id: "qa-from-6bf", label: "zz决策支持", icon: Layers },
|
||
{ id: "action-chat", label: "zzXD应用", icon: History },
|
||
{ id: "topic-research", label: "课题研究", icon: CircleHelp },
|
||
// { id: 'agent-qa', label: '智能体问答', icon: Bot },
|
||
// { id: 'multi-agent-qa', label: '多智能体协同', icon: Layers },
|
||
// { id: 'qa-records', label: '问答记录', icon: History },
|
||
],
|
||
},
|
||
{
|
||
id: "task-management",
|
||
label: "任务管理",
|
||
icon: Target,
|
||
children: [
|
||
// { id: "dashboard", label: "任务统计", icon: BarChart3 },
|
||
{
|
||
id: "xk-task",
|
||
label: "XK中任务",
|
||
icon: Folder,
|
||
children: [
|
||
{ id: "xk-task-jc", label: "任务JC", icon: ListTodo },
|
||
{ id: "xk-task-dispatch", label: "任务调度", icon: ListTodo },
|
||
],
|
||
},
|
||
{
|
||
id: "plan-task",
|
||
label: "COH中任务",
|
||
icon: Folder,
|
||
children: [
|
||
{ id: "plan-task-sentiment", label: "三情FX", icon: ListTodo },
|
||
{ id: "plan-task-fx", label: "任务FX", icon: ListTodo },
|
||
{ id: "plan-task-action", label: "行动CE", icon: ListTodo },
|
||
],
|
||
},
|
||
{
|
||
id: "effect-task",
|
||
label: "PG中任务",
|
||
icon: Folder,
|
||
children: [
|
||
{ id: "effect-task-pg", label: "任务PG", icon: ListTodo },
|
||
{ id: "effect-action-pg", label: "行动PG", icon: ListTodo },
|
||
{ id: "effect-info-pg", label: "信息PG", icon: ListTodo },
|
||
// { id: "effect-account-pg", label: "账号PG", icon: ListTodo },
|
||
],
|
||
},
|
||
{
|
||
id: "mnty-task",
|
||
label: "TY中任务",
|
||
icon: Folder,
|
||
children: [
|
||
{ id: "mnty-task-mechanism", label: "XDTY任务", icon: ListTodo },
|
||
{ id: "mnty-task-plan", label: "方案TY任务", icon: ListTodo },
|
||
{ id: "mnty-task-zsty", label: "XXTY任务", icon: ListTodo },
|
||
],
|
||
},
|
||
],
|
||
},
|
||
// {
|
||
// id: 'light-app-center', label: '工具管理', icon: Grid3X3,
|
||
// children: [
|
||
// { id: 'light-app-square', label: '应用广场', icon: Layout },
|
||
// { id: 'light-app-records', label: '运行记录', icon: History },
|
||
// { id: 'scene-list', label: '场景管理', icon: Layers },
|
||
// ]
|
||
// },
|
||
{
|
||
id: "agent-list",
|
||
label: " 综合管理",
|
||
icon: Bot,
|
||
children: [
|
||
// { id: 'agent-list', label: '业务链条管理', icon: Users },
|
||
// { id: 'agent-list', label: '智能体管理', icon: Users },
|
||
{ id: "agent-expert-center", label: "智能体管理", icon: Users },
|
||
{ id: 'scene-list', label: '业务链条管理', icon: Layers },
|
||
// { id: "skills-workshop", label: "技能列表", icon: Users },
|
||
// { id: "sixstep-agents", label: "mcp管理", icon: Layers },
|
||
// { id: "file-skills", label: "skills管理", icon: Layers },
|
||
// { id: 'agent-trial', label: '单智能体试用', icon: PlayCircle }
|
||
],
|
||
},
|
||
// { id: 'result-management', label: '结果管理', icon: BarChart3, children: [
|
||
// { id: 'result-planning', label: '规划任务', icon: Target, children: [
|
||
// { id: 'result-planning-all', label: '全部', icon: BarChart3, path: '/result-management/result-planning', activePath: '/result-management/result-planning' },
|
||
// { id: 'result-planning-goal', label: '目标分析', icon: Target, path: '/result-management/result-planning?subCategory=目标分析' },
|
||
// { id: 'result-planning-brand', label: '品牌策略', icon: Target, path: '/result-management/result-planning?subCategory=品牌策略' },
|
||
// { id: 'result-planning-content', label: '内容规划', icon: Target, path: '/result-management/result-planning?subCategory=内容规划' },
|
||
// { id: 'result-planning-channel', label: '渠道规划', icon: Target, path: '/result-management/result-planning?subCategory=渠道规划' },
|
||
// { id: 'result-planning-narrative', label: '叙事策略', icon: Target, path: '/result-management/result-planning?subCategory=叙事策略' },
|
||
// ] },
|
||
// { id: 'result-mnty', label: 'MNTY任务', icon: Brain, children: [
|
||
// { id: 'result-mnty-all', label: '全部', icon: BarChart3, path: '/result-management/result-mnty', activePath: '/result-management/result-mnty' },
|
||
// { id: 'result-mnty-mechanism', label: '机制研究', icon: Brain, path: '/result-management/result-mnty?subCategory=机制研究' },
|
||
// { id: 'result-mnty-plan', label: '方案设计', icon: Brain, path: '/result-management/result-mnty?subCategory=方案设计' },
|
||
// { id: 'result-mnty-zsty', label: 'ZSTY分析', icon: Brain, path: '/result-management/result-mnty?subCategory=ZSTY分析' },
|
||
// ] },
|
||
// { id: 'result-effect-pg', label: '效果PG任务', icon: TrendingUp, children: [
|
||
// { id: 'result-effect-pg-all', label: '全部', icon: BarChart3, path: '/result-management/result-effect-pg', activePath: '/result-management/result-effect-pg' },
|
||
// { id: 'result-effect-pg-behavior', label: '行为PG', icon: TrendingUp, path: '/result-management/result-effect-pg?subCategory=行为PG' },
|
||
// { id: 'result-effect-pg-evaluation', label: '效果评估', icon: TrendingUp, path: '/result-management/result-effect-pg?subCategory=效果评估' },
|
||
// { id: 'result-effect-pg-info', label: '信息PG', icon: TrendingUp, path: '/result-management/result-effect-pg?subCategory=信息PG' },
|
||
// { id: 'result-effect-pg-account', label: '账号PG', icon: TrendingUp, path: '/result-management/result-effect-pg?subCategory=账号PG' },
|
||
// ] },
|
||
// { id: 'result-xk', label: 'XK任务', icon: Compass, children: [
|
||
// { id: 'result-xk-all', label: '全部', icon: BarChart3, path: '/result-management/result-xk', activePath: '/result-management/result-xk' },
|
||
// { id: 'result-xk-jc', label: '任务JC', icon: Compass, path: '/result-management/result-xk?subCategory=任务JC' },
|
||
// { id: 'result-xk-dispatch', label: '任务调度', icon: Compass, path: '/result-management/result-xk?subCategory=任务调度' },
|
||
// ] },
|
||
// { id: 'result-dq', label: 'DQ研究类任务', icon: Database, children: [
|
||
// { id: 'result-dq-all', label: '全部', icon: BarChart3, path: '/result-management/result-dq', activePath: '/result-management/result-dq' },
|
||
// { id: 'result-dq-audience', label: '受众分析', icon: Database, path: '/result-management/result-dq?subCategory=受众分析' },
|
||
// { id: 'result-dq-kb', label: '知识库研究', icon: Database, path: '/result-management/result-dq?subCategory=知识库研究' },
|
||
// { id: 'result-dq-trend', label: '趋势研究', icon: Database, path: '/result-management/result-dq?subCategory=趋势研究' },
|
||
// ] },
|
||
// { id: 'result-other', label: '其他类任务', icon: MoreHorizontal, children: [
|
||
// { id: 'result-other-all', label: '全部', icon: BarChart3, path: '/result-management/result-other', activePath: '/result-management/result-other' },
|
||
// { id: 'result-other-general', label: '通用分析', icon: MoreHorizontal, path: '/result-management/result-other?subCategory=通用分析' },
|
||
// { id: 'result-other-temp', label: '临时任务', icon: MoreHorizontal, path: '/result-management/result-other?subCategory=临时任务' },
|
||
// { id: 'result-other-other', label: '其他', icon: MoreHorizontal, path: '/result-management/result-other?subCategory=其他' },
|
||
// ] },
|
||
// ] },
|
||
{
|
||
id: "resource-management",
|
||
label: "资源管理",
|
||
icon: Database,
|
||
children: [
|
||
// { id: "resource-zz", label: "ZZ资源管理", icon: FileBox },
|
||
{
|
||
id: "resource-network-actor",
|
||
label: "网络行为体资源管理",
|
||
icon: Network,
|
||
},
|
||
{ id: "resource-evaluation-index", label: "作战资源管理", icon: Library },
|
||
// {
|
||
// id: "resource-evaluation-index",
|
||
// label: "评估指标体系资源管理",
|
||
// icon: Scale,
|
||
// },
|
||
],
|
||
},
|
||
];
|
||
|
||
const subEntries = [
|
||
// { id: 'task-create', label: '新建任务', icon: ListTodo, parent: 'task-management' },
|
||
// { id: 'task-single', label: '单智能体任务', icon: Bot, parent: 'task-management' },
|
||
// { id: 'task-scene', label: '场景任务', icon: Workflow, parent: 'task-management' },
|
||
// { id: 'task-consult-create', label: '多智能体会商', icon: MessageSquare, parent: 'task-management' },
|
||
// { id: 'final-plan', label: '方案输出', icon: FileOutput, parent: 'strategy-result' },
|
||
];
|
||
|
||
const getPath = (id: PageType) => {
|
||
if (taskGroups.includes(id as TaskGroupId)) {
|
||
console.log('----task-management', id);
|
||
return `/task-management/${id}`;
|
||
}
|
||
if (taskGroups.some((group) => id.startsWith(group))) {
|
||
return `/task-management/${id.split("-").slice(0, 2).join("-")}/${id}`;
|
||
}
|
||
// 特殊处理 effect-task 下的子菜单项(effect-action-pg, effect-info-pg, effect-account-pg)
|
||
if (id.startsWith("effect-") && !id.startsWith("effect-task")) {
|
||
return `/task-management/effect-task/${id}`;
|
||
}
|
||
if (taskPages.has(id)) return `/task-management/${id}`;
|
||
if (qaPages.has(id)) return `/qa-center/${id}`;
|
||
if (id === "qa-center") return "/qa-center";
|
||
if (lightAppPages.has(id)) return `/light-app-center/${id}`;
|
||
if (agentPages.has(id)) return `/agent-list/${id}`;
|
||
if (resultPages.has(id)) return `/result-management/${id}`;
|
||
if (resourcePages.has(id)) return `/resource-management/${id}`;
|
||
|
||
return `/${id}`;
|
||
};
|
||
|
||
const toggleSet = <T,>(set: Set<T>, item: T) => {
|
||
const next = new Set(set);
|
||
next.has(item) ? next.delete(item) : next.add(item);
|
||
return next;
|
||
};
|
||
|
||
export default function Sidebar({
|
||
currentPage,
|
||
isCollapsed = false,
|
||
onToggleCollapse,
|
||
}: Props) {
|
||
const { theme } = useTheme();
|
||
const location = useLocation();
|
||
const isDark = theme === "dark";
|
||
const [collapsedMenus, setCollapsedMenus] = useState<Set<Level1MenuId>>(
|
||
new Set()
|
||
);
|
||
const [expandedTaskGroups, setExpandedTaskGroups] = useState<Set<string>>(
|
||
() =>
|
||
new Set([
|
||
...taskGroups.filter((group) => currentPage.startsWith(group)),
|
||
...(currentPage.startsWith("result-") ? [currentPage] : []),
|
||
])
|
||
);
|
||
|
||
const panel = `ml-4 pl-4 border-l space-y-1 theme-transition ${
|
||
isDark ? "border-blue-800/30" : "border-red-100"
|
||
}`;
|
||
const iconBtn = `rounded-lg transition-all duration-200 ${
|
||
isDark
|
||
? "text-slate-400 hover:text-white hover:bg-slate-800/50"
|
||
: "text-gray-500 hover:text-red-600 hover:bg-red-50"
|
||
}`;
|
||
const itemClass = (active: boolean) =>
|
||
`rounded-lg transition-all duration-200 theme-transition ${
|
||
active
|
||
? isDark
|
||
? "bg-blue-600/20 text-blue-400 border border-blue-500/30"
|
||
: "bg-red-50 text-red-600 border border-red-200"
|
||
: isDark
|
||
? "text-slate-400 hover:text-white hover:bg-slate-800/50"
|
||
: "text-gray-600 hover:text-red-600 hover:bg-red-50"
|
||
}`;
|
||
|
||
const isTopActive = (id: PageType) => {
|
||
if (id === "qa-center") return qaPages.has(currentPage);
|
||
if (id === "light-app-center") return currentPage.startsWith("light-app");
|
||
if (id === "task-management")
|
||
return (
|
||
currentPage === "dashboard" ||
|
||
taskPages.has(currentPage) ||
|
||
taskGroups.some((group) => currentPage.startsWith(group))
|
||
);
|
||
if (id === "scene-list") return currentPage.startsWith("scene");
|
||
if (id === "agent-list") return currentPage.startsWith("agent");
|
||
if (id === "result-management") return currentPage.startsWith("result");
|
||
if (id === "resource-management") return currentPage.startsWith("resource");
|
||
return currentPage === id;
|
||
};
|
||
const hasActiveChild = (item: MenuItem): boolean =>
|
||
currentPage === item.id || Boolean(item.children?.some(hasActiveChild));
|
||
|
||
const renderLink = (item: MenuItem, top = false) => {
|
||
const Icon = item.icon;
|
||
const activePath = decodeURI(`${location.pathname}${location.search}`);
|
||
const active = top
|
||
? isTopActive(item.id)
|
||
: item.path
|
||
? activePath === (item.activePath ?? item.path)
|
||
: currentPage === item.id;
|
||
return (
|
||
<Link
|
||
key={item.id}
|
||
to={item.path ?? getPath(item.id)}
|
||
onClick={() =>
|
||
top &&
|
||
item.id === "task-management" &&
|
||
expandedTaskGroups.size === 0 &&
|
||
setExpandedTaskGroups(new Set(["xk-task"]))
|
||
}
|
||
title={isCollapsed ? item.label : undefined}
|
||
className={`${top ? "flex-1" : "w-full"} flex items-center ${
|
||
isCollapsed && top ? "justify-center gap-0 px-2" : "gap-2 px-3"
|
||
} py-2 ${itemClass(active)}`}
|
||
>
|
||
<Icon
|
||
className={`${top ? "w-5 h-5" : "w-4 h-4"} flex-shrink-0 ${
|
||
active ? (isDark ? "text-blue-400" : "text-red-500") : ""
|
||
}`}
|
||
/>
|
||
{(!isCollapsed || !top) && (
|
||
<span
|
||
className={`${
|
||
top ? "text-sm" : "text-xs"
|
||
} font-medium flex-1 text-left`}
|
||
>
|
||
{item.label}
|
||
</span>
|
||
)}
|
||
</Link>
|
||
);
|
||
};
|
||
|
||
const renderTaskGroup = (item: MenuItem) => {
|
||
const expanded = expandedTaskGroups.has(item.id);
|
||
const active = hasActiveChild(item);
|
||
const Icon = expanded ? FolderOpen : Folder;
|
||
return (
|
||
<div key={item.id} className="space-y-1">
|
||
<button
|
||
type="button"
|
||
onClick={() =>
|
||
setExpandedTaskGroups((prev) => toggleSet(prev, item.id))
|
||
}
|
||
className={`w-full flex items-center gap-2 px-3 py-2 ${itemClass(
|
||
active
|
||
)}`}
|
||
>
|
||
<Icon
|
||
className={`w-4 h-4 flex-shrink-0 ${
|
||
active ? (isDark ? "text-blue-400" : "text-red-500") : ""
|
||
}`}
|
||
/>
|
||
<span className="text-xs font-medium flex-1 text-left">
|
||
{item.label}
|
||
</span>
|
||
<ChevronRight
|
||
className={`w-4 h-4 transition-transform duration-200 ${
|
||
expanded ? "rotate-90" : ""
|
||
}`}
|
||
/>
|
||
</button>
|
||
{expanded && item.children && (
|
||
<div className={panel}>
|
||
{item.children.map((child) => renderLink(child))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
const renderChildren = (item: MenuItem) =>
|
||
item.children ? (
|
||
<div className={panel}>
|
||
{item.children.map((child) =>
|
||
child.children ? renderTaskGroup(child) : renderLink(child)
|
||
)}
|
||
</div>
|
||
) : null;
|
||
const renderSubEntries = (item: MenuItem) => {
|
||
const entries = subEntries.filter((entry) => entry.parent === item.id);
|
||
return entries.length && isTopActive(item.id) ? (
|
||
<div className={panel}>{entries.map((entry) => renderLink(entry))}</div>
|
||
) : null;
|
||
};
|
||
|
||
return (
|
||
<aside
|
||
className={`fixed left-0 top-0 h-screen ${
|
||
isCollapsed ? "w-16" : "w-64"
|
||
} z-50 theme-transition overflow-y-auto ${
|
||
isDark
|
||
? "bg-slate-900/80 backdrop-blur-xl border-r border-blue-800/30"
|
||
: "bg-white border-r border-red-100 shadow-sm"
|
||
}`}
|
||
>
|
||
<div
|
||
className={`h-16 flex items-center ${
|
||
isCollapsed ? "justify-center px-2" : "justify-between px-6"
|
||
} border-b theme-transition flex-shrink-0 ${
|
||
isDark ? "border-blue-800/30" : "border-red-100"
|
||
}`}
|
||
>
|
||
<div className="flex items-center gap-3 min-w-0">
|
||
<div
|
||
className={`w-8 h-8 rounded-lg flex items-center justify-center flex-shrink-0 ${
|
||
isDark
|
||
? "bg-gradient-to-br from-blue-500 to-cyan-400"
|
||
: "bg-gradient-to-br from-red-500 to-red-400"
|
||
}`}
|
||
>
|
||
<FileText className="w-4 h-4 text-white" />
|
||
</div>
|
||
{!isCollapsed && (
|
||
<div>
|
||
<h1
|
||
className={`font-semibold text-sm ${
|
||
isDark ? "text-white" : "text-gray-900"
|
||
}`}
|
||
>
|
||
智能CM系统
|
||
</h1>
|
||
<p
|
||
className={`text-xs ${
|
||
isDark ? "text-blue-400/60" : "text-red-400/80"
|
||
}`}
|
||
>
|
||
Smart CM Platform
|
||
</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
{!isCollapsed && (
|
||
<button
|
||
type="button"
|
||
onClick={onToggleCollapse}
|
||
className={`p-2 ${iconBtn}`}
|
||
title="收起侧边栏"
|
||
>
|
||
<ChevronLeft className="w-4 h-4" />
|
||
</button>
|
||
)}
|
||
</div>
|
||
<nav className={`${isCollapsed ? "p-2" : "p-4"} space-y-2`}>
|
||
{isCollapsed && (
|
||
<button
|
||
type="button"
|
||
onClick={onToggleCollapse}
|
||
className={`w-full flex items-center justify-center p-2.5 ${iconBtn}`}
|
||
title="展开侧边栏"
|
||
>
|
||
<ChevronRight className="w-5 h-5" />
|
||
</button>
|
||
)}
|
||
{menuItems.map((item) => {
|
||
const canCollapse = collapsibleMenus.has(item.id);
|
||
const childrenCollapsed =
|
||
canCollapse && collapsedMenus.has(item.id as Level1MenuId);
|
||
return (
|
||
<div key={item.id} className="space-y-1">
|
||
<div className="flex items-center gap-2">
|
||
{renderLink(item, true)}
|
||
{!isCollapsed && item.children && canCollapse && (
|
||
<button
|
||
type="button"
|
||
onClick={() =>
|
||
setCollapsedMenus((prev) =>
|
||
toggleSet(prev, item.id as Level1MenuId)
|
||
)
|
||
}
|
||
className={`p-1.5 ${iconBtn}`}
|
||
title={childrenCollapsed ? "展开菜单" : "折叠菜单"}
|
||
>
|
||
<ChevronRight
|
||
className={`w-4 h-4 transition-transform duration-200 ${
|
||
childrenCollapsed ? "" : "rotate-90"
|
||
}`}
|
||
/>
|
||
</button>
|
||
)}
|
||
</div>
|
||
{!isCollapsed &&
|
||
item.children &&
|
||
!childrenCollapsed &&
|
||
renderChildren(item)}
|
||
{!isCollapsed && !childrenCollapsed && renderSubEntries(item)}
|
||
</div>
|
||
);
|
||
})}
|
||
</nav>
|
||
{isDark ? (
|
||
<>
|
||
<div className="absolute top-0 right-0 w-32 h-32 bg-blue-500/10 rounded-full blur-3xl pointer-events-none" />
|
||
<div className="absolute bottom-20 right-0 w-24 h-24 bg-cyan-500/10 rounded-full blur-3xl pointer-events-none" />
|
||
</>
|
||
) : (
|
||
<>
|
||
<div className="absolute top-0 right-0 w-32 h-32 bg-red-500/5 rounded-full blur-3xl pointer-events-none" />
|
||
<div className="absolute bottom-20 right-0 w-24 h-24 bg-red-400/5 rounded-full blur-3xl pointer-events-none" />
|
||
</>
|
||
)}
|
||
</aside>
|
||
);
|
||
}
|