mirror of
https://github.com/jaywcjlove/wxmp.git
synced 2026-01-11 07:48:48 +08:00
feat: add url parameter to load markdown content.
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
- [x] 支持主题选择 & 编辑预览。
|
||||
- [x] 支持明暗两种主题预览。
|
||||
- [ ] 支持色盘取色,快速替换文章整体色调
|
||||
- [ ] 支持 URL 参数加载 Markdown 内容。
|
||||
- [x] 支持 URL 参数加载 Markdown 内容。
|
||||
- [x] 支持 URL 参数选择预览主题。
|
||||
|
||||
### 支持代码块样式
|
||||
@@ -116,9 +116,9 @@ https://<URL>?md=<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
|
||||
```
|
||||
|
||||
## 主题定制
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.9",
|
||||
"@tanstack/react-query": "^4.2.3",
|
||||
"@uiw/codemirror-theme-abcdef": "^4.11.6",
|
||||
"@uiw/codemirror-theme-androidstudio": "^4.11.6",
|
||||
"@uiw/codemirror-theme-atomone": "^4.11.6",
|
||||
@@ -55,10 +56,10 @@
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@types/styled-components": "^5.1.25",
|
||||
"husky": "^8.0.1",
|
||||
"prettier": "^2.7.1",
|
||||
"pretty-quick": "~3.1.3",
|
||||
"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": {
|
||||
"extends": [
|
||||
|
||||
@@ -4,8 +4,9 @@ import { HashRouter } from 'react-router-dom';
|
||||
import BackToUp from '@uiw/react-back-to-top';
|
||||
import { Toaster } from 'react-hot-toast';
|
||||
import { createGlobalStyle } from 'styled-components';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import App from './App';
|
||||
import { Provider } from './store/context';
|
||||
import { Provider } from './store/Provider';
|
||||
|
||||
export const GlobalStyle = createGlobalStyle`
|
||||
[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 container = document.getElementById('root');
|
||||
@@ -61,8 +63,10 @@ root.render(
|
||||
<Toaster />
|
||||
<BackToUp style={style}>Top</BackToUp>
|
||||
<GlobalStyle />
|
||||
<Provider>
|
||||
<App />
|
||||
</Provider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Provider>
|
||||
<App />
|
||||
</Provider>
|
||||
</QueryClientProvider>
|
||||
</HashRouter>,
|
||||
);
|
||||
|
||||
@@ -14,16 +14,18 @@ export const Warpper = styled.div`
|
||||
|
||||
export const HomePage = () => {
|
||||
const commands = [...getCommands(), themeCommand];
|
||||
const { theme, markdown, setMarkdown } = useContext(Context);
|
||||
const { theme, markdown, isLoading, setMarkdown } = useContext(Context);
|
||||
const themeValue = themes[theme].value;
|
||||
const handleChange = (value: string) => setMarkdown(value);
|
||||
console.log(isLoading);
|
||||
return (
|
||||
<Warpper>
|
||||
<MarkdownEditor
|
||||
value={markdown}
|
||||
toolbars={commands}
|
||||
theme={themeValue}
|
||||
toolbarsMode={[cssCommand, previeTheme, copy, 'preview', 'fullscreen']}
|
||||
readOnly={isLoading}
|
||||
toolbarsMode={[cssCommand, previeTheme, copy, 'fullscreen', 'preview']}
|
||||
extensions={[EditorView.lineWrapping]}
|
||||
renderPreview={Preview}
|
||||
onChange={handleChange}
|
||||
|
||||
@@ -12,8 +12,8 @@ import { Warpper } from '../home';
|
||||
|
||||
export const EditorPage = () => {
|
||||
const commands = [themeTitle, themeCommand, previousCommand];
|
||||
const toolbarsMode: IMarkdownEditor['toolbarsMode'] = [previeTheme, copy, 'preview', 'fullscreen'];
|
||||
const { theme, css, setCss } = useContext(Context);
|
||||
const toolbarsMode: IMarkdownEditor['toolbarsMode'] = [previeTheme, copy, 'fullscreen', 'preview'];
|
||||
const { theme, css, setCss, isLoading } = useContext(Context);
|
||||
const value = themes[theme].value;
|
||||
const handleChange = (value: string) => setCss(value);
|
||||
return (
|
||||
@@ -21,6 +21,7 @@ export const EditorPage = () => {
|
||||
<MarkdownEditor
|
||||
value={css}
|
||||
theme={value}
|
||||
readOnly={isLoading}
|
||||
toolbars={commands}
|
||||
toolbarsMode={toolbarsMode}
|
||||
reExtensions={[EditorView.lineWrapping, cssLang()]}
|
||||
|
||||
49
src/store/Provider.tsx
Normal file
49
src/store/Provider.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
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';
|
||||
@@ -115,6 +114,8 @@ export type ThemeValue = keyof typeof themes;
|
||||
export type PreviewThemeValue = keyof typeof previewThemes;
|
||||
|
||||
export interface CreateContext {
|
||||
isLoading: boolean;
|
||||
setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
markdown: string;
|
||||
setMarkdown: React.Dispatch<React.SetStateAction<string>>;
|
||||
css: string;
|
||||
@@ -126,6 +127,8 @@ export interface CreateContext {
|
||||
}
|
||||
|
||||
export const Context = React.createContext<CreateContext>({
|
||||
isLoading: true,
|
||||
setIsLoading: () => {},
|
||||
markdown: data.source,
|
||||
setMarkdown: () => {},
|
||||
css: previewThemes['underscore'].value,
|
||||
@@ -135,35 +138,3 @@ export const Context = React.createContext<CreateContext>({
|
||||
theme: 'default',
|
||||
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
12
src/store/getMdSource.ts
Normal 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;
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -103,7 +103,7 @@ th {
|
||||
.code-spans {
|
||||
text-align: left;
|
||||
line-height: 1;
|
||||
white-space: pre;
|
||||
white-space: initial;
|
||||
background: rgba(27, 31, 35, 0.05);
|
||||
padding: 0.2em 0.6em;
|
||||
border-radius: 0.6em;
|
||||
|
||||
@@ -142,7 +142,7 @@ th {
|
||||
.code-spans {
|
||||
text-align: left;
|
||||
line-height: 1;
|
||||
white-space: pre;
|
||||
white-space: initial;
|
||||
color: #009874;
|
||||
background: rgba(27, 31, 35, 0.05);
|
||||
padding: 0.2em 0.6em;
|
||||
|
||||
@@ -142,7 +142,7 @@ th {
|
||||
.code-spans {
|
||||
text-align: left;
|
||||
line-height: 1;
|
||||
white-space: pre;
|
||||
white-space: initial;
|
||||
color: #0f4c81;
|
||||
background: rgba(27, 31, 35, 0.05);
|
||||
padding: 0.2em 0.6em;
|
||||
|
||||
@@ -139,7 +139,7 @@ th {
|
||||
.code-spans {
|
||||
text-align: left;
|
||||
line-height: 1;
|
||||
white-space: pre;
|
||||
white-space: initial;
|
||||
color: #ffb11b;
|
||||
background: rgba(27, 31, 35, 0.05);
|
||||
padding: 0.2em 0.6em;
|
||||
|
||||
Reference in New Issue
Block a user