@docsector/docsector-reader 3.5.0 → 3.6.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 CHANGED
@@ -75,6 +75,7 @@ Transform Markdown content into beautiful, navigable documentation sites — wit
75
75
  - 📎 **File Attachment Blocks** — Use `<d-file src="/files/...">...</d-file>` in Markdown to render downloadable file cards with automatic local size detection and support for external URLs
76
76
  - 🌐 **Embedded URL Blocks** — Use `<d-embedded-url url="https://...">...</d-embedded-url>` to render curated embeds for YouTube, Vimeo, Spotify, and CodePen with a safe link-card fallback for unsupported URLs
77
77
  - 🧭 **Quick Links Custom Element** — Use `<d-quick-links>` and `<d-quick-link>` in Markdown to render rich home navigation cards
78
+ - 🗂️ **Cards Custom Element** — Use `<d-block-cards>` and `<d-block-card>` in Markdown to render linked content cards with optional cover images
78
79
  - 🗂️ **API Catalog Well-Known** — Auto-generates `/.well-known/api-catalog` as Linkset JSON for machine-readable API discovery
79
80
  - 🗃️ **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
81
  - 🏷️ **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 }`
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.5.0'
26
+ const VERSION = '3.6.0'
27
27
 
28
28
  const HELP = `
29
29
  Docsector Reader v${VERSION}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docsector/docsector-reader",
