Multi-Brand Theming
Flo supports multiple brands (whitelabeling) through runtime brand detection. Each brand has its own visual identity while sharing the same codebase.
Current Brands
| Brand | Detection | Font | Description |
|---|---|---|---|
| Flo | Default (any hostname) | Bricolage Grotesque | Default green theme |
| Respirastudio | Hostname contains respirastudio | Playfair Display | Fitness studio theme |
How It Works
1. Brand Detection
At application startup, the frontend detects the brand from the hostname:
export function isRespirastudioUI(): boolean {
if (environment.forceRespirastudioUI) return true;
return window.location.hostname.includes('respirastudio');
}
The FORCE_RESPIRASTUDIO_UI environment variable can override detection for testing.
2. Theme Loading
Each brand has configuration files in dist/configs/:
| File | Content |
|---|---|
flo.configs.json | Title, PWA manifest path, font URLs |
flo.theme.json | 40+ CSS variable tokens (colors, spacing) |
respirastudio.configs.json | Same structure, Respirastudio values |
respirastudio.theme.json | Same structure, Respirastudio colors |
3. CSS Variable Injection
On startup, the app reads the brand's theme JSON and injects CSS variables into :root:
:root {
--primary-color: #4CAF50; /* Flo green */
--primary-color-text: #ffffff;
--surface-ground: #f5f5f5;
/* ... 40+ tokens */
}
All UI components reference these CSS variables, making the entire UI automatically theme-aware.
4. Brand-Specific Assets
Each brand has separate:
| Asset | Flo | Respirastudio |
|---|---|---|
| Color palette | Green-based | Custom brand colors |
| Font family | Bricolage Grotesque | Playfair Display |
| PWA manifest | manifest-flo.json | manifest-respirastudio.json |
| Favicon | Flo icon | Respirastudio icon |
| Login background | Flo background image | Respirastudio image |
| Email templates | Flo header/footer | Respirastudio branding |
Backend Theming
The backend serves brand-specific email templates based on the FORCE_RESPIRASTUDIO_UI environment variable. MJML templates include brand-specific:
- Header logo
- Color scheme
- Footer text
- Customer name (via
FLO_CUSTOMER_NAME_*env vars)
Adding a New Brand
- Create
<brand>.configs.jsonand<brand>.theme.jsonindist/configs/ - Add brand detection logic in
environment.ts - Create PWA manifest, favicon, and login assets
- Create MJML email templates with brand header/footer
- Test all UI flows with the new brand
Environment Variables
| Variable | Purpose |
|---|---|
FORCE_RESPIRASTUDIO_UI | Force Respirastudio brand regardless of hostname |
FLO_CUSTOMER_NAME_IT | Customer display name in Italian |
FLO_CUSTOMER_NAME_EN | Customer display name in English |