diff --git a/src/app/Document.tsx b/src/app/Document.tsx index f098151b0..0c3d8e38f 100644 --- a/src/app/Document.tsx +++ b/src/app/Document.tsx @@ -7,7 +7,8 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { Providers } from '@/app/Providers'; import { Viewport } from '@/components/Viewport'; -import { EnvHint } from '@/features/devtools/EnvHint'; +import { env } from '@/env.mjs'; +import { AppHint } from '@/features/devtools/AppHint'; import { useLocale } from '@/lib/i18n/useLocale'; import { TrpcProvider } from '@/lib/trpc/TrpcProvider'; import theme, { COLOR_MODE_STORAGE_KEY } from '@/theme'; @@ -65,8 +66,10 @@ export const Document = ({ children }: { children: ReactNode }) => { {children} - - + + {env.NEXT_PUBLIC_DEV_TOOLS_ENABLED && ( + + )} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index cc64349bc..168f35c52 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -4,7 +4,7 @@ import { Metadata } from 'next'; import { Document } from '@/app/Document'; import { NextLoader } from '@/app/NextLoader'; -import { getEnvHintTitlePrefix } from '@/features/devtools/EnvHint'; +import { getEnvHintTitlePrefix } from '@/features/devtools/AppHint'; export const metadata: Metadata = { title: { diff --git a/src/components/DarkModeSwitch/index.tsx b/src/components/DarkModeSwitch/index.tsx new file mode 100644 index 000000000..1af24c4dd --- /dev/null +++ b/src/components/DarkModeSwitch/index.tsx @@ -0,0 +1,46 @@ +import { useId } from 'react'; + +import { + FormControl, + FormLabel, + HStack, + Switch, + useColorMode, +} from '@chakra-ui/react'; +import { useTranslation } from 'react-i18next'; + +export const DarkModeSwitch = () => { + const { t } = useTranslation(['account']); + const { colorMode, setColorMode } = useColorMode(); + const id = useId(); + + return ( + + + + {t('account:preferences.theme.light')} + + setColorMode(e.target.checked ? 'dark' : 'light')} + /> + + {t('account:preferences.theme.dark')} + + + + ); +}; diff --git a/src/env.mjs b/src/env.mjs index fc4bb2bdd..5119a2f15 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -62,6 +62,16 @@ export const env = createEnv({ value ?? (process.env.NODE_ENV === 'development' ? 'warning' : 'success') ), + NEXT_PUBLIC_DEV_TOOLS_ENABLED: z + .enum(['true', 'false']) + .optional() + .transform((value) => { + if (value) { + return value === 'true'; + } + + return process.env.NODE_ENV === 'development' ? true : false; + }), NEXT_PUBLIC_NODE_ENV: zNodeEnv(), }, @@ -83,6 +93,7 @@ export const env = createEnv({ NEXT_PUBLIC_ENV_COLOR_SCHEME: process.env.NEXT_PUBLIC_ENV_COLOR_SCHEME, NEXT_PUBLIC_ENV_NAME: process.env.NEXT_PUBLIC_ENV_NAME, NEXT_PUBLIC_ENV_EMOJI: process.env.NEXT_PUBLIC_ENV_EMOJI, + NEXT_PUBLIC_DEV_TOOLS_ENABLED: process.env.NEXT_PUBLIC_DEV_TOOLS_ENABLED, NEXT_PUBLIC_IS_DEMO: process.env.NEXT_PUBLIC_IS_DEMO, NEXT_PUBLIC_NODE_ENV: process.env.NODE_ENV, }, diff --git a/src/features/account/PageAccount.tsx b/src/features/account/PageAccount.tsx index 377e0c860..a7cca5ef8 100644 --- a/src/features/account/PageAccount.tsx +++ b/src/features/account/PageAccount.tsx @@ -1,4 +1,4 @@ -import React, { useId } from 'react'; +import React from 'react'; import { Alert, @@ -6,22 +6,18 @@ import { Box, Button, Divider, - FormControl, - FormLabel, - HStack, Heading, Link, LinkBox, LinkOverlay, Stack, - Switch, - useColorMode, } from '@chakra-ui/react'; import { useRouter } from 'next/navigation'; import { useTranslation } from 'react-i18next'; import { LuArrowRight, LuLogOut, LuUser } from 'react-icons/lu'; import { ConfirmModal } from '@/components/ConfirmModal'; +import { DarkModeSwitch } from '@/components/DarkModeSwitch'; import { Icon } from '@/components/Icons'; import { AccountDeleteButton } from '@/features/account/AccountDeleteButton'; import { AccountEmailForm } from '@/features/account/AccountEmailForm'; @@ -117,39 +113,3 @@ export default function PageHome() { ); } - -const DarkModeSwitch = () => { - const { t } = useTranslation(['account']); - const { colorMode, setColorMode } = useColorMode(); - const id = useId(); - - return ( - - - - {t('account:preferences.theme.light')} - - setColorMode(e.target.checked ? 'dark' : 'light')} - /> - - {t('account:preferences.theme.dark')} - - - - ); -}; diff --git a/src/features/devtools/AppHint.tsx b/src/features/devtools/AppHint.tsx new file mode 100644 index 000000000..13809e529 --- /dev/null +++ b/src/features/devtools/AppHint.tsx @@ -0,0 +1,82 @@ +import { Box, HStack, Text, useDisclosure } from '@chakra-ui/react'; +import { LuAppWindow, LuPanelLeftOpen, LuPencilRuler } from 'react-icons/lu'; + +import { env } from '@/env.mjs'; +import { DevToolsDrawer } from '@/features/devtools/DevToolsDrawer'; + +export const getEnvHintTitlePrefix = () => { + if (env.NEXT_PUBLIC_ENV_EMOJI) return `${env.NEXT_PUBLIC_ENV_EMOJI} `; + if (env.NEXT_PUBLIC_ENV_NAME) return `[${env.NEXT_PUBLIC_ENV_NAME}] `; + return ''; +}; + +export const AppHint = () => { + if (!env.NEXT_PUBLIC_ENV_NAME && !env.NEXT_PUBLIC_DEV_TOOLS_ENABLED) { + return null; + } + + return ( + + + {env.NEXT_PUBLIC_ENV_NAME && } + {env.NEXT_PUBLIC_DEV_TOOLS_ENABLED && } + + + ); +}; + +const EnvHint = () => { + return ( + + {env.NEXT_PUBLIC_ENV_NAME} + + ); +}; +const DevToolsHint = () => { + const devToolsDrawer = useDisclosure(); + + return ( + <> + + + Dev helper + + + + ); +}; diff --git a/src/features/devtools/DevToolsDrawer.tsx b/src/features/devtools/DevToolsDrawer.tsx new file mode 100644 index 000000000..2467d4485 --- /dev/null +++ b/src/features/devtools/DevToolsDrawer.tsx @@ -0,0 +1,72 @@ +'use client'; + +import { + Checkbox, + Drawer, + DrawerBody, + DrawerCloseButton, + DrawerContent, + DrawerHeader, + FormControl, + FormLabel, + Radio, + RadioGroup, + Stack, + Wrap, + useColorMode, + useDisclosure, +} from '@chakra-ui/react'; +import { useTranslation } from 'react-i18next'; + +import { AVAILABLE_LANGUAGES } from '@/lib/i18n/constants'; + +export const DevToolsDrawer = ({ + disclosure, +}: { + disclosure: ReturnType; +}) => { + const { colorMode, setColorMode } = useColorMode(); + + const { t, i18n } = useTranslation(['common']); + + return ( + + + + Development panel + + + + setColorMode(e.target.checked ? 'dark' : 'light') + } + > + Dark mode + + + Language + i18n.changeLanguage(newValue)} + > + + {AVAILABLE_LANGUAGES.map((language) => ( + + {t(`common:languages.${language.key}`)} + + ))} + + + + + + + + ); +}; diff --git a/src/features/devtools/EnvHint.tsx b/src/features/devtools/EnvHint.tsx deleted file mode 100644 index f365bb4c5..000000000 --- a/src/features/devtools/EnvHint.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Box, Text } from '@chakra-ui/react'; - -import { env } from '@/env.mjs'; - -export const getEnvHintTitlePrefix = () => { - if (env.NEXT_PUBLIC_ENV_EMOJI) return `${env.NEXT_PUBLIC_ENV_EMOJI} `; - if (env.NEXT_PUBLIC_ENV_NAME) return `[${env.NEXT_PUBLIC_ENV_NAME}] `; - return ''; -}; - -export const EnvHint = () => { - if (!env.NEXT_PUBLIC_ENV_NAME) { - return null; - } - - return ( - - - {env.NEXT_PUBLIC_ENV_NAME} - - - ); -};