@docsector/docsector-reader 4.1.0 → 4.3.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.
Files changed (27) hide show
  1. package/README.md +16 -6
  2. package/bin/docsector.js +1 -1
  3. package/docsector.config.js +15 -0
  4. package/package.json +1 -1
  5. package/public/.well-known/agent-skills/docsector-documentation-authoring/SKILL.md +118 -0
  6. package/public/.well-known/agent-skills/docsector-documentation-authoring/references/authoring-patterns.md +98 -0
  7. package/public/.well-known/agent-skills/docsector-documentation-authoring/references/block-catalog.md +321 -0
  8. package/public/.well-known/agent-skills/docsector-documentation-authoring/references/mcp-webmcp.md +90 -0
  9. package/public/.well-known/agent-skills/docsector-documentation-authoring/references/page-structure.md +101 -0
  10. package/public/api/manual/http-client.json +91 -0
  11. package/public/quasar-api/QSeparator.json +39 -0
  12. package/src/components/DBlockApi.vue +634 -0
  13. package/src/components/DBlockApiEntry.js +623 -0
  14. package/src/components/DBlockCodeExample.vue +22 -0
  15. package/src/components/DBlockSourceCode.vue +2 -4
  16. package/src/components/DMenu.vue +70 -25
  17. package/src/components/DPageTokens.vue +8 -0
  18. package/src/components/api-block-model.js +326 -0
  19. package/src/components/page-section-tokens.js +53 -1
  20. package/src/components/source-code-lines.js +17 -0
  21. package/src/pages/manual/basic/agent-skills.overview.en-US.md +77 -0
  22. package/src/pages/manual/basic/agent-skills.overview.pt-BR.md +77 -0
  23. package/src/pages/manual/content/blocks/api-reference.overview.en-US.md +40 -0
  24. package/src/pages/manual/content/blocks/api-reference.overview.pt-BR.md +40 -0
  25. package/src/pages/manual/content/blocks/api-reference.showcase.en-US.md +33 -0
  26. package/src/pages/manual/content/blocks/api-reference.showcase.pt-BR.md +33 -0
  27. package/src/pages/manual.index.js +57 -0
