From 163f6cea08e83a5fd3bc4556682c862979d06523 Mon Sep 17 00:00:00 2001 From: QiShaoXuan Date: Mon, 26 Sep 2022 16:24:29 +0800 Subject: [PATCH] feat: add theme change handler --- src/components/simple-counter/index.ts | 5 ++-- src/pages/_app.tsx | 5 ++-- src/pages/index.tsx | 11 ++++++-- src/styles/hooks.ts | 4 +++ src/styles/index.ts | 7 ++++- src/styles/styled.ts | 3 ++ src/styles/theme.ts | 23 ++++++++------- src/styles/themeProvider.tsx | 39 ++++++++++++++++++++++++++ src/styles/types.ts | 21 ++++++++++++++ 9 files changed, 99 insertions(+), 19 deletions(-) create mode 100644 src/styles/hooks.ts create mode 100644 src/styles/styled.ts create mode 100644 src/styles/themeProvider.tsx create mode 100644 src/styles/types.ts diff --git a/src/components/simple-counter/index.ts b/src/components/simple-counter/index.ts index 83b6dbde95..6f99529c1b 100644 --- a/src/components/simple-counter/index.ts +++ b/src/components/simple-counter/index.ts @@ -1,7 +1,6 @@ -import { LitElement, css, html, unsafeCSS } from 'lit'; +import { LitElement, css, html } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import * as React from 'react'; -import { theme } from '@/styles'; export const tagName = 'simple-counter'; @@ -28,7 +27,7 @@ export class Counter extends LitElement { static styles = css` .counter-container { display: flex; - color: ${unsafeCSS(theme.colors.primary)}; + color: var(--color-primary); } button { margin: 0 5px; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 9908d21a12..e118fcf54f 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,12 +1,11 @@ import type { AppProps } from 'next/app'; -import { ThemeProvider } from '@emotion/react'; -import { theme } from '../styles'; +import { ThemeProvider } from '@/styles'; import '../../public/globals.css'; function MyApp({ Component, pageProps }: AppProps) { return ( - + ); diff --git a/src/pages/index.tsx b/src/pages/index.tsx index ef4fe01580..66d8048e7e 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,6 +1,5 @@ import type { NextPage } from 'next'; -import styled from '@emotion/styled'; - +import { styled, useTheme } from '@/styles'; import '@/components/simple-counter'; const Button = styled('div')(({ theme }) => { @@ -10,10 +9,18 @@ const Button = styled('div')(({ theme }) => { }); const Home: NextPage = () => { + const { changeMode, mode } = useTheme(); return (
+
); }; diff --git a/src/styles/hooks.ts b/src/styles/hooks.ts new file mode 100644 index 0000000000..94398c7f36 --- /dev/null +++ b/src/styles/hooks.ts @@ -0,0 +1,4 @@ +import { useContext } from 'react'; +import { ThemeContext } from './themeProvider'; + +export const useTheme = () => useContext(ThemeContext); diff --git a/src/styles/index.ts b/src/styles/index.ts index 7b1f54ecf9..f1c02991ff 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1 +1,6 @@ -export * from './theme'; +export type { ThemeMode, ThemeProviderProps, AffineTheme } from './types'; + +export { styled } from './styled'; +export { ThemeProvider } from './themeProvider'; +export { lightTheme, darkTheme } from './theme'; +export { useTheme } from './hooks'; diff --git a/src/styles/styled.ts b/src/styles/styled.ts new file mode 100644 index 0000000000..11464cee29 --- /dev/null +++ b/src/styles/styled.ts @@ -0,0 +1,3 @@ +import emotionStyled from '@emotion/styled'; + +export const styled = emotionStyled; diff --git a/src/styles/theme.ts b/src/styles/theme.ts index 45f6a84ed4..7afc298e8c 100644 --- a/src/styles/theme.ts +++ b/src/styles/theme.ts @@ -1,17 +1,20 @@ import '@emotion/react'; +import { AffineTheme } from './types'; -interface AffineTheme { - colors: { - primary: string; - }; -} - -export const theme: AffineTheme = { +export const lightTheme: AffineTheme = { colors: { primary: '#0070f3', }, }; -declare module '@emotion/react' { - export interface Theme extends AffineTheme {} -} +export const darkTheme: AffineTheme = { + colors: { + primary: '#000', + }, +}; + +export const globalThemeConstant = (theme: AffineTheme) => { + return { + '--color-primary': theme.colors.primary, + }; +}; diff --git a/src/styles/themeProvider.tsx b/src/styles/themeProvider.tsx new file mode 100644 index 0000000000..383ae2dd74 --- /dev/null +++ b/src/styles/themeProvider.tsx @@ -0,0 +1,39 @@ +import { + ThemeProvider as EmotionThemeProvider, + Global, + css, +} from '@emotion/react'; +import { createContext, useState } from 'react'; +import type { PropsWithChildren } from 'react'; +import { ThemeMode, ThemeProviderProps, ThemeProviderValue } from './types'; +import { lightTheme, darkTheme, globalThemeConstant } from './theme'; + +export const ThemeContext = createContext({ + mode: 'light', + changeMode: () => {}, + theme: lightTheme, +}); + +export const ThemeProvider = ({ + defaultMode = 'light', + children, +}: PropsWithChildren) => { + const [mode, setMode] = useState(defaultMode); + const theme = mode === 'dark' ? darkTheme : lightTheme; + const changeMode = (themeMode: ThemeMode) => { + setMode(themeMode); + }; + + return ( + + + {children} + + ); +}; diff --git a/src/styles/types.ts b/src/styles/types.ts new file mode 100644 index 0000000000..e3a9ce0476 --- /dev/null +++ b/src/styles/types.ts @@ -0,0 +1,21 @@ +export type ThemeMode = 'light' | 'dark'; + +export type ThemeProviderProps = { + defaultMode?: ThemeMode; +}; + +export type ThemeProviderValue = { + theme: AffineTheme; + mode: ThemeMode; + changeMode: (newMode: ThemeMode) => void; +}; + +export interface AffineTheme { + colors: { + primary: string; + }; +} + +declare module '@emotion/react' { + export interface Theme extends AffineTheme {} +}