nuxt-ui-tools 1.24.0 → 1.25.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 (206) hide show
  1. package/dist/module.d.mts +3 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +8 -0
  4. package/dist/runtime/display/components/blocks/display-accordion.d.vue.ts +4 -0
  5. package/dist/runtime/display/components/blocks/display-accordion.vue +93 -0
  6. package/dist/runtime/display/components/blocks/display-accordion.vue.d.ts +4 -0
  7. package/dist/runtime/display/components/blocks/display-alert.d.vue.ts +4 -0
  8. package/dist/runtime/display/components/blocks/display-alert.vue +133 -0
  9. package/dist/runtime/display/components/blocks/display-alert.vue.d.ts +4 -0
  10. package/dist/runtime/display/components/blocks/display-breakdown.d.vue.ts +4 -0
  11. package/dist/runtime/display/components/blocks/display-breakdown.vue +178 -0
  12. package/dist/runtime/display/components/blocks/display-breakdown.vue.d.ts +4 -0
  13. package/dist/runtime/display/components/blocks/display-chart.d.vue.ts +4 -0
  14. package/dist/runtime/display/components/blocks/display-chart.vue +237 -0
  15. package/dist/runtime/display/components/blocks/display-chart.vue.d.ts +4 -0
  16. package/dist/runtime/display/components/blocks/display-code.d.vue.ts +4 -0
  17. package/dist/runtime/display/components/blocks/display-code.vue +143 -0
  18. package/dist/runtime/display/components/blocks/display-code.vue.d.ts +4 -0
  19. package/dist/runtime/display/components/blocks/display-date.d.vue.ts +4 -0
  20. package/dist/runtime/display/components/blocks/display-date.vue +174 -0
  21. package/dist/runtime/display/components/blocks/display-date.vue.d.ts +4 -0
  22. package/dist/runtime/display/components/blocks/display-diff.d.vue.ts +4 -0
  23. package/dist/runtime/display/components/blocks/display-diff.vue +142 -0
  24. package/dist/runtime/display/components/blocks/display-diff.vue.d.ts +4 -0
  25. package/dist/runtime/display/components/blocks/display-empty.d.vue.ts +4 -0
  26. package/dist/runtime/display/components/blocks/display-empty.vue +74 -0
  27. package/dist/runtime/display/components/blocks/display-empty.vue.d.ts +4 -0
  28. package/dist/runtime/display/components/blocks/display-facts.d.vue.ts +4 -0
  29. package/dist/runtime/display/components/blocks/display-facts.vue +180 -0
  30. package/dist/runtime/display/components/blocks/display-facts.vue.d.ts +4 -0
  31. package/dist/runtime/display/components/blocks/display-heading.d.vue.ts +4 -0
  32. package/dist/runtime/display/components/blocks/display-heading.vue +96 -0
  33. package/dist/runtime/display/components/blocks/display-heading.vue.d.ts +4 -0
  34. package/dist/runtime/display/components/blocks/display-list.d.vue.ts +4 -0
  35. package/dist/runtime/display/components/blocks/display-list.vue +295 -0
  36. package/dist/runtime/display/components/blocks/display-list.vue.d.ts +4 -0
  37. package/dist/runtime/display/components/blocks/display-media.d.vue.ts +4 -0
  38. package/dist/runtime/display/components/blocks/display-media.vue +326 -0
  39. package/dist/runtime/display/components/blocks/display-media.vue.d.ts +4 -0
  40. package/dist/runtime/display/components/blocks/display-meter.d.vue.ts +4 -0
  41. package/dist/runtime/display/components/blocks/display-meter.vue +301 -0
  42. package/dist/runtime/display/components/blocks/display-meter.vue.d.ts +4 -0
  43. package/dist/runtime/display/components/blocks/display-person.d.vue.ts +4 -0
  44. package/dist/runtime/display/components/blocks/display-person.vue +146 -0
  45. package/dist/runtime/display/components/blocks/display-person.vue.d.ts +4 -0
  46. package/dist/runtime/display/components/blocks/display-record.d.vue.ts +4 -0
  47. package/dist/runtime/display/components/blocks/display-record.vue +208 -0
  48. package/dist/runtime/display/components/blocks/display-record.vue.d.ts +4 -0
  49. package/dist/runtime/display/components/blocks/display-stat.d.vue.ts +4 -0
  50. package/dist/runtime/display/components/blocks/display-stat.vue +178 -0
  51. package/dist/runtime/display/components/blocks/display-stat.vue.d.ts +4 -0
  52. package/dist/runtime/display/components/blocks/display-table.d.vue.ts +4 -0
  53. package/dist/runtime/display/components/blocks/display-table.vue +132 -0
  54. package/dist/runtime/display/components/blocks/display-table.vue.d.ts +4 -0
  55. package/dist/runtime/display/components/blocks/display-text.d.vue.ts +4 -0
  56. package/dist/runtime/display/components/blocks/display-text.vue +135 -0
  57. package/dist/runtime/display/components/blocks/display-text.vue.d.ts +4 -0
  58. package/dist/runtime/display/components/blocks/display-timeline.d.vue.ts +4 -0
  59. package/dist/runtime/display/components/blocks/display-timeline.vue +232 -0
  60. package/dist/runtime/display/components/blocks/display-timeline.vue.d.ts +4 -0
  61. package/dist/runtime/display/components/display.d.vue.ts +24 -0
  62. package/dist/runtime/display/components/display.vue +21 -0
  63. package/dist/runtime/display/components/display.vue.d.ts +24 -0
  64. package/dist/runtime/display/components/parts/display-actions.d.vue.ts +9 -0
  65. package/dist/runtime/display/components/parts/display-actions.vue +24 -0
  66. package/dist/runtime/display/components/parts/display-actions.vue.d.ts +9 -0
  67. package/dist/runtime/display/components/parts/display-chip.d.vue.ts +11 -0
  68. package/dist/runtime/display/components/parts/display-chip.vue +45 -0
  69. package/dist/runtime/display/components/parts/display-chip.vue.d.ts +11 -0
  70. package/dist/runtime/display/components/parts/display-copy.d.vue.ts +6 -0
  71. package/dist/runtime/display/components/parts/display-copy.vue +27 -0
  72. package/dist/runtime/display/components/parts/display-copy.vue.d.ts +6 -0
  73. package/dist/runtime/display/components/parts/display-empty-line.d.vue.ts +7 -0
  74. package/dist/runtime/display/components/parts/display-empty-line.vue +21 -0
  75. package/dist/runtime/display/components/parts/display-empty-line.vue.d.ts +7 -0
  76. package/dist/runtime/display/components/parts/display-fact-value.d.vue.ts +7 -0
  77. package/dist/runtime/display/components/parts/display-fact-value.vue +35 -0
  78. package/dist/runtime/display/components/parts/display-fact-value.vue.d.ts +7 -0
  79. package/dist/runtime/display/components/parts/display-load-error.d.vue.ts +7 -0
  80. package/dist/runtime/display/components/parts/display-load-error.vue +29 -0
  81. package/dist/runtime/display/components/parts/display-load-error.vue.d.ts +7 -0
  82. package/dist/runtime/display/components/parts/display-more.d.vue.ts +10 -0
  83. package/dist/runtime/display/components/parts/display-more.vue +23 -0
  84. package/dist/runtime/display/components/parts/display-more.vue.d.ts +10 -0
  85. package/dist/runtime/display/components/parts/display-record-media.d.vue.ts +9 -0
  86. package/dist/runtime/display/components/parts/display-record-media.vue +59 -0
  87. package/dist/runtime/display/components/parts/display-record-media.vue.d.ts +9 -0
  88. package/dist/runtime/display/components/parts/display-render.d.ts +10 -0
  89. package/dist/runtime/display/components/parts/display-render.js +5 -0
  90. package/dist/runtime/display/components/parts/display-skeleton.d.vue.ts +7 -0
  91. package/dist/runtime/display/components/parts/display-skeleton.vue +67 -0
  92. package/dist/runtime/display/components/parts/display-skeleton.vue.d.ts +7 -0
  93. package/dist/runtime/display/composables/use-display-config.d.ts +6 -0
  94. package/dist/runtime/display/composables/use-display-config.js +11 -0
  95. package/dist/runtime/display/composables/use-display-file-preview.d.ts +9 -0
  96. package/dist/runtime/display/composables/use-display-file-preview.js +11 -0
  97. package/dist/runtime/display/composables/use-display-icons.d.ts +8 -0
  98. package/dist/runtime/display/composables/use-display-icons.js +62 -0
  99. package/dist/runtime/display/composables/use-display-locale.d.ts +5 -0
  100. package/dist/runtime/display/composables/use-display-locale.js +5 -0
  101. package/dist/runtime/display/composables/use-display-number.d.ts +2 -0
  102. package/dist/runtime/display/composables/use-display-number.js +7 -0
  103. package/dist/runtime/display/composables/use-display-reveal.d.ts +14 -0
  104. package/dist/runtime/display/composables/use-display-reveal.js +15 -0
  105. package/dist/runtime/display/composables/use-display-url.d.ts +26 -0
  106. package/dist/runtime/display/composables/use-display-url.js +46 -0
  107. package/dist/runtime/display/index.d.ts +4 -0
  108. package/dist/runtime/display/index.js +3 -0
  109. package/dist/runtime/display/plugins/display-tones.d.ts +3 -0
  110. package/dist/runtime/display/plugins/display-tones.js +17 -0
  111. package/dist/runtime/display/types/blocks/accordion.d.ts +18 -0
  112. package/dist/runtime/display/types/blocks/accordion.js +0 -0
  113. package/dist/runtime/display/types/blocks/alert.d.ts +31 -0
  114. package/dist/runtime/display/types/blocks/alert.js +0 -0
  115. package/dist/runtime/display/types/blocks/breakdown.d.ts +36 -0
  116. package/dist/runtime/display/types/blocks/breakdown.js +0 -0
  117. package/dist/runtime/display/types/blocks/chart.d.ts +23 -0
  118. package/dist/runtime/display/types/blocks/chart.js +0 -0
  119. package/dist/runtime/display/types/blocks/code.d.ts +21 -0
  120. package/dist/runtime/display/types/blocks/code.js +0 -0
  121. package/dist/runtime/display/types/blocks/date.d.ts +27 -0
  122. package/dist/runtime/display/types/blocks/date.js +0 -0
  123. package/dist/runtime/display/types/blocks/diff.d.ts +20 -0
  124. package/dist/runtime/display/types/blocks/diff.js +0 -0
  125. package/dist/runtime/display/types/blocks/empty.d.ts +13 -0
  126. package/dist/runtime/display/types/blocks/empty.js +0 -0
  127. package/dist/runtime/display/types/blocks/facts.d.ts +50 -0
  128. package/dist/runtime/display/types/blocks/facts.js +0 -0
  129. package/dist/runtime/display/types/blocks/heading.d.ts +19 -0
  130. package/dist/runtime/display/types/blocks/heading.js +0 -0
  131. package/dist/runtime/display/types/blocks/list.d.ts +36 -0
  132. package/dist/runtime/display/types/blocks/list.js +0 -0
  133. package/dist/runtime/display/types/blocks/media.d.ts +42 -0
  134. package/dist/runtime/display/types/blocks/media.js +0 -0
  135. package/dist/runtime/display/types/blocks/meter.d.ts +48 -0
  136. package/dist/runtime/display/types/blocks/meter.js +0 -0
  137. package/dist/runtime/display/types/blocks/person.d.ts +32 -0
  138. package/dist/runtime/display/types/blocks/person.js +0 -0
  139. package/dist/runtime/display/types/blocks/record.d.ts +42 -0
  140. package/dist/runtime/display/types/blocks/record.js +0 -0
  141. package/dist/runtime/display/types/blocks/stat.d.ts +44 -0
  142. package/dist/runtime/display/types/blocks/stat.js +0 -0
  143. package/dist/runtime/display/types/blocks/table.d.ts +28 -0
  144. package/dist/runtime/display/types/blocks/table.js +0 -0
  145. package/dist/runtime/display/types/blocks/text.d.ts +22 -0
  146. package/dist/runtime/display/types/blocks/text.js +0 -0
  147. package/dist/runtime/display/types/blocks/timeline.d.ts +37 -0
  148. package/dist/runtime/display/types/blocks/timeline.js +0 -0
  149. package/dist/runtime/display/types/config.d.ts +53 -0
  150. package/dist/runtime/display/types/config.js +0 -0
  151. package/dist/runtime/display/types/index.d.ts +22 -0
  152. package/dist/runtime/display/types/index.js +0 -0
  153. package/dist/runtime/display/types/registry.d.ts +57 -0
  154. package/dist/runtime/display/types/registry.js +0 -0
  155. package/dist/runtime/display/types/shared.d.ts +71 -0
  156. package/dist/runtime/display/types/shared.js +0 -0
  157. package/dist/runtime/display/utils/classes.d.ts +3 -0
  158. package/dist/runtime/display/utils/classes.js +7 -0
  159. package/dist/runtime/display/utils/config.d.ts +6 -0
  160. package/dist/runtime/display/utils/config.js +7 -0
  161. package/dist/runtime/display/utils/content.d.ts +7 -0
  162. package/dist/runtime/display/utils/content.js +13 -0
  163. package/dist/runtime/display/utils/dates.d.ts +16 -0
  164. package/dist/runtime/display/utils/dates.js +34 -0
  165. package/dist/runtime/display/utils/json.d.ts +7 -0
  166. package/dist/runtime/display/utils/json.js +15 -0
  167. package/dist/runtime/display/utils/meter.d.ts +7 -0
  168. package/dist/runtime/display/utils/meter.js +13 -0
  169. package/dist/runtime/display/utils/registry.d.ts +47 -0
  170. package/dist/runtime/display/utils/registry.js +64 -0
  171. package/dist/runtime/display/utils/tone-css.d.ts +7 -0
  172. package/dist/runtime/display/utils/tone-css.js +38 -0
  173. package/dist/runtime/display/utils/tone.d.ts +26 -0
  174. package/dist/runtime/display/utils/tone.js +38 -0
  175. package/dist/runtime/display/utils/urls.d.ts +10 -0
  176. package/dist/runtime/display/utils/urls.js +33 -0
  177. package/dist/runtime/file-preview/components/shell/file-preview-stage.vue +5 -3
  178. package/dist/runtime/file-preview/composables/use-file-preview-source.d.ts +7 -0
  179. package/dist/runtime/file-preview/composables/use-file-preview-source.js +7 -1
  180. package/dist/runtime/file-preview/index.d.ts +1 -0
  181. package/dist/runtime/file-preview/index.js +1 -0
  182. package/dist/runtime/file-preview/types/file.d.ts +9 -0
  183. package/dist/runtime/file-preview/utils/errors.d.ts +30 -0
  184. package/dist/runtime/file-preview/utils/errors.js +26 -0
  185. package/dist/runtime/form/components/utils/form-file-preview.vue +7 -2
  186. package/dist/runtime/form/composables/use-form-root.js +2 -0
  187. package/dist/runtime/form/composables/use-form-runtime.js +7 -2
  188. package/dist/runtime/form/fields/index.d.ts +5 -0
  189. package/dist/runtime/form/fields/info/component.vue +51 -19
  190. package/dist/runtime/form/fields/info/config.d.ts +5 -0
  191. package/dist/runtime/form/fields/info/config.js +2 -1
  192. package/dist/runtime/form/fields/info/types.d.ts +78 -4
  193. package/dist/runtime/form/fields/info/use-info-display.d.ts +20 -0
  194. package/dist/runtime/form/fields/info/use-info-display.js +82 -0
  195. package/dist/runtime/form/fields/upload/upload-item.vue +10 -2
  196. package/dist/runtime/form/types/api.d.ts +6 -0
  197. package/dist/runtime/form/types/runtime.d.ts +2 -0
  198. package/dist/runtime/form/utils/dynamic.d.ts +6 -0
  199. package/dist/runtime/form/utils/dynamic.js +7 -0
  200. package/dist/runtime/i18n/locales/en.js +27 -0
  201. package/dist/runtime/i18n/locales/fr.js +27 -0
  202. package/dist/runtime/i18n/types.d.ts +35 -0
  203. package/dist/runtime/shared/styles/tokens.css +1 -1
  204. package/dist/runtime/shared/utils/file.d.ts +1 -1
  205. package/dist/runtime/table/utils/data-list-ui.d.ts +1 -1
  206. package/package.json +16 -1