@@ -0,0 +1,623 @@
1
+ import { h, ref } from 'vue'
2
+ import { copyToClipboard, Notify, QBadge, QBtn, QBtnToggle } from 'quasar'
3
+ import { mdiMinusBox, mdiPlusBox } from '@quasar/extras/mdi-v7'
4
+
5
+ function copyPropName(propName) {
6
+ copyToClipboard(propName).then(() => {
7
+ Notify.create({
8
+ message: `"${propName}" has been copied to clipboard.`,
9
+ position: 'top',
10
+ actions: [{ icon: 'cancel', color: 'white', dense: true, round: true }],
11
+ timeout: 2000
12
+ })
13
+ })
14
+ }
15
+
16
+ function getEventParams(event) {
17
+ const params =
18
+ event.params === void 0 ||
19
+ event.params === null ||
20
+ Object.keys(event.params).length === 0
21
+ ? ''
22
+ : Object.keys(event.params).join(', ')
23
+
24
+ return `(${params}) => void`
25
+ }
26
+
27
+ function getMethodParams(method, noRequired) {
28
+ if (
29
+ method.params === void 0 ||
30
+ method.params === null ||
31
+ Object.keys(method.params).length === 0
32
+ ) {
33
+ return '()'
34
+ }
35
+
36
+ if (noRequired) {
37
+ return `(${Object.keys(method.params).join(', ')})`
38
+ }
39
+
40
+ const params = Object.keys(method.params)
41
+ const optionalIndex = params.findIndex(
42
+ (param) => method.params[param].required !== true
43
+ )
44
+
45
+ const str = optionalIndex !== -1
46
+ ? params.slice(0, optionalIndex).join(', ') +
47
+ (optionalIndex < params.length
48
+ ? (optionalIndex > 0 ? ', ' : '') +
49
+ params.slice(optionalIndex).join('?, ') +
50
+ '?'
51
+ : '')
52
+ : params.join(', ')
53
+
54
+ return `(${str})`
55
+ }
56
+
57
+ function getMethodReturnValue(method) {
58
+ return method.returns === void 0 || method.returns === null
59
+ ? ' => void'
60
+ : ` => ${getStringType(method.returns.type)}`
61
+ }
62
+
63
+ function getStringType(type) {
64
+ if (Array.isArray(type)) {
65
+ return type.join(' | ')
66
+ }
67
+
68
+ return String(type || 'Unknown')
69
+ }
70
+
71
+ const NAME_PROP_COLOR = ['orange-8', 'primary', 'green-5', 'purple-5']
72
+ const NAME_PROP_COLOR_LEN = NAME_PROP_COLOR.length
73
+
74
+ function getDiv(col, propName, propValue, slot) {
75
+ return h('div', { class: `doc-api-entry__item col-xs-12 col-sm-${col}` }, [
76
+ h('div', { class: 'doc-api-entry__type' }, propName),
77
+ propValue !== void 0
78
+ ? h('div', { class: 'doc-api-entry__value' }, propValue)
79
+ : slot
80
+ ])
81
+ }
82
+
83
+ function getNameDiv(prop, label, level, suffix, prefix) {
84
+ const child = []
85
+
86
+ if (prefix !== void 0) {
87
+ child.push(h('div', { class: 'doc-api-entry__type q-mr-xs' }, prefix))
88
+ }
89
+
90
+ child.push(
91
+ h(QBadge, {
92
+ class: 'doc-api-entry__pill cursor-pointer',
93
+ label,
94
+ color: NAME_PROP_COLOR[level % NAME_PROP_COLOR_LEN],
95
+ onClick: () => {
96
+ copyPropName(label)
97
+ }
98
+ })
99
+ )
100
+
101
+ const suffixLabel = `${suffix ? ` : ${suffix}` : ''}${prop.required ? ' - required!' : ''}`
102
+ if (suffixLabel !== '') {
103
+ child.push(h('div', { class: 'doc-api-entry__type q-ml-xs' }, suffixLabel))
104
+ }
105
+
106
+ if (prop.addedIn !== void 0) {
107
+ child.push(
108
+ h(QBadge, {
109
+ class: 'q-ml-sm doc-api-entry__added-in',
110
+ outline: true,
111
+ label: `${prop.addedIn}+`
112
+ })
113
+ )
114
+ }
115
+
116
+ return h(
117
+ 'div',
118
+ { class: 'doc-api-entry__item col-xs-12 col-sm-12 row items-center' },
119
+ child
120
+ )
121
+ }
122
+
123
+ function getExpandable(openState, desc, isExpandable, key, getDetails) {
124
+ if (isExpandable) {
125
+ const expanded = openState.value[key] === true
126
+ const child = [
127
+ h('div', { class: 'doc-api-entry__item col-xs-12 col-sm-12' }, [
128
+ h('div', { class: 'doc-api-entry__type row items-center no-wrap' }, [
129
+ h('span', 'Description'),
130
+ h(QBtn, {
131
+ class: 'doc-api-entry__expand-btn',
132
+ flat: true,
133
+ size: '11px',
134
+ padding: '1px',
135
+ icon: expanded ? mdiMinusBox : mdiPlusBox,
136
+ onClick: () => {
137
+ openState.value[key] = !expanded
138
+ }
139
+ })
140
+ ]),
141
+ h('div', { class: 'doc-api-entry__value' }, desc)
142
+ ])
143
+ ]
144
+
145
+ return expanded ? [...child, ...getDetails()] : child
146
+ }
147
+
148
+ return [getDiv(12, 'Description', desc)]
149
+ }
150
+
151
+ function getPropDetails(openState, masterKey, prop, level) {
152
+ const details = []
153
+
154
+ if (prop.sync) {
155
+ details.push(getDiv(3, 'Note', 'Required to be used with v-model!'))
156
+ }
157
+
158
+ if (prop.default !== void 0) {
159
+ details.push(
160
+ getDiv(
161
+ 3,
162
+ 'Default value',
163
+ void 0,
164
+ h(
165
+ 'div',
166
+ { class: 'doc-api-entry--indent doc-api-entry__value' },
167
+ h('div', { class: 'doc-token' }, String(prop.default))
168
+ )
169
+ )
170
+ )
171
+ }
172
+
173
+ if (prop.link) {
174
+ details.push(getDiv(6, 'External link', prop.link))
175
+ }
176
+
177
+ if (prop.values !== void 0) {
178
+ details.push(
179
+ getDiv(
180
+ 12,
181
+ 'Accepted values',
182
+ void 0,
183
+ h(
184
+ 'div',
185
+ { class: 'doc-api-entry--indent doc-api-entry__value' },
186
+ prop.values.map((val) => h('div', { class: 'doc-token' }, String(val)))
187
+ )
188
+ )
189
+ )
190
+ }
191
+
192
+ if (prop.definition !== void 0) {
193
+ const nodes = []
194
+
195
+ Object.entries(prop.definition).forEach(([propName, value]) => {
196
+ nodes.push(getProp(openState, masterKey, value, propName, level))
197
+ })
198
+
199
+ details.push(
200
+ getDiv(
201
+ 12,
202
+ 'Props',
203
+ void 0,
204
+ h('div', { class: 'doc-api-entry__subitem' }, nodes)
205
+ )
206
+ )
207
+ }
208
+
209
+ if (prop.params !== void 0 && prop.params !== null) {
210
+ const nodes = []
211
+
212
+ Object.entries(prop.params).forEach(([propName, value]) => {
213
+ nodes.push(getProp(openState, masterKey, value, propName, level))
214
+ })
215
+
216
+ details.push(
217
+ getDiv(
218
+ 12,
219
+ 'Params',
220
+ void 0,
221
+ h('div', { class: 'doc-api-entry__subitem' }, nodes)
222
+ )
223
+ )
224
+ }
225
+
226
+ if (prop.returns !== void 0 && prop.returns !== null) {
227
+ details.push(
228
+ getDiv(
229
+ 12,
230
+ `Return type: ${getStringType(prop.returns.type)}`,
231
+ void 0,
232
+ h('div', { class: 'doc-api-entry__subitem' }, [
233
+ getProp(openState, masterKey, prop.returns, void 0, level)
234
+ ])
235
+ )
236
+ )
237
+ }
238
+
239
+ if (prop.scope !== void 0) {
240
+ const nodes = []
241
+
242
+ Object.entries(prop.scope).forEach(([propName, value]) => {
243
+ nodes.push(getProp(openState, masterKey, value, propName, level))
244
+ })
245
+
246
+ details.push(
247
+ getDiv(
248
+ 12,
249
+ 'Scope',
250
+ void 0,
251
+ h('div', { class: 'doc-api-entry__subitem' }, nodes)
252
+ )
253
+ )
254
+ }
255
+
256
+ if (prop.examples !== void 0) {
257
+ details.push(
258
+ getDiv(
259
+ 12,
260
+ `Example${prop.examples.length > 1 ? 's' : ''}`,
261
+ void 0,
262
+ h(
263
+ 'div',
264
+ { class: 'doc-api-entry--indent doc-api-entry__value' },
265
+ prop.examples.map((example) => h('div', { class: 'doc-token' }, String(example)))
266
+ )
267
+ )
268
+ )
269
+ }
270
+
271
+ return details
272
+ }
273
+
274
+ function getProp(openState, masterKey, prop, propName, level, onlyChildren) {
275
+ const configToggle = useConfigToggle(openState)
276
+
277
+ if (
278
+ configToggle.enabled &&
279
+ configToggle.type === 'configFile' &&
280
+ prop.configFileType === null
281
+ ) {
282
+ return undefined
283
+ }
284
+
285
+ const rawType = configToggle.enabled
286
+ ? configToggle.type === 'configFile'
287
+ ? prop.configFileType || prop.type
288
+ : prop.type
289
+ : prop.type
290
+ const type = getStringType(rawType)
291
+ const child = []
292
+
293
+ if (propName !== void 0) {
294
+ const suffix = type === 'Function'
295
+ ? `${getMethodParams(prop, true)}${getMethodReturnValue(prop)}`
296
+ : type
297
+
298
+ child.push(getNameDiv(prop, propName, level, suffix))
299
+
300
+ if (prop.reactive) {
301
+ child.push(getDiv(3, 'Reactive', 'yes'))
302
+ }
303
+ }
304
+
305
+ const isExpandable =
306
+ prop.sync === true ||
307
+ prop.default !== void 0 ||
308
+ prop.link === true ||
309
+ prop.values !== void 0 ||
310
+ prop.definition !== void 0 ||
311
+ (prop.params !== void 0 && prop.params !== null) ||
312
+ (prop.returns !== void 0 && prop.returns !== null) ||
313
+ prop.scope !== void 0 ||
314
+ prop.examples !== void 0
315
+
316
+ const childKey = `${masterKey}|||prop|${prop.type}|${propName}|${level}`
317
+
318
+ child.push(
319
+ ...getExpandable(openState, prop.desc, isExpandable, childKey, () =>
320
+ getPropDetails(openState, childKey, prop, level + 1)
321
+ )
322
+ )
323
+
324
+ return onlyChildren !== true
325
+ ? h('div', { class: 'doc-api-entry row' }, child.filter(Boolean))
326
+ : child.filter(Boolean)
327
+ }
328
+
329
+ const describe = {}
330
+
331
+ const describePropsLike = (masterKey) => (openState, props) => {
332
+ const child = []
333
+
334
+ Object.entries(props || {}).forEach(([propName, value]) => {
335
+ child.push(getProp(openState, masterKey, value, propName, 0))
336
+ })
337
+
338
+ return child.filter(Boolean)
339
+ }
340
+
341
+ describe.props = describePropsLike('props')
342
+ describe.computedProps = describePropsLike('computedProps')
343
+ describe.slots = describePropsLike('slots')
344
+ describe.generic = describePropsLike('generic')
345
+
346
+ describe.events = (openState, events) => {
347
+ const child = []
348
+
349
+ if (events === void 0) {
350
+ return child
351
+ }
352
+
353
+ Object.entries(events).forEach(([eventName, event]) => {
354
+ const masterKey = `event|${eventName}`
355
+
356
+ child.push(
357
+ h('div', { class: 'doc-api-entry row' }, [
358
+ getNameDiv(event, `@${eventName}`, 0, getEventParams(event)),
359
+
360
+ ...getExpandable(
361
+ openState,
362
+ event.desc,
363
+ event.params !== void 0 && event.params !== null,
364
+ masterKey,
365
+ () => {
366
+ const params = []
367
+
368
+ Object.entries(event.params || {}).forEach(([paramName, value]) => {
369
+ params.push(getProp(openState, masterKey, value, paramName, 1))
370
+ })
371
+
372
+ return [
373
+ getDiv(
374
+ 12,
375
+ 'Parameters',
376
+ void 0,
377
+ h('div', { class: 'doc-api-entry__subitem' }, params.filter(Boolean))
378
+ )
379
+ ]
380
+ }
381
+ )
382
+ ])
383
+ )
384
+ })
385
+
386
+ return child.filter(Boolean)
387
+ }
388
+
389
+ describe.methods = (openState, methods) => {
390
+ const child = []
391
+
392
+ Object.entries(methods || {}).forEach(([methodName, method]) => {
393
+ const masterKey = `method|${methodName}`
394
+ const alias = method.alias ? `Alias: "${method.alias}"; ` : ''
395
+ const desc = `${alias}${method.desc}`
396
+
397
+ child.push(
398
+ h('div', { class: 'doc-api-entry row' }, [
399
+ getNameDiv(
400
+ method,
401
+ methodName,
402
+ 0,
403
+ `${getMethodParams(method)}${getMethodReturnValue(method)}`
404
+ ),
405
+
406
+ ...getExpandable(
407
+ openState,
408
+ desc,
409
+ method.params !== void 0 || method.returns !== void 0,
410
+ masterKey,
411
+ () => {
412
+ const nodes = []
413
+
414
+ if (method.params !== void 0 && method.params !== null) {
415
+ const props = []
416
+
417
+ Object.entries(method.params || {}).forEach(([paramName, value]) => {
418
+ props.push(getProp(openState, masterKey, value, paramName, 1))
419
+ })
420
+
421
+ nodes.push(
422
+ getDiv(
423
+ 12,
424
+ 'Parameters',
425
+ void 0,
426
+ h('div', { class: 'doc-api-entry__subitem' }, props.filter(Boolean))
427
+ )
428
+ )
429
+ }
430
+
431
+ if (method.returns !== void 0 && method.returns !== null) {
432
+ nodes.push(
433
+ getDiv(
434
+ 12,
435
+ `Return type: ${getStringType(method.returns.type)}`,
436
+ void 0,
437
+ h('div', { class: 'doc-api-entry__subitem' }, [
438
+ getProp(openState, masterKey, method.returns, void 0, 1)
439
+ ])
440
+ )
441
+ )
442
+ }
443
+
444
+ return nodes
445
+ }
446
+ )
447
+ ])
448
+ )
449
+ })
450
+
451
+ return child.filter(Boolean)
452
+ }
453
+
454
+ describe.value = (openState, value) => [
455
+ h(
456
+ 'div',
457
+ { class: 'doc-api-entry row' },
458
+ [getDiv(12, 'Type', getStringType(value.type))].concat(
459
+ getProp(openState, 'value', value, void 0, -1, true)
460
+ )
461
+ )
462
+ ]
463
+
464
+ describe.arg = (openState, arg) => [
465
+ h(
466
+ 'div',
467
+ { class: 'doc-api-entry row' },
468
+ [getDiv(12, 'Type', getStringType(arg.type))].concat(
469
+ getProp(openState, 'arg', arg, void 0, -1, true)
470
+ )
471
+ )
472
+ ]
473
+
474
+ describe.modifiers = (openState, modifiers) => {
475
+ const child = []
476
+
477
+ Object.entries(modifiers || {}).forEach(([modifierName, modifier]) => {
478
+ child.push(
479
+ h(
480
+ 'div',
481
+ { class: 'doc-api-entry row' },
482
+ getProp(openState, 'modifiers', modifier, modifierName, 0, true)
483
+ )
484
+ )
485
+ })
486
+
487
+ return child.filter(Boolean)
488
+ }
489
+
490
+ describe.injection = (_, injection) => [
491
+ h('div', { class: 'doc-api-entry row' }, [
492
+ getNameDiv({ required: false }, injection, 0)
493
+ ])
494
+ ]
495
+
496
+ function useConfigToggle(openState) {
497
+ return {
498
+ enabled: openState.value.quasarConfOptions !== void 0,
499
+ type: openState.value.quasarConfOptions ? 'uiConfig' : 'configFile',
500
+ setType: (type) => {
501
+ openState.value.quasarConfOptions = type === 'uiConfig'
502
+ }
503
+ }
504
+ }
505
+
506
+ describe.quasarConfOptions = (openState, conf) => {
507
+ const configToggle = useConfigToggle(openState)
508
+
509
+ if (!configToggle.enabled) {
510
+ const needsConfigToggle = conf.definition && Object.values(conf.definition).some(
511
+ ({ configFileType }) => configFileType !== void 0
512
+ )
513
+
514
+ if (needsConfigToggle) {
515
+ openState.value.quasarConfOptions = false
516
+ }
517
+ }
518
+
519
+ const configFileName = () => getNameDiv(
520
+ conf,
521
+ conf.propName,
522
+ 0,
523
+ false,
524
+ 'quasar.config file > framework > config > '
525
+ )
526
+ const uiConfigName = () => getNameDiv(
527
+ conf,
528
+ conf.propName,
529
+ 0,
530
+ '... }})',
531
+ 'app.use(Quasar, { config: { '
532
+ )
533
+
534
+ const entry = configToggle.enabled
535
+ ? [
536
+ configToggle.type === 'configFile' ? configFileName() : uiConfigName(),
537
+ getDiv(
538
+ 8,
539
+ 'Type',
540
+ getStringType(conf.configFileType || conf.type || 'Object')
541
+ ),
542
+ h(
543
+ 'div',
544
+ { class: 'doc-api-entry__item col row justify-end items-center' },
545
+ [
546
+ h(QBtnToggle, {
547
+ modelValue: configToggle.type,
548
+ 'onUpdate:modelValue': configToggle.setType,
549
+ options: [
550
+ { label: 'quasar.config file', value: 'configFile' },
551
+ { label: 'UI config', value: 'uiConfig' }
552
+ ],
553
+ noCaps: true,
554
+ rounded: true,
555
+ outline: true,
556
+ toggleColor: 'orange-8'
557
+ })
558
+ ]
559
+ )
560
+ ]
561
+ : [
562
+ configFileName(),
563
+ uiConfigName(),
564
+ getDiv(12, 'Type', getStringType(conf.type || 'Object'))
565
+ ]
566
+
567
+ if (conf.desc) {
568
+ entry.push(getDiv(12, 'Description', conf.desc))
569
+ }
570
+
571
+ entry.push(...getPropDetails(openState, 'quasarConfOptions', conf, 0))
572
+
573
+ if (conf.definition && Object.keys(conf.definition).length === 0) {
574
+ entry.push(
575
+ h('div', { class: 'q-pa-md doc-api__nothing-to-show' }, [
576
+ h('div', 'No matching props found.'),
577
+ h(
578
+ 'div',
579
+ 'Please check the other tabs/subtabs with a number badge on their label or refine the filter.'
580
+ )
581
+ ])
582
+ )
583
+ }
584
+
585
+ return [h('div', { class: 'doc-api-entry row' }, entry)]
586
+ }
587
+
588
+ export default {
589
+ name: 'DBlockApiEntry',
590
+
591
+ props: {
592
+ type: String,
593
+ definition: {
594
+ type: [Object, String],
595
+ default: () => ({})
596
+ }
597
+ },
598
+
599
+ setup(props) {
600
+ const openState = ref({})
601
+
602
+ return () => {
603
+ const definition = props.definition || {}
604
+ const hasEntries = typeof definition === 'string'
605
+ ? definition.trim() !== ''
606
+ : Object.keys(definition).length !== 0
607
+ const describeEntry = describe[props.type] || describe.generic
608
+ const content = hasEntries
609
+ ? describeEntry(openState, definition)
610
+ : [
611
+ h('div', { class: 'q-pa-md doc-api__nothing-to-show' }, [
612
+ h('div', 'No matching entries found on this tab.'),
613
+ h(
614
+ 'div',
615
+ 'Please check the other tabs/subtabs with a number badge on their label or refine the filter.'
616
+ )
617
+ ])
618
+ ]
619
+
620
+ return h('div', { class: 'doc-api-entries' }, content)
621
+ }
622
+ }
623
+ }
@@ -327,6 +327,9 @@ function openGitHub () {
327
327
  body.body--light
328
328
  --d-code-example-bg: #ffffff
329
329
  --d-code-example-border: rgba(37, 67, 45, 0.16)
330
+ --d-code-example-button-bg: #edf3ee
331
+ --d-code-example-button-border: rgba(37, 67, 45, 0.12)
332
+ --d-code-example-button-hover-bg: #e2ebe4
330
333
  --d-code-example-toolbar-bg: #f6f8f5
331
334
  --d-code-example-toolbar-text: #26352b
332
335
  --d-code-example-preview-bg: #ffffff
@@ -336,6 +339,9 @@ body.body--light
336
339
  body.body--dark
337
340
  --d-code-example-bg: #111512
338
341
  --d-code-example-border: rgba(197, 220, 200, 0.18)
342
+ --d-code-example-button-bg: #29342d
343
+ --d-code-example-button-border: rgba(197, 220, 200, 0.18)
344
+ --d-code-example-button-hover-bg: #314036
339
345
  --d-code-example-toolbar-bg: #1a211c
340
346
  --d-code-example-toolbar-text: #e8efe9
341
347
  --d-code-example-preview-bg: #0c0f0d
@@ -371,11 +377,27 @@ body.body--dark
371
377
  white-space: nowrap
372
378
 
373
379
  &__button
380
+ background: var(--d-code-example-button-bg)
381
+ border: 1px solid var(--d-code-example-button-border)
382
+ border-radius: 999px
374
383
  color: var(--d-code-example-muted)
375
384
  flex: 0 0 auto
385
+ min-height: 30px
386
+ min-width: 30px
387
+ transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease
388
+
389
+ &:hover,
390
+ &:focus-visible
391
+ background: var(--d-code-example-button-hover-bg)
392
+ color: var(--d-code-example-toolbar-text)
393
+
394
+ &.q-btn--disabled,
395
+ &[disabled]
396
+ opacity: 0.55
376
397
 
377
398
  &__source
378
399
  border-top: 1px solid var(--d-code-example-border)
400
+ border-bottom: 1px solid var(--d-code-example-border)
379
401
 
380
402
  .source-code
381
403
  box-shadow: none
@@ -3,6 +3,7 @@ import { ref, computed, watch } from 'vue'
3
3
  import { useQuasar } from 'quasar'
4
4
  import { useStore } from 'vuex'
5
5
  import Prism from './code-block-highlighting'
6
+ import { countRenderedCodeLines } from './source-code-lines'
6
7
  import { looksLikeFileName, resolveFileIconUrl } from '../composables/useFileIcon'
7
8
 
8
9
  defineOptions({
@@ -95,10 +96,7 @@ const activeBreadcrumbItems = computed(() => {
95
96
  })
96
97
  const activeBreadcrumbTitle = computed(() => activeBreadcrumbs.value.join(' > '))
97
98
  const hasBreadcrumbs = computed(() => activeBreadcrumbs.value.length > 0)
98
- const lines = computed(() => {
99
- const splited = activeText.value.split(/\r\n|\n/)
100
- return splited.length - 1
101
- })
99
+ const lines = computed(() => countRenderedCodeLines(activeText.value))
102
100
  const showHeader = computed(() => hasTabs.value || hasBreadcrumbs.value || (lines.value && lines.value > 1))
103
101
  const codeLanguageClass = computed(() => `language-${activeLanguage.value}`)
104
102
  const highlighted = computed(() => {