Skip to content

feat(brand): operator brand-logo override (#70)#71

Merged
vnykmshr merged 4 commits into
mainfrom
feat/v3.12.0
May 17, 2026
Merged

feat(brand): operator brand-logo override (#70)#71
vnykmshr merged 4 commits into
mainfrom
feat/v3.12.0

Conversation

@vnykmshr
Copy link
Copy Markdown
Collaborator

Closes #70. Drop your SVG at <STATIC_PATH>/img/brand-logo.svg to swap the header logo — the last template-embedded brand surface becomes operator-overridable, completing what v3.10.2's STATIC_PATH overlay started for favicons, fonts, themes, and OG images. Validates well-formed XML with <svg> root, caps at 32 KiB via io.LimitReader, injects class="brand-logo" when absent (string-scan, preserves operator formatting), silently falls back when the file is missing, warns-and-falls-back on validation failure. Operator filesystem is the trust boundary, same model as STATIC_PATH-overlaid CSS/JS since v3.10.2 — documented in docs/configuration.md#branding. Surfaced from log.1mb.dev M3-polish-2 wave-3 feedback.

Three atomic commits: refactor extracts the inline SVG to a per-instance FuncMap helper backed by an embedded asset (and drops the unused logo.svg); feat adds the overlay read + validation + class injection; docs add the Branding section with starter SVG, override contract, and the overlay-eligible asset inventory. Embedded read failure aborts startup as a build invariant. 15 new tests cover embedded-only, overlay-replaces, class injection (missing/preserves/quoted-attrs/single-quotes/newlines/non-svg), all three validation-failure paths, and end-to-end render through TemplateService.

vnykmshr added 4 commits May 17, 2026 18:15
… logo.svg

Move the hardcoded inline brand-logo from base.html into a per-instance
FuncMap helper backed by an embedded asset at web/static/img/brand-logo.svg.
Phase 2 will extend loadBrandLogo to read a STATIC_PATH overlay; for now
this is behavior-preserving.

Embedded read failure aborts startup (build invariant). Deletes the
stale, unreferenced web/static/img/logo.svg.
Read <STATIC_PATH>/img/brand-logo.svg at startup. Validates well-formed XML
with <svg> root, caps at 32 KiB via io.LimitReader, injects class="brand-logo"
when absent (string-scan, preserves operator formatting). Silent fallback when
the file is absent; logs a single warning on malformed/oversize/wrong-root
overlays. Operator filesystem is the trust boundary (same model as CSS/JS
overlay since v3.10.2).

Closes #70.
Add docs/configuration.md#branding section with starter SVG, validation
contract, theme-reactivity guidance, and the overlay-eligible brand asset
inventory. One-line pointer added in GETTING-STARTED's filesystem-overrides
paragraph. CHANGELOG entry under Unreleased.
Three self-review fixups surfaced by /code-review:

- NewTemplateService now calls cancel() before returning the loadTemplates
  error, matching the obcache and loadBrandLogo failure paths so the
  goflow scheduler goroutine started by setupTemplateMaintenance can shut
  down cleanly. Pre-existing leak made visible by adjacent changes.
- loadBrandLogo runs the embedded fallback through injectBrandLogoClass,
  so CSS sizing keeps working even if a future refactor drops the class
  from the embedded SVG. Latent today, structural going forward.
- GetTemplateFuncMap docstring now states the returned map is stateless;
  per-instance helpers like brandLogoSVG live on TemplateService.funcMap.
@vnykmshr
Copy link
Copy Markdown
Collaborator Author

Code review

No issues found. Three sub-80 findings (cancel-leak on adjacent loadTemplates error path, embedded fallback bypassing injectBrandLogoClass, GetTemplateFuncMap docstring drift) were reconsidered on merit and resolved in ca4b6dd.

@vnykmshr vnykmshr merged commit 8b940d1 into main May 17, 2026
6 checks passed
@vnykmshr vnykmshr deleted the feat/v3.12.0 branch May 17, 2026 13:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(brand): customizable header brand-logo asset

1 participant