@mongoosejs/studio 0.1.16 → 0.1.17

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.
@@ -631,6 +631,14 @@ video {
631
631
  bottom: 0px;
632
632
  }
633
633
 
634
+ .-left-2 {
635
+ left: -0.5rem;
636
+ }
637
+
638
+ .-left-3 {
639
+ left: -0.75rem;
640
+ }
641
+
634
642
  .left-0 {
635
643
  left: 0px;
636
644
  }
@@ -659,6 +667,10 @@ video {
659
667
  top: 0.25rem;
660
668
  }
661
669
 
670
+ .top-1\/2 {
671
+ top: 50%;
672
+ }
673
+
662
674
  .top-2 {
663
675
  top: 0.5rem;
664
676
  }
@@ -769,6 +781,10 @@ video {
769
781
  margin-bottom: 0.25rem;
770
782
  }
771
783
 
784
+ .mb-1\.5 {
785
+ margin-bottom: 0.375rem;
786
+ }
787
+
772
788
  .mb-2 {
773
789
  margin-bottom: 0.5rem;
774
790
  }
@@ -984,6 +1000,10 @@ video {
984
1000
  max-height: 50vh;
985
1001
  }
986
1002
 
1003
+ .max-h-\[6\.5em\] {
1004
+ max-height: 6.5em;
1005
+ }
1006
+
987
1007
  .min-h-0 {
988
1008
  min-height: 0px;
989
1009
  }
@@ -1072,6 +1092,10 @@ video {
1072
1092
  min-width: 140px;
1073
1093
  }
1074
1094
 
1095
+ .min-w-\[80px\] {
1096
+ min-width: 80px;
1097
+ }
1098
+
1075
1099
  .min-w-full {
1076
1100
  min-width: 100%;
1077
1101
  }
@@ -1080,6 +1104,10 @@ video {
1080
1104
  max-width: 64rem;
1081
1105
  }
1082
1106
 
1107
+ .max-w-\[30em\] {
1108
+ max-width: 30em;
1109
+ }
1110
+
1083
1111
  .max-w-\[calc\(100vw-3rem\)\] {
1084
1112
  max-width: calc(100vw - 3rem);
1085
1113
  }
@@ -1128,6 +1156,11 @@ video {
1128
1156
  transform-origin: top right;
1129
1157
  }
1130
1158
 
