Переглянути джерело

Brand control UI with ferrite.fm logo

main
Jan 1 місяць тому
джерело
коміт
c1c50b23b3
7 змінених файлів з 22 додано та 11 видалено
  1. BIN
      docs/Logo/Minimalist logo.png
  2. BIN
      docs/Logo/unused/ferrite-fm-Logo.png
  3. BIN
      docs/Logo/unused/ferrite-fm-Logo.psd
  4. BIN
      docs/Logo/unused/ferrite-fm-Logo_ultrahighres.png
  5. +10
    -0
      internal/control/control.go
  6. BIN
      internal/control/logo.png
  7. +12
    -11
      internal/control/ui.html

BIN
docs/Logo/Minimalist logo.png Переглянути файл

Перед Після
Ширина: 2046  |  Висота: 769  |  Розмір: 245KB

BIN
docs/Logo/unused/ferrite-fm-Logo.png Переглянути файл

Перед Після
Ширина: 644  |  Висота: 154  |  Розмір: 166KB

BIN
docs/Logo/unused/ferrite-fm-Logo.psd Переглянути файл


BIN
docs/Logo/unused/ferrite-fm-Logo_ultrahighres.png Переглянути файл

Перед Після
Ширина: 16100  |  Висота: 3850  |  Розмір: 14MB

+ 10
- 0
internal/control/control.go Переглянути файл

