mirror of
https://github.com/sst/opencode.git
synced 2025-07-07 16:14:59 +00:00
docs: share improve markdown rendering of ai responses
This commit is contained in:
parent
06dba28bd6
commit
143fd8e076
6 changed files with 78 additions and 27 deletions
8
bun.lock
8
bun.lock
|
@ -31,7 +31,6 @@
|
||||||
"@openauthjs/openauth": "0.4.3",
|
"@openauthjs/openauth": "0.4.3",
|
||||||
"@standard-schema/spec": "1.0.0",
|
"@standard-schema/spec": "1.0.0",
|
||||||
"ai": "catalog:",
|
"ai": "catalog:",
|
||||||
"air": "0.4.14",
|
|
||||||
"decimal.js": "10.5.0",
|
"decimal.js": "10.5.0",
|
||||||
"diff": "8.0.2",
|
"diff": "8.0.2",
|
||||||
"env-paths": "3.0.0",
|
"env-paths": "3.0.0",
|
||||||
|
@ -79,6 +78,7 @@
|
||||||
"lang-map": "0.4.0",
|
"lang-map": "0.4.0",
|
||||||
"luxon": "3.6.1",
|
"luxon": "3.6.1",
|
||||||
"marked": "15.0.12",
|
"marked": "15.0.12",
|
||||||
|
"marked-shiki": "1.2.0",
|
||||||
"rehype-autolink-headings": "7.1.0",
|
"rehype-autolink-headings": "7.1.0",
|
||||||
"sharp": "0.32.5",
|
"sharp": "0.32.5",
|
||||||
"shiki": "3.4.2",
|
"shiki": "3.4.2",
|
||||||
|
@ -517,8 +517,6 @@
|
||||||
|
|
||||||
"ai": ["ai@4.3.16", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "@ai-sdk/react": "1.2.12", "@ai-sdk/ui-utils": "1.2.11", "@opentelemetry/api": "1.9.0", "jsondiffpatch": "0.6.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.23.8" }, "optionalPeers": ["react"] }, "sha512-KUDwlThJ5tr2Vw0A1ZkbDKNME3wzWhuVfAOwIvFUzl1TPVDFAXDFTXio3p+jaKneB+dKNCvFFlolYmmgHttG1g=="],
|
"ai": ["ai@4.3.16", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "@ai-sdk/react": "1.2.12", "@ai-sdk/ui-utils": "1.2.11", "@opentelemetry/api": "1.9.0", "jsondiffpatch": "0.6.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.23.8" }, "optionalPeers": ["react"] }, "sha512-KUDwlThJ5tr2Vw0A1ZkbDKNME3wzWhuVfAOwIvFUzl1TPVDFAXDFTXio3p+jaKneB+dKNCvFFlolYmmgHttG1g=="],
|
||||||
|
|
||||||
"air": ["air@0.4.14", "", { "dependencies": { "zephyr": "~1.3.5" } }, "sha512-E8bl9LlSGSQqjxxjeGIrpYpf8jVyJplsdK1bTobh61F7ks+3aLeXL4KbGSJIFsiaSSz5ZExLU51DGztmQSlZTQ=="],
|
|
||||||
|
|
||||||
"ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="],
|
"ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="],
|
||||||
|
|
||||||
"ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
"ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||||
|
@ -1055,6 +1053,8 @@
|
||||||
|
|
||||||
"marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="],
|
"marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="],
|
||||||
|
|
||||||
|
"marked-shiki": ["marked-shiki@1.2.0", "", { "peerDependencies": { "marked": ">=7.0.0", "shiki": ">=1.0.0" } }, "sha512-N924hp8veE6Mc91g5/kCNVoTU7TkeJfB2G2XEWb+k1fVA0Bck2T0rVt93d39BlOYH6ohP4Q9BFlPk+UkblhXbg=="],
|
||||||
|
|
||||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||||
|
|
||||||
"mdast-util-definitions": ["mdast-util-definitions@6.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ=="],
|
"mdast-util-definitions": ["mdast-util-definitions@6.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ=="],
|
||||||
|
@ -1703,8 +1703,6 @@
|
||||||
|
|
||||||
"youch": ["youch@3.3.4", "", { "dependencies": { "cookie": "^0.7.1", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="],
|
"youch": ["youch@3.3.4", "", { "dependencies": { "cookie": "^0.7.1", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="],
|
||||||
|
|
||||||
"zephyr": ["zephyr@1.3.6", "", {}, "sha512-oYH52DGZzIbXNrkijskaR8YpVKnXAe8jNgH1KirglVBnTFOn6mK9/0SVCxGn+73l0Hjhr4UYNzYkO07LXSWy6w=="],
|
|
||||||
|
|
||||||
"zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
|
"zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
|
||||||
|
|
||||||
"zod-openapi": ["zod-openapi@4.2.4", "", { "peerDependencies": { "zod": "^3.21.4" } }, "sha512-tsrQpbpqFCXqVXUzi3TPwFhuMtLN3oNZobOtYnK6/5VkXsNdnIgyNr4r8no4wmYluaxzN3F7iS+8xCW8BmMQ8g=="],
|
"zod-openapi": ["zod-openapi@4.2.4", "", { "peerDependencies": { "zod": "^3.21.4" } }, "sha512-tsrQpbpqFCXqVXUzi3TPwFhuMtLN3oNZobOtYnK6/5VkXsNdnIgyNr4r8no4wmYluaxzN3F7iS+8xCW8BmMQ8g=="],
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
"lang-map": "0.4.0",
|
"lang-map": "0.4.0",
|
||||||
"luxon": "3.6.1",
|
"luxon": "3.6.1",
|
||||||
"marked": "15.0.12",
|
"marked": "15.0.12",
|
||||||
|
"marked-shiki": "1.2.0",
|
||||||
"rehype-autolink-headings": "7.1.0",
|
"rehype-autolink-headings": "7.1.0",
|
||||||
"sharp": "0.32.5",
|
"sharp": "0.32.5",
|
||||||
"shiki": "3.4.2",
|
"shiki": "3.4.2",
|
||||||
|
|
|
@ -1,21 +1,39 @@
|
||||||
import { type JSX, splitProps, createResource } from "solid-js"
|
import { type JSX, splitProps, createResource } from "solid-js"
|
||||||
import { marked } from "marked"
|
import { marked } from "marked"
|
||||||
|
import markedShiki from "marked-shiki"
|
||||||
|
import { codeToHtml } from "shiki"
|
||||||
|
import { transformerNotationDiff } from "@shikijs/transformers"
|
||||||
import styles from "./markdownview.module.css"
|
import styles from "./markdownview.module.css"
|
||||||
|
|
||||||
interface MarkdownViewProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
interface MarkdownViewProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
||||||
markdown: string
|
markdown: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const markedWithShiki = marked.use(
|
||||||
|
markedShiki({
|
||||||
|
highlight(code, lang) {
|
||||||
|
return codeToHtml(code, {
|
||||||
|
lang: lang || "text",
|
||||||
|
themes: {
|
||||||
|
light: "github-light",
|
||||||
|
dark: "github-dark",
|
||||||
|
},
|
||||||
|
transformers: [transformerNotationDiff()],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
function MarkdownView(props: MarkdownViewProps) {
|
function MarkdownView(props: MarkdownViewProps) {
|
||||||
const [local, rest] = splitProps(props, ["markdown"])
|
const [local, rest] = splitProps(props, ["markdown"])
|
||||||
const [html] = createResource(() => local.markdown, async (markdown) => {
|
const [html] = createResource(
|
||||||
return marked.parse(markdown)
|
() => local.markdown,
|
||||||
})
|
async (markdown) => {
|
||||||
|
return markedWithShiki.parse(markdown)
|
||||||
return (
|
},
|
||||||
<div innerHTML={html()} class={styles["markdown-body"]} {...rest} />
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return <div innerHTML={html()} class={styles["markdown-body"]} {...rest} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MarkdownView
|
export default MarkdownView
|
||||||
|
|
||||||
|
|
|
@ -294,15 +294,11 @@ function ResultsButton(props: ResultsButtonProps) {
|
||||||
interface TextPartProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
interface TextPartProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
||||||
text: string
|
text: string
|
||||||
expand?: boolean
|
expand?: boolean
|
||||||
invert?: boolean
|
|
||||||
highlight?: boolean
|
|
||||||
}
|
}
|
||||||
function TextPart(props: TextPartProps) {
|
function TextPart(props: TextPartProps) {
|
||||||
const [local, rest] = splitProps(props, [
|
const [local, rest] = splitProps(props, [
|
||||||
"text",
|
"text",
|
||||||
"expand",
|
"expand",
|
||||||
"invert",
|
|
||||||
"highlight",
|
|
||||||
])
|
])
|
||||||
const [expanded, setExpanded] = createSignal(false)
|
const [expanded, setExpanded] = createSignal(false)
|
||||||
const [overflowed, setOverflowed] = createSignal(false)
|
const [overflowed, setOverflowed] = createSignal(false)
|
||||||
|
@ -332,8 +328,6 @@ function TextPart(props: TextPartProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
class={styles["message-text"]}
|
class={styles["message-text"]}
|
||||||
data-invert={local.invert}
|
|
||||||
data-highlight={local.highlight}
|
|
||||||
data-expanded={expanded() || local.expand === true}
|
data-expanded={expanded() || local.expand === true}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
|
@ -991,9 +985,9 @@ export default function Share(props: {
|
||||||
</div>
|
</div>
|
||||||
<div data-section="content">
|
<div data-section="content">
|
||||||
<TextPart
|
<TextPart
|
||||||
invert
|
|
||||||
text={part().text}
|
text={part().text}
|
||||||
expand={isLastPart()}
|
expand={isLastPart()}
|
||||||
|
data-background="blue"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1021,7 +1015,6 @@ export default function Share(props: {
|
||||||
</div>
|
</div>
|
||||||
<div data-section="content">
|
<div data-section="content">
|
||||||
<MarkdownPart
|
<MarkdownPart
|
||||||
highlight
|
|
||||||
expand={isLastPart()}
|
expand={isLastPart()}
|
||||||
text={stripEnclosingTag(part().text)}
|
text={stripEnclosingTag(part().text)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -40,11 +40,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
white-space: pre-wrap;
|
--shiki-dark-bg: var(--sl-color-bg-surface) !important;
|
||||||
border-radius: 0.25rem;
|
background-color: var(--sl-color-bg-surface) !important;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.5rem 0.75rem;
|
||||||
|
line-height: 1.6;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
|
||||||
|
span {
|
||||||
|
white-space: break-spaces;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
|
@ -61,4 +67,40 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid var(--sl-color-border);
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
border-bottom: 1px solid var(--sl-color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove outer borders */
|
||||||
|
table tr:first-child th,
|
||||||
|
table tr:first-child td {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tr:last-child td {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th:first-child,
|
||||||
|
table td:first-child {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th:last-child,
|
||||||
|
table td:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -493,9 +493,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-highlight="true"] {
|
&[data-background="none"] { background-color: transparent; }
|
||||||
background-color: var(--sl-color-blue-low);
|
&[data-background="blue"] { background-color: var(--sl-color-blue-low); }
|
||||||
}
|
|
||||||
|
|
||||||
&[data-expanded="true"] {
|
&[data-expanded="true"] {
|
||||||
pre {
|
pre {
|
||||||
|
@ -669,7 +668,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-markdown {
|
.message-markdown {
|
||||||
background-color: var(--sl-color-bg-surface);
|
border: 1px solid var(--sl-color-blue-high);
|
||||||
padding: 0.5rem calc(0.5rem + 3px);
|
padding: 0.5rem calc(0.5rem + 3px);
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue