mirror of
https://github.com/jaywcjlove/wxmp.git
synced 2026-01-10 07:18:47 +08:00
feat: support custom style & ignore content syntax.
This commit is contained in:
47
README.md
47
README.md
@@ -4,7 +4,9 @@
|
||||
|
||||
</div>
|
||||
|
||||
微信公众号文章 Markdown 编辑器,使用 markdown 语法创建一篇简介美观大方的微信公众号图文。由于发版本麻烦,和一些功能无法扩展停滞开发了,未来不再开发 Chrome 的工具(暂存在 chrome 分支),通过 web 版本定制更丰富的功能。
|
||||

|
||||
|
||||
微信公众号文章 Markdown 在线编辑器,使用 markdown 语法创建一篇简介美观大方的微信公众号图文。由于发版本麻烦,和一些功能无法扩展停滞开发了,未来不再开发 Chrome 的工具(暂存在 chrome 分支),通过 web 版本定制更丰富的功能。
|
||||
|
||||
## 功能特性
|
||||
|
||||
@@ -56,10 +58,11 @@ Inline Code `{code: 0}`
|
||||
|
||||
### 支持 GFM 脚注
|
||||
|
||||
这是一个简单的脚注[^1]。 页面最后有一些额外的文字描述。注意这不是完整的注脚[^2]。
|
||||
这是一个简单的 Markdown[^1] 语法的脚注[^2]。 页面最后有一些额外的文字描述。注意这不是完整的注脚[^3]特性。
|
||||
|
||||
[^1]: https://github.github.com/gfm/
|
||||
[^2]: 微信文章不支持锚点跳转和打开第三方 URL 超链接,所以不支持完整的注脚
|
||||
[^1]: GitHub 风格的 Markdown 规范 https://github.github.com/gfm/
|
||||
[^2]: 脚注 https://github.blog/changelog/2021-09-30-footnotes-now-supported-in-markdown-fields/
|
||||
[^3]: 微信文章不支持锚点跳转和打开第三方 URL 超链接,所以不支持完整的注脚特性。
|
||||
|
||||
### 支持注释
|
||||
|
||||
@@ -72,6 +75,31 @@ Inline Code `{code: 0}`
|
||||
音 <rp></rp><rt>yin</rt><rp></rp>
|
||||
</ruby>
|
||||
|
||||
### 支持自定义样式
|
||||
<!--rehype:style=color: red;-->
|
||||
|
||||
在 Markdown 中 HTML 注释也可以用在 markdown 中,利用这一特点,为一些内容自定一样式。使用 HTML 注释 `<!--rehype:xxx-->`<!--rehype:style=color: red;background: #ff000033;--> 让 Markdown 支持样式自定义。
|
||||
|
||||
```markdown
|
||||
## 定义标题样式
|
||||
<!--rehype:style=display: flex; height: 230px; align-items: center; justify-content: center; font-size: 38px;-->
|
||||
|
||||
支持对某些文字变更样式,如_文字颜色_<!--rehype:style=color: red;-->,文字颜色将被设置为红色(red)。
|
||||
```
|
||||
|
||||
⚠️ 注意:这一特性可能适用于有一定 css 前端基础知识的用户,不过它也非常简单,使用 `<!--rehype:style=` 开始,`-->` 结束,中间包裹 css 样式,如 `color: red;` 设置文字红色。
|
||||
|
||||
|
||||
### 标记忽略内容
|
||||
|
||||
此特性利用 HTML 注释在 markdown 中被忽略的特性,标记需要忽略的内容,标记开始 `<!--rehype:ignore:start-->`,标记结束 `<!--rehype:ignore:end-->`,被标记的内容在微信 Markdown 编辑器预览中不显示。在其它预览工具中展示内容,比如 GitHub 中能展示。
|
||||
|
||||
```markdown
|
||||
# 注释忽略
|
||||
|
||||
<!--rehype:ignore:start-->内容在微信 Markdown 编辑器预览中不显示。在其它预览工具中展示内容。<!--rehype:ignore:end-->
|
||||
```
|
||||
|
||||
## 部署
|
||||
|
||||
[](https://hub.docker.com/r/wcjiang/wxmp) [](https://hub.docker.com/r/wcjiang/wxmp) [](https://hub.docker.com/r/wcjiang/wxmp)
|
||||
@@ -98,16 +126,19 @@ docker run --name wxmp -itd -p 96611:3000 ghcr.io/jaywcjlove/wxmp:latest
|
||||
http://localhost:96611/
|
||||
```
|
||||
|
||||
## Contributors
|
||||
## 贡献者
|
||||
|
||||
As always, thanks to our amazing contributors!
|
||||
一如既往,感谢我们出色的贡献者!
|
||||
|
||||
<a href="https://github.com/jaywcjlove/wxmp/graphs/contributors">
|
||||
<img src="https://jaywcjlove.github.io/wxmp/CONTRIBUTORS.svg" />
|
||||
</a>
|
||||
|
||||
Made with [github-action-contributors](https://github.com/jaywcjlove/github-action-contributors).
|
||||
上图贡献者列表,由 [action-contributors](https://github.com/jaywcjlove/github-action-contributors)[^4] 自动生成贡献者图片。
|
||||
|
||||
|
||||
[^4]: Action Contributors https://github.com/jaywcjlove/github-action-contributors
|
||||
|
||||
## License
|
||||
|
||||
Licensed under the MIT License.
|
||||
根据 MIT 许可证获得许可。
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hot-toast": "^2.3.0",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"rehype-attr": "^2.0.8",
|
||||
"rehype-ignore": "^1.0.1",
|
||||
"rehype-prism-plus": "^1.5.0",
|
||||
"rehype-raw": "^6.1.1",
|
||||
"rehype-stringify": "^9.0.3",
|
||||
|
||||
@@ -163,6 +163,21 @@ th {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RootContent, Element, Text } from 'hast';
|
||||
import { RootContent, Element, Text, Root } from 'hast';
|
||||
|
||||
export const getBlock = (data: any, str: string = '') => {
|
||||
if (data && data.data && data.data.type === 'Declaration') {
|
||||
@@ -87,4 +87,14 @@ export const footnotesLabel = (node: Element) => {
|
||||
type: 'text',
|
||||
value: `[${label}]`
|
||||
}];
|
||||
}
|
||||
|
||||
export const imagesStyle = (node: Element, parent: Root | Element | null) => {
|
||||
if (parent?.type === 'element' && parent.tagName === 'p' && node?.type === 'element' && node.tagName === 'img') {
|
||||
parent.tagName = 'figure';
|
||||
if (!parent.properties) parent.properties = {}
|
||||
parent.properties.className = ['image-warpper']
|
||||
if (!node.properties) node.properties = {}
|
||||
node.properties.className = ['image']
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,11 @@ import remarkGfm from 'remark-gfm';
|
||||
import remarkRehype from 'remark-rehype';
|
||||
import rehypePrism from 'rehype-prism-plus';
|
||||
import rehypeRaw from 'rehype-raw';
|
||||
import rehypeAttrs from 'rehype-attr';
|
||||
import rehypeIgnore from 'rehype-ignore';
|
||||
import rehypeRewrite from 'rehype-rewrite';
|
||||
import stringify from 'rehype-stringify';
|
||||
import { cssdata, spaceEscape, footnotes, footnotesLabel } from './css';
|
||||
import { cssdata, spaceEscape, footnotes, footnotesLabel, imagesStyle } from './css';
|
||||
|
||||
export type MarkdownToHTMLOptions = {
|
||||
|
||||
@@ -25,14 +27,18 @@ export function markdownToHTML(md: string, css: string, options: MarkdownToHTMLO
|
||||
});
|
||||
// @ts-ignore
|
||||
const data = cssdata(ast.children.head);
|
||||
console.log(data)
|
||||
const processor = unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkGfm)
|
||||
.use(remarkRehype, { allowDangerousHtml: true })
|
||||
.use(rehypePrism)
|
||||
.use(remarkGfm)
|
||||
.use(rehypeRaw)
|
||||
.use(rehypeIgnore, { })
|
||||
.use(rehypeAttrs, { properties: 'attr' })
|
||||
.use(rehypeRewrite, {
|
||||
rewrite: (node, index, parent) => {
|
||||
// @ts-ignore
|
||||
if (node?.type === 'element' && node?.tagName === 'code' && parent?.type === 'element' && parent?.tagName === 'pre') {
|
||||
spaceEscape(node)
|
||||
}
|
||||
@@ -42,17 +48,23 @@ export function markdownToHTML(md: string, css: string, options: MarkdownToHTMLO
|
||||
if (node?.type === 'element' && node.tagName === 'sup') {
|
||||
footnotesLabel(node)
|
||||
}
|
||||
if (node?.type === 'element' && node.tagName === 'img') {
|
||||
imagesStyle(node, parent)
|
||||
}
|
||||
// Code Spans style
|
||||
if (node?.type === 'element' && node?.tagName === 'code' && parent?.type === 'element' && parent?.tagName !== 'pre') {
|
||||
if (!node.properties) node.properties = {}
|
||||
node.properties!.className = ['code-spans'];
|
||||
}
|
||||
if (node?.type === 'element') {
|
||||
if (node.tagName === 'input' && parent?.type === 'element') {
|
||||
if (parent && parent.type === 'element') {
|
||||
parent.children = parent?.children.filter(elm => (elm as Element).tagName !== 'input')
|
||||
}
|
||||
return;
|
||||
// List TODO style
|
||||
if (parent?.type === 'element' && node?.type === 'element' && node?.tagName === 'input') {
|
||||
if (parent && parent.type === 'element') {
|
||||
parent.children = parent?.children.filter(elm => (elm as Element).tagName !== 'input')
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Support *.md.css
|
||||
if (node?.type === 'element') {
|
||||
if (!node.properties) {
|
||||
node.properties = {};
|
||||
}
|
||||
@@ -67,7 +79,7 @@ export function markdownToHTML(md: string, css: string, options: MarkdownToHTMLO
|
||||
}
|
||||
if (!style) style = data[node.tagName];
|
||||
if (style) {
|
||||
node.properties.style = style;
|
||||
node.properties.style = style + (node.properties.style || '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user