Font support on themes
This commit is contained in:
@@ -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} />
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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={[
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user