@docsector/docsector-reader 3.4.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.
@@ -0,0 +1,365 @@
1
+ const DEFAULT_EMBED = {
2
+ mode: 'link',
3
+ provider: 'link',
4
+ kind: 'link',
5
+ icon: 'link',
6
+ title: '',
7
+ providerLabel: '',
8
+ canonicalUrl: '',
9
+ displayUrl: '',
10
+ embedSrc: '',
11
+ aspectRatio: '',
12
+ frameHeight: 0,
13
+ allow: '',
14
+ allowFullscreen: false
15
+ }
16
+
17
+ const YOUTUBE_HOSTS = new Set([
18
+ 'youtu.be',
19
+ 'youtube.com',
20
+ 'www.youtube.com',
21
+ 'm.youtube.com',
22
+ 'music.youtube.com',
23
+ 'youtube-nocookie.com',
24
+ 'www.youtube-nocookie.com'
25
+ ])
26
+
27
+ const VIMEO_HOSTS = new Set([
28
+ 'vimeo.com',
29
+ 'www.vimeo.com',
30
+ 'player.vimeo.com'
31
+ ])
32
+
33
+ const SPOTIFY_HOSTS = new Set([
34
+ 'spotify.com',
35
+ 'www.spotify.com',
36
+ 'open.spotify.com'
37
+ ])
38
+
39
+ const CODEPEN_HOSTS = new Set([
40
+ 'codepen.io',
41
+ 'www.codepen.io'
42
+ ])
43
+
44
+ const SPOTIFY_PROVIDER_BY_KIND = {
45
+ track: {
46
+ kind: 'audio',
47
+ icon: 'music_note',
48
+ title: 'Spotify track',
49
+ frameHeight: 152
50
+ },
51
+ episode: {
52
+ kind: 'audio',
53
+ icon: 'podcasts',
54
+ title: 'Spotify episode',
55
+ frameHeight: 232
56
+ },
57
+ artist: {
58
+ kind: 'music',
59
+ icon: 'person',
60
+ title: 'Spotify artist',
61
+ frameHeight: 352
62
+ },
63
+ album: {
64
+ kind: 'music',
65
+ icon: 'album',
66
+ title: 'Spotify album',
67
+ frameHeight: 352
68
+ },
69
+ playlist: {
70
+ kind: 'music',
71
+ icon: 'queue_music',
72
+ title: 'Spotify playlist',
73
+ frameHeight: 352
74
+ },
75
+ show: {
76
+ kind: 'podcast',
77
+ icon: 'radio',
78
+ title: 'Spotify show',
79
+ frameHeight: 352
80
+ }
81
+ }
82
+
83
+ const createFallbackResult = (rawUrl = '', title = '') => {
84
+ const trimmed = String(rawUrl || '').trim()
85
+ const normalized = parseHttpUrl(trimmed)
86
+
87
+ return {
88
+ ...DEFAULT_EMBED,
89
+ title: title || normalized?.hostname || trimmed,
90
+ providerLabel: normalized?.hostname || '',
91
+ canonicalUrl: normalized?.toString() || trimmed,
92
+ displayUrl: normalized?.toString() || trimmed
93
+ }
94
+ }
95
+
96
+ const parseHttpUrl = (rawUrl = '') => {
97
+ const trimmed = String(rawUrl || '').trim()
98
+
99
+ if (!trimmed) {
100
+ return null
101
+ }
102
+
103
+ try {
104
+ const url = new URL(trimmed)
105
+
106
+ if (!['http:', 'https:'].includes(url.protocol)) {
107
+ return null
108
+ }
109
+
110
+ return url
111
+ } catch {
112
+ return null
113
+ }
114
+ }
115
+
116
+ const mergeSearchParams = (url, options = {}) => {
117
+ const params = new URLSearchParams(url.search)
118
+
119
+ ;(options.remove || []).forEach((key) => {
120
+ params.delete(key)
121
+ })
122
+
123
+ Object.entries(options.set || {}).forEach(([key, value]) => {
124
+ if (value === '' || value === null || value === undefined) {
125
+ params.delete(key)
126
+ return
127
+ }
128
+
129
+ params.set(key, String(value))
130
+ })
131
+
132
+ const query = params.toString()
133
+ return query ? `?${query}` : ''
134
+ }
135
+
136
+ const parseTimeToSeconds = (value = '') => {
137
+ const trimmed = String(value || '').trim()
138
+
139
+ if (!trimmed) {
140
+ return ''
141
+ }
142
+
143
+ if (/^\d+$/.test(trimmed)) {
144
+ return trimmed
145
+ }
146
+
147
+ const match = trimmed.match(/^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/i)
148
+ if (!match) {
149
+ return ''
150
+ }
151
+
152
+ const hours = Number(match[1] || 0)
153
+ const minutes = Number(match[2] || 0)
154
+ const seconds = Number(match[3] || 0)
155
+ const total = (hours * 3600) + (minutes * 60) + seconds
156
+
157
+ return total > 0 ? String(total) : ''
158
+ }
159
+
160
+ const resolveYouTubeVideoId = (url) => {
161
+ const segments = url.pathname.split('/').filter(Boolean)
162
+
163
+ if (url.hostname === 'youtu.be') {
164
+ return segments[0] || ''
165
+ }
166
+
167
+ if (segments[0] === 'watch') {
168
+ return url.searchParams.get('v') || ''
169
+ }
170
+
171
+ if (['embed', 'shorts', 'live', 'v'].includes(segments[0])) {
172
+ return segments[1] || ''
173
+ }
174
+
175
+ return url.searchParams.get('v') || ''
176
+ }
177
+
178
+ const resolveYouTubeEmbed = (url, title = '') => {
179
+ const videoId = resolveYouTubeVideoId(url)
180
+
181
+ if (!videoId) {
182
+ return null
183
+ }
184
+
185
+ const start = parseTimeToSeconds(url.searchParams.get('t'))
186
+ const query = mergeSearchParams(url, {
187
+ remove: ['v', 't'],
188
+ set: {
189
+ ...(start ? { start } : {}),
190
+ ...((url.searchParams.get('loop') === '1' || url.searchParams.get('loop') === 'true') && !url.searchParams.get('playlist')
191
+ ? { playlist: videoId }
192
+ : {})
193
+ }
194
+ })
195
+
196
+ return {
197
+ ...DEFAULT_EMBED,
198
+ mode: 'embed',
199
+ provider: 'youtube',
200
+ kind: 'video',
201
+ icon: 'smart_display',
202
+ title: title || 'YouTube video',
203
+ providerLabel: 'YouTube',
204
+ canonicalUrl: url.toString(),
205
+ displayUrl: url.toString(),
206
+ embedSrc: `https://www.youtube.com/embed/${videoId}${query}`,
207
+ aspectRatio: '16 / 9',
208
+ allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
209
+ allowFullscreen: true
210
+ }
211
+ }
212
+
213
+ const resolveVimeoVideoId = (url) => {
214
+ const segments = url.pathname.split('/').filter(Boolean)
215
+
216
+ if (segments[0] === 'video') {
217
+ return segments[1] || ''
218
+ }
219
+
220
+ return segments.find((segment) => /^\d+$/.test(segment)) || ''
221
+ }
222
+
223
+ const resolveVimeoEmbed = (url, title = '') => {
224
+ const videoId = resolveVimeoVideoId(url)
225
+
226
+ if (!videoId) {
227
+ return null
228
+ }
229
+
230
+ return {
231
+ ...DEFAULT_EMBED,
232
+ mode: 'embed',
233
+ provider: 'vimeo',
234
+ kind: 'video',
235
+ icon: 'movie',
236
+ title: title || 'Vimeo video',
237
+ providerLabel: 'Vimeo',
238
+ canonicalUrl: url.toString(),
239
+ displayUrl: url.toString(),
240
+ embedSrc: `https://player.vimeo.com/video/${videoId}${mergeSearchParams(url)}`,
241
+ aspectRatio: '16 / 9',
242
+ allow: 'autoplay; fullscreen; picture-in-picture',
243
+ allowFullscreen: true
244
+ }
245
+ }
246
+
247
+ const resolveSpotifyParts = (url) => {
248
+ const segments = url.pathname.split('/').filter(Boolean)
249
+ const embedIndex = segments[0] === 'embed' ? 1 : 0
250
+ const type = segments[embedIndex] || ''
251
+ const id = segments[embedIndex + 1] || ''
252
+
253
+ if (!SPOTIFY_PROVIDER_BY_KIND[type] || !id) {
254
+ return null
255
+ }
256
+
257
+ return { type, id }
258
+ }
259
+
260
+ const resolveSpotifyEmbed = (url, title = '') => {
261
+ const parts = resolveSpotifyParts(url)
262
+
263
+ if (parts === null) {
264
+ return null
265
+ }
266
+
267
+ const definition = SPOTIFY_PROVIDER_BY_KIND[parts.type]
268
+
269
+ return {
270
+ ...DEFAULT_EMBED,
271
+ mode: 'embed',
272
+ provider: 'spotify',
273
+ kind: definition.kind,
274
+ icon: definition.icon,
275
+ title: title || definition.title,
276
+ providerLabel: 'Spotify',
277
+ canonicalUrl: url.toString(),
278
+ displayUrl: url.toString(),
279
+ embedSrc: `https://open.spotify.com/embed/${parts.type}/${parts.id}${mergeSearchParams(url)}`,
280
+ aspectRatio: '',
281
+ frameHeight: definition.frameHeight,
282
+ allow: 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
283
+ allowFullscreen: false
284
+ }
285
+ }
286
+
287
+ const resolveCodePenParts = (url) => {
288
+ const segments = url.pathname.split('/').filter(Boolean)
289
+
290
+ if (segments[0] === 'team') {
291
+ const team = segments[1] || ''
292
+ const penType = segments[2] || ''
293
+ const penId = segments[3] || ''
294
+
295
+ if (!team || !penId || !['pen', 'full', 'details', 'embed', 'debug'].includes(penType)) {
296
+ return null
297
+ }
298
+
299
+ return {
300
+ user: `team/${team}`,
301
+ penId
302
+ }
303
+ }
304
+
305
+ const user = segments[0] || ''
306
+ const penType = segments[1] || ''
307
+ const penId = segments[2] || ''
308
+
309
+ if (!user || !penId || !['pen', 'full', 'details', 'embed', 'debug'].includes(penType)) {
310
+ return null
311
+ }
312
+
313
+ return { user, penId }
314
+ }
315
+
316
+ const resolveCodePenEmbed = (url, title = '') => {
317
+ const parts = resolveCodePenParts(url)
318
+
319
+ if (parts === null) {
320
+ return null
321
+ }
322
+
323
+ return {
324
+ ...DEFAULT_EMBED,
325
+ mode: 'embed',
326
+ provider: 'codepen',
327
+ kind: 'code',
328
+ icon: 'code',
329
+ title: title || 'CodePen embed',
330
+ providerLabel: 'CodePen',
331
+ canonicalUrl: url.toString(),
332
+ displayUrl: url.toString(),
333
+ embedSrc: `https://codepen.io/${parts.user}/embed/${parts.penId}${mergeSearchParams(url)}`,
334
+ aspectRatio: '16 / 9',
335
+ allow: 'accelerometer; camera; clipboard-write; display-capture; encrypted-media; geolocation; gyroscope; microphone; midi; web-share',
336
+ allowFullscreen: true
337
+ }
338
+ }
339
+
340
+ export const resolveEmbeddedUrl = (rawUrl = '', options = {}) => {
341
+ const title = String(options.title || '').trim()
342
+ const normalized = parseHttpUrl(rawUrl)
343
+
344
+ if (normalized === null) {
345
+ return createFallbackResult(rawUrl, title)
346
+ }
347
+
348
+ if (YOUTUBE_HOSTS.has(normalized.hostname)) {
349
+ return resolveYouTubeEmbed(normalized, title) || createFallbackResult(rawUrl, title)
350
+ }
351
+
352
+ if (VIMEO_HOSTS.has(normalized.hostname)) {
353
+ return resolveVimeoEmbed(normalized, title) || createFallbackResult(rawUrl, title)
354
+ }
355
+
356
+ if (SPOTIFY_HOSTS.has(normalized.hostname)) {
357
+ return resolveSpotifyEmbed(normalized, title) || createFallbackResult(rawUrl, title)
358
+ }
359
+
360
+ if (CODEPEN_HOSTS.has(normalized.hostname)) {
361
+ return resolveCodePenEmbed(normalized, title) || createFallbackResult(rawUrl, title)
362
+ }
363
+
364
+ return createFallbackResult(rawUrl, title)
365
+ }
@@ -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>
@@ -0,0 +1,33 @@
1
+ ## Overview
2
+
3
+ Embedded URLs turn supported public links into responsive embeds directly inside Markdown pages.
4
+
5
+ This block is a higher-level alternative to raw iframe markup when the source is a supported provider and the page should keep a consistent card + preview treatment.
6
+
7
+ ## Markdown Syntax
8
+
9
+ ```html
10
+ <d-embedded-url url="https://www.youtube.com/watch?v=M7lc1UVf-VE" title="YouTube player demo">
11
+ Optional caption rendered as inline Markdown.
12
+ </d-embedded-url>
13
+ ```
14
+
15
+ You can also omit the caption body when the provider preview already gives enough context:
16
+
17
+ ```html
18
+ <d-embedded-url url="https://open.spotify.com/track/7ouMYWpwJ422jRcDASZB7P" />
19
+ ```
20
+
21
+ ## Supported Providers
22
+
23
+ - YouTube
24
+ - Vimeo
25
+ - Spotify
26
+ - CodePen
27
+
28
+ ## Notes
29
+
30
+ - `url` is required. `title` is optional.
31
+ - The block preserves the original query string, so provider options such as `autoplay=1&loop=1` continue to work when the provider supports them.
32
+ - Unsupported or private URLs fall back to a safe external-link card instead of attempting a generic iframe.
33
+ - Use Raw HTML when you need a provider outside the curated list or when you need full manual iframe control.
@@ -0,0 +1,33 @@
1
+ ## Apresentação
2
+
3
+ URLs embutidas transformam links públicos suportados em embeds responsivos diretamente dentro das páginas Markdown.
4
+
5
+ Este block é uma alternativa de nível mais alto ao uso manual de iframe quando a origem pertence a um provider suportado e a página deve manter um tratamento consistente de preview + card.
6
+
7
+ ## Sintaxe Markdown
8
+
9
+ ```html
10
+ <d-embedded-url url="https://www.youtube.com/watch?v=M7lc1UVf-VE" title="Demo do player do YouTube">
11
+ Legenda opcional renderizada como Markdown inline.
12
+ </d-embedded-url>
13
+ ```
14
+
15
+ Você também pode omitir o corpo quando o preview do provider já entrega contexto suficiente:
16
+
17
+ ```html
18
+ <d-embedded-url url="https://open.spotify.com/track/7ouMYWpwJ422jRcDASZB7P" />
19
+ ```
20
+
21
+ ## Providers suportados
22
+
23
+ - YouTube
24
+ - Vimeo
25
+ - Spotify
26
+ - CodePen
27
+
28
+ ## Observações
29
+
30
+ - `url` é obrigatório. `title` é opcional.
31
+ - O block preserva a query string original, então opções do provider como `autoplay=1&loop=1` continuam funcionando quando houver suporte.
32
+ - URLs não suportadas ou privadas fazem fallback para um card seguro com link externo, sem tentar um iframe genérico.
33
+ - Use HTML bruto quando você precisar de um provider fora da lista curada ou de controle manual total sobre o iframe.
@@ -0,0 +1,25 @@
1
+ ## Showcase
2
+
3
+ ### YouTube Video
4
+
5
+ <d-embedded-url url="https://www.youtube.com/watch?v=M7lc1UVf-VE&autoplay=1&loop=1" title="YouTube player demo">
6
+ The original playback query parameters stay attached to the provider URL.
7
+ </d-embedded-url>
8
+
9
+ ### Spotify Track
10
+
11
+ <d-embedded-url url="https://open.spotify.com/track/7ouMYWpwJ422jRcDASZB7P?si=1234">
12
+ Spotify links render with the provider-specific compact player height.
13
+ </d-embedded-url>
14
+
15
+ ### CodePen Demo
16
+
17
+ <d-embedded-url url="https://codepen.io/team/codepen/pen/PNaGbb?default-tab=result" title="Interactive demo">
18
+ Use the same block for live front-end demos without dropping to raw HTML.
19
+ </d-embedded-url>
20
+
21
+ ### Unsupported URL Fallback
22
+
23
+ <d-embedded-url url="https://example.com/docs/embed-me" title="External API docs">
24
+ Unsupported providers render a safe link card so the reading flow still keeps the URL visible and actionable.
25
+ </d-embedded-url>
@@ -0,0 +1,25 @@
1
+ ## Demonstração
2
+
3
+ ### Vídeo do YouTube
4
+
5
+ <d-embedded-url url="https://www.youtube.com/watch?v=M7lc1UVf-VE&autoplay=1&loop=1" title="Demo do player do YouTube">
6
+ Os parâmetros originais de reprodução continuam anexados à URL do provider.
7
+ </d-embedded-url>
8
+
9
+ ### Faixa do Spotify
10
+
11
+ <d-embedded-url url="https://open.spotify.com/track/7ouMYWpwJ422jRcDASZB7P?si=1234">
12
+ Links do Spotify renderizam com a altura compacta específica do provider.
13
+ </d-embedded-url>
14
+
15
+ ### Demo no CodePen
16
+
17
+ <d-embedded-url url="https://codepen.io/team/codepen/pen/PNaGbb?default-tab=result" title="Demo interativa">
18
+ Use o mesmo block para demos front-end ao vivo sem cair para HTML bruto.
19
+ </d-embedded-url>
20
+
21
+ ### Fallback para URL não suportada
22
+
23
+ <d-embedded-url url="https://example.com/docs/embed-me" title="Documentação externa da API">
24
+ Providers não suportados renderizam um card seguro com link externo, mantendo a URL visível e acionável no fluxo de leitura.
25
+ </d-embedded-url>
@@ -599,6 +599,34 @@ export default {
599
599
  }
