From 0580011f7b7ae1a617fb0b4a68c052c9d02cf33c Mon Sep 17 00:00:00 2001 From: jaywcjlove <398188662@qq.com> Date: Sat, 3 Sep 2022 01:11:22 +0800 Subject: [PATCH] feat: add preview themes. --- README.md | 50 +++++++- package.json | 3 +- src/components/Layout.tsx | 4 +- src/conf/default.md.css | 195 ------------------------------ src/pages/home/Preview.tsx | 8 +- src/pages/home/index.tsx | 7 +- src/pages/home/theme.tsx | 54 +++++---- src/store/context.tsx | 116 ++++++++++++++---- src/themes/default.md.css | 225 +++++++++++++++++++++++++++++++++++ src/themes/simple.md.css | 225 +++++++++++++++++++++++++++++++++++ src/themes/underscore.md.css | 222 ++++++++++++++++++++++++++++++++++ 11 files changed, 858 insertions(+), 251 deletions(-) delete mode 100644 src/conf/default.md.css create mode 100644 src/themes/default.md.css create mode 100644 src/themes/simple.md.css create mode 100644 src/themes/underscore.md.css diff --git a/README.md b/README.md index 084be39..f22e352 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ - [x] 支持 Markdown 所有基础语法 - [x] 支持自定义 CSS 样式 -- [ ] 支持主题选择 & 配置。 +- [x] 支持主题选择 & 配置。 - [x] 支持明暗两种主题预览。 - [ ] 支持色盘取色,快速替换文章整体色调 @@ -100,6 +100,54 @@ Inline Code `{code: 0}` 内容在微信 Markdown 编辑器预览中不显示。在其它预览工具中展示内容。 ``` +## 主题定制 + +在目录 `src/themes` 中存放默认主题,主题使用 css 定义样式,不支持复杂的选择器。 + +```css +/* 1~6 标题样式定义 */ +h1 {} h2 {} h3 {} h4 {} h5 {} h6 {} +a { color: red; } /* 超链接样式定义 */ +del {} /* 删除线样式定义 */ +em {} /* 下划线样式定义 */ +strong {} /* 加粗样式定义 */ +u {} /* 下划线样式定义 */ +p {} /* 段落样式定义 */ +ul {} /* 无序列表样式定义 */ +ol {} /* 有序列表样式定义 */ +li {} /* 列表条目样式定义 */ +blockquote {} /* 块级引用样式定义 */ +table {} +td {} +th {} +pre {} /* 样式定义 */ +.code-highlight {} /* 代码块样式定义 */ +.code-line {} /* 代码块行样式定义 */ +.code-spans {} /* 代码块行样式定义 */ + +sup {} /* GFM 脚注样式定义 */ +.footnotes-title {} /* GFM 脚注,参考标题样式定义 */ +.footnotes-list {} /* GFM 脚注,参考列表样式定义 */ + +.image-warpper {} /* 图片父节点样式定义 */ +.image {} /* 图片样式定义 */ + +/* 部分代码高亮样式 */ +.comment {} +.property {} +.function {} +.keyword {} +.punctuation {} +.unit {} +.tag {} +.color {} +.selector {} +.quote {} +.number {} +.attr-name {} +.attr-value {} +``` + ## 部署 [![Docker Image Version (latest by date)](https://img.shields.io/docker/v/wcjiang/wxmp?logo=docker)](https://hub.docker.com/r/wcjiang/wxmp) [![Docker Image Size (latest by date)](https://img.shields.io/docker/image-size/wcjiang/wxmp?logo=docker)](https://hub.docker.com/r/wcjiang/wxmp) [![Docker Pulls](https://img.shields.io/docker/pulls/wcjiang/wxmp?logo=docker)](https://hub.docker.com/r/wcjiang/wxmp) diff --git a/package.json b/package.json index 05bee47..d1e31ed 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,7 @@ "@uiw/codemirror-theme-xcode": "^4.11.6", "@uiw/react-back-to-top": "^1.2.0", "@uiw/react-github-corners": "^1.5.15", - "@uiw/react-markdown-editor": "^5.3.2", - "@uiw/react-markdown-preview": "^4.1.0", + "@uiw/react-markdown-editor": "^5.5.1", "@wcj/dark-mode": "^1.0.15", "css-tree": "^2.2.1", "react": "^18.2.0", diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index b8471d3..f7f9ce0 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -48,7 +48,9 @@ const Section = styled.section` align-items: center; gap: 0.8rem; dark-mode { - font-size: 1.2rem; + font-size: 1.05rem; + display: block; + line-height: 12px; } a svg { display: block; diff --git a/src/conf/default.md.css b/src/conf/default.md.css deleted file mode 100644 index e8c5db6..0000000 --- a/src/conf/default.md.css +++ /dev/null @@ -1,195 +0,0 @@ -a { - color: #576b95; - text-decoration: none; - font-size: 14px; -} - -h1 { - text-align:center; - color:#3f3f3f; - line-height:1.75; - font-family:-apple-system-font,BlinkMacSystemFont,"Helvetica Neue","PingFang SC","Hiragino Sans GB","Microsoft YaHei UI","Microsoft YaHei",Arial,sans-serif; - font-size:1.2em; - font-weight:bold; - display:table; - margin:2em auto 1em; - padding:0 1em; - border-bottom:2px solid #009874; - margin-top: 0; -} - -h2 { - text-align:center; - color:#fff; - line-height:1.75; - font-family:-apple-system-font,BlinkMacSystemFont,"Helvetica Neue","PingFang SC","Hiragino Sans GB","Microsoft YaHei UI","Microsoft YaHei",Arial,sans-serif; - font-size:1.2em; - font-weight:bold; - display:table; - margin:4em auto 2em; - padding:0 0.3em; - border-radius: 0.3rem; - background:#009874; -} - -p { - font-size: 14px; -} - -h3 { - text-align:left; - color:#3f3f3f; - line-height:1.2; - font-family:-apple-system-font,BlinkMacSystemFont,"Helvetica Neue","PingFang SC","Hiragino Sans GB","Microsoft YaHei UI","Microsoft YaHei",Arial,sans-serif; - font-size:1.1em; - font-weight:bold; - margin:2em 8px 0.75em 0; - padding-left:8px; - border-left:3px solid #009874; -} - -ul { - padding-left: 1.2em; - font-size: 14px; -} - -ol { - padding-left: 1.2em; - font-size: 14px; -} - -li { - font-size: 16px; - margin: 0; - line-height: 26px; - color: rgb(30 41 59); - font-size: 14px; -} - -blockquote { - text-align:left; - line-height:1.75; - font-family:-apple-system-font,BlinkMacSystemFont,"Helvetica Neue","PingFang SC","Hiragino Sans GB","Microsoft YaHei UI","Microsoft YaHei",Arial,sans-serif; - font-size:14px; - font-style:normal; - border-left:none; - padding:0.1rem 1rem; - border-radius:4px; - background:rgba(27,31,35,.05); - margin: 1rem 0; -} - -pre { - display: block; - overflow-x: auto; - padding: 1em; - color: rgb(51, 51, 51); - background: rgb(248, 248, 248); - font-size: 14px; - font-style: normal; - font-variant-ligatures: normal; - font-variant-caps: normal; - font-weight: 400; - letter-spacing: normal; - orphans: 2; - text-indent: 0px; - text-transform: none; - widows: 2; - word-spacing: 0px; - text-decoration-style: initial; - text-decoration-color: initial; - text-align: left; - line-height: 1.5; - font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif; - border-radius: 5px; - margin: 0.9rem 0; - white-space: pre; -} - -table { - width: 100% !important; - border-collapse: collapse; - line-height: 1.35; - font-size: 90%; -} - -td { - border: 1px solid #DDD; - padding: 0.25em 0.5em; -} - -th { - background: rgb(0 0 0 / 5%); - border: 1px solid #DDD; - padding: 0.25em 0.5em; -} - -.code-highlight { - text-align: left; - line-height: 1.75; - font-family: Menlo, "Operator Mono", Consolas, Monaco, monospace; - font-size: 14px; - margin: 0px; - white-space: nowrap; -} - -.code-line { - display: block; - line-height: 1.3; -} - -.code-spans { - text-align:left; - line-height:1; - white-space:pre; - color: #009874; - background:rgba(27,31,35,.05); - padding: 0.2rem 0.3rem; - border-radius:4px; - font-weight: bold; - font-size: 14px; -} - -.footnotes-title { - font-family:-apple-system-font,BlinkMacSystemFont,"Helvetica Neue","PingFang SC","Hiragino Sans GB","Microsoft YaHei UI","Microsoft YaHei",Arial,sans-serif; - font-size:1.0rem; - font-weight:bold; - display:table; - margin:3rem 0 0.6rem 0; - padding-left: 0.2rem; -} - -.footnotes-list { - font-size: 12px; - font-style: italic; - line-height: 1.2; - margin: 0.4rem 0; -} - -figure { - margin: 0; -} - -.image-warpper { - text-align: center; - margin-bottom: 0rem; - visibility: visible; -} - -.image { - display: initial; - max-width: 100%; -} - -.comment { color: #6a737d; } -.property { color: #6f42c1; } -.function { color: #6f42c1; } -.keyword { color: #d73a49; } -.punctuation { color: #0550ae; } -.unit { color: #0550ae; } -.tag { color: #22863a; } -.selector { color: #22863a; } -.quote { color: #22863a; } -.number { color: #005cc5; } -.attr-name { color: #005cc5; } -.attr-value { color: #005cc5; } \ No newline at end of file diff --git a/src/pages/home/Preview.tsx b/src/pages/home/Preview.tsx index 184d045..5ef250c 100644 --- a/src/pages/home/Preview.tsx +++ b/src/pages/home/Preview.tsx @@ -1,6 +1,7 @@ import { MarkdownPreviewProps } from '@uiw/react-markdown-preview'; import styled from 'styled-components'; -import def from '../../conf/default.md.css'; +import { useContext } from 'react'; +import { Context, previewThemes } from '../../store/context'; import { markdownToHTML } from '../../utils/markdownToHTML'; @@ -11,7 +12,8 @@ const Warpper = styled.div` min-height: 100%; `; -export const Preview = (props: MarkdownPreviewProps, visible: boolean) => { - const html = markdownToHTML(props.source || '', def); +export const Preview = (props: MarkdownPreviewProps) => { + const { css } = useContext(Context); + const html = markdownToHTML(props.source || '', previewThemes[css].value); return ; }; diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx index 2d478c0..be43183 100644 --- a/src/pages/home/index.tsx +++ b/src/pages/home/index.tsx @@ -4,7 +4,7 @@ import { EditorView } from '@codemirror/view'; import styled from 'styled-components'; import { Preview } from './Preview'; import { copy } from './copy'; -import { theme as themeCommand } from './theme'; +import { theme as themeCommand, previeTheme } from './theme'; import { Context, themes } from '../../store/context'; import data from '../../../README.md'; @@ -15,13 +15,14 @@ const Warpper = styled.div` export const HomePage = () => { const commands = [...getCommands(), themeCommand]; const { theme } = useContext(Context); + const value = themes[theme].value; return ( ) => setTheme(ev.target.value as any); return ( ); }; @@ -53,10 +43,26 @@ export const theme: ICommand = { name: 'theme', keyCommand: 'theme', button: (command, props, opts) => , - icon: ( - - - - - ), +}; + +const ThemePreviewView: React.FC<{}> = () => { + const { css, setCss } = useContext(Context); + const handleChange = (ev: React.ChangeEvent) => setCss(ev.target.value as any); + return ( + + ); +}; + +export const previeTheme: ICommand = { + name: 'previewTtheme', + keyCommand: 'previewTtheme', + button: () => , }; diff --git a/src/store/context.tsx b/src/store/context.tsx index 1a38c4b..bca25c4 100644 --- a/src/store/context.tsx +++ b/src/store/context.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { defaultTheme } from '@uiw/react-markdown-editor'; import { abcdef } from '@uiw/codemirror-theme-abcdef'; import { androidstudio } from '@uiw/codemirror-theme-androidstudio'; import { atomone } from '@uiw/codemirror-theme-atomone'; @@ -12,45 +13,116 @@ import { githubLight, githubDark } from '@uiw/codemirror-theme-github'; import { okaidia } from '@uiw/codemirror-theme-okaidia'; import { sublime } from '@uiw/codemirror-theme-sublime'; import { xcodeLight, xcodeDark } from '@uiw/codemirror-theme-xcode'; +import defStyle from '../themes/default.md.css'; +import simpleStyle from '../themes/simple.md.css'; +import underscoreStyle from '../themes/underscore.md.css'; export const themes = { - abcdef, - androidstudio, - atomone, - bbedit, - bespin, - darcula, - dracula, - duotoneLight, - duotoneDark, - eclipse, - githubLight, - githubDark, - okaidia, - sublime, - xcodeLight, - xcodeDark, + default: { + label: '默认主题', + value: defaultTheme, + }, + abcdef: { + label: 'Abcdef Theme', + value: abcdef, + }, + androidstudio: { + label: 'Android Studio Theme', + value: androidstudio, + }, + atomone: { + label: 'Atomone Theme', + value: atomone, + }, + bbedit: { + label: 'Bbedit Theme', + value: bbedit, + }, + bespin: { + label: 'Bespin Theme', + value: bespin, + }, + darcula: { + label: 'Darcula Theme', + value: darcula, + }, + dracula: { + label: 'Dracula Theme', + value: dracula, + }, + duotoneLight: { + label: 'Duotone Light Theme', + value: duotoneLight, + }, + duotoneDark: { + label: 'Duotone Dark Theme', + value: duotoneDark, + }, + eclipse: { + label: 'Eclipse Theme', + value: eclipse, + }, + githubLight: { + label: 'Github Light Theme', + value: githubLight, + }, + githubDark: { + label: 'Github Dark Theme', + value: githubDark, + }, + okaidia: { + label: 'Okaidia Theme', + value: okaidia, + }, + sublime: { + label: 'Sublime Theme', + value: sublime, + }, + xcodeLight: { + label: 'Xcode Light Theme', + value: xcodeLight, + }, + xcodeDark: { + label: 'Xcode Dark Theme', + value: xcodeDark, + }, +}; + +export const previewThemes = { + default: { + label: '翡翠绿', + value: defStyle, + }, + simple: { + label: '简洁蓝', + value: simpleStyle, + }, + underscore: { + label: '下划线黄', + value: underscoreStyle, + }, }; export type ThemeValue = keyof typeof themes; +export type PreviewThemeValue = keyof typeof previewThemes; export interface CreateContext { - css: string; - setCss: React.Dispatch>; + css: PreviewThemeValue; + setCss: React.Dispatch>; theme: ThemeValue; setTheme: React.Dispatch>; } export const Context = React.createContext({ - css: '', + css: 'default', setCss: () => {}, - theme: 'githubLight', + theme: 'default', setTheme: () => {}, }); export const Provider: React.FC = ({ children }) => { - const [css, setCss] = React.useState(''); - const [theme, setTheme] = React.useState('githubLight'); + const [css, setCss] = React.useState('underscore'); + const [theme, setTheme] = React.useState('default'); return (