From bda862e4d3ae01daf07ae7be6da1a8be53da271a Mon Sep 17 00:00:00 2001 From: Phearun UM <35354771+phearunum@users.noreply.github.com> Date: Mon, 15 Sep 2025 13:43:22 +0700 Subject: [PATCH] menu collaged full view and font size adjustment (#162) * menu sticky and add font adjustment * menu sticky and add font adjustment * ui menu sticky and fontsize adjustment --------- Co-authored-by: phearun --- application/index.html | 44 ++- application/package-lock.json | 184 +++++++++ application/package.json | 2 + application/src/App.tsx | 184 ++++++--- .../components/dashboard/DashboardContent.tsx | 42 +- .../src/components/dashboard/Header.tsx | 265 ++++++++++--- .../components/dashboard/ServiceFilters.tsx | 37 +- .../src/components/dashboard/Sidebar.tsx | 22 +- .../dashboard/sidebar/MainNavigation.tsx | 13 +- .../components/dashboard/sidebar/MenuItem.tsx | 23 +- .../dashboard/sidebar/SettingsPanel.tsx | 95 +++-- .../dashboard/sidebar/SidebarHeader.tsx | 19 +- .../OperationalPageContent.tsx | 91 +++-- .../RegionalMonitoringContent.tsx | 67 ++-- .../ScheduleIncidentContent.tsx | 74 ++-- .../src/components/servers/ServerTable.tsx | 370 +++++++++++++----- .../ssl-domain/SSLDomainContent.tsx | 186 +++++---- application/src/contexts/FontSizeContext.tsx | 14 + application/src/contexts/SidebarContext.tsx | 40 +- application/src/pages/InstanceMonitoring.tsx | 94 +++-- application/src/pages/SslDomain.tsx | 82 ++-- 21 files changed, 1382 insertions(+), 566 deletions(-) create mode 100644 application/src/contexts/FontSizeContext.tsx diff --git a/application/index.html b/application/index.html index bf65603..78d00e0 100644 --- a/application/index.html +++ b/application/index.html @@ -1,25 +1,29 @@ - - - - - CheckCle - - - - - - + + + + CheckCle - Dev + + - - - - + + + + - -
- - - + + + + + + + +
+ + + + \ No newline at end of file diff --git a/application/package-lock.json b/application/package-lock.json index adec743..0cf478b 100644 --- a/application/package-lock.json +++ b/application/package-lock.json @@ -8,6 +8,7 @@ "name": "vite_react_shadcn_ts", "version": "0.0.0", "dependencies": { + "@headlessui/react": "2.2.7", "@hookform/resolvers": "^3.9.0", "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-alert-dialog": "^1.1.1", @@ -644,6 +645,21 @@ "@floating-ui/utils": "^0.2.8" } }, + "node_modules/@floating-ui/react": { + "version": "0.26.28", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", + "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@floating-ui/react-dom": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", @@ -663,6 +679,26 @@ "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", "license": "MIT" }, + "node_modules/@headlessui/react": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.7.tgz", + "integrity": "sha512-WKdTymY8Y49H8/gUc/lIyYK1M+/6dq0Iywh4zTZVAaiTDprRfioxSgD0wnXTQTBpjpGJuTL1NO/mqEvc//5SSg==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.26.16", + "@react-aria/focus": "^3.20.2", + "@react-aria/interactions": "^3.25.0", + "@tanstack/react-virtual": "^3.13.9", + "use-sync-external-store": "^1.5.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/@hookform/resolvers": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.0.tgz", @@ -2280,6 +2316,103 @@ "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", "license": "MIT" }, + "node_modules/@react-aria/focus": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.1.tgz", + "integrity": "sha512-hmH1IhHlcQ2lSIxmki1biWzMbGgnhdxJUM0MFfzc71Rv6YAzhlx4kX3GYn4VNcjCeb6cdPv4RZ5vunV4kgMZYQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.25.5", + "@react-aria/utils": "^3.30.1", + "@react-types/shared": "^3.32.0", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/interactions": { + "version": "3.25.5", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.25.5.tgz", + "integrity": "sha512-EweYHOEvMwef/wsiEqV73KurX/OqnmbzKQa2fLxdULbec5+yDj6wVGaRHIzM4NiijIDe+bldEl5DG05CAKOAHA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-aria/utils": "^3.30.1", + "@react-stately/flags": "^3.1.2", + "@react-types/shared": "^3.32.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz", + "integrity": "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/utils": { + "version": "3.30.1", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.30.1.tgz", + "integrity": "sha512-zETcbDd6Vf9GbLndO6RiWJadIZsBU2MMm23rBACXLmpRztkrIqPEb2RVdlLaq1+GklDx0Ii6PfveVjx+8S5U6A==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-stately/flags": "^3.1.2", + "@react-stately/utils": "^3.10.8", + "@react-types/shared": "^3.32.0", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/flags": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@react-stately/flags/-/flags-3.1.2.tgz", + "integrity": "sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@react-stately/utils": { + "version": "3.10.8", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.8.tgz", + "integrity": "sha512-SN3/h7SzRsusVQjQ4v10LaVsDc81jyyR0DD5HnsQitm/I5WDpaSr2nRHtyloPFU48jlql1XX/S04T2DLQM7Y3g==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/shared": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.32.0.tgz", + "integrity": "sha512-t+cligIJsZYFMSPFMvsJMjzlzde06tZMOIOFa1OV5Z0BcMowrb2g4mB57j/9nP28iJIRYn10xCniQts+qadrqQ==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, "node_modules/@remix-run/router": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz", @@ -2729,6 +2862,15 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@swc/types": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.13.tgz", @@ -2793,6 +2935,33 @@ "react": "^18 || ^19" } }, + "node_modules/@tanstack/react-virtual": { + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.12.tgz", + "integrity": "sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.13.12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.12.tgz", + "integrity": "sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@types/d3-array": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", @@ -6289,6 +6458,12 @@ "node": ">=12.0.0" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "2.5.4", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.4.tgz", @@ -6568,6 +6743,15 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/application/package.json b/application/package.json index e047fff..60f00c7 100644 --- a/application/package.json +++ b/application/package.json @@ -11,6 +11,7 @@ "preview": "vite preview" }, "dependencies": { + "@headlessui/react": "2.2.7", "@hookform/resolvers": "^3.9.0", "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-alert-dialog": "^1.1.1", @@ -45,6 +46,7 @@ "cmdk": "^1.0.0", "date-fns": "^3.6.0", "embla-carousel-react": "^8.3.0", + "framer-motion": "12.23.12", "input-otp": "^1.2.4", "jspdf": "^3.0.1", "jspdf-autotable": "^5.0.2", diff --git a/application/src/App.tsx b/application/src/App.tsx index e7f1e0b..a64bc67 100644 --- a/application/src/App.tsx +++ b/application/src/App.tsx @@ -1,37 +1,40 @@ -import React, { useState } from 'react'; -import { BrowserRouter, Routes, Route } from 'react-router-dom'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { Toaster } from '@/components/ui/sonner'; +import React, { useState } from "react"; +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { Toaster } from "@/components/ui/sonner"; -import { ThemeProvider } from './contexts/ThemeContext'; -import { LanguageProvider } from './contexts/LanguageContext'; -import { SidebarProvider } from './contexts/SidebarContext'; +import { ThemeProvider } from "./contexts/ThemeContext"; +import { LanguageProvider } from "./contexts/LanguageContext"; +import { SidebarProvider } from "./contexts/SidebarContext"; -import Index from './pages/Index'; -import Login from './pages/Login'; -import Dashboard from './pages/Dashboard'; -import InstanceMonitoring from './pages/InstanceMonitoring'; -import ContainerMonitoring from './pages/ContainerMonitoring'; -import ServiceDetail from './pages/ServiceDetail'; -import SslDomain from './pages/SslDomain'; -import ScheduleIncident from './pages/ScheduleIncident'; -import OperationalPage from './pages/OperationalPage'; -import RegionalMonitoring from './pages/RegionalMonitoring'; -import Settings from './pages/Settings'; -import Profile from './pages/Profile'; -import NotFound from './pages/NotFound'; -import PublicStatusPage from './pages/PublicStatusPage'; -import { ProtectedRoute } from './components/auth/ProtectedRoute'; -import ServerDetail from './pages/ServerDetail'; +import Index from "./pages/Index"; +import Login from "./pages/Login"; +import Dashboard from "./pages/Dashboard"; +import InstanceMonitoring from "./pages/InstanceMonitoring"; +import ContainerMonitoring from "./pages/ContainerMonitoring"; +import ServiceDetail from "./pages/ServiceDetail"; +import SslDomain from "./pages/SslDomain"; +import ScheduleIncident from "./pages/ScheduleIncident"; +import OperationalPage from "./pages/OperationalPage"; +import RegionalMonitoring from "./pages/RegionalMonitoring"; +import Settings from "./pages/Settings"; +import Profile from "./pages/Profile"; +import NotFound from "./pages/NotFound"; +import PublicStatusPage from "./pages/PublicStatusPage"; +import { ProtectedRoute } from "./components/auth/ProtectedRoute"; +import ServerDetail from "./pages/ServerDetail"; function App() { - const [queryClient] = useState(() => new QueryClient({ - defaultOptions: { - queries: { - staleTime: 60 * 1000 - } - } - })); + const [queryClient] = useState( + () => + new QueryClient({ + defaultOptions: { + queries: { + staleTime: 60 * 1000, + }, + }, + }) + ); return ( @@ -43,22 +46,113 @@ function App() { {/* Public routes */} } /> - + {/* Protected routes */} } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> } /> @@ -69,4 +163,4 @@ function App() { ); } -export default App; \ No newline at end of file +export default App; diff --git a/application/src/components/dashboard/DashboardContent.tsx b/application/src/components/dashboard/DashboardContent.tsx index 64308b6..7ef077a 100644 --- a/application/src/components/dashboard/DashboardContent.tsx +++ b/application/src/components/dashboard/DashboardContent.tsx @@ -1,4 +1,3 @@ - import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Plus } from "lucide-react"; @@ -15,17 +14,24 @@ interface DashboardContentProps { error: Error | null; } -export const DashboardContent = ({ services, isLoading, error }: DashboardContentProps) => { +export const DashboardContent = ({ + services, + isLoading, + error, +}: DashboardContentProps) => { const { t } = useLanguage(); const [filter, setFilter] = useState("all"); const [searchTerm, setSearchTerm] = useState(""); const [isAddDialogOpen, setIsAddDialogOpen] = useState(false); // Filter services based on search term and type filter - const filteredServices = services.filter(service => { - const matchesSearch = service.name.toLowerCase().includes(searchTerm.toLowerCase()) || - (service.url && service.url.toLowerCase().includes(searchTerm.toLowerCase())); - const matchesFilter = filter === 'all' || service.type.toLowerCase() === filter.toLowerCase(); + const filteredServices = services.filter((service) => { + const matchesSearch = + service.name.toLowerCase().includes(searchTerm.toLowerCase()) || + (service.url && + service.url.toLowerCase().includes(searchTerm.toLowerCase())); + const matchesFilter = + filter === "all" || service.type.toLowerCase() === filter.toLowerCase(); return matchesSearch && matchesFilter; }); @@ -33,40 +39,42 @@ export const DashboardContent = ({ services, isLoading, error }: DashboardConten return (

