Replace own theme solution with next-themes

This commit is contained in:
Steve Ruiz 2021-07-14 09:04:07 +01:00
parent d92b9ecadb
commit 03326adbaf
15 changed files with 95 additions and 82 deletions

View file

@ -1,5 +1,5 @@
import * as Sentry from '@sentry/node'
import React, { useRef } from 'react'
import React, { useEffect, useRef } from 'react'
import { ErrorBoundary } from 'react-error-boundary'
import state, { useSelector } from 'state'
@ -33,23 +33,28 @@ export default function Canvas(): JSX.Element {
const events = useCanvasEvents(rCanvas)
const isSettingCamera = useSelector((s) => s.isIn('settingCamera'))
const isReady = useSelector((s) => s.isIn('ready'))
useEffect(() => {
if (isSettingCamera) {
state.send('MOUNTED_SHAPES')
}
}, [isSettingCamera])
return (
<ContextMenu>
<MainSVG ref={rCanvas} {...events}>
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={resetError}>
<Defs />
{isReady && (
<g ref={rGroup} id="shapes">
<BoundsBg />
<Page />
<Coop />
<Bounds />
<Handles />
<Brush />
</g>
)}
<g ref={rGroup} id="shapes" opacity={isReady ? 1 : 0}>
<BoundsBg />
<Page />
<Coop />
<Bounds />
<Handles />
<Brush />
</g>
</ErrorBoundary>
</MainSVG>
</ContextMenu>

View file

@ -1,5 +1,5 @@
import Editor, { Monaco } from '@monaco-editor/react'
import useTheme from 'hooks/useTheme'
import { useTheme } from 'next-themes'
import libImport from './es5-lib'
import typesImport from './types-import'
import React, { useCallback, useEffect, useRef } from 'react'

View file

@ -1,5 +1,6 @@
import useKeyboardEvents from 'hooks/useKeyboardEvents'
import useLoadOnMount from 'hooks/useLoadOnMount'
import useStateTheme from 'hooks/useStateTheme'
import Menu from './menu/menu'
import Canvas from './canvas/canvas'
import ToolsPanel from './tools-panel/tools-panel'
@ -13,6 +14,7 @@ import ControlsPanel from './controls-panel/controls-panel'
export default function Editor({ roomId }: { roomId?: string }): JSX.Element {
useKeyboardEvents()
useLoadOnMount(roomId)
useStateTheme()
return (
<Layout>

View file

@ -18,11 +18,11 @@ import {
import state, { useSelector } from 'state'
import { commandKey } from 'utils'
import { signOut } from 'next-auth/client'
import { useTheme } from 'next-themes'
const handleNew = () => state.send('CREATED_NEW_PROJECT')
const handleSave = () => state.send('SAVED')
const handleLoad = () => state.send('LOADED_FROM_FILE_STSTEM')
const toggleDarkMode = () => state.send('TOGGLED_DARK_MODE')
const toggleDebugMode = () => state.send('TOGGLED_DEBUG_MODE')
function Menu() {
@ -99,14 +99,16 @@ function RecentFiles() {
}
function Preferences() {
const { theme, setTheme } = useTheme()
const isDebugMode = useSelector((s) => s.data.settings.isDebugMode)
const isDarkMode = useSelector((s) => s.data.settings.isDarkMode)
const isDarkMode = theme === 'dark'
return (
<DropdownMenuSubMenu label="Preferences">
<DropdownMenuCheckboxItem
checked={isDarkMode}
onCheckedChange={toggleDarkMode}
onCheckedChange={() => setTheme(isDarkMode ? 'light' : 'dark')}
>
<span>Dark Mode</span>
</DropdownMenuCheckboxItem>

View file

@ -4,7 +4,7 @@ import Tooltip from 'components/tooltip'
import { strokes } from 'state/shape-styles'
import state, { useSelector } from 'state'
import { BoxIcon, Item, DropdownContent } from '../shared'
import useTheme from 'hooks/useTheme'
import { useTheme } from 'next-themes'
import { ColorStyle } from 'types'
function handleColorChange(color: ColorStyle): void {

View file

@ -115,19 +115,21 @@ export default function useCanvasEvents(
rCanvas.current.addEventListener('touchstart', preventNavigation)
return () => {
rCanvas.current.removeEventListener(
'gestureend',
preventGestureNavigation
)
rCanvas.current.removeEventListener(
'gesturechange',
preventGestureNavigation
)
rCanvas.current.removeEventListener(
'gesturestart',
preventGestureNavigation
)
rCanvas.current.removeEventListener('touchstart', preventNavigation)
if (rCanvas.current) {
rCanvas.current.removeEventListener(
'gestureend',
preventGestureNavigation
)
rCanvas.current.removeEventListener(
'gesturechange',
preventGestureNavigation
)
rCanvas.current.removeEventListener(
'gesturestart',
preventGestureNavigation
)
rCanvas.current.removeEventListener('touchstart', preventNavigation)
}
}
}, [])

11
hooks/useStateTheme.ts Normal file
View file

@ -0,0 +1,11 @@
import { useTheme } from 'next-themes'
import { useEffect } from 'react'
import state from 'state'
export default function useStateTheme(): void {
const { theme } = useTheme()
useEffect(() => {
state.send('CHANGED_DARK_MODE', { isDarkMode: theme === 'dark' })
}, [theme])
}

View file

@ -1,14 +0,0 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { useCallback } from 'react'
import state, { useSelector } from 'state'
import { Theme } from 'types'
export default function useTheme() {
const theme: Theme = useSelector((state) =>
state.data.settings.isDarkMode ? 'dark' : 'light'
)
const toggleTheme = useCallback(() => state.send('TOGGLED_THEME'), [])
return { theme, toggleTheme }
}

View file

@ -57,6 +57,7 @@
"next": "^11.0.1",
"next-auth": "^3.27.3",
"next-pwa": "^5.2.23",
"next-themes": "^0.0.15",
"perfect-freehand": "^0.4.91",
"react": "^17.0.2",
"react-dom": "^17.0.2",

View file

@ -1,10 +1,11 @@
import useGtag from 'hooks/useGtag'
import Head from 'next/head'
import { AppProps } from 'next/app'
import { globalStyles } from 'styles'
import { globalStyles, dark, light } from 'styles'
import { Provider } from 'next-auth/client'
import { init } from 'utils/sentry'
import 'styles/globals.css'
import { ThemeProvider } from 'next-themes'
init()
@ -22,9 +23,16 @@ function MyApp({ Component, pageProps }: AppProps): JSX.Element {
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, user-scalable=no, viewport-fit=cover"
/>
</Head>
<Provider session={pageProps.session}>
<Component {...pageProps} />
</Provider>
<ThemeProvider
disableTransitionOnChange
attribute="class"
value={{ light: light.toString(), dark: dark.toString() }}
defaultTheme="light"
>
<Provider session={pageProps.session}>
<Component {...pageProps} />
</Provider>
</ThemeProvider>
</>
)
}

View file

@ -5,7 +5,7 @@ import NextDocument, {
NextScript,
DocumentContext,
} from 'next/document'
import { dark, getCssString } from 'styles'
import { getCssString } from 'styles'
import { GA_TRACKING_ID } from 'utils/gtag'
class MyDocument extends NextDocument {
@ -90,7 +90,7 @@ class MyDocument extends NextDocument {
}}
/>
</Head>
<body className={dark}>
<body>
<Main />
<NextScript />
</body>

View file

@ -8,7 +8,6 @@ import storage from './storage'
import session from './session'
import clipboard from './clipboard'
import commands from './commands'
import { dark, light } from 'styles'
import {
vec,
getCommonBounds,
@ -47,8 +46,8 @@ const initialData: Data = {
settings: {
fontSize: 13,
isTestMode: false,
isDarkMode: true,
isCodeOpen: false,
isDarkMode: false,
isDebugMode: false,
isDebugOpen: false,
isStyleOpen: false,
@ -148,8 +147,8 @@ for (let i = 0; i < count; i++) {
const state = createState({
data: initialData,
onEnter: 'applyTheme',
on: {
CHANGED_DARK_MODE: 'setDarkMode',
TOGGLED_DEBUG_PANEL: 'toggleDebugPanel',
TOGGLED_DEBUG_MODE: 'toggleDebugMode',
TOGGLED_TEST_MODE: 'toggleTestMode',
@ -168,20 +167,23 @@ const state = createState({
'resetHistory',
'resetStorage',
'restoredPreviousDocument',
{ to: 'settingCamera' },
],
},
},
settingCamera: {
on: {
MOUNTED_SHAPES: [
{
if: 'hasSelection',
do: 'zoomCameraToSelectionActual',
else: 'zoomCameraToFit',
},
{ to: 'ready' },
],
},
},
ready: {
onEnter: [
'applyTheme',
{
wait: 0.01,
if: 'hasSelection',
do: 'zoomCameraToSelectionActual',
else: ['zoomCameraToActual'],
},
],
on: {
UNMOUNTED: {
do: ['saveDocumentState', 'resetDocumentState'],
@ -214,9 +216,6 @@ const state = createState({
unlessAny: ['isReadOnly', 'isInSession'],
do: 'pasteShapesFromClipboard',
},
TOGGLED_DARK_MODE: {
do: ['toggleDarkMode', 'applyTheme'],
},
TOGGLED_SHAPE_LOCK: {
unlessAny: ['isReadOnly', 'isInSession'],
if: 'hasSelection',
@ -1290,6 +1289,10 @@ const state = createState({
},
},
actions: {
setDarkMode(data, payload: { isDarkMode: boolean }) {
data.settings.isDarkMode = payload.isDarkMode
},
/* ---------------------- Debug --------------------- */
closeDebugPanel(data) {
@ -2041,21 +2044,6 @@ const state = createState({
history.reset()
},
/* ------------------- Preferences ------------------ */
toggleDarkMode(data) {
data.settings.isDarkMode = !data.settings.isDarkMode
},
applyTheme(data) {
if (data.settings.isDarkMode && typeof document !== 'undefined') {
document.body.classList.remove(light)
document.body.classList.add(dark)
} else {
document.body.classList.remove(dark)
document.body.classList.add(light)
}
},
/* --------------------- Styles --------------------- */
toggleStylePanel(data) {

View file

@ -30,10 +30,13 @@ class Storage {
data.document.id = roomId ? roomId : uniqueId()
} else {
// If we did find a state and document, load it into state.
const restoredDocument: Data = JSON.parse(decompress(savedState))
const restoredState: Data = JSON.parse(decompress(savedState))
// Lose the settings, these are meant to be stable
delete restoredState.settings
// Merge restored data into state.
Object.assign(data, restoredDocument)
Object.assign(data, restoredState)
}
}

View file

@ -6,12 +6,12 @@ export interface Data {
isReadOnly: boolean
settings: {
fontSize: number
isDarkMode: boolean
isCodeOpen: boolean
isTestMode: boolean
isDebugOpen: boolean
isDebugMode: boolean
isStyleOpen: boolean
isDarkMode: boolean
nudgeDistanceSmall: number
nudgeDistanceLarge: number
isToolLocked: boolean

View file

@ -5984,6 +5984,11 @@ next-pwa@^5.2.23:
workbox-webpack-plugin "^6.1.5"
workbox-window "^6.1.5"
next-themes@^0.0.15:
version "0.0.15"
resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.15.tgz#ab0cee69cd763b77d41211f631e108beab39bf7d"
integrity sha512-LTmtqYi03c4gMTJmWwVK9XkHL7h0/+XrtR970Ujvtu3s0kZNeJN24aJsi4rkZOI8i19+qq6f8j+8Duwy5jqcrQ==
next@^11.0.1:
version "11.0.1"
resolved "https://registry.yarnpkg.com/next/-/next-11.0.1.tgz#b8e3914d153aaf7143cb98c09bcd3c8230eeb17a"