From 0c91a49db732fe4cfcebcd26e975f03fba070a33 Mon Sep 17 00:00:00 2001 From: hanif salafi Date: Thu, 3 Jul 2025 09:52:06 +0700 Subject: [PATCH 1/6] feat: update sidebar and layout --- app/(admin)/admin/dashboard/page.tsx | 29 +- app/globals.css | 62 ++ app/layout.tsx | 24 +- components/landing-page/option.tsx | 95 +++- .../landing-page/retracting-sidedar.tsx | 371 +++++++----- components/layout/admin-layout.tsx | 126 ++++- components/layout/breadcrumbs.tsx | 145 +++-- .../main/dashboard/dashboard-container.tsx | 535 ++++++++---------- 8 files changed, 841 insertions(+), 546 deletions(-) diff --git a/app/(admin)/admin/dashboard/page.tsx b/app/(admin)/admin/dashboard/page.tsx index 3be562d..92cce1c 100644 --- a/app/(admin)/admin/dashboard/page.tsx +++ b/app/(admin)/admin/dashboard/page.tsx @@ -1,11 +1,34 @@ +"use client"; + import DashboardContainer from "@/components/main/dashboard/dashboard-container"; +import { motion } from "framer-motion"; +import { useEffect, useState } from "react"; export default function AdminPage() { + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + if (!mounted) { + return ( +
+
+
+ ); + } + return ( -
-
+ +
-
+ ); } diff --git a/app/globals.css b/app/globals.css index dc98be7..a609acd 100644 --- a/app/globals.css +++ b/app/globals.css @@ -120,3 +120,65 @@ @apply bg-background text-foreground; } } + +/* Custom utility classes */ +@layer utilities { + .line-clamp-1 { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; + } + + .line-clamp-2 { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + } + + .line-clamp-3 { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; + } + + .text-gradient { + background: linear-gradient(to right, var(--tw-gradient-stops)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + } + + .scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; + } + + .scrollbar-hide::-webkit-scrollbar { + display: none; + } + + .scrollbar-thin { + scrollbar-width: thin; + scrollbar-color: rgb(203 213 225) transparent; + } + + .scrollbar-thin::-webkit-scrollbar { + width: 6px; + } + + .scrollbar-thin::-webkit-scrollbar-track { + background: transparent; + } + + .scrollbar-thin::-webkit-scrollbar-thumb { + background-color: rgb(203 213 225); + border-radius: 3px; + } + + .scrollbar-thin::-webkit-scrollbar-thumb:hover { + background-color: rgb(148 163 184); + } +} diff --git a/app/layout.tsx b/app/layout.tsx index 14490a5..63e2178 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,16 +1,16 @@ import type { Metadata } from "next"; -// import { Geist, Geist_Mono } from "next/font/google"; +import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; -// const geistSans = Geist({ -// variable: "--font-geist-sans", -// subsets: ["latin"], -// }); +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); -// const geistMono = Geist_Mono({ -// variable: "--font-geist-mono", -// subsets: ["latin"], -// }); +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); export const metadata: Metadata = { title: "Mikul News", @@ -23,10 +23,8 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - - + + {children} diff --git a/components/landing-page/option.tsx b/components/landing-page/option.tsx index 42670c5..45d544c 100644 --- a/components/landing-page/option.tsx +++ b/components/landing-page/option.tsx @@ -21,35 +21,98 @@ const Option = ({ Icon, title, selected, setSelected, open, notifs, active }: Op onClick={() => setSelected?.(title)} onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)} - className={`relative flex h-10 w-full items-center rounded-md transition-colors cursor-pointer ${isActive ? "bg-slate-400 text-black" : "text-black hover:bg-slate-100"}`} + className={`relative flex h-12 w-full items-center rounded-xl transition-all duration-200 cursor-pointer group ${ + isActive + ? "bg-gradient-to-r from-blue-500 to-purple-500 text-white shadow-lg shadow-blue-500/25" + : "text-slate-600 hover:bg-gradient-to-r hover:from-slate-100 hover:to-slate-200/50 hover:text-slate-800" + }`} + whileHover={{ scale: 1.02 }} + whileTap={{ scale: 0.98 }} > - - + {/* Active indicator */} + {isActive && ( + + )} + + +
+ +
{open && ( - - {title} - - )} - - {!open && hovered && ( - {title} )} + {/* Tooltip for collapsed state */} + {!open && hovered && ( + +
+ {title} + {/* Tooltip arrow */} +
+
+
+ )} + + {/* Notification badge */} {notifs && open && ( - + {notifs} )} + + {/* Hover effect overlay */} + {hovered && !isActive && ( + + )} ); }; diff --git a/components/landing-page/retracting-sidedar.tsx b/components/landing-page/retracting-sidedar.tsx index dfcbdc1..ba869b6 100644 --- a/components/landing-page/retracting-sidedar.tsx +++ b/components/landing-page/retracting-sidedar.tsx @@ -1,6 +1,6 @@ "use client"; -import React, { Dispatch, SetStateAction, useState } from "react"; +import React, { Dispatch, SetStateAction, useState, useEffect } from "react"; import Image from "next/image"; import { Icon } from "@iconify/react"; @@ -8,7 +8,7 @@ import Link from "next/link"; import DashboardContainer from "../main/dashboard/dashboard-container"; import { usePathname } from "next/navigation"; import Option from "./option"; -import { motion } from "framer-motion"; +import { motion, AnimatePresence } from "framer-motion"; interface RetractingSidebarProps { sidebarData: boolean; @@ -17,7 +17,7 @@ interface RetractingSidebarProps { const sidebarSections = [ { - title: "DashBoard", + title: "Dashboard", items: [ { title: "Dashboard", @@ -29,15 +29,15 @@ const sidebarSections = [ ], }, { - title: "Apps", + title: "Content Management", items: [ { - title: "Artikel", + title: "Articles", icon: () => , link: "/admin/article", }, { - title: "Kategori", + title: "Categories", icon: () => , link: "/admin/master-category", }, @@ -47,7 +47,7 @@ const sidebarSections = [ // link: "/admin/magazine", // }, { - title: "Advertise", + title: "Advertisements", icon: () => , link: "/admin/advertise", }, @@ -59,15 +59,15 @@ const sidebarSections = [ ], }, { - title: "Master", + title: "System", items: [ { - title: "Master Static Page", + title: "Static Pages", icon: () => , link: "/admin/static-page", }, { - title: "Master User", + title: "User Management", icon: () => , link: "/admin/master-user", }, @@ -80,43 +80,94 @@ export const RetractingSidebar = ({ updateSidebarData, }: RetractingSidebarProps) => { const pathname = usePathname(); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + if (!mounted) { + return null; + } return ( <> {/* DESKTOP SIDEBAR */} - - - - - {/* MOBILE SIDEBAR */} - {sidebarData && ( - + - {/* */} - - )} + + + + {/* Desktop Toggle Button - appears when sidebar is collapsed */} + + {!sidebarData && ( + updateSidebarData(true)} + > + + + )} + + + {/* Mobile Toggle Button */} + + {!sidebarData && ( + updateSidebarData(true)} + > + + + )} + + + {/* MOBILE SIDEBAR */} + + {sidebarData && ( + + {/* */} + + + )} + ); }; @@ -132,126 +183,162 @@ const SidebarContent = ({ }) => { return ( <> - {/* BAGIAN ATAS */} -
- {!open && ( -
- -
- )} - -
- - + + Mikul News + + Admin Panel + + )} - {/* {open && ( - - )} */} + {open && ( - + + )}
-
- {sidebarSections.map((section) => ( -
-

{section.title}

- {section.items.map((item) => ( - -
+ {/* Navigation Sections */} +
+ {sidebarSections.map((section, sectionIndex) => ( + + {open && ( + + {section.title} + + )} +
+ {section.items.map((item, itemIndex) => ( + +
+
))}
- {/* BAGIAN BAWAH */} -
-