3
- "version": "3.5.0",
3
+ "version": "3.6.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,60 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720" role="img" aria-labelledby="title desc">
2
+ <title id="title">Getting started cover</title>
3
+ <desc id="desc">Abstract cover with warm gradients and onboarding steps.</desc>
4
+ <defs>
5
+ <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
6
+ <stop offset="0%" stop-color="#12141c"/>
7
+ <stop offset="48%" stop-color="#1b2230"/>
8
+ <stop offset="100%" stop-color="#27384d"/>
9
+ </linearGradient>
10
+ <linearGradient id="panel" x1="0" y1="0" x2="1" y2="1">
11
+ <stop offset="0%" stop-color="#f1d8a1" stop-opacity="0.95"/>
12
+ <stop offset="100%" stop-color="#b78f41" stop-opacity="0.85"/>
13
+ </linearGradient>
14
+ <linearGradient id="accent" x1="0" y1="0" x2="1" y2="0">
15
+ <stop offset="0%" stop-color="#69d8c3"/>
16
+ <stop offset="100%" stop-color="#8ab6ff"/>
17
+ </linearGradient>
18
+ <filter id="blur" x="-20%" y="-20%" width="140%" height="140%">
19
+ <feGaussianBlur stdDeviation="24"/>
20
+ </filter>
21
+ </defs>
22
+
23
+ <rect width="1280" height="720" fill="url(#bg)"/>
24
+ <circle cx="1120" cy="132" r="136" fill="#69d8c3" opacity="0.16" filter="url(#blur)"/>
25
+ <circle cx="180" cy="640" r="170" fill="#8ab6ff" opacity="0.18" filter="url(#blur)"/>
26
+
27
+ <rect x="90" y="96" width="470" height="528" rx="34" fill="#0f141c" opacity="0.92" stroke="#3a4c63"/>
28
+ <rect x="126" y="140" width="398" height="18" rx="9" fill="url(#accent)" opacity="0.9"/>
29
+ <rect x="126" y="188" width="182" height="28" rx="14" fill="#f5efe1" opacity="0.92"/>
30
+ <rect x="126" y="242" width="300" height="16" rx="8" fill="#8da6c7" opacity="0.7"/>
31
+ <rect x="126" y="272" width="260" height="16" rx="8" fill="#8da6c7" opacity="0.55"/>
32
+
33
+ <g transform="translate(126 344)">
34
+ <rect width="318" height="68" rx="18" fill="#17212d" stroke="#32465d"/>
35
+ <circle cx="36" cy="34" r="15" fill="#69d8c3"/>
36
+ <path d="M29 34l5 5 10-12" fill="none" stroke="#0d1722" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
37
+ <rect x="72" y="22" width="110" height="12" rx="6" fill="#f1f5f9"/>
38
+ <rect x="72" y="42" width="160" height="10" rx="5" fill="#8da6c7" opacity="0.75"/>
39
+ </g>
40
+
41
+ <g transform="translate(126 430)">
42
+ <rect width="356" height="68" rx="18" fill="#17212d" stroke="#32465d"/>
43
+ <circle cx="36" cy="34" r="15" fill="#69d8c3" opacity="0.82"/>
44
+ <path d="M29 34l5 5 10-12" fill="none" stroke="#0d1722" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
45
+ <rect x="72" y="22" width="132" height="12" rx="6" fill="#f1f5f9"/>
46
+ <rect x="72" y="42" width="200" height="10" rx="5" fill="#8da6c7" opacity="0.75"/>
47
+ </g>
48
+
49
+ <g transform="translate(640 88)">
50
+ <rect width="548" height="548" rx="44" fill="url(#panel)"/>
51
+ <rect x="78" y="84" width="392" height="244" rx="26" fill="#0f141c" opacity="0.92"/>
52
+ <path d="M128 282c42-72 86-108 132-108 35 0 69 15 103 44 31 27 58 40 80 40 39 0 73-21 104-64l29 20c-42 63-87 94-136 94-33 0-67-13-102-39-32-24-60-36-84-36-34 0-67 28-98 84z" fill="#69d8c3"/>
53
+ <circle cx="272" cy="206" r="46" fill="#8ab6ff" opacity="0.92"/>
54
+ <rect x="78" y="372" width="188" height="22" rx="11" fill="#0f141c" opacity="0.88"/>
55
+ <rect x="78" y="414" width="300" height="16" rx="8" fill="#243447" opacity="0.6"/>
56
+ <rect x="78" y="444" width="262" height="16" rx="8" fill="#243447" opacity="0.44"/>
57
+ <rect x="78" y="484" width="164" height="56" rx="18" fill="#0f141c" opacity="0.88"/>
58
+ <rect x="102" y="506" width="114" height="12" rx="6" fill="#f5efe1" opacity="0.88"/>
59
+ </g>
60
+ </svg>
@@ -0,0 +1,71 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720" role="img" aria-labelledby="title desc">
2
+ <title id="title">Quick links cover</title>
3
+ <desc id="desc">Abstract navigation cover with cards and directional accents.</desc>
4
+ <defs>
5
+ <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
6
+ <stop offset="0%" stop-color="#10261f"/>
7
+ <stop offset="45%" stop-color="#16372d"/>
8
+ <stop offset="100%" stop-color="#1e4d3e"/>
9
+ </linearGradient>
10
+ <linearGradient id="card" x1="0" y1="0" x2="1" y2="1">
11
+ <stop offset="0%" stop-color="#f3f0e7"/>
12
+ <stop offset="100%" stop-color="#d5ddd1"/>
13
+ </linearGradient>
14
+ <linearGradient id="accent" x1="0" y1="0" x2="1" y2="0">
15
+ <stop offset="0%" stop-color="#69d8c3"/>
16
+ <stop offset="100%" stop-color="#d3b874"/>
17
+ </linearGradient>
18
+ <filter id="blur" x="-20%" y="-20%" width="140%" height="140%">
19
+ <feGaussianBlur stdDeviation="26"/>
20
+ </filter>
21
+ </defs>
22
+
23
+ <rect width="1280" height="720" fill="url(#bg)"/>
24
+ <circle cx="154" cy="138" r="126" fill="#69d8c3" opacity="0.18" filter="url(#blur)"/>
25
+ <circle cx="1090" cy="598" r="170" fill="#d3b874" opacity="0.16" filter="url(#blur)"/>
26
+
27
+ <g transform="translate(98 112)">
28
+ <rect width="452" height="480" rx="42" fill="#0f1714" opacity="0.94" stroke="#385247"/>
29
+ <rect x="44" y="48" width="162" height="18" rx="9" fill="url(#accent)"/>
30
+ <rect x="44" y="100" width="278" height="18" rx="9" fill="#f3f0e7" opacity="0.94"/>
31
+ <rect x="44" y="136" width="212" height="14" rx="7" fill="#9cb5ac" opacity="0.58"/>
32
+
33
+ <g transform="translate(44 204)">
34
+ <rect width="364" height="86" rx="24" fill="#17231e" stroke="#33493f"/>
35
+ <rect x="28" y="24" width="116" height="12" rx="6" fill="#f3f0e7"/>
36
+ <rect x="28" y="46" width="176" height="10" rx="5" fill="#8aa196" opacity="0.82"/>
37
+ <circle cx="320" cy="43" r="20" fill="#22362d"/>
38
+ <path d="M311 43h18M321 34l9 9-9 9" fill="none" stroke="#69d8c3" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
39
+ </g>
40
+
41
+ <g transform="translate(44 310)">
42
+ <rect width="330" height="86" rx="24" fill="#17231e" stroke="#33493f"/>
43
+ <rect x="28" y="24" width="96" height="12" rx="6" fill="#f3f0e7"/>
44
+ <rect x="28" y="46" width="156" height="10" rx="5" fill="#8aa196" opacity="0.82"/>
45
+ <circle cx="286" cy="43" r="20" fill="#22362d"/>
46
+ <path d="M277 43h18M287 34l9 9-9 9" fill="none" stroke="#69d8c3" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
47
+ </g>
48
+ </g>
49
+
50
+ <g transform="translate(646 100)">
51
+ <rect width="536" height="520" rx="44" fill="url(#card)" opacity="0.98"/>
52
+ <rect x="58" y="56" width="420" height="248" rx="28" fill="#0f1714" opacity="0.94"/>
53
+ <g transform="translate(110 114)">
54
+ <rect width="116" height="116" rx="28" fill="#69d8c3"/>
55
+ <path d="M40 58h36M58 40l18 18-18 18" fill="none" stroke="#0f1714" stroke-width="10" stroke-linecap="round" stroke-linejoin="round"/>
56
+ </g>
57
+ <g transform="translate(250 114)">
58
+ <rect width="116" height="116" rx="28" fill="#d3b874"/>
59
+ <path d="M40 58h36M58 40l18 18-18 18" fill="none" stroke="#0f1714" stroke-width="10" stroke-linecap="round" stroke-linejoin="round"/>
60
+ </g>
61
+ <g transform="translate(180 272)">
62
+ <rect width="116" height="116" rx="28" fill="#8ab6ff"/>
63
+ <path d="M40 58h36M58 40l18 18-18 18" fill="none" stroke="#0f1714" stroke-width="10" stroke-linecap="round" stroke-linejoin="round"/>
64
+ </g>
65
+ <rect x="58" y="360" width="204" height="18" rx="9" fill="#10261f" opacity="0.92"/>
66
+ <rect x="58" y="396" width="294" height="14" rx="7" fill="#425b52" opacity="0.6"/>
67
+ <rect x="58" y="424" width="248" height="14" rx="7" fill="#425b52" opacity="0.42"/>
68
+ <rect x="58" y="470" width="172" height="58" rx="18" fill="#10261f" opacity="0.92"/>
69
+ <rect x="84" y="493" width="120" height="12" rx="6" fill="#f3f0e7" opacity="0.92"/>
70
+ </g>
71
+ </svg>
@@ -0,0 +1,223 @@
1
+ <script setup>
2
+ const BASE_URL = import.meta.env.BASE_URL || '/'
3
+
4
+ defineOptions({
5
+ name: 'DBlockCard'
6
+ })
7
+
8
+ const props = defineProps({
9
+ items: {
10
+ type: Array,
11
+ default: () => []
12
+ },
13
+ title: {
14
+ type: String,
15
+ default: ''
16
+ }
17
+ })
18
+
19
+ const isExternal = (item) => {
20
+ const href = item?.href || ''
21
+ return /^https?:\/\//i.test(href)
22
+ }
23
+
24
+ const itemTag = (item) => {
25
+ if (item?.to) return 'router-link'
26
+ return 'a'
27
+ }
28
+
29
+ const itemProps = (item) => {
30
+ if (item?.to) {
31
+ return {
32
+ to: item.to
33
+ }
34
+ }
35
+
36
+ const href = item?.href || ''
37
+ return {
38
+ href,
39
+ target: isExternal(item) ? '_blank' : undefined,
40
+ rel: isExternal(item) ? 'noopener noreferrer' : undefined
41
+ }
42
+ }
43
+
44
+ const resolveAssetUrl = (raw = '') => {
45
+ const value = String(raw || '').trim()
46
+
47
+ if (!value) {
48
+ return ''
49
+ }
50
+
51
+ if (/^(?:[a-z]+:)?\/\//i.test(value) || /^(?:data:|blob:)/i.test(value)) {
52
+ return value
53
+ }
54
+
55
+ const trimmedBase = String(BASE_URL).replace(/\/$/, '')
56
+
57
+ if (value.startsWith('/')) {
58
+ return `${trimmedBase}${value}` || value
59
+ }
60
+
61
+ const normalized = value.replace(/^\.\//, '')
62
+ return `${trimmedBase}/${normalized}`.replace(/\/+/g, '/')
63
+ }
64
+ </script>
65
+
66
+ <template>
67
+ <div class="d-cards">
68
+ <h3 v-if="title" class="d-cards__title">{{ title }}</h3>
69
+
70
+ <div class="d-cards__grid">
71
+ <component
72
+ :is="itemTag(item)"
73
+ v-for="(item, index) in props.items"
74
+ :key="`${item.title}-${index}`"
75
+ class="d-cards__link"
76
+ v-bind="itemProps(item)"
77
+ >
78
+ <q-card flat bordered class="d-cards__card">
79
+ <q-img
80
+ v-if="item.image"
81
+ :src="resolveAssetUrl(item.image)"
82
+ :alt="item.title"
83
+ ratio="1.7778"
84
+ class="d-cards__image"
85
+ />
86
+
87
+ <q-card-section v-else-if="item.icon" class="d-cards__icon-section">
88
+ <div class="d-cards__icon-surface">
89
+ <q-icon :name="item.icon" size="56px" color="primary" />
90
+ </div>
91
+ </q-card-section>
92
+
93
+ <q-card-section class="d-cards__body">
94
+ <div class="d-cards__heading-row">
95
+ <div class="d-cards__heading-group">
96
+ <q-icon
97
+ v-if="item.image && item.icon"
98
+ :name="item.icon"
99
+ size="18px"
100
+ color="primary"
101
+ />
102
+ <div class="d-cards__label">{{ item.title }}</div>
103
+ </div>
104
+
105
+ <q-icon :name="isExternal(item) ? 'arrow_outward' : 'arrow_forward'" size="18px" />
106
+ </div>
107
+
108
+ <div class="d-cards__description">{{ item.description }}</div>
109
+ </q-card-section>
110
+ </q-card>
111
+ </component>
112
+ </div>
113
+ </div>
114
+ </template>
115
+
116
+ <style lang="sass">
117
+ body.body--light
118
+ --d-cards-card-bg: #fffdf8
119
+ --d-cards-card-border: rgba(123, 94, 45, 0.16)
120
+ --d-cards-card-shadow: rgba(94, 73, 37, 0.08)
121
+ --d-cards-card-shadow-hover: rgba(94, 73, 37, 0.16)
122
+ --d-cards-description: #4d5563
123
+ --d-cards-icon-surface: linear-gradient(180deg, rgba(210, 190, 145, 0.22), rgba(210, 190, 145, 0.08))
124
+
125
+ body.body--dark
126
+ --d-cards-card-bg: rgba(255, 248, 235, 0.035)
127
+ --d-cards-card-border: rgba(255, 235, 194, 0.12)
128
+ --d-cards-card-shadow: rgba(0, 0, 0, 0.25)
129
+ --d-cards-card-shadow-hover: rgba(0, 0, 0, 0.38)
130
+ --d-cards-description: rgba(255, 255, 255, 0.82)
131
+ --d-cards-icon-surface: linear-gradient(180deg, rgba(193, 166, 103, 0.18), rgba(193, 166, 103, 0.05))
132
+
133
+ .d-cards
134
+ margin: 0 auto
135
+
136
+ .d-cards__title
137
+ text-align: center
138
+ margin: 0 0 16px
139
+
140
+ .d-cards__grid
141
+ display: grid
142
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr))
143
+ gap: 16px
144
+
145
+ .d-cards__link
146
+ display: block
147
+ color: inherit
148
+ text-decoration: none
149
+ border-bottom: 0 !important
150
+ background: transparent !important
151
+
152
+ .d-cards__link:hover,
153
+ .d-cards__link:focus-visible,
154
+ .d-cards__link:active,
155
+ .d-cards__link:visited
156
+ color: inherit !important
157
+ text-decoration: none
158
+ border-bottom: 0 !important
159
+ background: transparent !important
160
+
161
+ .d-cards__card
162
+ height: 100%
163
+ overflow: hidden
164
+ border-radius: 18px
165
+ background: var(--d-cards-card-bg)
166
+ border-color: var(--d-cards-card-border)
167
+ box-shadow: 0 12px 28px var(--d-cards-card-shadow)
168
+ transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease
169
+
170
+ .d-cards__link:hover .d-cards__card,
171
+ .d-cards__link:focus-visible .d-cards__card
172
+ transform: translateY(-2px)
173
+ box-shadow: 0 18px 36px var(--d-cards-card-shadow-hover)
174
+
175
+ .d-cards__link:focus-visible
176
+ outline: none
177
+
178
+ .d-cards__image
179
+ background: rgba(0, 0, 0, 0.05)
180
+
181
+ .d-cards__icon-section
182
+ display: flex
183
+ padding-bottom: 0
184
+
185
+ .d-cards__icon-surface
186
+ display: flex
187
+ align-items: center
188
+ justify-content: center
189
+ width: 100%
190
+ min-height: 156px
191
+ border-radius: 14px
192
+ background: var(--d-cards-icon-surface)
193
+
194
+ .d-cards__body
195
+ display: grid
196
+ gap: 10px
197
+
198
+ .d-cards__heading-row
199
+ display: flex
200
+ align-items: flex-start
201
+ justify-content: space-between
202
+ gap: 12px
203
+
204
+ .d-cards__heading-group
205
+ display: flex
206
+ align-items: center
207
+ gap: 8px
208
+ min-width: 0
209
+
210
+ .d-cards__label
211
+ font-size: 1rem
212
+ font-weight: 700
213
+ line-height: 1.35
214
+
215
+ .d-cards__description
216
+ color: var(--d-cards-description)
217
+ font-size: 0.97rem
218
+ line-height: 1.55
219
+
220
+ @media (max-width: 599px)
221
+ .d-cards__grid
222
+ grid-template-columns: 1fr
223
+ </style>
@@ -25,6 +25,7 @@ import DPageBlockquote from './DPageBlockquote.vue'
25
25
  import DPageImage from './DPageImage.vue'
