Skip to content
Open
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"vue"
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"i18n-ally.localesPaths": [
"server/locales"
Expand Down
16 changes: 15 additions & 1 deletion client/components/editor/editor-markdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ import mdFootnote from 'markdown-it-footnote'
import mdImsize from 'markdown-it-imsize'
import katex from 'katex'
import underline from '../../libs/markdown-it-underline'
import githubAlerts from '../../libs/markdown-it-github-alerts'
import 'katex/dist/contrib/mhchem'
import twemoji from 'twemoji'
import plantuml from './markdown/plantuml'
Expand Down Expand Up @@ -266,6 +267,7 @@ const md = new MarkdownIt({
})
.use(mdDecorate)
.use(underline)
.use(githubAlerts)
.use(mdEmoji)
.use(mdTaskLists, { label: false, labelAfter: false })
.use(mdExpandTabs)
Expand Down Expand Up @@ -308,9 +310,21 @@ function injectLineNumbers (tokens, idx, options, env, slf) {
}
return slf.renderToken(tokens, idx, options, env, slf)
}

// Store the existing blockquote renderer (which now includes GitHub alerts)
const existingBlockquoteRender = md.renderer.rules.blockquote_open

// Create a combined renderer for blockquotes that handles both line numbers and GitHub alerts
md.renderer.rules.blockquote_open = function(tokens, idx, opts, env, slf) {
// First apply line number injection
injectLineNumbers(tokens, idx, opts, env, slf)
// Then apply the GitHub alerts rendering (if any)
return existingBlockquoteRender(tokens, idx, opts, env, slf)
}

// Apply line number injection to other elements
md.renderer.rules.paragraph_open = injectLineNumbers
md.renderer.rules.heading_open = injectLineNumbers
md.renderer.rules.blockquote_open = injectLineNumbers

cmFold.register('markdown')
// ========================================
Expand Down
64 changes: 64 additions & 0 deletions client/libs/markdown-it-github-alerts/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// ------------------------------------
// Markdown - GitHub-style Alerts (Client-side)
// ------------------------------------

function githubAlertsPlugin(md, options = {}) {
const alertTypes = {
'note': { class: 'is-info' },
'info': { class: 'is-info' },
'tip': { class: 'is-success' },
'warning': { class: 'is-warning' },
'important': { class: 'is-info' },
'caution': { class: 'is-danger' }
}

// Store original renderer - will handle line number injection if it exists
const defaultRender = md.renderer.rules.blockquote_open || function(tokens, idx, options, env, slf) {
return slf.renderToken(tokens, idx, options)
}

// Override blockquote_open renderer to handle both alerts and line numbers
md.renderer.rules.blockquote_open = function(tokens, idx, opts, env, slf) {
const nextToken = tokens[idx + 1]

// Check if the next token is a paragraph containing inline content
if (nextToken && nextToken.type === 'paragraph_open') {
const inlineToken = tokens[idx + 2] // The inline token after paragraph_open

if (inlineToken && inlineToken.type === 'inline' && inlineToken.children) {
const firstChild = inlineToken.children[0]

if (firstChild && firstChild.type === 'text') {
const content = firstChild.content
const alertMatch = content.match(/^\[!(NOTE|INFO|TIP|WARNING|IMPORTANT|CAUTION)\]/i)

if (alertMatch) {
const alertType = alertMatch[1].toLowerCase()

const alertConfig = alertTypes[alertType]
if (alertConfig) {
// Add CSS class to blockquote
tokens[idx].attrJoin('class', alertConfig.class)

// Remove the alert tag
firstChild.content = firstChild.content.replace(/^\[!(NOTE|INFO|TIP|WARNING|IMPORTANT|CAUTION)\]\s*/i, '')

// If we emptied the first text node, remove it
if (firstChild.content === '') {
inlineToken.children.shift()
// Also remove the following softbreak if it exists
if (inlineToken.children[0] && inlineToken.children[0].type === 'softbreak') {
inlineToken.children.shift()
}
}
}
}
}
}
}

return defaultRender(tokens, idx, opts, env, slf)
}
}

module.exports = githubAlertsPlugin
13 changes: 8 additions & 5 deletions dev/containers/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
# -- DEV DOCKERFILE --
# -- DO NOT USE IN PRODUCTION! --

FROM node:18
LABEL maintainer "requarks.io"
FROM node:20
LABEL maintainer="requarks.io"

RUN apt-get update && \
apt-get install -y bash curl git python3 make g++ nano openssh-server gnupg && \
apt-get install -y --no-install-recommends bash curl git python3 make g++ nano openssh-server gnupg && \
apt-get upgrade -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
mkdir -p /wiki

WORKDIR /wiki

ENV dockerdev 1
ENV DEVDB postgres
ENV dockerdev=1
ENV DEVDB=postgres

EXPOSE 3000

Expand Down
2 changes: 0 additions & 2 deletions dev/containers/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ services:
- "3000:3000"
volumes:
- ../..:/wiki
- /wiki/node_modules
- /wiki/.git


volumes:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
key: markdownGithubAlerts
title: GitHub-Style Alerts
description: Parse GitHub-style alert syntax (> [!NOTE], > [!WARNING], etc.)
author: requarks.io
icon: mdi-alert-box-outline
enabledDefault: true
dependsOn: markdownCore
71 changes: 71 additions & 0 deletions server/modules/rendering/markdown-github-alerts/renderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// ------------------------------------
// Markdown - GitHub-style Alerts
// ------------------------------------

module.exports = {
init (md, conf) {
// Plugin to parse GitHub-style alerts using renderer approach
md.use(githubAlertsPlugin, conf)
}
}

function githubAlertsPlugin(md, options = {}) {
const alertTypes = {
'note': { class: 'is-info' },
'info': { class: 'is-info' },
'tip': { class: 'is-success' },
'warning': { class: 'is-warning' },
'important': { class: 'is-info' },
'caution': { class: 'is-danger' }
}

// Store original renderer
const defaultRender = md.renderer.rules.blockquote_open || function(tokens, idx, options, env, slf) {
return slf.renderToken(tokens, idx, options)
}

// Override blockquote_open renderer
md.renderer.rules.blockquote_open = function(tokens, idx, opts, env, slf) {
const nextToken = tokens[idx + 1]

// Check if the next token is a paragraph containing inline content
if (nextToken && nextToken.type === 'paragraph_open') {
const inlineToken = tokens[idx + 2] // The inline token after paragraph_open

if (inlineToken && inlineToken.type === 'inline' && inlineToken.children) {
const firstChild = inlineToken.children[0]

if (firstChild && firstChild.type === 'text') {
const content = firstChild.content
const alertMatch = content.match(/^\[!(NOTE|INFO|TIP|WARNING|IMPORTANT|CAUTION)\]/i)

if (alertMatch) {
const alertType = alertMatch[1].toLowerCase()

const alertConfig = alertTypes[alertType]
if (alertConfig) {
// Add CSS class to blockquote
tokens[idx].attrJoin('class', alertConfig.class)

// Remove the alert tag
firstChild.content = firstChild.content.replace(/^\[!(NOTE|INFO|TIP|WARNING|IMPORTANT|CAUTION)\]\s*/i, '')

// If we emptied the first text node, remove it
if (firstChild.content === '') {
inlineToken.children.shift()
// Also remove the following softbreak if it exists
if (inlineToken.children[0] && inlineToken.children[0].type === 'softbreak') {
inlineToken.children.shift()
}
}
}
}
}
}
}

return defaultRender(tokens, idx, opts, env, slf)
}
}