@@ -0,0 +1,301 @@
1
+ <script setup>
2
+ import UIcon from "@nuxt/ui/components/Icon.vue";
3
+ import { computed } from "vue";
4
+ import { isPlainObject } from "../../../shared/utils/predicate";
5
+ import { useDisplayAppUi } from "../../composables/use-display-config";
6
+ import { useDisplayNumber } from "../../composables/use-display-number";
7
+ import { resolveDisplayClasses } from "../../utils/classes";
8
+ import { displayContentText, isDisplayContentEmpty, resolveDisplayText } from "../../utils/content";
9
+ import { meterShare, meterTone } from "../../utils/meter";
10
+ import { displayToneClass } from "../../utils/tone";
11
+ import DisplayRender from "../parts/display-render";
12
+ import DisplaySkeleton from "../parts/display-skeleton.vue";
13
+ const {
14
+ variant = "bar",
15
+ label = void 0,
16
+ value = 0,
17
+ max = void 0,
18
+ valueLabel = void 0,
19
+ tone = void 0,
20
+ thresholds = void 0,
21
+ parts = void 0,
22
+ caption = void 0,
23
+ levels = void 0,
24
+ current = void 0,
25
+ target = void 0,
26
+ size = "md",
27
+ loading = false,
28
+ ui = void 0
29
+ } = defineProps({
30
+ variant: { type: String, required: false },
31
+ label: { type: [String, Number, Function, Object, Boolean, null, Array], required: false, skipCheck: true },
32
+ value: { type: Number, required: false },
33
+ max: { type: Number, required: false },
34
+ valueLabel: { type: [String, Number, Function, Object, Boolean, null, Array], required: false, skipCheck: true },
35
+ tone: { type: String, required: false },
36
+ thresholds: { type: Object, required: false },
37
+ parts: { type: Array, required: false },
38
+ caption: { type: [String, Number, Function, Object, Boolean, null, Array], required: false, skipCheck: true },
39
+ levels: { type: Array, required: false },
40
+ current: { type: Number, required: false },
41
+ target: { type: Number, required: false },
42
+ size: { type: String, required: false },
43
+ loading: { type: Boolean, required: false },
44
+ ui: { type: Object, required: false }
45
+ });
46
+ const PALETTE = ["primary", "info", "success", "warning", "secondary", "neutral"];
47
+ const RING_SIZES = { lg: 112, md: 88, sm: 64 };
48
+ const format = useDisplayNumber();
49
+ const appUi = useDisplayAppUi("meter");
50
+ const partTotal = computed(() => (parts ?? []).reduce((sum, part) => sum + part.value, 0));
51
+ const resolvedMax = computed(
52
+ () => max ?? (variant === "segments" || variant === "split" ? partTotal.value : 100)
53
+ );
54
+ const share = computed(() => meterShare(value, resolvedMax.value));
55
+ const resolvedTone = computed(() => meterTone(share.value, tone, thresholds));
56
+ const resolvedParts = computed(
57
+ () => (parts ?? []).map((part, index) => ({
58
+ ...part,
59
+ tone: part.tone ?? (variant === "ring" ? resolvedTone.value : PALETTE[index % PALETTE.length] ?? "primary"),
60
+ width: meterShare(part.value, resolvedMax.value) * 100
61
+ }))
62
+ );
63
+ const headerValue = computed(() => valueLabel ?? `${format(value)} / ${format(resolvedMax.value)}`);
64
+ const ariaLabel = computed(() => displayContentText(label));
65
+ const ring = computed(() => {
66
+ const diameter = RING_SIZES[size];
67
+ const stroke = Math.round(diameter / 11);
68
+ const radius = (diameter - stroke) / 2;
69
+ const circumference = 2 * Math.PI * radius;
70
+ return { circumference, diameter, radius, stroke, filled: circumference * share.value };
71
+ });
72
+ const resolvedLevels = computed(
73
+ () => (levels ?? []).map(
74
+ (level) => isMeterLevel(level) ? level : { label: level }
75
+ )
76
+ );
77
+ const classes = computed(
78
+ () => resolveDisplayClasses(
79
+ {
80
+ bar: "h-full bg-[var(--nut-tone)] transition-[width] duration-300 ease-out first:rounded-s-full last:rounded-e-full",
81
+ caption: "mt-1.5 text-xs text-dimmed",
82
+ header: "flex items-baseline justify-between gap-3 text-sm",
83
+ label: "flex min-w-0 items-center gap-1.5 font-semibold text-toned",
84
+ legend: "mt-2 flex flex-wrap gap-x-3 gap-y-1 text-xs text-muted",
85
+ legendItem: "inline-flex items-center gap-1.5",
86
+ level: "grid h-8 place-items-center rounded-[calc(var(--nut-display-radius)*0.75)] text-xs font-bold",
87
+ levelCaption: "text-center text-[10.5px] text-dimmed",
88
+ levels: "mt-2 grid gap-1",
89
+ parts: "flex min-w-0 flex-1 flex-col gap-2.5",
90
+ ring: "flex items-center gap-4",
91
+ root: "min-w-0",
92
+ track: "mt-2 flex h-2 gap-0.5 overflow-hidden rounded-full bg-[var(--nut-display-track)]",
93
+ value: "shrink-0 font-semibold text-highlighted tabular-nums"
94
+ },
95
+ appUi.value,
96
+ ui
97
+ )
98
+ );
99
+ function levelClass(index) {
100
+ if (index === current) return "bg-[var(--nut-tone)] text-[var(--nut-tone-contrast)]";
101
+ if (index === target)
102
+ return "text-[var(--nut-tone-ink)] outline-dashed outline-[1.5px] -outline-offset-[1.5px] outline-[var(--nut-tone)]";
103
+ if (current !== void 0 && index < current)
104
+ return "bg-[var(--nut-tone-soft)] text-[var(--nut-tone-ink)]";
105
+ return "bg-elevated text-dimmed";
106
+ }
107
+ function isMeterLevel(level) {
108
+ return isPlainObject(level);
109
+ }
110
+ function partTone(partToneName) {
111
+ return displayToneClass(partToneName);
112
+ }
113
+ </script>
114
+
115
+ <template>
116
+ <DisplaySkeleton v-if="loading" :layout="variant === 'ring' ? 'ring' : 'lines'" :count="2" />
117
+ <div
118
+ v-else
119
+ :class="[classes.root, displayToneClass(resolvedTone)]"
120
+ data-display="meter"
121
+ :data-variant="variant"
122
+ >
123
+ <div v-if="variant === 'ring'" :class="classes.ring">
124
+ <svg
125
+ :width="ring.diameter"
126
+ :height="ring.diameter"
127
+ :viewBox="`0 0 ${ring.diameter} ${ring.diameter}`"
128
+ class="shrink-0"
129
+ role="meter"
130
+ :aria-valuenow="value"
131
+ aria-valuemin="0"
132
+ :aria-valuemax="resolvedMax"
133
+ :aria-label="ariaLabel"
134
+ >
135
+ <circle
136
+ :cx="ring.diameter / 2"
137
+ :cy="ring.diameter / 2"
138
+ :r="ring.radius"
139
+ fill="none"
140
+ stroke="var(--nut-display-track)"
141
+ :stroke-width="ring.stroke"
142
+ />
143
+ <circle
144
+ :cx="ring.diameter / 2"
145
+ :cy="ring.diameter / 2"
146
+ :r="ring.radius"
147
+ fill="none"
148
+ stroke="var(--nut-tone)"
149
+ :stroke-width="ring.stroke"
150
+ stroke-linecap="round"
151
+ :stroke-dasharray="`${ring.filled} ${ring.circumference}`"
152
+ :transform="`rotate(-90 ${ring.diameter / 2} ${ring.diameter / 2})`"
153
+ />
154
+ <text
155
+ :x="ring.diameter / 2"
156
+ :y="ring.diameter / 2 + ring.diameter * 0.04"
157
+ text-anchor="middle"
158
+ class="fill-[var(--ui-text-highlighted)] font-extrabold"
159
+ :font-size="ring.diameter * 0.22"
160
+ >
161
+ {{ displayContentText(valueLabel) ?? format(value) }}
162
+ </text>
163
+ <text
164
+ :x="ring.diameter / 2"
165
+ :y="ring.diameter / 2 + ring.diameter * 0.2"
166
+ text-anchor="middle"
167
+ class="fill-[var(--ui-text-dimmed)]"
168
+ :font-size="ring.diameter * 0.115"
169
+ >
170
+ / {{ format(resolvedMax) }}
171
+ </text>
172
+ </svg>
173
+ <div :class="classes.parts">
174
+ <div v-if="!isDisplayContentEmpty(label)" :class="classes.label">
175
+ <DisplayRender :content="label" />
176
+ </div>
177
+ <div v-for="(part, index) in resolvedParts" :key="index" :class="partTone(part.tone)">
178
+ <div :class="classes.header">
179
+ <span :class="classes.label">
180
+ <UIcon v-if="part.icon" :name="part.icon" class="size-3.5" />
181
+ <DisplayRender :content="part.label" />
182
+ </span>
183
+ <span :class="classes.value"
184
+ ><DisplayRender :content="part.valueLabel ?? format(part.value)"
185
+ /></span>
186
+ </div>
187
+ <div :class="[classes.track, 'mt-1 h-1.5']">
188
+ <i
189
+ :class="classes.bar"
190
+ :style="{ width: `${meterShare(part.value, part.max ?? resolvedMax) * 100}%` }"
191
+ />
192
+ </div>
193
+ </div>
194
+ <div v-if="!isDisplayContentEmpty(caption)" :class="classes.caption">
195
+ <DisplayRender :content="caption" />
196
+ </div>
197
+ </div>
198
+ </div>
199
+ <template v-else-if="variant === 'scale'">
200
+ <div :class="classes.header">
201
+ <span :class="classes.label"><DisplayRender :content="label" /></span>
202
+ <span v-if="!isDisplayContentEmpty(valueLabel)" :class="classes.value"
203
+ ><DisplayRender :content="valueLabel"
204
+ /></span>
205
+ </div>
206
+ <div
207
+ :class="classes.levels"
208
+ :style="{ gridTemplateColumns: `repeat(${resolvedLevels.length || 1}, minmax(0, 1fr))` }"
209
+ >
210
+ <div
211
+ v-for="(level, index) in resolvedLevels"
212
+ :key="index"
213
+ :class="[classes.level, levelClass(index)]"
214
+ :data-state="
215
+ index === current ? 'current' : index === target ? 'target' : current !== void 0 && index < current ? 'reached' : 'idle'
216
+ "
217
+ >
218
+ {{ resolveDisplayText(level.label) }}
219
+ </div>
220
+ </div>
221
+ <div
222
+ v-if="resolvedLevels.some((level2) => level2.caption !== void 0)"
223
+ class="mt-1 grid gap-1"
224
+ :style="{ gridTemplateColumns: `repeat(${resolvedLevels.length}, minmax(0, 1fr))` }"
225
+ >
226
+ <span v-for="(level, index) in resolvedLevels" :key="index" :class="classes.levelCaption">
227
+ {{ resolveDisplayText(level.caption) }}
228
+ </span>
229
+ </div>
230
+ <div v-if="!isDisplayContentEmpty(caption)" :class="classes.caption">
231
+ <DisplayRender :content="caption" />
232
+ </div>
233
+ </template>
234
+ <template v-else-if="variant === 'split'">
235
+ <div class="mb-1.5 flex items-end justify-between gap-3 text-xs">
236
+ <span
237
+ v-for="(part, index) in resolvedParts.slice(0, 2)"
238
+ :key="index"
239
+ :class="['flex items-baseline gap-1.5', index === 1 ? 'text-end' : '']"
240
+ >
241
+ <b class="text-base font-extrabold text-highlighted tabular-nums"
242
+ >{{ Math.round(part.width) }} %</b
243
+ >
244
+ <span class="text-muted"><DisplayRender :content="part.label" /></span>
245
+ </span>
246
+ </div>
247
+ <div :class="[classes.track, 'mt-0']" role="img" :aria-label="ariaLabel">
248
+ <i
249
+ v-for="(part, index) in resolvedParts.slice(0, 2)"
250
+ :key="index"
251
+ :class="[classes.bar, partTone(part.tone)]"
252
+ :style="{ width: `${part.width}%` }"
253
+ />
254
+ </div>
255
+ <div v-if="!isDisplayContentEmpty(caption)" :class="classes.caption">
256
+ <DisplayRender :content="caption" />
257
+ </div>
258
+ </template>
259
+ <template v-else>
260
+ <div v-if="!isDisplayContentEmpty(label) || variant === 'bar'" :class="classes.header">
261
+ <span :class="classes.label"><DisplayRender :content="label" /></span>
262
+ <span :class="classes.value"
263
+ ><DisplayRender :content="variant === 'bar' ? headerValue : valueLabel"
264
+ /></span>
265
+ </div>
266
+ <div
267
+ :class="classes.track"
268
+ role="meter"
269
+ :aria-valuenow="variant === 'bar' ? value : partTotal"
270
+ aria-valuemin="0"
271
+ :aria-valuemax="resolvedMax"
272
+ :aria-label="ariaLabel"
273
+ >
274
+ <i v-if="variant === 'bar'" :class="classes.bar" :style="{ width: `${share * 100}%` }" />
275
+ <i
276
+ v-for="(part, index) in variant === 'segments' ? resolvedParts : []"
277
+ v-else
278
+ :key="index"
279
+ :class="[classes.bar, partTone(part.tone)]"
280
+ :style="{ width: `${part.width}%` }"
281
+ />
282
+ </div>
283
+ <div v-if="variant === 'segments' && resolvedParts.length" :class="classes.legend">
284
+ <span
285
+ v-for="(part, index) in resolvedParts"
286
+ :key="index"
287
+ :class="[classes.legendItem, partTone(part.tone)]"
288
+ >
289
+ <i class="size-2 rounded-[2px] bg-[var(--nut-tone)]" />
290
+ <DisplayRender :content="part.label" />
291
+ <b class="font-semibold text-default tabular-nums"
292
+ ><DisplayRender :content="part.valueLabel ?? format(part.value)"
293
+ /></b>
294
+ </span>
295
+ </div>
296
+ <div v-if="!isDisplayContentEmpty(caption)" :class="classes.caption">
297
+ <DisplayRender :content="caption" />
298
+ </div>
299
+ </template>
300
+ </div>
301
+ </template>
@@ -0,0 +1,4 @@
1
+ import type { DisplayMeterProps } from '../../types/index.js';
2
+ declare const __VLS_export: import("vue").DefineComponent<DisplayMeterProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<DisplayMeterProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
3
+ declare const _default: typeof __VLS_export;
4
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import type { DisplayPersonProps } from '../../types/index.js';
2
+ declare const __VLS_export: import("vue").DefineComponent<DisplayPersonProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<DisplayPersonProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
3
+ declare const _default: typeof __VLS_export;
4
+ export default _default;
@@ -0,0 +1,146 @@
1
+ <script setup>
2
+ import UAvatar from "@nuxt/ui/components/Avatar.vue";
3
+ import UIcon from "@nuxt/ui/components/Icon.vue";
4
+ import ULink from "@nuxt/ui/components/Link.vue";
5
+ import { computed } from "vue";
6
+ import { useDisplayAppUi } from "../../composables/use-display-config";
7
+ import { resolveDisplayClasses } from "../../utils/classes";
8
+ import { isDisplayContentEmpty, resolveDisplayText } from "../../utils/content";
9
+ import {
10
+ DISPLAY_SURFACE_CLASSES,
11
+ displayToneClass,
12
+ initialsOf,
13
+ toneFromName
14
+ } from "../../utils/tone";
15
+ import DisplayChip from "../parts/display-chip.vue";
16
+ import DisplayCopy from "../parts/display-copy.vue";
17
+ import DisplayRender from "../parts/display-render";
18
+ import DisplaySkeleton from "../parts/display-skeleton.vue";
19
+ const {
20
+ variant = "user",
21
+ people = void 0,
22
+ max = 4,
23
+ label = void 0,
24
+ contacts = void 0,
25
+ size = "md",
26
+ loading = false,
27
+ ui = void 0,
28
+ ...person
29
+ } = defineProps({
30
+ variant: { type: String, required: false },
31
+ people: { type: Array, required: false },
32
+ max: { type: Number, required: false },
33
+ label: { type: [String, Number, Function, Object, Boolean, null, Array], required: false, skipCheck: true },
34
+ contacts: { type: Array, required: false },
35
+ size: { type: String, required: false },
36
+ loading: { type: Boolean, required: false },
37
+ ui: { type: Object, required: false },
38
+ name: { type: [String, Number, Function], required: false },
39
+ description: { type: [String, Number, Function, Object, Boolean, null, Array], required: false, skipCheck: true },
40
+ avatar: { type: Object, required: false },
41
+ tone: { type: String, required: false },
42
+ chip: { type: Object, required: false }
43
+ });
44
+ const AVATAR_SIZES = {
45
+ contact: { lg: "2xl", md: "xl", sm: "lg" },
46
+ group: { lg: "lg", md: "md", sm: "sm" },
47
+ user: { lg: "xl", md: "lg", sm: "md" }
48
+ };
49
+ const appUi = useDisplayAppUi("person");
50
+ const self = computed(() => ({ ...person, name: person.name ?? "" }));
51
+ const shown = computed(() => (people ?? []).slice(0, max));
52
+ const overflow = computed(() => Math.max(0, (people?.length ?? 0) - shown.value.length));
53
+ const classes = computed(
54
+ () => resolveDisplayClasses(
55
+ {
56
+ avatar: variant === "group" ? "ring-2 ring-[var(--ui-bg)]" : "",
57
+ body: "min-w-0 flex-1",
58
+ chip: "shrink-0",
59
+ contact: "flex min-w-0 items-center gap-2 text-sm text-toned",
60
+ contactIcon: "size-3.5 shrink-0 text-muted",
61
+ contactValue: "min-w-0 flex-1 truncate",
62
+ contacts: "mt-3 flex flex-col gap-1",
63
+ description: "truncate text-xs text-muted",
64
+ group: "flex -space-x-2",
65
+ label: "text-sm text-toned",
66
+ name: `truncate font-semibold text-highlighted ${size === "lg" ? "text-base" : "text-sm"}`,
67
+ root: variant === "contact" ? `min-w-0 ${DISPLAY_SURFACE_CLASSES.bordered} p-3.5` : "flex min-w-0 items-center gap-3"
68
+ },
69
+ appUi.value,
70
+ ui
71
+ )
72
+ );
73
+ function avatarOf(entry) {
74
+ const name = resolveDisplayText(entry.name) ?? "";
75
+ const tone = entry.tone ?? toneFromName(name);
76
+ return {
77
+ alt: name,
78
+ text: initialsOf(name),
79
+ ...entry.avatar,
80
+ class: [displayToneClass(tone), classes.value.avatar, "shrink-0"],
81
+ ui: {
82
+ fallback: "text-[0.8em] font-semibold text-[var(--nut-tone-ink)]",
83
+ root: "bg-[var(--nut-tone-soft)]"
84
+ }
85
+ };
86
+ }
87
+ </script>
88
+
89
+ <template>
90
+ <DisplaySkeleton v-if="loading" layout="card" />
91
+ <div
92
+ v-else-if="variant === 'group'"
93
+ :class="classes.root"
94
+ data-display="person"
95
+ data-variant="group"
96
+ >
97
+ <div :class="classes.group">
98
+ <UAvatar
99
+ v-for="(person, index) in shown"
100
+ :key="index"
101
+ v-bind="avatarOf(person)"
102
+ :size="AVATAR_SIZES.group[size]"
103
+ :title="resolveDisplayText(person.name)"
104
+ />
105
+ <UAvatar
106
+ v-if="overflow"
107
+ :text="`+${overflow}`"
108
+ :size="AVATAR_SIZES.group[size]"
109
+ :class="[classes.avatar, 'nut-display-tone-neutral']"
110
+ :ui="{ fallback: 'font-semibold text-toned', root: 'bg-elevated' }"
111
+ />
112
+ </div>
113
+ <span v-if="!isDisplayContentEmpty(label)" :class="classes.label"
114
+ ><DisplayRender :content="label"
115
+ /></span>
116
+ </div>
117
+ <div v-else :class="classes.root" data-display="person" :data-variant="variant">
118
+ <div class="flex min-w-0 items-center gap-3">
119
+ <UAvatar
120
+ v-bind="avatarOf(self)"
121
+ :size="AVATAR_SIZES[variant === 'contact' ? 'contact' : 'user'][size]"
122
+ />
123
+ <div :class="classes.body">
124
+ <div :class="classes.name">{{ resolveDisplayText(self.name) }}</div>
125
+ <div v-if="!isDisplayContentEmpty(self.description)" :class="classes.description">
126
+ <DisplayRender :content="self.description" />
127
+ </div>
128
+ </div>
129
+ <DisplayChip v-if="self.chip" :chip="self.chip" :class="classes.chip" />
130
+ </div>
131
+ <div v-if="variant === 'contact' && contacts?.length" :class="classes.contacts">
132
+ <div v-for="(contact, index) in contacts" :key="index" :class="classes.contact">
133
+ <UIcon v-if="contact.icon" :name="contact.icon" :class="classes.contactIcon" />
134
+ <ULink
135
+ v-if="contact.href"
136
+ :to="contact.href"
137
+ :class="[classes.contactValue, 'hover:text-highlighted']"
138
+ >
139
+ {{ contact.value }}
140
+ </ULink>
141
+ <span v-else :class="classes.contactValue">{{ contact.value }}</span>
142
+ <DisplayCopy v-if="contact.copy !== false" :value="contact.value" class="-my-1" />
143
+ </div>
144
+ </div>
145
+ </div>
146
+ </template>
@@ -0,0 +1,4 @@
1
+ import type { DisplayPersonProps } from '../../types/index.js';
2
+ declare const __VLS_export: import("vue").DefineComponent<DisplayPersonProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<DisplayPersonProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
3
+ declare const _default: typeof __VLS_export;
4
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import type { DisplayRecordProps } from '../../types/index.js';
2
+ declare const __VLS_export: import("vue").DefineComponent<DisplayRecordProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<DisplayRecordProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
3
+ declare const _default: typeof __VLS_export;
4
+ export default _default;