26
26
  import DPageFile from './DPageFile.vue'
27
27
  import DPageEmbeddedUrl from './DPageEmbeddedUrl.vue'
28
+ import DBlockCard from './DBlockCard.vue'
28
29
  import DQuickLinks from './DQuickLinks.vue'
29
30
  import DPageExpandable from './DPageExpandable.vue'
30
31
  </script>
@@ -128,6 +129,12 @@ import DPageExpandable from './DPageExpandable.vue'
128
129
  :content="token.content"
129
130
  />
130
131
 
132
+ <d-block-card
133
+ v-else-if="token.tag === 'cards'"
134
+ :title="token.title"
135
+ :items="token.items"
136
+ />
137
+
131
138
  <d-quick-links
132
139
  v-else-if="token.tag === 'quick-links'"
133
140
  :title="token.title"
@@ -13,6 +13,7 @@ const ALERT_MESSAGE_TYPES = new Set([
13
13
  'caution'
14
14
  ])
15
15
 
16
+ const CARDS_MARKER_PREFIX = '@@DOCSECTOR_CARDS_'
16
17
  const QUICK_LINKS_MARKER_PREFIX = '@@DOCSECTOR_QUICK_LINKS_'
17
18
  const EXPANDABLE_MARKER_PREFIX = '@@DOCSECTOR_EXPANDABLE_'
18
19
  const FILE_MARKER_PREFIX = '@@DOCSECTOR_FILE_'
@@ -190,6 +191,55 @@ const extractQuickLinksBlocks = (source = '') => {
190
191
  }
191
192
  }
192
193
 
194
+ const extractCardsBlocks = (source = '') => {
195
+ const map = new Map()
196
+ let index = 0
197
+
198
+ const blockPattern = /<d-(?:block-)?cards\b([^>]*)>([\s\S]*?)<\/d-(?:block-)?cards>/gi
199
+ const replaced = String(source).replace(blockPattern, (_, blockAttrsRaw, inner) => {
200
+ const blockAttrs = parseCustomTagAttributes(blockAttrsRaw)
201
+ const items = []
202
+ const itemPattern = /<d-(?:block-)?card\b([^>]*)\/?\s*>/gi
203
+
204
+ let itemMatch = itemPattern.exec(inner)
205
+ while (itemMatch !== null) {
206
+ const itemAttrs = parseCustomTagAttributes(itemMatch[1])
207
+ const title = itemAttrs.title || ''
208
+ const description = itemAttrs.description || ''
209
+ const to = itemAttrs.to || ''
210
+ const href = itemAttrs.href || ''
211
+
212
+ if (title && description && (to || href)) {
213
+ items.push({
214
+ title,
215
+ description,
216
+ to,
217
+ href,
218
+ image: itemAttrs.image || '',
219
+ icon: itemAttrs.icon || ''
220
+ })
221
+ }
222
+
223
+ itemMatch = itemPattern.exec(inner)
224
+ }
225
+
226
+ const marker = `${CARDS_MARKER_PREFIX}${index}@@`
227
+ index++
228
+
229
+ map.set(marker, {
230
+ title: blockAttrs.title || '',
231
+ items
232
+ })
233
+
234
+ return `\n${marker}\n`
235
+ })
236
+
237
+ return {
238
+ source: replaced,
239
+ cardsMap: map
240
+ }
241
+ }
242
+
193
243
  const parseExpandableOpenState = (raw = '') => {
194
244
  return ['1', 'true', 'yes', 'on'].includes(String(raw).trim().toLowerCase())
195
245
  }
@@ -601,7 +651,8 @@ export const tokenizePageSectionSource = (source = '', options = {}) => {
601
651
  })
602
652
  })
603
653
 
604
- const { source: sourceWithQuickLinks, quickLinksMap } = extractQuickLinksBlocks(sourceWithExpandables)
654
+ const { source: sourceWithCards, cardsMap } = extractCardsBlocks(sourceWithExpandables)
655
+ const { source: sourceWithQuickLinks, quickLinksMap } = extractQuickLinksBlocks(sourceWithCards)
605
656
  const { source: sourceWithFiles, fileMap } = extractFileBlocks(sourceWithQuickLinks)
606
657
  const { source: sourceWithEmbeddedUrls, embeddedUrlMap } = extractEmbeddedUrlBlocks(sourceWithFiles)
607
658
 
@@ -779,6 +830,17 @@ export const tokenizePageSectionSource = (source = '', options = {}) => {
779
830
  break
780
831
  }
781
832
 
833
+ if (cardsMap.has(element.content.trim())) {
834
+ const data = cardsMap.get(element.content.trim())
835
+
836
+ tokens.push({
837
+ tag: 'cards',
838
+ title: data.title,
839
+ items: data.items
840
+ })
841
+ break
842
+ }
843
+
782
844
  if (quickLinksMap.has(element.content.trim())) {
783
845
  const data = quickLinksMap.get(element.content.trim())
784
846
 
@@ -0,0 +1,32 @@
1
+ ## Overview
2
+
3
+ Cards render a responsive grid of linked content blocks directly inside Markdown.
4
+
5
+ They are useful for landing sections, curated resource lists, and any place where a plain list of links feels too flat.
6
+
7
+ ## Markdown Syntax
8
+
9
+ ```html
10
+ <d-block-cards title="Explore more">
11
+ <d-block-card
12
+ title="Install"
13
+ description="Set up the project"
14
+ to="/guide/getting-started"
15
+ image="/images/cards/getting-started-cover.svg"
16
+ />
17
+ <d-block-card
18
+ title="GitHub"
19
+ description="Open the repository"
20
+ href="https://github.com/docsector/docsector-reader"
21
+ icon="launch"
22
+ />
23
+ </d-block-cards>
24
+ ```
25
+
26
+ ## Notes
27
+
28
+ - Use `to` for internal navigation and `href` for external URLs.
29
+ - Add `image` when the card should feel more like a landing-page tile.
30
+ - Add `icon` when the card has no image but still needs a stronger visual cue.
31
+ - Short descriptions scan better than paragraph-sized copy.
32
+ - Cover images look best in a wide format such as 16:9.
@@ -0,0 +1,32 @@
1
+ ## Visão geral
2
+
3
+ Cards renderizam uma grade responsiva de blocos com link diretamente dentro do Markdown.
4
+
5
+ Eles são úteis para seções de entrada, listas curadas de recursos e qualquer lugar em que uma lista simples de links fique visualmente pobre.
6
+
7
+ ## Sintaxe Markdown
8
+
9
+ ```html
10
+ <d-block-cards title="Explore mais">
11
+ <d-block-card
12
+ title="Instalação"
13
+ description="Configure o projeto"
14
+ to="/guide/getting-started"
15
+ image="/images/cards/getting-started-cover.svg"
16
+ />
17
+ <d-block-card
18
+ title="GitHub"
19
+ description="Abra o repositório"
20
+ href="https://github.com/docsector/docsector-reader"
21
+ icon="launch"
22
+ />
23
+ </d-block-cards>
24
+ ```
25
+
26
+ ## Notas
27
+
28
+ - Use `to` para navegação interna e `href` para URLs externas.
29
+ - Adicione `image` quando o card precisar se comportar mais como um bloco de landing page.
30
+ - Adicione `icon` quando o card não tiver imagem, mas ainda precisar de uma pista visual mais forte.
31
+ - Descrições curtas funcionam melhor do que textos longos.
32
+ - Imagens de capa ficam melhores em formatos largos, como 16:9.
@@ -0,0 +1,39 @@
1
+ ## Showcase
2
+
3
+ <d-block-cards title="Start here">
4
+ <d-block-card
5
+ title="Getting Started"
6
+ description="Install and run the project"
7
+ to="/guide/getting-started"
8
+ image="/images/cards/getting-started-cover.svg"
9
+ />
10
+ <d-block-card
11
+ title="Quick Links"
12
+ description="Open another navigation-focused block"
13
+ to="/manual/content/blocks/quick-links"
14
+ image="/images/cards/quick-links-cover.svg"
15
+ />
16
+ <d-block-card
17
+ title="GitHub"
18
+ description="Open the repository"
19
+ href="https://github.com/docsector/docsector-reader"
20
+ icon="launch"
21
+ />
22
+ </d-block-cards>
23
+
24
+ ## Without Cover Images
25
+
26
+ <d-block-cards title="Continue reading">
27
+ <d-block-card
28
+ title="Expandable"
29
+ description="Read the collapsible content block overview"
30
+ to="/manual/content/blocks/expandable"
31
+ icon="unfold_more"
32
+ />
33
+ <d-block-card
34
+ title="Page structure"
35
+ description="Review the main page container structure"
36
+ to="/manual/content/structures/page"
37
+ icon="view_quilt"
38
+ />
39
+ </d-block-cards>
@@ -0,0 +1,39 @@
1
+ ## Showcase
2
+
3
+ <d-block-cards title="Comece por aqui">
4
+ <d-block-card
5
+ title="Primeiros passos"
6
+ description="Instale e execute o projeto"
7
+ to="/guide/getting-started"
8
+ image="/images/cards/getting-started-cover.svg"
9
+ />
10
+ <d-block-card
11
+ title="Quick Links"
12
+ description="Abra outro block focado em navegação"
13
+ to="/manual/content/blocks/quick-links"
14
+ image="/images/cards/quick-links-cover.svg"
15
+ />
16
+ <d-block-card
17
+ title="GitHub"
18
+ description="Abra o repositório"
19
+ href="https://github.com/docsector/docsector-reader"
20
+ icon="launch"
21
+ />
22
+ </d-block-cards>
23
+
24
+ ## Sem imagens de capa
25
+
26
+ <d-block-cards title="Continue lendo">
27
+ <d-block-card
28
+ title="Expandable"
29
+ description="Leia a visão geral do block colapsável"
30
+ to="/manual/content/blocks/expandable"
31
+ icon="unfold_more"
32
+ />
33
+ <d-block-card
34
+ title="Estrutura de página"
35
+ description="Revise a estrutura principal do container de página"
36
+ to="/manual/content/structures/page"
37
+ icon="view_quilt"
38
+ />
39
+ </d-block-cards>
@@ -767,6 +767,34 @@ export default {
767
767
  }
768
768
  },
769
769
 
770
+ '/content/blocks/cards': {
771
+ config: {
772
+ icon: 'view_module',
773
+ status: 'done',
774
+ meta: {
775
+ description: {
776
+ 'en-US': 'Cards — Documentation of Docsector Reader',
777
+ 'pt-BR': 'Cartões — Documentacao do Docsector Reader'
778
+ }
779
+ },
780
+ book: 'manual',
781
+ menu: {},
782
+ subpages: {
783
+ showcase: true
784
+ }
785
+ },
786
+ data: {
787
+ 'en-US': { title: 'Cards' },
788
+ 'pt-BR': { title: 'Cartões' }
789
+ },
790
+ metadata: {
791
+ tags: {
792
+ 'en-US': 'cards grid cover image navigation content links layout',
793
+ 'pt-BR': 'cartões grade imagem capa navegação conteúdo links layout'
794
+ }
795
+ }
796
+ },
797
+
770
798
  '/content/structures': {
771
799
  config: null,
772
800
  data: {