Bug fixes and refactoring

This commit is contained in:
Sean Edmunds
2026-02-04 15:44:38 -06:00
parent aa9fdd5be0
commit 8daeffcb39
7 changed files with 1199 additions and 1048 deletions

View File

@@ -0,0 +1,83 @@
import { Group, Text, UnstyledButton } from '@mantine/core';
export default function BackgroundItem({
item,
index,
hovered,
designerTheme,
setDesignerTheme,
}: {
item: string;
index: number;
hovered: number;
designerTheme: any;
setDesignerTheme: any;
}) {
const re = /(?:\.([^.]+))?$/;
return (
<UnstyledButton
data-list-item
key={item}
style={{
width: '100%',
height: '75px',
background:
item !== 'none' && item !== 'None'
? index === hovered
? `linear-gradient(${designerTheme.backgroundColor}88, ${designerTheme.backgroundColor}88), no-repeat center url(../../api/backgroundImages/thumbs/${item})`
: `no-repeat center url(../../api/backgroundImages/thumbs/${item})`
: 'repeating-linear-gradient(45deg, #33333366, #33333366 10px, #88888866 10px, #88888866 20px)',
backgroundSize: item === 'none' ? undefined : 'cover',
backgroundColor: item === 'none' ? '#00000088' : undefined,
paddingLeft: '.5rem',
alignItems: 'center',
}}
onClick={() =>
setDesignerTheme({
...designerTheme,
backgroundImage: item,
})
}
>
<Group
h={'100%'}
w={'100%'}
justify='space-between'
style={{ textOverflow: 'hidden', whiteSpace: 'nowrap' }}
>
<Text
style={{
width: 'min-content',
maxWidth: '170px',
backdropFilter: 'blur(5px) brightness(.25)',
padding: '.5rem',
borderBottomRightRadius: 4,
marginTop: '-2.15rem',
marginLeft: '-.5rem',
color: 'white',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}
>
{item.replace(/\.[^/.]+$/, '')}
</Text>
{item !== 'None' && (
<Text
style={{
width: 'min-content',
backdropFilter: 'blur(5px) brightness(.25)',
padding: '.5rem',
marginTop: '2rem',
marginBottom: -1,
borderTopLeftRadius: 4,
color: 'white',
}}
>
{re.exec(item.toUpperCase())?.[1]}
</Text>
)}
</Group>
</UnstyledButton>
);
}

View File

@@ -0,0 +1,138 @@
import { Button, Group, ScrollArea, Stack, TextInput } from '@mantine/core';
import { useRef, useState } from 'react';
import { FiSave, FiX } from 'react-icons/fi';
import { scrollAreaClasses, textInputClasses } from 'styles';
import type { Theme } from 'types';
import BackgroundItem from './BackgroundItem';
export default function BackgroundPicker({
defaultTheme,
designerTheme,
setDesignerTheme,
backgroundList,
closeBackgroundPicker,
}: {
defaultTheme: Theme;
designerTheme: Theme;
setDesignerTheme: (Theme: Theme) => void;
backgroundList: string[];
closeBackgroundPicker: () => void;
}) {
const [query, setQuery] = useState('');
const filtered = backgroundList.filter((item: string) =>
item.toLowerCase().includes(query.toLowerCase()),
);
const [hovered, setHovered] = useState(-1);
const viewportRef = useRef<HTMLDivElement>(null);
return (
<Stack h={'100%'} align='center' justify='center'>
<Group gap={0}>
<TextInput
className={textInputClasses.default}
classNames={textInputClasses}
styles={{
label: {
color: 'var(--mantine-color-primary-0)',
},
input: {
color: designerTheme.primaryColor,
backgroundColor: designerTheme.backgroundColor,
border: 'none',
borderBottom: '1px solid var(--mantine-color-primary-0)',
},
}}
placeholder='Search'
value={query.replace(/\.[^/.]+$/, '')}
rightSection={
<FiX
style={{
cursor: 'pointer',
margin: '.25rem',
}}
onClick={() => {
setQuery('');
}}
/>
}
onChange={(event) => {
setQuery(event.currentTarget.value);
setHovered(-1);
}}
onKeyDown={(event) => {
if (event.key === 'ArrowDown') {
event.preventDefault();
setHovered((current: number) => {
const nextIndex = current + 1 >= filtered.length ? current : current + 1;
viewportRef.current
?.querySelectorAll('[data-list-item]')
?.[nextIndex]?.scrollIntoView({ block: 'nearest' });
return nextIndex;
});
}
if (event.key === 'ArrowUp') {
event.preventDefault();
setHovered((current: number) => {
const nextIndex = current - 1 < 0 ? current : current - 1;
viewportRef.current
?.querySelectorAll('[data-list-item]')
?.[nextIndex]?.scrollIntoView({ block: 'nearest' });
return nextIndex;
});
}
}}
/>
</Group>
<ScrollArea.Autosize
viewportRef={viewportRef}
className={scrollAreaClasses.default}
classNames={scrollAreaClasses}
style={{
height: 325,
width: '90%',
borderRadius: 8,
}}
>
<Stack gap={0} align='center' display={'block'}>
{filtered.map((image: string, index: number) => (
<BackgroundItem
key={image}
item={image}
index={index}
hovered={hovered}
designerTheme={designerTheme}
setDesignerTheme={setDesignerTheme}
/>
))}
</Stack>
</ScrollArea.Autosize>
<Group justify='center'>
<Button
color={'green'}
onClick={() => {
setDesignerTheme({
...designerTheme,
backgroundImage: designerTheme.backgroundImage,
});
closeBackgroundPicker();
}}
>
<FiSave />
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeBackgroundPicker();
setDesignerTheme({
...designerTheme,
backgroundImage: defaultTheme.backgroundImage,
});
}}
>
<FiX />
</Button>
</Group>
</Stack>
);
}