@@ -22,6 +22,9 @@ import (
//go:embed ui.html
var uiHTML []byte

//go:embed logo.png
var logoPNG []byte

// TXController is an optional interface the Server uses to start/stop TX
// and apply live config changes.
type TXController interface {
@@ -279,6 +282,7 @@ func (s *Server) SetHardReload(fn func()) {
func (s *Server) Handler() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", s.handleUI)
mux.HandleFunc("/logo", s.handleLogo)
mux.HandleFunc("/healthz", s.handleHealth)
mux.HandleFunc("/status", s.handleStatus)
mux.HandleFunc("/dry-run", s.handleDryRun)
@@ -307,6 +311,12 @@ func (s *Server) handleUI(w http.ResponseWriter, r *http.Request) {
w.Write(uiHTML)
}

func (s *Server) handleLogo(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "image/png")
w.Header().Set("Cache-Control", "public, max-age=3600")
w.Write(logoPNG)
}

func (s *Server) handleStatus(w http.ResponseWriter, _ *http.Request) {
s.mu.RLock()
cfg := s.cfg


BIN
internal/control/logo.png Переглянути файл

Перед Після
Ширина: 2046  |  Висота: 769  |  Розмір: 245KB

+ 12
- 11
internal/control/ui.html Переглянути файл

@@ -22,16 +22,21 @@ body{background:linear-gradient(180deg,#fbfcfe 0%,var(--bg) 100%);color:var(--te
button,input,select{font:inherit}button{user-select:none}
.app{max-width:1560px;margin:0 auto;padding:24px}
/* Header */
.header{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;padding:4px 0 20px;border-bottom:1px solid var(--border);margin-bottom:20px}
.header-main{display:flex;flex-direction:column;gap:8px}
.header h1{font-size:28px;font-weight:800;letter-spacing:-.03em}
.header{display:flex;align-items:center;justify-content:space-between;gap:18px;padding:2px 0 18px;border-bottom:1px solid var(--border);margin-bottom:20px}
.header-main{display:flex;align-items:center;min-height:64px}
.brand-lockup{display:flex;align-items:center;gap:0}
.brand-logo{height:62px;width:auto;display:block;object-fit:contain}
.brand-title{font-size:28px;font-weight:800;letter-spacing:-.03em}
.header-note{font-size:13px;color:var(--text-muted)}
.header-sub{display:flex;flex-wrap:wrap;gap:8px}
.badge{display:inline-flex;align-items:center;gap:8px;min-height:28px;padding:0 10px;border:1px solid var(--border);border-radius:999px;background:var(--surface2);color:var(--text-dim);font-size:11px;text-transform:uppercase;letter-spacing:.08em}
.badge strong{white-space:nowrap}
.badge .tag{margin-left:2px}
.badge strong{color:var(--text);font-weight:700}
.header-status{display:flex;align-items:center;gap:10px;padding-top:6px}
.header-status{display:flex;align-items:center;gap:8px;padding-top:0;padding-right:2px}
.header-status .danger-btn{min-height:36px;padding:0 14px;border-radius:10px;background:rgba(176,48,48,.06);border-color:rgba(176,48,48,.22);font-size:11px;letter-spacing:.08em}
.header-status .danger-btn:hover:not(:disabled){background:rgba(176,48,48,.1)}
.header-status .led{margin-left:4px}
/* LED */
.led{width:10px;height:10px;border-radius:50%;background:#333;transition:all .25s;flex-shrink:0}
.led.on-green{background:var(--green);box-shadow:0 0 0 3px rgba(13,148,74,.16)}
@@ -285,19 +290,15 @@ input.input-error{border-color:var(--red);box-shadow:0 0 0 3px rgba(176,48,48,.1
.toast.warn{background:var(--amber);color:#141414}.toast.info{background:var(--text-dim);color:#fff}
/* Responsive */
@media(max-width:980px){.app{max-width:100%;padding:14px}.tab-columns.two{grid-template-columns:1fr}.tx-bar{grid-template-columns:1fr}.tx-state-wrap{align-items:flex-start}.status-hint{text-align:left}.quick-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.signal-grid{grid-template-columns:1fr}.flow-master{grid-template-columns:1fr}.flow-topbar,.flow-bottom{grid-template-columns:repeat(2,minmax(0,1fr))}.flow-chain{grid-template-columns:repeat(4,minmax(140px,1fr))}}
@media(max-width:640px){.app{padding:12px}.header{flex-direction:column;gap:10px}.header h1{font-size:22px}.badge{width:100%;justify-content:space-between}.badge strong{max-width:52%;overflow:hidden;text-overflow:ellipsis}.quick-grid{grid-template-columns:1fr 1fr;gap:8px}.ctrl-row{flex-direction:column;align-items:stretch}.ctrl-label-wrap{min-width:auto}.ctrl-input{flex-wrap:wrap}.ingest-grid{grid-template-columns:1fr}input[type="number"]{width:100%;text-align:left}.actions-row,.tx-actions{flex-direction:column}.tx-btn,.ghost-btn,.apply-btn,.preset-btn,.danger-btn{width:100%}.freq-display{font-size:31px}.flow-master,.flow-topbar,.flow-bottom,.flow-chain{grid-template-columns:1fr}}
@media(max-width:640px){.app{padding:12px}.header{flex-direction:column;align-items:flex-start;gap:10px}.brand-logo{height:54px}.badge{width:100%;justify-content:space-between}.badge strong{max-width:52%;overflow:hidden;text-overflow:ellipsis}.quick-grid{grid-template-columns:1fr 1fr;gap:8px}.ctrl-row{flex-direction:column;align-items:stretch}.ctrl-label-wrap{min-width:auto}.ctrl-input{flex-wrap:wrap}.ingest-grid{grid-template-columns:1fr}input[type="number"]{width:100%;text-align:left}.actions-row,.tx-actions{flex-direction:column}.tx-btn,.ghost-btn,.apply-btn,.preset-btn,.danger-btn{width:100%}.freq-display{font-size:31px}.flow-master,.flow-topbar,.flow-bottom,.flow-chain{grid-template-columns:1fr}}
</style>
</head>
<body>
<div class="app">
<div class="header">
<div class="header-main">
<h1>ferrite.fm Control Plane</h1>
<div class="header-note">Operate confidently: tune fast, inspect state instantly, diagnose only when needed.</div>
<div class="header-sub">
<div class="badge"><span>Backend</span><strong id="badge-backend">--</strong></div>
<div class="badge"><span>Mode</span><strong id="badge-mode">Control Plane</strong></div>
<div class="badge"><span>Live Config</span><strong id="badge-live">--</strong></div>
<div class="brand-lockup">
<img class="brand-logo" src="/logo" alt="ferrite.fm logo">
</div>
</div>
<div class="header-status">


Завантаження…
Відмінити
Зберегти