diff --git a/src/pages/settings/components/Theming/Themes/ThemeModal/components/BackgroundItem.tsx b/src/pages/settings/components/Theming/Themes/ThemeModal/components/BackgroundItem.tsx new file mode 100644 index 0000000..623f6d9 --- /dev/null +++ b/src/pages/settings/components/Theming/Themes/ThemeModal/components/BackgroundItem.tsx @@ -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 ( + + setDesignerTheme({ + ...designerTheme, + backgroundImage: item, + }) + } + > + + + {item.replace(/\.[^/.]+$/, '')} + + {item !== 'None' && ( + + {re.exec(item.toUpperCase())?.[1]} + + )} + + + ); +} diff --git a/src/pages/settings/components/Theming/Themes/ThemeModal/components/BackgroundPicker.tsx b/src/pages/settings/components/Theming/Themes/ThemeModal/components/BackgroundPicker.tsx new file mode 100644 index 0000000..c988210 --- /dev/null +++ b/src/pages/settings/components/Theming/Themes/ThemeModal/components/BackgroundPicker.tsx @@ -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(null); + return ( + + + { + 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; + }); + } + }} + /> + + + + {filtered.map((image: string, index: number) => ( + + ))} + + + + + + + + ); +} diff --git a/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeChanges.tsx b/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeChanges.tsx new file mode 100644 index 0000000..3c029d0 --- /dev/null +++ b/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeChanges.tsx @@ -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 ( + + + Changes + + + + {getObjectDiff(defaultTheme, designerTheme) !== null && + Object.keys(getObjectDiff(defaultTheme, designerTheme)).map((key: any) => { + return ( + key !== 'id' && ( + + + + {ThemeProperties[key as keyof typeof ThemeProperties]} + + + { + setDesignerTheme({ + ...designerTheme, + [key]: defaultTheme[key as keyof Theme], + }); + }} + pos={'absolute'} + right={0} + > + + + + + + {key === 'name' && ( + + {defaultTheme[key as keyof Theme]} + → + {designerTheme[key as keyof Theme]} + + )} + {key.includes('Shadow') && ( + + {defaultTheme[key as keyof Theme] === 0 ? ( + Off + ) : ( + On + )} + → + {designerTheme[key as keyof Theme] === 0 ? ( + Off + ) : ( + On + )} + + )} + {key.includes('Font') && ( + <> + + {defaultTheme[key as keyof Theme] || + `Default (${currentUser.defaultFont})`} + + → + + {designerTheme[key as keyof Theme] || + `Default (${currentUser.defaultFont})`} + + + )} + {key === 'backgroundImage' && ( + <> + + → + + + )} + {key.includes('Color') && ( + <> + + { + navigator.clipboard.writeText( + defaultTheme[key as keyof Theme] as string, + ); + notifications.show({ + title: ( + + Copied{' '} + { + ThemeProperties[ + key as keyof typeof ThemeProperties + ] + } + + ), + message: ( + + {defaultTheme[key as keyof Theme] as string} + + ), + autoClose: true, + withCloseButton: true, + icon: , + }); + }} + color={defaultTheme[key as keyof Theme] as string} + style={{ + cursor: 'pointer', + }} + styles={{ + alphaOverlay: { + borderRadius: '0px', + }, + colorOverlay: { + borderRadius: '0px', + }, + shadowOverlay: { + borderRadius: '0px', + }, + childrenOverlay: { + borderRadius: '0px', + }, + }} + /> + + → + + { + navigator.clipboard.writeText( + defaultTheme[key as keyof Theme] as string, + ); + notifications.show({ + title: ( + + Copied{' '} + { + ThemeProperties[ + key as keyof typeof ThemeProperties + ] + } + + ), + message: ( + + {designerTheme[key as keyof Theme] as string} + + ), + autoClose: true, + withCloseButton: true, + icon: , + }); + }} + color={designerTheme[key as keyof Theme] as string} + style={{ + cursor: 'pointer', + }} + styles={{ + alphaOverlay: { + borderRadius: '0px', + }, + colorOverlay: { + borderRadius: '0px', + }, + shadowOverlay: { + borderRadius: '0px', + }, + childrenOverlay: { + borderRadius: '0px', + }, + }} + /> + + + )} + + + ) + ); + })} + + + + ); +} diff --git a/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeColorPicker.tsx b/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeColorPicker.tsx new file mode 100644 index 0000000..24e45ad --- /dev/null +++ b/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeColorPicker.tsx @@ -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 ( + + + Change {ThemeProperties[colorId as keyof typeof ThemeProperties]} + + {colorId === 'searchColor' && ( + { + setColorValue(e); + setDesignerTheme({ + ...designerTheme, + [colorId]: e, + }); + }} + format={'hexa'} + w={'90%'} + /> + )} + {colorId !== 'searchColor' && ( + { + setColorValue(e); + setDesignerTheme({ + ...designerTheme, + [colorId]: e, + }); + }} + format={'hex'} + w={'90%'} + mb={'1.5rem'} + /> + )} + + setColorValue(e.target.value)} + /> + + { + 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, + }); + } + }} + /> + { + 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, + }); + } + }} + /> + { + 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, + }); + } + }} + /> + { + 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, + }); + } + }} + /> + + + + + + + + + + + + + + + ); +} diff --git a/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeColorSwatches.tsx b/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeColorSwatches.tsx new file mode 100644 index 0000000..5016e2e --- /dev/null +++ b/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeColorSwatches.tsx @@ -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 ( + <> + + { + handleSwatchClick('primaryColor', designerTheme.primaryColor); + }} + color={designerTheme.primaryColor} + style={{ borderColor: designerTheme.primaryColor }} + className={colorSwatchClasses.themeDesignerSwatch} + classNames={colorSwatchClasses} + top={'11.5rem'} + left={'8.5rem'} + /> + + + { + handleSwatchClick('accentColor', designerTheme.accentColor); + }} + color={designerTheme.accentColor} + style={{ borderColor: designerTheme.primaryColor }} + className={colorSwatchClasses.themeDesignerSwatch} + classNames={colorSwatchClasses} + bottom={'6rem'} + left={'11rem'} + /> + + + { + handleSwatchClick('backgroundColor', designerTheme.backgroundColor); + }} + color={designerTheme.backgroundColor} + style={{ borderColor: designerTheme.primaryColor }} + className={colorSwatchClasses.themeDesignerSwatch} + classNames={colorSwatchClasses} + bottom={'4rem'} + right={'3.5rem'} + /> + + + { + handleSwatchClick('borderColor', designerTheme.borderColor); + }} + color={designerTheme.borderColor} + style={{ borderColor: designerTheme.primaryColor }} + className={colorSwatchClasses.themeDesignerSwatch} + classNames={colorSwatchClasses} + top={'4.5rem'} + right={'15%'} + /> + + + { + handleSwatchClick('searchColor', designerTheme.searchColor); + }} + color={designerTheme.searchColor} + style={{ borderColor: designerTheme.primaryColor }} + className={colorSwatchClasses.themeDesignerSwatch} + classNames={colorSwatchClasses} + top={'3.25rem'} + left={'6.5rem'} + /> + + + { + closePicker(); + openBackgroundPicker(); + setDesignerTheme(designerTheme); + }} + pos={'absolute'} + right={0} + style={{ + color: designerTheme.backgroundColor, + backgroundColor: designerTheme.primaryColor, + borderRadius: 0, + borderBottomLeftRadius: 10, + borderTopRightRadius: 10, + }} + > + + + + + ); +} diff --git a/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeEditor.tsx b/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeEditor.tsx index f8749c1..e4ec2cd 100644 --- a/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeEditor.tsx +++ b/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeEditor.tsx @@ -1,38 +1,14 @@ -import { - ActionIcon, - Box, - Button, - Checkbox, - ColorPicker, - ColorSwatch, - Group, - Image, - Overlay, - ScrollArea, - Stack, - Text, - TextInput, - Tooltip, - UnstyledButton, -} from '@mantine/core'; +import { Button, Group, Stack } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; -import { notifications } from '@mantine/notifications'; import { useCommonHooks } from 'hooks'; -import { useEffect, useRef, useState } from 'react'; -import FontPicker from 'react-fontpicker-ts'; -import { FaCheck, FaClipboard, FaFont, FaGoogle } from 'react-icons/fa'; -import { FaShuffle } from 'react-icons/fa6'; -import { FiImage, FiRefreshCcw, FiSave, FiShuffle, FiX } from 'react-icons/fi'; -import { - buttonClasses, - colorSwatchClasses, - scrollAreaClasses, - textClasses, - textInputClasses, - toolTipClasses, -} from 'styles'; -import { type Theme, ThemeProperties } from 'types'; +import { useEffect, useState } from 'react'; +import { buttonClasses } from 'styles'; +import type { Theme } from 'types'; +import BackgroundPicker from './BackgroundPicker'; +import ThemeColorPicker from './ThemeColorPicker'; +import ThemeColorSwatches from './ThemeColorSwatches'; import { ThemeModalContent } from './ThemeModalContent'; +import ThemeOptions from './ThemeOptions'; export function ThemeEditor({ backgroundList, @@ -61,11 +37,7 @@ export function ThemeEditor({ duplicate: boolean; setDuplicate: (duplicate: boolean) => void; }) { - const [query, setQuery] = useState(''); - const [hovered, setHovered] = useState(-1); - const { currentUser, isMobile, theme, getObjectDiff, textShadowStyle } = - useCommonHooks(); - const viewportRef = useRef(null); + const { currentUser, isMobile } = useCommonHooks(); const [colorId, setColorId] = useState(''); const [colorValue, setColorValue] = useState('#000000'); const [rgba, setRgba] = useState<{ r: number; g: number; b: number; a?: number }>({ @@ -75,80 +47,8 @@ export function ThemeEditor({ }); const [font, setFont] = useState(); const [customFontEnabled, setCustomFontEnabled] = useState(false); - const re = /(?:\.([^.]+))?$/; const [backgroundPicker, { open: openBackgroundPicker, close: closeBackgroundPicker }] = useDisclosure(false); - const filtered = backgroundList.filter((item: string) => - item.toLowerCase().includes(query.toLowerCase()), - ); - const items = filtered.map((item: string, index: number) => { - return ( - - setDesignerTheme({ - ...designerTheme, - backgroundImage: item, - }) - } - > - - - {item.replace(/\.[^/.]+$/, '')} - - {item !== 'None' && ( - - {re.exec(item.toUpperCase())?.[1]} - - )} - - - ); - }); const handleSwatchClick = (colorId: string, colorValue: string) => { setRgba({ @@ -200,120 +100,19 @@ export function ThemeEditor({ }); } }, [colorValue]); + return ( <> - - { - handleSwatchClick('primaryColor', designerTheme.primaryColor); - }} - color={designerTheme.primaryColor} - style={{ borderColor: designerTheme.primaryColor }} - className={colorSwatchClasses.themeDesignerSwatch} - classNames={colorSwatchClasses} - top={'11.5rem'} - left={'8.5rem'} - /> - - - { - handleSwatchClick('accentColor', designerTheme.accentColor); - }} - color={designerTheme.accentColor} - style={{ borderColor: designerTheme.primaryColor }} - className={colorSwatchClasses.themeDesignerSwatch} - classNames={colorSwatchClasses} - bottom={'6rem'} - left={'11rem'} - /> - - - { - handleSwatchClick('backgroundColor', designerTheme.backgroundColor); - }} - color={designerTheme.backgroundColor} - style={{ borderColor: designerTheme.primaryColor }} - className={colorSwatchClasses.themeDesignerSwatch} - classNames={colorSwatchClasses} - bottom={'4rem'} - right={'3.5rem'} - /> - - - { - handleSwatchClick('borderColor', designerTheme.borderColor); - }} - color={designerTheme.borderColor} - style={{ borderColor: designerTheme.primaryColor }} - className={colorSwatchClasses.themeDesignerSwatch} - classNames={colorSwatchClasses} - top={'4.5rem'} - right={'15%'} - /> - - - { - handleSwatchClick('searchColor', designerTheme.searchColor); - }} - color={designerTheme.searchColor} - style={{ borderColor: designerTheme.primaryColor }} - className={colorSwatchClasses.themeDesignerSwatch} - classNames={colorSwatchClasses} - top={'3.25rem'} - left={'6.5rem'} - /> - - - { - closePicker(); - openBackgroundPicker(); - setDesignerTheme(designerTheme); - }} - pos={'absolute'} - right={0} - style={{ - color: designerTheme.backgroundColor, - backgroundColor: designerTheme.primaryColor, - borderRadius: 0, - borderBottomLeftRadius: 10, - borderTopRightRadius: 10, - }} - > - - - + {pickerOpen && ( - - - Change {ThemeProperties[colorId as keyof typeof ThemeProperties]} - - {colorId === 'searchColor' && ( - { - setColorValue(e); - setDesignerTheme({ - ...designerTheme, - [colorId]: e, - }); - }} - format={'hexa'} - w={'90%'} - /> - )} - {colorId !== 'searchColor' && ( - { - setColorValue(e); - setDesignerTheme({ - ...designerTheme, - [colorId]: e, - }); - }} - format={'hex'} - w={'90%'} - mb={'1.5rem'} - /> - )} - - setColorValue(e.target.value)} - /> - - { - 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, - }); - } - }} - /> - { - 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, - }); - } - }} - /> - { - 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, - }); - } - }} - /> - { - 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, - }); - } - }} - /> - - - - - - - - - - - - - - + )} {backgroundPicker && ( - - - { - setQuery(''); - }} - /> - } - onChange={(event) => { - setQuery(event.currentTarget.value); - setHovered(-1); - }} - onKeyDown={(event) => { - if (event.key === 'ArrowDown') { - event.preventDefault(); - setHovered((current) => { - 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) => { - const nextIndex = current - 1 < 0 ? current : current - 1; - viewportRef.current - ?.querySelectorAll('[data-list-item]') - ?.[nextIndex]?.scrollIntoView({ block: 'nearest' }); - return nextIndex; - }); - } - }} - /> - - - - {items} - - - - - - - + )} {!pickerOpen && !backgroundPicker && ( - - - - { - 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', - }} - > - - - - Shadows - - - - - { - 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', - }} - > - - - - - - - - - - { - setCustomFontEnabled(!customFontEnabled); - setFont( - customFontEnabled - ? currentUser.defaultFont - : defaultTheme.themeFont, - ); - }} - style={{ - borderRadius: '0px', - filter: `grayscale(${customFontEnabled ? 0 : '75%'})`, - }} - > - - - - { - if (!customFontEnabled) { - e.preventDefault(); - e.stopPropagation(); - } - }} - pos={'relative'} - > - {!customFontEnabled && } - { - if (customFontEnabled) { - setFont(pickerFont); - } - }} - /> - - - { - setFont(currentUser.defaultFont); - setCustomFontEnabled(false); - }} - style={{ - borderRadius: '0px', - }} - > - - - - - - {JSON.stringify(defaultTheme) !== JSON.stringify(designerTheme) && ( - - - Changes - - - - {getObjectDiff(defaultTheme, designerTheme) !== null && - Object.keys(getObjectDiff(defaultTheme, designerTheme)).map( - (key: any) => { - return ( - key !== 'id' && ( - - - - { - ThemeProperties[ - key as keyof typeof ThemeProperties - ] - } - - - { - setDesignerTheme({ - ...designerTheme, - [key]: defaultTheme[key as keyof Theme], - }); - }} - pos={'absolute'} - right={0} - > - - - - - - {key === 'name' && ( - <> - {defaultTheme[key as keyof Theme]} - → - {designerTheme[key as keyof Theme]} - - )} - {key.includes('Shadow') && ( - <> - {defaultTheme[key as keyof Theme] === 0 ? ( - Off - ) : ( - On - )} - → - {designerTheme[key as keyof Theme] === 0 ? ( - Off - ) : ( - On - )} - - )} - {key.includes('Font') && ( - <> - - {defaultTheme[key as keyof Theme] || - `Default (${currentUser.defaultFont})`} - - → - - {designerTheme[key as keyof Theme] || - `Default (${currentUser.defaultFont})`} - - - )} - {key === 'backgroundImage' && ( - <> - - → - - - )} - {key.includes('Color') && ( - <> - - { - navigator.clipboard.writeText( - defaultTheme[ - key as keyof Theme - ] as string, - ); - notifications.show({ - title: ( - - Copied{' '} - { - ThemeProperties[ - key as keyof typeof ThemeProperties - ] - } - - ), - message: ( - - { - defaultTheme[ - key as keyof Theme - ] as string - } - - ), - autoClose: true, - withCloseButton: true, - icon: , - }); - }} - color={ - defaultTheme[key as keyof Theme] as string - } - style={{ - cursor: 'pointer', - }} - styles={{ - alphaOverlay: { - borderRadius: '0px', - }, - colorOverlay: { - borderRadius: '0px', - }, - shadowOverlay: { - borderRadius: '0px', - }, - childrenOverlay: { - borderRadius: '0px', - }, - }} - /> - - → - - { - navigator.clipboard.writeText( - defaultTheme[ - key as keyof Theme - ] as string, - ); - notifications.show({ - title: ( - - Copied{' '} - { - ThemeProperties[ - key as keyof typeof ThemeProperties - ] - } - - ), - message: ( - - { - designerTheme[ - key as keyof Theme - ] as string - } - - ), - autoClose: true, - withCloseButton: true, - icon: , - }); - }} - color={ - designerTheme[key as keyof Theme] as string - } - style={{ - cursor: 'pointer', - }} - styles={{ - alphaOverlay: { - borderRadius: '0px', - }, - colorOverlay: { - borderRadius: '0px', - }, - shadowOverlay: { - borderRadius: '0px', - }, - childrenOverlay: { - borderRadius: '0px', - }, - }} - /> - - - )} - - - ) - ); - }, - )} - - - - )} - - - - - - - + )} diff --git a/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeOptions.tsx b/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeOptions.tsx new file mode 100644 index 0000000..d341c5e --- /dev/null +++ b/src/pages/settings/components/Theming/Themes/ThemeModal/components/ThemeOptions.tsx @@ -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 ( + + + + { + 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', + }} + > + + + + Shadows + + + + + { + 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', + }} + > + + + + + + + + + + { + setCustomFontEnabled(!customFontEnabled); + setFont( + customFontEnabled ? currentUser.defaultFont : defaultTheme.themeFont, + ); + }} + style={{ + borderRadius: '0px', + filter: `grayscale(${customFontEnabled ? 0 : '75%'})`, + }} + > + + + + { + if (!customFontEnabled) { + e.preventDefault(); + e.stopPropagation(); + } + }} + pos={'relative'} + > + {!customFontEnabled && } + { + if (customFontEnabled) { + setFont(pickerFont); + } + }} + /> + + + { + setFont(currentUser.defaultFont); + setCustomFontEnabled(false); + }} + style={{ + borderRadius: '0px', + }} + > + + + + + + {JSON.stringify(defaultTheme) !== JSON.stringify(designerTheme) && ( + + )} + + + + + + + + ); +}