Brand customization

Brand customization

A Cobuntu integration has two chrome surfaces and Cobuntu makes both wear the customer's brand:

The customer's landing is the visual source of truth. Cobuntu pages + Cobuntu widgets pull from that same source, so a visitor who clicks from yourdomain.com/about (landing) to yourdomain.com/events (Cobuntu page) experiences one continuous brand.


Step 1 — The leader connects their landing

In cobuntu-admin at /[communityTag]/customize, there's a "Sync from landing" section. The leader pastes their landing URL (or it's auto-detected from landingPageUrl on their community record) and hits Sync now.

The scraper opens the landing in a real headless browser, not just regex on HTML — that lets it pick up CSS variables computed at runtime, web-font URLs from @font-face declarations, and button-radius / card-radius defaults from the rendered DOM.

The diff step is intentional. A community might already have a manually-set brandColor and the new scrape produced a slightly different shade — the leader sees both and chooses.


Step 2 — The themeConfig contract

What ends up in communities.themeConfig (a JSONB column) is a flat set of brand tokens:

{
  "brandColor":      "#D4AF37",
  "accentColor":     "#F2D47E",
  "bgColor":         "#0A0A0A",
  "textColor":       "#E0E0E0",
  "headingFont":     "Playfair Display",
  "bodyFont":        "Montserrat",
  "headingFontUrl":  "https://fonts.gstatic.com/...",
  "bodyFontUrl":     "https://fonts.gstatic.com/...",
  "buttonRadius":    "0px",
  "cardRadius":      "22px",
  "inputRadius":     "12px",
  "primaryBtnBg":    "linear-gradient(135deg, #D4AF37 0%, #F2D47E 100%)",
  "primaryBtnText":  "#000000",
  "secondaryBtnBg":  "rgba(255,255,255,0.05)",
  "secondaryBtnText":"#E0E0E0",
  "linkColor":       "#D4AF37"
}

Everything is optional — missing tokens fall back to a Cobuntu default. Each token has a documented purpose; see community-config for the full table.


Step 3 — How Cobuntu pages pick them up

The community-app's root layout reads themeConfig server-side and emits inline CSS variables on <html>:

<html style="
  --brand-color: #D4AF37;
  --accent-color: #F2D47E;
  --bg-color: #0A0A0A;
  --text-color: #E0E0E0;
  --heading-font: Playfair Display;
  --body-font: Montserrat;
  --button-radius: 0px;
  --card-radius: 22px;
  --primary-btn-bg: linear-gradient(135deg, #D4AF37 0%, #F2D47E 100%);
  /* ... */
">

Every component on every Cobuntu page references these variables:

.btn-primary {
  background: var(--primary-btn-bg);
  color: var(--primary-btn-text);
  border-radius: var(--button-radius);
  font-family: var(--body-font);
}

So /feed, /events, /marketplace, /profile, etc. all paint in the customer's brand automatically. There's no per-page override — every Cobuntu surface is derived from the same JSON column.


Step 4 — Widgets inherit the same tokens

When you embed a Cobuntu widget on your landing — <div data-cobuntu-cart> or <CobuntuAuth /> — it picks up CSS variables from its own :root. If you've also configured themeConfig in cobuntu-admin, those tokens are exposed as --cobuntu-* variables and the widget will use them.

:root {
  /* Set these once at the top of your landing's CSS — or just
     let cobuntu-admin's /customize sync set them automatically. */
  --cobuntu-bg: var(--brand-color, transparent);
  --cobuntu-color: var(--text-color, inherit);
  --cobuntu-radius: var(--button-radius, 8px);
  --cobuntu-font: var(--body-font, inherit);
  --cobuntu-hover-bg: var(--accent-color, rgba(0,0,0,0.05));
}

Three customization levels exist for each widget:

See widgets for the per-widget reference (cart, auth, messages, notifications, search). The same tokens drive every one — set them once, every widget on your page paints consistently.


What about cobuntu-admin itself?

cobuntu-admin (the surface community leaders use) is not themed by themeConfig. It's Cobuntu's own dashboard — same brand, same chrome, regardless of which community the leader is managing. The /customize page edits a community's tokens; the admin itself stays in Cobuntu's house style.


Trade-offs of automatic sync

Pros.

  • Zero manual work for leaders. Paste a URL → press button → Cobuntu pages look like the landing.
  • One source of truth. The landing's CSS is the canonical brand; Cobuntu just reads it.
  • Re-syncs at any time. Update the landing, hit Sync, Cobuntu pages update on next request.

Cons.

  • The scrape is an opinion, not a contract. If your landing uses CSS-in-JS with runtime-computed colours, the scraper might pick the wrong shade. Hence the diff step — the leader confirms before writing.
  • Web fonts loaded via JavaScript (Google Fonts variable fonts, some Adobe Fonts loaders) sometimes aren't visible to the scraper. The headless browser waits for load event but not for late-loaded fonts. Manual override is the workaround.

Going deeper

  • Widgets reference — per-widget data-attribute and CSS variable contracts
  • community-config — the full themeConfig schema with every supported token
  • REST API: branding — PATCH endpoint if you're scripting this from your own tooling instead of using cobuntu-admin