diff --git a/plugins/gatsby-remark-custom/index.mjs b/plugins/gatsby-remark-custom/index.mjs index 91a5ac8..acbf5b0 100644 --- a/plugins/gatsby-remark-custom/index.mjs +++ b/plugins/gatsby-remark-custom/index.mjs @@ -1,6 +1,7 @@ import mdastDisableLocalLink from "./mdastDisableLocalLink.mjs"; import mdastImageControl from "./mdastImageControl.mjs"; import remarkSpoiler from "./remarkSpoiler.mjs"; +import remarkMark from "./remarkMark.mjs"; function gatsbyRemarkCustom({ markdownAST }) { // 禁用指向本地文件的链接 @@ -11,6 +12,11 @@ function gatsbyRemarkCustom({ markdownAST }) { } // 注入自定义remark插件 -gatsbyRemarkCustom.setParserPlugins = () => [remarkSpoiler]; +gatsbyRemarkCustom.setParserPlugins = () => [ + // 支持标记语法 + remarkMark, + // 支持Spoiler语法 + remarkSpoiler, +]; export default gatsbyRemarkCustom; diff --git a/plugins/gatsby-remark-custom/remarkMark.mjs b/plugins/gatsby-remark-custom/remarkMark.mjs new file mode 100644 index 0000000..6b9eaaf --- /dev/null +++ b/plugins/gatsby-remark-custom/remarkMark.mjs @@ -0,0 +1,123 @@ +/** + * @import {Processor} from 'unified' + */ + +import { markdownLineEnding } from "micromark-util-character"; +import { factorySpace } from "micromark-factory-space"; +import { codes, types, constants } from "micromark-util-symbol"; + +function micromarkExt() { + const marker = { + partial: true, + tokenize: function (effects, ok, nok) { + let markerSize = 0; + if (this.previous === codes.equalsTo) { + return nok; + } + const start = function (code) { + effects.enter("markMarker"); + return marker; + }; + const marker = function (code) { + if (code === codes.equalsTo) { + effects.consume(code); + markerSize++; + return marker; + } + if (markerSize == 2) { + effects.exit("markMarker"); + markerSize = 0; + return ok; + } + return nok; + }; + return factorySpace(effects, start, types.whitespace); + }, + }; + + const mark = { + name: "mark", + tokenize: function (effects, ok, nok) { + const start = function (code) { + effects.enter("mark"); + return effects.attempt(marker, factorySpace(effects, contentStart, types.whitespace), nok); + }; + const contentStart = function (code) { + effects.enter(types.chunkText, { + contentType: constants.contentTypeText, + }); + return content; + }; + const content = function (code) { + return effects.check(marker, factorySpace(effects, contentAfter, types.whitespace), comsumeData); + }; + const comsumeData = function (code) { + if (markdownLineEnding(code) || code === codes.eof) { + return nok; + } + effects.consume(code); + return content; + }; + const contentAfter = function (code) { + effects.exit(types.chunkText); + return effects.attempt(marker, after, nok); + }; + const after = function (code) { + effects.exit("mark"); + return ok; + }; + return start; + }, + }; + + return { + text: { + [codes.equalsTo]: mark, + }, + }; +} + +function fromMarkdownExt() { + const enterMark = function (token) { + this.enter( + { + type: "mark", + children: [], + }, + token + ); + }; + const exitMark = function (token) { + const node = this.exit(token); + node.data = { + ...node.data, + hName: "mark", + hProperties: { + className: "m-mark", + }, + }; + }; + return { + enter: { + mark: enterMark, + }, + exit: { + mark: exitMark, + }, + }; +} + +export default function remarkMark() { + const self = /** @type {Processor} */ (this); + const data = self.data(); + function add(key, value) { + if (Array.isArray(data[key])) { + data[key].push(value); + } else { + data[key] = [value]; + } + } + + add("micromarkExtensions", micromarkExt()); + add("fromMarkdownExtensions", fromMarkdownExt()); +} diff --git a/plugins/gatsby-remark-custom/remarkSpoiler.mjs b/plugins/gatsby-remark-custom/remarkSpoiler.mjs index 72c20da..dbfb207 100644 --- a/plugins/gatsby-remark-custom/remarkSpoiler.mjs +++ b/plugins/gatsby-remark-custom/remarkSpoiler.mjs @@ -6,76 +6,70 @@ import { markdownLineEnding } from "micromark-util-character"; import { factorySpace } from "micromark-factory-space"; import { codes, types, constants } from "micromark-util-symbol"; -function tokenizeSpoiler(effects, ok, nok) { - const self = this; - const start = function (code) { - effects.enter("spoiler"); - return effects.attempt(marker, factorySpace(effects, contentStart, types.whitespace), nok); - }; - const contentStart = function (code) { - effects.enter(types.chunkText, { - contentType: constants.contentTypeText, - }); - return content; - }; - const content = function (code) { - return effects.check(marker, factorySpace(effects, contentAfter, types.whitespace), comsumeData); - }; - const comsumeData = function (code) { - if (markdownLineEnding(code) || code === codes.eof) { - return nok; - } - effects.consume(code); - return content; - }; - const contentAfter = function (code) { - effects.exit(types.chunkText); - return effects.attempt(marker, after, nok); - }; - const after = function (code) { - effects.exit("spoiler"); - return ok; +function micromarkExt() { + const marker = { + partial: true, + tokenize: function (effects, ok, nok) { + let markerSize = 0; + if (this.previous === codes.exclamationMark) { + return nok; + } + const start = function (code) { + effects.enter("spoilerMarker"); + return marker; + }; + const marker = function (code) { + if (code === codes.exclamationMark) { + effects.consume(code); + markerSize++; + return marker; + } + if (markerSize == 2) { + effects.exit("spoilerMarker"); + markerSize = 0; + return ok; + } + return nok; + }; + return factorySpace(effects, start, types.whitespace); + }, }; - return start; -} -// 定义分界符 (!!) 的 Tokenizer -const tokenizeMarker = function (effects, ok, nok) { - let markerSize = 0; - if (this.previous === codes.exclamationMark) { - return nok; - } - const start = function (code) { - effects.enter("spoilerMarker"); - return marker; - }; - const marker = function (code) { - if (code === codes.exclamationMark) { - effects.consume(code); - markerSize++; - return marker; - } - if (markerSize == 2) { - effects.exit("spoilerMarker"); - markerSize = 0; - return ok; - } - return nok; + const spoiler = { + name: "spoiler", + tokenize: function (effects, ok, nok) { + const start = function (code) { + effects.enter("spoiler"); + return effects.attempt(marker, factorySpace(effects, contentStart, types.whitespace), nok); + }; + const contentStart = function (code) { + effects.enter(types.chunkText, { + contentType: constants.contentTypeText, + }); + return content; + }; + const content = function (code) { + return effects.check(marker, factorySpace(effects, contentAfter, types.whitespace), comsumeData); + }; + const comsumeData = function (code) { + if (markdownLineEnding(code) || code === codes.eof) { + return nok; + } + effects.consume(code); + return content; + }; + const contentAfter = function (code) { + effects.exit(types.chunkText); + return effects.attempt(marker, after, nok); + }; + const after = function (code) { + effects.exit("spoiler"); + return ok; + }; + return start; + }, }; - return factorySpace(effects, start, types.whitespace); -}; - -const marker = { - tokenize: tokenizeMarker, - partial: true, -}; - -const spoiler = { - name: "spoiler", - tokenize: tokenizeSpoiler, -}; -function syntax() { return { text: { [codes.exclamationMark]: spoiler, @@ -83,7 +77,7 @@ function syntax() { }; } -function fromMarkdown() { +function fromMarkdownExt() { const enterSpoiler = function (token) { this.enter( { @@ -97,7 +91,7 @@ function fromMarkdown() { const node = this.exit(token); node.data = { ...node.data, - hName: "span", + hName: "del", hProperties: { className: "m-spoiler", }, @@ -124,6 +118,6 @@ export default function remarkSpoiler() { } } - add("micromarkExtensions", syntax()); - add("fromMarkdownExtensions", fromMarkdown()); + add("micromarkExtensions", micromarkExt()); + add("fromMarkdownExtensions", fromMarkdownExt()); } diff --git a/src/style/typography-extend.less b/src/style/typography-extend.less index 7e65a46..695bf28 100644 --- a/src/style/typography-extend.less +++ b/src/style/typography-extend.less @@ -10,12 +10,20 @@ cursor: not-allowed; } + // 标记 + &mark { + background-color: #fff8c5; + padding: 2px 4px; + border-radius: 4px; + } + // Spoiler &spoiler { color: transparent; background-color: black; cursor: pointer; border-radius: 4px; + text-decoration: none; transition: color 250ms cubic-bezier(0.4, 0, 0.2, 1), background-color 250ms cubic-bezier(0.4, 0, 0.2, 1); &:hover { color: inherit;