lutaml-jsonschema 0.1.14 → 0.1.15
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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +1 -1
- data/frontend/src/components/DetailPanel.vue +212 -4
- data/frontend/src/components/SchemaBuilder.vue +81 -2
- data/frontend/src/composables/useMarkdownLite.ts +74 -4
- data/frontend/src/views/HomeView.vue +263 -56
- data/lib/lutaml/jsonschema/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a01871af7f67b7fac28c6c32abf7397d48af9c14cc95004849310f8f1b3d13cc
|
|
4
|
+
data.tar.gz: 119580a2cacbf4374811f05765074442fa06d25e733f81b65aec40f18a1069b0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 17e159091bff17f2d15ec5aefac90e6bff786a3df02677cb40bb24f635e4f2fc3785173d9336d5f7e5636a230cb1c1a21ade16d4d3155841d7ddcd3ae7d3207d
|
|
7
|
+
data.tar.gz: d3c1630021ee7690da9dff15293668fef1dc464c26493f7347d726c6e976f946c1e89057180023eb6aff4851ed011f9894ef6475b1118dfd823f4ce258bba69e
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on 2026-05-
|
|
3
|
+
# on 2026-05-13 07:41:21 UTC using RuboCop version 1.86.1.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
@@ -168,7 +168,8 @@
|
|
|
168
168
|
<td class="constraint-key">Enum</td>
|
|
169
169
|
<td>
|
|
170
170
|
<div class="enum-values-list">
|
|
171
|
-
<span v-for="e in propertyItem.enum" :key="e" class="enum-value-chip">{{ e }}</span>
|
|
171
|
+
<span v-for="e in visibleEnumValues(propertyItem.name, propertyItem.enum)" :key="e" class="enum-value-chip">{{ e }}</span>
|
|
172
|
+
<button v-if="propertyItem.enum.length > 8 && !detailEnumExpanded.has(propertyItem.name)" class="enum-more-btn" @click="toggleDetailEnum(propertyItem.name)">+{{ propertyItem.enum.length - 8 }} more</button>
|
|
172
173
|
</div>
|
|
173
174
|
</td>
|
|
174
175
|
</tr>
|
|
@@ -260,12 +261,15 @@
|
|
|
260
261
|
<div v-if="examples.length" class="example-group">
|
|
261
262
|
<h4 class="example-label">Provided Examples</h4>
|
|
262
263
|
<div v-for="(ex, idx) in examples" :key="idx" class="example-block">
|
|
263
|
-
<
|
|
264
|
+
<div v-if="isComplexExample(ex)" class="example-collapsible" @click="toggleExampleCollapse($event)" @keydown="handleExampleKey($event)">
|
|
265
|
+
<pre class="example-pre" v-html="renderExampleHtml(ex)"></pre>
|
|
266
|
+
</div>
|
|
267
|
+
<pre v-else class="example-pre"><code>{{ formatExample(ex) }}</code></pre>
|
|
264
268
|
</div>
|
|
265
269
|
</div>
|
|
266
270
|
<div v-if="generatedExample" class="example-group">
|
|
267
271
|
<h4 class="example-label">Generated Example</h4>
|
|
268
|
-
<pre class="example-pre example-generated"
|
|
272
|
+
<pre class="example-pre example-generated" v-html="renderExampleHtml(generatedExample)"></pre>
|
|
269
273
|
</div>
|
|
270
274
|
<p v-if="!examples.length && !generatedExample" class="text-muted">No examples available.</p>
|
|
271
275
|
</div>
|
|
@@ -281,10 +285,11 @@
|
|
|
281
285
|
</template>
|
|
282
286
|
|
|
283
287
|
<script setup lang="ts">
|
|
284
|
-
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
|
288
|
+
import { computed, ref, reactive, onMounted, onUnmounted } from 'vue'
|
|
285
289
|
import { useSchemaStore, type SelectedItem } from '../stores/schemaStore'
|
|
286
290
|
import { useUiStore } from '../stores/uiStore'
|
|
287
291
|
import { renderInlineMarkdown } from '../composables/useMarkdownLite'
|
|
292
|
+
import { jsonToCollapsibleHtml } from '../composables/useJsonViewer'
|
|
288
293
|
import type { SpaProperty } from '../types'
|
|
289
294
|
|
|
290
295
|
const schemaStore = useSchemaStore()
|
|
@@ -292,6 +297,17 @@ const uiStore = useUiStore()
|
|
|
292
297
|
|
|
293
298
|
const panelRef = ref<HTMLElement | null>(null)
|
|
294
299
|
const closeBtnRef = ref<HTMLButtonElement | null>(null)
|
|
300
|
+
const detailEnumExpanded = reactive(new Set<string>())
|
|
301
|
+
|
|
302
|
+
function visibleEnumValues(name: string, enums: string[]): string[] {
|
|
303
|
+
if (detailEnumExpanded.has(name) || enums.length <= 8) return enums
|
|
304
|
+
return enums.slice(0, 8)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function toggleDetailEnum(name: string) {
|
|
308
|
+
if (detailEnumExpanded.has(name)) detailEnumExpanded.delete(name)
|
|
309
|
+
else detailEnumExpanded.add(name)
|
|
310
|
+
}
|
|
295
311
|
|
|
296
312
|
onMounted(() => {
|
|
297
313
|
closeBtnRef.value?.focus()
|
|
@@ -514,6 +530,56 @@ function navigateToProperty(name: string) {
|
|
|
514
530
|
uiStore.closeDetailPanel()
|
|
515
531
|
schemaStore.selectProperty(name)
|
|
516
532
|
}
|
|
533
|
+
|
|
534
|
+
function isComplexExample(value: unknown): boolean {
|
|
535
|
+
if (typeof value === 'string') {
|
|
536
|
+
try { return typeof JSON.parse(value) === 'object' } catch { return false }
|
|
537
|
+
}
|
|
538
|
+
return typeof value === 'object' && value !== null
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function renderExampleHtml(value: unknown): string {
|
|
542
|
+
let parsed: unknown
|
|
543
|
+
if (typeof value === 'string') {
|
|
544
|
+
try { parsed = JSON.parse(value) } catch { return escapeHtml(value) }
|
|
545
|
+
} else {
|
|
546
|
+
parsed = value
|
|
547
|
+
}
|
|
548
|
+
try {
|
|
549
|
+
return jsonToCollapsibleHtml(parsed, 3)
|
|
550
|
+
} catch {
|
|
551
|
+
return escapeHtml(typeof parsed === 'string' ? parsed : JSON.stringify(parsed, null, 2))
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function escapeHtml(t: string): string {
|
|
556
|
+
return t.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function toggleExampleCollapse(event: MouseEvent) {
|
|
560
|
+
const target = event.target as HTMLElement
|
|
561
|
+
if (!target.classList.contains('jv-toggle')) return
|
|
562
|
+
const parent = target.parentElement
|
|
563
|
+
if (!parent) return
|
|
564
|
+
const children = parent.querySelector('.jv-children')
|
|
565
|
+
if (!children) return
|
|
566
|
+
const isCollapsed = children.classList.contains('jv-collapsed')
|
|
567
|
+
if (isCollapsed) {
|
|
568
|
+
children.classList.remove('jv-collapsed')
|
|
569
|
+
target.setAttribute('aria-label', 'collapse')
|
|
570
|
+
} else {
|
|
571
|
+
children.classList.add('jv-collapsed')
|
|
572
|
+
target.setAttribute('aria-label', 'expand')
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function handleExampleKey(event: KeyboardEvent) {
|
|
577
|
+
if (event.key !== 'Enter' && event.key !== ' ') return
|
|
578
|
+
const target = event.target as HTMLElement
|
|
579
|
+
if (!target.classList.contains('jv-toggle')) return
|
|
580
|
+
event.preventDefault()
|
|
581
|
+
toggleExampleCollapse(event as unknown as MouseEvent)
|
|
582
|
+
}
|
|
517
583
|
</script>
|
|
518
584
|
|
|
519
585
|
<style scoped>
|
|
@@ -820,6 +886,20 @@ function navigateToProperty(name: string) {
|
|
|
820
886
|
color: var(--text-primary);
|
|
821
887
|
}
|
|
822
888
|
|
|
889
|
+
.enum-more-btn {
|
|
890
|
+
font-size: 11px;
|
|
891
|
+
color: var(--color-primary);
|
|
892
|
+
background: none;
|
|
893
|
+
border: none;
|
|
894
|
+
cursor: pointer;
|
|
895
|
+
padding: 1px 4px;
|
|
896
|
+
font-family: var(--font-mono);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
.enum-more-btn:hover {
|
|
900
|
+
text-decoration: underline;
|
|
901
|
+
}
|
|
902
|
+
|
|
823
903
|
.constraint-table td:first-child {
|
|
824
904
|
font-weight: 500;
|
|
825
905
|
color: var(--text-secondary);
|
|
@@ -896,6 +976,103 @@ function navigateToProperty(name: string) {
|
|
|
896
976
|
border-color: var(--color-primary-alpha);
|
|
897
977
|
}
|
|
898
978
|
|
|
979
|
+
.example-collapsible {
|
|
980
|
+
cursor: default;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
.example-pre :deep(ul) {
|
|
984
|
+
list-style: none;
|
|
985
|
+
padding-left: var(--space-4);
|
|
986
|
+
margin: 0;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
.example-pre :deep(li) {
|
|
990
|
+
margin: 0;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
.example-pre :deep(.jv-toggle) {
|
|
994
|
+
background: none;
|
|
995
|
+
border: 1px solid var(--border-medium);
|
|
996
|
+
border-radius: 2px;
|
|
997
|
+
cursor: pointer;
|
|
998
|
+
width: 14px;
|
|
999
|
+
height: 14px;
|
|
1000
|
+
font-size: 9px;
|
|
1001
|
+
line-height: 1;
|
|
1002
|
+
display: inline-flex;
|
|
1003
|
+
align-items: center;
|
|
1004
|
+
justify-content: center;
|
|
1005
|
+
color: var(--text-muted);
|
|
1006
|
+
padding: 0;
|
|
1007
|
+
margin-right: 4px;
|
|
1008
|
+
vertical-align: middle;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
.example-pre :deep(.jv-toggle:hover) {
|
|
1012
|
+
background: var(--bg-hover);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
.example-pre :deep(.jv-toggle[aria-label="expand"])::after { content: '+'; }
|
|
1016
|
+
.example-pre :deep(.jv-toggle[aria-label="collapse"])::after { content: '−'; }
|
|
1017
|
+
|
|
1018
|
+
.example-pre :deep(.jv-ellipsis) {
|
|
1019
|
+
display: none;
|
|
1020
|
+
color: var(--text-muted);
|
|
1021
|
+
font-size: var(--text-xs);
|
|
1022
|
+
font-style: italic;
|
|
1023
|
+
margin-left: 4px;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
.example-pre :deep(.jv-children.jv-collapsed) {
|
|
1027
|
+
display: none;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
.example-pre :deep(.jv-children.jv-collapsed + .jv-ellipsis) {
|
|
1031
|
+
display: inline;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
.example-pre :deep(.jv-key) {
|
|
1035
|
+
color: var(--color-primary-dark);
|
|
1036
|
+
font-weight: 500;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
.example-pre :deep(.jv-punct) {
|
|
1040
|
+
color: var(--text-muted);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
.example-pre :deep(.jv-string) {
|
|
1044
|
+
color: var(--color-green);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
.example-pre :deep(.jv-number) {
|
|
1048
|
+
color: var(--color-orange);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
.example-pre :deep(.jv-boolean) {
|
|
1052
|
+
color: var(--color-accent);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
.example-pre :deep(.jv-null) {
|
|
1056
|
+
color: var(--text-muted);
|
|
1057
|
+
font-style: italic;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
.example-pre :deep(.jv-link) {
|
|
1061
|
+
color: var(--color-green);
|
|
1062
|
+
text-decoration: underline;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
.example-pre :deep(.jv-row:hover) {
|
|
1066
|
+
background: var(--bg-hover);
|
|
1067
|
+
border-radius: 2px;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
:root[data-theme="dark"] .example-pre :deep(.jv-key) { color: var(--color-primary-light); }
|
|
1071
|
+
:root[data-theme="dark"] .example-pre :deep(.jv-string) { color: var(--color-teal); }
|
|
1072
|
+
:root[data-theme="dark"] .example-pre :deep(.jv-number) { color: var(--color-accent-light); }
|
|
1073
|
+
:root[data-theme="dark"] .example-pre :deep(.jv-boolean) { color: var(--color-primary-light); }
|
|
1074
|
+
:root[data-theme="dark"] .example-pre :deep(.jv-toggle) { border-color: rgba(255, 255, 255, 0.2); }
|
|
1075
|
+
|
|
899
1076
|
.panel-content :deep(.md-code) {
|
|
900
1077
|
font-family: var(--font-mono);
|
|
901
1078
|
font-size: inherit;
|
|
@@ -914,6 +1091,37 @@ function navigateToProperty(name: string) {
|
|
|
914
1091
|
text-decoration: underline;
|
|
915
1092
|
}
|
|
916
1093
|
|
|
1094
|
+
.panel-content :deep(.md-heading) {
|
|
1095
|
+
font-weight: 600;
|
|
1096
|
+
margin: var(--space-2) 0 var(--space-1);
|
|
1097
|
+
color: var(--text-primary);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
.panel-content :deep(.md-list) {
|
|
1101
|
+
margin: var(--space-1) 0;
|
|
1102
|
+
padding-left: var(--space-5);
|
|
1103
|
+
font-size: inherit;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
.panel-content :deep(.md-list li) {
|
|
1107
|
+
margin-bottom: 2px;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
.panel-content :deep(.md-pre) {
|
|
1111
|
+
background: var(--bg-secondary);
|
|
1112
|
+
border: 1px solid var(--border-light);
|
|
1113
|
+
border-radius: var(--radius-sm);
|
|
1114
|
+
padding: var(--space-2);
|
|
1115
|
+
margin: var(--space-2) 0;
|
|
1116
|
+
overflow-x: auto;
|
|
1117
|
+
font-size: var(--text-sm);
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
.panel-content :deep(.md-pre code) {
|
|
1121
|
+
font-family: var(--font-mono);
|
|
1122
|
+
font-size: inherit;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
917
1125
|
/* Dark mode overrides */
|
|
918
1126
|
:root[data-theme="dark"] .detail-panel {
|
|
919
1127
|
border-left: 1px solid rgba(255, 255, 255, 0.08);
|
|
@@ -33,9 +33,11 @@
|
|
|
33
33
|
:aria-label="`Include ${field.prop.name}`"
|
|
34
34
|
@change="toggleField(field, ($event.target as HTMLInputElement).checked)"
|
|
35
35
|
/>
|
|
36
|
-
<
|
|
36
|
+
<span class="field-bullet" aria-hidden="true"></span>
|
|
37
|
+
<button class="field-name" :class="{ dimmed: !field.included, deprecated: field.prop.deprecated, expandable: !!field.resolvedDef }" :aria-label="field.resolvedDef ? `${field.expanded ? 'Collapse' : 'Expand'} ${field.prop.name}` : `View details for ${field.prop.name}`" @click="field.resolvedDef && field.included ? (field.expanded = !field.expanded) : openPropertyDetail(field.prop)">
|
|
37
38
|
<span v-if="field.prop.title && field.prop.title !== field.prop.name" class="field-human-title">{{ field.prop.title }}</span>
|
|
38
39
|
<span class="font-mono">{{ field.prop.name }}</span>
|
|
40
|
+
<span v-if="field.resolvedDef" class="field-expand-icon" :class="{ expanded: field.expanded }">▶</span>
|
|
39
41
|
</button>
|
|
40
42
|
<span class="field-type-badge" :class="typeBadgeClass(field.prop)">{{ displayType(field.prop, field.resolvedDef?.title || field.resolvedDef?.name) }}</span>
|
|
41
43
|
<span v-if="field.prop.title && field.prop.title !== field.prop.name" class="field-title-badge">{{ field.prop.title }}</span>
|
|
@@ -247,7 +249,7 @@
|
|
|
247
249
|
</button>
|
|
248
250
|
</div>
|
|
249
251
|
</div>
|
|
250
|
-
<pre ref="jsonBlockRef" class="json-block" @click="handleJsonClick" @dblclick="selectJsonBlock" v-html="highlightedJson"></pre>
|
|
252
|
+
<pre ref="jsonBlockRef" class="json-block" @click="handleJsonClick" @keydown="handleJsonKey" @dblclick="selectJsonBlock" v-html="highlightedJson"></pre>
|
|
251
253
|
<div v-if="!hasIncludedFields" class="json-empty-hint">
|
|
252
254
|
<span class="text-muted">Check fields to build JSON</span>
|
|
253
255
|
</div>
|
|
@@ -433,6 +435,19 @@ function collapseAllJson() {
|
|
|
433
435
|
function handleJsonClick(event: MouseEvent) {
|
|
434
436
|
const target = event.target as HTMLElement
|
|
435
437
|
if (!target.classList.contains('jv-toggle')) return
|
|
438
|
+
toggleJsonNode(target)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function handleJsonKey(event: KeyboardEvent) {
|
|
442
|
+
const target = event.target as HTMLElement
|
|
443
|
+
if (!target.classList.contains('jv-toggle')) return
|
|
444
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
445
|
+
event.preventDefault()
|
|
446
|
+
toggleJsonNode(target)
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function toggleJsonNode(target: HTMLElement) {
|
|
436
451
|
const parent = target.parentElement
|
|
437
452
|
if (!parent) return
|
|
438
453
|
const children = parent.querySelector('.jv-children')
|
|
@@ -628,6 +643,23 @@ async function copyJson() {
|
|
|
628
643
|
cursor: default;
|
|
629
644
|
}
|
|
630
645
|
|
|
646
|
+
.field-bullet {
|
|
647
|
+
width: 4px;
|
|
648
|
+
height: 4px;
|
|
649
|
+
border-radius: 50%;
|
|
650
|
+
background: var(--border-medium);
|
|
651
|
+
flex-shrink: 0;
|
|
652
|
+
margin-left: -2px;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.field-bullet + .field-name.dimmed {
|
|
656
|
+
opacity: 0.35;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
.field-bullet + .field-name.dimmed + .field-bullet {
|
|
660
|
+
opacity: 0.35;
|
|
661
|
+
}
|
|
662
|
+
|
|
631
663
|
.field-name {
|
|
632
664
|
font-weight: 600;
|
|
633
665
|
font-size: var(--text-sm);
|
|
@@ -666,6 +698,21 @@ async function copyJson() {
|
|
|
666
698
|
opacity: 0.7;
|
|
667
699
|
}
|
|
668
700
|
|
|
701
|
+
.field-name.expandable .font-mono:hover {
|
|
702
|
+
color: var(--color-primary);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
.field-expand-icon {
|
|
706
|
+
font-size: 8px;
|
|
707
|
+
color: var(--text-muted);
|
|
708
|
+
transition: transform var(--transition-fast);
|
|
709
|
+
margin-left: 2px;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.field-expand-icon.expanded {
|
|
713
|
+
transform: rotate(90deg);
|
|
714
|
+
}
|
|
715
|
+
|
|
669
716
|
.field-type-badge {
|
|
670
717
|
font-size: 11px;
|
|
671
718
|
font-weight: 500;
|
|
@@ -937,6 +984,38 @@ async function copyJson() {
|
|
|
937
984
|
text-decoration: underline;
|
|
938
985
|
}
|
|
939
986
|
|
|
987
|
+
.field-desc :deep(.md-heading) {
|
|
988
|
+
font-weight: 600;
|
|
989
|
+
margin: var(--space-2) 0 var(--space-1);
|
|
990
|
+
color: var(--text-primary);
|
|
991
|
+
font-size: inherit;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
.field-desc :deep(.md-list) {
|
|
995
|
+
margin: var(--space-1) 0;
|
|
996
|
+
padding-left: var(--space-5);
|
|
997
|
+
font-size: inherit;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
.field-desc :deep(.md-list li) {
|
|
1001
|
+
margin-bottom: 2px;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
.field-desc :deep(.md-pre) {
|
|
1005
|
+
background: var(--bg-secondary);
|
|
1006
|
+
border: 1px solid var(--border-light);
|
|
1007
|
+
border-radius: var(--radius-sm);
|
|
1008
|
+
padding: var(--space-2);
|
|
1009
|
+
margin: var(--space-2) 0;
|
|
1010
|
+
overflow-x: auto;
|
|
1011
|
+
font-size: var(--text-xs);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
.field-desc :deep(.md-pre code) {
|
|
1015
|
+
font-family: var(--font-mono);
|
|
1016
|
+
font-size: inherit;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
940
1019
|
.field-constraints {
|
|
941
1020
|
display: flex;
|
|
942
1021
|
flex-wrap: wrap;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Lightweight inline Markdown renderer for schema descriptions.
|
|
3
|
-
* Handles: **bold**, *italic*, `code`, [link](url), ```fenced code blocks
|
|
3
|
+
* Handles: **bold**, *italic*, `code`, [link](url), ```fenced code blocks```,
|
|
4
|
+
* bullet lists (-, *, +), numbered lists (1.), headings (###).
|
|
4
5
|
*/
|
|
5
6
|
export function renderInlineMarkdown(text: string): string {
|
|
6
7
|
if (!text) return ''
|
|
@@ -8,12 +9,82 @@ export function renderInlineMarkdown(text: string): string {
|
|
|
8
9
|
|
|
9
10
|
// Fenced code blocks: ```lang\n...\n``` (must run before inline code)
|
|
10
11
|
html = html.replace(/```[\w]*\n([\s\S]*?)```/g, (_match, code: string) => {
|
|
11
|
-
return
|
|
12
|
+
return `\x00FENCED${code.trim()}\x00ENDFENCED`
|
|
12
13
|
})
|
|
13
14
|
|
|
14
|
-
//
|
|
15
|
+
// Split into lines for block-level processing
|
|
16
|
+
const lines = html.split('\n')
|
|
17
|
+
const result: string[] = []
|
|
18
|
+
let inUl = false
|
|
19
|
+
let inOl = false
|
|
20
|
+
|
|
21
|
+
for (let i = 0; i < lines.length; i++) {
|
|
22
|
+
const line = lines[i]
|
|
23
|
+
|
|
24
|
+
// Skip fenced code block internals (already escaped)
|
|
25
|
+
if (line.includes('\x00FENCED') || line.includes('\x00ENDFENCED')) {
|
|
26
|
+
if (inUl) { result.push('</ul>'); inUl = false }
|
|
27
|
+
if (inOl) { result.push('</ol>'); inOl = false }
|
|
28
|
+
result.push(line)
|
|
29
|
+
continue
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Heading: ### text
|
|
33
|
+
const headingMatch = line.match(/^(#{1,4})\s+(.+)$/)
|
|
34
|
+
if (headingMatch) {
|
|
35
|
+
if (inUl) { result.push('</ul>'); inUl = false }
|
|
36
|
+
if (inOl) { result.push('</ol>'); inOl = false }
|
|
37
|
+
const level = headingMatch[1].length
|
|
38
|
+
result.push(`<h${level + 2} class="md-heading">${headingMatch[2]}</h${level + 2}>`)
|
|
39
|
+
continue
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Bullet list: -, *, + followed by space
|
|
43
|
+
const ulMatch = line.match(/^(\s*)([-*+])\s+(.+)$/)
|
|
44
|
+
if (ulMatch) {
|
|
45
|
+
if (inOl) { result.push('</ol>'); inOl = false }
|
|
46
|
+
if (!inUl) { result.push('<ul class="md-list">'); inUl = true }
|
|
47
|
+
result.push(`<li>${applyInline(ulMatch[3])}</li>`)
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Numbered list: 1. text
|
|
52
|
+
const olMatch = line.match(/^(\s*)\d+\.\s+(.+)$/)
|
|
53
|
+
if (olMatch) {
|
|
54
|
+
if (inUl) { result.push('</ul>'); inUl = false }
|
|
55
|
+
if (!inOl) { result.push('<ol class="md-list">'); inOl = true }
|
|
56
|
+
result.push(`<li>${applyInline(olMatch[2])}</li>`)
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Close list if non-list line encountered
|
|
61
|
+
if (inUl) { result.push('</ul>'); inUl = false }
|
|
62
|
+
if (inOl) { result.push('</ol>'); inOl = false }
|
|
63
|
+
|
|
64
|
+
// Regular line
|
|
65
|
+
result.push(line)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (inUl) result.push('</ul>')
|
|
69
|
+
if (inOl) result.push('</ol>')
|
|
70
|
+
|
|
71
|
+
html = result.join('\n')
|
|
72
|
+
|
|
73
|
+
// Restore fenced code blocks
|
|
74
|
+
html = html.replace(/\x00FENCED([\s\S]*?)\x00ENDFENCED/g, (_match, code: string) => {
|
|
75
|
+
return `<pre class="md-pre"><code>${code}</code></pre>`
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// Line breaks: \n → <br> (after block elements are formed)
|
|
15
79
|
html = html.replace(/\n/g, '<br>')
|
|
16
80
|
|
|
81
|
+
// Apply inline formatting to the whole output
|
|
82
|
+
html = applyInline(html)
|
|
83
|
+
|
|
84
|
+
return html
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function applyInline(html: string): string {
|
|
17
88
|
// Links: [text](url)
|
|
18
89
|
html = html.replace(
|
|
19
90
|
/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
@@ -27,7 +98,6 @@ export function renderInlineMarkdown(text: string): string {
|
|
|
27
98
|
html = html.replace(/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g, '<em>$1</em>')
|
|
28
99
|
// Code: `text`
|
|
29
100
|
html = html.replace(/`([^`]+)`/g, '<code class="md-code">$1</code>')
|
|
30
|
-
|
|
31
101
|
return html
|
|
32
102
|
}
|
|
33
103
|
|
|
@@ -187,15 +187,18 @@
|
|
|
187
187
|
<div v-if="viewMode === 'source'" class="schema-section">
|
|
188
188
|
<div v-if="schemaStore.selectedSchema.sourceJson" class="source-viewer">
|
|
189
189
|
<div class="source-toolbar">
|
|
190
|
-
<span class="text-muted">
|
|
191
|
-
<
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
190
|
+
<span class="text-muted">Source JSON Schema</span>
|
|
191
|
+
<div class="source-toolbar-actions">
|
|
192
|
+
<button class="btn btn-ghost btn-sm copy-btn-wrap" @click="copySource">
|
|
193
|
+
Copy
|
|
194
|
+
<span v-if="sourceCopied" class="copy-tooltip">Copied!</span>
|
|
195
|
+
</button>
|
|
196
|
+
<button class="btn btn-ghost btn-sm" @click="expandSourceAll">Expand all</button>
|
|
197
|
+
<button class="btn btn-ghost btn-sm" @click="collapseSourceAll">Collapse all</button>
|
|
198
|
+
</div>
|
|
195
199
|
</div>
|
|
196
200
|
<div class="source-code-wrapper">
|
|
197
|
-
<
|
|
198
|
-
<pre class="source-pre" @dblclick="selectSourceBlock"><code v-html="highlightedSource"></code></pre>
|
|
201
|
+
<pre ref="sourcePreRef" class="source-pre" @click="handleSourceClick" @keydown="handleSourceKey" @dblclick="selectSourceBlock"><code v-html="highlightedSource"></code></pre>
|
|
199
202
|
</div>
|
|
200
203
|
</div>
|
|
201
204
|
<div v-else class="source-empty">
|
|
@@ -208,7 +211,10 @@
|
|
|
208
211
|
<div v-else class="landing-page">
|
|
209
212
|
<div class="landing-header">
|
|
210
213
|
<div>
|
|
211
|
-
<
|
|
214
|
+
<div class="landing-title-row">
|
|
215
|
+
<h1>{{ schemaStore.metadata?.title || 'JSON Schema Documentation' }}</h1>
|
|
216
|
+
<span v-if="schemaStore.metadata?.version" class="version-badge">v{{ schemaStore.metadata.version }}</span>
|
|
217
|
+
</div>
|
|
212
218
|
<p v-if="schemaStore.metadata?.description" class="landing-description">{{ schemaStore.metadata.description }}</p>
|
|
213
219
|
<div class="landing-subtitle">
|
|
214
220
|
<span>{{ schemaStore.schemaCounts.schemas }} schemas</span>
|
|
@@ -216,6 +222,10 @@
|
|
|
216
222
|
<span>{{ schemaStore.schemaCounts.properties }} properties</span>
|
|
217
223
|
<span class="separator">·</span>
|
|
218
224
|
<span>{{ schemaStore.schemaCounts.definitions }} definitions</span>
|
|
225
|
+
<template v-if="schemaStore.metadata?.baseUrl">
|
|
226
|
+
<span class="separator">·</span>
|
|
227
|
+
<a :href="schemaStore.metadata.baseUrl" target="_blank" rel="noopener" class="landing-base-url">{{ schemaStore.metadata.baseUrl }}</a>
|
|
228
|
+
</template>
|
|
219
229
|
</div>
|
|
220
230
|
<div v-if="schemaStore.schemas.length > 3" class="landing-search">
|
|
221
231
|
<input
|
|
@@ -294,6 +304,7 @@ import { useUiStore } from '../stores/uiStore'
|
|
|
294
304
|
import SchemaBuilder from '../components/SchemaBuilder.vue'
|
|
295
305
|
import { downloadFile } from '../composables/useDownload'
|
|
296
306
|
import { renderInlineMarkdown } from '../composables/useMarkdownLite'
|
|
307
|
+
import { jsonToCollapsibleHtml } from '../composables/useJsonViewer'
|
|
297
308
|
import { copyToClipboard } from '../composables/useClipboard'
|
|
298
309
|
import type { SpaSchema, SpaProperty } from '../types'
|
|
299
310
|
|
|
@@ -305,6 +316,7 @@ const sourceCopied = ref(false)
|
|
|
305
316
|
const activeSourceLine = ref(-1)
|
|
306
317
|
const landingSearch = ref('')
|
|
307
318
|
const linkCopied = ref(false)
|
|
319
|
+
const sourcePreRef = ref<HTMLElement | null>(null)
|
|
308
320
|
|
|
309
321
|
const selectedDefinitionTitle = computed(() => {
|
|
310
322
|
const name = schemaStore.selectedDefinitionName
|
|
@@ -348,7 +360,11 @@ function collapseAllDefs() {
|
|
|
348
360
|
const highlightedSource = computed(() => {
|
|
349
361
|
const src = schemaStore.selectedSchema?.sourceJson
|
|
350
362
|
if (!src) return ''
|
|
351
|
-
|
|
363
|
+
try {
|
|
364
|
+
return jsonToCollapsibleHtml(JSON.parse(src), 2)
|
|
365
|
+
} catch {
|
|
366
|
+
return syntaxHighlight(src)
|
|
367
|
+
}
|
|
352
368
|
})
|
|
353
369
|
|
|
354
370
|
const sourceLineCount = computed(() => {
|
|
@@ -392,7 +408,7 @@ function syntaxHighlight(json: string): string {
|
|
|
392
408
|
}
|
|
393
409
|
|
|
394
410
|
function selectSourceBlock() {
|
|
395
|
-
const el =
|
|
411
|
+
const el = sourcePreRef.value
|
|
396
412
|
if (!el) return
|
|
397
413
|
const range = document.createRange()
|
|
398
414
|
range.selectNodeContents(el)
|
|
@@ -403,6 +419,57 @@ function selectSourceBlock() {
|
|
|
403
419
|
}
|
|
404
420
|
}
|
|
405
421
|
|
|
422
|
+
function handleSourceClick(event: MouseEvent) {
|
|
423
|
+
const target = event.target as HTMLElement
|
|
424
|
+
if (!target.classList.contains('jv-toggle')) return
|
|
425
|
+
toggleSourceNode(target)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function handleSourceKey(event: KeyboardEvent) {
|
|
429
|
+
const target = event.target as HTMLElement
|
|
430
|
+
if (!target.classList.contains('jv-toggle')) return
|
|
431
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
432
|
+
event.preventDefault()
|
|
433
|
+
toggleSourceNode(target)
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function toggleSourceNode(target: HTMLElement) {
|
|
438
|
+
const parent = target.parentElement
|
|
439
|
+
if (!parent) return
|
|
440
|
+
const children = parent.querySelector('.jv-children')
|
|
441
|
+
if (!children) return
|
|
442
|
+
const isCollapsed = children.classList.contains('jv-collapsed')
|
|
443
|
+
if (isCollapsed) {
|
|
444
|
+
children.classList.remove('jv-collapsed')
|
|
445
|
+
target.setAttribute('aria-label', 'collapse')
|
|
446
|
+
} else {
|
|
447
|
+
children.classList.add('jv-collapsed')
|
|
448
|
+
target.setAttribute('aria-label', 'expand')
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function expandSourceAll() {
|
|
453
|
+
const container = sourcePreRef.value
|
|
454
|
+
if (!container) return
|
|
455
|
+
container.querySelectorAll('.jv-collapsed').forEach(el => el.classList.remove('jv-collapsed'))
|
|
456
|
+
container.querySelectorAll('.jv-toggle').forEach(btn => btn.setAttribute('aria-label', 'collapse'))
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function collapseSourceAll() {
|
|
460
|
+
const container = sourcePreRef.value
|
|
461
|
+
if (!container) return
|
|
462
|
+
const children = container.querySelectorAll('.jv-children')
|
|
463
|
+
children.forEach((el, i) => {
|
|
464
|
+
if (i === 0) return
|
|
465
|
+
el.classList.add('jv-collapsed')
|
|
466
|
+
})
|
|
467
|
+
container.querySelectorAll('.jv-toggle').forEach((btn, i) => {
|
|
468
|
+
if (i === 0) return
|
|
469
|
+
btn.setAttribute('aria-label', 'expand')
|
|
470
|
+
})
|
|
471
|
+
}
|
|
472
|
+
|
|
406
473
|
function selectSchema(name: string) {
|
|
407
474
|
schemaStore.selectSchema(name)
|
|
408
475
|
}
|
|
@@ -814,6 +881,11 @@ watch(() => schemaStore.selectedItemKey, (key) => {
|
|
|
814
881
|
font-size: var(--text-xs);
|
|
815
882
|
}
|
|
816
883
|
|
|
884
|
+
.source-toolbar-actions {
|
|
885
|
+
display: flex;
|
|
886
|
+
gap: var(--space-2);
|
|
887
|
+
}
|
|
888
|
+
|
|
817
889
|
/* Copy button tooltip */
|
|
818
890
|
.copy-btn-wrap {
|
|
819
891
|
position: relative;
|
|
@@ -852,56 +924,112 @@ watch(() => schemaStore.selectedItemKey, (key) => {
|
|
|
852
924
|
}
|
|
853
925
|
|
|
854
926
|
.source-code-wrapper {
|
|
855
|
-
display: flex;
|
|
856
927
|
max-height: 70vh;
|
|
857
928
|
overflow: auto;
|
|
858
929
|
}
|
|
859
930
|
|
|
860
|
-
.source-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
931
|
+
.source-pre :deep(.json-key) { color: var(--color-primary-dark); }
|
|
932
|
+
.source-pre :deep(.json-string) { color: var(--color-green); }
|
|
933
|
+
.source-pre :deep(.json-number) { color: var(--color-orange); }
|
|
934
|
+
.source-pre :deep(.json-boolean) { color: var(--color-accent); }
|
|
935
|
+
.source-pre :deep(.json-null) { color: var(--text-muted); }
|
|
936
|
+
|
|
937
|
+
.source-pre :deep(.json-url) {
|
|
938
|
+
color: var(--color-green);
|
|
939
|
+
text-decoration: underline;
|
|
940
|
+
text-decoration-style: dotted;
|
|
941
|
+
}
|
|
942
|
+
.source-pre :deep(.json-url:hover) {
|
|
943
|
+
text-decoration-style: solid;
|
|
869
944
|
}
|
|
870
945
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
946
|
+
/* Collapsible JSON in source viewer */
|
|
947
|
+
.source-pre :deep(ul) {
|
|
948
|
+
list-style: none;
|
|
949
|
+
padding-left: var(--space-4);
|
|
950
|
+
margin: 0;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.source-pre :deep(li) {
|
|
954
|
+
margin: 0;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
.source-pre :deep(.jv-toggle) {
|
|
958
|
+
background: none;
|
|
959
|
+
border: 1px solid var(--border-medium);
|
|
960
|
+
border-radius: 2px;
|
|
961
|
+
cursor: pointer;
|
|
962
|
+
width: 14px;
|
|
963
|
+
height: 14px;
|
|
964
|
+
font-size: 9px;
|
|
965
|
+
line-height: 1;
|
|
966
|
+
display: inline-flex;
|
|
967
|
+
align-items: center;
|
|
968
|
+
justify-content: center;
|
|
875
969
|
color: var(--text-muted);
|
|
876
|
-
|
|
877
|
-
|
|
970
|
+
padding: 0;
|
|
971
|
+
margin-right: 4px;
|
|
972
|
+
vertical-align: middle;
|
|
973
|
+
transition: background var(--transition-fast);
|
|
878
974
|
}
|
|
879
975
|
|
|
880
|
-
.source-
|
|
976
|
+
.source-pre :deep(.jv-toggle:hover) {
|
|
881
977
|
background: var(--bg-hover);
|
|
882
|
-
border-radius: 2px;
|
|
883
978
|
}
|
|
884
979
|
|
|
885
|
-
.source-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
980
|
+
.source-pre :deep(.jv-toggle[aria-label="expand"])::after { content: '+'; }
|
|
981
|
+
.source-pre :deep(.jv-toggle[aria-label="collapse"])::after { content: '−'; }
|
|
982
|
+
|
|
983
|
+
.source-pre :deep(.jv-ellipsis) {
|
|
984
|
+
display: none;
|
|
985
|
+
color: var(--text-muted);
|
|
986
|
+
font-size: var(--text-xs);
|
|
987
|
+
font-style: italic;
|
|
988
|
+
margin-left: 4px;
|
|
890
989
|
}
|
|
891
990
|
|
|
892
|
-
.source-pre :deep(.
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
.source-pre :deep(.json-boolean) { color: var(--color-accent); }
|
|
896
|
-
.source-pre :deep(.json-null) { color: var(--text-muted); }
|
|
991
|
+
.source-pre :deep(.jv-children.jv-collapsed) {
|
|
992
|
+
display: none;
|
|
993
|
+
}
|
|
897
994
|
|
|
898
|
-
.source-pre :deep(.
|
|
995
|
+
.source-pre :deep(.jv-children.jv-collapsed + .jv-ellipsis) {
|
|
996
|
+
display: inline;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
.source-pre :deep(.jv-key) {
|
|
1000
|
+
color: var(--color-primary-dark);
|
|
1001
|
+
font-weight: 500;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
.source-pre :deep(.jv-punct) {
|
|
1005
|
+
color: var(--text-muted);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
.source-pre :deep(.jv-string) {
|
|
1009
|
+
color: var(--color-green);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
.source-pre :deep(.jv-number) {
|
|
1013
|
+
color: var(--color-orange);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
.source-pre :deep(.jv-boolean) {
|
|
1017
|
+
color: var(--color-accent);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
.source-pre :deep(.jv-null) {
|
|
1021
|
+
color: var(--text-muted);
|
|
1022
|
+
font-style: italic;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
.source-pre :deep(.jv-link) {
|
|
899
1026
|
color: var(--color-green);
|
|
900
1027
|
text-decoration: underline;
|
|
901
|
-
text-decoration-style: dotted;
|
|
902
1028
|
}
|
|
903
|
-
|
|
904
|
-
|
|
1029
|
+
|
|
1030
|
+
.source-pre :deep(.jv-row:hover) {
|
|
1031
|
+
background: var(--bg-hover);
|
|
1032
|
+
border-radius: 2px;
|
|
905
1033
|
}
|
|
906
1034
|
|
|
907
1035
|
:root[data-theme="dark"] .source-pre :deep(.json-key) { color: var(--color-primary-light); }
|
|
@@ -910,23 +1038,18 @@ watch(() => schemaStore.selectedItemKey, (key) => {
|
|
|
910
1038
|
:root[data-theme="dark"] .source-pre :deep(.json-boolean) { color: var(--color-primary-light); }
|
|
911
1039
|
:root[data-theme="dark"] .source-pre :deep(.json-null) { color: var(--text-muted); }
|
|
912
1040
|
|
|
1041
|
+
:root[data-theme="dark"] .source-pre :deep(.jv-key) { color: var(--color-primary-light); }
|
|
1042
|
+
:root[data-theme="dark"] .source-pre :deep(.jv-string) { color: var(--color-teal); }
|
|
1043
|
+
:root[data-theme="dark"] .source-pre :deep(.jv-number) { color: var(--color-accent-light); }
|
|
1044
|
+
:root[data-theme="dark"] .source-pre :deep(.jv-boolean) { color: var(--color-primary-light); }
|
|
1045
|
+
:root[data-theme="dark"] .source-pre :deep(.jv-null) { color: var(--text-muted); }
|
|
1046
|
+
:root[data-theme="dark"] .source-pre :deep(.jv-toggle) { border-color: rgba(255, 255, 255, 0.2); }
|
|
1047
|
+
:root[data-theme="dark"] .source-pre :deep(.jv-punct) { color: var(--panel-dark-muted); }
|
|
1048
|
+
:root[data-theme="dark"] .source-pre :deep(.jv-row:hover) { background: rgba(255, 255, 255, 0.06); }
|
|
1049
|
+
|
|
913
1050
|
:root[data-theme="dark"] .source-code-wrapper {
|
|
914
1051
|
background: var(--panel-dark-bg);
|
|
915
1052
|
}
|
|
916
|
-
:root[data-theme="dark"] .source-lines {
|
|
917
|
-
background: rgba(0, 0, 0, 0.15);
|
|
918
|
-
border-right-color: rgba(255, 255, 255, 0.08);
|
|
919
|
-
}
|
|
920
|
-
:root[data-theme="dark"] .source-lines span {
|
|
921
|
-
color: var(--panel-dark-muted);
|
|
922
|
-
}
|
|
923
|
-
:root[data-theme="dark"] .source-lines span:hover {
|
|
924
|
-
background: rgba(255, 255, 255, 0.06);
|
|
925
|
-
}
|
|
926
|
-
:root[data-theme="dark"] .source-lines span.source-line-active {
|
|
927
|
-
background: rgba(91, 156, 212, 0.2);
|
|
928
|
-
color: var(--color-primary-light);
|
|
929
|
-
}
|
|
930
1053
|
:root[data-theme="dark"] .source-pre {
|
|
931
1054
|
color: var(--panel-dark-text);
|
|
932
1055
|
}
|
|
@@ -1039,6 +1162,48 @@ watch(() => schemaStore.selectedItemKey, (key) => {
|
|
|
1039
1162
|
text-decoration: underline;
|
|
1040
1163
|
}
|
|
1041
1164
|
|
|
1165
|
+
.def-card-desc :deep(.md-heading),
|
|
1166
|
+
.def-body-desc :deep(.md-heading),
|
|
1167
|
+
.schema-desc :deep(.md-heading) {
|
|
1168
|
+
font-weight: 600;
|
|
1169
|
+
margin: var(--space-2) 0 var(--space-1);
|
|
1170
|
+
color: var(--text-primary);
|
|
1171
|
+
font-size: inherit;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
.def-card-desc :deep(.md-list),
|
|
1175
|
+
.def-body-desc :deep(.md-list),
|
|
1176
|
+
.schema-desc :deep(.md-list) {
|
|
1177
|
+
margin: var(--space-1) 0;
|
|
1178
|
+
padding-left: var(--space-5);
|
|
1179
|
+
font-size: inherit;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
.def-card-desc :deep(.md-list li),
|
|
1183
|
+
.def-body-desc :deep(.md-list li),
|
|
1184
|
+
.schema-desc :deep(.md-list li) {
|
|
1185
|
+
margin-bottom: 2px;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
.def-card-desc :deep(.md-pre),
|
|
1189
|
+
.def-body-desc :deep(.md-pre),
|
|
1190
|
+
.schema-desc :deep(.md-pre) {
|
|
1191
|
+
background: var(--bg-secondary);
|
|
1192
|
+
border: 1px solid var(--border-light);
|
|
1193
|
+
border-radius: var(--radius-sm);
|
|
1194
|
+
padding: var(--space-2);
|
|
1195
|
+
margin: var(--space-2) 0;
|
|
1196
|
+
overflow-x: auto;
|
|
1197
|
+
font-size: var(--text-xs);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
.def-card-desc :deep(.md-pre code),
|
|
1201
|
+
.def-body-desc :deep(.md-pre code),
|
|
1202
|
+
.schema-desc :deep(.md-pre code) {
|
|
1203
|
+
font-family: var(--font-mono);
|
|
1204
|
+
font-size: inherit;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1042
1207
|
.def-card-info {
|
|
1043
1208
|
padding: 0 var(--space-4) var(--space-3);
|
|
1044
1209
|
margin-top: calc(var(--space-1) * -1);
|
|
@@ -1349,6 +1514,27 @@ watch(() => schemaStore.selectedItemKey, (key) => {
|
|
|
1349
1514
|
margin-bottom: var(--space-2);
|
|
1350
1515
|
}
|
|
1351
1516
|
|
|
1517
|
+
.landing-title-row {
|
|
1518
|
+
display: flex;
|
|
1519
|
+
align-items: center;
|
|
1520
|
+
gap: var(--space-3);
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
.landing-title-row h1 {
|
|
1524
|
+
margin-bottom: 0;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
.version-badge {
|
|
1528
|
+
font-size: var(--text-sm);
|
|
1529
|
+
font-weight: 500;
|
|
1530
|
+
color: var(--text-muted);
|
|
1531
|
+
background: var(--bg-secondary);
|
|
1532
|
+
padding: 2px 8px;
|
|
1533
|
+
border-radius: var(--radius-md);
|
|
1534
|
+
border: 1px solid var(--border-light);
|
|
1535
|
+
font-family: var(--font-mono);
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1352
1538
|
.landing-description {
|
|
1353
1539
|
font-size: var(--text-base);
|
|
1354
1540
|
color: var(--text-secondary);
|
|
@@ -1411,6 +1597,17 @@ watch(() => schemaStore.selectedItemKey, (key) => {
|
|
|
1411
1597
|
margin: 0 var(--space-1);
|
|
1412
1598
|
}
|
|
1413
1599
|
|
|
1600
|
+
.landing-base-url {
|
|
1601
|
+
color: var(--color-primary);
|
|
1602
|
+
text-decoration: none;
|
|
1603
|
+
font-size: var(--text-sm);
|
|
1604
|
+
font-family: var(--font-mono);
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
.landing-base-url:hover {
|
|
1608
|
+
text-decoration: underline;
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1414
1611
|
.schema-grid {
|
|
1415
1612
|
display: grid;
|
|
1416
1613
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
@@ -1484,6 +1681,16 @@ watch(() => schemaStore.selectedItemKey, (key) => {
|
|
|
1484
1681
|
text-decoration: underline;
|
|
1485
1682
|
}
|
|
1486
1683
|
|
|
1684
|
+
.schema-card-desc :deep(.md-list) {
|
|
1685
|
+
margin: var(--space-1) 0;
|
|
1686
|
+
padding-left: var(--space-5);
|
|
1687
|
+
font-size: inherit;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
.schema-card-desc :deep(.md-pre) {
|
|
1691
|
+
display: none;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1487
1694
|
.schema-card-meta {
|
|
1488
1695
|
margin-bottom: var(--space-2);
|
|
1489
1696
|
}
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lutaml-jsonschema
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: json
|