mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
- Updated global CSS to implement a new brand color palette and improve light/dark theme consistency. - Enhanced the MitmServerCard component to provide clearer user feedback regarding admin privileges. - Filtered LLM combos in the CombosPage to ensure only relevant data is displayed. - Improved APIPageClient layout for better usability and visual consistency. - Added functionality to save and load DNS tool states in the MITM manager. - Updated OAuth configuration URLs for Qwen to reflect the new endpoint structure. - Refined tunnel management logic to improve reliability and user experience.
105 lines
3.8 KiB
JavaScript
105 lines
3.8 KiB
JavaScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { usePathname } from "next/navigation";
|
|
import { useNotificationStore } from "@/store/notificationStore";
|
|
import Sidebar from "../Sidebar";
|
|
import Header from "../Header";
|
|
|
|
function getToastStyle(type) {
|
|
if (type === "success") {
|
|
return {
|
|
wrapper: "border-green-500/30 bg-green-500/10 text-green-600 dark:text-green-400",
|
|
icon: "check_circle",
|
|
};
|
|
}
|
|
if (type === "error") {
|
|
return {
|
|
wrapper: "border-red-500/30 bg-red-500/10 text-red-600 dark:text-red-400",
|
|
icon: "error",
|
|
};
|
|
}
|
|
if (type === "warning") {
|
|
return {
|
|
wrapper: "border-amber-500/30 bg-amber-500/10 text-amber-600 dark:text-amber-400",
|
|
icon: "warning",
|
|
};
|
|
}
|
|
return {
|
|
wrapper: "border-blue-500/30 bg-blue-500/10 text-blue-600 dark:text-blue-400",
|
|
icon: "info",
|
|
};
|
|
}
|
|
|
|
export default function DashboardLayout({ children }) {
|
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
const pathname = usePathname();
|
|
const notifications = useNotificationStore((state) => state.notifications);
|
|
const removeNotification = useNotificationStore((state) => state.removeNotification);
|
|
|
|
return (
|
|
<div className="flex h-screen w-full overflow-hidden bg-bg">
|
|
<div className="fixed top-4 right-4 z-[80] flex w-[min(92vw,380px)] flex-col gap-2">
|
|
{notifications.map((n) => {
|
|
const style = getToastStyle(n.type);
|
|
return (
|
|
<div
|
|
key={n.id}
|
|
className={`rounded-lg border px-3 py-2 shadow-lg backdrop-blur-sm ${style.wrapper}`}
|
|
>
|
|
<div className="flex items-start gap-2">
|
|
<span className="material-symbols-outlined text-[18px] leading-5">{style.icon}</span>
|
|
<div className="min-w-0 flex-1">
|
|
{n.title ? <p className="text-xs font-semibold mb-0.5">{n.title}</p> : null}
|
|
<p className="text-xs whitespace-pre-wrap break-words">{n.message}</p>
|
|
</div>
|
|
{n.dismissible ? (
|
|
<button
|
|
type="button"
|
|
onClick={() => removeNotification(n.id)}
|
|
className="text-current/70 hover:text-current"
|
|
aria-label="Dismiss notification"
|
|
>
|
|
<span className="material-symbols-outlined text-[16px]">close</span>
|
|
</button>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
{/* Mobile sidebar overlay */}
|
|
{sidebarOpen && (
|
|
<div
|
|
className="fixed inset-0 z-40 bg-black/20 lg:hidden"
|
|
onClick={() => setSidebarOpen(false)}
|
|
/>
|
|
)}
|
|
|
|
{/* Sidebar - Desktop */}
|
|
<div className="hidden lg:flex">
|
|
<Sidebar />
|
|
</div>
|
|
|
|
{/* Sidebar - Mobile */}
|
|
<div
|
|
className={`fixed inset-y-0 left-0 z-50 transform lg:hidden transition-transform duration-300 ease-in-out ${
|
|
sidebarOpen ? "translate-x-0" : "-translate-x-full"
|
|
}`}
|
|
>
|
|
<Sidebar onClose={() => setSidebarOpen(false)} />
|
|
</div>
|
|
|
|
{/* Main content */}
|
|
<main className="flex flex-col flex-1 h-full min-w-0 relative transition-colors duration-300 isolate">
|
|
{/* Faint grid background */}
|
|
<div className="landing-grid absolute inset-0 pointer-events-none -z-10" aria-hidden="true" />
|
|
<Header key={pathname} onMenuClick={() => setSidebarOpen(true)} />
|
|
<div className={`flex-1 overflow-y-auto custom-scrollbar ${pathname === "/dashboard/basic-chat" ? "" : "p-6 lg:p-10"} ${pathname === "/dashboard/basic-chat" ? "flex flex-col overflow-hidden" : ""}`}>
|
|
<div className={`${pathname === "/dashboard/basic-chat" ? "flex-1 w-full h-full flex flex-col" : "max-w-7xl mx-auto"}`}>{children}</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|