feat: add url parameter to load markdown content.

This commit is contained in:
jaywcjlove
2022-09-03 16:40:11 +08:00
parent 57b719c163
commit b1dc77e98b
12 changed files with 92 additions and 52 deletions

View File

@@ -15,7 +15,7 @@
- [x] 支持主题选择 & 编辑预览。 - [x] 支持主题选择 & 编辑预览。
- [x] 支持明暗两种主题预览。 - [x] 支持明暗两种主题预览。
- [ ] 支持色盘取色,快速替换文章整体色调 - [ ] 支持色盘取色,快速替换文章整体色调
- [ ] 支持 URL 参数加载 Markdown 内容。 - [x] 支持 URL 参数加载 Markdown 内容。
- [x] 支持 URL 参数选择预览主题。 - [x] 支持 URL 参数选择预览主题。
### 支持代码块样式 ### 支持代码块样式
@@ -116,9 +116,9 @@ https://<URL>?md=<Markdown 资源 URL>
加载 Markdown 内容的示例 URL 加载 Markdown 内容的示例 URL
``` ```
https://jaywcjlove.github.io/wxmp/#/?theme=underscore&md=https%3A%2F%2Fraw.githubusercontent.com%2Fuiwjs%2Freact-markdown-editor%2Fmaster%2FREADME.md https://jaywcjlove.github.io/wxmp/#/?theme=underscore&md=https://raw.githubusercontent.com/jaywcjlove/c-tutorial/master/README.md
Markdown URL 地址: https://raw.githubusercontent.com/uiwjs/react-markdown-editor/master/README.md Markdown URL 地址: https://raw.githubusercontent.com/jaywcjlove/c-tutorial/master/README.md
``` ```
## 主题定制 ## 主题定制

View File

