import { ActionIcon, Button, Checkbox, ColorPicker, ColorSwatch, Group, Image, Modal, ScrollArea, Stack, Text, TextInput, Tooltip, UnstyledButton, } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; import { useCommonHooks } from 'hooks'; import { useEffect, useRef, useState } from 'react'; import { FiImage, FiSave, FiX } from 'react-icons/fi'; import { modalClasses, scrollAreaClasses, textClasses, textInputClasses } from 'styles'; import { BackgroundProperties, type Theme } from 'types'; import { ThemeModalContent } from './ThemeModalContent'; export function ThemeModal({ opened, handleClose, selectedTheme, setSelectedTheme, openPicker, backgroundList, pickerOpen, closePicker, handleSaveTheme, }: { opened: boolean; handleClose: () => void; selectedTheme: Theme; setSelectedTheme: (selectedTheme: Theme) => void; openPicker: () => void; backgroundList: string[]; pickerOpen: boolean; closePicker: () => void; handleSaveTheme: () => void; }) { const { isMobile, theme, getObjectDiff } = useCommonHooks(); const viewportRef = useRef(null); const [query, setQuery] = useState(''); const [hovered, setHovered] = useState(-1); const [colorId, setColorId] = useState(''); const [colorValue, setColorValue] = useState('#000000'); const [defaultTheme, setDefaultTheme] = useState({ ...selectedTheme }); const [designerTheme, setDesignerTheme] = useState({ ...selectedTheme, }); const filtered = backgroundList.filter((item: string) => item.toLowerCase().includes(query.toLowerCase()), ); const [backgroundPicker, { open: openBackgroundPicker, close: closeBackgroundPicker }] = useDisclosure(false); const re = /(?:\.([^.]+))?$/; const items = filtered.map((item: string, index: number) => { return ( setDesignerTheme({ ...designerTheme, backgroundImage: item, }) } > {item.replace(/\.[^/.]+$/, '')} {item !== 'None' && ( {re.exec(item.toUpperCase())?.[1]} )} ); }); const handleSwatchClick = () => { closeBackgroundPicker(); openPicker(); setDesignerTheme(selectedTheme); }; useEffect(() => { setDesignerTheme(selectedTheme); if (defaultTheme.id !== selectedTheme.id) { setDefaultTheme(selectedTheme); } }, [selectedTheme]); return ( Name: setSelectedTheme({ ...selectedTheme, name: e.target.value }) } styles={{ label: { color: 'var(--mantine-color-primary-0)', }, input: { color: selectedTheme.primaryColor, backgroundColor: selectedTheme.backgroundColor, border: 'none', borderBottom: '1px solid var(--mantine-color-primary-0)', }, }} /> { setColorId('primaryColor'); setColorValue(selectedTheme.primaryColor); handleSwatchClick(); }} color={selectedTheme.primaryColor} bd={`1px solid ${selectedTheme.primaryColor}`} pos={'absolute'} top={'6.25rem'} left={'1.5rem'} /> { setColorId('accentColor'); setColorValue(selectedTheme.accentColor); handleSwatchClick(); }} color={selectedTheme.accentColor} bd={`1px solid ${selectedTheme.primaryColor}`} pos={'absolute'} bottom={'6rem'} left={'11rem'} /> { setColorId('backgroundColor'); setColorValue(selectedTheme.backgroundColor); handleSwatchClick(); }} color={selectedTheme.backgroundColor} bd={`1px solid ${selectedTheme.primaryColor}`} pos={'absolute'} bottom={'10rem'} right={'3.5rem'} /> { setColorId('borderColor'); setColorValue(selectedTheme.borderColor); handleSwatchClick(); }} color={selectedTheme.borderColor} bd={`1px solid ${selectedTheme.primaryColor}`} pos={'absolute'} top={'4.5rem'} right={'15%'} /> { setColorId('searchColor'); setColorValue(selectedTheme.searchColor); handleSwatchClick(); }} color={selectedTheme.searchColor} bd={`1px solid ${selectedTheme.primaryColor}`} pos={'absolute'} top={'3.25rem'} left={'6.5rem'} /> { closePicker(); openBackgroundPicker(); setDesignerTheme(selectedTheme); }} pos={'absolute'} right={0} > {pickerOpen && ( Change{' '} {BackgroundProperties[colorId as keyof typeof BackgroundProperties]} {colorId === 'backgroundColor' && ( { setColorValue(e); setDesignerTheme({ ...designerTheme, backgroundColor: e, }); }} format={'hex'} w={'90%'} mb={'1.5rem'} /> )} {colorId !== 'backgroundColor' && ( { setColorValue(e); setDesignerTheme({ ...designerTheme, [colorId]: e, }); }} format={'hexa'} w={'90%'} /> )} setColorValue(e.target.value)} /> )} {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 && ( { setSelectedTheme({ ...selectedTheme, textShadowsEnabled: e.target.checked ? 1 : 0, }); }} styles={{ root: { width: '50%' }, body: { width: '100%', display: 'flex', justifyContent: 'space-between', }, }} /> { setSelectedTheme({ ...selectedTheme, appShadowsEnabled: e.target.checked ? 1 : 0, }); }} styles={{ root: { width: '50%' }, body: { width: '100%', display: 'flex', justifyContent: 'space-between', }, }} /> {JSON.stringify(defaultTheme) !== JSON.stringify(selectedTheme) && ( <> Changes: {getObjectDiff(defaultTheme, designerTheme) !== null && Object.keys(getObjectDiff(defaultTheme, designerTheme)).map( (key: any) => { return ( { BackgroundProperties[ key as keyof typeof BackgroundProperties ] } {key === 'name' && ( {defaultTheme[key as keyof Theme]} → {designerTheme[key as keyof Theme]} )} {key === 'backgroundImage' && ( → )} {key.includes('Color') && ( → )} {key.includes('Shadow') && ( {defaultTheme[key as keyof Theme] === 0 ? ( Off ) : ( On )} → {designerTheme[key as keyof Theme] === 0 ? ( Off ) : ( On )} )} ); }, )} )} )} ); }