@md-plugins/quasar-app-extension-q-press 0.1.0-beta.17 → 0.1.0-beta.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/install.js +5 -0
- package/dist/templates/init/src/_q-press/api/components/MarkdownCode.json +2 -2
- package/dist/templates/init/src/_q-press/components/MarkdownCode.vue +70 -2
- package/dist/templates/init/src/_q-press/components/MarkdownLink.vue +3 -3
- package/dist/templates/init/src/_q-press/css/app.scss +16 -6
- package/{src/templates/update/src/_q-press/css/prism-theme.scss → dist/templates/init/src/_q-press/css/code-theme.scss} +17 -2
- package/dist/templates/init/src/_q-press/css/themes/default.scss +1 -1
- package/dist/templates/init/src/_q-press/css/themes/mystic.scss +1 -1
- package/dist/templates/init/src/_q-press/css/themes/newspaper.scss +1 -1
- package/dist/templates/init/src/_q-press/css/themes/sunrise.scss +1 -1
- package/dist/templates/init/src/_q-press/css/themes/tawny.scss +1 -1
- package/dist/templates/init/src/components/LandingPage/LandingPage.vue +5 -1
- package/dist/templates/init/src/components/page-parts/releases/GitHubReleases.vue +121 -0
- package/dist/templates/init/src/components/page-parts/releases/PackageReleases.vue +191 -0
- package/dist/templates/init/src/components/page-parts/releases/md-table-parser.ts +52 -0
- package/dist/templates/init/src/components/page-parts/releases/sanitize.ts +132 -0
- package/dist/templates/init/src/markdown/__elements.md +2 -2
- package/dist/templates/init/src/markdown/__elements2.md +2 -2
- package/dist/templates/init/src/markdown/getting-started/introduction.md +3 -3
- package/dist/templates/init/src/markdown/md-plugins/codeblocks/advanced.md +2 -2
- package/dist/templates/init/src/markdown/md-plugins/codeblocks/overview.md +3 -3
- package/dist/templates/init/src/markdown/other/contact.md +37 -0
- package/dist/templates/init/src/markdown/other/contributing/bugs-and-feature-requests.md +33 -0
- package/dist/templates/init/src/markdown/other/contributing/call-to-action.md +25 -0
- package/dist/templates/init/src/markdown/other/contributing/documentation.md +31 -0
- package/dist/templates/init/src/markdown/other/contributing/overview.md +44 -0
- package/dist/templates/init/src/markdown/other/contributing/packages.md +28 -0
- package/dist/templates/init/src/markdown/other/contributing/sponsor.md +23 -0
- package/dist/templates/init/src/markdown/{guides → other}/faq.md +7 -0
- package/dist/templates/init/src/markdown/other/releases.md +11 -0
- package/dist/templates/init/src/markdown/{guides → other}/upgrade-guide.md +9 -4
- package/dist/templates/init/src/markdown/quasar-app-extensions/qpress/components.md +0 -4
- package/dist/templates/init/src/markdown/quasar-app-extensions/qpress/overview.md +5 -5
- package/dist/templates/init/src/markdown/quasar-app-extensions/qpress/site-config.md +1 -2
- package/dist/templates/init/src/markdown/quasar-app-extensions/qpress/themes.md +89 -8
- package/dist/templates/init/src/siteConfig/index.ts +27 -21
- package/dist/templates/update/src/_q-press/api/components/MarkdownCode.json +2 -2
- package/dist/templates/update/src/_q-press/components/MarkdownCode.vue +70 -2
- package/dist/templates/update/src/_q-press/components/MarkdownLink.vue +3 -3
- package/dist/templates/update/src/_q-press/css/app.scss +16 -6
- package/dist/templates/update/src/_q-press/css/{prism-theme.scss → code-theme.scss} +17 -2
- package/dist/templates/update/src/_q-press/css/themes/default.scss +1 -1
- package/dist/templates/update/src/_q-press/css/themes/mystic.scss +1 -1
- package/dist/templates/update/src/_q-press/css/themes/newspaper.scss +1 -1
- package/dist/templates/update/src/_q-press/css/themes/sunrise.scss +1 -1
- package/dist/templates/update/src/_q-press/css/themes/tawny.scss +1 -1
- package/package.json +15 -15
- package/src/install.ts +6 -0
- package/src/templates/init/src/_q-press/api/components/MarkdownCode.json +2 -2
- package/src/templates/init/src/_q-press/components/MarkdownCode.vue +70 -2
- package/src/templates/init/src/_q-press/components/MarkdownLink.vue +3 -3
- package/src/templates/init/src/_q-press/css/app.scss +16 -6
- package/{dist/templates/init/src/_q-press/css/prism-theme.scss → src/templates/init/src/_q-press/css/code-theme.scss} +17 -2
- package/src/templates/init/src/_q-press/css/themes/default.scss +1 -1
- package/src/templates/init/src/_q-press/css/themes/mystic.scss +1 -1
- package/src/templates/init/src/_q-press/css/themes/newspaper.scss +1 -1
- package/src/templates/init/src/_q-press/css/themes/sunrise.scss +1 -1
- package/src/templates/init/src/_q-press/css/themes/tawny.scss +1 -1
- package/src/templates/init/src/components/LandingPage/LandingPage.vue +5 -1
- package/src/templates/init/src/components/page-parts/releases/GitHubReleases.vue +121 -0
- package/src/templates/init/src/components/page-parts/releases/PackageReleases.vue +191 -0
- package/src/templates/init/src/components/page-parts/releases/md-table-parser.ts +52 -0
- package/src/templates/init/src/components/page-parts/releases/sanitize.ts +132 -0
- package/src/templates/init/src/markdown/__elements.md +2 -2
- package/src/templates/init/src/markdown/__elements2.md +2 -2
- package/src/templates/init/src/markdown/getting-started/introduction.md +3 -3
- package/src/templates/init/src/markdown/md-plugins/codeblocks/advanced.md +2 -2
- package/src/templates/init/src/markdown/md-plugins/codeblocks/overview.md +3 -3
- package/src/templates/init/src/markdown/other/contact.md +37 -0
- package/src/templates/init/src/markdown/other/contributing/bugs-and-feature-requests.md +33 -0
- package/src/templates/init/src/markdown/other/contributing/call-to-action.md +25 -0
- package/src/templates/init/src/markdown/other/contributing/documentation.md +31 -0
- package/src/templates/init/src/markdown/other/contributing/overview.md +44 -0
- package/src/templates/init/src/markdown/other/contributing/packages.md +28 -0
- package/src/templates/init/src/markdown/other/contributing/sponsor.md +23 -0
- package/src/templates/init/src/markdown/{guides → other}/faq.md +7 -0
- package/src/templates/init/src/markdown/other/releases.md +11 -0
- package/src/templates/init/src/markdown/{guides → other}/upgrade-guide.md +9 -4
- package/src/templates/init/src/markdown/quasar-app-extensions/qpress/components.md +0 -4
- package/src/templates/init/src/markdown/quasar-app-extensions/qpress/overview.md +5 -5
- package/src/templates/init/src/markdown/quasar-app-extensions/qpress/site-config.md +1 -2
- package/src/templates/init/src/markdown/quasar-app-extensions/qpress/themes.md +89 -8
- package/src/templates/init/src/siteConfig/index.ts +27 -21
- package/src/templates/update/src/_q-press/api/components/MarkdownCode.json +2 -2
- package/src/templates/update/src/_q-press/components/MarkdownCode.vue +70 -2
- package/src/templates/update/src/_q-press/components/MarkdownLink.vue +3 -3
- package/src/templates/update/src/_q-press/css/app.scss +16 -6
- package/src/templates/{init/src/_q-press/css/prism-theme.scss → update/src/_q-press/css/code-theme.scss} +17 -2
- package/src/templates/update/src/_q-press/css/themes/default.scss +1 -1
- package/src/templates/update/src/_q-press/css/themes/mystic.scss +1 -1
- package/src/templates/update/src/_q-press/css/themes/newspaper.scss +1 -1
- package/src/templates/update/src/_q-press/css/themes/sunrise.scss +1 -1
- package/src/templates/update/src/_q-press/css/themes/tawny.scss +1 -1
- package/dist/templates/init/src/_q-press/api/components/MarkdownCodePrism.json +0 -29
- package/dist/templates/init/src/_q-press/components/MarkdownCodePrism.ts +0 -36
- package/dist/templates/init/src/markdown/guides/contributing.md +0 -101
- package/dist/templates/init/src/markdown/guides/release-notes.md +0 -0
- package/dist/templates/init/src/markdown/guides/style-guide.md +0 -0
- package/dist/templates/init/src/markdown/other/release-notes.md +0 -8
- package/dist/templates/update/src/_q-press/api/components/MarkdownCodePrism.json +0 -29
- package/dist/templates/update/src/_q-press/components/MarkdownCodePrism.ts +0 -36
- package/src/templates/init/src/_q-press/api/components/MarkdownCodePrism.json +0 -29
- package/src/templates/init/src/_q-press/components/MarkdownCodePrism.ts +0 -36
- package/src/templates/init/src/markdown/guides/contributing.md +0 -101
- package/src/templates/init/src/markdown/guides/release-notes.md +0 -0
- package/src/templates/init/src/markdown/guides/style-guide.md +0 -0
- package/src/templates/init/src/markdown/other/release-notes.md +0 -8
- package/src/templates/update/src/_q-press/api/components/MarkdownCodePrism.json +0 -29
- package/src/templates/update/src/_q-press/components/MarkdownCodePrism.ts +0 -36
package/README.md
CHANGED
|
@@ -40,12 +40,12 @@ See the [documentation](https://md-plugins.netlify.app/quasar-app-extensions/qpr
|
|
|
40
40
|
- `pnpm i -D markdown-it @types/markdown-it`
|
|
41
41
|
- `bun add -d markdown-it @types/markdown-it`
|
|
42
42
|
|
|
43
|
-
3.
|
|
43
|
+
3. Q-Press adds `shiki` to your project dependencies when invoked. If you are wiring the generated files manually, add it yourself:
|
|
44
44
|
|
|
45
|
-
- `npm i
|
|
46
|
-
- `yarn add
|
|
47
|
-
- `pnpm add
|
|
48
|
-
- `bun add
|
|
45
|
+
- `npm i shiki`
|
|
46
|
+
- `yarn add shiki`
|
|
47
|
+
- `pnpm add shiki`
|
|
48
|
+
- `bun add shiki`
|
|
49
49
|
|
|
50
50
|
## Modifications
|
|
51
51
|
|
package/dist/install.js
CHANGED
|
@@ -22,6 +22,11 @@ export default defineInstallScript(async (api) => {
|
|
|
22
22
|
console.error('----------------------------------');
|
|
23
23
|
throw new Error('This extension requires TypeScript');
|
|
24
24
|
}
|
|
25
|
+
api.extendPackageJson({
|
|
26
|
+
dependencies: {
|
|
27
|
+
shiki: '^4.1.0',
|
|
28
|
+
},
|
|
29
|
+
});
|
|
25
30
|
const path = api.resolve.src('siteConfig');
|
|
26
31
|
if (existsSync(path)) {
|
|
27
32
|
// this is an update scenario
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"props": {
|
|
7
7
|
"code": {
|
|
8
8
|
"type": "String",
|
|
9
|
-
"desc": "The code to display",
|
|
9
|
+
"desc": "The code to display with Shiki syntax highlighting",
|
|
10
10
|
"examples": [
|
|
11
11
|
"'const a = 1;'",
|
|
12
12
|
"'<div>Hello World</div>'"
|
|
@@ -34,4 +34,4 @@
|
|
|
34
34
|
"category": "content"
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
}
|
|
37
|
+
}
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative-position markdown-copybtn-hover">
|
|
3
|
-
<
|
|
3
|
+
<pre class="markdown-code" :class="block.className" :style="[style, block.style]"><code v-html="block.code"></code></pre>
|
|
4
4
|
<MarkdownCopyButton />
|
|
5
5
|
</div>
|
|
6
6
|
</template>
|
|
7
7
|
|
|
8
8
|
<script setup lang="ts">
|
|
9
|
+
import { createHighlighterCoreSync } from 'shiki/core'
|
|
10
|
+
import { createJavaScriptRegexEngine } from 'shiki/engine/javascript'
|
|
11
|
+
import htmlLang from 'shiki/langs/html.mjs'
|
|
12
|
+
import javascriptLang from 'shiki/langs/javascript.mjs'
|
|
13
|
+
import vueLang from 'shiki/langs/vue.mjs'
|
|
14
|
+
import githubDark from 'shiki/themes/github-dark.mjs'
|
|
15
|
+
import githubLight from 'shiki/themes/github-light.mjs'
|
|
9
16
|
import { computed } from 'vue'
|
|
10
17
|
|
|
11
|
-
import MarkdownCodePrism from './MarkdownCodePrism'
|
|
12
18
|
import MarkdownCopyButton from './MarkdownCopyButton.vue'
|
|
13
19
|
|
|
14
20
|
const props = defineProps({
|
|
@@ -28,4 +34,66 @@ const props = defineProps({
|
|
|
28
34
|
})
|
|
29
35
|
|
|
30
36
|
const style = computed(() => (props.maxHeight !== void 0 ? { maxHeight: props.maxHeight } : null))
|
|
37
|
+
|
|
38
|
+
const block = computed(() => {
|
|
39
|
+
return parseHighlightedBlock(highlightCode(props.code, props.lang))
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const highlighter = createHighlighterCoreSync({
|
|
43
|
+
engine: createJavaScriptRegexEngine(),
|
|
44
|
+
themes: [githubLight, githubDark],
|
|
45
|
+
langs: [htmlLang, javascriptLang, vueLang].flat(),
|
|
46
|
+
langAlias: {
|
|
47
|
+
bash: 'javascript',
|
|
48
|
+
css: 'html',
|
|
49
|
+
js: 'javascript',
|
|
50
|
+
markup: 'vue',
|
|
51
|
+
sass: 'html',
|
|
52
|
+
scss: 'html',
|
|
53
|
+
sh: 'javascript',
|
|
54
|
+
shell: 'javascript',
|
|
55
|
+
ts: 'javascript',
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
function highlightCode(code: string, lang: string): string {
|
|
60
|
+
const options = {
|
|
61
|
+
lang: normalizeLang(lang),
|
|
62
|
+
themes: {
|
|
63
|
+
light: 'github-light',
|
|
64
|
+
dark: 'github-dark',
|
|
65
|
+
},
|
|
66
|
+
defaultColor: false,
|
|
67
|
+
} as const
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
return highlighter.codeToHtml(code, options)
|
|
71
|
+
} catch {
|
|
72
|
+
return highlighter.codeToHtml(code, {
|
|
73
|
+
...options,
|
|
74
|
+
lang: 'text',
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function normalizeLang(lang: string): string {
|
|
80
|
+
return (
|
|
81
|
+
{
|
|
82
|
+
js: 'javascript',
|
|
83
|
+
markup: 'html',
|
|
84
|
+
ts: 'typescript',
|
|
85
|
+
}[lang] ?? lang
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function parseHighlightedBlock(html: string): { className: string; code: string; style: string } {
|
|
90
|
+
const match = html.match(/^<pre(?<attrs>[^>]*)><code>(?<code>[\s\S]*)<\/code><\/pre>$/)
|
|
91
|
+
const attrs = match?.groups?.attrs ?? ''
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
className: attrs.match(/class="(?<value>[^"]*)"/)?.groups?.value ?? 'shiki',
|
|
95
|
+
code: match?.groups?.code ?? '',
|
|
96
|
+
style: attrs.match(/style="(?<value>[^"]*)"/)?.groups?.value ?? '',
|
|
97
|
+
}
|
|
98
|
+
}
|
|
31
99
|
</script>
|
|
@@ -20,14 +20,14 @@ const internal = computed(
|
|
|
20
20
|
|
|
21
21
|
<style lang="scss">
|
|
22
22
|
.markdown-link {
|
|
23
|
-
color:
|
|
23
|
+
color: $brand-light-text;
|
|
24
24
|
text-decoration: none;
|
|
25
|
-
border-bottom: 1px dotted
|
|
25
|
+
border-bottom: 1px dotted rgba($brand-primary, 0.78);
|
|
26
26
|
outline: 0;
|
|
27
27
|
transition: color $header-quick-transition;
|
|
28
28
|
|
|
29
29
|
body.body--dark & {
|
|
30
|
-
color: $brand-
|
|
30
|
+
color: $brand-dark-text;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
&:hover {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
@use 'sass:math';
|
|
2
2
|
@use './fonts.scss';
|
|
3
3
|
|
|
4
|
-
// Keep this import so
|
|
5
|
-
@import './
|
|
4
|
+
// Keep this import so Shiki code blocks share the selected qPress theme variables.
|
|
5
|
+
@import './code-theme.scss';
|
|
6
6
|
|
|
7
7
|
.material-icons {
|
|
8
8
|
font-family: 'Material Icons';
|
|
@@ -83,9 +83,10 @@ ul {
|
|
|
83
83
|
line-height: $font-size;
|
|
84
84
|
border-radius: $generic-border-radius;
|
|
85
85
|
font-family: inherit;
|
|
86
|
-
color:
|
|
86
|
+
color: $brand-light-text;
|
|
87
|
+
background-color: rgba($brand-primary, 0.08);
|
|
87
88
|
vertical-align: baseline;
|
|
88
|
-
border: 1px solid
|
|
89
|
+
border: 1px solid rgba($brand-primary, 0.5);
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
.markdown-note {
|
|
@@ -108,10 +109,13 @@ ul {
|
|
|
108
109
|
// .markdown-note__title,
|
|
109
110
|
.markdown-link,
|
|
110
111
|
.markdown-token {
|
|
111
|
-
color:
|
|
112
|
+
color: $brand-light-text;
|
|
113
|
+
}
|
|
114
|
+
.markdown-link {
|
|
115
|
+
border-bottom-color: rgba($brand-primary, 0.78);
|
|
112
116
|
}
|
|
113
117
|
.markdown-token {
|
|
114
|
-
border-color:
|
|
118
|
+
border-color: rgba($brand-primary, 0.5);
|
|
115
119
|
}
|
|
116
120
|
& strong {
|
|
117
121
|
font-weight: 700;
|
|
@@ -553,6 +557,12 @@ $letter-spacing-list: 40, 100, 225, 263, 300, 375, 450;
|
|
|
553
557
|
}
|
|
554
558
|
|
|
555
559
|
body.body--dark {
|
|
560
|
+
.markdown-token {
|
|
561
|
+
color: $brand-dark-text;
|
|
562
|
+
background-color: rgba($brand-primary, 0.18);
|
|
563
|
+
border-color: rgba($brand-primary, 0.72);
|
|
564
|
+
}
|
|
565
|
+
|
|
556
566
|
.markdown-technical {
|
|
557
567
|
color: $brand-dark-text;
|
|
558
568
|
background: $brand-dark-bg;
|
|
@@ -29,11 +29,16 @@
|
|
|
29
29
|
&--copying {
|
|
30
30
|
.c-lpref,
|
|
31
31
|
.c-line,
|
|
32
|
-
.
|
|
33
|
-
.token.prefix {
|
|
32
|
+
.line.diff.remove {
|
|
34
33
|
display: none;
|
|
35
34
|
}
|
|
36
35
|
}
|
|
36
|
+
|
|
37
|
+
.line {
|
|
38
|
+
position: relative;
|
|
39
|
+
display: inline-block;
|
|
40
|
+
width: 100%;
|
|
41
|
+
}
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
.c-line {
|
|
@@ -100,6 +105,11 @@
|
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
body.body--light {
|
|
108
|
+
.shiki,
|
|
109
|
+
.shiki span {
|
|
110
|
+
color: var(--shiki-light);
|
|
111
|
+
}
|
|
112
|
+
|
|
103
113
|
.markdown-code {
|
|
104
114
|
color: $brand-light-codeblock-text;
|
|
105
115
|
background-color: $brand-light-codeblock-bg;
|
|
@@ -205,6 +215,11 @@ body.body--light {
|
|
|
205
215
|
}
|
|
206
216
|
|
|
207
217
|
body.body--dark {
|
|
218
|
+
.shiki,
|
|
219
|
+
.shiki span {
|
|
220
|
+
color: var(--shiki-dark);
|
|
221
|
+
}
|
|
222
|
+
|
|
208
223
|
.markdown-code {
|
|
209
224
|
color: $brand-dark-codeblock-text;
|
|
210
225
|
background-color: $brand-dark-codeblock-bg;
|
|
@@ -33,7 +33,7 @@ $light-pill: $brand-light;
|
|
|
33
33
|
$light-text: $brand-light-text;
|
|
34
34
|
$light-bg: $brand-light-bg;
|
|
35
35
|
|
|
36
|
-
$dark-pill: scale-color($brand-
|
|
36
|
+
$dark-pill: scale-color($brand-dark-bg, $lightness: 12%);
|
|
37
37
|
$dark-text: $brand-dark-text;
|
|
38
38
|
$dark-bg: $brand-dark-bg;
|
|
39
39
|
|
|
@@ -38,7 +38,7 @@ $light-pill: $brand-light;
|
|
|
38
38
|
$light-text: $brand-light-text;
|
|
39
39
|
$light-bg: $brand-light-bg;
|
|
40
40
|
|
|
41
|
-
$dark-pill: scale-color($brand-
|
|
41
|
+
$dark-pill: scale-color($brand-dark-bg, $lightness: 12%);
|
|
42
42
|
$dark-text: $brand-dark-text;
|
|
43
43
|
$dark-bg: $brand-dark-bg;
|
|
44
44
|
|
|
@@ -34,7 +34,7 @@ $light-pill: $brand-light;
|
|
|
34
34
|
$light-text: $brand-light-text;
|
|
35
35
|
$light-bg: $brand-light-bg;
|
|
36
36
|
|
|
37
|
-
$dark-pill: scale-color($brand-
|
|
37
|
+
$dark-pill: scale-color($brand-dark-bg, $lightness: 12%);
|
|
38
38
|
$dark-text: $brand-dark-text;
|
|
39
39
|
$dark-bg: $brand-dark-bg;
|
|
40
40
|
|
|
@@ -34,7 +34,7 @@ $light-pill: $brand-light;
|
|
|
34
34
|
$light-text: $brand-light-text;
|
|
35
35
|
$light-bg: $brand-light-bg;
|
|
36
36
|
|
|
37
|
-
$dark-pill: scale-color($brand-dark, $lightness:
|
|
37
|
+
$dark-pill: scale-color($brand-dark-bg, $lightness: 12%);
|
|
38
38
|
$dark-text: $brand-dark-text;
|
|
39
39
|
$dark-bg: $brand-dark-bg;
|
|
40
40
|
|
|
@@ -34,7 +34,7 @@ $light-pill: $brand-light;
|
|
|
34
34
|
$light-text: $brand-light-text;
|
|
35
35
|
$light-bg: $brand-light-bg;
|
|
36
36
|
|
|
37
|
-
$dark-pill: scale-color($brand-
|
|
37
|
+
$dark-pill: scale-color($brand-dark-bg, $lightness: 12%);
|
|
38
38
|
$dark-text: $brand-dark-text;
|
|
39
39
|
$dark-bg: $brand-dark-bg;
|
|
40
40
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
</span>
|
|
27
27
|
</router-link>
|
|
28
28
|
<router-link
|
|
29
|
-
to="/
|
|
29
|
+
to="/other/upgrade-guide"
|
|
30
30
|
class="hero-button q-btn q-btn-item non-selectable no-outline q-btn--standard q-btn--rectangle q-btn--actionable q-focusable q-hoverable q-btn--no-uppercase q-btn--rounded q-btn--dense"
|
|
31
31
|
>
|
|
32
32
|
<span
|
|
@@ -54,6 +54,10 @@
|
|
|
54
54
|
Markdown Plugins go beyond the standard Markdown syntax.<br />Discover the power of Markdown
|
|
55
55
|
Plugins and enhance your documentation experience!
|
|
56
56
|
</p>
|
|
57
|
+
<p>
|
|
58
|
+
Use the Markdown-it and Vite plugins in Vue/Vite projects, or choose the Quasar app
|
|
59
|
+
extensions when you want Q-Press and Quasar CLI Vite integration.
|
|
60
|
+
</p>
|
|
57
61
|
</div>
|
|
58
62
|
<div class="row justify-center hero">
|
|
59
63
|
<div class="hero-title">Markdown-It! Plugins</div>
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<q-card flat bordered>
|
|
3
|
+
<q-card-section v-if="error" class="row no-wrap items-center">
|
|
4
|
+
<q-icon name="warning" size="24px" color="negative" class="q-mr-sm" />
|
|
5
|
+
<div>Cannot connect to GitHub. Try again later.</div>
|
|
6
|
+
</q-card-section>
|
|
7
|
+
<q-card-section v-else-if="loading" class="row no-wrap items-center">
|
|
8
|
+
<q-spinner size="24px" color="primary" class="q-mr-sm" />
|
|
9
|
+
<div>Loading release notes from GitHub</div>
|
|
10
|
+
</q-card-section>
|
|
11
|
+
<template v-else>
|
|
12
|
+
<q-separator />
|
|
13
|
+
<q-tab-panels v-model="currentPackage" animated class="packages-container">
|
|
14
|
+
<q-tab-panel
|
|
15
|
+
v-for="(packageReleases, packageName) in packages"
|
|
16
|
+
:key="packageName"
|
|
17
|
+
:name="packageName"
|
|
18
|
+
class="q-pa-none"
|
|
19
|
+
>
|
|
20
|
+
<PackageReleases
|
|
21
|
+
:latest-version="latestVersions[packageName]"
|
|
22
|
+
:releases="packageReleases"
|
|
23
|
+
repo-url="https://github.com/md-plugins/md-plugins"
|
|
24
|
+
/>
|
|
25
|
+
</q-tab-panel>
|
|
26
|
+
</q-tab-panels>
|
|
27
|
+
</template>
|
|
28
|
+
</q-card>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup lang="ts">
|
|
32
|
+
import { onMounted, ref } from 'vue'
|
|
33
|
+
import { date } from 'quasar'
|
|
34
|
+
|
|
35
|
+
import PackageReleases from './PackageReleases.vue'
|
|
36
|
+
import type { ReleaseInfo } from './PackageReleases.vue'
|
|
37
|
+
|
|
38
|
+
const { extractDate, formatDate } = date
|
|
39
|
+
const packageName = 'MD-Plugins'
|
|
40
|
+
|
|
41
|
+
interface GitHubRelease {
|
|
42
|
+
name?: string
|
|
43
|
+
tag_name?: string
|
|
44
|
+
published_at: string
|
|
45
|
+
body?: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type ReleasePackageMap = Record<string, ReleaseInfo[]>
|
|
49
|
+
|
|
50
|
+
const loading = ref(false)
|
|
51
|
+
const error = ref(false)
|
|
52
|
+
const packages = ref<ReleasePackageMap>({ [packageName]: [] })
|
|
53
|
+
const currentPackage = ref(packageName)
|
|
54
|
+
const latestVersions = ref<Record<string, string>>({})
|
|
55
|
+
|
|
56
|
+
function getReleaseVersion(release: GitHubRelease): string | undefined {
|
|
57
|
+
const name = release.name || release.tag_name || ''
|
|
58
|
+
const match = name.match(/(?:^|\s)v?(\d+\.\d+\.\d+(?:[-\w.]+)?)/)
|
|
59
|
+
|
|
60
|
+
return match?.[1] ?? release.tag_name?.replace(/^v/, '')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function queryReleases(): Promise<void> {
|
|
64
|
+
loading.value = true
|
|
65
|
+
error.value = false
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const response = await fetch(
|
|
69
|
+
'https://api.github.com/repos/md-plugins/md-plugins/releases?per_page=100',
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if (response.ok === false) {
|
|
73
|
+
throw new Error(`GitHub request failed with ${response.status}`)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const releases = (await response.json()) as GitHubRelease[]
|
|
77
|
+
const parsedReleases = releases
|
|
78
|
+
.map((release) => {
|
|
79
|
+
const version = getReleaseVersion(release)
|
|
80
|
+
|
|
81
|
+
if (version === undefined) {
|
|
82
|
+
return null
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
version,
|
|
87
|
+
date: formatDate(extractDate(release.published_at, 'YYYY-MM-DD'), 'YYYY-MM-DD'),
|
|
88
|
+
body: release.body || '',
|
|
89
|
+
label: version,
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
.filter((release): release is ReleaseInfo => release !== null)
|
|
93
|
+
.sort((a, b) => {
|
|
94
|
+
return (
|
|
95
|
+
Number.parseInt(b.date.replace(/-/g, ''), 10) -
|
|
96
|
+
Number.parseInt(a.date.replace(/-/g, ''), 10)
|
|
97
|
+
)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
if (parsedReleases.length === 0) {
|
|
101
|
+
throw new Error('No releases returned from GitHub')
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
packages.value = { [packageName]: parsedReleases }
|
|
105
|
+
latestVersions.value = { [packageName]: parsedReleases[0]?.label ?? '' }
|
|
106
|
+
} catch {
|
|
107
|
+
error.value = true
|
|
108
|
+
} finally {
|
|
109
|
+
loading.value = false
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
onMounted(queryReleases)
|
|
114
|
+
</script>
|
|
115
|
+
|
|
116
|
+
<style lang="scss">
|
|
117
|
+
.packages-container .q-tab-panel {
|
|
118
|
+
padding-right: 0;
|
|
119
|
+
padding-top: 0;
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<q-input
|
|
4
|
+
v-model="search"
|
|
5
|
+
dense
|
|
6
|
+
square
|
|
7
|
+
borderless
|
|
8
|
+
color="white"
|
|
9
|
+
placeholder="Search..."
|
|
10
|
+
clearable
|
|
11
|
+
class="q-mx-md"
|
|
12
|
+
>
|
|
13
|
+
<template #prepend>
|
|
14
|
+
<q-icon :name="mdiMagnify" />
|
|
15
|
+
</template>
|
|
16
|
+
</q-input>
|
|
17
|
+
<q-separator />
|
|
18
|
+
<q-splitter :model-value="20" :limits="[14, 90]" class="release__splitter">
|
|
19
|
+
<template #before>
|
|
20
|
+
<q-scroll-area>
|
|
21
|
+
<q-tabs
|
|
22
|
+
v-model="selectedVersion"
|
|
23
|
+
vertical
|
|
24
|
+
active-color="primary"
|
|
25
|
+
active-bg-color="blue-1"
|
|
26
|
+
indicator-color="primary"
|
|
27
|
+
>
|
|
28
|
+
<q-tab
|
|
29
|
+
v-for="releaseInfo in filteredReleases"
|
|
30
|
+
:key="releaseInfo.label"
|
|
31
|
+
:name="releaseInfo.label"
|
|
32
|
+
>
|
|
33
|
+
<div class="q-tab__label">{{ releaseInfo.version }}</div>
|
|
34
|
+
<small class="text-grey-7">{{ releaseInfo.date }}</small>
|
|
35
|
+
</q-tab>
|
|
36
|
+
</q-tabs>
|
|
37
|
+
</q-scroll-area>
|
|
38
|
+
</template>
|
|
39
|
+
<template #after>
|
|
40
|
+
<q-tab-panels
|
|
41
|
+
v-model="selectedVersion"
|
|
42
|
+
animated
|
|
43
|
+
transition-prev="slide-down"
|
|
44
|
+
transition-next="slide-up"
|
|
45
|
+
class="releases-container"
|
|
46
|
+
>
|
|
47
|
+
<q-tab-panel
|
|
48
|
+
v-for="releaseInfo in filteredReleases"
|
|
49
|
+
:key="releaseInfo.label"
|
|
50
|
+
:name="releaseInfo.label"
|
|
51
|
+
class="q-pa-none"
|
|
52
|
+
>
|
|
53
|
+
<q-scroll-area>
|
|
54
|
+
<div class="q-pa-md" v-html="currentReleaseBody" />
|
|
55
|
+
</q-scroll-area>
|
|
56
|
+
</q-tab-panel>
|
|
57
|
+
</q-tab-panels>
|
|
58
|
+
</template>
|
|
59
|
+
</q-splitter>
|
|
60
|
+
</div>
|
|
61
|
+
</template>
|
|
62
|
+
|
|
63
|
+
<script setup lang="ts">
|
|
64
|
+
import { computed, ref, watch } from 'vue'
|
|
65
|
+
import { mdiMagnify } from '@quasar/extras/mdi-v7'
|
|
66
|
+
|
|
67
|
+
import sanitize from './sanitize'
|
|
68
|
+
import parseMdTable from './md-table-parser'
|
|
69
|
+
|
|
70
|
+
export interface ReleaseInfo {
|
|
71
|
+
version: string
|
|
72
|
+
date: string
|
|
73
|
+
body: string
|
|
74
|
+
label: string
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const props = withDefaults(
|
|
78
|
+
defineProps<{
|
|
79
|
+
latestVersion?: string | undefined
|
|
80
|
+
releases?: ReleaseInfo[]
|
|
81
|
+
repoUrl?: string
|
|
82
|
+
}>(),
|
|
83
|
+
{
|
|
84
|
+
releases: () => [],
|
|
85
|
+
repoUrl: 'https://github.com/md-plugins/md-plugins',
|
|
86
|
+
},
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
const search = ref('')
|
|
90
|
+
const selectedVersion = ref<string | undefined>(props.latestVersion)
|
|
91
|
+
|
|
92
|
+
watch(
|
|
93
|
+
() => props.latestVersion,
|
|
94
|
+
(val) => {
|
|
95
|
+
selectedVersion.value = val
|
|
96
|
+
},
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
const filteredReleases = computed(() => {
|
|
100
|
+
if (search.value !== '') {
|
|
101
|
+
const val = search.value.toLowerCase()
|
|
102
|
+
|
|
103
|
+
return props.releases.filter((release) => release.body.toLowerCase().includes(val))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return props.releases
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
function escapeRegExp(value: string): string {
|
|
110
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function parse(body: string): string {
|
|
114
|
+
let content = sanitize(body) + '\n'
|
|
115
|
+
|
|
116
|
+
if (search.value !== '') {
|
|
117
|
+
content = content.replace(
|
|
118
|
+
new RegExp(`(${escapeRegExp(search.value)})`, 'gi'),
|
|
119
|
+
'<span class="bg-accent text-white">$1</span>',
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
content = content
|
|
124
|
+
.replace(/### ([\S ]+)/g, '<div class="text-h6">$1</div>')
|
|
125
|
+
.replace(/## ([\S ]+)/g, '<div class="text-h5">$1</div>')
|
|
126
|
+
.replace(/# ([\S ]+)/g, '<div class="text-h4">$1</div>')
|
|
127
|
+
.replace(/\*\*([\S ]*?)\*\*/g, '<strong>$1</strong>')
|
|
128
|
+
.replace(/\*([\S ]*?)\*/g, '<em>$1</em>')
|
|
129
|
+
.replace(/```([\S]+)/g, '<pre class="markdown-code release__code"><code>')
|
|
130
|
+
.replace(/```\n/g, '</code></pre>')
|
|
131
|
+
.replace(/`(.*?)`/g, '<code class="markdown-token">$1</code>')
|
|
132
|
+
.replace(
|
|
133
|
+
/#([\d]+)/g,
|
|
134
|
+
`<a class="markdown-link" href="${props.repoUrl}/issues/$1" target="_blank">#$1</a>`,
|
|
135
|
+
)
|
|
136
|
+
.replace(/^> ([\S ]+)$/gm, '<div class="release__blockquote">$1</div>')
|
|
137
|
+
.replace(
|
|
138
|
+
/\[([\S ]*?)\]\((\S*?)\)/g,
|
|
139
|
+
'<a class="markdown-link" href="$2" target="_blank">$1</a>',
|
|
140
|
+
)
|
|
141
|
+
.replace(/^ {2}[-*] ([\S .]+)$/gm, '<li class="q-pl-md">$1</li>')
|
|
142
|
+
.replace(/^[-*] ([\S .]+)$/gm, '<li>$1</li>')
|
|
143
|
+
.replace(/<\/li>[\s\n\r]*<li/g, '</li><li')
|
|
144
|
+
.replace(/(<li(?: class="[^"]*")?>.*?<\/li>)+/g, '<ul class="release__list">$&</ul>')
|
|
145
|
+
.replace(/\n/g, '<br>')
|
|
146
|
+
|
|
147
|
+
return content.includes('| -') ? parseMdTable(content) : content
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const currentReleaseBody = computed(() => {
|
|
151
|
+
const release = props.releases.find((entry) => entry.label === selectedVersion.value)
|
|
152
|
+
|
|
153
|
+
return release ? parse(release.body) : ''
|
|
154
|
+
})
|
|
155
|
+
</script>
|
|
156
|
+
|
|
157
|
+
<style lang="scss">
|
|
158
|
+
.release__splitter .q-scrollarea {
|
|
159
|
+
height: 600px;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.release__body {
|
|
163
|
+
white-space: pre-line;
|
|
164
|
+
|
|
165
|
+
.q-markup-table {
|
|
166
|
+
white-space: normal;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.release__list {
|
|
171
|
+
margin: 8px 0 16px;
|
|
172
|
+
padding-left: 28px;
|
|
173
|
+
|
|
174
|
+
li {
|
|
175
|
+
margin: 4px 0;
|
|
176
|
+
padding-left: 4px;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.release__blockquote {
|
|
181
|
+
background: rgba($primary, 0.05);
|
|
182
|
+
border: 1px solid $primary;
|
|
183
|
+
padding: 4px 8px;
|
|
184
|
+
border-radius: $generic-border-radius;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.release__code {
|
|
188
|
+
padding: 4px;
|
|
189
|
+
margin: 8px;
|
|
190
|
+
}
|
|
191
|
+
</style>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
function getTable(rows: string[]): string {
|
|
2
|
+
const header = (rows[0] ?? '')
|
|
3
|
+
.split('|')
|
|
4
|
+
.filter((col) => col)
|
|
5
|
+
.map((col) => `<th class="text-left">${col.trim()}</th>`)
|
|
6
|
+
.join('')
|
|
7
|
+
|
|
8
|
+
const body = rows
|
|
9
|
+
.slice(2)
|
|
10
|
+
.map(
|
|
11
|
+
(row) =>
|
|
12
|
+
'<tr>' +
|
|
13
|
+
row
|
|
14
|
+
.split('|')
|
|
15
|
+
.filter((col) => col)
|
|
16
|
+
.map((col) => `<td>${col.trim()}</td>`)
|
|
17
|
+
.join('') +
|
|
18
|
+
'</tr>',
|
|
19
|
+
)
|
|
20
|
+
.join('')
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
'<div class="q-markup-table q-table__container q-table__card ' +
|
|
24
|
+
'q-table--horizontal-separator q-table--flat q-table--bordered ' +
|
|
25
|
+
'q-table--no-wrap q-table--dense">' +
|
|
26
|
+
`<table class="q-table"><thead>${header}</thead>` +
|
|
27
|
+
`<tbody>${body}</tbody></table></div>`
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default function parseMdTable(raw: string): string {
|
|
32
|
+
let content = ''
|
|
33
|
+
let tableRows: string[] = []
|
|
34
|
+
|
|
35
|
+
for (const row of raw.split('\n')) {
|
|
36
|
+
if (row.indexOf('|') > -1) {
|
|
37
|
+
tableRows.push(row.trim())
|
|
38
|
+
} else {
|
|
39
|
+
if (tableRows.length > 0) {
|
|
40
|
+
content += getTable(tableRows) + '\n'
|
|
41
|
+
tableRows = []
|
|
42
|
+
}
|
|
43
|
+
content += row + '\n'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (tableRows.length > 0) {
|
|
48
|
+
content += getTable(tableRows) + '\n'
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return content
|
|
52
|
+
}
|