View File

@@ -0,0 +1,309 @@
import {
ActionIcon,
ColorSwatch,
Group,
Image,
ScrollArea,
Stack,
Text,
Tooltip,
} from '@mantine/core';
import { notifications } from '@mantine/notifications';
import { useCommonHooks } from 'hooks';
import { FaClipboard } from 'react-icons/fa';
import { FiX } from 'react-icons/fi';
import { scrollAreaClasses, toolTipClasses } from 'styles';
import { type Theme, ThemeProperties } from 'types';
export default function ThemeChanges({
duplicate,
defaultTheme,
designerTheme,
setDesignerTheme,
}: {
duplicate: boolean;
defaultTheme: Theme;
designerTheme: Theme;
setDesignerTheme: (theme: Theme) => void;
}) {
const { currentUser, getObjectDiff } = useCommonHooks();
return (
<Stack
gap={0}
w={'95%'}
h={'calc(100% - 144px)'}
align='center'
style={{
backgroundColor: 'var(--mantine-color-background-0)',
borderRadius: 8,
}}
>
<Text
c={'var(--mantine-color-primary-0)'}
fz={'1.5rem'}
w={'100%'}
style={{
textAlign: 'center',
borderBottom: '1px solid var(--mantine-color-primary-0',
}}
>
Changes
</Text>
<ScrollArea.Autosize
w={'100%'}
className={scrollAreaClasses.default}
classNames={scrollAreaClasses}
style={{
padding: '1rem',
}}
styles={{
scrollbar: {
position: 'absolute',
right: -2,
},
}}
>
<Stack w={'95%'} gap={2}>
{getObjectDiff(defaultTheme, designerTheme) !== null &&
Object.keys(getObjectDiff(defaultTheme, designerTheme)).map((key: any) => {
return (
key !== 'id' && (
<Stack w={'100%'} align='center' justify='center' gap={0} key={key}>
<Group w={'100%'} justify='space-between' pos={'relative'}>
<Text
w={'100%'}
key={key}
pl={2}
style={{
color: 'var(--mantine-color-primary-0)',
backgroundColor: 'var(--mantine-color-background-0)',
overflow: 'clip',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
}}
>
{ThemeProperties[key as keyof typeof ThemeProperties]}
</Text>
<Tooltip
label={`Reset ${
ThemeProperties[key as keyof typeof ThemeProperties]
}`}
classNames={toolTipClasses}
className={toolTipClasses.default}
>
<ActionIcon
disabled={duplicate && key === 'name'}
variant='subtle'
color='red'
onClick={() => {
setDesignerTheme({
...designerTheme,
[key]: defaultTheme[key as keyof Theme],
});
}}
pos={'absolute'}
right={0}
>
<FiX />
</ActionIcon>
</Tooltip>
</Group>
<Group
w={'100%'}
justify={key.includes('Color') ? 'space-between' : 'center'}
gap={key.includes('Color') ? 4 : 0}
bg='var(--mantine-color-accent-0)'
c='var(--mantine-color-background-0)'
style={{ borderRadius: 8, overflow: 'clip' }}
h={48}
>
{key === 'name' && (
<Group w={'95%'} justify='space-between'>
<Text>{defaultTheme[key as keyof Theme]}</Text>
<Text>→</Text>
<Text>{designerTheme[key as keyof Theme]}</Text>
</Group>
)}
{key.includes('Shadow') && (
<Group w={'95%'} justify='space-between'>
{defaultTheme[key as keyof Theme] === 0 ? (
<Text>Off</Text>
) : (
<Text>On</Text>
)}
<Text>→</Text>
{designerTheme[key as keyof Theme] === 0 ? (
<Text>Off</Text>
) : (
<Text>On</Text>
)}
</Group>
)}
{key.includes('Font') && (
<>
<Text
style={{
fontFamily:
(defaultTheme[key as keyof Theme] as string) ?? undefined,
fontSize: 18,
}}
>
{defaultTheme[key as keyof Theme] ||
`Default (${currentUser.defaultFont})`}
</Text>
<Text>→</Text>
<Text
style={{
fontFamily: designerTheme.themeFont ?? undefined,
fontSize: 18,
}}
>
{designerTheme[key as keyof Theme] ||
`Default (${currentUser.defaultFont})`}
</Text>
</>
)}
{key === 'backgroundImage' && (
<>
<Image
w={'40%'}
src={
(
defaultTheme[key as keyof Theme] as string
).toLocaleLowerCase() === 'none'
? 'https://placehold.co/540x360?text=None'
: `../../api/backgroundImages/thumbs/${defaultTheme[key as keyof Theme] as string}`
}
/>
<Text>→</Text>
<Image
w={'40%'}
src={
(
designerTheme[key as keyof Theme] as string
).toLocaleLowerCase() === 'none'
? 'https://placehold.co/540x360?text=None'
: `../../api/backgroundImages/thumbs/${designerTheme[key as keyof Theme] as string}`
}
/>
</>
)}
{key.includes('Color') && (
<>
<Tooltip
label='Copy color code'
classNames={toolTipClasses}
className={toolTipClasses.default}
>
<ColorSwatch
h={50}
onClick={() => {
navigator.clipboard.writeText(
defaultTheme[key as keyof Theme] as string,
);
notifications.show({
title: (
<Text fw={600} c={'var(--mantine-color-accent-0)'}>
Copied{' '}
{
ThemeProperties[
key as keyof typeof ThemeProperties
]
}
</Text>
),
message: (
<Text c={'var(--mantine-color-primary-0)'}>
{defaultTheme[key as keyof Theme] as string}
</Text>
),
autoClose: true,
withCloseButton: true,
icon: <FaClipboard size={24} />,
});
}}
color={defaultTheme[key as keyof Theme] as string}
style={{
cursor: 'pointer',
}}
styles={{
alphaOverlay: {
borderRadius: '0px',
},
colorOverlay: {
borderRadius: '0px',
},
shadowOverlay: {
borderRadius: '0px',
},
childrenOverlay: {
borderRadius: '0px',
},
}}
/>
</Tooltip>
<Text>→</Text>
<Tooltip
label='Copy color code'
classNames={toolTipClasses}
className={toolTipClasses.default}
>
<ColorSwatch
h={50}
onClick={() => {
navigator.clipboard.writeText(
defaultTheme[key as keyof Theme] as string,
);
notifications.show({
title: (
<Text fw={600} c={'var(--mantine-color-accent-0)'}>
Copied{' '}
{
ThemeProperties[
key as keyof typeof ThemeProperties
]
}
</Text>
),
message: (
<Text c={'var(--mantine-color-primary-0)'}>
{designerTheme[key as keyof Theme] as string}
</Text>
),
autoClose: true,
withCloseButton: true,
icon: <FaClipboard size={24} />,
});
}}
color={designerTheme[key as keyof Theme] as string}
style={{
cursor: 'pointer',
}}
styles={{
alphaOverlay: {
borderRadius: '0px',
},
colorOverlay: {
borderRadius: '0px',
},
shadowOverlay: {
borderRadius: '0px',
},
childrenOverlay: {
borderRadius: '0px',
},
}}
/>
</Tooltip>
</>
)}
</Group>
</Stack>
)
);
})}
</Stack>
</ScrollArea.Autosize>
</Stack>
);
}

