Self-host Inter and DM Mono fonts (#22506)
Replaces the two Google Fonts stylesheets with self-hosted fonts via `@fontsource`, imported in the app entry (and Storybook preview), and removes the duplicate Inter that BlockNote was shipping. ## Why - **The caching argument for Google Fonts is dead.** Browsers partition the HTTP cache by top-level site (Chrome 86+, Firefox 85+, Safari even earlier), so a font cached from another website is never reused on ours. Every first-time visitor downloads the fonts either way — Google just adds a detour. - **Faster first paint.** This removes two render-blocking cross-origin stylesheets from `index.html` (DNS + TLS to `fonts.googleapis.com`, then a second connection to `fonts.gstatic.com`, with no preconnect today). The fonts now ship from our own `/assets` alongside the rest of the app, behind the same CDN and cache policy. - **Privacy.** Visitor IPs are no longer sent to Google on every page load. A German court ruled in 2022 that Google Fonts embedding violates GDPR, and privacy-conscious self-hosters currently have no way to opt out of the dependency. - **Air-gapped / offline self-hosted instances** currently render fallback system fonts; they now get the real ones. ## Font unification We were actually loading Inter from two places: the Google stylesheet, plus `@blocknote/core/fonts/inter.css` (8 weights, latin-only, woff+woff2) imported by the two rich-text editors — whichever loaded last won the cascade. Both are gone; `@fontsource` is now the single source: - Inter 400/500/600 (theme weights) + 700 (rich-text bold, previously only covered by the BlockNote copy) - DM Mono 400/500 (DM Mono has no 600 upstream; the old Google link requested one anyway) Fontsource ships the same `unicode-range` subsets as the Google CSS, so browsers still only download the subset they need (~60KB of woff2 for latin), and non-latin locales keep full coverage — which the latin-only BlockNote copy didn't provide. ## Notes - The BlockNote PDF export (`exportBlockNoteEditorToPdf.ts`) still fetches Inter TTFs from `fonts.gstatic.com` at export time — react-pdf needs TTF files, left unchanged here. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22506?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
@@ -1,8 +1,3 @@
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.7/iframeResizer.contentWindow.min.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import '@fontsource/dm-mono/400.css';
|
||||
import '@fontsource/dm-mono/500.css';
|
||||
import '@fontsource/inter/400.css';
|
||||
import '@fontsource/inter/500.css';
|
||||
import '@fontsource/inter/600.css';
|
||||
import '@fontsource/inter/700.css';
|
||||
|
||||
import { i18n } from '@lingui/core';
|
||||
import { I18nProvider } from '@lingui/react';
|
||||
import { type Preview } from '@storybook/react-vite';
|
||||
|
||||
@@ -28,15 +28,6 @@
|
||||
|
||||
<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">
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
"@dnd-kit/react": "^0.3.2",
|
||||
"@dr.pogodin/react-helmet": "^3.2.2",
|
||||
"@floating-ui/react": "^0.24.3",
|
||||
"@fontsource/dm-mono": "^5.2.7",
|
||||
"@fontsource/inter": "^5.2.8",
|
||||
"@graphiql/plugin-explorer": "^5.1.2",
|
||||
"@graphiql/react": "^0.37.6",
|
||||
"@hello-pangea/dnd": "^18.0.1",
|
||||
|
||||
@@ -3,6 +3,12 @@ import ReactDOM from 'react-dom/client';
|
||||
import { App } from '@/app/components/App';
|
||||
import { migrateTokenPairCookieToLocalStorage } from '@/auth/utils/migrateTokenPairCookieToLocalStorage';
|
||||
import { hydrateMetadataStore } from '@/metadata-store/storage/metadataStoreStorage';
|
||||
import '@fontsource/dm-mono/400.css';
|
||||
import '@fontsource/dm-mono/500.css';
|
||||
import '@fontsource/inter/400.css';
|
||||
import '@fontsource/inter/500.css';
|
||||
import '@fontsource/inter/600.css';
|
||||
import '@fontsource/inter/700.css';
|
||||
import 'react-loading-skeleton/dist/skeleton.css';
|
||||
import 'twenty-ui/style.css';
|
||||
import 'twenty-ui/theme-light.css';
|
||||
|
||||
-1
@@ -24,7 +24,6 @@ import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import '@blocknote/core/fonts/inter.css';
|
||||
import '@blocknote/mantine/style.css';
|
||||
import { useCreateBlockNote } from '@blocknote/react';
|
||||
import '@blocknote/react/style.css';
|
||||
|
||||
-1
@@ -17,7 +17,6 @@ import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePush
|
||||
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import '@blocknote/core/fonts/inter.css';
|
||||
import '@blocknote/mantine/style.css';
|
||||
import { useCreateBlockNote } from '@blocknote/react';
|
||||
import '@blocknote/react/style.css';
|
||||
|
||||
@@ -7005,6 +7005,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@fontsource/dm-mono@npm:^5.2.7":
|
||||
version: 5.2.7
|
||||
resolution: "@fontsource/dm-mono@npm:5.2.7"
|
||||
checksum: 10c0/028843c26545e86ad01219786daabe18386ed5e19ebefd6bc00fd799f8dc33df0c3d679fe942bf9355696d21903459282d97cd671ee8b2e05cd876560f9bb441
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@fontsource/inter@npm:^5.2.8":
|
||||
version: 5.2.8
|
||||
resolution: "@fontsource/inter@npm:5.2.8"
|
||||
checksum: 10c0/f737dd50005e4809887ba55ae0c9b7174216d6d14875d17a4fbb9a0ad75dec4265928b805a43fe16a23f14a878f1974a398bbfc84ad65c79fc4d4b9c3ea154e1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@gar/promise-retry@npm:^1.0.0, @gar/promise-retry@npm:^1.0.2":
|
||||
version: 1.0.3
|
||||
resolution: "@gar/promise-retry@npm:1.0.3"
|
||||
@@ -52817,6 +52831,8 @@ __metadata:
|
||||
"@dnd-kit/react": "npm:^0.3.2"
|
||||
"@dr.pogodin/react-helmet": "npm:^3.2.2"
|
||||
"@floating-ui/react": "npm:^0.24.3"
|
||||
"@fontsource/dm-mono": "npm:^5.2.7"
|
||||
"@fontsource/inter": "npm:^5.2.8"
|
||||
"@graphiql/plugin-explorer": "npm:^5.1.2"
|
||||
"@graphiql/react": "npm:^0.37.6"
|
||||
"@graphql-codegen/cli": "npm:^6.3.1"
|
||||
|
||||
Reference in New Issue
Block a user