Error loading service data.

- +
); } return ( -
-
+
+
-

{t('overview')}

-
- + - - - +
- diff --git a/application/src/components/dashboard/Header.tsx b/application/src/components/dashboard/Header.tsx index d0db992..3b740ee 100644 --- a/application/src/components/dashboard/Header.tsx +++ b/application/src/components/dashboard/Header.tsx @@ -1,13 +1,39 @@ import { Button } from "@/components/ui/button"; import { AuthUser } from "@/services/authService"; import { useTheme } from "@/contexts/ThemeContext"; -import { Moon, PanelLeft, PanelLeftClose, Sun, Globe, FileText, Github, Twitter, MessageSquare, Bell, User, Settings, LogOut } from "lucide-react"; +import { + Moon, + PanelLeft, + PanelLeftClose, + Sun, + Globe, + FileText, + Github, + Twitter, + MessageSquare, + Bell, + User, + Settings, + LogOut, + CaseUpper, + BookA, + CaseSensitive, + CaseLower, + ALargeSmall, +} from "lucide-react"; import { useLanguage } from "@/contexts/LanguageContext"; -import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from "@/components/ui/dropdown-menu"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, + DropdownMenuSeparator, +} from "@/components/ui/dropdown-menu"; import { useEffect, useState } from "react"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { useNavigate } from "react-router-dom"; import { useSystemSettings } from "@/hooks/useSystemSettings"; +import useDynamicFontSize from "@/contexts/FontSizeContext"; interface HeaderProps { currentUser: AuthUser | null; @@ -20,7 +46,7 @@ export const Header = ({ currentUser, onLogout, sidebarCollapsed, - toggleSidebar + toggleSidebar, }: HeaderProps) => { const { theme, toggleTheme } = useTheme(); const { language, setLanguage, t } = useLanguage(); @@ -55,148 +81,270 @@ export const Header = ({ }, [currentUser]); // Prepare avatar URL - ensure it displays correctly if it's a local profile image - let avatarUrl = ''; + let avatarUrl = ""; if (currentUser?.avatar) { // If it's a relative path from the public folder, make sure it's resolved properly - if (currentUser.avatar.startsWith('/upload/profile/')) { + if (currentUser.avatar.startsWith("/upload/profile/")) { avatarUrl = currentUser.avatar; } else { avatarUrl = currentUser.avatar; } console.log("Final avatar URL:", avatarUrl); } - + const [fontSize, setFontSize] = useState(() => { + const savedFontSize = localStorage.getItem("fontSize"); + return savedFontSize ? parseInt(savedFontSize, 10) : 14; + }); + useDynamicFontSize(fontSize); return (
{/* Grid Pattern Overlay - Similar to StatusCards */}
-
- + {/* Header Content */}
- - +
-

{greeting}, {currentUser?.name || currentUser?.email?.split('@')[0] || 'User'} 👋 ✨

+

+ {greeting},{" "} + {currentUser?.name || currentUser?.email?.split("@")[0] || "User"}{" "} + 👋 ✨ +

- +
- - + - - setLanguage("en")} className={language === "en" ? "bg-accent" : ""}> + setLanguage("en")} + className={language === "en" ? "bg-accent" : ""} + > {t("english")} - setLanguage("km")} className={language === "km" ? "bg-accent" : ""}> + setLanguage("km")} + className={language === "km" ? "bg-accent" : ""} + > {t("khmer")} - setLanguage("de")} className={language === "de" ? "bg-accent" : ""}> + setLanguage("de")} + className={language === "de" ? "bg-accent" : ""} + > {t("Deutsch")} - setLanguage("ko")} className={language === "ko" ? "bg-accent" : ""}> + setLanguage("ko")} + className={language === "ko" ? "bg-accent" : ""} + > {t("korean")} - setLanguage("ja")} className={language === "ja" ? "bg-accent" : ""}> + setLanguage("ja")} + className={language === "ja" ? "bg-accent" : ""} + > {t("japanese")} - setLanguage("zhcn")} className={language === "zhcn" ? "bg-accent" : ""}> + setLanguage("zhcn")} + className={language === "zhcn" ? "bg-accent" : ""} + > {t("simplifiedChinese")} - + {/* Documentation */} - - + {/* GitHub */} - - + {/* X (Twitter) */} - - + {/* Discord */} - - + {/* Notifications */} - - + {/* Fond Size */} + + + + + + setFontSize((prev) => prev + 1)} + className={`cursor-pointer`} + > + Aa + + + setFontSize((prev) => prev - 1)} + className={`cursor-pointer`} + > + Aa - + + + + {/* User Profile Dropdown */} - {avatarUrl ? : - {currentUser?.name?.[0] || currentUser?.email?.[0] || 'U'} - } + {avatarUrl ? ( + + ) : ( + + {currentUser?.name?.[0] || currentUser?.email?.[0] || "U"} + + )}
- {avatarUrl ? : - {currentUser?.name?.[0] || currentUser?.email?.[0] || 'U'} - } + {avatarUrl ? ( + + ) : ( + + {currentUser?.name?.[0] || currentUser?.email?.[0] || "U"} + + )}
- {currentUser?.name || 'User'} - {currentUser?.email} + + {currentUser?.name || "User"} + + + {currentUser?.email} +
@@ -209,7 +357,10 @@ export const Header = ({ {t("settings")} - + {t("logout")} diff --git a/application/src/components/dashboard/ServiceFilters.tsx b/application/src/components/dashboard/ServiceFilters.tsx index 613fba4..eb18d64 100644 --- a/application/src/components/dashboard/ServiceFilters.tsx +++ b/application/src/components/dashboard/ServiceFilters.tsx @@ -1,7 +1,12 @@ - import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; -import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@/components/ui/select"; +import { + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectItem, +} from "@/components/ui/select"; import { Plus } from "lucide-react"; import { useLanguage } from "@/contexts/LanguageContext"; @@ -13,29 +18,31 @@ interface ServiceFiltersProps { servicesCount: number; } -export const ServiceFilters = ({ - filter, - setFilter, - searchTerm, +export const ServiceFilters = ({ + filter, + setFilter, + searchTerm, setSearchTerm, - servicesCount + servicesCount, }: ServiceFiltersProps) => { const { t } = useLanguage(); return ( -
+
-

{t('currentlyMonitoring')}

+

+ {t("currentlyMonitoring")} +

{servicesCount}
- setSearchTerm(e.target.value)} /> diff --git a/application/src/components/dashboard/Sidebar.tsx b/application/src/components/dashboard/Sidebar.tsx index 21ba733..744e2ca 100644 --- a/application/src/components/dashboard/Sidebar.tsx +++ b/application/src/components/dashboard/Sidebar.tsx @@ -1,4 +1,3 @@ - import React from "react"; import { useTheme } from "@/contexts/ThemeContext"; import { SidebarHeader } from "./sidebar/SidebarHeader"; @@ -11,18 +10,25 @@ interface SidebarProps { export const Sidebar = ({ collapsed }: SidebarProps) => { const { theme } = useTheme(); - + return ( -
+
+ Version: latest +
); -}; \ No newline at end of file +}; diff --git a/application/src/components/dashboard/sidebar/MainNavigation.tsx b/application/src/components/dashboard/sidebar/MainNavigation.tsx index 9b4e103..6e6f86b 100644 --- a/application/src/components/dashboard/sidebar/MainNavigation.tsx +++ b/application/src/components/dashboard/sidebar/MainNavigation.tsx @@ -1,4 +1,3 @@ - import React from "react"; import { MenuItem } from "./MenuItem"; import { mainMenuItems } from "./navigationData"; @@ -7,9 +6,15 @@ interface MainNavigationProps { collapsed: boolean; } -export const MainNavigation: React.FC = ({ collapsed }) => { +export const MainNavigation: React.FC = ({ + collapsed, +}) => { return ( -