View File

@@ -0,0 +1,246 @@
import {
Button,
ColorPicker,
Group,
Stack,
Text,
TextInput,
Tooltip,
} from '@mantine/core';
import { useCommonHooks } from 'hooks';
import { FaCheck } from 'react-icons/fa';
import { FiRefreshCcw, FiShuffle } from 'react-icons/fi';
import { textClasses, textInputClasses, toolTipClasses } from 'styles';
import { type Theme, ThemeProperties } from 'types';
export default function ThemeColorPicker({
colorId,
colorValue,
setColorValue,
defaultTheme,
designerTheme,
setDesignerTheme,
rgba,
setRgba,
randomColor,
closePicker,
}: {
colorId: string;
colorValue: string;
setColorValue: any;
defaultTheme: Theme;
designerTheme: Theme;
setDesignerTheme: any;
rgba: any;
setRgba: (rgba: any) => void;
randomColor: (withAlpha?: boolean) => string;
closePicker: () => void;
}) {
const { theme, textShadowStyle } = useCommonHooks();
return (
<Stack h={'100%'} align='center'>
<Text
className={textClasses.sectionTitle}
classNames={textClasses}
c={'var(--mantine-color-background-0)'}
style={{
textShadow: theme.textShadowsEnabled ? textShadowStyle : undefined,
}}
>
Change {ThemeProperties[colorId as keyof typeof ThemeProperties]}
</Text>
{colorId === 'searchColor' && (
<ColorPicker
value={colorValue}
onChange={(e) => {
setColorValue(e);
setDesignerTheme({
...designerTheme,
[colorId]: e,
});
}}
format={'hexa'}
w={'90%'}
/>
)}
{colorId !== 'searchColor' && (
<ColorPicker
value={colorValue}
onChange={(e) => {
setColorValue(e);
setDesignerTheme({
...designerTheme,
[colorId]: e,
});
}}
format={'hex'}
w={'90%'}
mb={'1.5rem'}
/>
)}
<Stack w={'90%'} gap={0}>
<TextInput
className={textInputClasses.colorSwatchInput}
classNames={textInputClasses}
label={'Hex Value'}
value={colorValue}
onChange={(e) => setColorValue(e.target.value)}
/>
<Group gap={0} w={'100%'} justify='space-between'>
<TextInput
className={textInputClasses.colorSwatchInput}
classNames={textInputClasses}
label={'Red'}
w={'23%'}
value={rgba.r}
onChange={(e) => {
if (e.target.value) {
setRgba({
...rgba,
r: Number.parseInt(e.target.value, 10),
});
setColorValue(
`${colorValue.substring(0, 1)}${Number.parseInt(e.target.value, 10).toString(16).padStart(2, '0')}${colorValue.substring(3)}`,
);
} else {
setRgba({
...rgba,
r: 0,
});
}
}}
/>
<TextInput
className={textInputClasses.colorSwatchInput}
classNames={textInputClasses}
label={'Green'}
w={'23%'}
value={rgba.g}
onChange={(e) => {
if (e.target.value) {
setRgba({
...rgba,
g: Number.parseInt(e.target.value, 10),
});
setColorValue(
`${colorValue.substring(0, 3)}${Number.parseInt(e.target.value, 10).toString(16).padStart(2, '0')}${colorValue.substring(5)}`,
);
} else {
setRgba({
...rgba,
g: 0,
});
}
}}
/>
<TextInput
className={textInputClasses.colorSwatchInput}
classNames={textInputClasses}
label={'Blue'}
w={'23%'}
value={rgba.b}
onChange={(e) => {
if (e.target.value) {
setRgba({
...rgba,
b: Number.parseInt(e.target.value, 10),
});
setColorValue(
`${colorValue.substring(0, 5)}${Number.parseInt(e.target.value, 10).toString(16).padStart(2, '0')}${colorValue.substring(7)}`,
);
} else {
setRgba({
...rgba,
b: 0,
});
}
}}
/>
<TextInput
disabled={colorId !== 'searchColor'}
className={textInputClasses.colorSwatchInput}
classNames={textInputClasses}
label={'Alpha'}
w={'23%'}
value={rgba.a}
onChange={(e) => {
if (e.target.value) {
setRgba({
...rgba,
a: Number.parseInt(e.target.value, 10),
});
setColorValue(
`${colorValue.substring(0, 7)}${Number.parseInt(e.target.value, 10).toString(16).padStart(2, '0')}`,
);
} else {
setRgba({
...rgba,
a: 0,
});
}
}}
/>
</Group>
</Stack>
<Group mt={'auto'} justify='center' mih={'36px'} pb={'1.5rem'}>
<Tooltip
label={'Random Color'}
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<Button
c={'white'}
onClick={() => {
const rc = randomColor(colorId === 'searchColor');
setColorValue(rc);
setDesignerTheme({
...designerTheme,
[colorId]: rc,
});
}}
>
<FiShuffle />
</Button>
</Tooltip>
<Tooltip
label={'Reset Color'}
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
setColorValue(defaultTheme[colorId as keyof Theme] as string);
setDesignerTheme({
...designerTheme,
[colorId]: defaultTheme[colorId as keyof Theme],
});
}}
>
<FiRefreshCcw />
</Button>
</Tooltip>
<Tooltip
label={'Done'}
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<Button
color={'green'}
onClick={() => {
setDesignerTheme({
...designerTheme,
[colorId]: colorValue,
});
closePicker();
}}
>
<FaCheck />
</Button>
</Tooltip>
</Group>
</Stack>
);
}

