Files
twenty/packages/twenty-front/index.html
T
Charles BochetandGitHub c41a8e2b23 [DevXP] Simplify twenty-ui theme system: replace auto-generated files with static CSS variables (#18389)
## Summary

Now that Twenty has fully migrated from Emotion to Linaria, the theme
system has been simplified to remove unnecessary complexity that existed
only to support the old runtime injection pattern.

### What changed

- **Deleted** `generateThemeConstants.ts` script and the entire
`generated/` directory — no more auto-generation
- **Added** `theme-light.css` and `theme-dark.css`: static CSS files
with 991 custom properties each, scoped under `.light` and `.dark`
selectors respectively
- **Moved** `themeCssVariables.ts` out of `generated/` and hand-maintain
it as a static `as const` object of `var(--t-*)` references (Linaria can
statically evaluate these at build time)
- **Extracted** numeric constants (`MOBILE_VIEWPORT`, `ICON_SIZES`,
`ICON_STROKES`) into a new `constants.ts` — CSS variables can't be used
in media queries or as numeric icon size props
- **Simplified** `ThemeContextProvider`: removed
`ThemeCssVariableInjectorEffect` entirely; now uses a single
`useLayoutEffect` to toggle `.light`/`.dark` class on `<html>`
- **Added** `class="light"` to `index.html` as default to prevent FOUC
before React hydration

### Why

The previous setup maintained a dual system: JS theme objects
(`THEME_LIGHT`/`THEME_DARK`) used at runtime, plus a generation script
that produced CSS variable entry arrays, which were then injected into
the DOM by `ThemeCssVariableInjectorEffect`. With Linaria, theme values
only need to be CSS custom properties — the JS objects were redundant.
This PR removes ~250 lines of infrastructure while keeping the same
theming capabilities.
2026-03-04 23:30:25 +01:00

94 lines
2.8 KiB
HTML

<!doctype html>
<html lang="en" translate="no" class="light">
<head>
<meta charset="UTF-8" />
<link
rel="icon"
type="image/x-icon"
href="/images/icons/android/android-launchericon-48-48.png"
data-rh="true"
/>
<link rel="apple-touch-icon" href="/images/icons/ios/192.png" />
<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="A modern open-source CRM" />
<meta
property="og:image"
content="https://raw.githubusercontent.com/twentyhq/twenty/main/docs/static/img/social-card.png"
/>
<meta property="og:description" content="A modern open-source CRM" />
<meta property="og:title" content="Twenty" />
<meta name="twitter:card" content="summary_large_image" />
<meta
name="twitter:image"
content="https://raw.githubusercontent.com/twentyhq/twenty/main/docs/static/img/social-card.png"
/>
<meta name="twitter:description" content="A modern open-source CRM" />
<meta name="twitter:title" content="Twenty" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
/>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500;600&display=swap"
/>
<title>Twenty</title>
<!-- BEGIN: Twenty Config -->
<script id="twenty-env-config">
window._env_ = {
// This will be overwritten
};
</script>
<!-- END: Twenty Config -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script type="module">
const disableInputAutoZoom = () => {
const viewportMetadata = document.querySelector('meta[name=viewport]');
if (viewportMetadata !== null) {
viewportMetadata.setAttribute(
'content',
'width=device-width, initial-scale=1.0, maximum-scale=1.0',
);
}
};
const isIOS = /iPad|iPhone/.test(navigator.userAgent);
if (isIOS) {
disableInputAutoZoom();
}
</script>
<style>
:root {
/* THEME_DARK.background.tertiary */
--theme-dark-background-tertiary: #1d1d1d;
/* THEME_LIGHT.background.tertiary */
--theme-light-background-tertiary: #f1f1f1;
}
@media (prefers-color-scheme: dark) {
html, body {
background-color: var(--theme-dark-background-tertiary);
}
}
@media (prefers-color-scheme: light) {
html, body {
background-color: var(--theme-light-background-tertiary);
}
}
</style>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>