600
600
  },
601
601
 
602
+ '/content/blocks/embedded-urls': {
603
+ config: {
604
+ icon: 'link',
605
+ status: 'new',
606
+ meta: {
607
+ description: {
608
+ 'en-US': 'Embedded URLs — Documentation of Docsector Reader',
609
+ 'pt-BR': 'URLs embutidas — Documentação do Docsector Reader'
610
+ }
611
+ },
612
+ book: 'manual',
613
+ menu: {},
614
+ subpages: {
615
+ showcase: true
616
+ }
617
+ },
618
+ data: {
619
+ 'en-US': { title: 'Embedded URLs' },
620
+ 'pt-BR': { title: 'URLs embutidas' }
621
+ },
622
+ metadata: {
623
+ tags: {
624
+ 'en-US': 'embed embedded url youtube vimeo spotify codepen iframe preview external link gitbook',
625
+ 'pt-BR': 'embed url embutida youtube vimeo spotify codepen iframe preview link externo gitbook'
626
+ }
627
+ }
628
+ },
629
+
602
630
  '/content/blocks/math-and-tex': {
603
631
  config: {
604
632
  icon: 'functions',
@@ -739,6 +767,34 @@ export default {
739
767
  }
740
768
  },
741
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
+
742
798
  '/content/structures': {
743
799
  config: null,
744
800
  data: {