RawLayout.tsx 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import type { JSX, ReactNode } from 'react';
  2. import React, { useState } from 'react';
  3. import dynamic from 'next/dynamic';
  4. import Head from 'next/head';
  5. import type { ColorScheme } from '@growi/core';
  6. import { useIsomorphicLayoutEffect } from 'usehooks-ts';
  7. import {
  8. NextThemesProvider,
  9. useNextThemes,
  10. } from '~/stores-universal/use-next-themes';
  11. import loggerFactory from '~/utils/logger';
  12. import styles from './RawLayout.module.scss';
  13. const toastContainerClass = styles['grw-toast-container'] ?? '';
  14. const logger = loggerFactory('growi:cli:RawLayout');
  15. const ToastContainer = dynamic(
  16. () => import('react-toastify').then((mod) => mod.ToastContainer),
  17. { ssr: false },
  18. );
  19. type Props = {
  20. className?: string;
  21. children?: ReactNode;
  22. };
  23. export const RawLayout = ({ children, className }: Props): JSX.Element => {
  24. const classNames: string[] = ['layout-root', 'growi'];
  25. if (className != null) {
  26. classNames.push(className);
  27. }
  28. // get color scheme from next-themes
  29. const { resolvedTheme, resolvedThemeByAttributes } = useNextThemes();
  30. const [colorScheme, setColorScheme] = useState<ColorScheme | undefined>(
  31. undefined,
  32. );
  33. // set colorScheme in CSR
  34. useIsomorphicLayoutEffect(() => {
  35. setColorScheme(resolvedTheme ?? resolvedThemeByAttributes);
  36. }, [resolvedTheme, resolvedThemeByAttributes]);
  37. return (
  38. <>
  39. <Head>
  40. <meta charSet="utf-8" />
  41. <meta name="viewport" content="initial-scale=1.0, width=device-width" />
  42. </Head>
  43. <NextThemesProvider>
  44. <div className={classNames.join(' ')}>
  45. {children}
  46. <ToastContainer className={toastContainerClass} theme={colorScheme} />
  47. </div>
  48. </NextThemesProvider>
  49. </>
  50. );
  51. };