From 7b588421e05419ef29bc9faf5985e0bd10cd3431 Mon Sep 17 00:00:00 2001 From: Ty Tremblay Date: Fri, 13 Dec 2024 14:11:19 -0500 Subject: [PATCH] add dynamic settings modal --- .../Sections/ConfigSection/ConfigSection.tsx | 105 +++++++++++++++--- .../Sections/ConfigSection/Settings.tsx | 95 ++++++---------- .../Sections/ConfigSection/ThemeSelector.tsx | 25 +++-- src/hooks/index.ts | 1 + src/hooks/useMediaQuery.tsx | 17 +++ 5 files changed, 156 insertions(+), 87 deletions(-) create mode 100644 src/hooks/useMediaQuery.tsx diff --git a/src/components/Sections/ConfigSection/ConfigSection.tsx b/src/components/Sections/ConfigSection/ConfigSection.tsx index 099b1e6..d59c52f 100644 --- a/src/components/Sections/ConfigSection/ConfigSection.tsx +++ b/src/components/Sections/ConfigSection/ConfigSection.tsx @@ -1,3 +1,13 @@ +import { ConfigEditor } from '@/components/ConfigEditor'; +import { Button } from '@/components/ui/button'; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog'; import { Drawer, DrawerContent, @@ -6,33 +16,92 @@ import { DrawerTitle, DrawerTrigger, } from '@/components/ui/drawer'; +import { useMediaQuery } from '@/hooks'; +import { setConfig } from '@/store/store'; +import { Transition } from '@headlessui/react'; import { Cog6ToothIcon } from '@heroicons/react/20/solid'; +import { useMemo, useState } from 'preact/hooks'; import { Section } from '../../core/Section'; import { Settings } from './Settings'; import { ThemeSelector } from './ThemeSelector'; export function ConfigSection() { - return ( -
-
- - -
+ const [open, setOpen] = useState(false); + const [showEditor, setShowEditor] = useState(false); + const isDesktop = useMediaQuery('(min-width: 768px)'); + + const handleShowEditor = (show: boolean) => { + if (show) { + setOpen(false); + } + setShowEditor(show); + }; + + const dialogOrDrawer = useMemo(() => { + if (isDesktop) { + return ( + + +
-
- - - Settings - - - + + + + + Settings + + + - - -
-
+ + + + ); + } + return ( + + + + + + + Settings + + + + + + + + ); + }, [isDesktop, open, setShowEditor]); + + return ( +
+ {dialogOrDrawer} + + + setShowEditor(false)} + onSave={configString => { + setConfig(configString); + setShowEditor(false); + }} + /> +
); } diff --git a/src/components/Sections/ConfigSection/Settings.tsx b/src/components/Sections/ConfigSection/Settings.tsx index 48ab2cb..bf0d3e4 100644 --- a/src/components/Sections/ConfigSection/Settings.tsx +++ b/src/components/Sections/ConfigSection/Settings.tsx @@ -1,13 +1,9 @@ import { Button } from '@/components/ui/button'; -import { Transition } from '@headlessui/react'; -import { useState } from 'preact/hooks'; import { resetToDefaultConfig, - setConfig, uploadConfig, useQRScoutState, } from '../../../store/store'; -import { ConfigEditor } from '../../ConfigEditor'; import { Config } from '../../inputs/BaseInputProps'; /** @@ -44,63 +40,46 @@ function downloadConfig(formData: Config) { download('QRScout_config.json', JSON.stringify(configDownload)); } -export function Settings() { +type SettingsProps = { + setShowEditor: (showEditor: boolean) => void; +}; + +export function Settings({ setShowEditor }: SettingsProps) { const formData = useQRScoutState(state => state.formData); - const [showEditor, setShowEditor] = useState(false); return ( - <> -
- - - - - -
- + + + + - + + + ); } diff --git a/src/components/Sections/ConfigSection/ThemeSelector.tsx b/src/components/Sections/ConfigSection/ThemeSelector.tsx index 37ee1d7..c856e87 100644 --- a/src/components/Sections/ConfigSection/ThemeSelector.tsx +++ b/src/components/Sections/ConfigSection/ThemeSelector.tsx @@ -6,16 +6,19 @@ export function ThemeSelector() { const { theme, setTheme, resolvedTheme } = useTheme(); return ( - - - - - - - - - - - +
+ Theme: + + + + + + + + + + + +
); } diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 84bc075..77acb1e 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1 +1,2 @@ +export * from './useMediaQuery'; export * from './useOnClickOutside'; diff --git a/src/hooks/useMediaQuery.tsx b/src/hooks/useMediaQuery.tsx new file mode 100644 index 0000000..3df1740 --- /dev/null +++ b/src/hooks/useMediaQuery.tsx @@ -0,0 +1,17 @@ +import { useEffect, useState } from 'react'; + +export function useMediaQuery(query: string) { + const [matches, setMatches] = useState(false); + + useEffect(() => { + const media = window.matchMedia(query); + if (media.matches !== matches) { + setMatches(media.matches); + } + const listener = () => setMatches(media.matches); + window.addEventListener('resize', listener); + return () => window.removeEventListener('resize', listener); + }, [matches, query]); + + return matches; +}