This is an automated email from the ASF dual-hosted git repository.

twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks-controller.git


The following commit(s) were added to refs/heads/unstable by this push:
     new bf1ba47  feat(webui): redesign the controller web management UI (#281)
bf1ba47 is described below

commit bf1ba4759640bf192292392e93c6288b21af9455
Author: Agnik Misra <[email protected]>
AuthorDate: Thu Mar 20 08:21:45 2025 +0530

    feat(webui): redesign the controller web management UI (#281)
    
    * Fix edge case handling in Mock engine List method
    
    * There's a typo in the main UI heading - Controler should be Controller
    
    * This code launches a new goroutine for each node in the cluster without 
any concurrency limits.
    
    * redesign the webpage
    
    * Update cluster.go
    
    * fix conflict
    
    * conflict
    
    * Update webui/src/app/page.tsx
    
    * Update webui/src/app/page.tsx
    
    * Update webui/src/app/layout.tsx
    
    * Update webui/src/app/ui/banner.tsx
    
    * Update webui/src/app/page.tsx
    
    * Update webui/src/app/page.tsx
    
    ---------
    
    Co-authored-by: Twice <[email protected]>
---
 webui/src/app/globals.css                          |  67 +++++
 webui/src/app/layout.tsx                           |  19 +-
 .../[namespace]/clusters/[cluster]/page.tsx        | 124 ++++++---
 .../[cluster]/shards/[shard]/nodes/[node]/page.tsx | 281 +++++++++++++++++----
 .../clusters/[cluster]/shards/[shard]/page.tsx     | 157 ++++++++----
 webui/src/app/namespaces/[namespace]/page.tsx      | 144 +++++++----
 webui/src/app/namespaces/page.tsx                  |  68 ++---
 webui/src/app/not-found.tsx                        |  67 +++++
 webui/src/app/page.tsx                             | 189 +++++++++++++-
 webui/src/app/theme-provider.tsx                   | 109 ++++++++
 webui/src/app/ui/banner.tsx                        |  80 +++++-
 webui/src/app/ui/createCard.tsx                    | 155 +++++++-----
 webui/src/app/ui/emptyState.tsx                    |  63 +++++
 webui/src/app/ui/formDialog.tsx                    | 120 ++++++---
 webui/src/app/ui/loadingSpinner.tsx                |  56 +++-
 webui/src/app/ui/nav-links.tsx                     |  44 +++-
 webui/src/app/ui/sidebar.tsx                       | 272 +++++++++++++-------
 webui/src/app/ui/sidebarItem.tsx                   | 143 +++++++----
 webui/src/app/utils.ts                             |  52 +++-
 webui/tailwind.config.ts                           |  57 ++++-
 20 files changed, 1766 insertions(+), 501 deletions(-)

diff --git a/webui/src/app/globals.css b/webui/src/app/globals.css
index 7c7084d..6578a51 100644
--- a/webui/src/app/globals.css
+++ b/webui/src/app/globals.css
@@ -20,3 +20,70 @@
 @tailwind base;
 @tailwind components;
 @tailwind utilities;
+
+@layer components {
+  .card {
+    @apply bg-white dark:bg-dark-paper border border-light-border 
dark:border-dark-border rounded-lg shadow-card hover:shadow-card-hover 
transition-all p-5 flex flex-col;
+  }
+  
+  .sidebar-item {
+    @apply flex items-center px-4 py-2 text-gray-700 dark:text-gray-300 
hover:bg-gray-100 dark:hover:bg-dark-paper rounded-lg my-1 transition-colors;
+  }
+  
+  .sidebar-item-active {
+    @apply bg-primary-light/10 text-primary dark:text-primary-light;
+  }
+  
+  .btn {
+    @apply px-4 py-2 rounded-md transition-colors focus:outline-none 
focus:ring-2 focus:ring-offset-2;
+  }
+  
+  .btn-primary {
+    @apply bg-primary text-white hover:bg-primary-dark focus:ring-primary;
+  }
+  
+  .btn-outline {
+    @apply border border-primary text-primary hover:bg-primary 
hover:text-white focus:ring-primary;
+  }
+  
+  .container-inner {
+    @apply p-6 max-w-screen-2xl mx-auto;
+  }
+}
+
+/* custom scrollbar */
+::-webkit-scrollbar {
+  width: 8px;
+  height: 8px;
+}
+
+::-webkit-scrollbar-track {
+  background: transparent;
+}
+
+::-webkit-scrollbar-thumb {
+  background: #c1c1c1;
+  border-radius: 4px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+  background: #a1a1a1;
+}
+
+.dark ::-webkit-scrollbar-thumb {
+  background: #555;
+}
+
+.dark ::-webkit-scrollbar-thumb:hover {
+  background: #777;
+}
+
+/* smooth transitions for dark mode */
+body {
+  transition: background-color 0.3s ease;
+}
+
+.dark body {
+  background-color: #121212;
+  color: #e0e0e0;
+}
diff --git a/webui/src/app/layout.tsx b/webui/src/app/layout.tsx
index a1e1a0a..20a34d7 100644
--- a/webui/src/app/layout.tsx
+++ b/webui/src/app/layout.tsx
@@ -22,12 +22,13 @@ import { Inter } from "next/font/google";
 import "./globals.css";
 import Banner from "./ui/banner";
 import { Container } from "@mui/material";
+import { ThemeProvider } from "./theme-provider";
 
 const inter = Inter({ subsets: ["latin"] });
 
 export const metadata: Metadata = {
-    title: "Kvrocks Controller",
-    description: "Kvrocks Controller",
+    title: "Apache Kvrocks Controller",
+    description: "Management UI for Apache Kvrocks clusters",
 };
 
 export default function RootLayout({
@@ -36,12 +37,14 @@ export default function RootLayout({
   children: React.ReactNode;
 }>) {
     return (
-        <html lang="en">
-            <body className={inter.className}>
-                <Banner />
-                <Container sx={{marginTop: '64px', height: 'calc(100vh - 
64px)'}} maxWidth={false} disableGutters>
-                    {children}
-                </Container>
+        <html lang="en" suppressHydrationWarning>
+            <body className={`${inter.className} bg-light dark:bg-dark 
min-h-screen`}>
+                <ThemeProvider>
+                    <Banner />
+                    <Container sx={{marginTop: '64px', height: 'calc(100vh - 
64px)'}} maxWidth={false} disableGutters>
+                        {children}
+                    </Container>
+                </ThemeProvider>
             </body>
         </html>
     );
diff --git a/webui/src/app/namespaces/[namespace]/clusters/[cluster]/page.tsx 
b/webui/src/app/namespaces/[namespace]/clusters/[cluster]/page.tsx
index 16f8151..9fdd96c 100644
--- a/webui/src/app/namespaces/[namespace]/clusters/[cluster]/page.tsx
+++ b/webui/src/app/namespaces/[namespace]/clusters/[cluster]/page.tsx
@@ -22,15 +22,20 @@
 import {
     Box,
     Container,
-    Typography
+    Typography,
+    Chip,
+    Badge,
 } from "@mui/material";
 import { ClusterSidebar } from "../../../../ui/sidebar";
 import { useState, useEffect } from "react";
 import { listShards } from "@/app/lib/api";
-import { AddShardCard, CreateCard } from "@/app/ui/createCard";
+import { AddShardCard, ResourceCard } from "@/app/ui/createCard";
 import Link from "next/link";
 import { useRouter } from "next/navigation";
 import { LoadingSpinner } from "@/app/ui/loadingSpinner";
+import DnsIcon from '@mui/icons-material/Dns';
+import StorageIcon from '@mui/icons-material/Storage';
+import EmptyState from "@/app/ui/emptyState";
 
 export default function Cluster({
     params,
@@ -67,42 +72,91 @@ export default function Cluster({
         return <LoadingSpinner />;
     }
 
+    const formatSlotRanges = (ranges: string[]) => {
+        if (!ranges || ranges.length === 0) return "None";
+        if (ranges.length <= 2) return ranges.join(", ");
+        return `${ranges[0]}, ${ranges[1]}, ... (+${ranges.length - 2} more)`;
+    };
+
     return (
         <div className="flex h-full">
             <ClusterSidebar namespace={namespace} />
-            <Container
-                maxWidth={false}
-                disableGutters
-                sx={{ height: "100%", overflowY: "auto", marginLeft: "16px" }}
-            >
-                <div className="flex flex-row flex-wrap">
-                    <AddShardCard namespace={namespace} cluster={cluster} />
-                    {shardsData.map((shard, index) => (
-                        <Link
-                            key={index}
-                            
href={`/namespaces/${namespace}/clusters/${cluster}/shards/${index}`}
-                        >
-                            <CreateCard>
-                                <Typography variant="h6" gutterBottom noWrap>
-                  Shard {index + 1}
-                                </Typography>
-                                <Typography variant="body2" gutterBottom>
-                  Nodes : {shard.nodes.length}
-                                </Typography>
-                                <Typography variant="body2" gutterBottom>
-                  Slots: {shard.slot_ranges.join(", ")}
-                                </Typography>
-                                <Typography variant="body2" gutterBottom>
-                  Target Shard Index: {shard.target_shard_index}
-                                </Typography>
-                                <Typography variant="body2" gutterBottom>
-                  Migrating Slot: {shard.migrating_slot}
-                                </Typography>
-                            </CreateCard>
-                        </Link>
-                    ))}
-                </div>
-            </Container>
+            <div className="flex-1 overflow-auto">
+                <Box className="container-inner">
+                    <Box className="flex items-center justify-between mb-6">
+                        <div>
+                            <Typography variant="h5" className="font-medium 
text-gray-800 dark:text-gray-100 flex items-center">
+                                <StorageIcon className="mr-2 text-primary 
dark:text-primary-light" /> 
+                                {cluster}
+                                <Chip 
+                                    label={`${shardsData.length} shards`} 
+                                    size="small" 
+                                    color="primary" 
+                                    className="ml-3"
+                                />
+                            </Typography>
+                            <Typography variant="body2" 
className="text-gray-500 dark:text-gray-400 mt-1">
+                                Cluster in namespace: {namespace}
+                            </Typography>
+                        </div>
+                    </Box>
+
+                    <div className="grid grid-cols-1 sm:grid-cols-2 
lg:grid-cols-3 xl:grid-cols-4 gap-4">
+                        <Box className="col-span-1">
+                            <AddShardCard namespace={namespace} 
cluster={cluster} />
+                        </Box>
+                        
+                        {shardsData.length > 0 ? (
+                            shardsData.map((shard, index) => (
+                                <Link
+                                    key={index}
+                                    
href={`/namespaces/${namespace}/clusters/${cluster}/shards/${index}`}
+                                    className="col-span-1"
+                                >
+                                    <ResourceCard
+                                        title={`Shard ${index + 1}`}
+                                        tags={[
+                                            { label: `${shard.nodes.length} 
nodes`, color: "secondary" },
+                                            shard.migrating_slot >= 0 ? { 
label: "Migrating", color: "warning" } : undefined
+                                        ].filter(Boolean)}
+                                    >
+                                        <div className="space-y-2 text-sm">
+                                            <div className="flex 
justify-between">
+                                                <span className="text-gray-500 
dark:text-gray-400">Slots:</span>
+                                                <span 
className="font-medium">{formatSlotRanges(shard.slot_ranges)}</span>
+                                            </div>
+                                            
+                                            {shard.target_shard_index >= 0 && (
+                                                <div className="flex 
justify-between">
+                                                    <span 
className="text-gray-500 dark:text-gray-400">Target Shard:</span>
+                                                    <span 
className="font-medium">{shard.target_shard_index + 1}</span>
+                                                </div>
+                                            )}
+                                            
+                                            {shard.migrating_slot >= 0 && (
+                                                <div className="flex 
justify-between">
+                                                    <span 
className="text-gray-500 dark:text-gray-400">Migrating Slot:</span>
+                                                    <Badge color="warning" 
variant="dot">
+                                                        <span 
className="font-medium">{shard.migrating_slot}</span>
+                                                    </Badge>
+                                                </div>
+                                            )}
+                                        </div>
+                                    </ResourceCard>
+                                </Link>
+                            ))
+                        ) : (
+                            <Box className="col-span-full">
+                                <EmptyState
+                                    title="No shards found"
+                                    description="Create a shard to get started"
+                                    icon={<DnsIcon sx={{ fontSize: 60 }} />}
+                                />
+                            </Box>
+                        )}
+                    </div>
+                </Box>
+            </div>
         </div>
     );
 }
diff --git 
a/webui/src/app/namespaces/[namespace]/clusters/[cluster]/shards/[shard]/nodes/[node]/page.tsx
 
b/webui/src/app/namespaces/[namespace]/clusters/[cluster]/shards/[shard]/nodes/[node]/page.tsx
index 9ac6ea1..d65e428 100644
--- 
a/webui/src/app/namespaces/[namespace]/clusters/[cluster]/shards/[shard]/nodes/[node]/page.tsx
+++ 
b/webui/src/app/namespaces/[namespace]/clusters/[cluster]/shards/[shard]/nodes/[node]/page.tsx
@@ -23,18 +23,24 @@ import { listNodes } from "@/app/lib/api";
 import { NodeSidebar } from "@/app/ui/sidebar";
 import {
     Box,
-    Container,
-    Card,
-    Alert,
-    Snackbar,
     Typography,
-    Tooltip,
+    Chip,
+    Paper,
+    Divider,
+    Grid,
+    Alert,
 } from "@mui/material";
 import { useEffect, useState } from "react";
 import { useRouter } from "next/navigation";
 import { LoadingSpinner } from "@/app/ui/loadingSpinner";
-import { AddNodeCard, CreateCard } from "@/app/ui/createCard";
 import { truncateText } from "@/app/utils";
+import DeviceHubIcon from '@mui/icons-material/DeviceHub';
+import LockIcon from '@mui/icons-material/Lock';
+import ContentCopyIcon from '@mui/icons-material/ContentCopy';
+import AccessTimeIcon from '@mui/icons-material/AccessTime';
+import CheckCircleIcon from '@mui/icons-material/CheckCircle';
+import StorageIcon from '@mui/icons-material/Storage';
+import DnsIcon from '@mui/icons-material/Dns';
 
 export default function Node({
     params,
@@ -43,8 +49,9 @@ export default function Node({
 }) {
     const { namespace, cluster, shard, node } = params;
     const router = useRouter();
-    const [nodeData, setNodeData] = useState<any>(null);
+    const [nodeData, setNodeData] = useState<any[]>([]);
     const [loading, setLoading] = useState<boolean>(true);
+    const [copied, setCopied] = useState<string | null>(null);
 
     useEffect(() => {
         const fetchData = async () => {
@@ -70,51 +77,229 @@ export default function Node({
         return <LoadingSpinner />;
     }
 
+    const currentNode = nodeData[parseInt(node)];
+    if (!currentNode) {
+        return (
+            <div className="flex h-full">
+                <NodeSidebar namespace={namespace} cluster={cluster} 
shard={shard} />
+                <Box className="flex-1 container-inner flex items-center 
justify-center">
+                    <Alert severity="error" variant="filled" 
className="shadow-lg">
+                        Node not found
+                    </Alert>
+                </Box>
+            </div>
+        );
+    }
+
+    // Get role color and text style
+    const getRoleStyles = (role: string) => {
+        if (role === 'master') {
+            return { 
+                color: 'success', 
+                textClass: 'text-success font-medium',
+                icon: <CheckCircleIcon fontSize="small" className="mr-1" />
+            };
+        }
+        return { 
+            color: 'info', 
+            textClass: 'text-info font-medium',
+            icon: <DeviceHubIcon fontSize="small" className="mr-1" /> 
+        };
+    };
+
+    const copyToClipboard = (text: string, type: string) => {
+        navigator.clipboard.writeText(text);
+        setCopied(type);
+        setTimeout(() => setCopied(null), 2000);
+    };
+
+    const formattedDate = new Date(currentNode.created_at * 
1000).toLocaleString();
+
     return (
         <div className="flex h-full">
             <NodeSidebar namespace={namespace} cluster={cluster} shard={shard} 
/>
-            <Container
-                maxWidth={false}
-                disableGutters
-                sx={{ height: "100%", overflowY: "auto", marginLeft: "16px" }}
-            >
-                <div className="flex flex-row flex-wrap">
-                    {nodeData.map((nodeObj: any, index: number) =>
-                        index === Number(node) ? (
-                            <>
-                                <CreateCard>
-                                    <Typography variant="h6" gutterBottom>
-                    Node {index + 1}
-                                    </Typography>
-                                    <Tooltip title={nodeObj.id}>
-                                        <Typography
-                                            variant="body2"
-                                            gutterBottom
-                                            sx={{
-                                                whiteSpace: "nowrap",
-                                                overflow: "hidden",
-                                                textOverflow: "ellipsis",
-                                            }}
-                                        >
-                      ID: {truncateText(nodeObj.id, 20)}
+            <div className="flex-1 overflow-auto">
+                <Box className="container-inner">
+                    <Box className="flex items-center justify-between mb-6">
+                        <div>
+                            <Typography variant="h5" className="font-medium 
text-gray-800 dark:text-gray-100 flex items-center">
+                                <DeviceHubIcon className="mr-2 text-primary 
dark:text-primary-light" /> 
+                                Node {parseInt(node) + 1}
+                                <Chip 
+                                    label={currentNode.role} 
+                                    size="small" 
+                                    
color={getRoleStyles(currentNode.role).color as any}
+                                    className="ml-3"
+                                    icon={getRoleStyles(currentNode.role).icon}
+                                />
+                            </Typography>
+                            <Typography variant="body2" 
className="text-gray-500 dark:text-gray-400 mt-1">
+                                Shard {parseInt(shard) + 1}, {cluster} 
cluster, {namespace} namespace
+                            </Typography>
+                        </div>
+                    </Box>
+
+                    <Paper className="bg-white dark:bg-dark-paper border 
border-light-border dark:border-dark-border rounded-lg shadow-card p-6 mb-6">
+                        <Typography variant="h6" className="mb-4 font-medium 
flex items-center">
+                            <StorageIcon fontSize="small" className="mr-2" />
+                            Node Details
+                        </Typography>
+                        <Divider className="mb-4" />
+                        
+                        <Grid container spacing={3}>
+                            <Grid item xs={12} md={6}>
+                                <div className="space-y-4">
+                                    <div>
+                                        <Typography variant="subtitle2" 
className="text-gray-500 dark:text-gray-400 mb-1">
+                                            ID
+                                        </Typography>
+                                        <div className="flex items-center">
+                                            <Typography variant="body1" 
className="font-mono bg-gray-50 dark:bg-dark-border px-3 py-2 rounded flex-1 
overflow-hidden text-ellipsis">
+                                                {currentNode.id}
+                                            </Typography>
+                                            <IconButton 
+                                                onClick={() => 
copyToClipboard(currentNode.id, 'id')} 
+                                                className="ml-2 text-gray-500 
hover:text-primary"
+                                                title="Copy ID"
+                                            >
+                                                {copied === 'id' ? 
+                                                    <CheckCircleIcon 
fontSize="small" className="text-success" /> : 
+                                                    <ContentCopyIcon 
fontSize="small" />
+                                                }
+                                            </IconButton>
+                                        </div>
+                                    </div>
+                                    
+                                    <div>
+                                        <Typography variant="subtitle2" 
className="text-gray-500 dark:text-gray-400 mb-1">
+                                            Address
                                         </Typography>
-                                    </Tooltip>
-                                    <Typography variant="body2" gutterBottom>
-                    Address: {nodeObj.addr}
-                                    </Typography>
-                                    <Typography variant="body2" gutterBottom>
-                    Role: {nodeObj.role}
-                                    </Typography>
-                                    <Typography variant="body2" gutterBottom>
-                    Created At:{" "}
-                                        {new Date(nodeObj.created_at * 
1000).toLocaleString()}
-                                    </Typography>
-                                </CreateCard>
-                            </>
-                        ) : null
-                    )}
-                </div>
-            </Container>
+                                        <div className="flex items-center">
+                                            <Typography variant="body1" 
className="bg-gray-50 dark:bg-dark-border px-3 py-2 rounded flex-1">
+                                                {currentNode.addr}
+                                            </Typography>
+                                            <IconButton 
+                                                onClick={() => 
copyToClipboard(currentNode.addr, 'addr')} 
+                                                className="ml-2 text-gray-500 
hover:text-primary"
+                                                title="Copy Address"
+                                            >
+                                                {copied === 'addr' ? 
+                                                    <CheckCircleIcon 
fontSize="small" className="text-success" /> : 
+                                                    <ContentCopyIcon 
fontSize="small" />
+                                                }
+                                            </IconButton>
+                                        </div>
+                                    </div>
+                                </div>
+                            </Grid>
+                            
+                            <Grid item xs={12} md={6}>
+                                <div className="space-y-4">
+                                    <div>
+                                        <Typography variant="subtitle2" 
className="text-gray-500 dark:text-gray-400 mb-1">
+                                            Role
+                                        </Typography>
+                                        <Typography variant="body1" 
className={`${getRoleStyles(currentNode.role).textClass} flex items-center`}>
+                                            
{getRoleStyles(currentNode.role).icon} {currentNode.role}
+                                        </Typography>
+                                    </div>
+                                    
+                                    <div>
+                                        <Typography variant="subtitle2" 
className="text-gray-500 dark:text-gray-400 mb-1">
+                                            Created At
+                                        </Typography>
+                                        <Typography variant="body1" 
className="flex items-center">
+                                            <AccessTimeIcon fontSize="small" 
className="mr-1 text-gray-500" /> 
+                                            {formattedDate}
+                                        </Typography>
+                                    </div>
+                                    
+                                    {currentNode.password && (
+                                        <div>
+                                            <Typography variant="subtitle2" 
className="text-gray-500 dark:text-gray-400 mb-1">
+                                                Authentication
+                                            </Typography>
+                                            <div className="flex items-center">
+                                                <Typography variant="body2" 
className="bg-gray-50 dark:bg-dark-border px-3 py-2 rounded flex-1 font-mono">
+                                                    {currentNode.password ? 
'••••••••' : 'No password set'}
+                                                </Typography>
+                                                <IconButton 
+                                                    onClick={() => 
copyToClipboard(currentNode.password, 'pwd')} 
+                                                    className="ml-2 
text-gray-500 hover:text-primary"
+                                                    title="Copy Password"
+                                                    
disabled={!currentNode.password}
+                                                >
+                                                    {copied === 'pwd' ? 
+                                                        <CheckCircleIcon 
fontSize="small" className="text-success" /> : 
+                                                        <LockIcon 
fontSize="small" />
+                                                    }
+                                                </IconButton>
+                                            </div>
+                                        </div>
+                                    )}
+                                </div>
+                            </Grid>
+                        </Grid>
+                    </Paper>
+
+                    <Paper className="bg-white dark:bg-dark-paper border 
border-light-border dark:border-dark-border rounded-lg shadow-card p-6">
+                        <Typography variant="h6" className="mb-4 font-medium 
flex items-center">
+                            <DnsIcon fontSize="small" className="mr-2" />
+                            Shard Information
+                        </Typography>
+                        <Divider className="mb-4" />
+                        
+                        <Grid container spacing={3}>
+                            <Grid item xs={12} md={4}>
+                                <Typography variant="subtitle2" 
className="text-gray-500 dark:text-gray-400 mb-1">
+                                    Shard
+                                </Typography>
+                                <Typography variant="body1">
+                                    Shard {parseInt(shard) + 1}
+                                </Typography>
+                            </Grid>
+                            <Grid item xs={12} md={4}>
+                                <Typography variant="subtitle2" 
className="text-gray-500 dark:text-gray-400 mb-1">
+                                    Cluster
+                                </Typography>
+                                <Typography variant="body1">
+                                    {cluster}
+                                </Typography>
+                            </Grid>
+                            <Grid item xs={12} md={4}>
+                                <Typography variant="subtitle2" 
className="text-gray-500 dark:text-gray-400 mb-1">
+                                    Namespace
+                                </Typography>
+                                <Typography variant="body1">
+                                    {namespace}
+                                </Typography>
+                            </Grid>
+                        </Grid>
+                    </Paper>
+                </Box>
+            </div>
         </div>
     );
 }
+
+interface IconButtonProps {
+    onClick: () => void;
+    className?: string;
+    title?: string;
+    disabled?: boolean;
+    children: React.ReactNode;
+}
+
+// Custom IconButton component
+const IconButton: React.FC<IconButtonProps> = ({ onClick, className = "", 
title, disabled = false, children }) => {
+    return (
+        <button 
+            onClick={onClick}
+            disabled={disabled}
+            className={`w-8 h-8 rounded-full flex items-center justify-center 
hover:bg-gray-100 dark:hover:bg-dark-border ${disabled ? 'opacity-50 
cursor-not-allowed' : ''} ${className}`}
+            title={title}
+        >
+            {children}
+        </button>
+    );
+};
diff --git 
a/webui/src/app/namespaces/[namespace]/clusters/[cluster]/shards/[shard]/page.tsx
 
b/webui/src/app/namespaces/[namespace]/clusters/[cluster]/shards/[shard]/page.tsx
index a6f453a..aad1602 100644
--- 
a/webui/src/app/namespaces/[namespace]/clusters/[cluster]/shards/[shard]/page.tsx
+++ 
b/webui/src/app/namespaces/[namespace]/clusters/[cluster]/shards/[shard]/page.tsx
@@ -19,15 +19,21 @@
 
 "use client";
 
-import { Container, Typography, Tooltip } from "@mui/material";
+import { Box, Typography, Chip, Badge } from "@mui/material";
 import { ShardSidebar } from "@/app/ui/sidebar";
 import { fetchShard } from "@/app/lib/api";
 import { useRouter } from "next/navigation";
 import { useState, useEffect } from "react";
-import { AddNodeCard, AddShardCard, CreateCard } from "@/app/ui/createCard";
+import { AddNodeCard, ResourceCard } from "@/app/ui/createCard";
 import Link from "next/link";
 import { LoadingSpinner } from "@/app/ui/loadingSpinner";
 import { truncateText } from "@/app/utils";
+import DeviceHubIcon from '@mui/icons-material/DeviceHub';
+import DnsIcon from '@mui/icons-material/Dns';
+import EmptyState from "@/app/ui/emptyState";
+import AlarmIcon from '@mui/icons-material/Alarm';
+import CheckCircleIcon from '@mui/icons-material/CheckCircle';
+import RemoveCircleIcon from '@mui/icons-material/RemoveCircle';
 
 export default function Shard({
     params,
@@ -63,54 +69,113 @@ export default function Shard({
         return <LoadingSpinner />;
     }
 
+    // Calculate uptime from creation timestamp
+    const calculateUptime = (timestamp: number) => {
+        const now = Math.floor(Date.now() / 1000);
+        const uptimeSeconds = now - timestamp;
+        
+        if (uptimeSeconds < 60) return `${uptimeSeconds} seconds`;
+        if (uptimeSeconds < 3600) return `${Math.floor(uptimeSeconds / 60)} 
minutes`;
+        if (uptimeSeconds < 86400) return `${Math.floor(uptimeSeconds / 3600)} 
hours`;
+        return `${Math.floor(uptimeSeconds / 86400)} days`;
+    };
+
+    // Get role color and icon
+    const getRoleInfo = (role: string) => {
+        if (role === 'master') {
+            return { 
+                color: 'success', 
+                icon: <CheckCircleIcon fontSize="small" 
className="text-success" /> 
+            };
+        }
+        return { 
+            color: 'info', 
+            icon: <DeviceHubIcon fontSize="small" className="text-info" /> 
+        };
+    };
+
     return (
         <div className="flex h-full">
             <ShardSidebar namespace={namespace} cluster={cluster} />
-            <Container
-                maxWidth={false}
-                disableGutters
-                sx={{ height: "100%", overflowY: "auto", marginLeft: "16px" }}
-            >
-                <div className="flex flex-row flex-wrap">
-                    <AddNodeCard namespace={namespace} cluster={cluster} 
shard={shard} />
-                    {nodesData.nodes.map(
-                        (node: any, index: number) => (
-                            <Link
-                                
href={`/namespaces/${namespace}/clusters/${cluster}/shards/${shard}/nodes/${index}`}
-                                key={index}
-                            >
-                                <CreateCard>
-                                    <Typography variant="h6" gutterBottom>
-                                        Node {index + 1}
-                                    </Typography>
-                                    <Tooltip title={node.id}>
-                                        <Typography
-                                            variant="body2"
-                                            gutterBottom
-                                            sx={{
-                                                whiteSpace: "nowrap",
-                                                overflow: "hidden",
-                                                textOverflow: "ellipsis",
-                                            }}
+            <div className="flex-1 overflow-auto">
+                <Box className="container-inner">
+                    <Box className="flex items-center justify-between mb-6">
+                        <div>
+                            <Typography variant="h5" className="font-medium 
text-gray-800 dark:text-gray-100 flex items-center">
+                                <DnsIcon className="mr-2 text-primary 
dark:text-primary-light" /> 
+                                Shard {parseInt(shard) + 1}
+                                {nodesData?.nodes && (
+                                    <Chip 
+                                        label={`${nodesData.nodes.length} 
nodes`} 
+                                        size="small" 
+                                        color="secondary" 
+                                        className="ml-3"
+                                    />
+                                )}
+                            </Typography>
+                            <Typography variant="body2" 
className="text-gray-500 dark:text-gray-400 mt-1">
+                                {cluster} cluster in namespace {namespace}
+                            </Typography>
+                        </div>
+                    </Box>
+
+                    <div className="grid grid-cols-1 sm:grid-cols-2 
lg:grid-cols-3 xl:grid-cols-4 gap-4">
+                        <Box className="col-span-1">
+                            <AddNodeCard namespace={namespace} 
cluster={cluster} shard={shard} />
+                        </Box>
+                        
+                        {nodesData?.nodes && nodesData.nodes.length > 0 ? (
+                            nodesData.nodes.map((node: any, index: number) => {
+                                const roleInfo = getRoleInfo(node.role);
+                                return (
+                                    <Link
+                                        
href={`/namespaces/${namespace}/clusters/${cluster}/shards/${shard}/nodes/${index}`}
+                                        key={index}
+                                        className="col-span-1"
+                                    >
+                                        <ResourceCard
+                                            title={`Node ${index + 1}`}
+                                            tags={[
+                                                { label: node.role, color: 
roleInfo.color as any },
+                                            ]}
                                         >
-                                            ID: {truncateText(node.id, 20)}
-                                        </Typography>
-                                    </Tooltip>
-                                    <Typography variant="body2" gutterBottom>
-                                        Address: {node.addr}
-                                    </Typography>
-                                    <Typography variant="body2" gutterBottom>
-                                        Role: {node.role}
-                                    </Typography>
-                                    <Typography variant="body2" gutterBottom>
-                                        Created At: {new Date(node.created_at 
* 1000).toLocaleString()}
-                                    </Typography>
-                                </CreateCard>
-                            </Link>
-                        )
-                    )}
-                </div>
-            </Container>
+                                            <div className="space-y-2 text-sm 
mt-2">
+                                                <div className="flex 
justify-between items-center">
+                                                    <span 
className="text-gray-500 dark:text-gray-400">ID:</span>
+                                                    <span className="font-mono 
bg-gray-100 dark:bg-dark-border px-2 py-0.5 rounded text-xs overflow-hidden 
text-ellipsis max-w-[120px]" title={node.id}>
+                                                        {truncateText(node.id, 
10)}
+                                                    </span>
+                                                </div>
+                                                
+                                                <div className="flex 
justify-between">
+                                                    <span 
className="text-gray-500 dark:text-gray-400">Address:</span>
+                                                    <span 
className="font-medium">{node.addr}</span>
+                                                </div>
+                                                
+                                                <div className="flex 
justify-between items-center">
+                                                    <span 
className="text-gray-500 dark:text-gray-400">Uptime:</span>
+                                                    <span className="flex 
items-center">
+                                                        <AlarmIcon 
fontSize="small" className="mr-1 text-gray-400 dark:text-gray-500" />
+                                                        
{calculateUptime(node.created_at)}
+                                                    </span>
+                                                </div>
+                                            </div>
+                                        </ResourceCard>
+                                    </Link>
+                                );
+                            })
+                        ) : (
+                            <Box className="col-span-full">
+                                <EmptyState
+                                    title="No nodes found"
+                                    description="Create a node to get started"
+                                    icon={<DeviceHubIcon sx={{ fontSize: 60 }} 
/>}
+                                />
+                            </Box>
+                        )}
+                    </div>
+                </Box>
+            </div>
         </div>
     );
 }
diff --git a/webui/src/app/namespaces/[namespace]/page.tsx 
b/webui/src/app/namespaces/[namespace]/page.tsx
index 6f06b9f..71bbc77 100644
--- a/webui/src/app/namespaces/[namespace]/page.tsx
+++ b/webui/src/app/namespaces/[namespace]/page.tsx
@@ -19,14 +19,18 @@
 
 "use client";
 
-import { Container, Typography } from "@mui/material";
+import { Box, Typography, Chip } from "@mui/material";
 import { NamespaceSidebar } from "../../ui/sidebar";
-import { AddClusterCard, CreateCard } from "../../ui/createCard";
+import { AddClusterCard, ResourceCard } from "../../ui/createCard";
 import { fetchCluster, fetchClusters, fetchNamespaces } from "@/app/lib/api";
 import Link from "next/link";
-import { useRouter } from "next/navigation";
+import { useRouter, notFound } from "next/navigation";
 import { useState, useEffect } from "react";
 import { LoadingSpinner } from "@/app/ui/loadingSpinner";
+import StorageIcon from '@mui/icons-material/Storage';
+import FolderIcon from '@mui/icons-material/Folder';
+import EmptyState from "@/app/ui/emptyState";
+import GridViewIcon from '@mui/icons-material/GridView';
 
 export default function Namespace({
     params,
@@ -44,7 +48,7 @@ export default function Namespace({
 
                 if (!fetchedNamespaces.includes(params.namespace)) {
                     console.error(`Namespace ${params.namespace} not found`);
-                    router.push("/404");
+                    notFound();
                     return;
                 }
 
@@ -78,45 +82,99 @@ export default function Namespace({
     return (
         <div className="flex h-full">
             <NamespaceSidebar />
-            <Container
-                maxWidth={false}
-                disableGutters
-                sx={{ height: "100%", overflowY: "auto", marginLeft: "16px" }}
-            >
-                <div className="flex flex-row flex-wrap">
-                    <AddClusterCard namespace={params.namespace} />
-                    {clusterData.map(
-                        (data, index) =>
-                            data && (
-                                <Link
-                                    
href={`/namespaces/${params.namespace}/clusters/${data.name}`}
-                                    key={index}
-                                >
-                                    <CreateCard>
-                                        <Typography variant="h6" gutterBottom>
-                                            {data.name}
-                                        </Typography>
-                                        <Typography variant="body2" 
gutterBottom>
-                      Version: {data.version}
-                                        </Typography>
-                                        <Typography variant="body2" 
gutterBottom>
-                      Shards: {data.shards.length}
-                                        </Typography>
-                                        <Typography variant="body2" 
gutterBottom>
-                      Slots: {data.shards[0].slot_ranges.join(", ")}
-                                        </Typography>
-                                        <Typography variant="body2" 
gutterBottom>
-                      Target Shard Index: {data.shards[0].target_shard_index}
-                                        </Typography>
-                                        <Typography variant="body2" 
gutterBottom>
-                      Migrating Slot: {data.shards[0].migrating_slot}
-                                        </Typography>
-                                    </CreateCard>
-                                </Link>
-                            )
-                    )}
-                </div>
-            </Container>
+            <div className="flex-1 overflow-auto">
+                <Box className="container-inner">
+                    <Box className="flex items-center justify-between mb-6">
+                        <div>
+                            <Typography variant="h5" className="font-medium 
text-gray-800 dark:text-gray-100 flex items-center">
+                                <FolderIcon className="mr-2 text-primary 
dark:text-primary-light" /> 
+                                {params.namespace}
+                                <Chip 
+                                    label={`${clusterData.length} clusters`} 
+                                    size="small" 
+                                    color="primary" 
+                                    className="ml-3"
+                                />
+                            </Typography>
+                            <Typography variant="body2" 
className="text-gray-500 dark:text-gray-400 mt-1">
+                                Namespace
+                            </Typography>
+                        </div>
+                    </Box>
+
+                    <div className="grid grid-cols-1 sm:grid-cols-2 
lg:grid-cols-3 xl:grid-cols-4 gap-4">
+                        <Box className="col-span-1">
+                            <AddClusterCard namespace={params.namespace} />
+                        </Box>
+                        
+                        {clusterData.length > 0 ? (
+                            clusterData.map((data, index) => (
+                                data && (
+                                    <Link
+                                        
href={`/namespaces/${params.namespace}/clusters/${data.name}`}
+                                        key={index}
+                                        className="col-span-1"
+                                    >
+                                        <ResourceCard
+                                            title={data.name}
+                                            description={`Version: 
${data.version}`}
+                                            tags={[
+                                                { label: 
`${data.shards.length} shards`, color: "secondary" },
+                                                ...(data.shards.some((s: any) 
=> s.migrating_slot >= 0)
+                                                    ? [{ label: "Migrating", 
color: "warning" }]
+                                                    : [])
+                                            ]}
+                                        >
+                                            <div className="space-y-2 text-sm 
my-2">
+                                                <div className="flex 
justify-between">
+                                                    <span 
className="text-gray-500 dark:text-gray-400">Slots:</span>
+                                                    <span 
className="font-medium">
+                                                        
{data.shards[0]?.slot_ranges.length > 0 ? 
+                                                            
(data.shards[0].slot_ranges.length > 2 ? 
+                                                                
`${data.shards[0].slot_ranges[0]}, ${data.shards[0].slot_ranges[1]}, ...` : 
+                                                                
data.shards[0].slot_ranges.join(', ')) : 
+                                                            'None'}
+                                                    </span>
+                                                </div>
+                                                
+                                                
{data.shards[0]?.target_shard_index >= 0 && (
+                                                    <div className="flex 
justify-between">
+                                                        <span 
className="text-gray-500 dark:text-gray-400">Target Shard:</span>
+                                                        <span 
className="font-medium">{data.shards[0].target_shard_index + 1}</span>
+                                                    </div>
+                                                )}
+                                                
+                                                
{data.shards[0]?.migrating_slot >= 0 && (
+                                                    <div className="flex 
justify-between">
+                                                        <span 
className="text-gray-500 dark:text-gray-400">Migrating:</span>
+                                                        <Chip 
+                                                            label={`Slot 
${data.shards[0].migrating_slot}`} 
+                                                            size="small"
+                                                            color="warning"
+                                                        />
+                                                    </div>
+                                                )}
+                                            </div>
+                                            
+                                            <div className="mt-3 flex 
justify-center">
+                                                <GridViewIcon sx={{ fontSize: 
40 }} className="text-primary/20 dark:text-primary-light/30" />
+                                            </div>
+                                        </ResourceCard>
+                                    </Link>
+                                )
+                            ))
+                        ) : (
+                            <Box className="col-span-full">
+                                <EmptyState
+                                    title="No clusters found"
+                                    description="Create a cluster to get 
started"
+                                    icon={<StorageIcon sx={{ fontSize: 60 }} 
/>}
+                                />
+                            </Box>
+                        )}
+                    </div>
+                </Box>
+            </div>
         </div>
     );
 }
diff --git a/webui/src/app/namespaces/page.tsx 
b/webui/src/app/namespaces/page.tsx
index ae0dfbf..2f5daf5 100644
--- a/webui/src/app/namespaces/page.tsx
+++ b/webui/src/app/namespaces/page.tsx
@@ -19,13 +19,16 @@
 
 "use client";
 
-import { Box, Container, Card, Link, Typography } from "@mui/material";
+import { Container, Typography, Paper, Box } from "@mui/material";
 import { NamespaceSidebar } from "../ui/sidebar";
 import { useRouter } from "next/navigation";
 import { useState, useEffect } from "react";
 import { fetchNamespaces } from "../lib/api";
 import { LoadingSpinner } from "../ui/loadingSpinner";
-import { CreateCard } from "../ui/createCard";
+import { CreateCard, ResourceCard } from "../ui/createCard";
+import Link from "next/link";
+import FolderIcon from '@mui/icons-material/Folder';
+import EmptyState from "../ui/emptyState";
 
 export default function Namespace() {
     const [namespaces, setNamespaces] = useState<string[]>([]);
@@ -36,7 +39,6 @@ export default function Namespace() {
         const fetchData = async () => {
             try {
                 const fetchedNamespaces = await fetchNamespaces();
-
                 setNamespaces(fetchedNamespaces);
             } catch (error) {
                 console.error("Error fetching namespaces:", error);
@@ -55,34 +57,42 @@ export default function Namespace() {
     return (
         <div className="flex h-full">
             <NamespaceSidebar />
-            <Container
-                maxWidth={false}
-                disableGutters
-                sx={{ height: "100%", overflowY: "auto", marginLeft: "16px" }}
-            >
-                <div className="flex flex-row flex-wrap">
-                    {namespaces.length !== 0 ? (
-                        namespaces.map(
-                            (namespace, index) =>
-                                namespace && (
-                                    <Link key={namespace} 
href={`/namespaces/${namespace}`}>
-                                        <CreateCard>
-                                            <Typography variant="h6">
-                                                {namespace} Namespace
-                                            </Typography>
-                                        </CreateCard>
-                                    </Link>
-                                )
-                        )
+            <div className="flex-1 overflow-auto">
+                <Box className="container-inner">
+                    <Box className="flex items-center justify-between mb-6">
+                        <Typography variant="h5" className="font-medium 
text-gray-800 dark:text-gray-100">
+                            Namespaces
+                        </Typography>
+                    </Box>
+
+                    {namespaces.length > 0 ? (
+                        <div className="grid grid-cols-1 sm:grid-cols-2 
lg:grid-cols-3 xl:grid-cols-4 gap-4">
+                            {namespaces.map((namespace) => (
+                                <Link key={namespace} 
href={`/namespaces/${namespace}`} passHref>
+                                    <ResourceCard 
+                                        title={namespace} 
+                                        description="Namespace" 
+                                        tags={[{ label: "namespace", color: 
"primary" }]}
+                                    >
+                                        <div className="flex items-center 
justify-center h-20 mt-4">
+                                            <FolderIcon 
+                                                sx={{ fontSize: 60 }} 
+                                                className="text-primary/20 
dark:text-primary-light/30" 
+                                            />
+                                        </div>
+                                    </ResourceCard>
+                                </Link>
+                            ))}
+                        </div>
                     ) : (
-                        <Box>
-                            <Typography variant="h6">
-                No namespaces found, create one to get started
-                            </Typography>
-                        </Box>
+                        <EmptyState
+                            title="No namespaces found"
+                            description="Create a namespace to get started"
+                            icon={<FolderIcon sx={{ fontSize: 60 }} />}
+                        />
                     )}
-                </div>
-            </Container>
+                </Box>
+            </div>
         </div>
     );
 }
diff --git a/webui/src/app/not-found.tsx b/webui/src/app/not-found.tsx
new file mode 100644
index 0000000..25d957d
--- /dev/null
+++ b/webui/src/app/not-found.tsx
@@ -0,0 +1,67 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License. 
+ */
+
+'use client';
+
+import { Button, Typography, Box } from "@mui/material";
+import Link from "next/link";
+import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
+import HomeIcon from '@mui/icons-material/Home';
+import ArrowBackIcon from '@mui/icons-material/ArrowBack';
+import { useRouter } from "next/navigation";
+
+export default function NotFound() {
+  const router = useRouter();
+  
+  return (
+    <div className="flex items-center justify-center min-h-[calc(100vh-64px)]">
+      <Box className="text-center p-8 max-w-lg">
+        <ErrorOutlineIcon sx={{ fontSize: 80 }} className="text-error mb-4" />
+        
+        <Typography variant="h3" className="mb-2 font-bold text-gray-900 
dark:text-gray-100">
+          Page Not Found
+        </Typography>
+        
+        <Typography variant="body1" className="mb-8 text-gray-600 
dark:text-gray-300">
+          We couldn't find the page you're looking for. It might have been 
moved, deleted, or never existed.
+        </Typography>
+        
+        <div className="flex flex-wrap justify-center gap-4">
+          <Button 
+            variant="contained" 
+            color="primary"
+            startIcon={<HomeIcon />}
+            component={Link}
+            href="/"
+          >
+            Go to Home
+          </Button>
+          
+          <Button 
+            variant="outlined" 
+            startIcon={<ArrowBackIcon />}
+            onClick={() => router.back()}
+          >
+            Go Back
+          </Button>
+        </div>
+      </Box>
+    </div>
+  );
+}
diff --git a/webui/src/app/page.tsx b/webui/src/app/page.tsx
index 4a40fe5..9c46b5e 100644
--- a/webui/src/app/page.tsx
+++ b/webui/src/app/page.tsx
@@ -17,19 +17,186 @@
  * under the License. 
  */
 
-import { Button, Container, Typography } from "@mui/material";
+"use client";
+
+import { Button, Typography, Box, Paper, Grid } from "@mui/material";
+import Image from "next/image";
+import { useRouter } from "next/navigation";
+import { useTheme } from "./theme-provider";
+import StorageIcon from '@mui/icons-material/Storage';
+import DnsIcon from '@mui/icons-material/Dns';
+import DeviceHubIcon from '@mui/icons-material/DeviceHub';
+import BarChartIcon from '@mui/icons-material/BarChart';
+import GitHubIcon from '@mui/icons-material/GitHub';
+import LaunchIcon from '@mui/icons-material/Launch';
+import MenuBookIcon from '@mui/icons-material/MenuBook';
+import Link from "next/link";
 
 export default function Home() {
+    const router = useRouter();
+    const { isDarkMode } = useTheme();
+    const currentYear = new Date().getFullYear(); // minor change: compute 
current year once
+
+    const features = [
+        {
+            title: "Cluster Management",
+            description: "Create, modify, and monitor Redis clusters with an 
intuitive interface",
+            icon: <StorageIcon sx={{ fontSize: 40 }} className="text-primary 
dark:text-primary-light" />
+        },
+        {
+            title: "Shard Distribution",
+            description: "Efficiently distribute data across multiple shards 
for optimal performance",
+            icon: <DnsIcon sx={{ fontSize: 40 }} className="text-primary 
dark:text-primary-light" />
+        },
+        {
+            title: "Node Monitoring",
+            description: "Monitor node health, performance, and connectivity 
in real-time",
+            icon: <DeviceHubIcon sx={{ fontSize: 40 }} className="text-primary 
dark:text-primary-light" />
+        },
+        {
+            title: "Advanced Metrics",
+            description: "View detailed performance metrics to optimize your 
infrastructure",
+            icon: <BarChartIcon sx={{ fontSize: 40 }} className="text-primary 
dark:text-primary-light" />
+        }
+    ];
+
+    const resources = [
+        {
+            title: "Documentation",
+            description: "Learn how to use Kvrocks Controller",
+            icon: <MenuBookIcon sx={{ fontSize: 30 }} />,
+            url: "https://kvrocks.apache.org/docs/";
+        },
+        {
+            title: "GitHub Repository",
+            description: "View the source code on GitHub",
+            icon: <GitHubIcon sx={{ fontSize: 30 }} />,
+            url: "https://github.com/apache/kvrocks-controller";
+        }
+    ];
+
     return (
-        <div
-            style={{minHeight: 'calc(100vh - 64px)', height: 'calc(100vh - 
64px)'}}
-            className={'flex flex-col items-center justify-center space-y-2 
h-full'}
-        >
-            <Typography variant="h3">Kvrocks Controller UI</Typography>
-            <Typography variant="body1">Work in progress...</Typography>
-            <Button size="large" variant="outlined" sx={{ textTransform: 
'none' }} href="https://github.com/apache/kvrocks-controller/issues/135";>
-                Click here to submit your suggestions
-            </Button>
+        <div className="flex flex-col min-h-[calc(100vh-64px)] 
bg-gradient-to-b from-white to-gray-50 dark:from-dark dark:to-dark-paper">
+            {/* Hero Section */}
+            <section className="flex-grow flex flex-col items-center 
justify-center px-6 py-12 text-center">
+                <div className="max-w-3xl mx-auto">
+                    <div className="mb-8 mx-auto relative w-40 h-40">
+                        <Image
+                            src="/logo.svg"
+                            alt="Kvrocks Logo"
+                            layout="fill"
+                            objectFit="contain"
+                            priority
+                            className="animate-[pulse_4s_ease-in-out_infinite]"
+                        />
+                    </div>
+                    
+                    <Typography variant="h2" component="h1" 
className="font-bold mb-4 text-gray-900 dark:text-gray-100">
+                        Apache Kvrocks <span className="text-primary 
dark:text-primary-light">Controller</span>
+                    </Typography>
+                    
+                    <Typography variant="h6" className="mb-8 text-gray-600 
dark:text-gray-300 max-w-2xl mx-auto">
+                        A web management interface for Apache Kvrocks 
clusters, enabling efficient distribution, monitoring, and maintenance of your 
Redis compatible database infrastructure.
+                    </Typography>
+                    
+                    <div className="flex flex-wrap justify-center gap-4">
+                        <Button 
+                            variant="contained" 
+                            size="large"
+                            className="bg-primary hover:bg-primary-dark px-8 
py-3 text-lg"
+                            onClick={() => router.push('/namespaces')}
+                        >
+                            Get Started
+                        </Button>
+                        
+                        <Button 
+                            variant="outlined" 
+                            size="large"
+                            className="border-primary text-primary 
hover:bg-primary hover:text-white dark:border-primary-light 
dark:text-primary-light px-8 py-3 text-lg"
+                            
href="https://github.com/apache/kvrocks-controller/issues";
+                            target="_blank"
+                        >
+                            Submit Feedback
+                        </Button>
+                    </div>
+                </div>
+            </section>
+
+            {/* Features Section */}
+            <section className="py-16 px-6 bg-gray-50 dark:bg-dark-paper">
+                <div className="max-w-6xl mx-auto">
+                    <Typography variant="h4" component="h2" 
className="text-center font-bold mb-12 text-gray-900 dark:text-gray-100">
+                        Key Features
+                    </Typography>
+                    
+                    <Grid container spacing={4}>
+                        {features.map((feature, index) => (
+                            <Grid item xs={12} sm={6} md={3} key={index}>
+                                <Paper 
+                                    elevation={0}
+                                    className="card h-full p-6 flex flex-col 
items-center text-center"
+                                >
+                                    <div className="mb-4">
+                                        {feature.icon}
+                                    </div>
+                                    <Typography variant="h6" className="mb-2 
font-medium">
+                                        {feature.title}
+                                    </Typography>
+                                    <Typography variant="body2" 
className="text-gray-600 dark:text-gray-300">
+                                        {feature.description}
+                                    </Typography>
+                                </Paper>
+                            </Grid>
+                        ))}
+                    </Grid>
+                </div>
+            </section>
+
+            {/* Resources Section */}
+            <section className="py-16 px-6">
+                <div className="max-w-4xl mx-auto">
+                    <Typography variant="h4" component="h2" 
className="text-center font-bold mb-12 text-gray-900 dark:text-gray-100">
+                        Resources
+                    </Typography>
+                    
+                    <Grid container spacing={4} justifyContent="center">
+                        {resources.map((resource, index) => (
+                            <Grid item xs={12} sm={6} key={index}>
+                                <Link href={resource.url} target="_blank" 
rel="noopener noreferrer">
+                                    <Paper 
+                                        elevation={0}
+                                        className="card h-full p-6 flex 
flex-col hover:border-primary dark:hover:border-primary-light transition-all"
+                                    >
+                                        <div className="flex items-center 
mb-4">
+                                            <div className="p-2 rounded-full 
bg-primary/10 dark:bg-primary-dark/20 mr-4">
+                                                {resource.icon}
+                                            </div>
+                                            <div>
+                                                <Typography variant="h6" 
className="flex items-center">
+                                                    {resource.title} 
+                                                    <LaunchIcon 
fontSize="small" className="ml-2 text-gray-400" />
+                                                </Typography>
+                                                <Typography variant="body2" 
className="text-gray-600 dark:text-gray-300">
+                                                    {resource.description}
+                                                </Typography>
+                                            </div>
+                                        </div>
+                                    </Paper>
+                                </Link>
+                            </Grid>
+                        ))}
+                    </Grid>
+                </div>
+            </section>
+
+            {/* Footer */}
+            <footer className="py-6 px-6 border-t border-light-border 
dark:border-dark-border">
+                <div className="max-w-6xl mx-auto text-center">
+                    <Typography variant="body2" className="text-gray-500 
dark:text-gray-400">
+                        Copyright © {currentYear} The Apache Software 
Foundation. Apache Kvrocks, Kvrocks, and its feather logo are trademarks of The 
Apache Software Foundation. Redis and its cube logo are registered trademarks 
of Redis Ltd. Apache Kvrocks Controller is released under Apache License, 
Version 2.0.
+                    </Typography>
+                </div>
+            </footer>
         </div>
     );
-}
+}
\ No newline at end of file
diff --git a/webui/src/app/theme-provider.tsx b/webui/src/app/theme-provider.tsx
new file mode 100644
index 0000000..1b7e18f
--- /dev/null
+++ b/webui/src/app/theme-provider.tsx
@@ -0,0 +1,109 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License. 
+ */
+
+"use client";
+
+import { createContext, useContext, useEffect, useState } from "react";
+import { ThemeProvider as MuiThemeProvider, createTheme } from 
"@mui/material/styles";
+import CssBaseline from "@mui/material/CssBaseline";
+
+type ThemeContextType = {
+  isDarkMode: boolean;
+  toggleTheme: () => void;
+};
+
+const ThemeContext = createContext<ThemeContextType>({
+  isDarkMode: false,
+  toggleTheme: () => {}
+});
+
+export const useTheme = () => useContext(ThemeContext);
+
+export function ThemeProvider({ children }: { children: React.ReactNode }) {
+  const [isDarkMode, setIsDarkMode] = useState(false);
+
+  useEffect(() => {
+    // Check if user has already set a preference
+    const storedTheme = localStorage.getItem("theme");
+    const prefersDark = window.matchMedia("(prefers-color-scheme: 
dark)").matches;
+    
+    if (storedTheme === "dark" || (!storedTheme && prefersDark)) {
+      setIsDarkMode(true);
+      document.documentElement.classList.add("dark");
+    } else {
+      setIsDarkMode(false);
+      document.documentElement.classList.remove("dark");
+    }
+  }, []);
+
+  const toggleTheme = () => {
+    setIsDarkMode((prev) => {
+      const newMode = !prev;
+      if (newMode) {
+        document.documentElement.classList.add("dark");
+        localStorage.setItem("theme", "dark");
+      } else {
+        document.documentElement.classList.remove("dark");
+        localStorage.setItem("theme", "light");
+      }
+      return newMode;
+    });
+  };
+
+  // Create MUI theme based on current mode
+  const theme = createTheme({
+    palette: {
+      mode: isDarkMode ? "dark" : "light",
+      primary: {
+        main: "#1976d2",
+        light: "#42a5f5",
+        dark: "#1565c0",
+        contrastText: "#fff",
+      },
+      secondary: {
+        main: "#9c27b0",
+        light: "#ba68c8",
+        dark: "#7b1fa2",
+        contrastText: "#fff",
+      },
+      background: {
+        default: isDarkMode ? "#121212" : "#fafafa",
+        paper: isDarkMode ? "#1e1e1e" : "#ffffff",
+      },
+    },
+    components: {
+      MuiPaper: {
+        styleOverrides: {
+          root: {
+            transition: "background-color 0.3s ease",
+          },
+        },
+      },
+    },
+  });
+
+  return (
+    <ThemeContext.Provider value={{ isDarkMode, toggleTheme }}>
+      <MuiThemeProvider theme={theme}>
+        <CssBaseline />
+        {children}
+      </MuiThemeProvider>
+    </ThemeContext.Provider>
+  );
+}
diff --git a/webui/src/app/ui/banner.tsx b/webui/src/app/ui/banner.tsx
index b9b4d1c..69850e4 100644
--- a/webui/src/app/ui/banner.tsx
+++ b/webui/src/app/ui/banner.tsx
@@ -17,9 +17,16 @@
  * under the License. 
  */
 
-import { AppBar, Container, Toolbar } from "@mui/material";
+"use client";
+
+import { AppBar, Container, Toolbar, IconButton, Box, Tooltip, Typography } 
from "@mui/material";
 import Image from "next/image";
 import NavLinks from "./nav-links";
+import { useTheme } from "../theme-provider";
+import Brightness4Icon from "@mui/icons-material/Brightness4";
+import Brightness7Icon from "@mui/icons-material/Brightness7";
+import GitHubIcon from "@mui/icons-material/GitHub";
+import { usePathname } from "next/navigation";
 
 const links = [
     {
@@ -30,18 +37,69 @@ const links = [
         title: 'Namespaces'
     },{
         url: 'https://kvrocks.apache.org',
-        title: 'community',
+        title: 'Documentation',
         _blank: true
     },
-]
+];
 
 export default function Banner() {
-    return (<AppBar>
-        <Container maxWidth={false}>
-            <Toolbar className="space-x-4">
-                <Image src="/logo.svg" width={40} height={40} 
alt='logo'></Image>
-                <NavLinks links={links}/>
-            </Toolbar>
-        </Container>
-    </AppBar>)
+    const { isDarkMode, toggleTheme } = useTheme();
+    const pathname = usePathname();
+    
+    // Generate breadcrumb from pathname
+    const breadcrumbs = pathname.split('/').filter(Boolean);
+    
+    return (
+        <AppBar position="fixed" elevation={1} className="bg-white 
dark:bg-dark-paper text-gray-800 dark:text-gray-100">
+            <Container maxWidth={false}>
+                <Toolbar className="flex justify-between">
+                    <div className="flex items-center">
+                        <Image src="/logo.svg" width={40} height={40} 
alt='logo' className="mr-4" />
+                        <Typography variant="h6" component="div" 
className="hidden sm:block font-medium text-primary dark:text-primary-light">
+                            Apache Kvrocks Controller
+                        </Typography>
+                    </div>
+                    
+                    <Box className="hidden md:flex items-center space-x-1">
+                        <NavLinks links={links} />
+                    </Box>
+                    
+                    <Box className="flex items-center">
+                        {breadcrumbs.length > 0 && (
+                            <Box className="hidden md:flex items-center 
text-sm px-4 py-1 bg-gray-100 dark:bg-dark-border rounded-md mr-4">
+                                {breadcrumbs.map((breadcrumb, i) => (
+                                    <Typography 
+                                        key={i} 
+                                        variant="body2" 
+                                        className="text-gray-500 
dark:text-gray-400"
+                                    >
+                                        {i > 0 && " / "}
+                                        {breadcrumb}
+                                    </Typography>
+                                ))}
+                            </Box>
+                        )}
+                        
+                        <Tooltip title="Toggle dark mode">
+                            <IconButton onClick={toggleTheme} color="inherit" 
size="small">
+                                {isDarkMode ? <Brightness7Icon /> : 
<Brightness4Icon />}
+                            </IconButton>
+                        </Tooltip>
+                        
+                        <Tooltip title="GitHub Repository">
+                            <IconButton 
+                                color="inherit"
+                                
href="https://github.com/apache/kvrocks-controller";
+                                target="_blank"
+                                size="small"
+                                className="ml-2"
+                            >
+                                <GitHubIcon />
+                            </IconButton>
+                        </Tooltip>
+                    </Box>
+                </Toolbar>
+            </Container>
+        </AppBar>
+    );
 }
\ No newline at end of file
diff --git a/webui/src/app/ui/createCard.tsx b/webui/src/app/ui/createCard.tsx
index d09f498..d3e6b32 100644
--- a/webui/src/app/ui/createCard.tsx
+++ b/webui/src/app/ui/createCard.tsx
@@ -19,7 +19,7 @@
 
 "use client";
 
-import { Card, Box } from "@mui/material";
+import { Box, Paper, Chip, Tooltip } from "@mui/material";
 import React, { ReactNode } from "react";
 import {
     ClusterCreation,
@@ -33,56 +33,38 @@ import { FontAwesomeIcon } from 
"@fortawesome/react-fontawesome";
 
 interface CreateCardProps {
   children: ReactNode;
+  className?: string;
 }
 
-export const CreateCard: React.FC<CreateCardProps> = ({ children }) => {
+export const CreateCard: React.FC<CreateCardProps> = ({ children, className = 
"" }) => {
     return (
-        <Box sx={{ position: "relative", display: "inline-block" }}>
-            <Card
-                variant="outlined"
-                sx={{
-                    width: "370px",
-                    height: "200px",
-                    padding: "16px",
-                    margin: "16px",
-                    borderRadius: "16px",
-                    transition: "transform 0.1s, box-shadow 0.3s",
-                    boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)",
-                    "&:hover": {
-                        transform: "scale(1.01)",
-                        boxShadow: "0 4px 8px rgba(0, 0, 0, 0.2)",
-                    },
-                    cursor: "pointer",
-                    display: "flex",
-                    flexDirection: "column",
-                    alignItems: "center",
-                    justifyContent: "center",
-                }}
+        <Box className="p-3">
+            <Paper
+                elevation={0}
+                className={`card w-72 h-52 transition-all ${className}`}
             >
                 {children}
-            </Card>
+            </Paper>
         </Box>
     );
 };
 
 export const AddClusterCard = ({ namespace }: { namespace: string }) => {
     return (
-        <CreateCard>
-            <FontAwesomeIcon
-                icon={faCirclePlus}
-                size="4x"
-                style={{
-                    color: "#e0e0e0",
-                    marginBottom: "8px",
-                    transition: "color 0.2s",
-                }}
-            />
-            <div className="mt-4 flex flex-row items-end ">
-                <div className="mr-0.5">
-                    <ClusterCreation position="card" namespace={namespace} />
-                </div>
-                <div className="ml-.5">
-                    <ImportCluster position="card" namespace={namespace} />
+        <CreateCard className="bg-gradient-to-br from-primary-light/5 
to-primary/10 dark:from-primary-dark/10 dark:to-primary/20 flex items-center 
justify-center">
+            <div className="text-center">
+                <FontAwesomeIcon
+                    icon={faCirclePlus}
+                    size="4x"
+                    className="text-primary/40 dark:text-primary-light/40 mb-4"
+                />
+                <div className="flex flex-row items-center justify-center 
space-x-2 mt-2">
+                    <div className="text-sm leading-tight">
+                        <ClusterCreation position="card" namespace={namespace} 
/>
+                    </div>
+                    <div className="text-sm leading-tight">
+                        <ImportCluster position="card" namespace={namespace} />
+                    </div>
                 </div>
             </div>
         </CreateCard>
@@ -97,25 +79,19 @@ export const AddShardCard = ({
   cluster: string;
 }) => {
     return (
-        <CreateCard>
-            <FontAwesomeIcon
-                icon={faCirclePlus}
-                size="4x"
-                style={{
-                    color: "#e0e0e0",
-                    marginBottom: "8px",
-                    transition: "color 0.2s",
-                }}
-            />
-            <div className="mt-4  flex flex-row items-end">
-                <div className="mr-0.5">
+        <CreateCard className="bg-gradient-to-br from-primary-light/5 
to-primary/10 dark:from-primary-dark/10 dark:to-primary/20 flex items-center 
justify-center">
+            <div className="text-center">
+                <FontAwesomeIcon
+                    icon={faCirclePlus}
+                    size="4x"
+                    className="text-primary/40 dark:text-primary-light/40 mb-6"
+                />
+                <div className="flex flex-row items-center justify-center 
space-x-3 mt-4">
                     <ShardCreation
                         position="card"
                         namespace={namespace}
                         cluster={cluster}
                     />
-                </div>
-                <div className="ml-.5">
                     <MigrateSlot
                         position="card"
                         namespace={namespace}
@@ -137,23 +113,62 @@ export const AddNodeCard = ({
   shard: string;
 }) => {
     return (
-        <CreateCard>
-            <FontAwesomeIcon
-                icon={faCirclePlus}
-                size="4x"
-                style={{
-                    color: "#e0e0e0",
-                    marginBottom: "8px",
-                    transition: "color 0.2s",
-                }}
-            />
-            <div className="mt-4">
-                <NodeCreation
-                    position="card"
-                    namespace={namespace}
-                    cluster={cluster}
-                    shard={shard}
+        <CreateCard className="bg-gradient-to-br from-primary-light/5 
to-primary/10 dark:from-primary-dark/10 dark:to-primary/20 flex items-center 
justify-center">
+            <div className="text-center">
+                <FontAwesomeIcon
+                    icon={faCirclePlus}
+                    size="4x"
+                    className="text-primary/40 dark:text-primary-light/40 mb-6"
                 />
+                <div className="mt-4">
+                    <NodeCreation
+                        position="card"
+                        namespace={namespace}
+                        cluster={cluster}
+                        shard={shard}
+                    />
+                </div>
+            </div>
+        </CreateCard>
+    );
+};
+
+export const ResourceCard = ({ 
+    title, 
+    description,
+    tags,
+    children 
+}: { 
+    title: string; 
+    description?: string;
+    tags?: Array<{label: string, color?: string}>;
+    children: ReactNode; 
+}) => {
+    return (
+        <CreateCard>
+            <div className="flex flex-col h-full">
+                <div className="font-medium text-lg mb-1">{title}</div>
+                {description && (
+                    <div className="text-sm text-gray-500 dark:text-gray-400 
mb-3">
+                        {description}
+                    </div>
+                )}
+                <div className="flex-grow">
+                    {children}
+                </div>
+                {tags && tags.length > 0 && (
+                    <div className="flex flex-wrap gap-1 mt-3">
+                        {tags.map((tag, i) => (
+                            <Chip 
+                                key={i} 
+                                label={tag.label} 
+                                size="small" 
+                                color={tag.color as any || "default"}
+                                className="text-xs"
+                            />
+                        ))}
+                    </div>
+                )}
             </div>
         </CreateCard>
     );
diff --git a/webui/src/app/ui/emptyState.tsx b/webui/src/app/ui/emptyState.tsx
new file mode 100644
index 0000000..a329c87
--- /dev/null
+++ b/webui/src/app/ui/emptyState.tsx
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React, { ReactNode } from 'react';
+import { Box, Paper, Typography, Button } from '@mui/material';
+
+interface EmptyStateProps {
+    title: string;
+    description: string;
+    icon?: ReactNode;
+    action?: {
+        label: string;
+        onClick: () => void;
+    };
+}
+
+const EmptyState: React.FC<EmptyStateProps> = ({ title, description, icon, 
action }) => {
+    return (
+        <Paper
+            elevation={0}
+            className="border border-light-border dark:border-dark-border 
rounded-lg bg-white dark:bg-dark-paper p-10 text-center max-w-md mx-auto"
+        >
+            {icon && (
+                <Box className="flex justify-center mb-4 text-gray-400 
dark:text-gray-500">
+                    {icon}
+                </Box>
+            )}
+            <Typography variant="h6" className="font-medium mb-2 text-gray-800 
dark:text-gray-100">
+                {title}
+            </Typography>
+            <Typography variant="body2" className="text-gray-500 
dark:text-gray-400 mb-6">
+                {description}
+            </Typography>
+            {action && (
+                <Button
+                    variant="contained"
+                    className="btn btn-primary"
+                    onClick={action.onClick}
+                >
+                    {action.label}
+                </Button>
+            )}
+        </Paper>
+    );
+};
+
+export default EmptyState;
diff --git a/webui/src/app/ui/formDialog.tsx b/webui/src/app/ui/formDialog.tsx
index 2e26df0..157ae86 100644
--- a/webui/src/app/ui/formDialog.tsx
+++ b/webui/src/app/ui/formDialog.tsx
@@ -23,6 +23,7 @@ import {
     Dialog,
     DialogActions,
     DialogContent,
+    DialogContentText,
     DialogTitle,
     Snackbar,
     TextField,
@@ -34,22 +35,25 @@ import {
     Select,
     InputLabel,
     FormControl,
+    Paper,
+    CircularProgress,
 } from "@mui/material";
 import React, { useCallback, useState, FormEvent } from "react";
-  
-  interface FormDialogProps {
+import AddIcon from '@mui/icons-material/Add';
+
+interface FormDialogProps {
     position: string;
     title: string;
     submitButtonLabel: string;
     formFields: {
-      name: string;
-      label: string;
-      type: string;
-      required?: boolean;
-      values?: string[];
+        name: string;
+        label: string;
+        type: string;
+        required?: boolean;
+        values?: string[];
     }[];
     onSubmit: (formData: FormData) => Promise<string | undefined>;
-  }
+}
   
 const FormDialog: React.FC<FormDialogProps> = ({
     position,
@@ -63,6 +67,7 @@ const FormDialog: React.FC<FormDialogProps> = ({
     const closeDialog = useCallback(() => setShowDialog(false), []);
     const [errorMessage, setErrorMessage] = useState("");
     const [arrayValues, setArrayValues] = useState<{ [key: string]: string[] 
}>({});
+    const [submitting, setSubmitting] = useState(false);
   
     const handleArrayChange = (name: string, value: string[]) => {
         setArrayValues({ ...arrayValues, [name]: value });
@@ -70,40 +75,70 @@ const FormDialog: React.FC<FormDialogProps> = ({
   
     const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
         event.preventDefault();
+        setSubmitting(true);
         const formData = new FormData(event.currentTarget);
   
         Object.keys(arrayValues).forEach((name) => {
             formData.append(name, JSON.stringify(arrayValues[name]));
         });
   
-        const error = await onSubmit(formData);
-        if (error) {
-            setErrorMessage(error);
-        } else {
-            closeDialog();
+        try {
+            const error = await onSubmit(formData);
+            if (error) {
+                setErrorMessage(error);
+            } else {
+                closeDialog();
+            }
+        } catch (error) {
+            setErrorMessage("An unexpected error occurred");
+        } finally {
+            setSubmitting(false);
         }
     };
   
     return (
         <>
             {position === "card" ? (
-                <Button variant="contained" onClick={openDialog}>
+                <Button 
+                    variant="contained"
+                    onClick={openDialog}
+                    className="btn btn-primary py-1 px-3 text-xs"
+                    startIcon={<AddIcon sx={{ fontSize: 16 }} />}
+                    size="small"
+                >
                     {title}
                 </Button>
             ) : (
-                <Button variant="outlined" onClick={openDialog}>
+                <Button 
+                    variant="outlined"
+                    onClick={openDialog}
+                    className="btn btn-outline w-full"
+                    startIcon={<AddIcon />}
+                >
                     {title}
                 </Button>
             )}
   
-            <Dialog open={showDialog} onClose={closeDialog}>
+            <Dialog 
+                open={showDialog} 
+                onClose={closeDialog}
+                PaperProps={{
+                    className: "rounded-lg shadow-xl"
+                }}
+                maxWidth="sm"
+                fullWidth
+            >
                 <form onSubmit={handleSubmit}>
-                    <DialogTitle>{title}</DialogTitle>
-                    <DialogContent sx={{ width: "500px" }}>
+                    <DialogTitle className="bg-gray-50 dark:bg-dark-paper 
border-b border-light-border dark:border-dark-border px-6 py-4">
+                        <Typography variant="h6" className="font-medium">
+                            {title}
+                        </Typography>
+                    </DialogTitle>
+                    <DialogContent className="p-6">
                         {formFields.map((field, index) =>
                             field.type === "array" ? (
-                                <Box key={index} mb={2}>
-                                    <Typography variant="subtitle1" 
className="mt-2 mb-2">
+                                <Box key={index} mb={3} mt={index === 0 ? 3 : 
2}>
+                                    <Typography variant="subtitle2" 
className="mb-2 font-medium">
                                         {field.label}
                                     </Typography>
                                     <Autocomplete
@@ -120,6 +155,8 @@ const FormDialog: React.FC<FormDialogProps> = ({
                                                     {...getTagProps({ index })}
                                                     key={index}
                                                     label={option}
+                                                    size="small"
+                                                    
className="bg-primary-light/20 dark:bg-primary-dark/20"
                                                 />
                                             ))
                                         }
@@ -129,19 +166,23 @@ const FormDialog: React.FC<FormDialogProps> = ({
                                                 variant="outlined"
                                                 label={`Add ${field.label}*`}
                                                 placeholder="Type and press 
enter"
+                                                size="small"
+                                                className="bg-white 
dark:bg-dark-paper rounded-md"
                                             />
                                         )}
                                     />
                                 </Box>
                             ) : field.type === "enum" ? (
-                                <FormControl key={index} fullWidth sx={{ mt:3 
}}>
-                                    <InputLabel>{field.label}</InputLabel>
+                                <FormControl key={index} fullWidth sx={{ mt: 
index === 0 ? 3 : 3, mb: 2 }}>
+                                    <InputLabel 
id={`${field.name}-label`}>{field.label}</InputLabel>
                                     <Select
+                                        labelId={`${field.name}-label`}
                                         name={field.name}
                                         label={field.label}
                                         required={field.required}
                                         defaultValue=""
-                                        multiple={false}
+                                        size="small"
+                                        className="bg-white dark:bg-dark-paper 
rounded-md"
                                     >
                                         {field.values?.map((value, index) => (
                                             <MenuItem key={index} 
value={value}>
@@ -159,16 +200,35 @@ const FormDialog: React.FC<FormDialogProps> = ({
                                     label={field.label}
                                     type={field.type}
                                     fullWidth
-                                    variant="standard"
+                                    variant="outlined"
                                     margin="normal"
-                                    sx={{ mb: 2 }}
+                                    size="small"
+                                    className="bg-white dark:bg-dark-paper 
rounded-md"
+                                    sx={{ 
+                                        mt: index === 0 ? 3 : 3, 
+                                        mb: 1.5 
+                                    }}
                                 />
                             )
                         )}
                     </DialogContent>
-                    <DialogActions>
-                        <Button onClick={closeDialog}>Cancel</Button>
-                        <Button type="submit">{submitButtonLabel}</Button>
+                    <DialogActions className="p-4 border-t border-light-border 
dark:border-dark-border bg-gray-50 dark:bg-dark-paper">
+                        <Button 
+                            onClick={closeDialog}
+                            disabled={submitting}
+                            className="text-gray-600 dark:text-gray-300 
hover:bg-gray-100 dark:hover:bg-dark-border"
+                        >
+                            Cancel
+                        </Button>
+                        <Button 
+                            type="submit" 
+                            variant="contained"
+                            disabled={submitting}
+                            className="btn-primary"
+                            startIcon={submitting ? <CircularProgress 
size={16} color="inherit" /> : null}
+                        >
+                            {submitting ? 'Processing...' : submitButtonLabel}
+                        </Button>
                     </DialogActions>
                 </form>
             </Dialog>
@@ -177,12 +237,13 @@ const FormDialog: React.FC<FormDialogProps> = ({
                 autoHideDuration={5000}
                 onClose={() => setErrorMessage("")}
                 anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
+                className="mb-4"
             >
                 <Alert
                     onClose={() => setErrorMessage("")}
                     severity="error"
                     variant="filled"
-                    sx={{ width: "100%" }}
+                    className="shadow-lg"
                 >
                     {errorMessage}
                 </Alert>
@@ -192,4 +253,3 @@ const FormDialog: React.FC<FormDialogProps> = ({
 };
   
 export default FormDialog;
-  
\ No newline at end of file
diff --git a/webui/src/app/ui/loadingSpinner.tsx 
b/webui/src/app/ui/loadingSpinner.tsx
index 51f7e11..3b314c9 100644
--- a/webui/src/app/ui/loadingSpinner.tsx
+++ b/webui/src/app/ui/loadingSpinner.tsx
@@ -20,21 +20,49 @@
 "use client";
 
 import React from 'react';
-import { Box, CircularProgress } from '@mui/material';
+import { Box, CircularProgress, Typography, Fade } from '@mui/material';
+
+interface LoadingSpinnerProps {
+    message?: string;
+    size?: 'small' | 'medium' | 'large';
+    fullScreen?: boolean;
+}
+
+export const LoadingSpinner: React.FC<LoadingSpinnerProps> = ({ 
+    message = 'Loading...', 
+    size = 'medium',
+    fullScreen = false
+}) => {
+    const spinnerSize = {
+        small: 24,
+        medium: 40,
+        large: 60
+    }[size];
 
-export const LoadingSpinner: React.FC = () => {
     return (
-        <Box
-            sx={{
-                display: 'flex',
-                alignItems: 'center',
-                justifyContent: 'center',
-                height: '100%',
-                width: '100%',
-                minHeight: '200px',
-            }}
-        >
-            <CircularProgress />
-        </Box>
+        <Fade in={true} timeout={300}>
+            <Box
+                sx={{
+                    display: 'flex',
+                    flexDirection: 'column',
+                    alignItems: 'center',
+                    justifyContent: 'center',
+                    height: fullScreen ? '100vh' : '100%',
+                    width: '100%',
+                    minHeight: fullScreen ? '100vh' : '300px',
+                }}
+                className="text-primary dark:text-primary-light"
+            >
+                <CircularProgress size={spinnerSize} thickness={4} 
className="text-primary dark:text-primary-light" />
+                {message && (
+                    <Typography 
+                        variant="body2" 
+                        className="mt-4 text-gray-600 dark:text-gray-300 
animate-pulse"
+                    >
+                        {message}
+                    </Typography>
+                )}
+            </Box>
+        </Fade>
     );
 };
\ No newline at end of file
diff --git a/webui/src/app/ui/nav-links.tsx b/webui/src/app/ui/nav-links.tsx
index 66312d6..ad4a075 100644
--- a/webui/src/app/ui/nav-links.tsx
+++ b/webui/src/app/ui/nav-links.tsx
@@ -17,8 +17,11 @@
  * under the License. 
  */
 
-import { Button } from "@mui/material"
-import Link from "next/link"
+"use client";
+
+import { Button } from "@mui/material";
+import Link from "next/link";
+import { usePathname } from "next/navigation";
 
 export default function NavLinks({links}: {
     links: Array<{
@@ -27,15 +30,32 @@ export default function NavLinks({links}: {
         _blank?: boolean,
     }>
 }) {
+    const pathname = usePathname();
+    
     return <>
-        {links.map(link => <Link
-            key={link.url}
-            href={link.url}
-            {...(link._blank ? {target: '_blank'} : {})}
-        >
-            <Button color="inherit">
-                {link.title}
-            </Button>
-        </Link>)}
-    </>
+        {links.map(link => {
+            const isActive = pathname === link.url || 
+                (link.url !== '/' && pathname.startsWith(link.url));
+                
+            return (
+                <Link
+                    key={link.url}
+                    href={link.url}
+                    passHref
+                    {...(link._blank ? {target: '_blank', rel: "noopener 
noreferrer"} : {})}
+                >
+                    <Button 
+                        color="inherit"
+                        className={`px-3 py-1 mx-1 rounded-md 
transition-colors ${
+                            isActive 
+                                ? 'bg-primary-light/10 text-primary 
dark:text-primary-light' 
+                                : 'hover:bg-gray-100 dark:hover:bg-dark-border'
+                        }`}
+                    >
+                        {link.title}
+                    </Button>
+                </Link>
+            );
+        })}
+    </>;
 }
\ No newline at end of file
diff --git a/webui/src/app/ui/sidebar.tsx b/webui/src/app/ui/sidebar.tsx
index 63bbd38..9ff1b65 100644
--- a/webui/src/app/ui/sidebar.tsx
+++ b/webui/src/app/ui/sidebar.tsx
@@ -19,7 +19,7 @@
 
 "use client";
 
-import { Divider, List, Typography } from "@mui/material";
+import { Divider, List, Typography, Paper, Box, Collapse } from 
"@mui/material";
 import {
     fetchClusters,
     fetchNamespaces,
@@ -35,10 +35,50 @@ import {
 } from "./formCreation";
 import Link from "next/link";
 import { useState, useEffect } from "react";
+import ChevronRightIcon from '@mui/icons-material/ChevronRight';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import FolderIcon from '@mui/icons-material/Folder';
+import StorageIcon from '@mui/icons-material/Storage';
+import DnsIcon from '@mui/icons-material/Dns';
+import DeviceHubIcon from '@mui/icons-material/DeviceHub';
+
+// Sidebar section header component
+const SidebarHeader = ({ 
+    title, 
+    count, 
+    isOpen, 
+    toggleOpen, 
+    icon 
+}: { 
+    title: string; 
+    count: number; 
+    isOpen: boolean; 
+    toggleOpen: () => void;
+    icon: React.ReactNode;
+}) => (
+    <div
+        className="flex items-center justify-between px-4 py-3 bg-gray-50 
dark:bg-dark-paper rounded-md mb-2 cursor-pointer hover:bg-gray-100 
dark:hover:bg-dark-border transition-colors"
+        onClick={toggleOpen}
+    >
+        <div className="flex items-center space-x-2">
+            {icon}
+            <Typography variant="subtitle1" className="font-medium">
+                {title}
+            </Typography>
+            {count > 0 && (
+                <span className="bg-primary text-white dark:bg-primary-dark 
px-2 py-0.5 rounded-full text-xs">
+                    {count}
+                </span>
+            )}
+        </div>
+        {isOpen ? <ExpandMoreIcon fontSize="small" /> : <ChevronRightIcon 
fontSize="small" />}
+    </div>
+);
 
 export function NamespaceSidebar() {
     const [namespaces, setNamespaces] = useState<string[]>([]);
     const [error, setError] = useState<string | null>(null);
+    const [isOpen, setIsOpen] = useState(true);
 
     useEffect(() => {
         const fetchData = async () => {
@@ -53,34 +93,45 @@ export function NamespaceSidebar() {
     }, []);
 
     return (
-        <div className="w-60 h-full flex">
-            <List className="w-full overflow-y-auto">
-                <div className="mt-2 mb-4 text-center">
-                    <NamespaceCreation position="sidebar" />
-                </div>
-                {error && (
-                    <Typography color="error" align="center">
-                        {error}
-                    </Typography>
-                )}
-                {namespaces.map((namespace) => (
-                    <div key={namespace}>
-                        <Divider />
-                        <Link href={`/namespaces/${namespace}`} passHref>
+        <Paper 
+            className="w-64 h-full flex flex-col overflow-hidden 
shadow-sidebar border-r border-light-border dark:border-dark-border"
+            elevation={0}
+            square
+        >
+            <Box className="p-4">
+                <NamespaceCreation position="sidebar" />
+            </Box>
+            
+            <SidebarHeader 
+                title="Namespaces" 
+                count={namespaces.length}
+                isOpen={isOpen}
+                toggleOpen={() => setIsOpen(!isOpen)}
+                icon={<FolderIcon className="text-primary 
dark:text-primary-light" />}
+            />
+
+            <Collapse in={isOpen}>
+                <List className="overflow-y-auto max-h-[calc(100vh-180px)] 
px-2">
+                    {error && (
+                        <Typography color="error" align="center" 
className="text-sm py-2">
+                            {error}
+                        </Typography>
+                    )}
+                    {namespaces.map((namespace) => (
+                        <Link href={`/namespaces/${namespace}`} passHref 
key={namespace}>
                             <Item type="namespace" item={namespace} />
                         </Link>
-                    </div>
-                ))}
-                <Divider />
-            </List>
-            <Divider orientation="vertical" flexItem />
-        </div>
+                    ))}
+                </List>
+            </Collapse>
+        </Paper>
     );
 }
 
 export function ClusterSidebar({ namespace }: { namespace: string }) {
     const [clusters, setClusters] = useState<string[]>([]);
     const [error, setError] = useState<string | null>(null);
+    const [isOpen, setIsOpen] = useState(true);
 
     useEffect(() => {
         const fetchData = async () => {
@@ -95,31 +146,38 @@ export function ClusterSidebar({ namespace }: { namespace: 
string }) {
     }, [namespace]);
 
     return (
-        <div className="w-60 h-full flex">
-            <List className="w-full overflow-y-auto">
-                <div className="mt-2 mb-4 text-center">
-                    <ClusterCreation namespace={namespace} position="sidebar" 
/>
-                </div>
-                {error && (
-                    <Typography color="error" align="center">
-                        {error}
-                    </Typography>
-                )}
-                {clusters.map((cluster) => (
-                    <div key={cluster}>
-                        <Divider />
-                        <Link
-                            
href={`/namespaces/${namespace}/clusters/${cluster}`}
-                            passHref
-                        >
+        <Paper 
+            className="w-64 h-full flex flex-col overflow-hidden 
shadow-sidebar border-r border-light-border dark:border-dark-border"
+            elevation={0}
+            square
+        >
+            <Box className="p-4">
+                <ClusterCreation namespace={namespace} position="sidebar" />
+            </Box>
+            
+            <SidebarHeader 
+                title="Clusters" 
+                count={clusters.length}
+                isOpen={isOpen}
+                toggleOpen={() => setIsOpen(!isOpen)}
+                icon={<StorageIcon className="text-primary 
dark:text-primary-light" />}
+            />
+
+            <Collapse in={isOpen}>
+                <List className="overflow-y-auto max-h-[calc(100vh-180px)] 
px-2">
+                    {error && (
+                        <Typography color="error" align="center" 
className="text-sm py-2">
+                            {error}
+                        </Typography>
+                    )}
+                    {clusters.map((cluster) => (
+                        <Link 
href={`/namespaces/${namespace}/clusters/${cluster}`} passHref key={cluster}>
                             <Item type="cluster" item={cluster} 
namespace={namespace} />
                         </Link>
-                    </div>
-                ))}
-                <Divider />
-            </List>
-            <Divider orientation="vertical" flexItem />
-        </div>
+                    ))}
+                </List>
+            </Collapse>
+        </Paper>
     );
 }
 
@@ -132,6 +190,7 @@ export function ShardSidebar({
 }) {
     const [shards, setShards] = useState<string[]>([]);
     const [error, setError] = useState<string | null>(null);
+    const [isOpen, setIsOpen] = useState(true);
 
     useEffect(() => {
         const fetchData = async () => {
@@ -149,27 +208,36 @@ export function ShardSidebar({
     }, [namespace, cluster]);
 
     return (
-        <div className="w-60 h-full flex">
-            <List className="w-full overflow-y-auto">
-                <div className="mt-2 mb-4 text-center">
-                    <ShardCreation
-                        namespace={namespace}
-                        cluster={cluster}
-                        position="sidebar"
-                    />
-                </div>
-                {error && (
-                    <Typography color="error" align="center">
-                        {error}
-                    </Typography>
-                )}
-                {shards.map((shard, index) => (
-                    <div key={shard}>
-                        <Divider />
-                        <Link
-                            
href={`/namespaces/${namespace}/clusters/${cluster}/shards/${index}`}
-                            passHref
-                        >
+        <Paper 
+            className="w-64 h-full flex flex-col overflow-hidden 
shadow-sidebar border-r border-light-border dark:border-dark-border"
+            elevation={0}
+            square
+        >
+            <Box className="p-4">
+                <ShardCreation
+                    namespace={namespace}
+                    cluster={cluster}
+                    position="sidebar"
+                />
+            </Box>
+            
+            <SidebarHeader 
+                title="Shards" 
+                count={shards.length}
+                isOpen={isOpen}
+                toggleOpen={() => setIsOpen(!isOpen)}
+                icon={<DnsIcon className="text-primary 
dark:text-primary-light" />}
+            />
+
+            <Collapse in={isOpen}>
+                <List className="overflow-y-auto max-h-[calc(100vh-180px)] 
px-2">
+                    {error && (
+                        <Typography color="error" align="center" 
className="text-sm py-2">
+                            {error}
+                        </Typography>
+                    )}
+                    {shards.map((shard, index) => (
+                        <Link 
href={`/namespaces/${namespace}/clusters/${cluster}/shards/${index}`} passHref 
key={index}>
                             <Item
                                 type="shard"
                                 item={shard}
@@ -177,14 +245,13 @@ export function ShardSidebar({
                                 cluster={cluster}
                             />
                         </Link>
-                    </div>
-                ))}
-                <Divider />
-            </List>
-            <Divider orientation="vertical" flexItem />
-        </div>
+                    ))}
+                </List>
+            </Collapse>
+        </Paper>
     );
 }
+
 interface NodeItem {
   addr: string;
   created_at: number;
@@ -204,6 +271,7 @@ export function NodeSidebar({
 }) {
     const [nodes, setNodes] = useState<NodeItem[]>([]);
     const [error, setError] = useState<string | null>(null);
+    const [isOpen, setIsOpen] = useState(true);
 
     useEffect(() => {
         const fetchData = async () => {
@@ -219,46 +287,56 @@ export function NodeSidebar({
             }
         };
         fetchData();
-    // eslint-disable-next-line react-hooks/exhaustive-deps
     }, [namespace, cluster, shard]);
 
     return (
-        <div className="w-60 h-full flex">
-            <List className="w-full overflow-y-auto">
-                <div className="mt-2 mb-4 text-center">
-                    <NodeCreation
-                        namespace={namespace}
-                        cluster={cluster}
-                        shard={shard}
-                        position="sidebar"
-                    />
-                </div>
-                {error && (
-                    <Typography color="error" align="center">
-                        {error}
-                    </Typography>
-                )}
-                {nodes.map((node, index) => (
-                    <div key={index}>
-                        <Divider />
+        <Paper 
+            className="w-64 h-full flex flex-col overflow-hidden 
shadow-sidebar border-r border-light-border dark:border-dark-border"
+            elevation={0}
+            square
+        >
+            <Box className="p-4">
+                <NodeCreation
+                    namespace={namespace}
+                    cluster={cluster}
+                    shard={shard}
+                    position="sidebar"
+                />
+            </Box>
+            
+            <SidebarHeader 
+                title="Nodes" 
+                count={nodes.length}
+                isOpen={isOpen}
+                toggleOpen={() => setIsOpen(!isOpen)}
+                icon={<DeviceHubIcon className="text-primary 
dark:text-primary-light" />}
+            />
+
+            <Collapse in={isOpen}>
+                <List className="overflow-y-auto max-h-[calc(100vh-180px)] 
px-2">
+                    {error && (
+                        <Typography color="error" align="center" 
className="text-sm py-2">
+                            {error}
+                        </Typography>
+                    )}
+                    {nodes.map((node, index) => (
                         <Link
                             
href={`/namespaces/${namespace}/clusters/${cluster}/shards/${shard}/nodes/${index}`}
                             passHref
+                            key={index}
                         >
                             <Item
                                 type="node"
-                                item={"Node\t" + (index + 1).toString()}
+                                item={`Node\t${index + 1}`}
                                 id={node.id}
                                 namespace={namespace}
                                 cluster={cluster}
                                 shard={shard}
                             />
                         </Link>
-                    </div>
-                ))}
-                <Divider />
-            </List>
-            <Divider orientation="vertical" flexItem />
-        </div>
+                    ))}
+                </List>
+            </Collapse>
+        </Paper>
     );
 }
diff --git a/webui/src/app/ui/sidebarItem.tsx b/webui/src/app/ui/sidebarItem.tsx
index 2342d8a..32b2d79 100644
--- a/webui/src/app/ui/sidebarItem.tsx
+++ b/webui/src/app/ui/sidebarItem.tsx
@@ -29,13 +29,15 @@ import {
     IconButton,
     ListItem,
     ListItemButton,
+    ListItemIcon,
     ListItemText,
     Menu,
     MenuItem,
     Snackbar,
     Tooltip,
+    Badge,
 } from "@mui/material";
-import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
+import MoreVertIcon from "@mui/icons-material/MoreVert";
 import { useCallback, useRef, useState } from "react";
 import { usePathname } from "next/navigation";
 import { useRouter } from "next/navigation";
@@ -45,8 +47,12 @@ import {
     deleteNode,
     deleteShard,
 } from "../lib/api";
-import { faTrash } from "@fortawesome/free-solid-svg-icons";
+import { faTrashCan } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import FolderIcon from '@mui/icons-material/Folder';
+import StorageIcon from '@mui/icons-material/Storage';
+import DnsIcon from '@mui/icons-material/Dns';
+import DeviceHubIcon from '@mui/icons-material/DeviceHub';
 
 interface NamespaceItemProps {
   item: string;
@@ -85,7 +91,7 @@ export default function Item(props: ItemProps) {
     const { item, type } = props;
     const [hover, setHover] = useState<boolean>(false);
     const [showMenu, setShowMenu] = useState<boolean>(false);
-    const listItemTextRef = useRef(null);
+    const listItemRef = useRef(null);
     const openMenu = useCallback(() => setShowMenu(true), []);
     const closeMenu = useCallback(
         () => (setShowMenu(false), setHover(false)),
@@ -105,6 +111,22 @@ export default function Item(props: ItemProps) {
     const router = useRouter();
     let activeItem = usePathname().split("/").pop() || "";
 
+    
+    const getItemIcon = () => {
+        switch (type) {
+            case "namespace":
+                return <FolderIcon fontSize="small" className="text-primary 
dark:text-primary-light" />;
+            case "cluster":
+                return <StorageIcon fontSize="small" className="text-primary 
dark:text-primary-light" />;
+            case "shard":
+                return <DnsIcon fontSize="small" className="text-primary 
dark:text-primary-light" />;
+            case "node":
+                return <DeviceHubIcon fontSize="small" className="text-primary 
dark:text-primary-light" />;
+            default:
+                return null;
+        }
+    };
+
     const confirmDelete = useCallback(async () => {
         let response = "";
         if (type === "namespace") {
@@ -150,76 +172,111 @@ export default function Item(props: ItemProps) {
 
     if (type === "shard") {
         activeItem = "Shard\t" + (parseInt(activeItem) + 1);
-    }else if (type === "node") {
+    } else if (type === "node") {
         activeItem = "Node\t" + (parseInt(activeItem) + 1);
     }
     const isActive = item === activeItem;
 
+
+    const displayName = item.includes("\t") ? item.split("\t")[0] + " " + 
item.split("\t")[1] : item;
+
     return (
         <ListItem
             disablePadding
-            secondaryAction={
-                hover && (
-                    <IconButton onClick={openMenu} ref={listItemTextRef}>
-                        <MoreHorizIcon />
-                    </IconButton>
-                )
-            }
+            className="mb-1"
+            ref={listItemRef}
             onMouseEnter={() => setHover(true)}
             onMouseLeave={() => !showMenu && setHover(false)}
-            sx={{
-                backgroundColor: isActive ? "rgba(0, 0, 0, 0.1)" : 
"transparent",
-                "&:hover": {
-                    backgroundColor: "rgba(0, 0, 0, 0.05)",
-                },
-            }}
         >
-            <ListItemButton sx={{ paddingRight: "10px" }}>
-                <Tooltip title={item} arrow>
-                    <ListItemText
-                        classes={{ primary: "overflow-hidden text-ellipsis 
text-nowrap" }}
-                        primary={`${item}`}
-                    />
-                </Tooltip>
+            <ListItemButton 
+                className={`rounded-md group transition-colors ${
+                    isActive 
+                        ? 'bg-primary-light/10 text-primary 
dark:text-primary-light' 
+                        : 'hover:bg-gray-100 dark:hover:bg-dark-border'
+                }`}
+                dense
+            >
+                <ListItemIcon sx={{ minWidth: 36 }}>
+                    {getItemIcon()}
+                </ListItemIcon>
+                <ListItemText 
+                    primary={displayName}
+                    className="overflow-hidden text-ellipsis"
+                    primaryTypographyProps={{ 
+                        className: "text-sm font-medium", 
+                        noWrap: true 
+                    }}
+                />
+                {hover && (
+                    <IconButton 
+                        size="small" 
+                        edge="end" 
+                        onClick={openMenu}
+                        className="opacity-0 group-hover:opacity-100 
transition-opacity"
+                    >
+                        <MoreVertIcon fontSize="small" />
+                    </IconButton>
+                )}
             </ListItemButton>
+            
             <Menu
-                id={item}
+                id={`menu-${item}`}
                 open={showMenu}
                 onClose={closeMenu}
-                anchorEl={listItemTextRef.current}
+                anchorEl={listItemRef.current}
                 anchorOrigin={{
-                    vertical: "center",
-                    horizontal: "center",
+                    vertical: "bottom",
+                    horizontal: "right",
+                }}
+                transformOrigin={{
+                    vertical: "top",
+                    horizontal: "right",
+                }}
+                PaperProps={{
+                    className: "shadow-lg"
                 }}
             >
-                <MenuItem onClick={openDeleteConfirmDialog}>
-                    <FontAwesomeIcon icon={faTrash} color="red" />
+                <MenuItem onClick={openDeleteConfirmDialog} 
className="text-error hover:bg-error-light/10">
+                    <FontAwesomeIcon icon={faTrashCan} className="mr-2" />
+                    Delete
                 </MenuItem>
             </Menu>
-            <Dialog open={showDeleteConfirm}>
-                <DialogTitle>Confirm</DialogTitle>
+            
+            <Dialog 
+                open={showDeleteConfirm}
+                onClose={closeDeleteConfirmDialog}
+                className="backdrop-blur-sm"
+                PaperProps={{
+                    className: "rounded-lg shadow-xl"
+                }}
+            >
+                <DialogTitle className="font-medium">Confirm 
Delete</DialogTitle>
                 <DialogContent>
-                    {type === "node" ? (
+                    {type === "node" || type === "shard" ? (
                         <DialogContentText>
-              Please confirm you want to delete {item}
-                        </DialogContentText>
-                    ) : type === "shard" ? (
-                        <DialogContentText>
-              Please confirm you want to delete {item}
+                            Are you sure you want to delete {displayName}?
                         </DialogContentText>
                     ) : (
                         <DialogContentText>
-              Please confirm you want to delete {type} {item}
+                            Are you sure you want to delete {type} <span 
className="font-semibold">{item}</span>?
                         </DialogContentText>
                     )}
                 </DialogContent>
-                <DialogActions>
-                    <Button onClick={closeDeleteConfirmDialog}>Cancel</Button>
-                    <Button onClick={confirmDelete} color="error">
-            Delete
+                <DialogActions className="p-4">
+                    <Button onClick={closeDeleteConfirmDialog} 
variant="outlined">
+                        Cancel
+                    </Button>
+                    <Button 
+                        onClick={confirmDelete} 
+                        variant="contained" 
+                        color="error" 
+                        className="bg-error hover:bg-error-dark"
+                    >
+                        Delete
                     </Button>
                 </DialogActions>
             </Dialog>
+            
             <Snackbar
                 open={!!errorMessage}
                 autoHideDuration={5000}
diff --git a/webui/src/app/utils.ts b/webui/src/app/utils.ts
index 4c79b17..9ddc6db 100644
--- a/webui/src/app/utils.ts
+++ b/webui/src/app/utils.ts
@@ -17,6 +17,54 @@
  * under the License.
  */
 
-export const truncateText = (text: string, limit: number) => {
-    return text.length > limit ? `${text.slice(0, limit)}...` : text;
+/**
+ * Truncates text to a specific length and adds an ellipsis
+ */
+export const truncateText = (text: string, maxLength: number): string => {
+  if (!text || text.length <= maxLength) return text;
+  return `${text.substring(0, maxLength)}...`;
+};
+
+/**
+ * Format a timestamp to a human-readable date
+ */
+export const formatTimestamp = (timestamp: number): string => {
+  return new Date(timestamp * 1000).toLocaleString();
+};
+
+/**
+ * Format bytes into a human-readable format
+ */
+export const formatBytes = (bytes: number, decimals: number = 2): string => {
+  if (bytes === 0) return '0 Bytes';
+  
+  const k = 1024;
+  const dm = decimals < 0 ? 0 : decimals;
+  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+  
+  const i = Math.floor(Math.log(bytes) / Math.log(k));
+  
+  return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
+};
+
+/**
+ * Calculate uptime from creation timestamp
+ */
+export const calculateUptime = (timestamp: number): string => {
+  const now = Math.floor(Date.now() / 1000);
+  const uptimeSeconds = now - timestamp;
+  
+  if (uptimeSeconds < 60) return `${uptimeSeconds} seconds`;
+  if (uptimeSeconds < 3600) return `${Math.floor(uptimeSeconds / 60)} minutes`;
+  if (uptimeSeconds < 86400) return `${Math.floor(uptimeSeconds / 3600)} 
hours`;
+  return `${Math.floor(uptimeSeconds / 86400)} days`;
+};
+
+/**
+ * Format slot ranges for better display
+ */
+export const formatSlotRanges = (ranges: string[]): string => {
+  if (!ranges || ranges.length === 0) return "None";
+  if (ranges.length <= 2) return ranges.join(", ");
+  return `${ranges[0]}, ${ranges[1]}, ... (+${ranges.length - 2} more)`;
 };
diff --git a/webui/tailwind.config.ts b/webui/tailwind.config.ts
index 0305e16..7b220bc 100644
--- a/webui/tailwind.config.ts
+++ b/webui/tailwind.config.ts
@@ -25,12 +25,65 @@ const config: Config = {
         "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
         "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
     ],
+    darkMode: 'class',
     theme: {
         extend: {
+            colors: {
+                primary: {
+                    DEFAULT: '#1976d2',
+                    light: '#42a5f5',
+                    dark: '#1565c0',
+                    contrastText: '#fff',
+                },
+                secondary: {
+                    DEFAULT: '#9c27b0',
+                    light: '#ba68c8',
+                    dark: '#7b1fa2',
+                    contrastText: '#fff',
+                },
+                success: {
+                    DEFAULT: '#2e7d32',
+                    light: '#4caf50',
+                    dark: '#1b5e20',
+                },
+                error: {
+                    DEFAULT: '#d32f2f',
+                    light: '#ef5350',
+                    dark: '#c62828',
+                },
+                warning: {
+                    DEFAULT: '#ed6c02',
+                    light: '#ff9800',
+                    dark: '#e65100',
+                },
+                info: {
+                    DEFAULT: '#0288d1',
+                    light: '#03a9f4',
+                    dark: '#01579b',
+                },
+                dark: {
+                    DEFAULT: '#121212',
+                    paper: '#1e1e1e',
+                    border: '#333333',
+                },
+                light: {
+                    DEFAULT: '#fafafa',
+                    paper: '#ffffff',
+                    border: '#e0e0e0',
+                }
+            },
             backgroundImage: {
                 "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
-                "gradient-conic":
-          "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
+                "gradient-conic": "conic-gradient(from 180deg at 50% 50%, 
var(--tw-gradient-stops))",
+            },
+            boxShadow: {
+                'card': '0 2px 8px rgba(0, 0, 0, 0.08)',
+                'card-hover': '0 4px 12px rgba(0, 0, 0, 0.15)',
+                'sidebar': '2px 0 5px rgba(0, 0, 0, 0.05)',
+            },
+            transitionProperty: {
+                'height': 'height',
+                'spacing': 'margin, padding',
             },
         },
     },

Reply via email to