From dfe0d39fa085026d1af64401e4d7775555291b74 Mon Sep 17 00:00:00 2001 From: Max Leiter Date: Tue, 15 Nov 2022 20:50:54 -0800 Subject: [PATCH] remove next-themes, convert header to custom button --- client/app/components/badges/badge.module.css | 5 ++ .../app/components/button-dropdown/index.tsx | 2 +- .../app/components/button/button.module.css | 5 ++ client/app/components/button/index.tsx | 9 ++- client/app/components/card/index.tsx | 2 +- client/app/components/header/controls.tsx | 12 ++-- .../app/components/header/header.module.css | 25 ++++++-- client/app/components/header/index.tsx | 64 ++++++++----------- client/app/components/page/index.tsx | 5 ++ client/app/components/page/page.module.css | 10 +++ .../app/components/settings-group/index.tsx | 16 ++--- .../theme/ThemeClientContextProvider.tsx | 62 ++++++++++++++++++ client/app/components/theme/ThemeProvider.tsx | 26 ++++++++ .../theme/ThemeServerContextProvider.tsx | 24 +++++++ client/app/components/theme/theme.tsx | 5 ++ client/app/components/tooltip/index.tsx | 14 ++-- client/app/layout.tsx | 49 +++++++++----- client/app/root-layout-wrapper.tsx | 61 ++---------------- client/app/styles/globals.css | 11 +++- client/package.json | 6 +- client/pnpm-lock.yaml | 28 ++++---- 21 files changed, 281 insertions(+), 160 deletions(-) create mode 100644 client/app/components/page/index.tsx create mode 100644 client/app/components/page/page.module.css create mode 100644 client/app/components/theme/ThemeClientContextProvider.tsx create mode 100644 client/app/components/theme/ThemeProvider.tsx create mode 100644 client/app/components/theme/ThemeServerContextProvider.tsx create mode 100644 client/app/components/theme/theme.tsx diff --git a/client/app/components/badges/badge.module.css b/client/app/components/badges/badge.module.css index 095aaf61..72a0d9c8 100644 --- a/client/app/components/badges/badge.module.css +++ b/client/app/components/badges/badge.module.css @@ -36,6 +36,11 @@ color: var(--fg); } +/* when data-theme on html is light, change font color */ +[data-theme="light"] .warning { + color: var(--bg); +} + .error { background-color: red; } diff --git a/client/app/components/button-dropdown/index.tsx b/client/app/components/button-dropdown/index.tsx index 635f972b..55da3c81 100644 --- a/client/app/components/button-dropdown/index.tsx +++ b/client/app/components/button-dropdown/index.tsx @@ -79,7 +79,7 @@ const ButtonDropdown: React.FC< return (
& { className?: string onClick?: (e: React.MouseEvent) => void iconRight?: React.ReactNode + iconLeft?: React.ReactNode } // eslint-disable-next-line react/display-name @@ -20,6 +21,7 @@ const Button = forwardRef( type = "button", disabled = false, iconRight, + iconLeft, ...props }, ref @@ -27,11 +29,16 @@ const Button = forwardRef( return ( ) } else if (tab.href) { return ( - - + + ) } @@ -180,28 +180,14 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
{buttons}
-
{/* setExpanded should occur elsewhere; we don't want to close if they change themes */} {isMobile && expanded && (
setExpanded(!expanded)}> - - {buttons} - + {buttons}
)} diff --git a/client/app/components/page/index.tsx b/client/app/components/page/index.tsx new file mode 100644 index 00000000..13f08078 --- /dev/null +++ b/client/app/components/page/index.tsx @@ -0,0 +1,5 @@ +import styles from "./page.module.css" + +export default function Page({ children }: { children: React.ReactNode }) { + return
{children}
+} diff --git a/client/app/components/page/page.module.css b/client/app/components/page/page.module.css new file mode 100644 index 00000000..fd397b2f --- /dev/null +++ b/client/app/components/page/page.module.css @@ -0,0 +1,10 @@ +.page { + max-width: 100vw; + min-height: 100vh; + box-sizing: border-box; + position: relative; + width: 100%; + height: auto; + padding: 0 calc(1.34 * 16px) 0 calc(1.34 * 16px); + margin: 0 auto 0 auto; +} diff --git a/client/app/components/settings-group/index.tsx b/client/app/components/settings-group/index.tsx index 9872ad77..62f29a66 100644 --- a/client/app/components/settings-group/index.tsx +++ b/client/app/components/settings-group/index.tsx @@ -1,5 +1,5 @@ -'use client'; -import { Fieldset, Text, Divider } from "@geist-ui/core/dist" +"use client" +import Card from "@components/card" import styles from "./settings-group.module.css" type Props = { @@ -9,13 +9,11 @@ type Props = { const SettingsGroup = ({ title, children }: Props) => { return ( -
- - {title} - - - {children} -
+ +

{title}

+
+
{children}
+
) } diff --git a/client/app/components/theme/ThemeClientContextProvider.tsx b/client/app/components/theme/ThemeClientContextProvider.tsx new file mode 100644 index 00000000..1fead632 --- /dev/null +++ b/client/app/components/theme/ThemeClientContextProvider.tsx @@ -0,0 +1,62 @@ +"use client" + +import { + FunctionComponent, + PropsWithChildren, + useCallback, + useMemo +} from "react" +import React, { useContext, useState, createContext } from "react" +import { DEFAULT_THEME, Theme, THEME_COOKIE_NAME } from "./theme" +import { setCookie } from "cookies-next" + +interface UseThemeProps { + theme: Theme + setTheme: (theme: Theme) => void +} + +const ThemeContext = createContext(null) + +export function useTheme(): { + theme: Theme + setTheme: (theme: Theme) => void +} { + return ( + useContext(ThemeContext) || { + theme: DEFAULT_THEME, + setTheme: () => {} + } + ) +} + +interface Props extends PropsWithChildren<{}> { + defaultTheme: Theme +} + +const ThemeClientContextProvider: FunctionComponent = ({ + defaultTheme, + children +}) => { + const [theme, setThemeState] = useState(defaultTheme) + const setCookieAndDocument = useCallback( + (theme: Theme) => { + setThemeState(theme) + setCookie(THEME_COOKIE_NAME, theme) + document.documentElement.setAttribute("data-theme", theme) + }, + [setThemeState] + ) + + const setTheme = useCallback( + (theme: Theme) => { + setCookieAndDocument(theme) + }, + [setCookieAndDocument] + ) + + const value = useMemo(() => ({ theme, setTheme }), [theme, setTheme]) + + return {children} +} + +export default ThemeClientContextProvider diff --git a/client/app/components/theme/ThemeProvider.tsx b/client/app/components/theme/ThemeProvider.tsx new file mode 100644 index 00000000..01923099 --- /dev/null +++ b/client/app/components/theme/ThemeProvider.tsx @@ -0,0 +1,26 @@ +import type { FunctionComponent, PropsWithChildren } from "react"; +import ThemeClientContextProvider from "./ThemeClientContextProvider"; +import ThemeServerContextProvider, { + useServerTheme, +} from "./ThemeServerContextProvider"; + +const ThemeProviderWrapper: FunctionComponent> = ({ + children, +}) => { + const theme = useServerTheme(); + return ( + + {children} + + ); +}; + +const ThemeProvider: FunctionComponent> = ({ children }) => { + return ( + + {children} + + ); +}; + +export default ThemeProvider; diff --git a/client/app/components/theme/ThemeServerContextProvider.tsx b/client/app/components/theme/ThemeServerContextProvider.tsx new file mode 100644 index 00000000..1a89205a --- /dev/null +++ b/client/app/components/theme/ThemeServerContextProvider.tsx @@ -0,0 +1,24 @@ +import type { FunctionComponent, PropsWithChildren } from "react"; +// @ts-ignore -- createServerContext is not in @types/react atm +import { useContext, createServerContext } from "react"; +import { cookies } from "next/headers"; +import { Theme, THEME_COOKIE_NAME } from "./theme"; +import { DEFAULT_THEME } from "./theme"; + +const ThemeContext = createServerContext(null); + +export function useServerTheme(): Theme { + return useContext(ThemeContext); +} + +const ThemeServerContextProvider: FunctionComponent> = ({ + children, +}) => { + const cookiesList = cookies(); + const theme = cookiesList.get(THEME_COOKIE_NAME)?.value ?? DEFAULT_THEME; + return ( + {children} + ); +}; + +export default ThemeServerContextProvider; diff --git a/client/app/components/theme/theme.tsx b/client/app/components/theme/theme.tsx new file mode 100644 index 00000000..241b19b8 --- /dev/null +++ b/client/app/components/theme/theme.tsx @@ -0,0 +1,5 @@ +export type Theme = "light" | "dark"; + +export const DEFAULT_THEME: Theme = "light"; + +export const THEME_COOKIE_NAME = "drift-theme"; diff --git a/client/app/components/tooltip/index.tsx b/client/app/components/tooltip/index.tsx index a9ec297d..837d3a07 100644 --- a/client/app/components/tooltip/index.tsx +++ b/client/app/components/tooltip/index.tsx @@ -1,6 +1,4 @@ -"use client" - -import { Card } from "@geist-ui/core/dist" +import Card from "@components/card" import * as RadixTooltip from "@radix-ui/react-tooltip" import "./tooltip.css" @@ -16,14 +14,12 @@ const Tooltip = ({ } & RadixTooltip.TooltipProps) => { return ( - {children} + + {children} + - - - {content} - - + {content} ) diff --git a/client/app/layout.tsx b/client/app/layout.tsx index 5f4ade10..ca3d0881 100644 --- a/client/app/layout.tsx +++ b/client/app/layout.tsx @@ -1,31 +1,46 @@ import "@styles/globals.css" -import { ServerThemeProvider } from "next-themes" import { LayoutWrapper } from "./root-layout-wrapper" -import styles from '@styles/Home.module.css'; -import { cookies } from "next/headers"; -import { getSession } from "@lib/server/session"; +import styles from "@styles/Home.module.css" +import { getSession } from "@lib/server/session" +import ThemeProvider from "@components/theme/ThemeProvider" +import { THEME_COOKIE_NAME } from "@components/theme/theme" +import { useServerTheme } from "@components/theme/ThemeServerContextProvider" interface RootLayoutProps { children: React.ReactNode } -export default async function RootLayout({ children }: RootLayoutProps) { +export default async function RootLayout({ children }: RootLayoutProps) { // TODO: this opts out of SSG const session = await getSession() return ( - - - - - + + +