mirror of
https://github.com/modrinth/code.git
synced 2026-08-31 03:55:59 +00:00
backwards compatibility
This commit is contained in:
@@ -825,15 +825,8 @@ a:not(.no-click-animation),
|
||||
padding-block-start: 0;
|
||||
}
|
||||
|
||||
blockquote,
|
||||
details,
|
||||
dl,
|
||||
ol,
|
||||
p,
|
||||
code,
|
||||
pre,
|
||||
table,
|
||||
ul {
|
||||
|
||||
> * {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
@@ -844,13 +837,31 @@ a:not(.no-click-animation),
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
ul.contains-task-list,
|
||||
li.task-list-item {
|
||||
list-style: none;
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.task-list-item-checkbox {
|
||||
margin-right: 0.5em;
|
||||
ul {
|
||||
list-style: disc;
|
||||
padding-left: 1.5em;
|
||||
|
||||
ul {
|
||||
list-style: circle;
|
||||
|
||||
ul {
|
||||
list-style: square;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style: decimal;
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
|
||||
li.task-list-item {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
|
||||
@@ -70,20 +70,3 @@
|
||||
.hljs-strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #222222;
|
||||
padding: 1em 1em 1em 1em;
|
||||
border-width: 5px;
|
||||
border-radius: 2em;
|
||||
border-color: var(--color-divider);
|
||||
overflow-x: hidden;
|
||||
|
||||
code {
|
||||
line-height: 100%;
|
||||
padding: 0.2em;
|
||||
letter-spacing: -0.05em;
|
||||
word-break: normal;
|
||||
font-family: monospace;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import MarkdownCollectionEmbed from './markdown/MarkdownCollectionEmbed.vue'
|
||||
import MarkdownHighlightedPre from './markdown/MarkdownHighlightedPre.vue'
|
||||
import MarkdownOrganizationEmbed from './markdown/MarkdownOrganizationEmbed.vue'
|
||||
import MarkdownProjectEmbed from './markdown/MarkdownProjectEmbed.vue'
|
||||
import MarkdownTaskCheckbox from './markdown/MarkdownTaskCheckbox.vue'
|
||||
import MarkdownUserEmbed from './markdown/MarkdownUserEmbed.vue'
|
||||
|
||||
defineOptions({
|
||||
@@ -82,6 +83,7 @@ const components = computed(() =>
|
||||
user: MarkdownUserEmbed,
|
||||
organization: MarkdownOrganizationEmbed,
|
||||
collection: MarkdownCollectionEmbed,
|
||||
input: MarkdownTaskCheckbox,
|
||||
...(props.highlight ? { pre: MarkdownHighlightedPre } : {}),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<span class="inline-flex align-middle mr-1 pointer-events-none">
|
||||
<Checkbox :model-value="!!checked" />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Checkbox from '../Checkbox.vue'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
defineProps<{
|
||||
checked?: boolean
|
||||
}>()
|
||||
</script>
|
||||
@@ -0,0 +1,128 @@
|
||||
import { defineComarkPlugin } from 'comark/parse'
|
||||
import { Parser as HtmlTagParser } from 'htmlparser2'
|
||||
import type Token from 'markdown-it/lib/token.mjs'
|
||||
|
||||
import type MarkdownIt = require('markdown-it')
|
||||
|
||||
// This is here to keep backwards compatibility
|
||||
// Comark closes most open html tags when it hits a blank line,
|
||||
// we make it only do that if we can't find a closing tag, in order to mimic the side effect of
|
||||
// markdown-it emitting html entirely raw (which your browser is then lenient with unclosed tags)
|
||||
// whereas comark does its fancy AST which means it can't just emit the html raw
|
||||
// Thank you for coming to my TED talk -chyz
|
||||
|
||||
type RuleBlock = MarkdownIt.ParserBlock.RuleBlock
|
||||
type StateBlock = MarkdownIt.StateBlock
|
||||
|
||||
// If you know a better way to do this go ahead
|
||||
function findHtmlBlockRuleFn(md: MarkdownIt): RuleBlock | undefined {
|
||||
const rules = (md.block.ruler as unknown as { __rules__: { name: string; fn: RuleBlock }[] })
|
||||
.__rules__
|
||||
return rules?.find((r) => r.name === 'comark_html_block')?.fn
|
||||
}
|
||||
|
||||
function extractOpenTagName(line: string): string | undefined {
|
||||
return /^<([a-zA-Z][a-zA-Z0-9-]*)/.exec(line)?.[1]?.toLowerCase()
|
||||
}
|
||||
|
||||
function parseOpenTagAttrs(line: string): [string, string][] {
|
||||
const attrs: [string, string][] = []
|
||||
const parser = new HtmlTagParser({
|
||||
onopentag(_name, attrObj) {
|
||||
for (const [key, value] of Object.entries(attrObj)) attrs.push([key, value])
|
||||
},
|
||||
})
|
||||
parser.write(line)
|
||||
parser.end()
|
||||
return attrs
|
||||
}
|
||||
|
||||
function markdownItModrinthHtmlBlock(md: MarkdownIt) {
|
||||
const htmlBlockFn = findHtmlBlockRuleFn(md)
|
||||
if (!htmlBlockFn) return
|
||||
|
||||
md.block.ruler.before(
|
||||
'comark_html_block',
|
||||
'modrinth_html_block',
|
||||
(state: StateBlock, startLine: number, endLine: number, silent: boolean) => {
|
||||
if (silent) return htmlBlockFn(state, startLine, endLine, true)
|
||||
|
||||
const tokensBefore = state.tokens.length
|
||||
const lineBefore = state.line
|
||||
const matched = htmlBlockFn(state, startLine, endLine, false)
|
||||
if (!matched) return false
|
||||
|
||||
const token = state.tokens[state.tokens.length - 1]
|
||||
if (token.type !== 'html_block' || !token.map) return true
|
||||
|
||||
const firstLine = (token.content.split('\n')[0] ?? '').trim()
|
||||
if (firstLine.endsWith('/>')) return true
|
||||
|
||||
const tagName = extractOpenTagName(firstLine)
|
||||
if (!tagName) return true
|
||||
|
||||
const openLineRe = new RegExp(`^<${tagName}(\\s|/?>|$)`, 'i')
|
||||
const closeLineRe = new RegExp(`^</${tagName}\\s*>$`, 'i')
|
||||
let depth = 0
|
||||
let closeLine = -1
|
||||
for (let line = startLine + 1; line < endLine; line++) {
|
||||
if (state.sCount[line] < state.blkIndent) break
|
||||
const p = state.bMarks[line] + state.tShift[line]
|
||||
const mx = state.eMarks[line]
|
||||
const text = state.src.slice(p, mx).trim()
|
||||
if (openLineRe.test(text) && !text.endsWith('/>')) {
|
||||
depth++
|
||||
continue
|
||||
}
|
||||
if (closeLineRe.test(text)) {
|
||||
if (depth > 0) {
|
||||
depth--
|
||||
continue
|
||||
}
|
||||
closeLine = line
|
||||
break
|
||||
}
|
||||
}
|
||||
if (closeLine === -1 || closeLine < token.map[1]) return true
|
||||
|
||||
state.tokens.length = tokensBefore
|
||||
state.line = lineBefore
|
||||
|
||||
const attrs = parseOpenTagAttrs(firstLine)
|
||||
const oldParent = state.parentType
|
||||
const oldLineMax = state.lineMax
|
||||
state.parentType = 'comark_block' as StateBlock['parentType']
|
||||
state.lineMax = closeLine
|
||||
|
||||
const tokenOpen: Token & { block?: boolean } = state.push('mdc_block_open', tagName, 1)
|
||||
tokenOpen.block = true
|
||||
tokenOpen.map = [startLine, closeLine + 1]
|
||||
for (const [key, value] of attrs) tokenOpen.attrSet(key, value)
|
||||
|
||||
const blkIndent = state.blkIndent
|
||||
state.blkIndent = 0
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const env = state.env as any
|
||||
env.comarkBlockTokens ||= []
|
||||
env.comarkBlockTokens.unshift(tokenOpen)
|
||||
state.md.block.tokenize(state, startLine + 1, closeLine)
|
||||
state.blkIndent = blkIndent
|
||||
env.comarkBlockTokens.shift()
|
||||
|
||||
const tokenClose: Token & { block?: boolean } = state.push('mdc_block_close', tagName, -1)
|
||||
tokenClose.map = [startLine, closeLine + 1]
|
||||
tokenClose.block = true
|
||||
|
||||
state.parentType = oldParent
|
||||
state.lineMax = oldLineMax
|
||||
state.line = closeLine + 1
|
||||
return true
|
||||
},
|
||||
{ alt: ['paragraph', 'reference', 'blockquote'] },
|
||||
)
|
||||
}
|
||||
|
||||
export const modrinthHtmlBlock = defineComarkPlugin(() => ({
|
||||
name: 'modrinth-html-block',
|
||||
markdownItPlugins: [markdownItModrinthHtmlBlock],
|
||||
}))
|
||||
@@ -16,6 +16,7 @@ import taskList from 'comark/plugins/task-list'
|
||||
import { visitAsync } from 'comark/utils'
|
||||
|
||||
import { modrinthEmbedSyntax } from './embeds'
|
||||
import { modrinthHtmlBlock } from './html-block'
|
||||
import { modrinthResolveMedia } from './media'
|
||||
import { modrinthSecurity } from './security'
|
||||
|
||||
@@ -44,6 +45,7 @@ export const modrinthPlugins: ComarkPlugin[] = [
|
||||
// frontmatter()
|
||||
// heading()
|
||||
html(),
|
||||
modrinthHtmlBlock(),
|
||||
// json-render()
|
||||
// math(), // needs dep
|
||||
// mermaid(), // needs dep
|
||||
@@ -53,7 +55,7 @@ export const modrinthPlugins: ComarkPlugin[] = [
|
||||
modrinthResolveMedia(),
|
||||
modrinthSecurity(),
|
||||
// shiki(), // needs dep + we have highlight.js
|
||||
// summary() // irrelevant
|
||||
// summary(), //TODO
|
||||
taskList(),
|
||||
// toc() // would be cool to have but would need heavy changes to project pages
|
||||
]
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@modrinth/api-client": "workspace:*",
|
||||
"@modrinth/tooling-config": "workspace:*"
|
||||
"@modrinth/tooling-config": "workspace:*",
|
||||
"@types/markdown-it": "14.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/commands": "^6.3.2",
|
||||
@@ -24,6 +25,7 @@
|
||||
"dayjs": "^1.11.10",
|
||||
"highlight.js": "^11.9.0",
|
||||
"highlightjs-mcfunction": "github:modrinth/better-highlightjs-mcfunction",
|
||||
"htmlparser2": "^12.0.0",
|
||||
"ofetch": "^1.3.4",
|
||||
"three": "^0.172.0"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user