diff --git a/internal/dashboard/handlers.go b/internal/dashboard/handlers.go index a911fdd..558a7ee 100644 --- a/internal/dashboard/handlers.go +++ b/internal/dashboard/handlers.go @@ -4,6 +4,7 @@ import ( "database/sql" "html/template" "log" + "math" "net/http" "os" "strconv" @@ -135,6 +136,7 @@ func getAllSites(db *sql.DB) ([]models.Site, error) { if err := rows.Scan(&site.ID, &site.Name, &site.URL, &site.IsUp, &site.LastCheck); err != nil { return nil, err } + site.LastCheck = math.Round(site.LastCheck * 1000) sites = append(sites, site) } return sites, nil diff --git a/internal/dashboard/templates/dashboard.html b/internal/dashboard/templates/dashboard.html index c4a2e26..ac7cac1 100644 --- a/internal/dashboard/templates/dashboard.html +++ b/internal/dashboard/templates/dashboard.html @@ -4,69 +4,85 @@ Webring Dashboard - - + + + +
-

Webring Dashboard

+ +

+ + Webring Dashboard +

+
-
-

Add New Site

-
- - - - -
-
-
-

Site List

-
- - - - - - - - - - - - - {{range .}} - - - - - - - - - {{end}} - -
IDNameURLStatusLast CheckActions
{{.ID}}{{.Name}}{{.URL}} - {{if .IsUp}} - Up - {{else}} - Down - {{end}} - {{.LastCheck}} -
-
- - - -
-
- -
-
-
-
-
+
+ + + + + + + + + + + + + + + + + + + + + {{range .}} + + + + + + + + + {{end}} + +
IDNameURLStatusPingActions
+ + +
{{.ID}} +
+ + + + +
+
+ {{if .IsUp}} + Up + {{else}} + Down + {{end}} + {{.LastCheck}} +
+ +
+
+ +
+
+
+
\ No newline at end of file diff --git a/static/dashboard.css b/static/dashboard.css new file mode 100644 index 0000000..1059039 --- /dev/null +++ b/static/dashboard.css @@ -0,0 +1,147 @@ +@import "/static/reset.css"; + +:root { + --color-primary-100: #dbeafe; + --color-primary-900: #1e3a8a; + --color-primary-950: #172554; + + --color-gray-100: #f4f4f5; + --color-gray-400: #a1a1aa; + --color-gray-600: #52525b; + --color-gray-900: #18181b; + --color-gray-950: #09090b; + + --color-green-100: #dcfce7; + --color-green-700: #15803d; + + --color-red-100: #fee2e2; + --color-red-700: #b91c1c; + + font-family: Inter, sans-serif; + font-feature-settings: 'liga' 1, 'calt' 1; /* fix for Chrome */ + font-weight: 500; +} + +@supports (font-variation-settings: normal) { + :root { font-family: InterVariable, sans-serif; } +} + +body { + background-color: var(--color-gray-950); + color: var(--color-gray-100); +} + +header { + background-color: var(--color-primary-950); + color: var(--color-primary-100); + padding: 1rem; + text-align: center; +} + +header h1 { + font-weight: bold; +} + +main { + max-width: 1200px; + margin: 2rem auto; + padding: 0 1rem; +} + +.table-responsive { + overflow-x: auto; +} + +table { + width: 100%; + border-collapse: separate; + border-spacing: 0; + border-radius: 4px; + overflow: hidden; + border: 1px var(--color-gray-900) solid; +} + +th, td { + padding: .5rem 1rem; + text-align: left; + border-bottom: 1px solid var(--color-gray-900); +} + +td { + border-right: 1px solid var(--color-gray-900); +} + +td:last-child { + border-right: none; +} + +th { + background-color: var(--color-primary-900); + color: var(--color-primary-100); + font-weight: 600; + text-transform: uppercase; + font-size: .875rem; +} + +.cell { + width: 100%; + justify-content: stretch; + display: flex; + gap: .5rem; +} + +tr:last-child td { + border-bottom: none; +} + +.badge { + width: 100%; + display: flex; + justify-content: center; + padding: 0.25rem 0.5rem; + border-radius: 4px; + font-size: 0.875rem; + font-weight: 600; + text-transform: uppercase; +} + +.badge-success { + background-color: var(--color-green-700); + color: var(--color-green-100); +} + +.badge-danger { + background-color: var(--color-red-700); + color: var(--color-red-100); +} + +input { + width: 100%; + min-width: 6rem; + border: none; + background: transparent; + border-radius: 4px; + font-size: 1rem; +} + +input[type=number] { + width: 3rem; + min-width: 3rem; +} + +input[type=url] { + min-width: 10rem; +} + +input:focus { + outline: none; + box-shadow: 0 0 0 1px var(--color-gray-400), 0 0 0 4px var(--color-gray-600); +} + +input::placeholder { + color: var(--color-gray-600); +} + +form { + display: none; +} diff --git a/static/reset.css b/static/reset.css new file mode 100644 index 0000000..860190f --- /dev/null +++ b/static/reset.css @@ -0,0 +1,67 @@ +*, ::before, ::after { + box-sizing: border-box; +} + +html, :host { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + -moz-tab-size: 4; + tab-size: 4; + font-feature-settings: normal; + font-variation-settings: normal; + -webkit-tap-highlight-color: transparent; +} + +body { + margin: 0; + line-height: inherit; +} + +a { + color: inherit; + text-decoration: inherit; +} + +h1, h2, h3, h4, h5, h6 { + font-size: inherit; + font-weight: inherit; +} + +button, input, optgroup, select, textarea { + font-family: inherit; + font-feature-settings: inherit; + font-variation-settings: inherit; + font-size: 100%; + font-weight: inherit; + line-height: inherit; + letter-spacing: inherit; + color: inherit; + margin: 0; + padding: 0; +} + +button, +input:where([type='button']), +input:where([type='reset']), +input:where([type='submit']) { + -webkit-appearance: button; + background-color: transparent; + background-image: none; + border: none; +} + +button, [role=button] { + cursor: pointer; +} + +button, select { + text-transform: none; +} + +b, strong { + font-weight: bolder; +} + +blockquote, dl, dd, h1, h2, h3, h4, h5, h6, hr, figure, p, pre { + margin: 0; +} \ No newline at end of file diff --git a/static/styles.css b/static/styles.css deleted file mode 100644 index 7b81cbe..0000000 --- a/static/styles.css +++ /dev/null @@ -1,177 +0,0 @@ -:root { - --primary-color: #3498db; - --secondary-color: #2ecc71; - --danger-color: #e74c3c; - --text-color: #333; - --background-color: #f5f5f5; - --card-background: #fff; -} - -body { - font-family: 'Roboto', sans-serif; - line-height: 1.6; - margin: 0; - padding: 0; - background-color: var(--background-color); - color: var(--text-color); -} - -header { - background-color: var(--primary-color); - color: white; - padding: 1rem; - text-align: center; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); -} - -h1 { - margin: 0; - font-weight: 300; -} - -main { - max-width: 1200px; - margin: 2rem auto; - padding: 0 1rem; -} - -h2 { - color: var(--primary-color); - margin-bottom: 1rem; -} - -.card { - background-color: var(--card-background); - border-radius: 8px; - padding: 1.5rem; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); - margin-bottom: 2rem; -} - -.table-responsive { - overflow-x: auto; -} - -table { - width: 100%; - border-collapse: separate; - border-spacing: 0; - background-color: var(--card-background); - border-radius: 8px; - overflow: hidden; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); -} - -th, td { - padding: 1rem; - text-align: left; - border-bottom: 1px solid #e0e0e0; -} - -th { - background-color: var(--primary-color); - color: white; - font-weight: 500; -} - -tr:last-child td { - border-bottom: none; -} - -.badge { - display: inline-block; - padding: 0.25rem 0.5rem; - border-radius: 4px; - font-size: 0.875rem; - font-weight: 500; -} - -.badge-success { - background-color: var(--secondary-color); - color: white; -} - -.badge-danger { - background-color: var(--danger-color); - color: white; -} - -input[type="text"], -input[type="url"], -input[type="number"] { - width: 100%; - padding: 0.5rem; - margin-bottom: 1rem; - border: 1px solid #ccc; - border-radius: 4px; - font-size: 1rem; -} - -.btn { - display: inline-block; - padding: 0.5rem 1rem; - border: none; - border-radius: 4px; - font-size: 0.875rem; - cursor: pointer; - transition: background-color 0.3s ease; - white-space: nowrap; -} - -.btn-primary { - background-color: var(--primary-color); - color: white; -} - -.btn-secondary { - background-color: var(--secondary-color); - color: white; -} - -.btn-danger { - background-color: var(--danger-color); - color: white; -} - -.btn:hover { - opacity: 0.9; -} - -.action-forms { - display: flex; - flex-direction: column; - gap: 0.5rem; -} - -.inline-form { - display: flex; - flex-wrap: wrap; - gap: 0.5rem; - align-items: center; -} - -.update-form { - width: 100%; -} - -.update-form input { - flex: 1; - min-width: 120px; - margin-bottom: 0; -} - -.remove-form { - align-self: flex-start; -} - -@media (max-width: 768px) { - .update-form { - flex-direction: column; - align-items: flex-start; - } - - .update-form input, - .update-form button { - width: 100%; - } -} \ No newline at end of file