Skip to content

Commit f0b0742

Browse files
authored
feat(theme): added custom envvars for themes (#1089)
* feat(theme): added custom envvars for themes * add regec
1 parent 8c9e182 commit f0b0742

File tree

4 files changed

+237
-148
lines changed

4 files changed

+237
-148
lines changed

apps/sim/app/layout.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { SpeedInsights } from '@vercel/speed-insights/next'
33
import type { Metadata, Viewport } from 'next'
44
import { PublicEnvScript } from 'next-runtime-env'
55
import { BrandedLayout } from '@/components/branded-layout'
6+
import { generateThemeCSS } from '@/lib/branding/inject-theme'
67
import { generateBrandedMetadata, generateStructuredData } from '@/lib/branding/metadata'
78
import { env } from '@/lib/env'
89
import { isHosted } from '@/lib/environment'
@@ -62,6 +63,7 @@ export const metadata: Metadata = generateBrandedMetadata()
6263

6364
export default function RootLayout({ children }: { children: React.ReactNode }) {
6465
const structuredData = generateStructuredData()
66+
const themeCSS = generateThemeCSS()
6567

6668
return (
6769
<html lang='en' suppressHydrationWarning>
@@ -74,6 +76,16 @@ export default function RootLayout({ children }: { children: React.ReactNode })
7476
}}
7577
/>
7678

79+
{/* Theme CSS Override */}
80+
{themeCSS && (
81+
<style
82+
id='theme-override'
83+
dangerouslySetInnerHTML={{
84+
__html: themeCSS,
85+
}}
86+
/>
87+
)}
88+
7789
{/* Meta tags for better SEO */}
7890
<meta name='color-scheme' content='light dark' />
7991
<meta name='format-detection' content='telephone=no' />

apps/sim/lib/branding/branding.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import { getEnv } from '@/lib/env'
22

3+
export interface ThemeColors {
4+
primaryColor?: string
5+
primaryHoverColor?: string
6+
secondaryColor?: string
7+
accentColor?: string
8+
accentHoverColor?: string
9+
backgroundColor?: string
10+
}
11+
312
export interface BrandConfig {
413
name: string
514
logoUrl?: string
@@ -9,6 +18,7 @@ export interface BrandConfig {
918
documentationUrl?: string
1019
termsUrl?: string
1120
privacyUrl?: string
21+
theme?: ThemeColors
1222
}
1323

1424
/**
@@ -23,6 +33,29 @@ const defaultConfig: BrandConfig = {
2333
documentationUrl: undefined,
2434
termsUrl: undefined,
2535
privacyUrl: undefined,
36+
theme: {
37+
primaryColor: '#701ffc',
38+
primaryHoverColor: '#802fff',
39+
secondaryColor: '#6518e6',
40+
accentColor: '#9d54ff',
41+
accentHoverColor: '#a66fff',
42+
backgroundColor: '#0c0c0c',
43+
},
44+
}
45+
46+
const getThemeColors = (): ThemeColors => {
47+
return {
48+
primaryColor: getEnv('NEXT_PUBLIC_BRAND_PRIMARY_COLOR') || defaultConfig.theme?.primaryColor,
49+
primaryHoverColor:
50+
getEnv('NEXT_PUBLIC_BRAND_PRIMARY_HOVER_COLOR') || defaultConfig.theme?.primaryHoverColor,
51+
secondaryColor:
52+
getEnv('NEXT_PUBLIC_BRAND_SECONDARY_COLOR') || defaultConfig.theme?.secondaryColor,
53+
accentColor: getEnv('NEXT_PUBLIC_BRAND_ACCENT_COLOR') || defaultConfig.theme?.accentColor,
54+
accentHoverColor:
55+
getEnv('NEXT_PUBLIC_BRAND_ACCENT_HOVER_COLOR') || defaultConfig.theme?.accentHoverColor,
56+
backgroundColor:
57+
getEnv('NEXT_PUBLIC_BRAND_BACKGROUND_COLOR') || defaultConfig.theme?.backgroundColor,
58+
}
2659
}
2760

2861
/**
@@ -39,6 +72,7 @@ export const getBrandConfig = (): BrandConfig => {
3972
documentationUrl: getEnv('NEXT_PUBLIC_DOCUMENTATION_URL') || defaultConfig.documentationUrl,
4073
termsUrl: getEnv('NEXT_PUBLIC_TERMS_URL') || defaultConfig.termsUrl,
4174
privacyUrl: getEnv('NEXT_PUBLIC_PRIVACY_URL') || defaultConfig.privacyUrl,
75+
theme: getThemeColors(),
4276
}
4377
}
4478

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
export function generateThemeCSS(): string {
2+
const cssVars: string[] = []
3+
4+
if (process.env.NEXT_PUBLIC_BRAND_PRIMARY_COLOR) {
5+
cssVars.push(`--brand-primary-hex: ${process.env.NEXT_PUBLIC_BRAND_PRIMARY_COLOR};`)
6+
}
7+
8+
if (process.env.NEXT_PUBLIC_BRAND_PRIMARY_HOVER_COLOR) {
9+
cssVars.push(`--brand-primary-hover-hex: ${process.env.NEXT_PUBLIC_BRAND_PRIMARY_HOVER_COLOR};`)
10+
}
11+
12+
if (process.env.NEXT_PUBLIC_BRAND_SECONDARY_COLOR) {
13+
cssVars.push(`--brand-secondary-hex: ${process.env.NEXT_PUBLIC_BRAND_SECONDARY_COLOR};`)
14+
}
15+
16+
if (process.env.NEXT_PUBLIC_BRAND_ACCENT_COLOR) {
17+
cssVars.push(`--brand-accent-hex: ${process.env.NEXT_PUBLIC_BRAND_ACCENT_COLOR};`)
18+
}
19+
20+
if (process.env.NEXT_PUBLIC_BRAND_ACCENT_HOVER_COLOR) {
21+
cssVars.push(`--brand-accent-hover-hex: ${process.env.NEXT_PUBLIC_BRAND_ACCENT_HOVER_COLOR};`)
22+
}
23+
24+
if (process.env.NEXT_PUBLIC_BRAND_BACKGROUND_COLOR) {
25+
cssVars.push(`--brand-background-hex: ${process.env.NEXT_PUBLIC_BRAND_BACKGROUND_COLOR};`)
26+
}
27+
28+
return cssVars.length > 0 ? `:root { ${cssVars.join(' ')} }` : ''
29+
}

0 commit comments

Comments
 (0)