Background modal updates
This commit is contained in:
@@ -19,7 +19,7 @@
|
|||||||
"noExplicitAny": "off",
|
"noExplicitAny": "off",
|
||||||
"noImplicitAnyLet": "off",
|
"noImplicitAnyLet": "off",
|
||||||
"recommended": true,
|
"recommended": true,
|
||||||
"noConsole": { "level": "error", "options": { "allow": ["error", "log"] } }
|
"noConsole": { "level": "error", "options": { "allow": ["error"] } }
|
||||||
},
|
},
|
||||||
"correctness": {
|
"correctness": {
|
||||||
"useExhaustiveDependencies": "off",
|
"useExhaustiveDependencies": "off",
|
||||||
|
|||||||
@@ -298,6 +298,8 @@ export function useFileUploadAPI() {
|
|||||||
onMutate: () => {},
|
onMutate: () => {},
|
||||||
onSuccess: (_variables) => {
|
onSuccess: (_variables) => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['GET', 'api/backgrounds'] });
|
queryClient.invalidateQueries({ queryKey: ['GET', 'api/backgrounds'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['GET', 'api/themes'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['GET', 'api/themePlaylists'] });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,12 @@ import {
|
|||||||
Group,
|
Group,
|
||||||
Image,
|
Image,
|
||||||
Modal,
|
Modal,
|
||||||
|
Overlay,
|
||||||
ScrollArea,
|
ScrollArea,
|
||||||
SimpleGrid,
|
SimpleGrid,
|
||||||
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
|
TextInput,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useCommonHooks } from 'hooks';
|
import { useCommonHooks } from 'hooks';
|
||||||
import { useFileUploadAPI, useMutationAPI } from 'hooks/useAPI';
|
import { useFileUploadAPI, useMutationAPI } from 'hooks/useAPI';
|
||||||
@@ -20,13 +23,18 @@ function BackgroundModal({
|
|||||||
backgroundModalOpened,
|
backgroundModalOpened,
|
||||||
handleBackgroundModalClose,
|
handleBackgroundModalClose,
|
||||||
backgroundList,
|
backgroundList,
|
||||||
|
inUseBackgrounds,
|
||||||
}: {
|
}: {
|
||||||
backgroundModalOpened: boolean;
|
backgroundModalOpened: boolean;
|
||||||
handleBackgroundModalClose: () => void;
|
handleBackgroundModalClose: () => void;
|
||||||
backgroundList: string[];
|
backgroundList: string[];
|
||||||
|
inUseBackgrounds: string[];
|
||||||
}) {
|
}) {
|
||||||
const [background, setBackground] = useState<File | null>(null);
|
const [background, setBackground] = useState<File | null>(null);
|
||||||
|
const [fileName, setFileName] = useState<string>('');
|
||||||
|
const [newFileName, setNewFileName] = useState<string>('');
|
||||||
const [err, setErr] = useState<boolean>(false);
|
const [err, setErr] = useState<boolean>(false);
|
||||||
|
const [confirm, setConfirm] = useState<boolean>(false);
|
||||||
const { isMobile } = useCommonHooks();
|
const { isMobile } = useCommonHooks();
|
||||||
const { mutateAsync: uploadAsync } = useFileUploadAPI();
|
const { mutateAsync: uploadAsync } = useFileUploadAPI();
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
@@ -34,8 +42,8 @@ function BackgroundModal({
|
|||||||
const handleFileUpload = (e: any) => {
|
const handleFileUpload = (e: any) => {
|
||||||
setErr(false);
|
setErr(false);
|
||||||
setBackground(e);
|
setBackground(e);
|
||||||
|
setFileName(e?.name);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal.Root
|
<Modal.Root
|
||||||
size={'75%'}
|
size={'75%'}
|
||||||
@@ -43,8 +51,11 @@ function BackgroundModal({
|
|||||||
classNames={modalClasses}
|
classNames={modalClasses}
|
||||||
opened={backgroundModalOpened}
|
opened={backgroundModalOpened}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
handleBackgroundModalClose();
|
|
||||||
setBackground(null);
|
setBackground(null);
|
||||||
|
setFileName('');
|
||||||
|
setNewFileName('');
|
||||||
|
handleBackgroundModalClose();
|
||||||
|
setConfirm(false);
|
||||||
}}
|
}}
|
||||||
fullScreen={isMobile}
|
fullScreen={isMobile}
|
||||||
centered
|
centered
|
||||||
@@ -59,141 +70,251 @@ function BackgroundModal({
|
|||||||
</Group>
|
</Group>
|
||||||
<Modal.CloseButton />
|
<Modal.CloseButton />
|
||||||
</Modal.Header>
|
</Modal.Header>
|
||||||
<Modal.Body p={'2rem'}>
|
<Modal.Body p={'1rem'}>
|
||||||
<ScrollArea
|
<Stack align='center' w={'100%'}>
|
||||||
className={scrollAreaClasses.default}
|
{confirm ? (
|
||||||
classNames={scrollAreaClasses}
|
<Stack
|
||||||
type={'always'}
|
justify='center'
|
||||||
style={{
|
align='center'
|
||||||
width: '100%',
|
style={{
|
||||||
height: '30rem',
|
width: '100%',
|
||||||
backgroundColor: 'var(--mantine-color-search-0)',
|
height: '30rem',
|
||||||
padding: '1rem',
|
backgroundColor: 'var(--mantine-color-search-0)',
|
||||||
borderRadius: '.5rem',
|
padding: '1rem',
|
||||||
backgroundFilter: 'blur(5px)',
|
borderRadius: '.5rem',
|
||||||
}}
|
backgroundFilter: 'blur(5px)',
|
||||||
>
|
}}
|
||||||
<SimpleGrid w={'100%'} cols={3} p={'.5rem'}>
|
>
|
||||||
{backgroundList
|
<Text fw={600} fz={'2rem'}>
|
||||||
.filter((background) => background !== 'None')
|
Are you sure you want to delete {fileName}?
|
||||||
.map((background) => (
|
</Text>
|
||||||
<Group key={background} display={'flex'} pos={'relative'}>
|
{inUseBackgrounds.includes(fileName) && (
|
||||||
<Text
|
<Text fw={600} fz={'1.5rem'}>
|
||||||
style={{
|
This background is currently in use! This will result in a blank
|
||||||
color: 'var(--mantine-color-primary-0)',
|
background on the theme.
|
||||||
backgroundColor: 'var(--mantine-color-accent-0)',
|
</Text>
|
||||||
padding: '.25rem',
|
)}
|
||||||
borderRadius: '.5rem',
|
<Text fw={600} fz={'3rem'}>
|
||||||
position: 'absolute',
|
THIS ACTION CANNOT BE UNDONE!!!
|
||||||
top: '-.5rem',
|
</Text>
|
||||||
left: 0,
|
<Card
|
||||||
zIndex: 3,
|
style={{
|
||||||
}}
|
aspectRatio: '16/9',
|
||||||
>
|
height: '100%',
|
||||||
{background}
|
backgroundImage: `url(../../api/backgroundImages/${fileName})`,
|
||||||
</Text>
|
backgroundSize: 'cover',
|
||||||
<Card
|
backgroundPosition: 'center',
|
||||||
style={{
|
backgroundRepeat: 'no-repeat',
|
||||||
aspectRatio: '16/9',
|
padding: '2rem',
|
||||||
width: '100%',
|
margin: '1rem',
|
||||||
backgroundImage: `url(../../api/backgroundImages/${background})`,
|
}}
|
||||||
backgroundSize: 'cover',
|
/>
|
||||||
backgroundPosition: 'center',
|
<Group>
|
||||||
backgroundRepeat: 'no-repeat',
|
<Button
|
||||||
padding: '2rem',
|
mt={'auto'}
|
||||||
margin: '1rem',
|
w={'min-content'}
|
||||||
}}
|
color='red'
|
||||||
/>
|
onClick={() => {
|
||||||
<ActionIcon
|
setBackground(null);
|
||||||
color='var(--mantine-color-red-6)'
|
setFileName('');
|
||||||
style={{
|
setNewFileName('');
|
||||||
position: 'absolute',
|
setConfirm(false);
|
||||||
bottom: '.5rem',
|
setFileName('');
|
||||||
right: '.5rem',
|
mutateAsync({
|
||||||
zIndex: 3,
|
method: 'DELETE',
|
||||||
}}
|
endpoint: 'api/backgrounds',
|
||||||
onClick={() => {
|
body: { fileName },
|
||||||
mutateAsync({
|
});
|
||||||
method: 'DELETE',
|
}}
|
||||||
endpoint: 'api/backgrounds',
|
>
|
||||||
body: { background },
|
DELETE
|
||||||
});
|
</Button>
|
||||||
}}
|
<Button
|
||||||
>
|
mt={'auto'}
|
||||||
<FiTrash />
|
w={'min-content'}
|
||||||
</ActionIcon>
|
onClick={() => {
|
||||||
</Group>
|
setBackground(null);
|
||||||
))}
|
setFileName('');
|
||||||
</SimpleGrid>
|
setNewFileName('');
|
||||||
</ScrollArea>
|
setConfirm(false);
|
||||||
<Group gap={0} w={'100%'} align={'center'} justify='space-between'>
|
setFileName('');
|
||||||
<FileInput
|
}}
|
||||||
clearable
|
>
|
||||||
accept='image/png,image/jpeg'
|
Cancel
|
||||||
value={background}
|
</Button>
|
||||||
onChange={handleFileUpload}
|
</Group>
|
||||||
label={'Upload Background'}
|
</Stack>
|
||||||
placeholder={'Select...'}
|
) : (
|
||||||
description={
|
<ScrollArea
|
||||||
'Max size: 50MB for upload. Images are resized to 300kb after upload.'
|
className={scrollAreaClasses.default}
|
||||||
}
|
classNames={scrollAreaClasses}
|
||||||
p={'xl'}
|
type={'always'}
|
||||||
w={'60%'}
|
style={{
|
||||||
pl={0}
|
width: '100%',
|
||||||
error={err && 'Please upload a background'}
|
height: '30rem',
|
||||||
styles={{
|
backgroundColor: 'var(--mantine-color-search-0)',
|
||||||
input: {
|
padding: '1rem',
|
||||||
color: 'var(--mantine-color-primary-0)',
|
borderRadius: '.5rem',
|
||||||
borderColor: 'var(--mantine-color-primary-0)',
|
backgroundFilter: 'blur(5px)',
|
||||||
},
|
}}
|
||||||
placeholder: {
|
>
|
||||||
color: 'var(--mantine-color-accent-0)',
|
<SimpleGrid w={'100%'} cols={3} p={'.5rem'}>
|
||||||
},
|
{backgroundList
|
||||||
}}
|
.filter((background) => background !== 'None')
|
||||||
/>
|
.map((background) => (
|
||||||
<Card
|
<Group key={background} display={'flex'} pos={'relative'}>
|
||||||
style={{
|
<Text
|
||||||
aspectRatio: '16/9',
|
style={{
|
||||||
width: '35%',
|
color: 'var(--mantine-color-primary-0)',
|
||||||
backgroundSize: 'cover',
|
backgroundColor: 'var(--mantine-color-accent-0)',
|
||||||
backgroundPosition: 'center',
|
padding: '.25rem',
|
||||||
backgroundRepeat: 'no-repeat',
|
borderRadius: '.5rem',
|
||||||
backgroundColor: 'var(--mantine-color-search-0)',
|
position: 'absolute',
|
||||||
padding: '2rem',
|
top: '-.5rem',
|
||||||
margin: '1rem',
|
left: 0,
|
||||||
marginRight: 0,
|
zIndex: 3,
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
{background}
|
||||||
|
</Text>
|
||||||
|
<Card
|
||||||
|
style={{
|
||||||
|
aspectRatio: '16/9',
|
||||||
|
width: '100%',
|
||||||
|
backgroundImage: `url(../../api/backgroundImages/${background})`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
padding: '2rem',
|
||||||
|
margin: '1rem',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ActionIcon
|
||||||
|
color='var(--mantine-color-red-6)'
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: '.5rem',
|
||||||
|
right: '.5rem',
|
||||||
|
zIndex: 3,
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
setFileName(background);
|
||||||
|
setConfirm(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FiTrash />
|
||||||
|
</ActionIcon>
|
||||||
|
</Group>
|
||||||
|
))}
|
||||||
|
</SimpleGrid>
|
||||||
|
</ScrollArea>
|
||||||
|
)}
|
||||||
|
<Stack
|
||||||
|
display={'flex'}
|
||||||
|
pos={'relative'}
|
||||||
|
w={'100%'}
|
||||||
|
align={'center'}
|
||||||
|
justify='space-between'
|
||||||
|
p={16}
|
||||||
>
|
>
|
||||||
{background ? (
|
{confirm && (
|
||||||
<Image src={URL.createObjectURL(background)} w={'100%'} h={'100%'} />
|
<Overlay
|
||||||
) : (
|
opacity={1}
|
||||||
<Image
|
color='var(--mantine-color-search-0)'
|
||||||
src={'https://placehold.co/800x450?text=Select%20an%20Image'}
|
style={{ borderRadius: '.5rem', backdropFilter: 'blur(5px)' }}
|
||||||
w={'100%'}
|
|
||||||
h={'100%'}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Card>
|
<Group gap={0}>
|
||||||
</Group>
|
<Stack gap={0} w={'60%'}>
|
||||||
<Button
|
<FileInput
|
||||||
onClick={() => {
|
clearable
|
||||||
if (background) {
|
accept='image/png,image/jpeg'
|
||||||
fd.append('background', background || '');
|
value={background}
|
||||||
uploadAsync({
|
onChange={handleFileUpload}
|
||||||
method: 'POST',
|
label={'Upload Background'}
|
||||||
endpoint: 'api/backgrounds',
|
placeholder={'Select...'}
|
||||||
body: fd,
|
error={err && 'Please upload a background'}
|
||||||
});
|
description={
|
||||||
handleBackgroundModalClose();
|
'Max size: 50MB for upload. Images are resized to 300kb after upload.'
|
||||||
setBackground(null);
|
}
|
||||||
setErr(false);
|
pr={'xl'}
|
||||||
} else {
|
pl={0}
|
||||||
setErr(true);
|
styles={{
|
||||||
}
|
input: {
|
||||||
}}
|
color: 'var(--mantine-color-primary-0)',
|
||||||
>
|
borderColor: 'var(--mantine-color-primary-0)',
|
||||||
Upload
|
},
|
||||||
</Button>
|
placeholder: {
|
||||||
|
color: 'var(--mantine-color-accent-0)',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label={'File Name'}
|
||||||
|
placeholder={fileName}
|
||||||
|
value={newFileName}
|
||||||
|
onChange={(e) => setNewFileName(e.target.value)}
|
||||||
|
pr={'xl'}
|
||||||
|
pl={0}
|
||||||
|
styles={{
|
||||||
|
input: {
|
||||||
|
color: 'var(--mantine-color-primary-0)',
|
||||||
|
borderColor: 'var(--mantine-color-primary-0)',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
<Card
|
||||||
|
style={{
|
||||||
|
aspectRatio: '16/9',
|
||||||
|
width: '35%',
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundColor: 'var(--mantine-color-search-0)',
|
||||||
|
padding: '2rem',
|
||||||
|
margin: '1rem',
|
||||||
|
marginRight: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{background ? (
|
||||||
|
<Image src={URL.createObjectURL(background)} w={'100%'} h={'100%'} />
|
||||||
|
) : (
|
||||||
|
<Image
|
||||||
|
src={'https://placehold.co/800x450?text=Upload%20an%20Image'}
|
||||||
|
w={'100%'}
|
||||||
|
h={'100%'}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
</Group>
|
||||||
|
<Button
|
||||||
|
w={'min-content'}
|
||||||
|
onClick={() => {
|
||||||
|
if (background) {
|
||||||
|
const newBackground = new File(
|
||||||
|
[background],
|
||||||
|
newFileName || background.name,
|
||||||
|
{ type: background.type },
|
||||||
|
);
|
||||||
|
fd.append('background', newBackground || '');
|
||||||
|
uploadAsync({
|
||||||
|
method: 'POST',
|
||||||
|
endpoint: 'api/backgrounds',
|
||||||
|
body: fd,
|
||||||
|
});
|
||||||
|
setBackground(null);
|
||||||
|
setNewFileName('');
|
||||||
|
setErr(false);
|
||||||
|
} else {
|
||||||
|
setErr(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Upload
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
</Modal.Content>
|
</Modal.Content>
|
||||||
</Modal.Root>
|
</Modal.Root>
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ function ThemesSettings() {
|
|||||||
const [colorId, setColorId] = useState<string>('');
|
const [colorId, setColorId] = useState<string>('');
|
||||||
const [colorValue, setColorValue] = useState('#000000');
|
const [colorValue, setColorValue] = useState('#000000');
|
||||||
const [backgroundList, setBackgroundList] = useState<string[]>(['None']);
|
const [backgroundList, setBackgroundList] = useState<string[]>(['None']);
|
||||||
|
const [inUseBackgrounds, setInUseBackgrounds] = useState<string[]>([]);
|
||||||
const [selectedTheme, setSelectedTheme] = useState<Theme>({
|
const [selectedTheme, setSelectedTheme] = useState<Theme>({
|
||||||
id: undefined,
|
id: undefined,
|
||||||
name: 'default',
|
name: 'default',
|
||||||
@@ -119,6 +120,23 @@ function ThemesSettings() {
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
}, [allThemeData, isAllThemeDataFetched, debouncedSearch]);
|
}, [allThemeData, isAllThemeDataFetched, debouncedSearch]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (allThemes) {
|
||||||
|
setInUseBackgrounds([
|
||||||
|
...new Set(
|
||||||
|
allThemes
|
||||||
|
.filter((t) => {
|
||||||
|
if (t.backgroundImage !== 'none') {
|
||||||
|
return t.backgroundImage;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map((t) => t.backgroundImage),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}, [allThemes]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack w={'100%'} align='center'>
|
<Stack w={'100%'} align='center'>
|
||||||
<ThemeModal
|
<ThemeModal
|
||||||
@@ -140,6 +158,7 @@ function ThemesSettings() {
|
|||||||
backgroundModalOpened={backgroundModalOpened}
|
backgroundModalOpened={backgroundModalOpened}
|
||||||
handleBackgroundModalClose={handleBackgroundModalClose}
|
handleBackgroundModalClose={handleBackgroundModalClose}
|
||||||
backgroundList={backgroundList}
|
backgroundList={backgroundList}
|
||||||
|
inUseBackgrounds={inUseBackgrounds}
|
||||||
/>
|
/>
|
||||||
<SettingsHeader
|
<SettingsHeader
|
||||||
setDragging={undefined}
|
setDragging={undefined}
|
||||||
|
|||||||
Reference in New Issue
Block a user