diff --git a/.eslintrc.json b/.eslintrc.json index 1f2f0f9e9..a8df5b229 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,52 +1,53 @@ { - "root": true, - "extends": [ - "plugin:react/recommended", - "plugin:@typescript-eslint/eslint-recommended", - "prettier" - ], - "parser": "@typescript-eslint/parser", - "plugins": ["react", "@typescript-eslint", "react-hooks"], - "env": { - "browser": true, - "es6": true, - "node": true - }, - "globals": { - "Atomics": "readonly", - "SharedArrayBuffer": "readonly" - }, - "parserOptions": { - "ecmaFeatures": { - "jsx": true - }, - "ecmaVersion": 2018, - "sourceType": "module" - }, - "rules": { - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": ["warn"], - "no-restricted-imports": [ - "error", + "extends": "next" + // "root": true, + // "extends": [ + // "plugin:react/recommended", + // "plugin:@typescript-eslint/eslint-recommended", + // "prettier" + // ], + // "parser": "@typescript-eslint/parser", + // "plugins": ["react", "@typescript-eslint", "react-hooks"], + // "env": { + // "browser": true, + // "es6": true, + // "node": true + // }, + // "globals": { + // "Atomics": "readonly", + // "SharedArrayBuffer": "readonly" + // }, + // "parserOptions": { + // "ecmaFeatures": { + // "jsx": true + // }, + // "ecmaVersion": 2018, + // "sourceType": "module" + // }, + // "rules": { + // "no-unused-vars": "off", + // "@typescript-eslint/no-unused-vars": ["warn"], + // "no-restricted-imports": [ + // "error", - { "name": "lodash", "message": "Use lodash/myFunction instead" } - ], - "react/prop-types": 0, - "react-hooks/rules-of-hooks": "error", - "react/display-name": 0, - // "react-hooks/exhaustive-deps": "warn", - "prefer-template": "error", - "react/self-closing-comp": [ - "warn", - { - "component": true, - "html": true - } - ] - }, - "settings": { - "react": { - "version": "detect" - } - } + // { "name": "lodash", "message": "Use lodash/myFunction instead" } + // ], + // "react/prop-types": 0, + // "react-hooks/rules-of-hooks": "error", + // "react/display-name": 0, + // // "react-hooks/exhaustive-deps": "warn", + // "prefer-template": "error", + // "react/self-closing-comp": [ + // "warn", + // { + // "component": true, + // "html": true + // } + // ] + // }, + // "settings": { + // "react": { + // "version": "detect" + // } + // } } diff --git a/app/ThemeRegistry.tsx b/app/ThemeRegistry.tsx new file mode 100644 index 000000000..db5e842c7 --- /dev/null +++ b/app/ThemeRegistry.tsx @@ -0,0 +1,75 @@ +"use client"; +import createCache from "@emotion/cache"; +import { CacheProvider } from "@emotion/react"; +import CssBaseline from "@mui/material/CssBaseline"; +import { ThemeProvider } from "@mui/material/styles"; +import { useServerInsertedHTML } from "next/navigation"; +import React, { useContext } from "react"; +import { SettingsContext } from "../lib/contexts/SettingsContext/SettingsContext"; +import { AppDarkTheme, AppLightTheme } from "../lib/theme"; + +// This implementation is from emotion-js +// https://github.com/emotion-js/emotion/issues/2928#issuecomment-1319747902 +export default function ThemeRegistry(props: { + options: Parameters[0]; + children: React.ReactNode; +}) { + const settingsManager = useContext(SettingsContext); + + const { options, children } = props; + + const [{ cache, flush }] = React.useState(() => { + const cache = createCache(options); + cache.compat = true; + const prevInsert = cache.insert; + let inserted: string[] = []; + cache.insert = (...args) => { + const serialized = args[1]; + if (cache.inserted[serialized.name] === undefined) { + inserted.push(serialized.name); + } + return prevInsert(...args); + }; + const flush = () => { + const prevInserted = inserted; + inserted = []; + return prevInserted; + }; + return { cache, flush }; + }); + + useServerInsertedHTML(() => { + const names = flush(); + if (names.length === 0) { + return null; + } + let styles = ""; + for (const name of names) { + styles += cache.inserted[name]; + } + return ( + - -
-
- Loading Fari -
-
- - - - - - diff --git a/lib/App.tsx b/lib/App.tsx index 7f1e99058..957fd7c20 100644 --- a/lib/App.tsx +++ b/lib/App.tsx @@ -1,19 +1,15 @@ -import { - CssBaseline, - StyledEngineProvider, - ThemeProvider, -} from "@mui/material"; +"use client"; + import * as Sentry from "@sentry/react"; -import React, { ReactNode, useContext } from "react"; +import { ReactNode, useContext } from "react"; import { DndProvider } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; -import { Helmet, HelmetProvider } from "react-helmet-async"; -import { BrowserRouter, useNavigate } from "react-router-dom"; -import { AppRouter } from "./components/AppRouter/AppRouter"; + +import { useRouter } from "next/navigation"; +import ThemeRegistry from "../app/ThemeRegistry"; import { previewContentEditable } from "./components/ContentEditable/ContentEditable"; import { ErrorReport } from "./components/ErrorBoundary/ErrorReport"; import { IManagerViewModel, MyBinder } from "./components/MyBinder/MyBinder"; -import { env } from "./constants/env"; import { CharactersContext, useCharacters, @@ -47,58 +43,37 @@ import { SceneFactory } from "./domains/scene/SceneFactory"; import { IScene } from "./hooks/useScene/IScene"; import { useTranslate } from "./hooks/useTranslate/useTranslate"; import { getDefaultInjections } from "./services/injections"; -import { AppDarkTheme, AppLightTheme } from "./theme"; const injections = getDefaultInjections(); -export function App() { - return ( - - - - ); -} - -function AppContexts(props: { children: ReactNode }) { +export function AppProviders(props: { children: ReactNode }) { const settingsManager = useSettings(); const charactersManager = useCharacters(); const scenesManager = useScenes(); const indexCardCollectionsManager = useIndexCardCollections(); - const diceManager = useDice({ - // defaultCommands: settingsManager.state.diceCommandIds, - // defaultOptions: settingsManager.state.diceOptions, - // onCommandSetsChange(commandSetOptions) { - // const commandSetIds = commandSetOptions.map((l) => l.id); - // settingsManager.actions.setDiceCommandsIds(commandSetIds); - // }, - // onOptionsChange: (options) => { - // settingsManager.actions.setDiceOptions(options); - // }, - }); + const diceManager = useDice({}); const myBinderManager = useMyBinder(); return ( - - - - - - - - - - {props.children} - - - - - - - - - + + + + + + + + + {props.children} + + + + + + + + ); } @@ -107,7 +82,7 @@ function MyBinderManager() { const charactersManager = useContext(CharactersContext); const indexCardCollectionsManager = useContext(IndexCardCollectionsContext); const myBinderManager = useContext(MyBinderContext); - const navigate = useNavigate(); + const router = useRouter(); type IHandlers = { onSelect(element: IManagerViewModel): void; @@ -168,7 +143,7 @@ function MyBinderManager() { if (myBinderManager.state.managerCallback.current) { myBinderManager.state.managerCallback.current(newCharacter); } else { - navigate(`/characters/${newCharacter.id}?advanced=true`); + router.push(`/characters/${newCharacter.id}?advanced=true`); } myBinderManager.actions.close(); }, @@ -176,7 +151,7 @@ function MyBinderManager() { if (myBinderManager.state.managerCallback.current) { myBinderManager.state.managerCallback.current(element.original); } else { - navigate(`/characters/${element.id}`); + router.push(`/characters/${element.id}`); } myBinderManager.actions.close(); }, @@ -193,9 +168,8 @@ function MyBinderManager() { charactersManager.actions.upsert(element.original); }, async onImport(importPaths) { - const { entity, exists } = await charactersManager.actions.importEntity( - importPaths, - ); + const { entity, exists } = + await charactersManager.actions.importEntity(importPaths); if (!exists) { charactersManager.actions.upsert(entity); @@ -227,7 +201,7 @@ function MyBinderManager() { if (myBinderManager.state.managerCallback.current) { myBinderManager.state.managerCallback.current(newScene); } else { - navigate(`/scenes/${newScene.id}`); + router.push(`/scenes/${newScene.id}`); } myBinderManager.actions.close(); }, @@ -235,7 +209,7 @@ function MyBinderManager() { if (myBinderManager.state.managerCallback.current) { myBinderManager.state.managerCallback.current(element.original); } else { - navigate(`/scenes/${element.id}`); + router.push(`/scenes/${element.id}`); } myBinderManager.actions.close(); }, @@ -252,9 +226,8 @@ function MyBinderManager() { scenesManager.actions.upsert(element.original); }, async onImport(importPaths) { - const { entity, exists } = await scenesManager.actions.importEntity( - importPaths, - ); + const { entity, exists } = + await scenesManager.actions.importEntity(importPaths); if (!exists) { scenesManager.actions.upsert(entity); @@ -284,7 +257,7 @@ function MyBinderManager() { if (myBinderManager.state.managerCallback.current) { myBinderManager.state.managerCallback.current(newEntity); } else { - navigate(`/cards/${newEntity.id}`); + router.push(`/cards/${newEntity.id}`); } myBinderManager.actions.close(); }, @@ -292,7 +265,7 @@ function MyBinderManager() { if (myBinderManager.state.managerCallback.current) { myBinderManager.state.managerCallback.current(element.original); } else { - navigate(`/cards/${element.id}`); + router.push(`/cards/${element.id}`); } myBinderManager.actions.close(); }, @@ -387,46 +360,23 @@ function MyBinderManager() { ); } -function AppProviders(props: { children: ReactNode }) { - const settingsManager = useContext(SettingsContext); - +function InternalProviders(props: { children: ReactNode }) { return ( - - - - - - - } - showDialog - > - - - - - {props.children} - - - - - + + + + + } + showDialog + > + + {props.children} + + ); } -AppProviders.displayName = "AppProvider"; /** * for dynamic keys diff --git a/lib/components/AppLink/AppLink.tsx b/lib/components/AppLink/AppLink.tsx index c067676c1..444bbdca2 100644 --- a/lib/components/AppLink/AppLink.tsx +++ b/lib/components/AppLink/AppLink.tsx @@ -5,22 +5,12 @@ import { Link as MaterialUILink, useTheme, } from "@mui/material"; +import NextJSLink, { LinkProps as NextJSLinkProps } from "next/link"; import React from "react"; -import { - Link as ReactRouterLink, - LinkProps as ReactRouterLinkProps, -} from "react-router-dom"; - -type IProps = { - to?: string; - onClick?(event: React.MouseEvent): void; -}; -export const AppLink: React.FC< - Omit & Omit & IProps -> = (props) => { - const { to = "", onClick, sx, ...rest } = props; - const isInternal = to.startsWith("/"); +export const AppLink: React.FC = (props) => { + const { href = "", onClick, sx, ...rest } = props; + const isInternal = href?.startsWith("/"); const theme = useTheme(); const style = { @@ -38,8 +28,8 @@ export const AppLink: React.FC< if (isInternal) { return ( ) => { if (onClick) { event.preventDefault(); @@ -58,7 +48,7 @@ export const AppLink: React.FC< return ( & NextJSLinkProps >((props, ref) => { - const isInternal = (props.to as string).startsWith("/"); + const isInternal = (props.href as string)?.startsWith("/"); if (isInternal) { return ( @@ -99,10 +89,10 @@ export const AppButtonLink = React.forwardRef< return ( @@ -110,4 +100,4 @@ export const AppButtonLink = React.forwardRef< }); export const MUILink = MaterialUILink; -export const RouterLink = ReactRouterLink; +export const RouterLink = NextJSLink; diff --git a/lib/components/AppRouter/AppRouter.tsx b/lib/components/AppRouter/AppRouter.tsx index 7903ed228..6ce72b338 100644 --- a/lib/components/AppRouter/AppRouter.tsx +++ b/lib/components/AppRouter/AppRouter.tsx @@ -1,237 +1,237 @@ -import { LiveObject } from "@liveblocks/client"; -import React, { useContext } from "react"; -import { Route, Routes, useLocation, useParams } from "react-router-dom"; -import { SettingsContext } from "../../contexts/SettingsContext/SettingsContext"; -import { StoryBuilderRoute } from "../../routes/StoryBuilder/StoryBuilderRoute"; -import StoryDiceRoute from "../../routes/StoryDice/StoryDiceRoute"; -import { RoomProvider } from "../../services/liveblocks/liveblocks.config"; -import { ExternalRedirect } from "../ExternalRedirect/ExternalRedirect"; -import { LoadingRoute } from "./LoadingRoute"; +// import { LiveObject } from "@liveblocks/client"; +// import React, { useContext } from "react"; +// import { Route, Routes, useLocation, useParams } from "react-router-dom"; +// import { SettingsContext } from "../../contexts/SettingsContext/SettingsContext"; +// import { StoryBuilderRoute } from "../../routes/StoryBuilder/StoryBuilderRoute"; +// import StoryDiceRoute from "../../routes/StoryDice/StoryDiceRoute"; +// import { RoomProvider } from "../../services/liveblocks/liveblocks.config"; +// import { ExternalRedirect } from "../ExternalRedirect/ExternalRedirect"; +// import { LoadingRoute } from "./LoadingRoute"; -const HomeRoute = React.lazy(() => import("../../routes/Home/HomeRoute")); +// const HomeRoute = React.lazy(() => import("../../routes/Home/HomeRoute")); -const CharacterRoute = React.lazy( - () => import("../../routes/Character/CharacterRoute"), -); -const NewCharacterRoute = React.lazy( - () => import("../../routes/NewCharacter/NewCharacterRoute"), -); -const CharacterPrintRoute = React.lazy( - () => import("../../routes/CharacterPrint/CharacterPrintRoute"), -); -const DiceRoute = React.lazy(() => import("../../routes/DiceRoute/DiceRoute")); -const FeatureRequestsRoute = React.lazy( - () => import("../../routes/FeatureRequests/FeatureRequestsRoute"), -); -const BugsRoute = React.lazy(() => import("../../routes/Bugs/BugsRoute")); -const DataRoute = React.lazy(() => import("../../routes/Data/DataRoute")); -const DrawRoute = React.lazy(() => import("../../routes/Draw/DrawRoute")); -const NotFoundRoute = React.lazy( - () => import("../../routes/NotFound/NotFoundRoute"), -); -const PlayOfflineRoute = React.lazy( - () => import("../../routes/Play/PlayOfflineRoute"), -); -const PlayRoute = React.lazy(() => import("../../routes/Play/PlayRoute")); -const JoinAGameRoute = React.lazy( - () => import("../../routes/Play/JoinAGameRoute"), -); -const SceneRoute = React.lazy(() => import("../../routes/Scene/SceneRoute")); -const CardCollection = React.lazy( - () => import("../../routes/CardCollection/CardCollectionRoute"), -); -const OracleRoute = React.lazy(() => import("../../routes/Oracle/OracleRoute")); +// const CharacterRoute = React.lazy( +// () => import("../../routes/Character/CharacterRoute"), +// ); +// const NewCharacterRoute = React.lazy( +// () => import("../../routes/NewCharacter/NewCharacterRoute"), +// ); +// const CharacterPrintRoute = React.lazy( +// () => import("../../routes/CharacterPrint/CharacterPrintRoute"), +// ); +// const DiceRoute = React.lazy(() => import("../../routes/DiceRoute/DiceRoute")); +// const FeatureRequestsRoute = React.lazy( +// () => import("../../routes/FeatureRequests/FeatureRequestsRoute"), +// ); +// const BugsRoute = React.lazy(() => import("../../routes/Bugs/BugsRoute")); +// const DataRoute = React.lazy(() => import("../../routes/Data/DataRoute")); +// const DrawRoute = React.lazy(() => import("../../routes/Draw/DrawRoute")); +// const NotFoundRoute = React.lazy( +// () => import("../../routes/NotFound/NotFoundRoute"), +// ); +// const PlayOfflineRoute = React.lazy( +// () => import("../../routes/Play/PlayOfflineRoute"), +// ); +// const PlayRoute = React.lazy(() => import("../../routes/Play/PlayRoute")); +// const JoinAGameRoute = React.lazy( +// () => import("../../routes/Play/JoinAGameRoute"), +// ); +// const SceneRoute = React.lazy(() => import("../../routes/Scene/SceneRoute")); +// const CardCollection = React.lazy( +// () => import("../../routes/CardCollection/CardCollectionRoute"), +// ); +// const OracleRoute = React.lazy(() => import("../../routes/Oracle/OracleRoute")); -const initialStorage = { - scene: new LiveObject(), - characters: new LiveObject(), - session: new LiveObject(), - chat: new LiveObject(), -}; +// const initialStorage = { +// scene: new LiveObject(), +// characters: new LiveObject(), +// session: new LiveObject(), +// chat: new LiveObject(), +// }; -export const AppRouter = () => { - const location = useLocation(); - const settingsManager = useContext(SettingsContext); - const userId = settingsManager.state.userId; +// export const AppRouter = () => { +// const location = useLocation(); +// const settingsManager = useContext(SettingsContext); +// const userId = settingsManager.state.userId; - return ( - }> - - } /> - } - /> - } /> - } - /> - } /> - } /> - } /> - } /> - { - const sessionId = params.id || userId; - return ( - - - - ); - }} - /> - } - /> - ; - { - const sessionId = params.id || userId; - return ( - - - - ); - }} - /> - } - /> - ; - { - const sessionId = params.id || userId; - return ( - - - - ); - }} - /> - } - /> - } /> - } /> - } /> - - } - /> - - } - /> - - } - /> - - } - /> - - } - /> - - } - /> - - } - /> - - } - /> - - } - /> - - } - /> - } - /> - } /> - } - /> - } /> - } /> - } /> - } /> - } /> - - - ); -}; +// return ( +// }> +// +// } /> +// } +// /> +// } /> +// } +// /> +// } /> +// } /> +// } /> +// } /> +// { +// const sessionId = params.id || userId; +// return ( +// +// +// +// ); +// }} +// /> +// } +// /> +// ; +// { +// const sessionId = params.id || userId; +// return ( +// +// +// +// ); +// }} +// /> +// } +// /> +// ; +// { +// const sessionId = params.id || userId; +// return ( +// +// +// +// ); +// }} +// /> +// } +// /> +// } /> +// } /> +// } /> +// +// } +// /> +// +// } +// /> +// +// } +// /> +// +// } +// /> +// +// } +// /> +// +// } +// /> +// +// } +// /> +// +// } +// /> +// +// } +// /> +// +// } +// /> +// } +// /> +// } /> +// } +// /> +// } /> +// } /> +// } /> +// } /> +// } /> +// +// +// ); +// }; -function Params(props: { render: (params: any) => JSX.Element }) { - const params = useParams(); - return props.render(params); -} +// function Params(props: { render: (params: any) => JSX.Element }) { +// const params = useParams(); +// return props.render(params); +// } diff --git a/lib/components/ColorPicker/ColorPicker.tsx b/lib/components/ColorPicker/ColorPicker.tsx index 1bbf07bbe..00821f2e9 100644 --- a/lib/components/ColorPicker/ColorPicker.tsx +++ b/lib/components/ColorPicker/ColorPicker.tsx @@ -37,4 +37,3 @@ export const ColorPicker: React.FC<{ /> ); }; -ColorPicker.displayName = "ColorPicker"; diff --git a/lib/components/ContentEditable/ContentEditable.tsx b/lib/components/ContentEditable/ContentEditable.tsx index 7d3acb82f..ab9bb04c1 100644 --- a/lib/components/ContentEditable/ContentEditable.tsx +++ b/lib/components/ContentEditable/ContentEditable.tsx @@ -199,4 +199,3 @@ export const ContentEditable: React.FC< ); }; -ContentEditable.displayName = "ContentEditable"; diff --git a/lib/components/CookieConsent/CookieConsent.tsx b/lib/components/CookieConsent/CookieConsent.tsx index 64a90fe80..5dde3fd22 100644 --- a/lib/components/CookieConsent/CookieConsent.tsx +++ b/lib/components/CookieConsent/CookieConsent.tsx @@ -54,5 +54,3 @@ export const CookieConsent: React.FC = () => { /> ); }; - -CookieConsent.displayName = "CookieConsent"; diff --git a/lib/components/DevTool/DevTool.tsx b/lib/components/DevTool/DevTool.tsx index 797e8e928..9449c49ff 100644 --- a/lib/components/DevTool/DevTool.tsx +++ b/lib/components/DevTool/DevTool.tsx @@ -18,4 +18,3 @@ export const DevTool: React.FC<{ ); }; -DevTool.displayName = "DevTool"; diff --git a/lib/components/FateLabel/FateLabel.tsx b/lib/components/FateLabel/FateLabel.tsx index 817bb9e1f..c83acb889 100644 --- a/lib/components/FateLabel/FateLabel.tsx +++ b/lib/components/FateLabel/FateLabel.tsx @@ -30,4 +30,3 @@ export const FateLabel: React.FC< ); }; -FateLabel.displayName = "FateLabel"; diff --git a/lib/components/MyBinder/MyBinder.tsx b/lib/components/MyBinder/MyBinder.tsx index 3759e0b24..df4591e1c 100644 --- a/lib/components/MyBinder/MyBinder.tsx +++ b/lib/components/MyBinder/MyBinder.tsx @@ -35,7 +35,8 @@ import { useTheme, } from "@mui/material"; import React, { useEffect, useState } from "react"; -import { useNavigate } from "react-router"; + +import { useRouter } from "next/navigation"; import { useLogger } from "../../contexts/InjectionsContext/hooks/useLogger"; import { arraySort } from "../../domains/array/arraySort"; import { LazyState, useLazyState } from "../../hooks/useLazyState/useLazyState"; @@ -88,7 +89,7 @@ export function MyBinder(props: { const { t } = useTranslate(); const logger = useLogger(); const theme = useTheme(); - const navigate = useNavigate(); + const router = useRouter(); const searchInputRef = React.useRef(null); const [search, setSearch] = useState(props.search); const [folder, setFolder] = useLazyState({ @@ -397,7 +398,7 @@ export function MyBinder(props: { { - navigate("/data"); + router.push("/data"); props.onClose(); }} > diff --git a/lib/components/Page/NavLink.tsx b/lib/components/Page/NavLink.tsx index ec20bea29..5df6256ef 100644 --- a/lib/components/Page/NavLink.tsx +++ b/lib/components/Page/NavLink.tsx @@ -12,10 +12,10 @@ import { useTheme, } from "@mui/material"; import React, { useState } from "react"; -import { ReactRouterLink } from "../ReactRouterLink/ReactRouterLink"; +import { RouterLink } from "../AppLink/AppLink"; export function NavLink(props: { - to?: string | { pathname: string }; + href?: string; target?: "_blank"; tooltip?: string; onClick?: () => void; @@ -25,13 +25,13 @@ export function NavLink(props: { endIcon?: React.ReactNode; children: React.ReactNode; }) { - if (props.to) { + if (props.href) { return ( @@ -537,7 +536,7 @@ export const HomeRoute: React.FC<{}> = () => { size="large" sx={{ height: "3rem" }} onClick={() => { - navigate("/play"); + router.push("/play"); logger.track("home.start_online_game"); }} > @@ -553,7 +552,7 @@ export const HomeRoute: React.FC<{}> = () => { data-cy="home.play-offline" sx={{ height: "3rem" }} onClick={() => { - navigate("/play-offline"); + router.push("/play-offline"); logger.track("home.start_offline_game"); }} > @@ -597,9 +596,6 @@ export const HomeRoute: React.FC<{}> = () => { } }; -HomeRoute.displayName = "HomeRoute"; -export default HomeRoute; - type ILightBoxProps = { children: JSX.Element; title?: JSX.Element | string; @@ -806,8 +802,8 @@ function HomeRouteCards(props: { cards: Array }) { color="secondary" variant="outlined" size="large" - component={AppButtonLink} - to={card.to} + LinkComponent={AppButtonLink} + href={card.to} > {card.ctaLabel} diff --git a/lib/routes/NewCharacter/NewCharacterRoute.tsx b/lib/routes/NewCharacter/NewCharacterRoute.tsx index b9634317a..f2eb21b59 100644 --- a/lib/routes/NewCharacter/NewCharacterRoute.tsx +++ b/lib/routes/NewCharacter/NewCharacterRoute.tsx @@ -15,7 +15,7 @@ import { } from "@mui/material"; import kebabCase from "lodash/kebabCase"; import startCase from "lodash/startCase"; -import React, { useContext, useEffect, useState } from "react"; +import { useContext, useEffect, useState } from "react"; import { useNavigate, useParams } from "react-router"; import { Page } from "../../components/Page/Page"; import { PageMeta } from "../../components/PageMeta/PageMeta"; @@ -186,5 +186,3 @@ export function NewCharacterRoute() { ); } - -export default NewCharacterRoute; diff --git a/lib/routes/NotFound/NotFoundRoute.tsx b/lib/routes/NotFound/NotFoundRoute.tsx index b6ca44196..365240bc2 100644 --- a/lib/routes/NotFound/NotFoundRoute.tsx +++ b/lib/routes/NotFound/NotFoundRoute.tsx @@ -42,6 +42,3 @@ export const NotFoundRoute: React.FC<{}> = () => { ); }; - -NotFoundRoute.displayName = "NotFoundRoute"; -export default NotFoundRoute; diff --git a/lib/routes/Oracle/OracleRoute.tsx b/lib/routes/Oracle/OracleRoute.tsx index 584b0fedd..82812e54c 100644 --- a/lib/routes/Oracle/OracleRoute.tsx +++ b/lib/routes/Oracle/OracleRoute.tsx @@ -10,7 +10,7 @@ import { Toolbar, Typography, } from "@mui/material"; -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { FateLabel } from "../../components/FateLabel/FateLabel"; import { Page } from "../../components/Page/Page"; import { PageMeta } from "../../components/PageMeta/PageMeta"; @@ -64,9 +64,6 @@ export const OracleRoute = () => { ); }; -OracleRoute.displayName = "OracleRoute"; -export default OracleRoute; - export function Oracle() { const { t } = useTranslate(); const theme = useTheme(); diff --git a/lib/routes/Play/JoinAGameRoute.tsx b/lib/routes/Play/JoinAGameRoute.tsx index 8399e349e..08efe66ce 100644 --- a/lib/routes/Play/JoinAGameRoute.tsx +++ b/lib/routes/Play/JoinAGameRoute.tsx @@ -12,13 +12,7 @@ import { Typography, useTheme, } from "@mui/material"; -import { - default as React, - useContext, - useEffect, - useRef, - useState, -} from "react"; +import { useContext, useEffect, useRef, useState } from "react"; import { useNavigate, useParams } from "react-router"; import { AppLink } from "../../components/AppLink/AppLink"; import { Page } from "../../components/Page/Page"; @@ -211,5 +205,3 @@ function JoinAGameRoute() { ); } } - -export default JoinAGameRoute; diff --git a/lib/routes/Play/PlayOfflineRoute.tsx b/lib/routes/Play/PlayOfflineRoute.tsx index fa9b4feca..5a19c05e2 100644 --- a/lib/routes/Play/PlayOfflineRoute.tsx +++ b/lib/routes/Play/PlayOfflineRoute.tsx @@ -53,6 +53,3 @@ export const PlayOfflineRoute: React.FC<{}> = () => { ); }; - -PlayOfflineRoute.displayName = "PlayOfflineRoute"; -export default PlayOfflineRoute; diff --git a/lib/routes/Play/PlayRoute.tsx b/lib/routes/Play/PlayRoute.tsx index db5f5357a..5acaa9fff 100644 --- a/lib/routes/Play/PlayRoute.tsx +++ b/lib/routes/Play/PlayRoute.tsx @@ -1,5 +1,5 @@ import { Alert, Snackbar } from "@mui/material"; -import React, { useContext, useEffect, useMemo, useRef, useState } from "react"; +import { useContext, useEffect, useMemo, useRef, useState } from "react"; import { useLocation, useParams } from "react-router-dom"; import { previewContentEditable } from "../../components/ContentEditable/ContentEditable"; import { PageMeta } from "../../components/PageMeta/PageMeta"; @@ -359,6 +359,3 @@ function PlayRoute() { ); } - -PlayRoute.displayName = "PlayRoute"; -export default PlayRoute; diff --git a/lib/routes/Play/components/Session/Session.tsx b/lib/routes/Play/components/Session/Session.tsx index 2ade8713d..95b9ee431 100644 --- a/lib/routes/Play/components/Session/Session.tsx +++ b/lib/routes/Play/components/Session/Session.tsx @@ -1217,4 +1217,3 @@ export function Session(props: { ); } } -Session.displayName = "Session"; diff --git a/lib/routes/Scene/SceneRoute.tsx b/lib/routes/Scene/SceneRoute.tsx index 57cf09adf..acafc58b1 100644 --- a/lib/routes/Scene/SceneRoute.tsx +++ b/lib/routes/Scene/SceneRoute.tsx @@ -1,5 +1,5 @@ import { Box } from "@mui/material"; -import React, { useContext, useEffect, useState } from "react"; +import { useContext, useEffect, useState } from "react"; import { useNavigate, useParams } from "react-router"; import { previewContentEditable } from "../../components/ContentEditable/ContentEditable"; import { Page } from "../../components/Page/Page"; @@ -77,6 +77,3 @@ function SceneRoute() { ); } - -SceneRoute.displayName = "SceneRoute"; -export default SceneRoute; diff --git a/lib/routes/StoryBuilder/StoryBuilderRoute.tsx b/lib/routes/StoryBuilder/StoryBuilderRoute.tsx index 76be6e6a1..a7f4617ec 100644 --- a/lib/routes/StoryBuilder/StoryBuilderRoute.tsx +++ b/lib/routes/StoryBuilder/StoryBuilderRoute.tsx @@ -1,3 +1,4 @@ +"use client"; import LocalLibraryIcon from "@mui/icons-material/LocalLibrary"; import ReplayIcon from "@mui/icons-material/Replay"; import { @@ -9,12 +10,11 @@ import { lighten, useTheme, } from "@mui/material"; -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { FateLabel } from "../../components/FateLabel/FateLabel"; import { Heading } from "../../components/Heading/Heading"; import { IndexCardColor } from "../../components/IndexCard/IndexCardColor"; import { Page } from "../../components/Page/Page"; -import { PageMeta } from "../../components/PageMeta/PageMeta"; import { Images } from "../../constants/Images"; import { useTextColors } from "../../hooks/useTextColors/useTextColors"; import { useTranslate } from "../../hooks/useTranslate/useTranslate"; @@ -39,11 +39,6 @@ export function StoryBuilderRoute() { return ( - - - <> @@ -47,8 +44,6 @@ export function StoryDiceRoute() { ); } -export default StoryDiceRoute; - export function StoryDice() { const [diceNameAndIcon, setDiceNameAndIcon] = useState< Record diff --git a/lib/services/logger/makeLogger.ts b/lib/services/logger/makeLogger.ts index f4a7ad8df..a37f749fe 100644 --- a/lib/services/logger/makeLogger.ts +++ b/lib/services/logger/makeLogger.ts @@ -18,7 +18,7 @@ export function makeLogger( return { track(event: string, body = {}) { //@ts-ignore - const googleAnalytics = window.gtag; + const googleAnalytics = typeof window !== "undefined" && window.gtag; if (!googleAnalytics) { return; diff --git a/lib/services/sentry/SentryService.ts b/lib/services/sentry/SentryService.ts index 286035466..b42289e9a 100644 --- a/lib/services/sentry/SentryService.ts +++ b/lib/services/sentry/SentryService.ts @@ -3,7 +3,10 @@ import { SeverityLevel } from "@sentry/react"; import { env } from "../../constants/env"; const shouldLog = - !env.isTest && !env.isDev && location.hostname !== "localhost"; + typeof window !== "undefined" && + !env.isTest && + !env.isDev && + location.hostname !== "localhost"; export function makeSentryService() { if (shouldLog) { diff --git a/lib/types/jpg.d.ts b/lib/types/jpg.d.ts deleted file mode 100644 index f187ad222..000000000 --- a/lib/types/jpg.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare module "*.jpg"; -declare module "*.jpeg"; diff --git a/lib/types/png.d.ts b/lib/types/png.d.ts deleted file mode 100644 index 49977505d..000000000 --- a/lib/types/png.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module "*.png"; diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 000000000..4f11a03dc --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/next.config.mjs b/next.config.mjs new file mode 100644 index 000000000..d564f36a7 --- /dev/null +++ b/next.config.mjs @@ -0,0 +1,7 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + output: "export", // Outputs a Single-Page Application (SPA). + // distDir: "./dist", // Changes the build output directory to `./dist/`. +}; + +export default nextConfig; diff --git a/package.json b/package.json index 12e5e0bec..f6af3bcfb 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "scripts": { "ci": "npm install --force && bun run build && bun run validate", - "dev": "bun run vite --open", + "dev": "next dev --turbo", "start": "bun run vite build --sourcemap inline --minify false && bun run vite preview --port 1234", "build": "bun run vite build", "serve:build": "bun run vite preview --port 1234", @@ -60,15 +60,13 @@ "immer": "^10.0.2", "lodash": "^4.17.21", "netlify-cli": "^15.11.0", + "next": "latest", "react": "^18.2.0", "react-color": "^2.19.3", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.2.0", - "react-helmet-async": "^1.3.0", "react-i18next": "^13.0.3", - "react-router": "^6.14.2", - "react-router-dom": "^6.14.2", "uuid": "^9.0.0", "vitest": "^0.34.4" }, @@ -110,8 +108,7 @@ "react-test-renderer": "^18.2.0", "storybook": "^7.3.1", "terser": "^5.19.4", - "typescript": "^5.1.6", - "vite": "^4.4.9" + "typescript": "^5.1.6" }, "lint-staged": { "*.{js,ts,tsx}": "eslint --cache --fix", diff --git a/stories/StoryProvider.tsx b/stories/StoryProvider.tsx index 988f720ab..b5365e077 100644 --- a/stories/StoryProvider.tsx +++ b/stories/StoryProvider.tsx @@ -6,7 +6,6 @@ import { import React, { useEffect } from "react"; import { DndProvider } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; -import { HelmetProvider } from "react-helmet-async"; import { BrowserRouter } from "react-router-dom"; import { CharactersContext, @@ -73,9 +72,7 @@ export function StoryProvider(props: { } > - - {props.children} - + {props.children} diff --git a/tsconfig.json b/tsconfig.json index 15ac4b11c..502b16f45 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,18 +4,50 @@ "module": "ESNext", "moduleResolution": "Node", "esModuleInterop": true, - "jsx": "react", + "jsx": "preserve", "outDir": "./.tsc", "skipLibCheck": true, - "lib": ["es2015", "es2016", "es2017", "ES2018", "ES2019", "dom"], + "lib": [ + "es2015", + "es2016", + "es2017", + "ES2018", + "ES2019", + "dom" + ], "strict": true, + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "incremental": true, "plugins": [ { "name": "typescript-tslint-plugin" + }, + { + "name": "next" } ], - "types": ["vitest/globals", "vite/client", "bun-types"] + "types": [ + "vitest/globals", + "bun-types", + "next" + ], + "noEmit": true, + "resolveJsonModule": true, + "isolatedModules": true }, - "include": ["lib/**/*", "stories/**/*"], - "exclude": ["node_modules", "cypress", "dist", "lib/**/*.test.tsx"] + "include": [ + "lib/**/*", + "app/**/*", + "stories/**/*", + "./dist/types/**/*.ts", + "./next-env.d.ts", + ".next/types/**/*.ts" + ], + "exclude": [ + "./node_modules", + "cypress", + "dist", + "lib/**/*.test.tsx" + ] } diff --git a/vite-env.d.ts b/vite-env.d.ts deleted file mode 100644 index 11f02fe2a..000000000 --- a/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -///