@docsector/docsector-reader 4.0.0 โ 4.1.0
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 +22 -4
- package/bin/docsector.js +1 -1
- package/package.json +1 -1
- package/src/components/DBlockCodeExample.vue +423 -0
- package/src/components/DBlockExpandable.vue +1 -0
- package/src/components/DBlockSourceCode.vue +1 -7
- package/src/components/DPageSection.vue +5 -0
- package/src/components/DPageTokens.vue +24 -1
- package/src/components/DSubpage.vue +14 -2
- package/src/components/code-block-highlighting.js +16 -0
- package/src/components/code-example-source.js +363 -0
- package/src/components/page-section-tokens.js +89 -1
- package/src/composables/useActiveAnchor.js +42 -0
- package/src/composables/useNavigator.js +24 -17
- package/src/examples/manual/code-examples/BasicCounter.vue +63 -0
- package/src/examples/manual/code-examples/InlineNotice.vue +60 -0
- package/src/home-page-mode.js +5 -0
- package/src/pages/manual/basic/d-page-anchor.overview.en-US.md +1 -1
- package/src/pages/manual/basic/d-page-anchor.overview.pt-BR.md +1 -1
- package/src/pages/manual/content/blocks/code-examples.overview.en-US.md +56 -0
- package/src/pages/manual/content/blocks/code-examples.overview.pt-BR.md +56 -0
- package/src/pages/manual/content/blocks/code-examples.showcase.en-US.md +38 -0
- package/src/pages/manual/content/blocks/code-examples.showcase.pt-BR.md +38 -0
- package/src/pages/manual.index.js +28 -0
- package/src/quasar.factory.js +90 -11
- package/src/store/Page.js +28 -2
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
<h1 align="center">Docsector Reader ๐</h1>
|
|
5
5
|
<p align="center">
|
|
6
|
-
<i>A documentation rendering engine built with Vue 3, Quasar v2 and Vite.</i>
|
|
6
|
+
<i>A documentation rendering engine built with Vue 3, Quasar v2 and Vite with AI features.</i>
|
|
7
7
|
</p>
|
|
8
8
|
<p align="center">
|
|
9
9
|
<a href="https://www.npmjs.com/package/@docsector/docsector-reader">
|
|
@@ -50,7 +50,7 @@ Transform Markdown content into beautiful, navigable documentation sites โ wit
|
|
|
50
50
|
- ๐จ **GitHub-Style Alerts** โ Native support for `[!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]`, and `[!CAUTION]`
|
|
51
51
|
- ๐ **Internationalization (i18n)** โ Multi-language support with HJSON locale files and per-page translations
|
|
52
52
|
- ๐ **Dark/Light Mode** โ Automatic theme switching with Quasar Dark Plugin
|
|
53
|
-
- ๐ **Anchor Navigation** โ Right-side Table of Contents tree with scroll tracking
|
|
53
|
+
- ๐ **Anchor Navigation** โ Right-side Table of Contents tree with stable scroll tracking, auto-scroll to the active section, and active-heading resolution based on the last heading that crossed the content threshold
|
|
54
54
|
- ๐ฑ๏ธ **Active Menu Item UX** โ Active menu entries keep pointer cursor, clear URL hash without redundant navigation, and prevent accidental label text selection
|
|
55
55
|
- ๐ **Search** โ Menu search across all documentation content and tags
|
|
56
56
|
- ๐ฑ **Responsive** โ Mobile-friendly with collapsible sidebar and drawers
|
|
@@ -65,7 +65,7 @@ Transform Markdown content into beautiful, navigable documentation sites โ wit
|
|
|
65
65
|
- ๐ **Translation Progress** โ Automatic translation percentage based on header coverage
|
|
66
66
|
- ๐ **Accurate Available Translations** โ Locale availability counter now uses actual localized page source presence, avoiding false negatives when metadata is equal
|
|
67
67
|
- ๐ **Markdown Home at Root** โ Homepage is rendered from `src/pages/Homepage.{lang}.md` directly at `/`
|
|
68
|
-
- ๐ **Remote README as Home** โ Optional build-time remote README source for homepage with automatic local fallback
|
|
68
|
+
- ๐ **Remote README as Home** โ Optional build-time remote README source for homepage with automatic local fallback and automatic primary-title handoff when the remote README already provides the project heading
|
|
69
69
|
- ๐ **GitHub-Compatible Heading Anchors** โ Markdown headings use GitHub-style slugs so standard README Table of Contents links work inside Docsector
|
|
70
70
|
- ๐งฌ **Scaffolded Homepage Override Wiring** โ New consumer projects automatically wire `virtual:docsector-homepage-override` into i18n message building
|
|
71
71
|
- ๐ **Expandable Markdown Sections** โ Use `<d-block-expandable title="...">...</d-block-expandable>` to collapse secondary content while keeping rich Markdown support inside the body
|
|
@@ -79,6 +79,7 @@ Transform Markdown content into beautiful, navigable documentation sites โ wit
|
|
|
79
79
|
- ๐๏ธ **Multi-Version History** โ Archive older major versions under `src/pages/.old/<version>/` and expose them at prefixed routes (e.g. `/v0.x/guide/...`) while keeping the current docs at unprefixed routes
|
|
80
80
|
- ๐ท๏ธ **Version Selector Badges** โ Every version in the sidebar selector displays a color-coded badge: green for released, orange for draft, red for deprecated; fully customizable via `badge: { label, color, textColor }`
|
|
81
81
|
- ๐ **Tabbed Code Blocks** โ Group consecutive fenced code blocks into tabs using the `group` and `tab` attributes in the fence info line
|
|
82
|
+
- ๐งช **Live Code Example Blocks** โ Use `<d-block-code-example src="..." />` to render bundled Vue SFC examples with a live preview, GitHub source link, source toggle, and CodePen export for compatible examples
|
|
82
83
|
- ๐ **Breadcrumb Path Display** โ Show a file path breadcrumb above code blocks with the `breadcrumb` attribute; renders as clickable path segments
|
|
83
84
|
- ๐จ **File Type Icons** โ Automatically resolves file extension or filename to a Material Icon Theme SVG icon, shown inline in tabs and beside the last breadcrumb segment
|
|
84
85
|
- โ๏ธ **Single Config File** โ Customize branding, links, and languages via `docsector.config.js`
|
|
@@ -360,7 +361,8 @@ You can configure Docsector Reader to use a remote README as homepage content.
|
|
|
360
361
|
|
|
361
362
|
- Fetch happens at build-time.
|
|
362
363
|
- The same README content is used for all configured languages.
|
|
363
|
-
-
|
|
364
|
+
- When the remote README resolves successfully, Docsector hides the autogenerated homepage title and uses the README's own primary heading in the rendered content.
|
|
365
|
+
- If fetch fails, it falls back to local `src/pages/Homepage.{lang}.md` by default and keeps the usual autogenerated homepage title.
|
|
364
366
|
- Standard GitHub-style heading links and README Table of Contents fragments keep working in the rendered homepage.
|
|
365
367
|
|
|
366
368
|
### Configure
|
|
@@ -1022,6 +1024,22 @@ Notes:
|
|
|
1022
1024
|
Supported alert types: `NOTE`, `TIP`, `IMPORTANT`, `WARNING`, `CAUTION`.
|
|
1023
1025
|
Regular blockquotes without `[!TYPE]` continue to work normally.
|
|
1024
1026
|
|
|
1027
|
+
### Code Example Blocks
|
|
1028
|
+
|
|
1029
|
+
```html
|
|
1030
|
+
<d-block-code-example src="manual/code-examples/basic-counter" title="Basic counter">
|
|
1031
|
+
Optional caption rendered as inline Markdown.
|
|
1032
|
+
</d-block-code-example>
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
Notes:
|
|
1036
|
+
|
|
1037
|
+
- Store live examples as Vue SFCs under `src/examples/**/*.vue`; for example, `src="manual/code-examples/basic-counter"` resolves `src/examples/manual/code-examples/BasicCounter.vue` after kebab-case normalization.
|
|
1038
|
+
- Readers get a live preview, a GitHub button for the example SFC, a source button with Template / Script / Style / All tabs, and a CodePen button when the example can be exported safely.
|
|
1039
|
+
- Use `expanded="true"` only when the source code should be visible by default.
|
|
1040
|
+
- CodePen export currently supports plain Vue SFCs with a template, optional style, and an Options API `export default` script. Named imports from `vue` and `quasar` are converted to browser globals.
|
|
1041
|
+
- Examples using `<script setup>`, TypeScript scripts, or local imports still render in Docsector, but the CodePen action is disabled. Use `codepen="false"` to hide it intentionally.
|
|
1042
|
+
|
|
1025
1043
|
### File Attachment Blocks
|
|
1026
1044
|
|
|
1027
1045
|
```html
|
package/bin/docsector.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docsector/docsector-reader",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "A documentation rendering engine built with Vue 3, Quasar v2 and Vite. Transform Markdown into beautiful, navigable documentation sites.",
|
|
5
5
|
"productName": "Docsector Reader",
|
|
6
6
|
"author": "Rodrigo de Araujo Vieira",
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, markRaw, ref, watch } from 'vue'
|
|
3
|
+
import { openURL, Quasar, useQuasar } from 'quasar'
|
|
4
|
+
|
|
5
|
+
import { resolveCodeExample } from 'virtual:docsector-code-examples'
|
|
6
|
+
import docsectorConfig from 'docsector.config.js'
|
|
7
|
+
|
|
8
|
+
import DBlockSourceCode from './DBlockSourceCode.vue'
|
|
9
|
+
import {
|
|
10
|
+
canCreateCodepenPayload,
|
|
11
|
+
createCodeExampleGitHubUrl,
|
|
12
|
+
createCodeExampleTabs,
|
|
13
|
+
createCodepenPayload,
|
|
14
|
+
getCodepenUnsupportedReason
|
|
15
|
+
} from './code-example-source'
|
|
16
|
+
|
|
17
|
+
defineOptions({
|
|
18
|
+
name: 'DBlockCodeExample'
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const props = defineProps({
|
|
22
|
+
index: {
|
|
23
|
+
type: Number,
|
|
24
|
+
required: true
|
|
25
|
+
},
|
|
26
|
+
src: {
|
|
27
|
+
type: String,
|
|
28
|
+
default: ''
|
|
29
|
+
},
|
|
30
|
+
title: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: ''
|
|
33
|
+
},
|
|
34
|
+
caption: {
|
|
35
|
+
type: String,
|
|
36
|
+
default: ''
|
|
37
|
+
},
|
|
38
|
+
expanded: {
|
|
39
|
+
type: Boolean,
|
|
40
|
+
default: false
|
|
41
|
+
},
|
|
42
|
+
codepen: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: true
|
|
45
|
+
},
|
|
46
|
+
scrollable: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: false
|
|
49
|
+
},
|
|
50
|
+
overflow: {
|
|
51
|
+
type: Boolean,
|
|
52
|
+
default: false
|
|
53
|
+
},
|
|
54
|
+
height: {
|
|
55
|
+
type: String,
|
|
56
|
+
default: ''
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const $q = useQuasar()
|
|
61
|
+
|
|
62
|
+
const isBusy = ref(false)
|
|
63
|
+
const errorMessage = ref('')
|
|
64
|
+
const component = ref(null)
|
|
65
|
+
const sourceText = ref('')
|
|
66
|
+
const sourceTabs = ref([])
|
|
67
|
+
const sourceOpen = ref(props.expanded)
|
|
68
|
+
const exampleFilePath = ref('')
|
|
69
|
+
let requestIndex = 0
|
|
70
|
+
|
|
71
|
+
const displayTitle = computed(() => props.title || props.src || 'Code example')
|
|
72
|
+
const frameTone = computed(() => $q.dark.isActive ? 'dark' : 'light')
|
|
73
|
+
const hasSource = computed(() => sourceText.value.trim().length > 0)
|
|
74
|
+
const codepenUnsupportedReason = computed(() => {
|
|
75
|
+
if (!hasSource.value) {
|
|
76
|
+
return 'Source code is still loading.'
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return getCodepenUnsupportedReason(sourceText.value)
|
|
80
|
+
})
|
|
81
|
+
const canOpenCodepen = computed(() => props.codepen && hasSource.value && canCreateCodepenPayload(sourceText.value))
|
|
82
|
+
const codepenTooltip = computed(() => canOpenCodepen.value ? 'Edit in CodePen' : codepenUnsupportedReason.value)
|
|
83
|
+
const githubUrl = computed(() => createCodeExampleGitHubUrl(exampleFilePath.value, docsectorConfig))
|
|
84
|
+
const canOpenGitHub = computed(() => githubUrl.value !== '')
|
|
85
|
+
const previewStyle = computed(() => {
|
|
86
|
+
const style = {}
|
|
87
|
+
const normalizedHeight = normalizeCssLength(props.height)
|
|
88
|
+
|
|
89
|
+
if (normalizedHeight) {
|
|
90
|
+
style.height = normalizedHeight
|
|
91
|
+
} else if (props.scrollable) {
|
|
92
|
+
style.height = '500px'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return style
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
watch(() => props.expanded, (value) => {
|
|
99
|
+
sourceOpen.value = value
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
watch(() => props.src, () => {
|
|
103
|
+
loadExample()
|
|
104
|
+
}, { immediate: true })
|
|
105
|
+
|
|
106
|
+
function normalizeCssLength (value = '') {
|
|
107
|
+
const normalized = String(value || '').trim()
|
|
108
|
+
|
|
109
|
+
if (!normalized) {
|
|
110
|
+
return ''
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (/^-?\d+(?:\.\d+)?$/.test(normalized)) {
|
|
114
|
+
return `${normalized}px`
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return normalized
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function loadExample () {
|
|
121
|
+
const currentRequest = ++requestIndex
|
|
122
|
+
const resolved = resolveCodeExample(props.src)
|
|
123
|
+
|
|
124
|
+
isBusy.value = true
|
|
125
|
+
errorMessage.value = ''
|
|
126
|
+
component.value = null
|
|
127
|
+
sourceText.value = ''
|
|
128
|
+
sourceTabs.value = []
|
|
129
|
+
exampleFilePath.value = ''
|
|
130
|
+
|
|
131
|
+
if (!props.src) {
|
|
132
|
+
errorMessage.value = 'Code example source is missing.'
|
|
133
|
+
isBusy.value = false
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!resolved.exists || typeof resolved.loadComponent !== 'function' || typeof resolved.loadSource !== 'function') {
|
|
138
|
+
errorMessage.value = `Code example not found: ${resolved.id || props.src}`
|
|
139
|
+
isBusy.value = false
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const [componentModule, rawSource] = await Promise.all([
|
|
145
|
+
resolved.loadComponent(),
|
|
146
|
+
resolved.loadSource()
|
|
147
|
+
])
|
|
148
|
+
|
|
149
|
+
if (currentRequest !== requestIndex) {
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
component.value = markRaw(componentModule.default || componentModule)
|
|
154
|
+
sourceText.value = String(rawSource || '')
|
|
155
|
+
sourceTabs.value = createCodeExampleTabs(sourceText.value)
|
|
156
|
+
exampleFilePath.value = resolved.filePath || ''
|
|
157
|
+
} catch (err) {
|
|
158
|
+
if (currentRequest !== requestIndex) {
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
errorMessage.value = err?.message || `Unable to load code example: ${props.src}`
|
|
163
|
+
} finally {
|
|
164
|
+
if (currentRequest === requestIndex) {
|
|
165
|
+
isBusy.value = false
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function toggleSource () {
|
|
171
|
+
sourceOpen.value = !sourceOpen.value
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function submitCodepenPayload (payload) {
|
|
175
|
+
if (typeof document === 'undefined') {
|
|
176
|
+
return
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const form = document.createElement('form')
|
|
180
|
+
const input = document.createElement('input')
|
|
181
|
+
|
|
182
|
+
form.method = 'post'
|
|
183
|
+
form.action = 'https://codepen.io/pen/define/'
|
|
184
|
+
form.target = '_blank'
|
|
185
|
+
form.rel = 'noopener'
|
|
186
|
+
form.style.display = 'none'
|
|
187
|
+
|
|
188
|
+
input.type = 'hidden'
|
|
189
|
+
input.name = 'data'
|
|
190
|
+
input.value = JSON.stringify(payload)
|
|
191
|
+
|
|
192
|
+
form.appendChild(input)
|
|
193
|
+
document.body.appendChild(form)
|
|
194
|
+
form.submit()
|
|
195
|
+
form.remove()
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function openCodepen () {
|
|
199
|
+
if (!canOpenCodepen.value) {
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const sourceUrl = typeof window === 'undefined'
|
|
204
|
+
? ''
|
|
205
|
+
: `${window.location.origin}${window.location.pathname}${window.location.hash}`
|
|
206
|
+
|
|
207
|
+
submitCodepenPayload(createCodepenPayload(sourceText.value, {
|
|
208
|
+
title: displayTitle.value,
|
|
209
|
+
quasarVersion: Quasar.version,
|
|
210
|
+
sourceUrl
|
|
211
|
+
}))
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function openGitHub () {
|
|
215
|
+
if (canOpenGitHub.value) {
|
|
216
|
+
openURL(githubUrl.value)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
</script>
|
|
220
|
+
|
|
221
|
+
<template>
|
|
222
|
+
<div
|
|
223
|
+
class="d-block-code-example"
|
|
224
|
+
:class="`d-block-code-example--${frameTone}`"
|
|
225
|
+
>
|
|
226
|
+
<div class="d-block-code-example__toolbar">
|
|
227
|
+
<div class="d-block-code-example__title">{{ displayTitle }}</div>
|
|
228
|
+
|
|
229
|
+
<q-space />
|
|
230
|
+
|
|
231
|
+
<q-btn
|
|
232
|
+
class="d-block-code-example__button"
|
|
233
|
+
dense
|
|
234
|
+
flat
|
|
235
|
+
round
|
|
236
|
+
icon="fab fa-github"
|
|
237
|
+
:disable="!canOpenGitHub"
|
|
238
|
+
aria-label="View example on GitHub"
|
|
239
|
+
@click="openGitHub"
|
|
240
|
+
>
|
|
241
|
+
<q-tooltip>{{ canOpenGitHub ? 'View on GitHub' : 'GitHub source is unavailable' }}</q-tooltip>
|
|
242
|
+
</q-btn>
|
|
243
|
+
|
|
244
|
+
<q-btn
|
|
245
|
+
v-if="codepen"
|
|
246
|
+
class="d-block-code-example__button"
|
|
247
|
+
dense
|
|
248
|
+
flat
|
|
249
|
+
round
|
|
250
|
+
icon="fab fa-codepen"
|
|
251
|
+
:disable="!canOpenCodepen"
|
|
252
|
+
aria-label="Edit in CodePen"
|
|
253
|
+
@click="openCodepen"
|
|
254
|
+
>
|
|
255
|
+
<q-tooltip>{{ codepenTooltip }}</q-tooltip>
|
|
256
|
+
</q-btn>
|
|
257
|
+
|
|
258
|
+
<q-btn
|
|
259
|
+
class="d-block-code-example__button"
|
|
260
|
+
dense
|
|
261
|
+
flat
|
|
262
|
+
round
|
|
263
|
+
icon="code"
|
|
264
|
+
:disable="!hasSource"
|
|
265
|
+
:aria-label="sourceOpen ? 'Hide source' : 'View source'"
|
|
266
|
+
@click="toggleSource"
|
|
267
|
+
>
|
|
268
|
+
<q-tooltip>{{ sourceOpen ? 'Hide source' : 'View source' }}</q-tooltip>
|
|
269
|
+
</q-btn>
|
|
270
|
+
</div>
|
|
271
|
+
|
|
272
|
+
<q-slide-transition>
|
|
273
|
+
<div
|
|
274
|
+
v-show="sourceOpen && hasSource"
|
|
275
|
+
class="d-block-code-example__source"
|
|
276
|
+
>
|
|
277
|
+
<d-block-source-code
|
|
278
|
+
:index="index"
|
|
279
|
+
language="vue"
|
|
280
|
+
:text="sourceText"
|
|
281
|
+
:tabs="sourceTabs"
|
|
282
|
+
/>
|
|
283
|
+
</div>
|
|
284
|
+
</q-slide-transition>
|
|
285
|
+
|
|
286
|
+
<q-linear-progress
|
|
287
|
+
v-if="isBusy"
|
|
288
|
+
color="primary"
|
|
289
|
+
indeterminate
|
|
290
|
+
/>
|
|
291
|
+
|
|
292
|
+
<div
|
|
293
|
+
class="d-block-code-example__preview"
|
|
294
|
+
:class="{
|
|
295
|
+
'd-block-code-example__preview--scrollable': scrollable,
|
|
296
|
+
'd-block-code-example__preview--overflow': overflow
|
|
297
|
+
}"
|
|
298
|
+
:style="previewStyle"
|
|
299
|
+
>
|
|
300
|
+
<component
|
|
301
|
+
v-if="component && !errorMessage"
|
|
302
|
+
:is="component"
|
|
303
|
+
class="d-block-code-example__component"
|
|
304
|
+
/>
|
|
305
|
+
|
|
306
|
+
<div
|
|
307
|
+
v-else-if="errorMessage"
|
|
308
|
+
class="d-block-code-example__fallback"
|
|
309
|
+
>
|
|
310
|
+
<q-icon
|
|
311
|
+
name="warning"
|
|
312
|
+
size="22px"
|
|
313
|
+
/>
|
|
314
|
+
<span>{{ errorMessage }}</span>
|
|
315
|
+
</div>
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
<div
|
|
319
|
+
v-if="caption"
|
|
320
|
+
class="d-block-code-example__caption"
|
|
321
|
+
v-html="caption"
|
|
322
|
+
></div>
|
|
323
|
+
</div>
|
|
324
|
+
</template>
|
|
325
|
+
|
|
326
|
+
<style lang="sass">
|
|
327
|
+
body.body--light
|
|
328
|
+
--d-code-example-bg: #ffffff
|
|
329
|
+
--d-code-example-border: rgba(37, 67, 45, 0.16)
|
|
330
|
+
--d-code-example-toolbar-bg: #f6f8f5
|
|
331
|
+
--d-code-example-toolbar-text: #26352b
|
|
332
|
+
--d-code-example-preview-bg: #ffffff
|
|
333
|
+
--d-code-example-caption: #405148
|
|
334
|
+
--d-code-example-muted: #5d7563
|
|
335
|
+
|
|
336
|
+
body.body--dark
|
|
337
|
+
--d-code-example-bg: #111512
|
|
338
|
+
--d-code-example-border: rgba(197, 220, 200, 0.18)
|
|
339
|
+
--d-code-example-toolbar-bg: #1a211c
|
|
340
|
+
--d-code-example-toolbar-text: #e8efe9
|
|
341
|
+
--d-code-example-preview-bg: #0c0f0d
|
|
342
|
+
--d-code-example-caption: #c7d4ca
|
|
343
|
+
--d-code-example-muted: #9aafa0
|
|
344
|
+
|
|
345
|
+
.d-block-code-example
|
|
346
|
+
background: var(--d-code-example-bg)
|
|
347
|
+
border: 1px solid var(--d-code-example-border)
|
|
348
|
+
border-radius: 6px
|
|
349
|
+
box-shadow: 0 1px 1px rgb(0 0 0 / 8%)
|
|
350
|
+
margin: 18px 0
|
|
351
|
+
max-width: calc(100vw - 40px)
|
|
352
|
+
overflow: hidden
|
|
353
|
+
|
|
354
|
+
&__toolbar
|
|
355
|
+
align-items: center
|
|
356
|
+
background: var(--d-code-example-toolbar-bg)
|
|
357
|
+
color: var(--d-code-example-toolbar-text)
|
|
358
|
+
display: flex
|
|
359
|
+
gap: 4px
|
|
360
|
+
min-height: 42px
|
|
361
|
+
min-width: 0
|
|
362
|
+
padding: 4px 8px 4px 14px
|
|
363
|
+
|
|
364
|
+
&__title
|
|
365
|
+
font-size: 14px
|
|
366
|
+
font-weight: 600
|
|
367
|
+
line-height: 20px
|
|
368
|
+
min-width: 0
|
|
369
|
+
overflow: hidden
|
|
370
|
+
text-overflow: ellipsis
|
|
371
|
+
white-space: nowrap
|
|
372
|
+
|
|
373
|
+
&__button
|
|
374
|
+
color: var(--d-code-example-muted)
|
|
375
|
+
flex: 0 0 auto
|
|
376
|
+
|
|
377
|
+
&__source
|
|
378
|
+
border-top: 1px solid var(--d-code-example-border)
|
|
379
|
+
|
|
380
|
+
.source-code
|
|
381
|
+
box-shadow: none
|
|
382
|
+
margin: 0
|
|
383
|
+
max-width: 100%
|
|
384
|
+
|
|
385
|
+
.source-code-frame
|
|
386
|
+
border: 0
|
|
387
|
+
border-radius: 0
|
|
388
|
+
|
|
389
|
+
&__preview
|
|
390
|
+
background: var(--d-code-example-preview-bg)
|
|
391
|
+
min-height: 96px
|
|
392
|
+
min-width: 0
|
|
393
|
+
overflow: hidden
|
|
394
|
+
position: relative
|
|
395
|
+
|
|
396
|
+
&--scrollable
|
|
397
|
+
overflow-y: auto
|
|
398
|
+
|
|
399
|
+
&--overflow
|
|
400
|
+
overflow: auto
|
|
401
|
+
|
|
402
|
+
&__component
|
|
403
|
+
display: block
|
|
404
|
+
min-width: 0
|
|
405
|
+
|
|
406
|
+
&__fallback
|
|
407
|
+
align-items: center
|
|
408
|
+
color: var(--d-code-example-muted)
|
|
409
|
+
display: flex
|
|
410
|
+
gap: 8px
|
|
411
|
+
min-height: 96px
|
|
412
|
+
padding: 18px
|
|
413
|
+
|
|
414
|
+
&__caption
|
|
415
|
+
border-top: 1px solid var(--d-code-example-border)
|
|
416
|
+
color: var(--d-code-example-caption)
|
|
417
|
+
font-size: 14px
|
|
418
|
+
line-height: 1.55
|
|
419
|
+
padding: 10px 14px 12px
|
|
420
|
+
|
|
421
|
+
p
|
|
422
|
+
margin: 0
|
|
423
|
+
</style>
|
|
@@ -2,13 +2,7 @@
|
|
|
2
2
|
import { ref, computed, watch } from 'vue'
|
|
3
3
|
import { useQuasar } from 'quasar'
|
|
4
4
|
import { useStore } from 'vuex'
|
|
5
|
-
import Prism from '
|
|
6
|
-
// @ Load Prism languages
|
|
7
|
-
import 'prismjs/components/prism-markup-templating' // dependency for prism-php extension
|
|
8
|
-
// PHP
|
|
9
|
-
import 'prismjs/components/prism-php'
|
|
10
|
-
// Bash
|
|
11
|
-
import 'prismjs/components/prism-bash'
|
|
5
|
+
import Prism from './code-block-highlighting'
|
|
12
6
|
import { looksLikeFileName, resolveFileIconUrl } from '../composables/useFileIcon'
|
|
13
7
|
|
|
14
8
|
defineOptions({
|
|
@@ -11,6 +11,10 @@ defineProps({
|
|
|
11
11
|
id: {
|
|
12
12
|
type: Number,
|
|
13
13
|
required: true
|
|
14
|
+
},
|
|
15
|
+
renderPrimaryHeading: {
|
|
16
|
+
type: Boolean,
|
|
17
|
+
default: false
|
|
14
18
|
}
|
|
15
19
|
})
|
|
16
20
|
|
|
@@ -32,6 +36,7 @@ const tokenized = computed(() => {
|
|
|
32
36
|
<section>
|
|
33
37
|
<d-page-tokens
|
|
34
38
|
:id="id"
|
|
39
|
+
:render-primary-heading="renderPrimaryHeading"
|
|
35
40
|
:tokens="tokenized"
|
|
36
41
|
/>
|
|
37
42
|
</section>
|
|
@@ -8,6 +8,10 @@ defineProps({
|
|
|
8
8
|
type: Number,
|
|
9
9
|
default: 0
|
|
10
10
|
},
|
|
11
|
+
renderPrimaryHeading: {
|
|
12
|
+
type: Boolean,
|
|
13
|
+
default: false
|
|
14
|
+
},
|
|
11
15
|
tokens: {
|
|
12
16
|
type: Array,
|
|
13
17
|
default: () => []
|
|
@@ -30,12 +34,18 @@ import DBlockQuickLinks from './DBlockQuickLinks.vue'
|
|
|
30
34
|
import DBlockTimeline from './DBlockTimeline.vue'
|
|
31
35
|
import DBlockExpandable from './DBlockExpandable.vue'
|
|
32
36
|
import DBlockStepper from './DBlockStepper.vue'
|
|
37
|
+
import DBlockCodeExample from './DBlockCodeExample.vue'
|
|
33
38
|
</script>
|
|
34
39
|
|
|
35
40
|
<template>
|
|
36
41
|
<template v-for="(token, index) in tokens" :key="`${token.tag}-${index}`">
|
|
42
|
+
<h1
|
|
43
|
+
v-if="token.tag === 'h1' && renderPrimaryHeading"
|
|
44
|
+
:id="token.anchorId"
|
|
45
|
+
v-html="token.content"
|
|
46
|
+
></h1>
|
|
37
47
|
<d-h2
|
|
38
|
-
v-if="token.tag === 'h2'"
|
|
48
|
+
v-else-if="token.tag === 'h2'"
|
|
39
49
|
:id="token.anchorId"
|
|
40
50
|
:value="token.content"
|
|
41
51
|
/>
|
|
@@ -126,6 +136,19 @@ import DBlockStepper from './DBlockStepper.vue'
|
|
|
126
136
|
:tabs="token.tabs"
|
|
127
137
|
/>
|
|
128
138
|
|
|
139
|
+
<d-block-code-example
|
|
140
|
+
v-else-if="token.tag === 'code-example'"
|
|
141
|
+
:index="id + token.codeIndex"
|
|
142
|
+
:src="token.src"
|
|
143
|
+
:title="token.title"
|
|
144
|
+
:caption="token.caption"
|
|
145
|
+
:expanded="token.expanded"
|
|
146
|
+
:codepen="token.codepen"
|
|
147
|
+
:scrollable="token.scrollable"
|
|
148
|
+
:overflow="token.overflow"
|
|
149
|
+
:height="token.height"
|
|
150
|
+
/>
|
|
151
|
+
|
|
129
152
|
<d-block-mermaid-diagram
|
|
130
153
|
v-else-if="token.tag === 'mermaid'"
|
|
131
154
|
:content="token.content"
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import { useRoute } from 'vue-router'
|
|
4
|
+
import { useStore } from 'vuex'
|
|
5
|
+
import { homePageSourceMode } from 'virtual:docsector-homepage-override'
|
|
4
6
|
// components
|
|
5
7
|
import DPage from "./DPage.vue";
|
|
6
8
|
import DPageBar from "./DPageBar.vue";
|
|
7
9
|
import DH1 from "./DH1.vue";
|
|
8
10
|
import DPageSection from "./DPageSection.vue";
|
|
11
|
+
import { usesRemoteReadmeHomeContent } from '../home-page-mode'
|
|
9
12
|
|
|
10
13
|
const route = useRoute()
|
|
14
|
+
const store = useStore()
|
|
11
15
|
|
|
12
16
|
const id = computed(() => {
|
|
13
17
|
const path = route.path
|
|
@@ -19,6 +23,13 @@ const id = computed(() => {
|
|
|
19
23
|
|
|
20
24
|
return hash >>> 0
|
|
21
25
|
})
|
|
26
|
+
|
|
27
|
+
const usesRemoteReadmeHome = computed(() => {
|
|
28
|
+
return usesRemoteReadmeHomeContent({
|
|
29
|
+
pageBase: store.state.page.base,
|
|
30
|
+
homePageSourceMode
|
|
31
|
+
})
|
|
32
|
+
})
|
|
22
33
|
</script>
|
|
23
34
|
|
|
24
35
|
<template>
|
|
@@ -26,11 +37,12 @@ const id = computed(() => {
|
|
|
26
37
|
<header>
|
|
27
38
|
<d-page-bar />
|
|
28
39
|
<hr />
|
|
29
|
-
<d-h1 :id="0" />
|
|
40
|
+
<d-h1 v-if="!usesRemoteReadmeHome" :id="0" />
|
|
41
|
+
<span v-else id="0" aria-hidden="true"></span>
|
|
30
42
|
</header>
|
|
31
43
|
|
|
32
44
|
<main>
|
|
33
|
-
<d-page-section :id="id" />
|
|
45
|
+
<d-page-section :id="id" :render-primary-heading="usesRemoteReadmeHome" />
|
|
34
46
|
</main>
|
|
35
47
|
</d-page>
|
|
36
48
|
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Prism from 'prismjs'
|
|
2
|
+
|
|
3
|
+
import 'prismjs/components/prism-markup'
|
|
4
|
+
import 'prismjs/components/prism-markup-templating'
|
|
5
|
+
import 'prismjs/components/prism-javascript'
|
|
6
|
+
import 'prismjs/components/prism-css'
|
|
7
|
+
import 'prismjs/components/prism-php'
|
|
8
|
+
import 'prismjs/components/prism-bash'
|
|
9
|
+
|
|
10
|
+
if (!Prism.languages.vue && Prism.languages.markup?.tag?.addInlined) {
|
|
11
|
+
Prism.languages.markup.tag.addInlined('script', 'javascript')
|
|
12
|
+
Prism.languages.markup.tag.addInlined('style', 'css')
|
|
13
|
+
Prism.languages.vue = Prism.languages.markup
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default Prism
|