mirror of
https://github.com/crocofied/CoreControl.git
synced 2025-12-18 07:56:57 +00:00
Sidebar
This commit is contained in:
parent
9b4d2e9735
commit
ec8c5ffc03
@ -30,7 +30,7 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ error: "User not found" }, { status: 404 });
|
return NextResponse.json({ error: "User not found" }, { status: 404 });
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json({ message: "Valid" }, { status: 200 });
|
return NextResponse.json({ message: "Valid", username: user.username, name: user.name }, { status: 200 });
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
|
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
|
||||||
|
|||||||
@ -1,9 +1,20 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import Sidebar from "@/components/Sidebar";
|
||||||
|
|
||||||
export default function DashboardPage() {
|
interface DashboardPageProps {
|
||||||
|
username: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DashboardPage({ username, name }: DashboardPageProps) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Dashboard</h1>
|
<Sidebar username={username} fullName={name}>
|
||||||
|
<main>
|
||||||
|
<h1>Dashboard</h1>
|
||||||
|
</main>
|
||||||
|
</Sidebar>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -11,6 +11,8 @@ import Cookies from "js-cookie";
|
|||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [name, setName] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
@ -23,6 +25,8 @@ export default function Dashboard() {
|
|||||||
Cookies.remove("token");
|
Cookies.remove("token");
|
||||||
router.push("/");
|
router.push("/");
|
||||||
} else {
|
} else {
|
||||||
|
setUsername(response.data.username);
|
||||||
|
setName(response.data.name);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -32,6 +36,6 @@ export default function Dashboard() {
|
|||||||
if (loading) {
|
if (loading) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
} else {
|
} else {
|
||||||
return <DashboardPage />;
|
return <DashboardPage username={username} name={name} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
182
components/Sidebar.tsx
Normal file
182
components/Sidebar.tsx
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import type React from "react"
|
||||||
|
|
||||||
|
import { useState } from "react"
|
||||||
|
import Link from "next/link"
|
||||||
|
import {
|
||||||
|
Home,
|
||||||
|
Globe,
|
||||||
|
Server,
|
||||||
|
Layout,
|
||||||
|
Clock,
|
||||||
|
PenToolIcon as Tool,
|
||||||
|
Settings,
|
||||||
|
LogOut,
|
||||||
|
ChevronDown,
|
||||||
|
Menu,
|
||||||
|
} from "lucide-react"
|
||||||
|
import packageJson from "@/package.json"
|
||||||
|
import Image from "next/image"
|
||||||
|
import Cookies from "js-cookie"
|
||||||
|
import { useRouter } from "next/navigation"
|
||||||
|
|
||||||
|
interface SidebarProps {
|
||||||
|
children: React.ReactNode
|
||||||
|
username: string
|
||||||
|
fullName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Sidebar({ children, username, fullName }: SidebarProps) {
|
||||||
|
const router = useRouter()
|
||||||
|
const [isProfileOpen, setIsProfileOpen] = useState(false)
|
||||||
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false)
|
||||||
|
|
||||||
|
const initials = useState(() => {
|
||||||
|
const nameToUse = fullName || username
|
||||||
|
|
||||||
|
return nameToUse
|
||||||
|
.split(" ")
|
||||||
|
.filter((part) => part.length > 0)
|
||||||
|
.map((part) => part[0])
|
||||||
|
.join("")
|
||||||
|
.toUpperCase()
|
||||||
|
.substring(0, 2)
|
||||||
|
})[0]
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
Cookies.remove("token")
|
||||||
|
router.push("/")
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col md:flex-row min-h-screen w-full bg-base-100">
|
||||||
|
{/* Mobile menu button */}
|
||||||
|
<div className="md:hidden flex items-center p-4 bg-base-200 border-b">
|
||||||
|
<button onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)} className="btn btn-square btn-ghost">
|
||||||
|
<Menu size={24} />
|
||||||
|
</button>
|
||||||
|
<span className="ml-2 text-xl font-bold">CoreControl</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Sidebar */}
|
||||||
|
<aside
|
||||||
|
className={`
|
||||||
|
bg-base-200 text-base-content md:flex md:flex-col
|
||||||
|
${isMobileMenuOpen ? "block" : "hidden"} md:block
|
||||||
|
w-full md:w-72 md:h-screen md:sticky md:top-0 md:left-0
|
||||||
|
relative
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{/* Top section with logo and title */}
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<div className="p-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<Image src="/logo.png" alt="Logo" width={60} height={60} className="rounded-lg" />
|
||||||
|
<div>
|
||||||
|
<h2 className="text-xl font-bold">CoreControl</h2>
|
||||||
|
<p className="text-sm opacity-70">v{packageJson.version}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Navigation menu - scrollable if needed */}
|
||||||
|
<div className="overflow-y-auto" style={{ height: "calc(100vh - 160px)" }}>
|
||||||
|
<ul className="menu menu-md p-4 w-full">
|
||||||
|
<li className="w-full">
|
||||||
|
<Link href="/dashboard" className="flex items-center w-full justify-start px-3 py-2">
|
||||||
|
<Home size={18} />
|
||||||
|
<span>Home</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li className="menu-title mt-4">
|
||||||
|
<span>Resources</span>
|
||||||
|
</li>
|
||||||
|
<li className="w-full">
|
||||||
|
<Link href="/dashboard/sites" className="flex items-center w-full justify-start px-3 py-2">
|
||||||
|
<Globe size={18} />
|
||||||
|
<span>Sites</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li className="w-full">
|
||||||
|
<Link href="/dashboard/servers" className="flex items-center w-full justify-start px-3 py-2">
|
||||||
|
<Server size={18} />
|
||||||
|
<span>Servers</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li className="w-full">
|
||||||
|
<Link href="/dashboard/applications" className="flex items-center w-full justify-start px-3 py-2">
|
||||||
|
<Layout size={18} />
|
||||||
|
<span>Applications</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li className="w-full">
|
||||||
|
<Link href="/dashboard/uptime" className="flex items-center w-full justify-start px-3 py-2">
|
||||||
|
<Clock size={18} />
|
||||||
|
<span>Uptime Pages</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li className="menu-title mt-4">
|
||||||
|
<span>System</span>
|
||||||
|
</li>
|
||||||
|
<li className="w-full">
|
||||||
|
<Link href="/dashboard/maintenance" className="flex items-center w-full justify-start px-3 py-2">
|
||||||
|
<Tool size={18} />
|
||||||
|
<span>Maintenance</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li className="w-full">
|
||||||
|
<Link href="/dashboard/settings" className="flex items-center w-full justify-start px-3 py-2">
|
||||||
|
<Settings size={18} />
|
||||||
|
<span>Settings</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* User profile fixed at bottom */}
|
||||||
|
<div className="p-4 border-t border-base-300 absolute bottom-0 left-0 w-full bg-base-200">
|
||||||
|
<div className="relative">
|
||||||
|
<button
|
||||||
|
onClick={() => setIsProfileOpen(!isProfileOpen)}
|
||||||
|
className="flex items-center gap-3 w-full p-2 rounded-lg hover:bg-base-300 transition-colors"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-center w-10 h-10 rounded-full bg-primary text-primary-content">
|
||||||
|
<span className="inline-flex items-center justify-center" style={{ lineHeight: 1 }}>
|
||||||
|
{initials}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 text-left">
|
||||||
|
<p className="font-medium">{username}</p>
|
||||||
|
<p className="text-sm opacity-70">{fullName}</p>
|
||||||
|
</div>
|
||||||
|
<ChevronDown size={16} className={`transition-transform ${isProfileOpen ? "rotate-180" : ""}`} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{isProfileOpen && (
|
||||||
|
<div className="absolute bottom-full mb-2 left-0 w-full bg-base-100 rounded-lg shadow-lg border border-base-300 overflow-hidden">
|
||||||
|
<ul className="menu p-0 w-full">
|
||||||
|
<li className="w-full">
|
||||||
|
<button
|
||||||
|
onClick={() => logout()}
|
||||||
|
className="flex items-center text-error w-full rounded-none px-4 py-3 justify-start"
|
||||||
|
>
|
||||||
|
<LogOut size={16} />
|
||||||
|
<span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
{/* Main content */}
|
||||||
|
<main className="flex-1 p-4 md:p-6 overflow-auto">{children}</main>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
BIN
public/logo.png
Normal file
BIN
public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Loading…
x
Reference in New Issue
Block a user