Appearance
主题切换
该项目主题色分为:全局主题色 和 预览区主题色,分别采用两种不同的解决方案。
- 全局主题色:采用
styled-components
的createGlobalStyle
来创建全局样式,通过styled-components
的ThemeProvider
来提供主题色。 - 预览区主题色:采用 css 变量来实现,方便用户后期自定义主题色。
全局主题色
定义主题色
ts
// src/theme/theme.ts 全局主题色
export const lightTheme = {
background: '#ffffff',
color: '#000000',
borderColor: '#e6e6e6',
silderHelpTitleColor: '#3f4a54',
silderHelpTextColor: '#959da5',
statusColor: '#333333',
toolbarHoverBg: '#e6e6e6',
scrollbarThumbBgColor: '#d9d9d9',
scrollbarTrackBgColor: '#f5f5f5'
}
export const darkTheme = {
background: '#191d24',
color: '#dfdfdf',
borderColor: '#464646',
silderHelpTitleColor: '#bac6d2',
silderHelpTextColor: '#bac6d2',
statusColor: '#dfdfdf',
toolbarHoverBg: '#464646',
scrollbarThumbBgColor: '#898989',
scrollbarTrackBgColor: '#898989'
}
类型文件 styled.d.ts,给 styled-components 提供 ts 类型提示
ts
import 'styled-components'
declare module 'styled-components' {
export interface DefaultTheme {
background: string
color: string
borderColor: string
silderHelpTitleColor: string
silderHelpTextColor: string
statusColor: string
toolbarHoverBg: string
scrollbarThumbBgColor: string
scrollbarTrackBgColor: string
}
}
通过 styled-components 中的 ThemeProvider
,创建全局样式组件
tsx
// src/theme/global-theme.tsx
import React, { FC } from 'react'
import { ThemeProvider } from 'styled-components'
import { lightTheme, darkTheme } from './theme'
const GlobalTheme: FC<{
children: React.ReactNode
theme?: 'light' | 'dark'
}> = ({ children, theme = 'light' }) => {
return (
<ThemeProvider theme={theme === 'light' ? lightTheme : darkTheme}>
{children}
</ThemeProvider>
)
}
export default GlobalTheme
例如,样式写法:
tsx
const Container = styled.div`
/* border: 1px solid #e6e6e6; */
border: 1px solid ${(props) => props.theme.borderColor};
/* background-color: #fff; */
background-color: ${(props) => props.theme.background};
`
预览区主题色
定义变量
ts
// src/theme/preview-theme.ts 预览区主题色
export const previewTheme = {
light: {
color: '#333',
'special-color': '#3f4a54',
'inlincode-color': '#3594f7',
'inlincode-bg-color': 'rgba(59, 170, 250, 0.1)',
'border-color': '#e6e6e6',
'blockquote-color': '#3f4a54',
'blockquote-border-color': '#d0d7de',
'table-border-color': '#ddd',
'th-bg-color': '#f2f2f2',
'table-hover-bg-color': '#f5f5f5'
},
dark: {
color: '#fff',
'special-color': '#bac6d2',
'inlincode-color': '#c9d1d9',
'inlincode-bg-color': '#2d3339',
'border-color': '#2d2d2d',
'blockquote-color': '#8b949e',
'blockquote-border-color': '#444c56',
'table-border-color': '#30363d',
'th-bg-color': '#252525',
'table-hover-bg-color': '#222222'
}
}
创建预览区主题 hook
原理:在根节点添加 css 变量的方式来实现主题切换
tsx
// src/hooks/use-preview-theme.tsx
import { previewTheme } from '@/theme/preview-theme'
import { useEffect } from 'react'
export const usePreviewTheme = (themeProps: 'light' | 'dark') => {
useEffect(() => {
const theme =
themeProps === 'light' ? previewTheme.light : previewTheme.dark
// 设置 CSS 变量
const root = document.body
Object.entries(theme).forEach(([key, value]) => {
root.style.setProperty(`--md-preview-${key}`, value)
})
}, [themeProps])
}
例如:
css
.mini-md-inline-code {
line-height: 22px;
padding: 2px 4px;
/* color: #3594f7; */
color: var(--md-preview-inlincode-color);
/* background-color: rgba(59, 170, 250, 0.1); */
background-color: var(--md-preview-inlincode-bg-color);
border-radius: 4px;
}