View File

@@ -0,0 +1,132 @@
import { ActionIcon, ColorSwatch, Tooltip } from '@mantine/core';
import { FiImage } from 'react-icons/fi';
import { colorSwatchClasses, toolTipClasses } from 'styles';
import type { Theme } from 'types';
export default function ThemeColorSwatches({
designerTheme,
setDesignerTheme,
handleSwatchClick,
openBackgroundPicker,
closePicker,
}: {
designerTheme: Theme;
setDesignerTheme: (Theme: Theme) => void;
handleSwatchClick: (colorId: string, colorValue: string) => void;
openBackgroundPicker: () => void;
closePicker: () => void;
}) {
return (
<>
<Tooltip
label={'Change Primary Color'}
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<ColorSwatch
onClick={() => {
handleSwatchClick('primaryColor', designerTheme.primaryColor);
}}
color={designerTheme.primaryColor}
style={{ borderColor: designerTheme.primaryColor }}
className={colorSwatchClasses.themeDesignerSwatch}
classNames={colorSwatchClasses}
top={'11.5rem'}
left={'8.5rem'}
/>
</Tooltip>
<Tooltip
label={'Change Accent Color'}
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<ColorSwatch
onClick={() => {
handleSwatchClick('accentColor', designerTheme.accentColor);
}}
color={designerTheme.accentColor}
style={{ borderColor: designerTheme.primaryColor }}
className={colorSwatchClasses.themeDesignerSwatch}
classNames={colorSwatchClasses}
bottom={'6rem'}
left={'11rem'}
/>
</Tooltip>
<Tooltip
label={'Change Background Color'}
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<ColorSwatch
onClick={() => {
handleSwatchClick('backgroundColor', designerTheme.backgroundColor);
}}
color={designerTheme.backgroundColor}
style={{ borderColor: designerTheme.primaryColor }}
className={colorSwatchClasses.themeDesignerSwatch}
classNames={colorSwatchClasses}
bottom={'4rem'}
right={'3.5rem'}
/>
</Tooltip>
<Tooltip
label={'Change Border Color'}
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<ColorSwatch
onClick={() => {
handleSwatchClick('borderColor', designerTheme.borderColor);
}}
color={designerTheme.borderColor}
style={{ borderColor: designerTheme.primaryColor }}
className={colorSwatchClasses.themeDesignerSwatch}
classNames={colorSwatchClasses}
top={'4.5rem'}
right={'15%'}
/>
</Tooltip>
<Tooltip
label={'Change Search Color'}
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<ColorSwatch
onClick={() => {
handleSwatchClick('searchColor', designerTheme.searchColor);
}}
color={designerTheme.searchColor}
style={{ borderColor: designerTheme.primaryColor }}
className={colorSwatchClasses.themeDesignerSwatch}
classNames={colorSwatchClasses}
top={'3.25rem'}
left={'6.5rem'}
/>
</Tooltip>
<Tooltip
label={'Change Background'}
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<ActionIcon
onClick={() => {
closePicker();
openBackgroundPicker();
setDesignerTheme(designerTheme);
}}
pos={'absolute'}
right={0}
style={{
color: designerTheme.backgroundColor,
backgroundColor: designerTheme.primaryColor,
borderRadius: 0,
borderBottomLeftRadius: 10,
borderTopRightRadius: 10,
}}
>
<FiImage size={20} />
</ActionIcon>
</Tooltip>
</>
);
}

