From ec5d4ef87078572de0e6508e39429fff38c4c88c Mon Sep 17 00:00:00 2001 From: Mohammad Aziz Date: Mon, 23 Mar 2026 17:48:37 +0530 Subject: [PATCH] fix(console): render changelog markdown (#18696) --- bun.lock | 1 + packages/console/app/package.json | 1 + .../app/src/routes/changelog/index.tsx | 61 ++++++++++++++----- 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/bun.lock b/bun.lock index 2a6a28b7d4..848959979e 100644 --- a/bun.lock +++ b/bun.lock @@ -97,6 +97,7 @@ "@solidjs/start": "catalog:", "@stripe/stripe-js": "8.6.1", "chart.js": "4.5.1", + "marked": "catalog:", "nitro": "3.0.1-alpha.1", "solid-js": "catalog:", "solid-list": "0.3.0", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index b90d77f405..06d3d4a4e6 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -27,6 +27,7 @@ "@solidjs/start": "catalog:", "@stripe/stripe-js": "8.6.1", "chart.js": "4.5.1", + "marked": "catalog:", "nitro": "3.0.1-alpha.1", "solid-js": "catalog:", "solid-list": "0.3.0", diff --git a/packages/console/app/src/routes/changelog/index.tsx b/packages/console/app/src/routes/changelog/index.tsx index 54f037479a..5540d80a10 100644 --- a/packages/console/app/src/routes/changelog/index.tsx +++ b/packages/console/app/src/routes/changelog/index.tsx @@ -1,4 +1,5 @@ import "./index.css" +import { marked } from "marked" import { Title, Meta } from "@solidjs/meta" import { createAsync } from "@solidjs/router" import { Header } from "~/component/header" @@ -6,7 +7,7 @@ import { Footer } from "~/component/footer" import { Legal } from "~/component/legal" import { changelog } from "~/lib/changelog" import type { HighlightGroup } from "~/lib/changelog" -import { For, Show, createSignal } from "solid-js" +import { For, Show, createSignal, type JSX } from "solid-js" import { useI18n } from "~/context/i18n" import { useLanguage } from "~/context/language" import { LocaleLinks } from "~/component/locale-links" @@ -20,24 +21,54 @@ function formatDate(dateString: string, locale: string) { }) } -function ReleaseItem(props: { item: string }) { - const parts = () => { - const match = props.item.match(/^(.+?)(\s*\(@([\w-]+)\))?$/) - if (match) { - return { - text: match[1], - username: match[3], - } - } - return { text: props.item, username: undefined } +function splitAuthor(item: string) { + const match = item.match(/^(.+?)(\s*\(@([\w-]+)\))?$/) + return { + text: match?.[1] ?? item, + user: match?.[3], } +} + +function parseInline(text: string) { + return marked.Lexer.lexInline(text, { + async: false, + breaks: false, + gfm: true, + }) +} + +function renderToken(token: ReturnType[number]): Array { + if (token.type === "strong") return [{renderInline(token.tokens ?? [])}] + if (token.type === "em") return [{renderInline(token.tokens ?? [])}] + if (token.type === "codespan") return [{token.text}] + if (token.type === "del") return [{renderInline(token.tokens ?? [])}] + if (token.type === "br") return [
] + if (token.type === "link") { + return [ + + {renderInline(token.tokens ?? [])} + , + ] + } + if (token.type === "text" && token.tokens) return renderInline(token.tokens) + if (token.type === "escape") return [token.text] + if (token.type === "html" || token.type === "text") return [token.raw] + return [token.raw] +} + +function renderInline(tokens: ReturnType) { + return tokens.flatMap(renderToken) +} + +function ReleaseItem(props: { item: string }) { + const part = splitAuthor(props.item) return (
  • - {parts().text} - - - (@{parts().username}) + {renderInline(parseInline(part.text))} + + + (@{part.user})