1159
+ .-translate-y-1\/2 {
1160
+ --tw-translate-y: -50%;
1161
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1162
+ }
1163
+
1131
1164
  .translate-x-0 {
1132
1165
  --tw-translate-x: 0px;
1133
1166
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@@ -1454,6 +1487,10 @@ video {
1454
1487
  border-bottom-width: 2px;
1455
1488
  }
1456
1489
 
1490
+ .border-l-\[3px\] {
1491
+ border-left-width: 3px;
1492
+ }
1493
+
1457
1494
  .border-r {
1458
1495
  border-right-width: 1px;
1459
1496
  }
@@ -1470,11 +1507,6 @@ video {
1470
1507
  border-style: none;
1471
1508
  }
1472
1509
 
1473
- .border-amber-400 {
1474
- --tw-border-opacity: 1;
1475
- border-color: rgb(251 191 36 / var(--tw-border-opacity));
1476
- }
1477
-
1478
1510
  .border-blue-300 {
1479
1511
  --tw-border-opacity: 1;
1480
1512
  border-color: rgb(147 197 253 / var(--tw-border-opacity));
@@ -1514,11 +1546,21 @@ video {
1514
1546
  border-color: rgb(63 83 255 / var(--tw-border-opacity));
1515
1547
  }
1516
1548
 
1549
+ .border-l-blue-500 {
1550
+ --tw-border-opacity: 1;
1551
+ border-left-color: rgb(59 130 246 / var(--tw-border-opacity));
1552
+ }
1553
+
1517
1554
  .bg-amber-100 {
1518
1555
  --tw-bg-opacity: 1;
1519
1556
  background-color: rgb(254 243 199 / var(--tw-bg-opacity));
1520
1557
  }
1521
1558
 
1559
+ .bg-amber-200 {
1560
+ --tw-bg-opacity: 1;
1561
+ background-color: rgb(253 230 138 / var(--tw-bg-opacity));
1562
+ }
1563
+
1522
1564
  .bg-black {
1523
1565
  --tw-bg-opacity: 1;
1524
1566
  background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@@ -1644,11 +1686,6 @@ video {
1644
1686
  background-color: rgb(220 38 38 / var(--tw-bg-opacity));
1645
1687
  }
1646
1688
 
1647
- .bg-slate-50 {
1648
- --tw-bg-opacity: 1;
1649
- background-color: rgb(248 250 252 / var(--tw-bg-opacity));
1650
- }
1651
-
1652
1689
  .bg-slate-500 {
1653
1690
  --tw-bg-opacity: 1;
1654
1691
  background-color: rgb(100 116 139 / var(--tw-bg-opacity));
@@ -1776,6 +1813,11 @@ video {
1776
1813
  padding-bottom: 0.5rem;
1777
1814
  }
1778
1815
 
1816
+ .py-2\.5 {
1817
+ padding-top: 0.625rem;
1818
+ padding-bottom: 0.625rem;
1819
+ }
1820
+
1779
1821
  .py-3 {
1780
1822
  padding-top: 0.75rem;
1781
1823
  padding-bottom: 0.75rem;
@@ -1890,6 +1932,10 @@ video {
1890
1932
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
1891
1933
  }
1892
1934
 
1935
+ .text-\[10px\] {
1936
+ font-size: 10px;
1937
+ }
1938
+
1893
1939
  .text-base {
1894
1940
  font-size: 1rem;
1895
1941
  line-height: 1.5rem;
@@ -2143,6 +2189,10 @@ video {
2143
2189
  opacity: 0.5;
2144
2190
  }
2145
2191
 
2192
+ .opacity-70 {
2193
+ opacity: 0.7;
2194
+ }
2195
+
2146
2196
  .opacity-75 {
2147
2197
  opacity: 0.75;
2148
2198
  }
@@ -2206,11 +2256,6 @@ video {
2206
2256
  --tw-ring-inset: inset;
2207
2257
  }
2208
2258
 
2209
- .ring-amber-200 {
2210
- --tw-ring-opacity: 1;
2211
- --tw-ring-color: rgb(253 230 138 / var(--tw-ring-opacity));
2212
- }
2213
-
2214
2259
  .ring-black {
2215
2260
  --tw-ring-opacity: 1;
2216
2261
  --tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity));
@@ -2241,10 +2286,6 @@ video {
2241
2286
  --tw-ring-opacity: 0.05;
2242
2287
  }
2243
2288
 
2244
- .ring-offset-1 {
2245
- --tw-ring-offset-width: 1px;
2246
- }
2247
-
2248
2289
  .filter {
2249
2290
  filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
2250
2291
  }
@@ -2307,6 +2348,10 @@ video {
2307
2348
  color: rgb(156 163 175 / var(--tw-text-opacity));
2308
2349
  }
2309
2350
 
2351
+ .last\:mb-0:last-child {
2352
+ margin-bottom: 0px;
2353
+ }
2354
+
2310
2355
  .focus-within\:ring-2:focus-within {
2311
2356
  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
2312
2357
  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@@ -2322,6 +2367,16 @@ video {
2322
2367
  --tw-ring-color: rgb(0 168 165 / var(--tw-ring-opacity));
2323
2368
  }
2324
2369
 
2370
+ .hover\:-translate-y-0:hover {
2371
+ --tw-translate-y: -0px;
2372
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
2373
+ }
2374
+
2375
+ .hover\:-translate-y-0\.5:hover {
2376
+ --tw-translate-y: -0.125rem;
2377
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
2378
+ }
2379
+
2325
2380
  .hover\:translate-x-0:hover {
2326
2381
  --tw-translate-x: 0px;
2327
2382
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@@ -2337,6 +2392,16 @@ video {
2337
2392
  border-color: rgb(209 213 219 / var(--tw-border-opacity));
2338
2393
  }
2339
2394
 
2395
+ .hover\:border-l-blue-600:hover {
2396
+ --tw-border-opacity: 1;
2397
+ border-left-color: rgb(37 99 235 / var(--tw-border-opacity));
2398
+ }
2399
+
2400
+ .hover\:bg-amber-200:hover {
2401
+ --tw-bg-opacity: 1;
2402
+ background-color: rgb(253 230 138 / var(--tw-bg-opacity));
2403
+ }
2404
+
2340
2405
  .hover\:bg-blue-600:hover {
2341
2406
  --tw-bg-opacity: 1;
2342
2407
  background-color: rgb(37 99 235 / var(--tw-bg-opacity));
@@ -2442,6 +2507,11 @@ video {
2442
2507
  background-color: rgb(148 163 184 / var(--tw-bg-opacity));
2443
2508
  }
2444
2509
 
2510
+ .hover\:bg-slate-50:hover {
2511
+ --tw-bg-opacity: 1;
2512
+ background-color: rgb(248 250 252 / var(--tw-bg-opacity));
2513
+ }
2514
+
2445
2515
  .hover\:bg-slate-500:hover {
2446
2516
  --tw-bg-opacity: 1;
2447
2517
  background-color: rgb(100 116 139 / var(--tw-bg-opacity));
@@ -2502,6 +2572,16 @@ video {
2502
2572
  color: rgb(6 14 172 / var(--tw-text-opacity));
2503
2573
  }
2504
2574
 
2575
+ .hover\:opacity-100:hover {
2576
+ opacity: 1;
2577
+ }
2578
+
2579
+ .hover\:shadow-lg:hover {
2580
+ --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
2581
+ --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
2582
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
2583
+ }
2584
+
2505
2585
  .focus\:z-10:focus {
2506
2586
  z-index: 10;
2507
2587
  }
@@ -0,0 +1,66 @@
1
+ 'use strict';
2
+
3
+ const { inspect } = require('node-inspect-extracted');
4
+
5
+ /**
6
+ * Format a value for display in array views
7
+ * @param {*} item - The item to format
8
+ * @returns {string} - Formatted string representation
9
+ */
10
+ function formatValue(item) {
11
+ if (item == null) {
12
+ return 'null';
13
+ }
14
+ if (typeof item === 'object') {
15
+ return inspect(item, { maxArrayLength: 50 });
16
+ }
17
+ return String(item);
18
+ }
19
+
20
+ /**
21
+ * Check if an item is a plain object (not array, not null)
22
+ * @param {*} item - The item to check
23
+ * @returns {boolean} - True if item is a plain object
24
+ */
25
+ function isObjectItem(item) {
26
+ return item != null && typeof item === 'object' && !Array.isArray(item) && item.constructor === Object;
27
+ }
28
+
29
+ /**
30
+ * Get the keys of an object item
31
+ * @param {*} item - The item to get keys from
32
+ * @returns {string[]} - Array of keys, or empty array if not an object
33
+ */
34
+ function getItemKeys(item) {
35
+ if (!isObjectItem(item)) {
36
+ return [];
37
+ }
38
+ return Object.keys(item);
39
+ }
40
+
41
+ /**
42
+ * Format a specific value from an object item by key
43
+ * @param {*} item - The object item
44
+ * @param {string} key - The key to get the value for
45
+ * @returns {string} - Formatted string representation of the value
46
+ */
47
+ function formatItemValue(item, key) {
48
+ const value = item[key];
49
+ if (value === null) {
50
+ return 'null';
51
+ }
52
+ if (value === undefined) {
53
+ return 'undefined';
54
+ }
55
+ if (typeof value === 'object') {
56
+ return inspect(value, { maxArrayLength: 50 });
57
+ }
58
+ return String(value);
59
+ }
60
+
61
+ module.exports = {
62
+ formatValue,
63
+ isObjectItem,
64
+ getItemKeys,
65
+ formatItemValue
66
+ };
@@ -141,5 +141,5 @@ module.exports = app => app.component('dashboard', {
141
141
  },
142
142
  beforeDestroy() {
143
143
  document.removeEventListener('click', this.handleDocumentClick);
144
- },
144
+ }
145
145
  });
@@ -1,3 +1,25 @@
1
- <div class="detail-array">
2
- <pre><code ref="code" class="language-javascript" v-text="displayValue"></code></pre>
3
- </div>
1
+ <div class="w-full">
2
+ <div v-if="!arrayValue || arrayValue.length === 0" class="text-gray-400 text-xs py-2 text-center">
3
+ Empty array
4
+ </div>
5
+
6
+ <div v-else class="mt-2">
7
+ <div
8
+ v-for="(item, index) in arrayValue"
9
+ :key="index"
10
+ :title="'Index: ' + index"
11
+ class="mb-1.5 last:mb-0 py-2.5 px-3 pl-4 bg-transparent border-l-[3px] border-l-blue-500 rounded-none transition-all duration-200 cursor-pointer relative hover:bg-slate-50 hover:border-l-blue-600 hover:shadow-lg hover:-translate-y-0.5">
12
+ <div class="absolute -left-3 top-1/2 -translate-y-1/2 w-5 h-5 bg-blue-500 text-white rounded-full flex items-center justify-center text-[10px] font-semibold font-mono z-10 hover:bg-blue-600">{{ index >= 1000 ? '1k+' : index }}</div>
13
+ <div v-if="arrayUtils.isObjectItem(item)" class="flex flex-col gap-1 mt-1 px-2">
14
+ <div
15
+ v-for="key in arrayUtils.getItemKeys(item)"
16
+ :key="key"
17
+ class="flex items-start gap-2 text-xs font-mono">
18
+ <span class="font-semibold text-gray-600 flex-shrink-0 min-w-[80px]">{{ key }}:</span>
19
+ <span class="text-gray-800 break-words whitespace-pre-wrap flex-1">{{ arrayUtils.formatItemValue(item, key) }}</span>
20
+ </div>
21
+ </div>
22
+ <div v-else class="text-xs py-1.5 px-2 font-mono text-gray-800 break-words whitespace-pre-wrap mt-1">{{ arrayUtils.formatValue(item) }}</div>
23
+ </div>
24
+ </div>
25
+ </div>
@@ -1,20 +1,36 @@
1
1
  'use strict';
2
2
 
3
3
  const template = require('./detail-array.html');
4
- const { inspect } = require('node-inspect-extracted');
5
4
 
6
5
  module.exports = app => app.component('detail-array', {
7
6
  template: template,
8
7
  props: ['value'],
9
- computed: {
10
- displayValue() {
8
+ data() {
9
+ return {
10
+ arrayValue: []
11
+ };
12
+ },
13
+ methods: {
14
+ initializeArray() {
11
15
  if (this.value == null) {
12
- return this.value;
16
+ this.arrayValue = [];
17
+ } else if (Array.isArray(this.value)) {
18
+ this.arrayValue = this.value;
19
+ } else {
20
+ this.arrayValue = [];
13
21
  }
14
- return inspect(this.value, { maxArrayLength: 50 });
15
22
  }
16
23
  },
17
24
  mounted() {
18
- Prism.highlightElement(this.$refs.code);
25
+ this.initializeArray();
26
+ },
27
+ watch: {
28
+ value: {
29
+ handler(newValue) {
30
+ this.initializeArray();
31
+ },
32
+ deep: true,
33
+ immediate: true
34
+ }
19
35
  }
20
36
  });
@@ -52,9 +52,9 @@
52
52
 
53
53
  <!-- Fields View -->
54
54
  <div v-if="viewMode === 'fields'">
55
- <!-- Schema Paths -->
55
+ <!-- Matched Schema Paths (shown first when searching) -->
56
56
  <div
57
- v-for="path in filteredSchemaPaths"
57
+ v-for="path in matchedSchemaPaths"
58
58
  :key="path.path || path"
59
59
  class="value"
60
60
  >
@@ -64,25 +64,74 @@
64
64
  :schemaPaths="schemaPaths"
65
65
  :editting="editting"
66
66
  :changes="changes"
67
- :highlight="isSchemaPathMatched(path)"
67
+ :highlight="true"
68
68
  :invalid="invalid"></document-property>
69
69
  </div>
70
70
 
71
- <!-- Virtual Fields -->
71
+ <!-- Matched Virtual Fields (shown after matched schema paths when searching) -->
72
72
  <div
73
- v-for="path in filteredVirtuals"
73
+ v-for="path in matchedVirtuals"
74
74
  :key="path.name"
75
- class="border rounded-lg mb-2 transition-all duration-200 ease-in-out"
76
- :class="[
77
- isVirtualMatched(path)
78
- ? 'border-amber-400 ring-2 ring-amber-200 ring-offset-1'
79
- : 'border-gray-200'
80
- ]"
75
+ class="border border-gray-200 rounded-lg mb-2 transition-all duration-200 ease-in-out mt-4"
81
76
  >
82
77
  <!-- Virtual Field Header (Always Visible) -->
83
78
  <div
84
79
  @click="toggleVirtualField(path.name)"
85
- class="p-3 bg-slate-50 hover:bg-slate-100 cursor-pointer flex items-center justify-between border-b border-gray-200"
80
+ class="p-3 bg-amber-100 hover:bg-amber-200 cursor-pointer flex items-center justify-between border-b border-gray-200 transition-colors duration-200 ease-in-out"
81
+ >
82
+ <div class="flex items-center">
83
+ <svg
84
+ :class="isVirtualFieldCollapsed(path.name) ? 'rotate-0' : 'rotate-90'"
85
+ class="w-4 h-4 text-gray-500 mr-2 transition-transform duration-200"
86
+ fill="none"
87
+ stroke="currentColor"
88
+ viewBox="0 0 24 24"
89
+ >
90
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
91
+ </svg>
92
+ <span class="font-medium text-gray-900">{{path.name}}</span>
93
+ <span v-if="path.isVirtual" class="ml-2 text-sm text-purple-600">(virtual - {{getVirtualFieldType(path)}})</span>
94
+ <span v-else class="ml-2 text-sm text-blue-600">(user-added - {{getVirtualFieldType(path)}})</span>
95
+ </div>
96
+ </div>
97
+
98
+ <!-- Virtual Field Content (Collapsible) -->
99
+ <div v-if="!isVirtualFieldCollapsed(path.name)" class="p-3">
100
+ <div v-if="path.value == null" class="text-sky-800">
101
+ {{'' + path.value}}
102
+ </div>
103
+ <div v-else>
104
+ {{path.value}}
105
+ </div>
106
+ </div>
107
+ </div>
108
+
109
+ <!-- Unmatched Schema Paths (shown after matched items when searching, or all when not searching) -->
110
+ <div
111
+ v-for="path in unmatchedSchemaPaths"
112
+ :key="path.path || path"
113
+ class="value"
114
+ >
115
+ <document-property
116
+ :path="path"
117
+ :document="document"
118
+ :schemaPaths="schemaPaths"
119
+ :editting="editting"
120
+ :changes="changes"
121
+ :highlight="false"
122
+ :invalid="invalid"></document-property>
123
+ </div>
124
+
125
+ <!-- Unmatched Virtual Fields (shown last) -->
126
+ <div
127
+ v-for="path in unmatchedVirtuals"
128
+ :key="path.name"
129
+ class="border border-gray-200 rounded-lg mb-2 transition-all duration-200 ease-in-out"
130
+ >
131
+ <!-- Virtual Field Header (Always Visible) -->
132
+ <div
133
+ @click="toggleVirtualField(path.name)"
134
+ class="p-3 bg-gray-50 hover:bg-gray-100 cursor-pointer flex items-center justify-between border-b border-gray-200 transition-colors duration-200 ease-in-out"
86
135
  >
87
136
  <div class="flex items-center">
88
137
  <svg
@@ -145,6 +145,20 @@ module.exports = app => app.component('document-details', {
145
145
 
146
146
  return matches.concat(nonMatches);
147
147
  },
148
+ matchedSchemaPaths() {
149
+ if (!this.searchQuery.trim()) {
150
+ return [];
151
+ }
152
+ const query = this.searchQuery.toLowerCase();
153
+ return this.typeFilteredSchemaPaths.filter(path => path.path.toLowerCase().includes(query));
154
+ },
155
+ unmatchedSchemaPaths() {
156
+ if (!this.searchQuery.trim()) {
157
+ return this.typeFilteredSchemaPaths;
158
+ }
159
+ const query = this.searchQuery.toLowerCase();
160
+ return this.typeFilteredSchemaPaths.filter(path => !path.path.toLowerCase().includes(query));
161
+ },
148
162
  typeFilteredVirtuals() {
149
163
  let virtuals = this.virtuals;
150
164
 
@@ -178,6 +192,20 @@ module.exports = app => app.component('document-details', {
178
192
 
179
193
  return matches.concat(nonMatches);
180
194
  },
195
+ matchedVirtuals() {
196
+ if (!this.searchQuery.trim()) {
197
+ return [];
198
+ }
199
+ const query = this.searchQuery.toLowerCase();
200
+ return this.typeFilteredVirtuals.filter(virtual => virtual.name.toLowerCase().includes(query));
201
+ },
202
+ unmatchedVirtuals() {
203
+ if (!this.searchQuery.trim()) {
204
+ return this.typeFilteredVirtuals;
205
+ }
206
+ const query = this.searchQuery.toLowerCase();
207
+ return this.typeFilteredVirtuals.filter(virtual => !virtual.name.toLowerCase().includes(query));
208
+ },
181
209
  schemaSearchMatchSet() {
182
210
  if (!this.searchQuery.trim()) {
183
211
  return new Set();
@@ -2,8 +2,8 @@
2
2
  <!-- Collapsible Header -->
3
3
  <div
4
4
  @click="toggleCollapse"
5
- class="p-3 hover:bg-gray-100 cursor-pointer flex items-center justify-between border-b border-gray-200 transition-colors duration-200 ease-in-out"
6
- :class="{ 'bg-amber-100': highlight, 'bg-gray-50': !highlight }"
5
+ class="p-3 cursor-pointer flex items-center justify-between border-b border-gray-200 transition-colors duration-200 ease-in-out"
6
+ :class="{ 'bg-amber-100 hover:bg-amber-200': highlight, 'bg-gray-50 hover:bg-gray-100': !highlight }"
7
7
  >
8
8
  <div class="flex items-center" >
9
9
  <svg
@@ -81,7 +81,43 @@
81
81
  </div>
82
82
  <div v-else>
83
83
  <!-- Show truncated or full value based on needsTruncation and isValueExpanded -->
84
- <div v-if="needsTruncation && !isValueExpanded" class="relative">
84
+ <!-- Special handling for truncated arrays -->
85
+ <div v-if="isArray && shouldShowTruncated" class="w-full">
86
+ <div class="mt-2">
87
+ <div
88
+ v-for="(item, index) in truncatedArrayItems"
89
+ :key="index"
90
+ class="mb-1.5 py-2.5 px-3 pl-4 bg-transparent border-l-[3px] border-l-blue-500 rounded-none transition-all duration-200 cursor-pointer relative hover:bg-slate-50 hover:border-l-blue-600">
91
+ <div class="absolute -left-2 top-1/2 -translate-y-1/2 w-5 h-5 bg-blue-500 text-white rounded-full flex items-center justify-center text-[10px] font-semibold font-mono z-10 hover:bg-blue-600">{{ index }}</div>
92
+ <div v-if="arrayUtils.isObjectItem(item)" class="flex flex-col gap-1 mt-1 px-2">
93
+ <div
94
+ v-for="key in arrayUtils.getItemKeys(item)"
95
+ :key="key"
96
+ class="flex items-start gap-2 text-xs font-mono">
97
+ <span class="font-semibold text-gray-600 flex-shrink-0 min-w-[80px]">{{ key }}:</span>
98
+ <span class="text-gray-800 break-words whitespace-pre-wrap flex-1">{{ arrayUtils.formatItemValue(item, key) }}</span>
99
+ </div>
100
+ </div>
101
+ <div v-else class="text-xs py-1.5 px-2 font-mono text-gray-800 break-words whitespace-pre-wrap mt-1">{{ arrayUtils.formatValue(item) }}</div>
102
+ </div>
103
+ <div class="mb-1.5 py-2.5 px-3 pl-4 bg-transparent border-none border-l-[3px] border-l-blue-500 rounded-none transition-all duration-200 cursor-pointer relative opacity-70 hover:opacity-100">
104
+ <div class="text-xs py-1.5 px-2 font-mono text-gray-500 italic break-words whitespace-pre-wrap mt-1">
105
+ ... and {{ remainingArrayCount }} more item{{ remainingArrayCount !== 1 ? 's' : '' }}
106
+ </div>
107
+ </div>
108
+ </div>
109
+ <button
110
+ @click="toggleValueExpansion"
111
+ class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium flex items-center gap-1 transform transition-all duration-200 ease-in-out hover:translate-x-0.5"
112
+ >
113
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
114
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
115
+ </svg>
116
+ Show all {{ arrayValue.length }} items
117
+ </button>
118
+ </div>
119
+ <!-- Non-array truncated view -->
120
+ <div v-else-if="shouldShowTruncated && !isArray" class="relative">
85
121
  <div class="text-gray-700 whitespace-pre-wrap break-words font-mono text-sm">{{truncatedString}}</div>
86
122
  <button
87
123
  @click="toggleValueExpansion"
@@ -93,6 +129,7 @@
93
129
  Show more ({{valueAsString.length}} characters)
94
130
  </button>
95
131
  </div>
132
+ <!-- Expanded view -->
96
133
  <div v-else-if="needsTruncation && isValueExpanded" class="relative">
97
134
  <component :is="getComponentForPath(path)" :value="getValueForPath(path.path)"></component>
98
135
  <button
@@ -105,6 +142,7 @@
105
142
  Show less
106
143
  </button>
107
144
  </div>
145
+ <!-- Full view (no truncation needed) -->
108
146
  <div v-else>
109
147
  <component :is="getComponentForPath(path)" :value="getValueForPath(path.path)"></component>
110
148
  </div>