View File

@@ -0,0 +1,245 @@
import {
ActionIcon,
Box,
Button,
Checkbox,
Group,
Overlay,
Stack,
Text,
Tooltip,
} from '@mantine/core';
import { useCommonHooks } from 'hooks';
import FontPicker from 'react-fontpicker-ts';
import { FaFont, FaGoogle } from 'react-icons/fa';
import { FaShuffle } from 'react-icons/fa6';
import { FiX } from 'react-icons/fi';
import { textClasses, toolTipClasses } from 'styles';
import type { Theme } from 'types';
import ThemeChanges from './ThemeChanges';
export default function ThemeOptions({
defaultTheme,
designerTheme,
setDesignerTheme,
setFont,
customFontEnabled,
setCustomFontEnabled,
duplicate,
randomColor,
}: {
defaultTheme: Theme;
designerTheme: any;
setDesignerTheme: any;
setFont: any;
customFontEnabled: boolean;
setCustomFontEnabled: any;
duplicate: boolean;
randomColor: (withAlpha?: boolean) => string;
}) {
const { currentUser } = useCommonHooks();
return (
<Stack h={'100%'} justify='space-between' align='center' gap={4}>
<Stack w={'100%'} align='center' gap={0} h={'min-content'}>
<Group gap={2} w={'100%'} justify='space-between' align='center'>
<Checkbox.Card
w={'calc(50% - 1px)'}
checked={designerTheme.textShadowsEnabled === 1}
c={'var(--mantine-color-background-0)'}
onChange={(e) => {
setDesignerTheme({
...designerTheme,
textShadowsEnabled: e ? 1 : 0,
});
}}
style={{
border: 'none',
filter: `grayscale(${designerTheme.textShadowsEnabled === 1 ? 0 : '75%'}) brightness(${designerTheme.textShadowsEnabled === 1 ? '1' : '1.5'})`,
transition: 'all 1s ease',
}}
>
<Tooltip
label='Text Shadows'
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<Group
w={'100%'}
justify='center'
style={{
backgroundColor: designerTheme.backgroundColor,
}}
>
<Text
classNames={textClasses}
className={textClasses.sectionTitle}
style={{
color: designerTheme.accentColor,
textShadow: `2px 2px ${designerTheme.primaryColor}`,
}}
>
Shadows
</Text>
</Group>
</Tooltip>
</Checkbox.Card>
<Checkbox.Card
w={'calc(50% - 1px)'}
checked={designerTheme.appShadowsEnabled === 1}
c={'var(--mantine-color-background-0)'}
onChange={(e) => {
setDesignerTheme({
...designerTheme,
appShadowsEnabled: e ? 1 : 0,
});
}}
style={{
border: 'none',
filter: `grayscale(${designerTheme.appShadowsEnabled === 1 ? 0 : '75%'}) brightness(${designerTheme.appShadowsEnabled === 1 ? '1' : '1.5'})`,
transition: 'all 1s ease',
}}
>
<Tooltip
label='Icon Shadows'
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<Group
w={'100%'}
justify='center'
align='center'
style={{
backgroundColor: designerTheme.backgroundColor,
overflow: 'clip',
}}
>
<FaGoogle
style={{
marginTop: '12px',
marginBottom: '7px',
color: designerTheme.primaryColor,
height: 32,
width: 32,
filter: `drop-shadow(2px 2px color-mix(in srgb, ${designerTheme.accentColor}, transparent 30%))`,
}}
/>
</Group>
</Tooltip>
</Checkbox.Card>
</Group>
<Group w={'100%'} gap={0} justify='center'>
<Tooltip
label={`Custom Font ${customFontEnabled ? 'Enabled' : 'Disabled'}`}
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<ActionIcon
color={'red'}
size={32}
onClick={() => {
setCustomFontEnabled(!customFontEnabled);
setFont(
customFontEnabled ? currentUser.defaultFont : defaultTheme.themeFont,
);
}}
style={{
borderRadius: '0px',
filter: `grayscale(${customFontEnabled ? 0 : '75%'})`,
}}
>
<FaFont />
</ActionIcon>
</Tooltip>
<Box
w={'calc(100% - 64px)'}
onClick={(e) => {
if (!customFontEnabled) {
e.preventDefault();
e.stopPropagation();
}
}}
pos={'relative'}
>
{!customFontEnabled && <Overlay pos={'absolute'} />}
<FontPicker
autoLoad
defaultValue={
designerTheme.themeFont === null
? currentUser.defaultFont
: designerTheme.themeFont
}
value={(pickerFont: string) => {
if (customFontEnabled) {
setFont(pickerFont);
}
}}
/>
</Box>
<Tooltip
label='Reset to use default'
className={toolTipClasses.default}
classNames={toolTipClasses}
>
<ActionIcon
disabled={!customFontEnabled}
color={'red'}
size={32}
onClick={() => {
setFont(currentUser.defaultFont);
setCustomFontEnabled(false);
}}
style={{
borderRadius: '0px',
}}
>
<FiX />
</ActionIcon>
</Tooltip>
</Group>
</Stack>
{JSON.stringify(defaultTheme) !== JSON.stringify(designerTheme) && (
<ThemeChanges
duplicate={duplicate}
defaultTheme={defaultTheme}
designerTheme={designerTheme}
setDesignerTheme={setDesignerTheme}
/>
)}
<Group mih={'36px'} pb={'1.5rem'}>
<Tooltip
label={'Randomize Colors!'}
c={'var(--mantine-color-primary-0)'}
bg={'var(--mantine-color-background-0)'}
>
<Button
onClick={() => {
setDesignerTheme({
...designerTheme,
backgroundColor: randomColor(),
searchColor: randomColor(true),
primaryColor: randomColor(),
accentColor: randomColor(),
borderColor: randomColor(),
});
}}
>
<FaShuffle />
</Button>
</Tooltip>
<Button
onClick={() => {
setCustomFontEnabled(defaultTheme.themeFont !== null);
duplicate
? setDesignerTheme({
...defaultTheme,
name: `${defaultTheme.name} copy`,
})
: setDesignerTheme({ ...defaultTheme });
}}
>
Reset Changes
</Button>
</Group>
</Stack>
);
}