@docsector/docsector-reader 3.3.1 → 3.5.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 +17 -0
- package/bin/docsector.js +1 -1
- package/jsconfig.json +1 -1
- package/package.json +2 -1
- package/src/components/DPageEmbeddedUrl.vue +375 -0
- package/src/components/DPageTokens.vue +10 -0
- package/src/components/page-section-tokens.js +112 -7
- package/src/composables/useEmbeddedUrl.js +365 -0
- package/src/css/app.sass +43 -0
- package/src/pages/manual/content/blocks/embedded-urls.overview.en-US.md +33 -0
- package/src/pages/manual/content/blocks/embedded-urls.overview.pt-BR.md +33 -0
- package/src/pages/manual/content/blocks/embedded-urls.showcase.en-US.md +25 -0
- package/src/pages/manual/content/blocks/embedded-urls.showcase.pt-BR.md +25 -0
- package/src/pages/manual/content/blocks/task-lists.overview.en-US.md +20 -0
- package/src/pages/manual/content/blocks/task-lists.overview.pt-BR.md +20 -0
- package/src/pages/manual/content/blocks/task-lists.showcase.en-US.md +23 -0
- package/src/pages/manual/content/blocks/task-lists.showcase.pt-BR.md +23 -0
- package/src/pages/manual.index.js +56 -0
- package/src/pages/manual/components/d-subpage.overview.en-US.md +0 -60
- package/src/pages/manual/components/d-subpage.overview.pt-BR.md +0 -60
|
@@ -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
|
+
}
|
package/src/css/app.sass
CHANGED
|
@@ -15,6 +15,11 @@ body
|
|
|
15
15
|
body.body--light
|
|
16
16
|
--q-primary: #655529 !important
|
|
17
17
|
--q-secondary: #000080 !important
|
|
18
|
+
--task-list-checkbox-bg: #ffffff
|
|
19
|
+
--task-list-checkbox-border: #7c6a3a
|
|
20
|
+
--task-list-checkbox-checked-bg: #5e4c1f
|
|
21
|
+
--task-list-checkbox-checked-border: #4f3f18
|
|
22
|
+
--task-list-checkbox-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2.3' d='M3.25 8.5 6.4 11.4 12.75 4.9'/%3E%3C/svg%3E")
|
|
18
23
|
|
|
19
24
|
--q-primary-background: #FFF !important
|
|
20
25
|
|
|
@@ -48,6 +53,11 @@ body.body--dark
|
|
|
48
53
|
--q-primary-in-dark-bg: #C1A667 !important
|
|
49
54
|
--q-secondary: #FFA07A !important
|
|
50
55
|
--q-negative: #fc001b !important
|
|
56
|
+
--task-list-checkbox-bg: #181818
|
|
57
|
+
--task-list-checkbox-border: #8f8a78
|
|
58
|
+
--task-list-checkbox-checked-bg: #d3b874
|
|
59
|
+
--task-list-checkbox-checked-border: #ebd08a
|
|
60
|
+
--task-list-checkbox-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23151515' stroke-linecap='round' stroke-linejoin='round' stroke-width='2.3' d='M3.25 8.5 6.4 11.4 12.75 4.9'/%3E%3C/svg%3E")
|
|
51
61
|
|
|
52
62
|
--q-light-in-dark-1: #ababab
|
|
53
63
|
--q-light-in-dark-2: #c9c9c9
|
|
@@ -199,6 +209,39 @@ body.body--dark
|
|
|
199
209
|
overflow-y: hidden
|
|
200
210
|
padding: 0.35rem 0.1rem
|
|
201
211
|
|
|
212
|
+
ul.contains-task-list,
|
|
213
|
+
ol.contains-task-list
|
|
214
|
+
list-style: none
|
|
215
|
+
padding-left: 1.75rem
|
|
216
|
+
|
|
217
|
+
li.task-list-item
|
|
218
|
+
list-style: none
|
|
219
|
+
|
|
220
|
+
input.task-list-item-checkbox
|
|
221
|
+
appearance: none
|
|
222
|
+
-webkit-appearance: none
|
|
223
|
+
width: 1rem
|
|
224
|
+
height: 1rem
|
|
225
|
+
margin: 0 0.55rem 0 -1.45rem
|
|
226
|
+
vertical-align: middle
|
|
227
|
+
pointer-events: none
|
|
228
|
+
opacity: 1
|
|
229
|
+
border: 2px solid var(--task-list-checkbox-border)
|
|
230
|
+
border-radius: 0.2rem
|
|
231
|
+
background-color: var(--task-list-checkbox-bg)
|
|
232
|
+
background-position: center
|
|
233
|
+
background-repeat: no-repeat
|
|
234
|
+
background-size: 0.72rem 0.72rem
|
|
235
|
+
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08)
|
|
236
|
+
|
|
237
|
+
&:checked
|
|
238
|
+
background-color: var(--task-list-checkbox-checked-bg)
|
|
239
|
+
border-color: var(--task-list-checkbox-checked-border)
|
|
240
|
+
background-image: var(--task-list-checkbox-check)
|
|
241
|
+
|
|
242
|
+
&:disabled
|
|
243
|
+
opacity: 1
|
|
244
|
+
|
|
202
245
|
a
|
|
203
246
|
text-decoration: none
|
|
204
247
|
outline: 0
|
|
@@ -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>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## Overview
|
|
2
|
+
|
|
3
|
+
Use task lists when each item should carry an explicit done or not-done state.
|
|
4
|
+
|
|
5
|
+
They work well for release preparation, editorial queues, migration follow-ups, and any checklist where progress matters as much as the content itself.
|
|
6
|
+
|
|
7
|
+
## Markdown Syntax
|
|
8
|
+
|
|
9
|
+
```markdown
|
|
10
|
+
- [ ] Write the overview page
|
|
11
|
+
- [x] Add localized examples
|
|
12
|
+
- [ ] Review screenshots
|
|
13
|
+
- [x] Update internal links
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Notes
|
|
17
|
+
|
|
18
|
+
- Task lists follow the same indentation rules as regular Markdown lists.
|
|
19
|
+
- Use `[ ]` for pending items and `[x]` for completed items.
|
|
20
|
+
- Published readers see static checkboxes and cannot toggle them from the page.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## Visão Geral
|
|
2
|
+
|
|
3
|
+
Use listas de tarefas quando cada item precisar deixar explícito se foi concluído ou não.
|
|
4
|
+
|
|
5
|
+
Elas funcionam bem para preparação de releases, filas editoriais, acompanhamentos de migração e qualquer checklist em que o progresso importa tanto quanto o conteúdo.
|
|
6
|
+
|
|
7
|
+
## Sintaxe em Markdown
|
|
8
|
+
|
|
9
|
+
```markdown
|
|
10
|
+
- [ ] Escreva a página de visão geral
|
|
11
|
+
- [x] Adicione exemplos localizados
|
|
12
|
+
- [ ] Revise as capturas de tela
|
|
13
|
+
- [x] Atualize os links internos
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Observações
|
|
17
|
+
|
|
18
|
+
- Listas de tarefas seguem as mesmas regras de indentação das listas Markdown comuns.
|
|
19
|
+
- Use `[ ]` para itens pendentes e `[x]` para itens concluídos.
|
|
20
|
+
- Leitores da documentação publicada veem checkboxes estáticos e não podem alterná-los pela página.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
## Showcase
|
|
2
|
+
|
|
3
|
+
### Simple Tasks
|
|
4
|
+
|
|
5
|
+
- [ ] Write the overview page
|
|
6
|
+
- [x] Add the showcase page
|
|
7
|
+
- [ ] Review internal links
|
|
8
|
+
|
|
9
|
+
### Nested Tasks
|
|
10
|
+
|
|
11
|
+
- [ ] Prepare the release
|
|
12
|
+
- [x] Update the changelog
|
|
13
|
+
- [ ] Run smoke tests
|
|
14
|
+
- [ ] Publish the package
|
|
15
|
+
|
|
16
|
+
### Mixed Guidance
|
|
17
|
+
|
|
18
|
+
> [!NOTE]
|
|
19
|
+
> Readers can see the authored state of each task, but published checkboxes stay read-only.
|
|
20
|
+
|
|
21
|
+
- [x] Keep completed items checked in the source.
|
|
22
|
+
- [ ] Use task lists when the state matters more than the order.
|
|
23
|
+
- Regular bullet lists are still better for collections that do not need a done/not-done signal.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
## Showcase
|
|
2
|
+
|
|
3
|
+
### Tarefas Simples
|
|
4
|
+
|
|
5
|
+
- [ ] Escreva a página de visão geral
|
|
6
|
+
- [x] Adicione a página de showcase
|
|
7
|
+
- [ ] Revise os links internos
|
|
8
|
+
|
|
9
|
+
### Tarefas Aninhadas
|
|
10
|
+
|
|
11
|
+
- [ ] Prepare a release
|
|
12
|
+
- [x] Atualize o changelog
|
|
13
|
+
- [ ] Execute smoke tests
|
|
14
|
+
- [ ] Publique o pacote
|
|
15
|
+
|
|
16
|
+
### Orientação de Uso
|
|
17
|
+
|
|
18
|
+
> [!NOTE]
|
|
19
|
+
> Leitores conseguem ver o estado definido no Markdown, mas os checkboxes publicados continuam somente leitura.
|
|
20
|
+
|
|
21
|
+
- [x] Mantenha marcados os itens concluídos no conteúdo-fonte.
|
|
22
|
+
- [ ] Use listas de tarefas quando o estado importar mais do que a ordem.
|
|
23
|
+
- Listas com marcadores continuam melhores para coleções que não precisam de sinal de concluído ou pendente.
|