@docsector/docsector-reader 3.2.0 → 3.2.2

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.
Files changed (137) hide show
  1. package/README.md +14 -2
  2. package/bin/docsector.js +1 -1
  3. package/jsconfig.json +1 -0
  4. package/package.json +8 -7
  5. package/src/components/DH2.vue +1 -1
  6. package/src/components/DH3.vue +1 -1
  7. package/src/components/DH4.vue +1 -1
  8. package/src/components/DH5.vue +1 -1
  9. package/src/components/DH6.vue +1 -1
  10. package/src/components/DMenu.vue +1 -1
  11. package/src/components/DPage.vue +26 -6
  12. package/src/components/DPageAnchor.vue +3 -9
  13. package/src/components/DPageImage.vue +80 -0
  14. package/src/components/DPageMeta.vue +1 -0
  15. package/src/components/DPageTokens.vue +12 -5
  16. package/src/components/QZoom.js +68 -14
  17. package/src/components/QZoom.sass +38 -3
  18. package/src/components/page-section-tokens.js +179 -16
  19. package/src/composables/useNavigator.js +45 -15
  20. package/src/pages/404Page.vue +2 -2
  21. package/src/pages/Homepage.en-US.md +3 -3
  22. package/src/pages/Homepage.pt-BR.md +3 -3
  23. package/src/pages/guide/i18n-and-markdown.overview.en-US.md +7 -1
  24. package/src/pages/guide/i18n-and-markdown.overview.pt-BR.md +7 -1
  25. package/src/pages/guide/pages-and-routing.overview.en-US.md +11 -9
  26. package/src/pages/guide/pages-and-routing.overview.pt-BR.md +11 -9
  27. package/src/pages/guide.index.js +0 -28
  28. package/src/pages/manual/basic/branding.overview.en-US.md +27 -0
  29. package/src/pages/manual/basic/branding.overview.pt-BR.md +27 -0
  30. package/src/pages/manual/{components → basic}/d-menu.overview.en-US.md +11 -3
  31. package/src/pages/manual/{components → basic}/d-menu.overview.pt-BR.md +11 -3
  32. package/src/pages/manual/{components → basic}/d-page-anchor.overview.en-US.md +5 -3
  33. package/src/pages/manual/{components → basic}/d-page-anchor.overview.pt-BR.md +5 -3
  34. package/src/pages/manual/{components → basic}/d-page-meta.overview.en-US.md +10 -2
  35. package/src/pages/manual/{components → basic}/d-page-meta.overview.pt-BR.md +10 -2
  36. package/src/pages/manual/basic/edit-on-github.overview.en-US.md +26 -0
  37. package/src/pages/manual/basic/edit-on-github.overview.pt-BR.md +26 -0
  38. package/src/pages/manual/basic/previous-and-next.overview.en-US.md +17 -0
  39. package/src/pages/manual/basic/previous-and-next.overview.pt-BR.md +17 -0
  40. package/src/pages/manual/basic/search.overview.en-US.md +24 -0
  41. package/src/pages/manual/basic/search.overview.pt-BR.md +24 -0
  42. package/src/pages/manual/basic/translation-progress.overview.en-US.md +19 -0
  43. package/src/pages/manual/basic/translation-progress.overview.pt-BR.md +19 -0
  44. package/src/pages/manual/basic/version-switcher.overview.en-US.md +28 -0
  45. package/src/pages/manual/basic/version-switcher.overview.pt-BR.md +28 -0
  46. package/src/pages/manual/components/d-subpage.overview.en-US.md +2 -2
  47. package/src/pages/manual/components/d-subpage.overview.pt-BR.md +2 -2
  48. package/src/pages/manual/content/blocks/code-blocks.overview.en-US.md +55 -0
  49. package/src/pages/manual/content/blocks/code-blocks.overview.pt-BR.md +55 -0
  50. package/src/pages/manual/{components/d-page-source-code.showcase.en-US.md → content/blocks/code-blocks.showcase.en-US.md} +14 -12
  51. package/src/pages/manual/{components/d-page-source-code.showcase.pt-BR.md → content/blocks/code-blocks.showcase.pt-BR.md} +28 -26
  52. package/src/pages/manual/{components/d-page-expandable.overview.en-US.md → content/blocks/expandable.overview.en-US.md} +3 -12
  53. package/src/pages/manual/{components/d-page-expandable.overview.pt-BR.md → content/blocks/expandable.overview.pt-BR.md} +3 -12
  54. package/src/pages/manual/content/blocks/headings.overview.en-US.md +45 -0
  55. package/src/pages/manual/content/blocks/headings.overview.pt-BR.md +45 -0
  56. package/src/pages/manual/{components/d-headings.showcase.en-US.md → content/blocks/headings.showcase.en-US.md} +1 -1
  57. package/src/pages/manual/{components/d-headings.showcase.pt-BR.md → content/blocks/headings.showcase.pt-BR.md} +1 -1
  58. package/src/pages/manual/content/blocks/hints.overview.en-US.md +30 -0
  59. package/src/pages/manual/content/blocks/hints.overview.pt-BR.md +30 -0
  60. package/src/pages/manual/content/blocks/hints.showcase.en-US.md +30 -0
  61. package/src/pages/manual/content/blocks/hints.showcase.pt-BR.md +30 -0
  62. package/src/pages/manual/content/blocks/images.overview.en-US.md +34 -0
  63. package/src/pages/manual/content/blocks/images.overview.pt-BR.md +16 -0
  64. package/src/pages/manual/content/blocks/images.showcase.en-US.md +19 -0
  65. package/src/pages/manual/content/blocks/images.showcase.pt-BR.md +11 -0
  66. package/src/pages/manual/content/blocks/math-and-tex.overview.en-US.md +27 -0
  67. package/src/pages/manual/content/blocks/math-and-tex.overview.pt-BR.md +27 -0
  68. package/src/pages/manual/content/blocks/math-and-tex.showcase.en-US.md +14 -0
  69. package/src/pages/manual/content/blocks/math-and-tex.showcase.pt-BR.md +14 -0
  70. package/src/pages/manual/content/blocks/mermaid-diagrams.overview.en-US.md +22 -0
  71. package/src/pages/manual/content/blocks/mermaid-diagrams.overview.pt-BR.md +22 -0
  72. package/src/pages/manual/content/blocks/ordered-lists.overview.en-US.md +19 -0
  73. package/src/pages/manual/content/blocks/ordered-lists.overview.pt-BR.md +19 -0
  74. package/src/pages/manual/content/blocks/ordered-lists.showcase.en-US.md +21 -0
  75. package/src/pages/manual/content/blocks/ordered-lists.showcase.pt-BR.md +21 -0
  76. package/src/pages/manual/content/blocks/paragraphs.overview.en-US.md +19 -0
  77. package/src/pages/manual/content/blocks/paragraphs.overview.pt-BR.md +19 -0
  78. package/src/pages/manual/content/blocks/paragraphs.showcase.en-US.md +9 -0
  79. package/src/pages/manual/content/blocks/paragraphs.showcase.pt-BR.md +9 -0
  80. package/src/pages/manual/content/blocks/quick-links.overview.en-US.md +28 -0
  81. package/src/pages/manual/content/blocks/quick-links.overview.pt-BR.md +28 -0
  82. package/src/pages/manual/content/blocks/quick-links.showcase.en-US.md +34 -0
  83. package/src/pages/manual/content/blocks/quick-links.showcase.pt-BR.md +34 -0
  84. package/src/pages/manual/content/blocks/quotes.overview.en-US.md +24 -0
  85. package/src/pages/manual/content/blocks/quotes.overview.pt-BR.md +24 -0
  86. package/src/pages/manual/content/blocks/quotes.showcase.en-US.md +17 -0
  87. package/src/pages/manual/content/blocks/quotes.showcase.pt-BR.md +17 -0
  88. package/src/pages/manual/content/blocks/raw-html.overview.en-US.md +19 -0
  89. package/src/pages/manual/content/blocks/raw-html.overview.pt-BR.md +19 -0
  90. package/src/pages/manual/content/blocks/raw-html.showcase.en-US.md +12 -0
  91. package/src/pages/manual/content/blocks/raw-html.showcase.pt-BR.md +12 -0
  92. package/src/pages/manual/content/blocks/tables.overview.en-US.md +19 -0
  93. package/src/pages/manual/content/blocks/tables.overview.pt-BR.md +19 -0
  94. package/src/pages/manual/content/blocks/tables.showcase.en-US.md +17 -0
  95. package/src/pages/manual/content/blocks/tables.showcase.pt-BR.md +17 -0
  96. package/src/pages/manual/content/blocks/unordered-lists.overview.en-US.md +21 -0
  97. package/src/pages/manual/content/blocks/unordered-lists.overview.pt-BR.md +21 -0
  98. package/src/pages/manual/content/blocks/unordered-lists.showcase.en-US.md +24 -0
  99. package/src/pages/manual/content/blocks/unordered-lists.showcase.pt-BR.md +24 -0
  100. package/src/pages/manual/content/structures/books.overview.en-US.md +36 -0
  101. package/src/pages/manual/content/structures/books.overview.pt-BR.md +36 -0
  102. package/src/pages/manual/content/structures/page.overview.en-US.md +61 -0
  103. package/src/pages/manual/content/structures/page.overview.pt-BR.md +61 -0
  104. package/src/pages/manual/content/structures/subpage.overview.en-US.md +62 -0
  105. package/src/pages/manual/content/structures/subpage.overview.pt-BR.md +62 -0
  106. package/src/pages/manual.index.js +487 -153
  107. package/src/router/routes.js +1 -1
  108. package/src/pages/guide/alerts-and-blockquotes.overview.en-US.md +0 -65
  109. package/src/pages/guide/alerts-and-blockquotes.overview.pt-BR.md +0 -65
  110. package/src/pages/manual/components/d-headings.overview.en-US.md +0 -54
  111. package/src/pages/manual/components/d-headings.overview.pt-BR.md +0 -54
  112. package/src/pages/manual/components/d-mermaid-diagram.overview.en-US.md +0 -31
  113. package/src/pages/manual/components/d-mermaid-diagram.overview.pt-BR.md +0 -29
  114. package/src/pages/manual/components/d-page-blockquote.overview.en-US.md +0 -66
  115. package/src/pages/manual/components/d-page-blockquote.overview.pt-BR.md +0 -66
  116. package/src/pages/manual/components/d-page-blockquote.showcase.en-US.md +0 -34
  117. package/src/pages/manual/components/d-page-blockquote.showcase.pt-BR.md +0 -34
  118. package/src/pages/manual/components/d-page-section.overview.en-US.md +0 -57
  119. package/src/pages/manual/components/d-page-section.overview.pt-BR.md +0 -57
  120. package/src/pages/manual/components/d-page-section.showcase.en-US.md +0 -43
  121. package/src/pages/manual/components/d-page-section.showcase.pt-BR.md +0 -43
  122. package/src/pages/manual/components/d-page-source-code.overview.en-US.md +0 -68
  123. package/src/pages/manual/components/d-page-source-code.overview.pt-BR.md +0 -68
  124. package/src/pages/manual/components/d-page.overview.en-US.md +0 -59
  125. package/src/pages/manual/components/d-page.overview.pt-BR.md +0 -59
  126. package/src/pages/manual/components/d-page.showcase.en-US.md +0 -35
  127. package/src/pages/manual/components/d-page.showcase.pt-BR.md +0 -35
  128. package/src/pages/manual/components/q-zoom.overview.en-US.md +0 -71
  129. package/src/pages/manual/components/q-zoom.overview.pt-BR.md +0 -71
  130. package/src/pages/manual/composables/use-navigator.overview.en-US.md +0 -89
  131. package/src/pages/manual/composables/use-navigator.overview.pt-BR.md +0 -89
  132. package/src/pages/manual/store/modules.overview.en-US.md +0 -96
  133. package/src/pages/manual/store/modules.overview.pt-BR.md +0 -96
  134. /package/src/pages/manual/{components/d-page-expandable.showcase.en-US.md → content/blocks/expandable.showcase.en-US.md} +0 -0
  135. /package/src/pages/manual/{components/d-page-expandable.showcase.pt-BR.md → content/blocks/expandable.showcase.pt-BR.md} +0 -0
  136. /package/src/pages/manual/{components/d-mermaid-diagram.showcase.en-US.md → content/blocks/mermaid-diagrams.showcase.en-US.md} +0 -0
  137. /package/src/pages/manual/{components/d-mermaid-diagram.showcase.pt-BR.md → content/blocks/mermaid-diagrams.showcase.pt-BR.md} +0 -0
