diff --git a/cmd/server/main.go b/cmd/server/main.go index 1b58f42..0b050fa 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -51,12 +51,22 @@ func (a *API) HandleLatest(w http.ResponseWriter, r *http.Request) { }) } + func (a *API) HandleHistory(w http.ResponseWriter, r *http.Request) { + + raw := a.buf.GetLast(100) + + out := make([]int, len(raw)) + for i, v := range raw { + out[i] = int(v) + } + json.NewEncoder(w).Encode(map[string]interface{}{ - "bytes": a.buf.GetLast(100), + "bytes": out, }) } + // === FIFO READER === func startPipeReader(ctx context.Context, buf *adapter.RingBuffer, path string) { go func() { @@ -119,19 +129,23 @@ func main() { buf: buf, startTime: time.Now(), } - fs := http.FileServer(http.Dir("/home/user/temp/golang/web")) + http.Handle("/api/", http.StripPrefix("/api", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - switch r.URL.Path { - case "/latest": - cors(api.HandleLatest)(w, r) + + w.Header().Set("Content-Type", "application/json") + switch r.URL.Path { + case "/latest": + cors(api.HandleLatest)(w, r) case "/history": cors(api.HandleHistory)(w, r) case "/health": cors(api.HandleHealth)(w, r) - } + default: + http.Error(w, "not found", 404) + } }))) - http.Handle("/", fs) + http.Handle("/", http.FileServer(http.Dir("/home/user/temp/golang/web"))) log.Println("server :8080") log.Fatal(http.ListenAndServe(":8080", nil)) diff --git a/web/css/style.css b/web/css/style.css new file mode 100644 index 0000000..8d619ae --- /dev/null +++ b/web/css/style.css @@ -0,0 +1,151 @@ +* { + box-sizing: border-box; +} + +body { + margin: 0; + font-family: monospace; + background: #050805; + color: #00ff88; + padding: 12px; +} + +h1 { + text-align: center; + font-size: 22px; + margin: 0 0 15px; +} + +/* ===== GRID ===== */ + +.grid { + display: grid; + grid-template-columns: 1fr; + gap: 12px; +} + +/* Desktop */ +@media (min-width: 900px) { + .grid { + grid-template-columns: 1fr 1fr; + } + + .wide { + grid-column: span 2; + } +} + +/* ===== CARD ===== */ + +.card { + border: 1px solid #00ff88; + border-radius: 10px; + padding: 14px; + background: rgba(0,255,136,0.05); + overflow: hidden; +} + +.card h3 { + margin: 0 0 10px; + font-size: 18px; +} + +/* ===== STATUS ===== */ + +#status { + font-size: 28px; + font-weight: bold; + margin-bottom: 8px; +} + +#meta { + font-size: 14px; + opacity: 0.8; + word-break: break-word; +} + +/* ===== LATEST ===== */ + +#latest { + font-size: 36px; + font-weight: bold; + margin-bottom: 12px; +} + +/* ===== BITS ===== */ + +#bits { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 8px; +} + +.bit { + height: 52px; + border: 1px solid #00ff88; + border-radius: 8px; + display: flex; + justify-content: center; + align-items: center; + font-size: 22px; + font-weight: bold; +} + +.bit.on { + background: #00ff88; + color: #000; +} + +/* Tablet/Desktop */ +@media (min-width: 700px) { + #bits { + grid-template-columns: repeat(8, 1fr); + } +} + +/* ===== HISTORY ===== */ + +#history { + font-size: 13px; + line-height: 1.35; + max-height: 420px; + overflow-y: auto; + white-space: nowrap; + padding-right: 4px; +} + +/* Desktop */ +@media (min-width: 900px) { + #history { + font-size: 12px; + max-height: 520px; + } +} + +/* ===== PHONE ===== */ + +@media (max-width: 500px) { + + h1 { + font-size: 18px; + } + + #status { + font-size: 22px; + } + + #latest { + font-size: 30px; + } + + .bit { + height: 44px; + font-size: 18px; + } + + #history { + font-size: 16px; + line-height: 1.5; + max-height: 55vh; + } +} diff --git a/web/dashboard.html b/web/dashboard.html new file mode 100644 index 0000000..a14fa50 --- /dev/null +++ b/web/dashboard.html @@ -0,0 +1,38 @@ + + +
+ +