feat(theme): ship exactly 2 themes (SRC default + VNClagoon); rebrand user-facing VNCmail+
Product decision 2026-08-05: exactly SRC (default) and VNClagoon ship as selectable themes. Everything else (Qui, Nord, Catppuccin, Solarized, Roundcube Elastic, Aurora Glass) is hidden via ThemePolicy.disabledBuiltinThemes rather than deleted - cheap to re-enable later, zero code lost. Also removed the hardcoded "Default/Bulwark" theme card from the Settings > Themes grid (product wants exactly 2 theme choices, not 3). Separately, found and fixed real "still says Bulwark" branding gaps: - All 24 locale files: "Bulwark"/"Bulwark Mail"/"Bulwark Webmail" -> "VNCmail+" in every user-facing string (verified via the translations test, which only checks structural key parity across locales, not content - a straight string swap is safe against it. 48/48 still pass). - PWA manifest fallback app name, package.json description/author. - Demo mode fixtures: the "Welcome to Bulwark Mail!" email and identity signature a first-time demo user actually sees. - The demo empty-state's logo was hardcoded to a literal Bulwark SVG file regardless of active theme - a real bug, not just stale text, since lib/theme-logo.ts's resolveThemeLogo() already exists and is already used correctly by the login page and nav rail for exactly this (theme-aware SRC mark / VNClagoon wordmark). Wired the same helper in here instead of a hardcoded path. NOT touched: internal code comments referencing "Bulwark" as historical/ attribution context (e.g. design-rationale comments explaining why a value differs from Bulwark's original) - those are harmless and a full-repo sweep of every comment wasn't the ask. Verified: typecheck clean, lint clean, translations test 48/48 passing.
This commit is contained in:
@@ -72,21 +72,11 @@ export function ThemesSettings() {
|
||||
|
||||
{/* Theme Grid */}
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
||||
{/* Default theme card */}
|
||||
<ThemeCard
|
||||
name="Default"
|
||||
author="Bulwark"
|
||||
isDefaultTheme
|
||||
variants={['light', 'dark']}
|
||||
isDark={isDark}
|
||||
isActive={activeThemeId === null}
|
||||
isBuiltIn
|
||||
isDefault={!themePolicy.defaultThemeId}
|
||||
disabled={Boolean(forcedThemeId)}
|
||||
onActivate={() => handleActivate(null)}
|
||||
/>
|
||||
|
||||
{/* Installed themes */}
|
||||
{/* No "Default/Bulwark" card: product decision 2026-08-05 ships exactly
|
||||
two themes (SRC default, VNClagoon) - see DEFAULT_THEME_POLICY in
|
||||
lib/admin/types.ts. The underlying activateTheme(null) capability
|
||||
stays reachable programmatically (e.g. an admin clearing
|
||||
defaultThemeId), just not offered as a selectable card here. */}
|
||||
{visibleThemes.map(theme => {
|
||||
const isForceEnabled = theme.id === forcedThemeId || theme.forceEnabled || isThemeForceEnabled(theme.id);
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user