package/README.md CHANGED
@@ -41,6 +41,8 @@ Transform Markdown content into beautiful, navigable documentation sites — wit
41
41
  ## ✨ Features
42
42
 
43
43
  - 📝 **Markdown Rendering** — Write docs in Markdown, rendered with syntax highlighting (Prism.js)
44
+ - 🔽 **Nested Markdown Lists** — Ordered and unordered lists preserve sublist hierarchy across multiple indentation levels
45
+ - 🖼️ **Block Image Captions & Zoom** — Standalone Markdown images render as zoomable figures, and raw `figure` / `picture` markup supports separate alt text and captions
44
46
  - 🧱 **Raw HTML in Markdown** — Renders inline and block HTML tags inside markdown sections (including homepage remote README content)
45
47
  - 🧩 **Mermaid Diagrams** — Native support for fenced ` ```mermaid ` blocks, with automatic dark/light theme switching
46
48
  - ➗ **Math & KaTeX** — Native support for inline `$...$` and display `$$...$$` formulas rendered with KaTeX
@@ -50,7 +52,6 @@ Transform Markdown content into beautiful, navigable documentation sites — wit
50
52
  - 🔗 **Anchor Navigation** — Right-side Table of Contents tree with scroll tracking and auto-scroll to active section
51
53
  - 🖱️ **Active Menu Item UX** — Active menu entries keep pointer cursor, clear URL hash without redundant navigation, and prevent accidental label text selection
52
54
  - 🔎 **Search** — Menu search across all documentation content and tags
53
- - 🌐 **WebMCP Browser Tools** — Registers in-page tools for browser agents with `registerTool` and optional `provideContext` fallback
54
55
  - 📱 **Responsive** — Mobile-friendly with collapsible sidebar and drawers
55
56
  - 📚 **Book Tabs with Per-State Colors** — Define `*.book.js` tabs with icons, order, and `color.active` / `color.inactive`
56
57
  - 🔀 **Internal Shortcut Pages** — Route entries can redirect with `config.link.to`, keeping localized titles while inheriting icon/status from the destination page
@@ -67,6 +68,7 @@ Transform Markdown content into beautiful, navigable documentation sites — wit
67
68
  - 🧭 **Content Signals** — Injects `Content-Signal` policy in `robots.txt` with deterministic, idempotent build output
68
69
  - 🏠 **Markdown Home at Root** — Homepage is rendered from `src/pages/Homepage.{lang}.md` directly at `/`
69
70
  - 🌍 **Remote README as Home** — Optional build-time remote README source for homepage with automatic local fallback
71
+ - 🔗 **GitHub-Compatible Heading Anchors** — Markdown headings use GitHub-style slugs so standard README Table of Contents links work inside Docsector
70
72
  - 🧬 **Scaffolded Homepage Override Wiring** — New consumer projects automatically wire `virtual:docsector-homepage-override` into i18n message building
71
73
  - 📖 **Expandable Markdown Sections** — Use `<d-expandable title="...">...</d-expandable>` to collapse secondary content while keeping rich Markdown support inside the body
72
74
  - 🧭 **Quick Links Custom Element** — Use `<d-quick-links>` and `<d-quick-link>` in Markdown to render rich home navigation cards
@@ -356,6 +358,7 @@ You can configure Docsector Reader to use a remote README as homepage content.
356
358
  - Fetch happens at build-time.
357
359
  - The same README content is used for all configured languages.
358
360
  - If fetch fails, it falls back to local `src/pages/Homepage.{lang}.md` by default.
361
+ - Standard GitHub-style heading links and README Table of Contents fragments keep working in the rendered homepage.
359
362
 
360
363
  ### Configure
361
364
 
@@ -856,7 +859,12 @@ my-docs/
856
859
  │ │ ├── guide.index.js # Guide page registry (routes + metadata)
857
860
  │ │ ├── boot.js # Boot page data
858
861
  │ │ ├── guide/ # Guide pages (.md files)
859
- │ │ └── manual/ # Manual pages (.md files)
862
+ │ │ └── manual/
863
+ │ │ ├── basic/ # Core UI docs exposed in the main manual nav
864
+ │ │ ├── content/
865
+ │ │ │ ├── blocks/ # User-facing Markdown block docs
866
+ │ │ │ └── structures/ # User-facing page structure docs
867
+ │ │ └── components/ # Legacy/internal engine-facing manual docs
860
868
  │ ├── i18n/
861
869
  │ │ ├── index.js # Uses buildMessages() from engine
862
870
  │ │ └── languages/ # HJSON locale files
@@ -870,6 +878,10 @@ my-docs/
870
878
  └── icons/ # PWA icons
871
879
  ```
