fix: UI overhaul — align all HTMX views with Lumina Design System (46 fixes)

- All 7 pages rewritten: Dashboard, Terminal, Snippets, Keychain, SFTP, Settings, Brief
- Apply consistent Lumina glassmorphic theme (rounded-2xl, shadows, borders, tracking)
- Fix SVG icons not rendering — return template.HTML instead of string
- Fix Alpine x-data scoping: terminal tabs, SFTP modals, snippet tag buttons
- Fix dashboard search sending literal ?q=...
- Rebuild CSS with all new Tailwind classes (62KB)
- Add .air.toml with hot-reload config, docs/PERBAIKANUI.md checklist
- Remove unused backup partials
This commit is contained in:
swanadiva
2026-07-07 14:55:42 +07:00
parent fd7361aa14
commit 8357d9d76e
29 changed files with 3321 additions and 924 deletions
+6 -2
View File
@@ -3,9 +3,13 @@ package handler
import "github.com/gofiber/fiber/v2"
func Brief(c *fiber.Ctx) error {
return c.Render("brief", fiber.Map{
data := fiber.Map{
"View": "brief",
"Title": "Quick Brief",
"NavItems": navItems,
})
}
if c.Get("HX-Request") != "" {
return c.Render("brief_content", data)
}
return c.Render("brief", data)
}
+3
View File
@@ -8,6 +8,9 @@ import (
var keyStore = store.NewKeyStore()
func Keychain(c *fiber.Ctx) error {
if c.Get("HX-Request") != "" {
return KeyGrid(c)
}
keys := keyStore.All()
return c.Render("keychain", fiber.Map{
"View": "keychain",
+6 -2
View File
@@ -10,13 +10,17 @@ var deviceStore = model.NewDeviceStore()
var settingsStore = store.NewSettingsStore()
func Settings(c *fiber.Ctx) error {
return c.Render("settings", fiber.Map{
data := fiber.Map{
"View": "settings",
"Title": "Settings",
"Config": settingsStore.Get(),
"Devices": deviceStore.All(),
"NavItems": navItems,
})
}
if c.Get("HX-Request") != "" {
return c.Render("settings_content", data)
}
return c.Render("settings", data)
}
func UpdateConfig(c *fiber.Ctx) error {
+6 -2
View File
@@ -9,7 +9,7 @@ var fileStore = model.NewFileStore()
func SFTP(c *fiber.Ctx) error {
local, remote := fileStore.All()
return c.Render("sftp", fiber.Map{
data := fiber.Map{
"View": "sftp",
"Title": "SFTP",
"LocalFiles": local,
@@ -17,7 +17,11 @@ func SFTP(c *fiber.Ctx) error {
"LocalBreadcrumb": fileStore.LocalBreadcrumb,
"RemoteBreadcrumb": fileStore.RemoteBreadcrumb,
"NavItems": navItems,
})
}
if c.Get("HX-Request") != "" {
return c.Render("sftp_content", data)
}
return c.Render("sftp", data)
}
func SFTPPane(c *fiber.Ctx) error {
+57 -9
View File
@@ -1,40 +1,88 @@
package handler
import (
"encoding/json"
"github.com/gofiber/fiber/v2"
"git.tukangketik.id/swanadiva/hostkeeper/v2/internal/model"
"git.tukangketik.id/swanadiva/hostkeeper/v2/internal/store"
)
func jsonOrEmpty(v interface{}) string {
b, err := json.Marshal(v)
if err != nil {
return "[]"
}
return string(b)
}
func allTags(snippets []model.Snippet) []string {
seen := map[string]bool{}
var out []string
for _, sn := range snippets {
for _, t := range sn.Tags {
if !seen[t] {
seen[t] = true
out = append(out, t)
}
}
}
return out
}
var snippetStore = store.NewSnippetStore()
func Snippets(c *fiber.Ctx) error {
if c.Get("HX-Request") != "" {
return SnippetGrid(c)
}
snippets := snippetStore.All()
return c.Render("snippets", fiber.Map{
"View": "snippets",
"Title": "Snippets",
"Snippets": snippets,
"NavItems": navItems,
"View": "snippets",
"Title": "Snippets",
"Snippets": snippets,
"SnippetsJSON": jsonOrEmpty(snippets),
"AllTags": allTags(snippets),
"NavItems": navItems,
})
}
func SnippetGrid(c *fiber.Ctx) error {
q := c.Query("q", "")
snippets := snippetStore.Search(q)
return c.Render("snippet_grid", fiber.Map{"Snippets": snippets})
collection := c.Query("collection", "")
tag := c.Query("tag", "")
snippets := snippetStore.Search(q, collection, tag)
return c.Render("snippet_grid", fiber.Map{
"Snippets": snippets,
"SnippetsJSON": jsonOrEmpty(snippets),
})
}
func CreateSnippet(c *fiber.Ctx) error {
name := c.FormValue("name")
content := c.FormValue("content")
language := c.FormValue("language")
snippetStore.Add(name, content, language, nil)
description := c.FormValue("description")
collection := c.FormValue("collection")
tagStr := c.FormValue("tags")
var tags []string
if tagStr != "" {
tags = []string{tagStr}
}
snippetStore.Add(name, content, language, tags, description, collection)
snippets := snippetStore.All()
return c.Render("snippet_grid", fiber.Map{"Snippets": snippets})
return c.Render("snippet_grid", fiber.Map{
"Snippets": snippets,
"SnippetsJSON": jsonOrEmpty(snippets),
})
}
func DeleteSnippet(c *fiber.Ctx) error {
id := c.Params("id")
snippetStore.Delete(id)
snippets := snippetStore.All()
return c.Render("snippet_grid", fiber.Map{"Snippets": snippets})
return c.Render("snippet_grid", fiber.Map{
"Snippets": snippets,
"SnippetsJSON": jsonOrEmpty(snippets),
})
}
+6 -2
View File
@@ -28,13 +28,17 @@ func Terminal(c *fiber.Ctx) error {
}
}
hostsJSON, _ := json.Marshal(available)
return c.Render("terminal", fiber.Map{
data := fiber.Map{
"View": "terminal",
"Title": "Terminal",
"NavItems": navItems,
"Hosts": available,
"HostsJSON": string(hostsJSON),
})
}
if c.Get("HX-Request") != "" {
return c.Render("terminal_content", data)
}
return c.Render("terminal", data)
}
func TerminalWS(c *websocket.Conn) {