Part A: shared app_list_row partial — ONE row grammar on four surfaces (v0.126.0)

- templates/app_row.html: app_list_row/app_list_row_end (layout_start/_end idiom) — icon+name
  (+optional secondary) left, caller action block right; compact 44px row; logoURL→PNG→
  optional FallbackIcon→hidden onerror chain
- applied: Távoli mentés toggle list, Visszaállítás restore-to-verify + .fab lists, dashboard
  Telepített alkalmazások (state edge + data-href preserved); Alkalmazások collapsed headers
  ALIGNED (icon+name left, status dot moved right before chevron; expander untouched)
- funcmap: dict + appHref; OffboxAppRow/AppBackupRow gain Slug
- style.css: .app-row family; stack-card/stack-info/stack-logo/stack-name/stack-desc/
  stack-actions rules retired (dashboard rows now shared); .app-backup-row-header matched
  to the shared row height
- scripts/app_row_dedup_gate.py: row markup single-sourced (red-proven: pasted old
  storage-path-item block → exit 1); render tests per surface (app_row_test.go)
- NO behavior change: toggle/download/expander actions byte-identical
This commit is contained in:
2026-07-13 11:26:48 +02:00
parent 7b3e7f2e71
commit 3eacb6c326
11 changed files with 380 additions and 87 deletions
+24
View File
@@ -379,6 +379,30 @@ func (s *Server) templateFuncMap() template.FuncMap {
b, _ := json.Marshal(v)
return template.JS(b)
},
// dict builds a map from key/value pairs — the argument carrier for the shared
// app_list_row partial (app_row.html). Keys must be strings.
"dict": func(pairs ...interface{}) (map[string]interface{}, error) {
if len(pairs)%2 != 0 {
return nil, fmt.Errorf("dict: odd argument count %d", len(pairs))
}
m := make(map[string]interface{}, len(pairs)/2)
for i := 0; i < len(pairs); i += 2 {
k, ok := pairs[i].(string)
if !ok {
return nil, fmt.Errorf("dict: key %d is not a string", i)
}
m[k] = pairs[i+1]
}
return m, nil
},
// appHref is appPageURL that yields "" for a slug-less stack, so the shared row
// partial's {{with .Href}} skips the data-href attribute entirely.
"appHref": func(slug string) string {
if slug == "" {
return ""
}
return s.cfg.AppPageURL(slug)
},
// pageMatch returns true if currentPage is in the pages slice.
// Used to filter page-specific alerts in layout.html.
"pageMatch": func(pages []string, currentPage string) bool {