872
880
 
881
+ A common manual pattern is to keep core UI references under `src/pages/manual/basic/` with user-friendly page titles and focused entry pages such as Search, Branding, Version Switcher, Edit on GitHub, Translation Progress, and Previous & Next, end-user content references under `src/pages/manual/content/blocks/`, structural docs under `src/pages/manual/content/structures/`, and legacy/internal engine-specific references under `src/pages/manual/components/`.
882
+
883
+ Blocks in `src/pages/manual/content/blocks/` should normally provide both `overview` and `showcase` markdown pages, while structural topics can stay overview-only when a visual demo adds little value.
884
+
873
885
  ---
874
886
 
875
887
  ## 📚 Defining Books (Tabs)
package/bin/docsector.js CHANGED
@@ -23,7 +23,7 @@ const packageRoot = resolve(__dirname, '..')
23
23
  const args = process.argv.slice(2)
24
24
  const command = args[0]
25
25
 
26
- const VERSION = '3.2.0'
26
+ const VERSION = '3.2.2'
27
27
 
28
28
  const HELP = `
29
29
  Docsector Reader v${VERSION}
package/jsconfig.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
+ "ignoreDeprecations": "6.0",
3
4
  "baseUrl": ".",
4
5
  "noUnusedLocals": false,
5
6
  "noUnusedParameters": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docsector/docsector-reader",
3
- "version": "3.2.0",
3
+ "version": "3.2.2",
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",
@@ -69,6 +69,7 @@
69
69
  "autoprefixer": "^10.4.2",
70
70
  "axios": "^1.7.7",
71
71
  "core-js": "^3.6.5",
72
+ "github-slugger": "^2.0.0",
72
73
  "hjson": "^3.2.2",
73
74
  "katex": "^0.17.0",
74
75
  "markdown-it": "^13.0.1",
@@ -88,11 +89,6 @@
88
89
  },
89
90
  "devDependencies": {
90
91
  "@quasar/extras": "^1.16.12",
91
- "quasar": "^2.16.6",
92
- "vue": "^3.5.13",
93
- "vue-i18n": "^9.0.0",
94
- "vue-router": "^4.0.0",
95
- "vuex": "^4.0.1",
96
92
  "eslint": "^8.57.0",
97
93
  "eslint-config-prettier": "^8.1.0",
98
94
  "eslint-plugin-import": "^2.19.1",
@@ -100,7 +96,12 @@
100
96
  "eslint-plugin-promise": "^6.0.0",
101
97
  "eslint-plugin-vue": "^9.0.0",
102
98
  "prettier": "^2.5.1",
103
- "vitest": "^2.1.8"
99
+ "quasar": "^2.16.6",
100
+ "vitest": "^2.1.8",
101
+ "vue": "^3.5.13",
102
+ "vue-i18n": "^9.0.0",
103
+ "vue-router": "^4.0.0",
104
+ "vuex": "^4.0.1"
104
105
  },
105
106
  "browserslist": [
106
107
  "last 10 Chrome versions",
@@ -5,7 +5,7 @@ import useNavigator from '../composables/useNavigator'
5
5
 
6
6
  const props = defineProps({
7
7
  id: {
8
- type: Number,
8
+ type: [String, Number],
9
9
  required: true
10
10
  },
11
11
  value: {
@@ -5,7 +5,7 @@ import useNavigator from '../composables/useNavigator'
5
5
 
6
6
  const props = defineProps({
7
7
  id: {
8
- type: Number,
8
+ type: [String, Number],
9
9
  required: true
10
10
  },
11
11
  value: {
@@ -5,7 +5,7 @@ import useNavigator from '../composables/useNavigator'
5
5
 
6
6
  const props = defineProps({
7
7
  id: {
8
- type: Number,
8
+ type: [String, Number],
9
9
  required: true
10
10
  },
11
11
  value: {
@@ -5,7 +5,7 @@ import useNavigator from '../composables/useNavigator'
5
5
 
6
6
  const props = defineProps({
7
7
  id: {
8
- type: Number,
8
+ type: [String, Number],
9
9
  required: true
10
10
  },
11
11
  value: {
@@ -5,7 +5,7 @@ import useNavigator from '../composables/useNavigator'
5
5
 
6
6
  const props = defineProps({
7
7
  id: {
8
- type: Number,
8
+ type: [String, Number],
9
9
  required: true
10
10
  },
11
11
  value: {
@@ -162,7 +162,7 @@ const normalizeRoutePath = (path) => {
162
162
  }
163
163
 
164
164
  const getTopRoutes = () => {
165
- return ($router.options.routes || []).slice(0, -2)
165
+ return ($router.options.routes || []).slice(0, -2).filter(route => route?.meta?.menu?.hidden !== true)
166
166
  }
167
167
 
168
168
  const routeHasSubpage = (route, subpageName) => {
@@ -150,11 +150,7 @@ const subroute = (to) => {
150
150
  }
151
151
 
152
152
  if (relative === to) {
153
- if (to !== '/showcase') {
154
- return router.push({ hash: '#0' })
155
- } else {
156
- return router.push({ hash: '#1' })
157
- }
153
+ return router.push({ hash: '#0' })
158
154
  }
159
155
 
160
156
  router.push(path)
@@ -237,6 +233,30 @@ const handleMainScrollKeys = (event) => {
237
233
  container.scrollTop = nextTop
238
234
  }
239
235
 
236
+ const handleContentAnchorClick = (event) => {
237
+ if (event.defaultPrevented || event.button !== 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
238
+ return
239
+ }
240
+
241
+ const target = event.target
242
+ if (!(target instanceof Element)) {
243
+ return
244
+ }
245
+
246
+ const link = target.closest('a[href]')
247
+ if (!link) {
248
+ return
249
+ }
250
+
251
+ const href = link.getAttribute('href') || ''
252
+ if (!href.startsWith('#') || href === '#') {
253
+ return
254
+ }
255
+
256
+ event.preventDefault()
257
+ navigate(href)
258
+ }
259
+
240
260
  const handlePageScroll = (scrollState) => {
241
261
  scrolling(scrollState)
242
262
  syncReadingProgress(scrollState?.position?.top)
@@ -327,7 +347,7 @@ watch(() => route.fullPath, () => {
327
347
 
328
348
  <q-page id="page">
329
349
  <q-scroll-area class="content" :class="main" ref="pageScrollArea">
330
- <div id="scroll-container">
350
+ <div id="scroll-container" @click="handleContentAnchorClick">
331
351
  <slot />
332
352
  </div>
333
353
  <d-page-meta v-if="!disableNav" />
@@ -21,19 +21,13 @@ const expanded = computed({
21
21
  get() {
22
22
  return store.getters['page/nodesExpanded']
23
23
  },
24
- set(value) {
24
+ set() {
25
25
  // console.log(value)
26
26
  }
27
27
  })
28
28
  const selected = computed({
29
29
  get() {
30
- let anchor = store.state.page.anchor
31
-
32
- if (store.state.page.relative !== '' && anchor === 0) {
33
- anchor = anchor + 1
34
- }
35
-
36
- return anchor
30
+ return store.state.page.anchor
37
31
  },
38
32
  set(value) {
39
33
  navigate(value)
@@ -90,7 +84,7 @@ onMounted(() => {
90
84
  const id = route.hash.replace(/^#+/g, '')
91
85
  if (id) {
92
86
  setTimeout(() => {
93
- anchor(id)
87
+ anchor(route.hash)
94
88
  }, 500)
95
89
  }
96
90
  })
@@ -0,0 +1,80 @@
1
+ <script setup>
2
+ import { computed } from 'vue'
3
+
4
+ defineOptions({
5
+ name: 'DPageImage'
6
+ })
7
+
8
+ const props = defineProps({
9
+ content: {
10
+ type: String,
11
+ default: ''
12
+ },
13
+ captionHtml: {
14
+ type: String,
15
+ default: ''
16
+ }
17
+ })
18
+
19
+ const hasCaption = computed(() => {
20
+ return String(props.captionHtml || '').trim() !== ''
21
+ })
22
+ </script>
23
+
24
+ <template>
25
+ <figure class="d-page-image">
26
+ <q-zoom
27
+ class="d-page-image__zoom"
28
+ background-color="rgba(18, 18, 20, 0.96)"
29
+ show-close-button
30
+ >
31
+ <div class="d-page-image__media" v-html="content"></div>
32
+ </q-zoom>
33
+
34
+ <figcaption v-if="hasCaption" class="d-page-image__caption" v-html="captionHtml"></figcaption>
35
+ </figure>
36
+ </template>
37
+
38
+ <style lang="sass" scoped>
39
+ .d-page-image
40
+ display: flex
41
+ flex-direction: column
42
+ align-items: center
43
+ gap: 0.75rem
44
+ width: 100%
45
+ margin: 1.75rem auto
46
+ text-align: center
47
+
48
+ .d-page-image__zoom
49
+ display: inline-block
50
+ width: fit-content
51
+ max-width: 100%
52
+
53
+ .d-page-image__media
54
+ display: inline-flex
55
+ align-items: center
56
+ justify-content: center
57
+ line-height: 0
58
+ max-width: 100%
59
+
60
+ :deep(img),
61
+ :deep(picture)
62
+ display: block
63
+ max-width: 100%
64
+
65
+ .d-page-image__caption
66
+ max-width: min(100%, 42rem)
67
+ margin: 0
68
+ padding: 0 1rem
69
+ color: inherit
70
+ opacity: 0.72
71
+ font-size: 0.92rem
72
+ line-height: 1.45
73
+ text-align: center
74
+
75
+ :deep(p)
76
+ margin: 0
77
+
78
+ :deep(*)
79
+ color: inherit
80
+ </style>
@@ -156,6 +156,7 @@ const getVersionSiblingPath = (offset) => {
156
156
  const currentPath = normalizeRoutePath(route.matched?.[0]?.path || `/${store.state.page.base}`)
157
157
  const routes = router.options.routes
158
158
  .slice(0, -2)
159
+ .filter(item => item?.meta?.menu?.hidden !== true)
159
160
  .filter(item => !versionId || item?.meta?.version === versionId)
160
161
 
161
162
  const index = routes.findIndex(item => normalizeRoutePath(item.path) === currentPath)
@@ -22,6 +22,7 @@ import DH6 from './DH6.vue'
22
22
  import DPageSourceCode from './DPageSourceCode.vue'
23
23
  import DMermaidDiagram from './DMermaidDiagram.vue'
24
24
  import DPageBlockquote from './DPageBlockquote.vue'
25
+ import DPageImage from './DPageImage.vue'
25
26
  import DQuickLinks from './DQuickLinks.vue'
26
27
  import DPageExpandable from './DPageExpandable.vue'
27
28
  </script>
@@ -30,27 +31,27 @@ import DPageExpandable from './DPageExpandable.vue'
30
31
  <template v-for="(token, index) in tokens" :key="`${token.tag}-${index}`">
31
32
  <d-h2
32
33
  v-if="token.tag === 'h2'"
33
- :id="id + token.map[0]"
34
+ :id="token.anchorId"
34
35
  :value="token.content"
35
36
  />
36
37
  <d-h3
37
38
  v-else-if="token.tag === 'h3'"
38
- :id="id + token.map[0]"
39
+ :id="token.anchorId"
39
40
  :value="token.content"
40
41
  />
41
42
  <d-h4
42
43
  v-else-if="token.tag === 'h4'"
43
- :id="id + token.map[0]"
44
+ :id="token.anchorId"
44
45
  :value="token.content"
45
46
  />
46
47
  <d-h5
47
48
  v-else-if="token.tag === 'h5'"
48
- :id="id + token.map[0]"
49
+ :id="token.anchorId"
49
50
  :value="token.content"
50
51
  />
51
52
  <d-h6
52
53
  v-else-if="token.tag === 'h6'"
53
- :id="id + token.map[0]"
54
+ :id="token.anchorId"
54
55
  :value="token.content"
55
56
  />
56
57
 
@@ -75,6 +76,12 @@ import DPageExpandable from './DPageExpandable.vue'
75
76
  v-html="token.content"
76
77
  ></div>
77
78
 
79
+ <d-page-image
80
+ v-else-if="token.tag === 'image'"
81
+ :content="token.content"
82
+ :caption-html="token.captionHtml"
83
+ />
84
+
78
85
  <p
79
86
  v-else-if="token.tag === 'p'"
80
87
  v-html="token.content"
@@ -6,15 +6,13 @@
6
6
 
7
7
  import {
8
8
  h,
9
+ Teleport,
9
10
  ref, computed,
10
11
  onMounted, onBeforeUnmount
11
12
  } from 'vue'
12
13
 
13
14
  import { useColorize } from 'q-colorize-mixin'
14
15
 
15
- import { dom } from 'quasar'
16
- const { offset } = dom
17
-
18
16
  import './QZoom.sass'
19
17
 
20
18
  // @
@@ -34,7 +32,12 @@ export default {
34
32
  initialScaleText: { type: Number, default: 100, validator: v => v >= 50 && v <= 500 },
35
33
  noCenter: Boolean,
36
34
  noWheelScale: Boolean,
37
- noEscClose: Boolean
35
+ noEscClose: Boolean,
36
+ showCloseButton: Boolean,
37
+ closeButtonLabel: {
38
+ type: String,
39
+ default: 'Close zoom'
40
+ }
38
41
  },
39
42
 
40
43
  setup (props, { emit, slots }) {
@@ -183,13 +186,29 @@ export default {
183
186
  }
184
187
  }
185
188
 
189
+ const onOverlayClick = (e) => {
190
+ if (isZoomed.value) {
191
+ hide()
192
+
193
+ e.preventDefault()
194
+ }
195
+ }
196
+
197
+ const stopEvent = (e) => {
198
+ e.stopPropagation()
199
+ }
200
+
186
201
  const getPosition = () => {
187
- const position = offset(vComponent.value)
202
+ const rect = vComponent.value.getBoundingClientRect()
203
+ const position = {
204
+ left: rect.left,
205
+ top: rect.top
206
+ }
188
207
 
189
208
  position.left = position.left + 'px'
190
209
  position.top = position.top + 'px'
191
- position.width = vComponent.value.clientWidth + 'px'
192
- position.height = vComponent.value.clientHeight + 'px'
210
+ position.width = rect.width + 'px'
211
+ position.height = rect.height + 'px'
193
212
 
194
213
  return position
195
214
  }
@@ -245,7 +264,34 @@ export default {
245
264
  fontSize: props.scaleText && !props.scale && `${scaleTextValue.value}%`
246
265
  }
247
266
  }), [
248
- slot && slot({ zoomed: isZoomed.value })
267
+ h('div', {
268
+ class: 'q-zoom__content-inner',
269
+ onClick: stopEvent
270
+ }, [
271
+ slot && slot({ zoomed: isZoomed.value })
272
+ ])
273
+ ])
274
+ }
275
+
276
+ const __renderCloseButton = () => {
277
+ if (!props.showCloseButton) {
278
+ return null
279
+ }
280
+
281
+ return h('button', {
282
+ type: 'button',
283
+ class: 'q-zoom__close-button',
284
+ 'aria-label': props.closeButtonLabel,
285
+ title: props.closeButtonLabel,
286
+ onClick: (e) => {
287
+ stopEvent(e)
288
+ hide()
289
+ }
290
+ }, [
291
+ h('span', {
292
+ class: 'q-zoom__close-icon',
293
+ 'aria-hidden': 'true'
294
+ }, '×')
249
295
  ])
250
296
  }
251
297
 
@@ -256,13 +302,18 @@ export default {
256
302
 
257
303
  return h('div', Colorize.setBackgroundColor(bgColor.value, {
258
304
  class: 'q-zoom__overlay' +
259
- (props.manual ? '' : ' q-zoom__zoom-out')
305
+ (props.manual ? '' : ' q-zoom__zoom-out'),
306
+ onClick: onOverlayClick
260
307
  }), [
308
+ __renderCloseButton(),
261
309
  __renderOverlayContent()
262
310
  ])
263
311
  }
264
312
 
265
- return () => h('div', {
313
+ return () => {
314
+ const overlay = __renderOverlay()
315
+
316
+ return h('div', {
266
317
  class: 'q-zoom' +
267
318
  (props.manual ? '' : ' q-zoom__zoom-in'),
268
319
 
@@ -270,9 +321,12 @@ export default {
270
321
  onWheel: wheelEvent,
271
322
 
272
323
  ref: vComponent
273
- }, [
274
- slots.default && slots.default({ zoomed: isZoomed.value }),
275
- __renderOverlay()
276
- ])
324
+ }, [
325
+ slots.default && slots.default({ zoomed: isZoomed.value }),
326
+ overlay
327
+ ? h(Teleport, { to: 'body' }, overlay)
328
+ : null
329
+ ])
330
+ }
277
331
  }
278
332
  }
@@ -22,19 +22,54 @@ $box-shadow: 1px 1px 7px 1px rgba(0,0,0,.2) !default
22
22
  padding: 0
23
23
  margin: 0
24
24
  z-index: 6000
25
+ overflow: hidden
25
26
 
26
27
  &__content
27
- position: relative
28
- display: block
28
+ position: absolute
29
+ display: flex
30
+ align-items: center
31
+ justify-content: center
29
32
  transition: all .5s cubic-bezier(.2,0,.2,1)
30
33
  text-align: center
31
- vertical-align: middle
32
34
  width: 100%
33
35
  height: 0
34
36
  max-width: 100%
35
37
  max-height: 100%
36
38
  overflow: hidden
37
39
 
40
+ & > *
41
+ max-width: 100%
42
+ max-height: 100%
43
+
44
+ &__content-inner
45
+ display: inline-flex
46
+ align-items: center
47
+ justify-content: center
48
+ max-width: 100%
49
+ max-height: 100%
50
+
51
+ &__close-button
52
+ position: absolute
53
+ top: 24px
54
+ right: 24px
55
+ width: 56px
56
+ height: 56px
57
+ display: inline-flex
58
+ align-items: center
59
+ justify-content: center
60
+ border: 0
61
+ border-radius: 999px
62
+ background: rgba(255,255,255,.12)
63
+ color: #fff
64
+ cursor: pointer
65
+ z-index: 6001
66
+ box-shadow: $box-shadow
67
+ backdrop-filter: blur(8px)
68
+
69
+ &__close-icon
70
+ font-size: 34px
71
+ line-height: 1
72
+
38
73
  &__no-center
39
74
  text-align: unset
40
75
  vertical-align: unset