@@ -12,6 +12,7 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.9", "@babel/runtime": "^7.18.9",
"@tanstack/react-query": "^4.2.3",
"@uiw/codemirror-theme-abcdef": "^4.11.6", "@uiw/codemirror-theme-abcdef": "^4.11.6",
"@uiw/codemirror-theme-androidstudio": "^4.11.6", "@uiw/codemirror-theme-androidstudio": "^4.11.6",
"@uiw/codemirror-theme-atomone": "^4.11.6", "@uiw/codemirror-theme-atomone": "^4.11.6",
@@ -55,10 +56,10 @@
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"@types/styled-components": "^5.1.25", "@types/styled-components": "^5.1.25",
"husky": "^8.0.1", "husky": "^8.0.1",
"prettier": "^2.7.1",
"pretty-quick": "~3.1.3",
"kkt": "^7.2.0", "kkt": "^7.2.0",
"markdown-react-code-preview-loader": "^2.1.2" "markdown-react-code-preview-loader": "^2.1.2",
"prettier": "^2.7.1",
"pretty-quick": "~3.1.3"
}, },
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [

View File

@@ -4,8 +4,9 @@ import { HashRouter } from 'react-router-dom';
import BackToUp from '@uiw/react-back-to-top'; import BackToUp from '@uiw/react-back-to-top';
import { Toaster } from 'react-hot-toast'; import { Toaster } from 'react-hot-toast';
import { createGlobalStyle } from 'styled-components'; import { createGlobalStyle } from 'styled-components';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import App from './App'; import App from './App';
import { Provider } from './store/context'; import { Provider } from './store/Provider';
export const GlobalStyle = createGlobalStyle` export const GlobalStyle = createGlobalStyle`
[data-color-mode*='dark'], [data-color-mode*='dark'] body { [data-color-mode*='dark'], [data-color-mode*='dark'] body {
@@ -52,6 +53,7 @@ export const GlobalStyle = createGlobalStyle`
} }
`; `;
const queryClient = new QueryClient();
const style: React.CSSProperties = { zIndex: 999 }; const style: React.CSSProperties = { zIndex: 999 };
const container = document.getElementById('root'); const container = document.getElementById('root');
@@ -61,8 +63,10 @@ root.render(
<Toaster /> <Toaster />
<BackToUp style={style}>Top</BackToUp> <BackToUp style={style}>Top</BackToUp>
<GlobalStyle /> <GlobalStyle />
<Provider> <QueryClientProvider client={queryClient}>
<App /> <Provider>
</Provider> <App />
</Provider>
</QueryClientProvider>
</HashRouter>, </HashRouter>,
); );

View File

@@ -14,16 +14,18 @@ export const Warpper = styled.div`
export const HomePage = () => { export const HomePage = () => {
const commands = [...getCommands(), themeCommand]; const commands = [...getCommands(), themeCommand];
const { theme, markdown, setMarkdown } = useContext(Context); const { theme, markdown, isLoading, setMarkdown } = useContext(Context);
const themeValue = themes[theme].value; const themeValue = themes[theme].value;
const handleChange = (value: string) => setMarkdown(value); const handleChange = (value: string) => setMarkdown(value);
console.log(isLoading);
return ( return (
<Warpper> <Warpper>
<MarkdownEditor <MarkdownEditor
value={markdown} value={markdown}
toolbars={commands} toolbars={commands}
theme={themeValue} theme={themeValue}
toolbarsMode={[cssCommand, previeTheme, copy, 'preview', 'fullscreen']} readOnly={isLoading}
toolbarsMode={[cssCommand, previeTheme, copy, 'fullscreen', 'preview']}
extensions={[EditorView.lineWrapping]} extensions={[EditorView.lineWrapping]}
renderPreview={Preview} renderPreview={Preview}
onChange={handleChange} onChange={handleChange}

View File

@@ -12,8 +12,8 @@ import { Warpper } from '../home';
export const EditorPage = () => { export const EditorPage = () => {
const commands = [themeTitle, themeCommand, previousCommand]; const commands = [themeTitle, themeCommand, previousCommand];
const toolbarsMode: IMarkdownEditor['toolbarsMode'] = [previeTheme, copy, 'preview', 'fullscreen']; const toolbarsMode: IMarkdownEditor['toolbarsMode'] = [previeTheme, copy, 'fullscreen', 'preview'];
const { theme, css, setCss } = useContext(Context); const { theme, css, setCss, isLoading } = useContext(Context);
const value = themes[theme].value; const value = themes[theme].value;
const handleChange = (value: string) => setCss(value); const handleChange = (value: string) => setCss(value);
return ( return (
@@ -21,6 +21,7 @@ export const EditorPage = () => {
<MarkdownEditor <MarkdownEditor
value={css} value={css}
theme={value} theme={value}
readOnly={isLoading}
toolbars={commands} toolbars={commands}
toolbarsMode={toolbarsMode} toolbarsMode={toolbarsMode}
reExtensions={[EditorView.lineWrapping, cssLang()]} reExtensions={[EditorView.lineWrapping, cssLang()]}

49
src/store/Provider.tsx Normal file
View File

@@ -0,0 +1,49 @@
import React, { useEffect } from 'react';
import { useSearchParams } from 'react-router-dom';
import { PreviewThemeValue, previewThemes, ThemeValue, Context } from './context';
import { useMdSource } from './getMdSource';
import data from '../../README.md';
export const Provider: React.FC<React.PropsWithChildren> = ({ children }) => {
const [searchParams, setSearchParams] = useSearchParams();
const paramPreviewTheme = searchParams.get('theme') as PreviewThemeValue;
const initPreviewTheme = paramPreviewTheme || 'underscore';
const mdurl = searchParams.get('md');
const [markdown, setMarkdown] = React.useState<string>(mdurl ? '' : data.source);
const [css, setCss] = React.useState<string>(previewThemes[initPreviewTheme].value);
const [previewTheme, setPreviewTheme] = React.useState<PreviewThemeValue>(initPreviewTheme);
const [theme, setTheme] = React.useState<ThemeValue>('default');
const [isLoading, setIsLoading] = React.useState<boolean>(true);
const { data: mddata, isLoading: loading } = useMdSource(mdurl);
useEffect(() => {
if (paramPreviewTheme !== previewTheme) {
searchParams.set('theme', previewTheme);
setSearchParams(searchParams);
}
}, [paramPreviewTheme, previewTheme, searchParams, setSearchParams]);
useEffect(() => {
if (mdurl) {
setMarkdown(mddata || '');
}
}, [mddata, mdurl]);
useEffect(() => setIsLoading(loading), [loading]);
return (
<Context.Provider
value={{
isLoading,
setIsLoading,
markdown,
setMarkdown,
css,
setCss,
previewTheme,
setPreviewTheme,
theme,
setTheme,
}}
>
{children}
</Context.Provider>
);
};

View File

@@ -1,5 +1,4 @@
import React, { useEffect } from 'react'; import React from 'react';
import { useSearchParams } from 'react-router-dom';
import { defaultTheme } from '@uiw/react-markdown-editor'; import { defaultTheme } from '@uiw/react-markdown-editor';
import { abcdef } from '@uiw/codemirror-theme-abcdef'; import { abcdef } from '@uiw/codemirror-theme-abcdef';
import { androidstudio } from '@uiw/codemirror-theme-androidstudio'; import { androidstudio } from '@uiw/codemirror-theme-androidstudio';
@@ -115,6 +114,8 @@ export type ThemeValue = keyof typeof themes;
export type PreviewThemeValue = keyof typeof previewThemes; export type PreviewThemeValue = keyof typeof previewThemes;
export interface CreateContext { export interface CreateContext {
isLoading: boolean;
setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
markdown: string; markdown: string;
setMarkdown: React.Dispatch<React.SetStateAction<string>>; setMarkdown: React.Dispatch<React.SetStateAction<string>>;
css: string; css: string;
@@ -126,6 +127,8 @@ export interface CreateContext {
} }
export const Context = React.createContext<CreateContext>({ export const Context = React.createContext<CreateContext>({
isLoading: true,
setIsLoading: () => {},
markdown: data.source, markdown: data.source,
setMarkdown: () => {}, setMarkdown: () => {},
css: previewThemes['underscore'].value, css: previewThemes['underscore'].value,
@@ -135,35 +138,3 @@ export const Context = React.createContext<CreateContext>({
theme: 'default', theme: 'default',
setTheme: () => {}, setTheme: () => {},
}); });
export const Provider: React.FC<React.PropsWithChildren> = ({ children }) => {
const [searchParams, setSearchParams] = useSearchParams();
const paramPreviewTheme = searchParams.get('theme') as PreviewThemeValue;
const initPreviewTheme = paramPreviewTheme || 'underscore';
const [markdown, setMarkdown] = React.useState<string>(data.source);
const [css, setCss] = React.useState<string>(previewThemes[initPreviewTheme].value);
const [previewTheme, setPreviewTheme] = React.useState<PreviewThemeValue>(initPreviewTheme);
const [theme, setTheme] = React.useState<ThemeValue>('default');
useEffect(() => {
if (paramPreviewTheme !== previewTheme) {
searchParams.set('theme', previewTheme);
setSearchParams(searchParams);
}
}, [paramPreviewTheme, previewTheme, searchParams, setSearchParams]);
return (
<Context.Provider
value={{
markdown,
setMarkdown,
css,
setCss,
previewTheme,
setPreviewTheme,
theme,
setTheme,
}}
>
{children}
</Context.Provider>
);
};

12
src/store/getMdSource.ts Normal file
View File

@@ -0,0 +1,12 @@
import { useQuery } from '@tanstack/react-query';
export const useMdSource = (url: string | null) => {
return useQuery(['database-list', url], () => {
if (!url) return Promise.resolve('');
return fetch(url)
.then((response) => response.text())
.then((data) => {
return data;
});
});
};

View File

@@ -103,7 +103,7 @@ th {
.code-spans { .code-spans {
text-align: left; text-align: left;
line-height: 1; line-height: 1;
white-space: pre; white-space: initial;
background: rgba(27, 31, 35, 0.05); background: rgba(27, 31, 35, 0.05);
padding: 0.2em 0.6em; padding: 0.2em 0.6em;
border-radius: 0.6em; border-radius: 0.6em;

View File

@@ -142,7 +142,7 @@ th {
.code-spans { .code-spans {
text-align: left; text-align: left;
line-height: 1; line-height: 1;
white-space: pre; white-space: initial;
color: #009874; color: #009874;
background: rgba(27, 31, 35, 0.05); background: rgba(27, 31, 35, 0.05);
padding: 0.2em 0.6em; padding: 0.2em 0.6em;

View File

@@ -142,7 +142,7 @@ th {
.code-spans { .code-spans {
text-align: left; text-align: left;
line-height: 1; line-height: 1;
white-space: pre; white-space: initial;
color: #0f4c81; color: #0f4c81;
background: rgba(27, 31, 35, 0.05); background: rgba(27, 31, 35, 0.05);
padding: 0.2em 0.6em; padding: 0.2em 0.6em;

View File

@@ -139,7 +139,7 @@ th {
.code-spans { .code-spans {
text-align: left; text-align: left;
line-height: 1; line-height: 1;
white-space: pre; white-space: initial;
color: #ffb11b; color: #ffb11b;
background: rgba(27, 31, 35, 0.05); background: rgba(27, 31, 35, 0.05);
padding: 0.2em 0.6em; padding: 0.2em 0.6em;