mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-15 21:41:52 +08:00
refactor: move component into a single package (#898)
This commit is contained in:
145
packages/component/src/styles/helper.ts
Normal file
145
packages/component/src/styles/helper.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import type { CSSProperties } from 'react';
|
||||
|
||||
export const displayFlex = (
|
||||
justifyContent: CSSProperties['justifyContent'] = 'unset',
|
||||
alignItems: CSSProperties['alignItems'] = 'unset',
|
||||
alignContent: CSSProperties['alignContent'] = 'unset'
|
||||
): {
|
||||
display: CSSProperties['display'];
|
||||
justifyContent: CSSProperties['justifyContent'];
|
||||
alignItems: CSSProperties['alignItems'];
|
||||
alignContent: CSSProperties['alignContent'];
|
||||
} => {
|
||||
return {
|
||||
display: 'flex',
|
||||
justifyContent,
|
||||
alignItems,
|
||||
alignContent,
|
||||
};
|
||||
};
|
||||
export const displayInlineFlex = (
|
||||
justifyContent: CSSProperties['justifyContent'] = 'unset',
|
||||
alignItems: CSSProperties['alignContent'] = 'unset',
|
||||
alignContent: CSSProperties['alignContent'] = 'unset'
|
||||
): {
|
||||
display: CSSProperties['display'];
|
||||
justifyContent: CSSProperties['justifyContent'];
|
||||
alignItems: CSSProperties['alignContent'];
|
||||
alignContent: CSSProperties['alignContent'];
|
||||
} => {
|
||||
return {
|
||||
display: 'inline-flex',
|
||||
justifyContent,
|
||||
alignItems,
|
||||
alignContent,
|
||||
};
|
||||
};
|
||||
|
||||
export const absoluteCenter = ({
|
||||
horizontal = false,
|
||||
vertical = false,
|
||||
position: { left, right, top, bottom } = {},
|
||||
}: {
|
||||
horizontal?: boolean;
|
||||
vertical?: boolean;
|
||||
position?: {
|
||||
left?: CSSProperties['left'];
|
||||
right?: CSSProperties['right'];
|
||||
top?: CSSProperties['top'];
|
||||
bottom?: CSSProperties['bottom'];
|
||||
};
|
||||
}): {
|
||||
position: CSSProperties['position'];
|
||||
left: CSSProperties['left'];
|
||||
top: CSSProperties['top'];
|
||||
right: CSSProperties['right'];
|
||||
bottom: CSSProperties['bottom'];
|
||||
transform: CSSProperties['transform'];
|
||||
} => {
|
||||
return {
|
||||
position: 'absolute',
|
||||
left: left ? left : horizontal ? '50%' : 'auto',
|
||||
top: top ? top : vertical ? '50%' : 'auto',
|
||||
right: right ? right : horizontal ? 'auto' : 'auto',
|
||||
bottom: bottom ? bottom : vertical ? 'auto' : 'auto',
|
||||
transform: `translate(${horizontal ? '-50%' : '0'}, ${
|
||||
vertical ? '-50%' : '0'
|
||||
})`,
|
||||
};
|
||||
};
|
||||
export const fixedCenter = ({
|
||||
horizontal = false,
|
||||
vertical = false,
|
||||
position: { left, right, top, bottom } = {},
|
||||
}: {
|
||||
horizontal?: boolean;
|
||||
vertical?: boolean;
|
||||
position?: {
|
||||
left?: CSSProperties['left'];
|
||||
right?: CSSProperties['right'];
|
||||
top?: CSSProperties['top'];
|
||||
bottom?: CSSProperties['bottom'];
|
||||
};
|
||||
}): {
|
||||
position: CSSProperties['position'];
|
||||
left: CSSProperties['left'];
|
||||
top: CSSProperties['top'];
|
||||
right: CSSProperties['right'];
|
||||
bottom: CSSProperties['bottom'];
|
||||
transform: CSSProperties['transform'];
|
||||
} => {
|
||||
return {
|
||||
position: 'fixed',
|
||||
left: left ? left : horizontal ? '50%' : 'auto',
|
||||
top: top ? top : vertical ? '50%' : 'auto',
|
||||
right: right ? right : horizontal ? 'auto' : 'auto',
|
||||
bottom: bottom ? bottom : vertical ? 'auto' : 'auto',
|
||||
transform: `translate(${horizontal ? '-50%' : '0'}, ${
|
||||
vertical ? '-50%' : '0'
|
||||
})`,
|
||||
};
|
||||
};
|
||||
|
||||
export const textEllipsis = (lineNum = 1): CSSProperties => {
|
||||
if (lineNum > 1) {
|
||||
return {
|
||||
display: '-webkit-box',
|
||||
wordBreak: 'break-all',
|
||||
WebkitBoxOrient: 'vertical',
|
||||
WebkitLineClamp: `${lineNum}`, //the number of rows to display
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
};
|
||||
}
|
||||
return {
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
};
|
||||
};
|
||||
|
||||
export const positionAbsolute = ({
|
||||
left,
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
}: {
|
||||
left?: CSSProperties['left'];
|
||||
top?: CSSProperties['top'];
|
||||
right?: CSSProperties['right'];
|
||||
bottom?: CSSProperties['bottom'];
|
||||
}): {
|
||||
position: CSSProperties['position'];
|
||||
left: CSSProperties['left'];
|
||||
top: CSSProperties['top'];
|
||||
right: CSSProperties['right'];
|
||||
bottom: CSSProperties['bottom'];
|
||||
} => {
|
||||
return {
|
||||
position: 'absolute',
|
||||
left,
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
};
|
||||
};
|
||||
5
packages/component/src/styles/index.ts
Normal file
5
packages/component/src/styles/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './styled';
|
||||
export * from './theme';
|
||||
export * from './helper';
|
||||
export * from './types';
|
||||
export * from './utils';
|
||||
15
packages/component/src/styles/styled.tsx
Normal file
15
packages/component/src/styles/styled.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { ThemeProvider as EmotionThemeProvider } from '@emotion/react';
|
||||
import emotionStyled from '@emotion/styled';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { AffineTheme } from './types';
|
||||
export { css, keyframes } from '@emotion/react';
|
||||
export const styled = emotionStyled;
|
||||
|
||||
export const ThemeProvider = ({
|
||||
theme,
|
||||
children,
|
||||
}: PropsWithChildren<{
|
||||
theme: AffineTheme;
|
||||
}>) => {
|
||||
return <EmotionThemeProvider theme={theme}>{children}</EmotionThemeProvider>;
|
||||
};
|
||||
208
packages/component/src/styles/theme.ts
Normal file
208
packages/component/src/styles/theme.ts
Normal file
@@ -0,0 +1,208 @@
|
||||
import '@emotion/react';
|
||||
import { AffineTheme, AffineThemeCSSVariables, ThemeMode } from './types';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
|
||||
const basicFontFamily =
|
||||
'apple-system, BlinkMacSystemFont,Helvetica Neue, Tahoma, PingFang SC, Microsoft Yahei, Arial,Hiragino Sans GB, sans-serif, Apple Color Emoji, Segoe UI Emoji,Segoe UI Symbol, Noto Color Emoji';
|
||||
|
||||
export const getLightTheme = (
|
||||
editorMode: EditorContainer['mode']
|
||||
): AffineTheme => {
|
||||
return {
|
||||
mode: 'light',
|
||||
editorMode,
|
||||
colors: {
|
||||
primaryColor: '#6880FF',
|
||||
|
||||
pageBackground: '#fff',
|
||||
hoverBackground: '#F1F3FF',
|
||||
innerHoverBackground: '#E9E9EC',
|
||||
popoverBackground: '#fff',
|
||||
tooltipBackground: '#6880FF',
|
||||
codeBackground: '#f2f5f9',
|
||||
codeBlockBackground: '#F9F9FB',
|
||||
blockHubBackground: '#fbfbfc',
|
||||
blockHubHoverBackground: '#f8f9ff',
|
||||
warningBackground: '#FFF9C7',
|
||||
errorBackground: '#FFDED8',
|
||||
|
||||
textColor: '#28293D',
|
||||
edgelessTextColor: '#3A4C5C',
|
||||
iconColor: '#555770',
|
||||
handleColor: '#c7c3d9',
|
||||
linkColor: '#6880FF',
|
||||
linkColor2: '#6880FF',
|
||||
linkVisitedColor: '#ABB8FE',
|
||||
popoverColor: '#4C6275',
|
||||
inputColor: '#4C6275',
|
||||
tooltipColor: '#fff',
|
||||
codeColor: '#517ea6',
|
||||
quoteColor: '#4C6275',
|
||||
placeHolderColor: '#888A9E',
|
||||
selectedColor: 'rgba(104, 128, 255, 0.1)',
|
||||
borderColor: '#E3E2E4',
|
||||
disableColor: '#555770',
|
||||
warningColor: '#906616',
|
||||
errorColor: '#EB4335',
|
||||
lineNumberColor: '#555770',
|
||||
},
|
||||
font: {
|
||||
title: '36px',
|
||||
h1: '28px',
|
||||
h2: '26px',
|
||||
h3: '24px',
|
||||
h4: '22px',
|
||||
h5: '20px',
|
||||
h6: '18px',
|
||||
base: '16px',
|
||||
xs: '14px',
|
||||
sm: '12px',
|
||||
|
||||
family: `Avenir Next, Poppins, ${basicFontFamily}`,
|
||||
numberFamily: `Roboto Mono, ${basicFontFamily}`,
|
||||
codeFamily: `Space Mono, Consolas, Menlo, Monaco, Courier, monospace, ${basicFontFamily}`,
|
||||
lineHeight: 'calc(1em + 8px)',
|
||||
},
|
||||
zIndex: {
|
||||
modal: 1000,
|
||||
popover: 100,
|
||||
},
|
||||
shadow: {
|
||||
popover:
|
||||
'4px 4px 7px rgba(58, 76, 92, 0.04), -4px -4px 13px rgba(58, 76, 92, 0.02), 6px 6px 36px rgba(58, 76, 92, 0.06);',
|
||||
modal:
|
||||
'4px 4px 7px rgba(58, 76, 92, 0.04), -4px -4px 13px rgba(58, 76, 92, 0.02), 6px 6px 36px rgba(58, 76, 92, 0.06);',
|
||||
tooltip: '1px 1px 4px rgba(0, 0, 0, 0.14)',
|
||||
},
|
||||
space: {
|
||||
paragraph: '8px',
|
||||
},
|
||||
radius: {
|
||||
popover: '10px',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const getDarkTheme = (
|
||||
editorMode: EditorContainer['mode']
|
||||
): AffineTheme => {
|
||||
const lightTheme = getLightTheme(editorMode);
|
||||
|
||||
return {
|
||||
...lightTheme,
|
||||
mode: 'dark',
|
||||
colors: {
|
||||
primaryColor: '#6880FF',
|
||||
|
||||
pageBackground: '#2c2c2c',
|
||||
hoverBackground: '#3C3C42',
|
||||
innerHoverBackground: '#E0E6FF',
|
||||
popoverBackground: '#1F2021',
|
||||
tooltipBackground: '#1F2021',
|
||||
codeBackground:
|
||||
editorMode === 'edgeless'
|
||||
? lightTheme.colors.codeBackground
|
||||
: '#505662',
|
||||
codeBlockBackground: '#36383D',
|
||||
blockHubBackground: '#272727',
|
||||
blockHubHoverBackground: '#363636',
|
||||
warningBackground: '#FFF9C7',
|
||||
errorBackground: '#FFDED8',
|
||||
|
||||
textColor: '#fff',
|
||||
edgelessTextColor: '#3A4C5C',
|
||||
iconColor: '#888a9e',
|
||||
handleColor: '#c7c3d9',
|
||||
linkColor: '#7D91FF',
|
||||
linkColor2: '#6880FF',
|
||||
linkVisitedColor: '#505FAB',
|
||||
popoverColor: '#C6CBD9',
|
||||
inputColor: '#C6CBD9',
|
||||
tooltipColor: '#fff',
|
||||
codeColor:
|
||||
editorMode === 'edgeless' ? lightTheme.colors.codeColor : '#BDDBFD',
|
||||
quoteColor: '#C6CBD9',
|
||||
placeHolderColor: '#C7C7C7',
|
||||
selectedColor: 'rgba(104, 128, 255, 0.1)',
|
||||
borderColor: '#4D4C53',
|
||||
disableColor: '#4b4b4b',
|
||||
warningColor: '#906616',
|
||||
errorColor: '#EB4335',
|
||||
lineNumberColor: '#888A9E',
|
||||
},
|
||||
shadow: {
|
||||
popover:
|
||||
'0px 1px 10px -6px rgba(24, 39, 75, 0.08), 0px 3px 16px -6px rgba(24, 39, 75, 0.04)',
|
||||
modal:
|
||||
'0px 1px 10px -6px rgba(24, 39, 75, 0.08), 0px 3px 16px -6px rgba(24, 39, 75, 0.04)',
|
||||
tooltip: '1px 1px 4px rgba(0, 0, 0, 0.14)',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const globalThemeVariables: (
|
||||
mode: ThemeMode,
|
||||
theme: AffineTheme
|
||||
) => AffineThemeCSSVariables = (mode, theme) => {
|
||||
return {
|
||||
'--affine-theme-mode': theme.mode,
|
||||
'--affine-editor-mode': theme.editorMode,
|
||||
|
||||
'--affine-primary-color': theme.colors.primaryColor,
|
||||
|
||||
'--affine-page-background': theme.colors.pageBackground,
|
||||
'--affine-popover-background': theme.colors.popoverBackground,
|
||||
'--affine-hover-background': theme.colors.hoverBackground,
|
||||
'--affine-code-background': theme.colors.codeBackground,
|
||||
'--affine-tooltip-background': theme.colors.tooltipBackground,
|
||||
|
||||
'--affine-block-hub-background': theme.colors.blockHubBackground,
|
||||
'--affine-block-hub-hover-background': theme.colors.blockHubHoverBackground,
|
||||
|
||||
'--affine-text-color': theme.colors.textColor,
|
||||
'--affine-edgeless-text-color': theme.colors.edgelessTextColor,
|
||||
'--affine-link-color': theme.colors.linkColor,
|
||||
// In dark mode, normal text`s (not bold) color
|
||||
'--affine-link-color2': theme.colors.linkColor2,
|
||||
'--affine-link-visited-color': theme.colors.linkVisitedColor,
|
||||
'--affine-icon-color': theme.colors.iconColor,
|
||||
'--affine-block-handle-color': theme.colors.handleColor,
|
||||
'--affine-popover-color': theme.colors.popoverColor,
|
||||
'--affine-input-color': theme.colors.inputColor,
|
||||
'--affine-code-color': theme.colors.codeColor,
|
||||
'--affine-code-block-background': theme.colors.codeBlockBackground,
|
||||
'--affine-quote-color': theme.colors.quoteColor,
|
||||
'--affine-selected-color': theme.colors.selectedColor,
|
||||
'--affine-placeholder-color': theme.colors.placeHolderColor,
|
||||
'--affine-border-color': theme.colors.borderColor,
|
||||
'--affine-disable-color': theme.colors.disableColor,
|
||||
'--affine-tooltip-color': theme.colors.tooltipColor,
|
||||
'--affine-line-number-color': theme.colors.lineNumberColor,
|
||||
|
||||
'--affine-modal-shadow': theme.shadow.modal,
|
||||
'--affine-popover-shadow': theme.shadow.popover,
|
||||
'--affine-tooltip-shadow': theme.shadow.tooltip,
|
||||
|
||||
'--affine-font-h1': theme.font.h1,
|
||||
'--affine-font-h2': theme.font.h2,
|
||||
'--affine-font-h3': theme.font.h3,
|
||||
'--affine-font-h4': theme.font.h4,
|
||||
'--affine-font-h5': theme.font.h5,
|
||||
'--affine-font-h6': theme.font.h6,
|
||||
'--affine-font-base': theme.font.base,
|
||||
'--affine-font-sm': theme.font.sm, // small
|
||||
'--affine-font-xs': theme.font.xs, // tiny
|
||||
|
||||
'--affine-line-height': theme.font.lineHeight,
|
||||
|
||||
'--affine-z-index-modal': theme.zIndex.modal,
|
||||
'--affine-z-index-popover': theme.zIndex.popover,
|
||||
|
||||
'--affine-font-family': theme.font.family,
|
||||
'--affine-font-number-family': theme.font.numberFamily,
|
||||
'--affine-font-code-family': theme.font.codeFamily,
|
||||
|
||||
'--affine-paragraph-space': theme.space.paragraph,
|
||||
'--affine-popover-radius': theme.radius.popover,
|
||||
};
|
||||
};
|
||||
150
packages/component/src/styles/types.ts
Normal file
150
packages/component/src/styles/types.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import { EditorContainer } from '@blocksuite/editor';
|
||||
|
||||
export type Theme = 'light' | 'dark';
|
||||
export type ThemeMode = Theme | 'auto';
|
||||
|
||||
export type ThemeProviderProps = {
|
||||
defaultTheme?: Theme;
|
||||
};
|
||||
|
||||
export type ThemeProviderValue = {
|
||||
theme: AffineTheme;
|
||||
mode: ThemeMode;
|
||||
changeMode: (newMode: ThemeMode) => void;
|
||||
};
|
||||
|
||||
export interface AffineTheme {
|
||||
mode: Theme;
|
||||
editorMode: EditorContainer['mode'];
|
||||
colors: {
|
||||
primaryColor: string;
|
||||
|
||||
pageBackground: string;
|
||||
popoverBackground: string;
|
||||
tooltipBackground: string;
|
||||
hoverBackground: string;
|
||||
innerHoverBackground: string;
|
||||
codeBackground: string;
|
||||
codeBlockBackground: string;
|
||||
blockHubBackground: string;
|
||||
blockHubHoverBackground: string;
|
||||
warningBackground: string;
|
||||
errorBackground: string;
|
||||
// Use for the page`s text
|
||||
textColor: string;
|
||||
// Use for the editor`s text, because in edgeless mode text is different form other
|
||||
edgelessTextColor: string;
|
||||
linkColor: string;
|
||||
// In dark mode, normal text`s (not bold) color
|
||||
linkColor2: string;
|
||||
linkVisitedColor: string;
|
||||
iconColor: string;
|
||||
handleColor: string;
|
||||
popoverColor: string;
|
||||
inputColor: string;
|
||||
tooltipColor: string;
|
||||
codeColor: string;
|
||||
quoteColor: string;
|
||||
placeHolderColor: string;
|
||||
selectedColor: string;
|
||||
borderColor: string;
|
||||
disableColor: string;
|
||||
warningColor: string;
|
||||
errorColor: string;
|
||||
lineNumberColor: string;
|
||||
};
|
||||
font: {
|
||||
title: string;
|
||||
h1: string;
|
||||
h2: string;
|
||||
h3: string;
|
||||
h4: string;
|
||||
h5: string;
|
||||
h6: string;
|
||||
base: string;
|
||||
sm: string; // small
|
||||
xs: string; // tiny
|
||||
|
||||
family: string;
|
||||
numberFamily: string;
|
||||
codeFamily: string;
|
||||
|
||||
lineHeight: string | number;
|
||||
};
|
||||
zIndex: {
|
||||
modal: number;
|
||||
popover: number;
|
||||
};
|
||||
shadow: {
|
||||
modal: string;
|
||||
popover: string;
|
||||
tooltip: string;
|
||||
};
|
||||
space: {
|
||||
paragraph: string;
|
||||
};
|
||||
radius: {
|
||||
popover: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface AffineThemeCSSVariables {
|
||||
'--affine-theme-mode': Theme;
|
||||
'--affine-editor-mode': EditorContainer['mode'];
|
||||
|
||||
'--affine-primary-color': AffineTheme['colors']['primaryColor'];
|
||||
'--affine-page-background': AffineTheme['colors']['pageBackground'];
|
||||
'--affine-popover-background': AffineTheme['colors']['popoverBackground'];
|
||||
'--affine-hover-background': AffineTheme['colors']['hoverBackground'];
|
||||
'--affine-code-background': AffineTheme['colors']['codeBackground'];
|
||||
|
||||
'--affine-code-block-background': AffineTheme['colors']['codeBlockBackground'];
|
||||
'--affine-tooltip-background': AffineTheme['colors']['tooltipBackground'];
|
||||
|
||||
'--affine-text-color': AffineTheme['colors']['textColor'];
|
||||
'--affine-edgeless-text-color': AffineTheme['colors']['edgelessTextColor'];
|
||||
'--affine-link-color': AffineTheme['colors']['linkColor'];
|
||||
// In dark mode, normal text`s (not bold) color
|
||||
'--affine-link-color2': AffineTheme['colors']['linkColor2'];
|
||||
'--affine-link-visited-color': AffineTheme['colors']['linkVisitedColor'];
|
||||
'--affine-icon-color': AffineTheme['colors']['iconColor'];
|
||||
'--affine-popover-color': AffineTheme['colors']['popoverColor'];
|
||||
'--affine-code-color': AffineTheme['colors']['codeColor'];
|
||||
'--affine-quote-color': AffineTheme['colors']['quoteColor'];
|
||||
'--affine-placeholder-color': AffineTheme['colors']['placeHolderColor'];
|
||||
'--affine-selected-color': AffineTheme['colors']['selectedColor'];
|
||||
'--affine-border-color': AffineTheme['colors']['borderColor'];
|
||||
'--affine-disable-color': AffineTheme['colors']['disableColor'];
|
||||
'--affine-tooltip-color': AffineTheme['colors']['tooltipColor'];
|
||||
'--affine-line-number-color': AffineTheme['colors']['lineNumberColor'];
|
||||
|
||||
'--affine-modal-shadow': AffineTheme['shadow']['modal'];
|
||||
'--affine-popover-shadow': AffineTheme['shadow']['popover'];
|
||||
'--affine-tooltip-shadow': AffineTheme['shadow']['tooltip'];
|
||||
'--affine-font-h1': AffineTheme['font']['h1'];
|
||||
'--affine-font-h2': AffineTheme['font']['h2'];
|
||||
'--affine-font-h3': AffineTheme['font']['h3'];
|
||||
'--affine-font-h4': AffineTheme['font']['h4'];
|
||||
'--affine-font-h5': AffineTheme['font']['h5'];
|
||||
'--affine-font-h6': AffineTheme['font']['h6'];
|
||||
'--affine-font-base': AffineTheme['font']['base'];
|
||||
'--affine-font-sm': AffineTheme['font']['sm']; // small
|
||||
'--affine-font-xs': AffineTheme['font']['xs']; // tiny
|
||||
'--affine-line-height': AffineTheme['font']['lineHeight'];
|
||||
|
||||
'--affine-z-index-modal': AffineTheme['zIndex']['modal'];
|
||||
'--affine-z-index-popover': AffineTheme['zIndex']['popover'];
|
||||
|
||||
'--affine-font-family': AffineTheme['font']['family'];
|
||||
'--affine-font-number-family': AffineTheme['font']['numberFamily'];
|
||||
'--affine-font-code-family': AffineTheme['font']['codeFamily'];
|
||||
|
||||
'--affine-paragraph-space': AffineTheme['space']['paragraph'];
|
||||
|
||||
'--affine-popover-radius': AffineTheme['radius']['popover'];
|
||||
}
|
||||
|
||||
declare module '@emotion/react' {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface Theme extends AffineTheme {}
|
||||
}
|
||||
2
packages/component/src/styles/utils/index.ts
Normal file
2
packages/component/src/styles/utils/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './systemThemeHelper';
|
||||
export * from './localStorageThemeHelper';
|
||||
@@ -0,0 +1,13 @@
|
||||
import { ThemeMode } from '../types';
|
||||
|
||||
export class LocalStorageThemeHelper {
|
||||
name = 'Affine-theme-mode';
|
||||
get = (): ThemeMode | null => {
|
||||
return localStorage.getItem(this.name) as ThemeMode | null;
|
||||
};
|
||||
set = (mode: ThemeMode) => {
|
||||
localStorage.setItem(this.name, mode);
|
||||
};
|
||||
}
|
||||
|
||||
export const localStorageThemeHelper = new LocalStorageThemeHelper();
|
||||
29
packages/component/src/styles/utils/systemThemeHelper.ts
Normal file
29
packages/component/src/styles/utils/systemThemeHelper.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Theme } from '../types';
|
||||
|
||||
export class SystemThemeHelper {
|
||||
media: MediaQueryList = window.matchMedia('(prefers-color-scheme: light)');
|
||||
eventList: Array<(e: Event) => void> = [];
|
||||
eventHandler = (e: Event) => {
|
||||
this.eventList.forEach(fn => fn(e));
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this.media.addEventListener('change', this.eventHandler);
|
||||
}
|
||||
|
||||
get = (): Theme => {
|
||||
if (typeof window === 'undefined') {
|
||||
return 'light';
|
||||
}
|
||||
return this.media.matches ? 'light' : 'dark';
|
||||
};
|
||||
|
||||
onChange = (callback: () => void) => {
|
||||
this.eventList.push(callback);
|
||||
};
|
||||
|
||||
dispose = () => {
|
||||
this.eventList = [];
|
||||
this.media.removeEventListener('change', this.eventHandler);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user