|
1 | 1 | {{ define "base" }} |
2 | 2 | <!DOCTYPE html> |
3 | 3 | <html lang="en" class="dark"> |
| 4 | + |
4 | 5 | <head> |
5 | 6 | <meta charset="UTF-8"> |
6 | 7 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
34 | 35 | <script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script> |
35 | 36 |
|
36 | 37 | <style> |
37 | | - body { font-family: 'Inter', sans-serif; } |
| 38 | + body { |
| 39 | + font-family: 'Inter', sans-serif; |
| 40 | + } |
| 41 | + |
38 | 42 | /* Showing HTMX attributes for visualization only */ |
39 | | - .htmx-indicator { opacity: 0; transition: opacity 200ms ease-in; } |
40 | | - .htmx-request .htmx-indicator { opacity: 1; } |
41 | | - [x-cloak] { display: none !important; } |
| 43 | + .htmx-indicator { |
| 44 | + opacity: 0; |
| 45 | + transition: opacity 200ms ease-in; |
| 46 | + } |
| 47 | + |
| 48 | + .htmx-request .htmx-indicator { |
| 49 | + opacity: 1; |
| 50 | + } |
| 51 | + |
| 52 | + [x-cloak] { |
| 53 | + display: none !important; |
| 54 | + } |
42 | 55 | </style> |
43 | 56 | </head> |
44 | | -<body class="bg-background text-zinc-100 h-screen w-screen flex overflow-hidden" x-data="{ collapsed: false }"> |
| 57 | + |
| 58 | +<body class="bg-background text-zinc-100 h-screen w-screen flex overflow-hidden" x-data="{ collapsed: false }" |
| 59 | + hx-boost="true" hx-target="#main-content" hx-select="#main-content" hx-swap="outerHTML"> |
45 | 60 |
|
46 | 61 | <!-- SIDEBAR --> |
47 | | - <div |
48 | | - class="border-r border-border bg-surface flex flex-col transition-all duration-300 ease-in-out w-64" |
49 | | - :class="collapsed ? '!w-20' : ''" |
50 | | - > |
| 62 | + <div class="border-r border-border bg-surface flex flex-col transition-all duration-300 ease-in-out w-64" |
| 63 | + :class="collapsed ? '!w-20' : ''"> |
51 | 64 | <div class="p-6 flex items-center gap-3 border-b border-border/50 overflow-hidden whitespace-nowrap"> |
52 | | - <div class="w-8 h-8 bg-zinc-100 rounded-lg flex-shrink-0 flex items-center justify-center cursor-pointer" @click="collapsed = !collapsed"> |
| 65 | + <div class="w-8 h-8 bg-zinc-100 rounded-lg flex-shrink-0 flex items-center justify-center cursor-pointer" |
| 66 | + @click="collapsed = !collapsed"> |
53 | 67 | <i data-lucide="box" class="text-black"></i> |
54 | 68 | </div> |
55 | | - <span class="font-bold text-lg tracking-tight transition-opacity duration-300 opacity-100" :class="collapsed ? '!opacity-0 !w-0' : ''">IronBuckets</span> |
| 69 | + <span class="font-bold text-lg tracking-tight transition-opacity duration-300 opacity-100" |
| 70 | + :class="collapsed ? '!opacity-0 !w-0' : ''">IronBuckets</span> |
56 | 71 | </div> |
57 | 72 |
|
58 | 73 | <div class="flex-1 py-6 px-3 space-y-1 overflow-y-auto overflow-x-hidden"> |
59 | 74 |
|
60 | 75 | <!-- Section Header --> |
61 | 76 | <div class="px-3 text-xs font-semibold text-zinc-500 uppercase tracking-wider mb-2 transition-opacity duration-300 whitespace-nowrap opacity-100" |
62 | | - :class="collapsed ? '!opacity-0 !h-0 !overflow-hidden !mb-0' : ''"> |
63 | | - Cluster |
| 77 | + :class="collapsed ? '!opacity-0 !h-0 !overflow-hidden !mb-0' : ''"> |
| 78 | + Cluster |
64 | 79 | </div> |
65 | 80 |
|
66 | 81 | <!-- Nav Items --> |
67 | | - <a href="/" class="w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "overview" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
| 82 | + <a href="/" |
| 83 | + class="sidebar-nav-link w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "overview" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
68 | 84 | <i data-lucide="activity" size="18" class="flex-shrink-0"></i> |
69 | 85 | <span class="opacity-100" :class="collapsed ? '!opacity-0 !w-0' : ''">Overview</span> |
70 | 86 | </a> |
71 | 87 |
|
72 | | - <a href="/drives" class="w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "drives" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
| 88 | + <a href="/drives" |
| 89 | + class="sidebar-nav-link w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "drives" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
73 | 90 | <i data-lucide="hard-drive" size="18" class="flex-shrink-0"></i> |
74 | 91 | <span class="opacity-100" :class="collapsed ? '!opacity-0 !w-0' : ''">Drives</span> |
75 | 92 | </a> |
76 | 93 |
|
77 | 94 | <!-- Section Header --> |
78 | 95 | <div class="px-3 text-xs font-semibold text-zinc-500 uppercase tracking-wider mb-2 mt-6 transition-opacity duration-300 whitespace-nowrap opacity-100" |
79 | | - :class="collapsed ? '!opacity-0 !h-0 !overflow-hidden !mt-2 !mb-0' : ''"> |
80 | | - Access |
| 96 | + :class="collapsed ? '!opacity-0 !h-0 !overflow-hidden !mt-2 !mb-0' : ''"> |
| 97 | + Access |
81 | 98 | </div> |
82 | 99 |
|
83 | | - <a href="/users" class="w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "users" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
| 100 | + <a href="/users" |
| 101 | + class="sidebar-nav-link w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "users" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
84 | 102 | <i data-lucide="user" size="18" class="flex-shrink-0"></i> |
85 | 103 | <span class="opacity-100" :class="collapsed ? '!opacity-0 !w-0' : ''">Users</span> |
86 | 104 | </a> |
87 | 105 |
|
88 | | - <a href="/groups" class="w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "groups" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
| 106 | + <a href="/groups" |
| 107 | + class="sidebar-nav-link w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "groups" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
89 | 108 | <i data-lucide="users" size="18" class="flex-shrink-0"></i> |
90 | 109 | <span class="opacity-100" :class="collapsed ? '!opacity-0 !w-0' : ''">Groups</span> |
91 | 110 | </a> |
92 | 111 |
|
93 | | - <a href="/buckets" class="w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "buckets" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
| 112 | + <a href="/buckets" |
| 113 | + class="sidebar-nav-link w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "buckets" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
94 | 114 | <i data-lucide="container" size="18" class="flex-shrink-0"></i> |
95 | 115 | <span class="opacity-100" :class="collapsed ? '!opacity-0 !w-0' : ''">Buckets</span> |
96 | 116 | </a> |
97 | 117 |
|
98 | 118 | <!-- Section Header --> |
99 | 119 | <div class="px-3 text-xs font-semibold text-zinc-500 uppercase tracking-wider mb-2 mt-6 transition-opacity duration-300 whitespace-nowrap opacity-100" |
100 | | - :class="collapsed ? '!opacity-0 !h-0 !overflow-hidden !mt-2 !mb-0' : ''"> |
101 | | - System |
| 120 | + :class="collapsed ? '!opacity-0 !h-0 !overflow-hidden !mt-2 !mb-0' : ''"> |
| 121 | + System |
102 | 122 | </div> |
103 | 123 |
|
104 | | - <a href="/settings" class="w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "settings" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
| 124 | + <a href="/settings" |
| 125 | + class="sidebar-nav-link w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap {{ if eq .ActiveNav "settings" }}bg-white/10 text-white{{ else }}text-zinc-400 hover:text-white hover:bg-white/5{{ end }}"> |
105 | 126 | <i data-lucide="settings" size="18" class="flex-shrink-0"></i> |
106 | 127 | <span class="opacity-100" :class="collapsed ? '!opacity-0 !w-0' : ''">Settings</span> |
107 | 128 | </a> |
108 | 129 |
|
109 | 130 | <!-- Logout at bottom --> |
110 | 131 | <div class="mt-auto pt-4 border-t border-border"> |
111 | | - <a href="/logout" class="w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap text-zinc-400 hover:text-red-400 hover:bg-red-500/10"> |
| 132 | + <a href="/logout" hx-boost="false" |
| 133 | + class="w-full flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap text-zinc-400 hover:text-red-400 hover:bg-red-500/10"> |
112 | 134 | <i data-lucide="log-out" size="18" class="flex-shrink-0"></i> |
113 | 135 | <span class="opacity-100" :class="collapsed ? '!opacity-0 !w-0' : ''">Logout</span> |
114 | 136 | </a> |
|
117 | 139 | </div> |
118 | 140 |
|
119 | 141 | <!-- MAIN CONTENT --> |
120 | | - <main class="flex-1 flex flex-col min-w-0 bg-background overflow-auto"> |
| 142 | + <main id="main-content" class="flex-1 flex flex-col min-w-0 bg-background overflow-auto"> |
121 | 143 | <!-- Header --> |
122 | | - <header class="h-16 border-b border-border flex items-center justify-between px-8 bg-background/50 backdrop-blur-sm sticky top-0 z-10"> |
| 144 | + <header |
| 145 | + class="h-16 border-b border-border flex items-center justify-between px-8 bg-background/50 backdrop-blur-sm sticky top-0 z-10"> |
123 | 146 | <div class="flex items-center gap-2"> |
124 | 147 | <span class="w-2 h-2 rounded-full bg-emerald-500 animate-pulse"></span> |
125 | 148 | <span class="text-sm font-medium text-zinc-300">Cluster Online</span> |
126 | | - <span class="text-xs text-zinc-500 ml-2" hx-get="/api/server/version" hx-trigger="load" hx-swap="innerHTML"></span> |
| 149 | + <span class="text-xs text-zinc-500 ml-2" hx-get="/api/server/version" hx-trigger="load" |
| 150 | + hx-swap="innerHTML"></span> |
127 | 151 | </div> |
128 | 152 | <!-- Right side items if needed --> |
129 | 153 | <div class="flex items-center gap-4"> |
130 | | - <!-- Removed Restart Button, moved to Settings --> |
| 154 | + <!-- Removed Restart Button, moved to Settings --> |
131 | 155 | </div> |
132 | 156 | </header> |
133 | 157 |
|
|
145 | 169 | lucide.createIcons(); |
146 | 170 |
|
147 | 171 | // Re-init icons on HTMX content swaps |
148 | | - document.body.addEventListener('htmx:afterSwap', function(evt) { |
| 172 | + document.body.addEventListener('htmx:afterSwap', function (evt) { |
149 | 173 | lucide.createIcons(); |
150 | 174 | }); |
| 175 | + |
| 176 | + // Update sidebar active state on navigation |
| 177 | + document.body.addEventListener('htmx:pushedIntoHistory', function (evt) { |
| 178 | + const path = window.location.pathname; |
| 179 | + const links = document.querySelectorAll('.sidebar-nav-link'); |
| 180 | + |
| 181 | + links.forEach(link => { |
| 182 | + const href = link.getAttribute('href'); |
| 183 | + // Simple exact match or startswith for sub-paths if needed. |
| 184 | + // For now, exact match or /users matching /users/create is good practice, |
| 185 | + // but let's stick to exact logic or simple logic matching the Go template: |
| 186 | + // Go template used exact match mostly. |
| 187 | + |
| 188 | + let isActive = false; |
| 189 | + if (href === '/' && path === '/') { |
| 190 | + isActive = true; |
| 191 | + } else if (href !== '/' && path.startsWith(href)) { |
| 192 | + isActive = true; |
| 193 | + } |
| 194 | + |
| 195 | + if (isActive) { |
| 196 | + link.classList.remove('text-zinc-400', 'hover:text-white', 'hover:bg-white/5'); |
| 197 | + link.classList.add('bg-white/10', 'text-white'); |
| 198 | + } else { |
| 199 | + link.classList.add('text-zinc-400', 'hover:text-white', 'hover:bg-white/5'); |
| 200 | + link.classList.remove('bg-white/10', 'text-white'); |
| 201 | + } |
| 202 | + }); |
| 203 | + }); |
151 | 204 | </script> |
152 | 205 | </body> |
| 206 | + |
153 | 207 | </html> |
154 | 208 | {{ end }} |
0 commit comments