Font support on themes

This commit is contained in:
Sean Edmunds
2026-01-28 16:11:54 -06:00
parent 983fcbe2ae
commit 9d46c5824d
5 changed files with 53 additions and 4 deletions

View File

@@ -24,6 +24,7 @@ import 'react-fontpicker-ts/dist/index.css';
import '@gfazioli/mantine-text-animate/styles.css'; import '@gfazioli/mantine-text-animate/styles.css';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { Homepage, Settings } from 'pages'; import { Homepage, Settings } from 'pages';
import FontPicker from 'react-fontpicker-ts';
import type { Theme, ThemePlaylist } from 'types'; import type { Theme, ThemePlaylist } from 'types';
function App() { function App() {
@@ -55,7 +56,7 @@ function App() {
search: colorsTuple(theme.searchColor), search: colorsTuple(theme.searchColor),
}, },
white: theme?.backgroundColor, white: theme?.backgroundColor,
fontFamily: `${personalData?.[0]?.defaultFont},Helvetica Neue,Roboto,system-ui,sans-serif`, fontFamily: `${theme?.themeFont || personalData?.[0]?.defaultFont},system-ui,sans-serif`,
autoContrast: true, autoContrast: true,
}); });
const mantineTheme = mergeMantineTheme(DEFAULT_THEME, overrides); const mantineTheme = mergeMantineTheme(DEFAULT_THEME, overrides);
@@ -139,6 +140,9 @@ function App() {
<> <>
{theme && ( {theme && (
<MantineProvider theme={mantineTheme}> <MantineProvider theme={mantineTheme}>
{theme.themeFont && (
<FontPicker loaderOnly loadFonts={theme.themeFont} autoLoad />
)}
<Notifications /> <Notifications />
<Loading loaded={loaded} /> <Loading loaded={loaded} />
<RouterProvider router={router} /> <RouterProvider router={router} />

View File

@@ -15,7 +15,8 @@ import {
} from '@mantine/core'; } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks'; import { useDisclosure } from '@mantine/hooks';
import { useCommonHooks } from 'hooks'; import { useCommonHooks } from 'hooks';
import { useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import FontPicker from 'react-fontpicker-ts';
import { FaShuffle } from 'react-icons/fa6'; import { FaShuffle } from 'react-icons/fa6';
import { FiImage, FiSave, FiShuffle, FiX } from 'react-icons/fi'; import { FiImage, FiSave, FiShuffle, FiX } from 'react-icons/fi';
import { import {
@@ -64,13 +65,27 @@ export function ThemeEditor({
const viewportRef = useRef<HTMLDivElement>(null); const viewportRef = useRef<HTMLDivElement>(null);
const [colorId, setColorId] = useState<string>(''); const [colorId, setColorId] = useState<string>('');
const [colorValue, setColorValue] = useState('#000000'); const [colorValue, setColorValue] = useState('#000000');
const [font, setFont] = useState<Theme['themeFont']>();
const re = /(?:\.([^.]+))?$/; const re = /(?:\.([^.]+))?$/;
const [backgroundPicker, { open: openBackgroundPicker, close: closeBackgroundPicker }] = const [backgroundPicker, { open: openBackgroundPicker, close: closeBackgroundPicker }] =
useDisclosure(false); useDisclosure(false);
const filtered = backgroundList.filter((item: string) => const filtered = backgroundList.filter((item: string) =>
item.toLowerCase().includes(query.toLowerCase()), item.toLowerCase().includes(query.toLowerCase()),
); );
useEffect(() => {
if (font) {
setSelectedTheme({
...selectedTheme,
themeFont: font,
});
} else {
setSelectedTheme({
...selectedTheme,
themeFont: null,
});
}
}, [font]);
const items = filtered.map((item: string, index: number) => { const items = filtered.map((item: string, index: number) => {
return ( return (
<UnstyledButton <UnstyledButton
@@ -516,6 +531,23 @@ export function ThemeEditor({
}, },
}} }}
/> />
<Group w={'100%'} justify='center'>
<FontPicker
style={{ width: '75%' }}
autoLoad
defaultValue={
selectedTheme.themeFont === null ? 'Jost' : selectedTheme.themeFont
}
value={(font: string) => setFont(font)}
/>
<ActionIcon
onClick={() => {
setFont(null);
}}
>
<FiX />
</ActionIcon>
</Group>
</Stack> </Stack>
{JSON.stringify(defaultTheme) !== JSON.stringify(selectedTheme) && ( {JSON.stringify(defaultTheme) !== JSON.stringify(selectedTheme) && (
<> <>
@@ -609,6 +641,16 @@ export function ThemeEditor({
)} )}
</Group> </Group>
)} )}
{key.includes('Font') && (
<Group w={'100%'} justify='center'>
<Text>
{defaultTheme[key as keyof Theme] ||
'Default (Jost)'}
</Text>
<Text>→</Text>
<Text>{designerTheme[key as keyof Theme]}</Text>
</Group>
)}
</Stack> </Stack>
); );
}, },

View File

@@ -31,6 +31,7 @@ export function ThemeModalContent({ selectedTheme }: { selectedTheme: Theme }) {
'--mantine-color-border-0': selectedTheme?.borderColor, '--mantine-color-border-0': selectedTheme?.borderColor,
'--mantine-color-search-0': selectedTheme?.searchColor, '--mantine-color-search-0': selectedTheme?.searchColor,
transition: 'all 0.2s ease', transition: 'all 0.2s ease',
fontFamily: selectedTheme.themeFont ?? undefined,
}} }}
align='center' align='center'
gap={0} gap={0}
@@ -45,6 +46,7 @@ export function ThemeModalContent({ selectedTheme }: { selectedTheme: Theme }) {
color: selectedTheme?.primaryColor, color: selectedTheme?.primaryColor,
borderBottom: `thin solid ${selectedTheme?.borderColor}`, borderBottom: `thin solid ${selectedTheme?.borderColor}`,
backgroundColor: `color-mix(in srgb, ${selectedTheme?.searchColor}, transparent 50%)`, backgroundColor: `color-mix(in srgb, ${selectedTheme?.searchColor}, transparent 50%)`,
fontFamily: selectedTheme.themeFont ?? undefined,
}, },
}} }}
data={[ data={[

View File

@@ -73,6 +73,7 @@ export function Themes() {
randomEnabled: 1, randomEnabled: 1,
textShadowsEnabled: 0, textShadowsEnabled: 0,
appShadowsEnabled: 0, appShadowsEnabled: 0,
themeFont: null,
}); });
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@@ -97,7 +98,6 @@ export function Themes() {
setIsLoading(false); setIsLoading(false);
} }
}, [debouncedSearch]); }, [debouncedSearch]);
return ( return (
<Stack> <Stack>
<ThemeModal <ThemeModal

View File

@@ -10,6 +10,7 @@ export interface Theme {
randomEnabled: number; randomEnabled: number;
textShadowsEnabled: number; textShadowsEnabled: number;
appShadowsEnabled: number; appShadowsEnabled: number;
themeFont?: string | null;
} }
export interface ThemePlaylist { export interface ThemePlaylist {