mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-23 01:32:56 +03:00
feat: add theme change handler
This commit is contained in:
parent
62d4b0a32d
commit
163f6cea08
@ -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 { customElement, property, state } from 'lit/decorators.js';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { theme } from '@/styles';
|
|
||||||
|
|
||||||
export const tagName = 'simple-counter';
|
export const tagName = 'simple-counter';
|
||||||
|
|
||||||
@ -28,7 +27,7 @@ export class Counter extends LitElement {
|
|||||||
static styles = css`
|
static styles = css`
|
||||||
.counter-container {
|
.counter-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
color: ${unsafeCSS(theme.colors.primary)};
|
color: var(--color-primary);
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import type { AppProps } from 'next/app';
|
import type { AppProps } from 'next/app';
|
||||||
import { ThemeProvider } from '@emotion/react';
|
import { ThemeProvider } from '@/styles';
|
||||||
import { theme } from '../styles';
|
|
||||||
|
|
||||||
import '../../public/globals.css';
|
import '../../public/globals.css';
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
function MyApp({ Component, pageProps }: AppProps) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider>
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import type { NextPage } from 'next';
|
import type { NextPage } from 'next';
|
||||||
import styled from '@emotion/styled';
|
import { styled, useTheme } from '@/styles';
|
||||||
|
|
||||||
import '@/components/simple-counter';
|
import '@/components/simple-counter';
|
||||||
|
|
||||||
const Button = styled('div')(({ theme }) => {
|
const Button = styled('div')(({ theme }) => {
|
||||||
@ -10,10 +9,18 @@ const Button = styled('div')(({ theme }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const Home: NextPage = () => {
|
const Home: NextPage = () => {
|
||||||
|
const { changeMode, mode } = useTheme();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Button>A button use the theme styles</Button>
|
<Button>A button use the theme styles</Button>
|
||||||
<simple-counter name="A counter created by web component" />
|
<simple-counter name="A counter created by web component" />
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
changeMode(mode === 'dark' ? 'light' : 'dark');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
current theme mode :{mode}(click to change)
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
4
src/styles/hooks.ts
Normal file
4
src/styles/hooks.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { ThemeContext } from './themeProvider';
|
||||||
|
|
||||||
|
export const useTheme = () => useContext(ThemeContext);
|
@ -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';
|
||||||
|
3
src/styles/styled.ts
Normal file
3
src/styles/styled.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import emotionStyled from '@emotion/styled';
|
||||||
|
|
||||||
|
export const styled = emotionStyled;
|
@ -1,17 +1,20 @@
|
|||||||
import '@emotion/react';
|
import '@emotion/react';
|
||||||
|
import { AffineTheme } from './types';
|
||||||
|
|
||||||
interface AffineTheme {
|
export const lightTheme: AffineTheme = {
|
||||||
colors: {
|
|
||||||
primary: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const theme: AffineTheme = {
|
|
||||||
colors: {
|
colors: {
|
||||||
primary: '#0070f3',
|
primary: '#0070f3',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
declare module '@emotion/react' {
|
export const darkTheme: AffineTheme = {
|
||||||
export interface Theme extends AffineTheme {}
|
colors: {
|
||||||
}
|
primary: '#000',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const globalThemeConstant = (theme: AffineTheme) => {
|
||||||
|
return {
|
||||||
|
'--color-primary': theme.colors.primary,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
39
src/styles/themeProvider.tsx
Normal file
39
src/styles/themeProvider.tsx
Normal file
@ -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<ThemeProviderValue>({
|
||||||
|
mode: 'light',
|
||||||
|
changeMode: () => {},
|
||||||
|
theme: lightTheme,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ThemeProvider = ({
|
||||||
|
defaultMode = 'light',
|
||||||
|
children,
|
||||||
|
}: PropsWithChildren<ThemeProviderProps>) => {
|
||||||
|
const [mode, setMode] = useState<ThemeMode>(defaultMode);
|
||||||
|
const theme = mode === 'dark' ? darkTheme : lightTheme;
|
||||||
|
const changeMode = (themeMode: ThemeMode) => {
|
||||||
|
setMode(themeMode);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={{ mode, changeMode, theme }}>
|
||||||
|
<Global
|
||||||
|
styles={css`
|
||||||
|
:root {
|
||||||
|
${globalThemeConstant(theme)}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
<EmotionThemeProvider theme={theme}>{children}</EmotionThemeProvider>
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
21
src/styles/types.ts
Normal file
21
src/styles/types.ts
Normal file
@ -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 {}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user