Skip to content

Configurable widget theme (scheme, accent, position, label) #8

Description

@ezzcodeezzlife

Summary

Let owners theme the widget so it does not always look like feedback2code’s orange terminal chip. The marketing FAQ already promises this: “The widget auto-detects light and dark mode. … Custom theming options are coming soon.” (components/seo/home-next-seo.tsx).

Today colors are hardcoded in the iframe script from prefers-color-scheme (lib/widget-embed.ts). There is no configure UI and no way to force light on a dark marketing site (or vice versa).

Current behavior

Inside buildFrameWidgetInlineScript:

  • isDark = matchMedia("(prefers-color-scheme: dark)")
  • Two palettes C with accent #ff6b00, monospace stack Fira/JetBrains, FAB label [ feedback ], bottom-right only (safe-area-inset-*).
  • Parent iframe is a large transparent hit-rect, also bottom-right (buildParentEmbedScript).

Configure (configure/page.tsx) cannot set appearance. Widget script cache is max-age=300; iframe HTML is no-store.

hello (lib/widget-hello.ts) does not return theme.

Problem

Agencies will not paste a widget that fights the client’s brand (wrong orange, wrong corner covering a chat widget like Intercom/Crisp, dark FAB on a dark footer). This is a sales blocker, not polish.

Proposed design

v1 knobs (keep the list short)

Setting Values Default
Color scheme system / light / dark system (today)
Accent hex (we validate) #ff6b00
Position bottom-right / bottom-left bottom-right
Label string, max 24 chars feedback

Explicitly not v1: arbitrary CSS injection, custom fonts, border-radius scales, hiding the brand entirely (keep a discreet “f2c” or “feedback2code” in the panel footer for trust; paid “remove branding” can be Pro later).

Config storage + delivery

Store on RepositoryConfig (JSON widgetTheme or columns). Same hello/config channel as path allowlist so changing theme does not require recopying the snippet.

Flow:

  1. Parent script requests config (GET hello//h) with widget id + origin.
  2. Response includes { theme: { scheme, accent, position, label } }.
  3. Parent sizes/positions the iframe (left vs right).
  4. Parent posts theme into the iframe with the existing f2c: "parent" message (extend payload) or the iframe fetches hello too. Prefer one fetch in the parent, then postMessage, so the iframe does not race.

If hello fails: fall back to today’s hardcoded defaults (widget still works).

Live preview on the configure page: a static mini-FAB using the same tokens. Do not iframe production feedback2code.dev into the dashboard unless easy.

Contrast / a11y

  • If they pick a light accent, FAB text should flip to #000 vs #fff (we already use btnFg black on orange). Compute contrast; if accent is too close to bg, show a configure warning.
  • Keep existing :focus outlines; do not drop aria-label on close.
  • Left position must still respect safe-area-inset-left on iOS.

Plan gating (assumption)

v1 un-gated (or gate only “remove branding”). Theme is why agencies embed. If we need a Pro hook, “custom accent” is the upsell — but shipping it on Free will convert more than locking it. Recommendation: all v1 knobs on Free.

Update FAQ from “coming soon” to the real list when this ships.

Assumptions

  • We stay a designed widget (terminal-ish), not a fully white-label CSS soup. Accent + scheme + corner is 90% of Intercom-style requests.
  • No runtime window.Feedback2Code('theme', …) API in v1; configure UI is the source of truth (avoids clients checking theme into git and drifting).
  • label is owner-controlled and appears on someone else’s site — strip RTL override chars / XSS; it is textContent, never innerHTML.
  • Dark/light follows widget setting, not the dashboard user’s OS. Client visitors get the owner’s choice when not system.

Acceptance criteria

  • Configure: scheme, accent (color input + hex), position, label; save without regenerating widget id.
  • Live site updates within ~1 minute (hello cache), no snippet recopy.
  • bottom-left FAB does not cover typical left-nav; iframe hit-rect moves with it.
  • light on a dark OS still renders the light palette (and vice versa).
  • Invalid hex rejected at save; missing config uses defaults.
  • FAQ copy updated when shipped.
  • Accent used for FAB, header label, and the 4px accent bar (current C.accent usages).

Out of scope

  • Per-page theme overrides.
  • Matching Intercom/Crisp collision avoidance (z-index is already 2147483647; document “put others lower” rather than building a collider).
  • Uploading a custom FAB icon.

Implementation notes

  • lib/widget-embed.ts — parameterize C, FAB side, label; stop closing over hardcoded orange only.
  • Parent iframe cssText position currently bottom:0;right:0 — must switch to left.
  • Shared types with hello payload and Prisma JSON.
  • app/embed/frame/route.ts could accept ?accent= as a cache-buster; prefer postMessage so we do not leak a huge query cache surface.

See also

  • Page-path allowlist (shared hello/config endpoint — implement one config API, two features)
  • Element picker (pick overlay color should use the same accent)
  • Use-case landings (show a themed widget screenshot on the agency page)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:dashboardDashboard, repo configure, accountarea:widgetEmbeddable widget, iframe, parent scriptenhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions