diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-16 08:24:18 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-16 08:24:18 +0800 |
| commit | 4bf7a9bad2931766e3383d907d6f4ab138e39b66 (patch) | |
| tree | 474d750f3b608818b3bc5a8b9278b543dad8b9b5 /docs/scripts/display-parse.js | |
| parent | 08116538a79875621dcd05ce6f6569cc62443b95 (diff) | |
feat(landing): enhance landing page with terminal hero and scroll snap
Add a fixed navigation bar, full-height hero section with tiled
grid background, and an animated command carousel terminal. Style
download links as interactive buttons and incorporate syntax
highlighting styles. Introduce MlingDisplay JS parser for rendering
display.rs-style markup with colors, headings, and formatting.
Update version file config to include dist/index.html.
Diffstat (limited to 'docs/scripts/display-parse.js')
| -rw-r--r-- | docs/scripts/display-parse.js | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/docs/scripts/display-parse.js b/docs/scripts/display-parse.js new file mode 100644 index 0000000..ca7b391 --- /dev/null +++ b/docs/scripts/display-parse.js @@ -0,0 +1,269 @@ +/*! + * MlingDisplay — client-side port of mingling_cli/src/utils/display.rs + * + * Parses the same markdown-ish markup used by `display.rs` and returns HTML + * with the equivalent ANSI styling applied as CSS classes / inline colors. + * + * Supported syntax: + * - Bold: **text** + * - Italic: *text* + * - Underline: _text_ + * - Cyan: <text> + * - Inline code: `text` (green) + * - Colors: [[color_name]] ... [[/]] (nested) + * - Escapes: \* \< \> \` \_ + * - Headings: # Heading 1 ... ###### Heading 6 + * - Blockquote: > text + * + * Exposes: window.MlingDisplay.parse(text) -> HTML string + */ +(function () { + "use strict"; + + function findMatch(chars, start, delimiter) { + var len = delimiter.length; + for (var j = start; j < chars.length; j++) { + if (len === 1) { + if (chars[j] === delimiter) return j; + } else if ( + j + 1 < chars.length && + chars[j] === delimiter[0] && + chars[j + 1] === delimiter[1] + ) { + return j; + } + } + return -1; + } + + var COLOR_MAP = { + black: "#000", + red: "#ff7b72", + green: "#7ee787", + yellow: "#d4a84b", + blue: "#79c0ff", + magenta: "#d2a8ff", + cyan: "#79c0ff", + white: "#e8ddd0", + b_white: "#e8ddd0", + bright_gray: "#6a5a4a", + bright_grey: "#6a5a4a", + b_gray: "#6a5a4a", + b_grey: "#6a5a4a", + bright_black: "#6a5a4a", + b_black: "#6a5a4a", + gray: "#6a5a4a", + grey: "#6a5a4a", + bright_red: "#ff7b72", + b_red: "#ff7b72", + bright_green: "#7ee787", + b_green: "#7ee787", + bright_yellow: "#d4a84b", + b_yellow: "#d4a84b", + bright_blue: "#79c0ff", + b_blue: "#79c0ff", + bright_magenta: "#d2a8ff", + b_magenta: "#d2a8ff", + bright_cyan: "#79c0ff", + b_cyan: "#79c0ff", + bright_white: "#e8ddd0", + }; + + function applyColorStack(text, stack) { + var wrapped = text; + for (var k = stack.length - 1; k >= 0; k--) { + var css = COLOR_MAP[stack[k]]; + if (css) { + wrapped = + '<span style="color:' + css + '">' + wrapped + "</span>"; + } + } + return wrapped; + } + + function escapeHtml(s) { + return s + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">"); + } + + function processLine(line) { + var chars = Array.from(line); + var result = ""; + var colorStack = []; + var i = 0; + + while (i < chars.length) { + var c = chars[i]; + + // Escape sequences \\* \\< \\> \\` \\_ + if ( + c === "\\" && + i + 1 < chars.length && + ["*", "<", ">", "`", "_"].indexOf(chars[i + 1]) !== -1 + ) { + result += escapeHtml(chars[i + 1]); + i += 2; + continue; + } + + // Color tags [[color]] / [[/]] + if (c === "[" && chars[i + 1] === "[") { + var tagEnd = -1; + for (var t = i + 2; t + 1 < chars.length; t++) { + if (chars[t] === "]" && chars[t + 1] === "]") { + tagEnd = t; + break; + } + } + if (tagEnd !== -1) { + var tag = chars.slice(i + 2, tagEnd).join(""); + if (tag === "/") colorStack.pop(); + else colorStack.push(tag); + i = tagEnd + 2; + continue; + } + } + + // **bold** + if (c === "*" && chars[i + 1] === "*") { + var bEnd = findMatch(chars, i + 2, "**"); + if (bEnd !== -1) { + var inner = processLine(chars.slice(i + 2, bEnd).join("")); + result += applyColorStack( + "<b>" + inner + "</b>", + colorStack, + ); + i = bEnd + 2; + continue; + } + } + + // *italic* + if (c === "*") { + var iEnd = findMatch(chars, i + 1, "*"); + if (iEnd !== -1) { + var italic = processLine(chars.slice(i + 1, iEnd).join("")); + result += applyColorStack( + "<i>" + italic + "</i>", + colorStack, + ); + i = iEnd + 1; + continue; + } + } + + // _underline_ + if (c === "_") { + var uEnd = findMatch(chars, i + 1, "_"); + if (uEnd !== -1) { + var uText = processLine(chars.slice(i + 1, uEnd).join("")); + result += applyColorStack( + "<u>" + uText + "</u>", + colorStack, + ); + i = uEnd + 1; + continue; + } + } + + // <angle> cyan + if (c === "<") { + var cEnd = findMatch(chars, i + 1, ">"); + if (cEnd !== -1) { + var angle = chars.slice(i, cEnd + 1).join(""); + result += applyColorStack( + '<span class="t-cyan">' + escapeHtml(angle) + "</span>", + colorStack, + ); + i = cEnd + 1; + continue; + } + } + + // `code` green + if (c === "`") { + var gEnd = findMatch(chars, i + 1, "`"); + if (gEnd !== -1) { + var codeText = chars.slice(i, gEnd + 1).join(""); + result += applyColorStack( + '<span class="t-green">' + + escapeHtml(codeText) + + "</span>", + colorStack, + ); + i = gEnd + 1; + continue; + } + } + + // Regular character + result += applyColorStack(escapeHtml(c), colorStack); + i += 1; + } + return result; + } + + function processLineWithQuote(line) { + var chars = Array.from(line); + if (chars.length && chars[0] === ">") { + if (chars.length > 1 && chars[1] === "\\") { + return processLine(line); + } + var rest = chars.length > 1 ? chars.slice(1).join("") : ""; + return '<span class="t-quote"> </span>' + processLine(rest); + } + return processLine(line); + } + + /** + * Parse display.rs-flavored markup into HTML. + * @param {string} text - Raw markup text. + * @returns {string} HTML with t-cyan / t-green / t-heading / t-quote classes + * and inline colors for [[color]] tags. + */ + function parse(text) { + var lines = String(text).split("\n"); + var result = ""; + var contentIndent = 0; + for (var n = 0; n < lines.length; n++) { + var line = lines[n]; + var trimmed = line.trim(); + var ls = line.trimStart(); + var lineResult = ""; + + if (ls.startsWith("#")) { + var level = 0; + while (level < ls.length && level < 7 && ls[level] === "#") { + level++; + } + var effective = level > 6 ? 6 : level; + var start = level; + while ( + start < ls.length && + (ls[start] === " " || ls[start] === "\t") + ) { + start++; + } + var content = start < ls.length ? ls.slice(start) : ""; + var heading = + '<span class="t-heading"> ' + + processLine(content) + + " </span>"; + var indent = " ".repeat(effective > 0 ? effective - 1 : 0); + lineResult = indent + heading; + contentIndent = effective; + } else if (trimmed !== "") { + lineResult = + " ".repeat(contentIndent) + processLineWithQuote(trimmed); + } else { + lineResult = " "; + } + result += lineResult + "\n"; + } + return result; + } + + window.MlingDisplay = { parse: parse }; +})(); |
