diff --git a/app/explorer/page.tsx b/app/explorer/page.tsx new file mode 100644 index 0000000..d56d3e5 --- /dev/null +++ b/app/explorer/page.tsx @@ -0,0 +1,10 @@ +'use client'; + +import { HyperwebExplorer } from '@hyperweb/explorer'; +import { useTheme } from '@/hooks'; + +export default function ExplorerPage() { + const theme = useTheme(); + + return ; +} diff --git a/app/layout.tsx b/app/layout.tsx index eb0a6ef..99e2c2d 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,30 +1,28 @@ -import type { Metadata } from 'next' -import { Inter } from 'next/font/google' -import './globals.css' -import { Providers } from './providers' -import { DashboardLayout } from '@/components/dashboard-layout' +import type { Metadata } from 'next'; +import { Inter } from 'next/font/google'; +import './globals.css'; +import { Providers } from './providers'; +import { DashboardLayout } from '@/components/dashboard-layout'; +import '@hyperweb/explorer/styles'; +import '@hyperweb/playground/styles'; +import '@hyperweb/playground/wallet-styles'; +import { cn } from '@/lib/utils'; -const inter = Inter({ subsets: ['latin'] }) +const inter = Inter({ subsets: ['latin'] }); export const metadata: Metadata = { title: 'Kubernetes Dashboard', description: 'A modern dashboard for managing Kubernetes resources', -} +}; -export default function RootLayout({ - children, -}: { - children: React.ReactNode -}) { +export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - - + + - - {children} - + {children} - ) -} \ No newline at end of file + ); +} diff --git a/app/playground/page.tsx b/app/playground/page.tsx new file mode 100644 index 0000000..d0d2d96 --- /dev/null +++ b/app/playground/page.tsx @@ -0,0 +1,10 @@ +'use client'; + +import { HyperwebPlayground } from '@hyperweb/playground'; +import { useTheme } from '@/hooks'; + +export default function PlaygroundPage() { + const theme = useTheme(); + + return ; +} diff --git a/components/dashboard-layout.tsx b/components/dashboard-layout.tsx index 033fc28..6a010f0 100644 --- a/components/dashboard-layout.tsx +++ b/components/dashboard-layout.tsx @@ -1,12 +1,12 @@ -'use client' - -import { useState } from 'react' -import NextLink from 'next/link' -import { usePathname } from 'next/navigation' -import { Button } from '@/components/ui/button' -import { NamespaceSwitcher } from '@/components/namespace-switcher' -import { ThemeToggle } from '@/components/ui/theme-toggle' -import { useKubernetes } from '../k8s/context' +'use client'; + +import { useState } from 'react'; +import NextLink from 'next/link'; +import { usePathname } from 'next/navigation'; +import { Button } from '@/components/ui/button'; +import { NamespaceSwitcher } from '@/components/namespace-switcher'; +import { ThemeToggle } from '@/components/ui/theme-toggle'; +import { useKubernetes } from '../k8s/context'; import { Package, Server, @@ -40,154 +40,265 @@ import { Grid3x3, ChevronDown, ChevronRight, - Heart -} from 'lucide-react' + Heart, + Box, +} from 'lucide-react'; const navigationItems = [ // Top items (no section) { id: 'overview', label: 'Overview', icon: Home, href: '/' }, { id: 'all', label: 'All Resources', icon: Grid3x3, href: '/all' }, { id: 'templates', label: 'Templates', icon: FileCode2, href: '/templates' }, - + { id: 'playground', label: 'Playground', icon: Zap, href: '/playground' }, + { id: 'explorer', label: 'Explorer', icon: Box, href: '/explorer' }, + // Workloads { id: 'workloads-header', label: 'Workloads', isHeader: true, section: 'workloads' }, - { id: 'deployments', label: 'Deployments', icon: Package, href: '/deployments', section: 'workloads' }, - { id: 'replicasets', label: 'ReplicaSets', icon: Copy, href: '/replicasets', section: 'workloads' }, - { id: 'statefulsets', label: 'StatefulSets', icon: Layers, href: '/statefulsets', section: 'workloads' }, - { id: 'daemonsets', label: 'DaemonSets', icon: Shield, href: '/daemonsets', section: 'workloads' }, + { + id: 'deployments', + label: 'Deployments', + icon: Package, + href: '/deployments', + section: 'workloads', + }, + { + id: 'replicasets', + label: 'ReplicaSets', + icon: Copy, + href: '/replicasets', + section: 'workloads', + }, + { + id: 'statefulsets', + label: 'StatefulSets', + icon: Layers, + href: '/statefulsets', + section: 'workloads', + }, + { + id: 'daemonsets', + label: 'DaemonSets', + icon: Shield, + href: '/daemonsets', + section: 'workloads', + }, { id: 'pods', label: 'Pods', icon: Activity, href: '/pods', section: 'workloads' }, { id: 'jobs', label: 'Jobs', icon: Zap, href: '/jobs', section: 'workloads' }, { id: 'cronjobs', label: 'CronJobs', icon: Calendar, href: '/cronjobs', section: 'workloads' }, - + // Config & Storage { id: 'config-header', label: 'Config & Storage', isHeader: true, section: 'config' }, { id: 'configmaps', label: 'ConfigMaps', icon: Settings, href: '/configmaps', section: 'config' }, { id: 'secrets', label: 'Secrets', icon: Key, href: '/secrets', section: 'config' }, - { id: 'pvcs', label: 'Persistent Volume Claims', icon: HardDrive, href: '/pvcs', section: 'config' }, + { + id: 'pvcs', + label: 'Persistent Volume Claims', + icon: HardDrive, + href: '/pvcs', + section: 'config', + }, { id: 'pvs', label: 'Persistent Volumes', icon: Database, href: '/pvs', section: 'config' }, - { id: 'storageclasses', label: 'Storage Classes', icon: Database, href: '/storageclasses', section: 'config' }, - { id: 'volumeattachments', label: 'Volume Attachments', icon: Paperclip, href: '/volumeattachments', section: 'config' }, - + { + id: 'storageclasses', + label: 'Storage Classes', + icon: Database, + href: '/storageclasses', + section: 'config', + }, + { + id: 'volumeattachments', + label: 'Volume Attachments', + icon: Paperclip, + href: '/volumeattachments', + section: 'config', + }, + // Network { id: 'network-header', label: 'Network', isHeader: true, section: 'network' }, { id: 'services', label: 'Services', icon: Server, href: '/services', section: 'network' }, { id: 'ingresses', label: 'Ingresses', icon: Globe, href: '/ingresses', section: 'network' }, - { id: 'networkpolicies', label: 'Network Policies', icon: Shield, href: '/networkpolicies', section: 'network' }, + { + id: 'networkpolicies', + label: 'Network Policies', + icon: Shield, + href: '/networkpolicies', + section: 'network', + }, { id: 'endpoints', label: 'Endpoints', icon: Network, href: '/endpoints', section: 'network' }, - { id: 'endpointslices', label: 'Endpoint Slices', icon: Network, href: '/endpointslices', section: 'network' }, - + { + id: 'endpointslices', + label: 'Endpoint Slices', + icon: Network, + href: '/endpointslices', + section: 'network', + }, + // Access Control { id: 'rbac-header', label: 'Access Control', isHeader: true, section: 'rbac' }, - { id: 'serviceaccounts', label: 'Service Accounts', icon: Bot, href: '/serviceaccounts', section: 'rbac' }, + { + id: 'serviceaccounts', + label: 'Service Accounts', + icon: Bot, + href: '/serviceaccounts', + section: 'rbac', + }, { id: 'roles', label: 'Roles', icon: UserCheck, href: '/roles', section: 'rbac' }, - { id: 'rolebindings', label: 'Role Bindings', icon: Users, href: '/rolebindings', section: 'rbac' }, - + { + id: 'rolebindings', + label: 'Role Bindings', + icon: Users, + href: '/rolebindings', + section: 'rbac', + }, + // Cluster { id: 'cluster-header', label: 'Cluster', isHeader: true, section: 'cluster' }, - { id: 'resourcequotas', label: 'Resource Quotas', icon: Gauge, href: '/resourcequotas', section: 'cluster' }, - { id: 'hpas', label: 'Horizontal Pod Autoscalers', icon: BarChart, href: '/hpas', section: 'cluster' }, - { id: 'pdbs', label: 'Pod Disruption Budgets', icon: ShieldCheck, href: '/pdbs', section: 'cluster' }, - { id: 'priorityclasses', label: 'Priority Classes', icon: Star, href: '/priorityclasses', section: 'cluster' }, - { id: 'runtimeclasses', label: 'Runtime Classes', icon: Cpu, href: '/runtimeclasses', section: 'cluster' }, + { + id: 'resourcequotas', + label: 'Resource Quotas', + icon: Gauge, + href: '/resourcequotas', + section: 'cluster', + }, + { + id: 'hpas', + label: 'Horizontal Pod Autoscalers', + icon: BarChart, + href: '/hpas', + section: 'cluster', + }, + { + id: 'pdbs', + label: 'Pod Disruption Budgets', + icon: ShieldCheck, + href: '/pdbs', + section: 'cluster', + }, + { + id: 'priorityclasses', + label: 'Priority Classes', + icon: Star, + href: '/priorityclasses', + section: 'cluster', + }, + { + id: 'runtimeclasses', + label: 'Runtime Classes', + icon: Cpu, + href: '/runtimeclasses', + section: 'cluster', + }, { id: 'events', label: 'Events', icon: Clock, href: '/events', section: 'cluster' }, -] +]; interface DashboardLayoutProps { - children: React.ReactNode + children: React.ReactNode; } export function DashboardLayout({ children }: DashboardLayoutProps) { - const [sidebarOpen, setSidebarOpen] = useState(true) - const [expandedSections, setExpandedSections] = useState>(new Set(['workloads', 'config', 'network', 'rbac', 'cluster'])) - const pathname = usePathname() - const { config } = useKubernetes() - + const [sidebarOpen, setSidebarOpen] = useState(true); + const [expandedSections, setExpandedSections] = useState>( + new Set(['workloads', 'config', 'network', 'rbac', 'cluster']) + ); + const pathname = usePathname(); + const { config } = useKubernetes(); + // Find active section based on pathname - const activeSection = navigationItems.find(item => !item.isHeader && item.href === pathname)?.label || 'Overview' - + const activeSection = + navigationItems.find((item) => !item.isHeader && item.href === pathname)?.label || 'Overview'; + // Toggle section expansion const toggleSection = (section: string) => { - const newExpanded = new Set(expandedSections) + const newExpanded = new Set(expandedSections); if (newExpanded.has(section)) { - newExpanded.delete(section) + newExpanded.delete(section); } else { - newExpanded.add(section) + newExpanded.add(section); } - setExpandedSections(newExpanded) - } + setExpandedSections(newExpanded); + }; return ( -
+
{/* Sidebar */} -
-
+
+
- - + +
-