pgo-uiux2 1.0.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 (180) hide show
  1. package/.env +1 -0
  2. package/.env.production +1 -0
  3. package/.prettierrc +13 -0
  4. package/.vscode/extensions.json +3 -0
  5. package/BUTTON_GUIDE.md +257 -0
  6. package/README.md +49 -0
  7. package/THEME_REFERENCE.md +310 -0
  8. package/eslint.config.ts +27 -0
  9. package/index.html +13 -0
  10. package/package.json +85 -0
  11. package/public/favicon.ico +0 -0
  12. package/src/App.vue +368 -0
  13. package/src/assets/fonts/Faruma.ttf +0 -0
  14. package/src/components/examples/AppBarExample.vue +101 -0
  15. package/src/components/examples/AvatarExample.vue +47 -0
  16. package/src/components/examples/BannerExample.vue +287 -0
  17. package/src/components/examples/BaseInputExample.vue +25 -0
  18. package/src/components/examples/BreadcrumbExample.vue +53 -0
  19. package/src/components/examples/CardExample.vue +77 -0
  20. package/src/components/examples/ChipExample.vue +225 -0
  21. package/src/components/examples/DatePickerExample.vue +31 -0
  22. package/src/components/examples/DropdownExample.vue +84 -0
  23. package/src/components/examples/EditorExample.vue +200 -0
  24. package/src/components/examples/ExpansionPanelExample.vue +42 -0
  25. package/src/components/examples/FileUploadExample.vue +40 -0
  26. package/src/components/examples/FormExample.vue +121 -0
  27. package/src/components/examples/HugeTest.vue +8 -0
  28. package/src/components/examples/LayoutContainerExample.vue +80 -0
  29. package/src/components/examples/ModalExample.vue +82 -0
  30. package/src/components/examples/NavDrawerExample.vue +170 -0
  31. package/src/components/examples/NumberFieldExample.vue +145 -0
  32. package/src/components/examples/RadioButtonExample.vue +161 -0
  33. package/src/components/examples/SearchExample.vue +322 -0
  34. package/src/components/examples/SelectExample.vue +121 -0
  35. package/src/components/examples/StackedTableViewExample.vue +53 -0
  36. package/src/components/examples/TabExample.vue +336 -0
  37. package/src/components/examples/TableExample.vue +228 -0
  38. package/src/components/examples/TextFieldExample.vue +181 -0
  39. package/src/components/examples/TextareaExample.vue +173 -0
  40. package/src/components/examples/ThemeToggle.vue +50 -0
  41. package/src/components/examples/TimelineExample.vue +66 -0
  42. package/src/components/examples/TipTapEditorExample.vue +20 -0
  43. package/src/components/examples/TooltipExample.vue +53 -0
  44. package/src/components/examples/VueDatePickerShowcase.vue +214 -0
  45. package/src/components/examples/_DatePickerExample.vue +33 -0
  46. package/src/components/examples/__FormExample.vue +77 -0
  47. package/src/components/index.ts +25 -0
  48. package/src/components/pgo/AppBar.vue +347 -0
  49. package/src/components/pgo/Avatar.vue +139 -0
  50. package/src/components/pgo/Banner.vue +300 -0
  51. package/src/components/pgo/Breadcrumb.vue +101 -0
  52. package/src/components/pgo/Button.vue +171 -0
  53. package/src/components/pgo/Card.vue +178 -0
  54. package/src/components/pgo/ConfirmationModel.vue +32 -0
  55. package/src/components/pgo/DataTable.vue +845 -0
  56. package/src/components/pgo/DatePicker/CalendarPanel.vue +43 -0
  57. package/src/components/pgo/DatePicker/__DatePicker.vue +122 -0
  58. package/src/components/pgo/DatePicker/types.ts +11 -0
  59. package/src/components/pgo/DatePicker/useCalendar.ts +39 -0
  60. package/src/components/pgo/DatePicker/useDatePicker.ts +31 -0
  61. package/src/components/pgo/Deprecated/ToastContainer.vue +51 -0
  62. package/src/components/pgo/Deprecated/ToastItem.vue +55 -0
  63. package/src/components/pgo/Dropdown.vue +296 -0
  64. package/src/components/pgo/DropdownItem.vue +40 -0
  65. package/src/components/pgo/Editor.vue +511 -0
  66. package/src/components/pgo/ExpansionPanel.vue +185 -0
  67. package/src/components/pgo/Footer.vue +39 -0
  68. package/src/components/pgo/HeroIcon.vue +124 -0
  69. package/src/components/pgo/InputSearch.vue +194 -0
  70. package/src/components/pgo/LayoutContainer.vue +104 -0
  71. package/src/components/pgo/Main.vue +37 -0
  72. package/src/components/pgo/Modal.vue +273 -0
  73. package/src/components/pgo/NavDrawer.vue +127 -0
  74. package/src/components/pgo/NavDrawerItem.vue +161 -0
  75. package/src/components/pgo/NavigationDrawer.vue +849 -0
  76. package/src/components/pgo/OLDNavDrawer.vue +661 -0
  77. package/src/components/pgo/OldAppBar.vue +223 -0
  78. package/src/components/pgo/PApp.vue +102 -0
  79. package/src/components/pgo/Pagination.vue +242 -0
  80. package/src/components/pgo/Search copy.vue +310 -0
  81. package/src/components/pgo/Search.vue +411 -0
  82. package/src/components/pgo/StackedTableView.vue +167 -0
  83. package/src/components/pgo/Tab.vue +617 -0
  84. package/src/components/pgo/TestInput.vue +395 -0
  85. package/src/components/pgo/Timeline.vue +367 -0
  86. package/src/components/pgo/TimelineItem.vue +80 -0
  87. package/src/components/pgo/TipTapEditor.vue +315 -0
  88. package/src/components/pgo/Tooltip.NOTES.md +12 -0
  89. package/src/components/pgo/Tooltip.PROPS.md +21 -0
  90. package/src/components/pgo/Tooltip.vue +281 -0
  91. package/src/components/pgo/base/Base.vue +444 -0
  92. package/src/components/pgo/buttons/Chip.vue +324 -0
  93. package/src/components/pgo/buttons/ChipGroup.vue +224 -0
  94. package/src/components/pgo/buttons/Radio.vue +424 -0
  95. package/src/components/pgo/filters/FilterSection.vue +188 -0
  96. package/src/components/pgo/filters/Searchbar.vue +216 -0
  97. package/src/components/pgo/forms/DynamicForm.vue +45 -0
  98. package/src/components/pgo/forms/Form.vue +132 -0
  99. package/src/components/pgo/index.ts +15 -0
  100. package/src/components/pgo/inputs/Checkbox.vue +320 -0
  101. package/src/components/pgo/inputs/DatePicker.vue +395 -0
  102. package/src/components/pgo/inputs/FileUpload.vue +326 -0
  103. package/src/components/pgo/inputs/NumberField.vue +243 -0
  104. package/src/components/pgo/inputs/Radio.vue +162 -0
  105. package/src/components/pgo/inputs/RadioGroup.vue +188 -0
  106. package/src/components/pgo/inputs/Select.vue +535 -0
  107. package/src/components/pgo/inputs/TextField.vue +194 -0
  108. package/src/components/pgo/inputs/Textarea.vue +181 -0
  109. package/src/main.js +12 -0
  110. package/src/pgo-components/_index.js +31 -0
  111. package/src/pgo-components/assets/fonts/Faruma.ttf +0 -0
  112. package/src/pgo-components/assets/fonts/logo.png +0 -0
  113. package/src/pgo-components/composables/useTheme.js +10 -0
  114. package/src/pgo-components/directives/tooltip-directive.ts +393 -0
  115. package/src/pgo-components/index.js +96 -0
  116. package/src/pgo-components/lib/componentConfig.js +147 -0
  117. package/src/pgo-components/lib/core/composables/_useCalendar.ts +127 -0
  118. package/src/pgo-components/lib/core/composables/useDefaults.ts +15 -0
  119. package/src/pgo-components/lib/core/composables/useLanguageSelect.js +0 -0
  120. package/src/pgo-components/lib/core/composables/useRtl.ts +12 -0
  121. package/src/pgo-components/lib/core/defaults/createDefaults.ts +5 -0
  122. package/src/pgo-components/lib/core/defaults/defaults.ts +7 -0
  123. package/src/pgo-components/lib/core/rtl/rtl.ts +3 -0
  124. package/src/pgo-components/lib/core/rtl/setRtl.ts +19 -0
  125. package/src/pgo-components/lib/drawerState.ts +3 -0
  126. package/src/pgo-components/lib/i18n/defaultLables.js +71 -0
  127. package/src/pgo-components/lib/i18n/i18nPlugin.js +52 -0
  128. package/src/pgo-components/lib/i18n/useI18n.js +35 -0
  129. package/src/pgo-components/lib/index.ts +38 -0
  130. package/src/pgo-components/pages/Component.vue +7 -0
  131. package/src/pgo-components/pages/ComponentRenderer.vue +85 -0
  132. package/src/pgo-components/pages/Home.vue +130 -0
  133. package/src/pgo-components/pages/ListView.vue +370 -0
  134. package/src/pgo-components/pages/Page1.vue +296 -0
  135. package/src/pgo-components/pages/_Page1.vue +180 -0
  136. package/src/pgo-components/plugins/SnackBar.vue +251 -0
  137. package/src/pgo-components/plugins/SnackBarContainer.vue +53 -0
  138. package/src/pgo-components/plugins/SnackBarPlugin.ts +136 -0
  139. package/src/pgo-components/plugins/theme-plugin.js +114 -0
  140. package/src/pgo-components/plugins/types.ts +46 -0
  141. package/src/pgo-components/plugins/useSnackBar.js +11 -0
  142. package/src/pgo-components/plugins/useSnackBar.ts +21 -0
  143. package/src/pgo-components/plugins/validation-plugin.js +11 -0
  144. package/src/pgo-components/services/Entry.json +813 -0
  145. package/src/pgo-components/services/axios.js +54 -0
  146. package/src/pgo-components/services/data.json +90 -0
  147. package/src/pgo-components/services/person.json +260 -0
  148. package/src/pgo-components/services/toast.ts +44 -0
  149. package/src/pgo-components/styles/global.css +234 -0
  150. package/src/pgo-components/styles/reset.css +96 -0
  151. package/src/pgo-components/styles/tokens.css +18 -0
  152. package/src/pgo-components/styles/utilities/border-radius.css +57 -0
  153. package/src/pgo-components/styles/utilities/borders.css +85 -0
  154. package/src/pgo-components/styles/utilities/colors.css +38 -0
  155. package/src/pgo-components/styles/utilities/cursor.css +19 -0
  156. package/src/pgo-components/styles/utilities/display.css +78 -0
  157. package/src/pgo-components/styles/utilities/elevation.css +33 -0
  158. package/src/pgo-components/styles/utilities/flex.css +403 -0
  159. package/src/pgo-components/styles/utilities/float.css +41 -0
  160. package/src/pgo-components/styles/utilities/hover.css +9 -0
  161. package/src/pgo-components/styles/utilities/index.css +18 -0
  162. package/src/pgo-components/styles/utilities/opacity.css +27 -0
  163. package/src/pgo-components/styles/utilities/overflow.css +26 -0
  164. package/src/pgo-components/styles/utilities/palette.css +515 -0
  165. package/src/pgo-components/styles/utilities/position.css +14 -0
  166. package/src/pgo-components/styles/utilities/sizing.css +70 -0
  167. package/src/pgo-components/styles/utilities/spacing.css +578 -0
  168. package/src/pgo-components/styles/utilities/transitions.css +58 -0
  169. package/src/pgo-components/styles/utilities/typography.css +91 -0
  170. package/src/pgo-components/styles/utilities/z-index.css +11 -0
  171. package/src/pgo-components/tokens/index.js +337 -0
  172. package/src/router/index.js +88 -0
  173. package/src/shims-vue.d.ts +14 -0
  174. package/src/validations/validationRules.js +50 -0
  175. package/tailwind.config.js +73 -0
  176. package/test.php +5 -0
  177. package/tsconfig.json +25 -0
  178. package/ui +31 -0
  179. package/ui.pgo.mv.conf +18 -0
  180. package/vite.config.js +42 -0
@@ -0,0 +1,367 @@
1
+ <template>
2
+ <div
3
+ class="timeline"
4
+ :class="[
5
+ direction === 'vertical' ? 'timeline--vertical vts-py-2' : 'timeline--horizontal vts-py-6 vts-px-2',
6
+ direction === 'vertical' && side === 'one' ? 'timeline--one' : '',
7
+ direction === 'vertical' && side === 'both' ? 'timeline--both' : '',
8
+ condensed ? 'timeline--condensed' : ''
9
+ ]"
10
+ :style="{ '--timeline-dot-size': dotSizePx + 'px', '--timeline-gap': gapPx + 'px' }"
11
+ >
12
+ <!-- Rail line -->
13
+ <div class="timeline-line" :class="{ 'is-dashed': lineStyle === 'dashed' }"></div>
14
+
15
+ <!-- Vertical items -->
16
+ <div v-if="direction === 'vertical'" class="timeline-items">
17
+ <div v-for="(item, i) in items" :key="item.id ?? i" class="timeline-item" :class="['timeline-item--' + itemSide(i), condensed ? 'vts-mb-3' : 'vts-mb-6']">
18
+ <!-- Dot -->
19
+ <div
20
+ class="timeline-dot vts-border-md vts-border-solid vts-rounded-circle"
21
+ :style="{
22
+ width: dotSizePx + 'px',
23
+ height: dotSizePx + 'px',
24
+ background: statusColor(item),
25
+ borderColor: 'var(--vts-color-surface)'
26
+ }"
27
+ ></div>
28
+
29
+ <!-- Content card -->
30
+ <div
31
+ class="timeline-card"
32
+ :class="['align-' + align, clickable ? 'is-clickable' : '', elevation ? 'elevation-' + elevation : '', 'vts-border-sm vts-border-solid vts-border-color vts-rounded-md vts-py-3 vts-px-4']"
33
+ :style="cardStyle(i)"
34
+ role="group"
35
+ tabindex="0"
36
+ @click="emit('item-click', { item, index: i })"
37
+ @keydown.enter.prevent="emit('item-click', { item, index: i })"
38
+ @keydown.space.prevent="emit('item-click', { item, index: i })"
39
+ >
40
+ <template v-if="hasItemSlot">
41
+ <slot name="item" :item="item" :index="i" />
42
+ </template>
43
+
44
+ <template v-else-if="hasDefaultSlot">
45
+ <slot :item="item" :index="i" />
46
+ </template>
47
+
48
+ <template v-else>
49
+ <div v-if="item.title" class="timeline-title vts-mb-1">{{ item.title }}</div>
50
+ <div v-if="item.time" class="timeline-time vts-mb-2">{{ item.time }}</div>
51
+ <div v-if="item.content" class="timeline-content">{{ item.content }}</div>
52
+ </template>
53
+ </div>
54
+ </div>
55
+ </div>
56
+
57
+ <!-- Horizontal items -->
58
+ <div v-else class="timeline-items timeline-items--horizontal vts-ga-6" :class="[equalizeCards ? 'equalize' : '']">
59
+ <div v-for="(item, i) in items" :key="item.id ?? i" class="timeline-item-h vts-pt-6">
60
+ <div class="timeline-dot vts-border-md vts-border-solid vts-rounded-circle" :style="{ width: dotSizePx + 'px', height: dotSizePx + 'px', background: statusColor(item), borderColor: 'var(--vts-color-surface)' }"></div>
61
+ <div
62
+ class="timeline-card"
63
+ :class="['align-' + align, elevation ? 'elevation-' + elevation : '', 'vts-border-sm vts-border-solid vts-border-color vts-rounded-md vts-py-3 vts-px-4 vts-mt-4']"
64
+ role="group"
65
+ tabindex="0"
66
+ @click="emit('item-click', { item, index: i })"
67
+ @keydown.enter.prevent="emit('item-click', { item, index: i })"
68
+ @keydown.space.prevent="emit('item-click', { item, index: i })"
69
+ >
70
+ <template v-if="hasItemSlot">
71
+ <slot name="item" :item="item" :index="i" />
72
+ </template>
73
+ <template v-else-if="hasDefaultSlot">
74
+ <slot :item="item" :index="i" />
75
+ </template>
76
+ <template v-else>
77
+ <div v-if="item.title" class="timeline-title vts-mb-1">{{ item.title }}</div>
78
+ <div v-if="item.time" class="timeline-time vts-mb-2">{{ item.time }}</div>
79
+ <div v-if="item.content" class="timeline-content">{{ item.content }}</div>
80
+ </template>
81
+ </div>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ </template>
86
+
87
+ <script setup lang="ts">
88
+ import { computed, useSlots } from 'vue'
89
+ import { globalRtl } from '../../pgo-components/lib/core/rtl/rtl'
90
+
91
+ export type TimelineStatus = 'default' | 'primary' | 'success' | 'warning' | 'error' | 'info'
92
+
93
+ export interface TimelineItem {
94
+ id: string | number
95
+ title?: string
96
+ content?: string
97
+ time?: string
98
+ status?: TimelineStatus
99
+ }
100
+
101
+ const props = withDefaults(
102
+ defineProps<{
103
+ items: TimelineItem[]
104
+ direction?: 'vertical' | 'horizontal'
105
+ side?: 'one' | 'both' // vertical only
106
+ align?: 'start' | 'center' | 'end' // content box alignment
107
+ alternate?: boolean // vertical/both: alternate left/right
108
+ rtl?: boolean
109
+ lineStyle?: 'solid' | 'dashed'
110
+ dotShape?: 'circle' | 'diamond'
111
+ dotSize?: 'sm' | 'md' | 'lg'
112
+ clickable?: boolean
113
+ condensed?: boolean
114
+ elevation?: 0 | 1 | 2 | 3
115
+ equalizeCards?: boolean
116
+ gap?: number
117
+ }>(),
118
+ {
119
+ direction: 'vertical',
120
+ side: 'both',
121
+ align: 'start',
122
+ alternate: true,
123
+ lineStyle: 'solid',
124
+ dotShape: 'circle',
125
+ dotSize: 'lg',
126
+ clickable: false,
127
+ condensed: false,
128
+ elevation: 1,
129
+ equalizeCards: true,
130
+ gap: 30
131
+ }
132
+ )
133
+
134
+ const isRtl = computed(() => props.rtl ?? globalRtl.value)
135
+
136
+ // Slots detection for card content customization
137
+ const slots = useSlots()
138
+ const hasItemSlot = computed(() => !!slots.item)
139
+ const hasDefaultSlot = computed(() => !!slots.default)
140
+
141
+ // Vertical line position and dot offsets
142
+ const railWidth = 2
143
+ const dotSizePx = computed(() => (props.dotSize === 'sm' ? 10 : props.dotSize === 'lg' ? 16 : 12))
144
+ const gapPx = computed(() => props.gap ?? 16)
145
+
146
+ function itemSide(index: number) {
147
+ if (props.direction === 'horizontal') return 'bottom'
148
+ if (props.side === 'one') {
149
+ // Content on one side; choose based on RTL
150
+ return isRtl.value ? 'right' : 'left'
151
+ }
152
+ // both sides
153
+ const left = props.alternate ? index % 2 === 0 : true
154
+ const logical = left ? 'left' : 'right'
155
+ return isRtl.value ? (logical === 'left' ? 'right' : 'left') : logical
156
+ }
157
+
158
+ // Inline margin styles for vertical layout, replacing CSS margins
159
+ function cardStyle(index: number) {
160
+ if (props.direction === 'horizontal') return {}
161
+ if (props.side === 'one') {
162
+ return {
163
+ maxWidth: '100%',
164
+ marginLeft: '0',
165
+ marginRight: '0',
166
+ marginInlineStart: gapPx.value + 'px',
167
+ marginInlineEnd: '0'
168
+ }
169
+ }
170
+ const side = itemSide(index) // 'left' or 'right' honoring RTL
171
+ if (side === 'left') {
172
+ return {
173
+ maxWidth: '45%',
174
+ marginLeft: '0',
175
+ marginRight: 'calc(50% + 16px)'
176
+ }
177
+ }
178
+ return {
179
+ maxWidth: '45%',
180
+ marginRight: '0',
181
+ marginLeft: 'calc(50% + 16px)'
182
+ }
183
+ }
184
+
185
+ function statusColor(item: TimelineItem) {
186
+ const s = item.status ?? 'default'
187
+ switch (s) {
188
+ case 'primary':
189
+ return 'var(--vts-color-primary)'
190
+ case 'success':
191
+ return 'var(--vts-color-success, #16a34a)'
192
+ case 'warning':
193
+ return 'var(--vts-color-warning, #f59e0b)'
194
+ case 'error':
195
+ return 'var(--vts-color-error, #dc2626)'
196
+ case 'info':
197
+ return 'var(--vts-color-info, #0ea5e9)'
198
+ default:
199
+ return 'var(--vts-color-borderHeavy)'
200
+ }
201
+ }
202
+
203
+ function onItemClick(item: TimelineItem, index: number) {
204
+ if (!props.clickable) return
205
+ // Emit item-click when clickable
206
+ // defineEmits must be at top in <script setup>
207
+ }
208
+
209
+ const emit = defineEmits<{
210
+ (e: 'item-click', payload: { item: TimelineItem; index: number }): void
211
+ }>()
212
+ </script>
213
+
214
+ <style scoped>
215
+ .timeline {
216
+ position: relative;
217
+ color: var(--vts-color-text);
218
+ }
219
+
220
+
221
+ /* Rail line */
222
+ .timeline-line {
223
+ position: absolute;
224
+ top: 0;
225
+ bottom: 0;
226
+ width: 2px;
227
+ background: var(--vts-color-borderHeavy);
228
+ }
229
+ .timeline-line.is-dashed {
230
+ background-image: linear-gradient(var(--vts-color-borderHeavy) 50%, rgba(0, 0, 0, 0) 0%);
231
+ background-size: 2px 8px;
232
+ background-repeat: repeat-y;
233
+ background-color: transparent;
234
+ }
235
+
236
+ /* Vertical layout */
237
+ .timeline--both .timeline-line {
238
+ left: calc(50% - 1px);
239
+ }
240
+ .timeline--one .timeline-line {
241
+ left: 0;
242
+ }
243
+ :dir(rtl) .timeline--one .timeline-line {
244
+ right: 0;
245
+ left: auto;
246
+ }
247
+
248
+ .timeline-items {
249
+ display: block;
250
+ }
251
+ .timeline-item {
252
+ position: relative;
253
+ clear: both;
254
+ }
255
+ /* Item vertical spacing moved to vts utility classes in template */
256
+
257
+ /* Dot */
258
+ .timeline-dot {
259
+ position: absolute;
260
+ left: calc(50% - (var(--timeline-dot-size, 12px) / 2));
261
+ top: 0.5rem;
262
+ box-shadow: var(--vts-elevation-1, 0 1px 2px rgba(0, 0, 0, 0.1));
263
+ }
264
+ /* In one-side layout, place dot centered on the edge rail (2px wide => center at 1px) */
265
+ .timeline--one .timeline-dot {
266
+ left: calc(1px - (var(--timeline-dot-size, 12px) / 2));
267
+ }
268
+ :dir(rtl) .timeline--one .timeline-dot {
269
+ left: auto;
270
+ right: calc(1px - (var(--timeline-dot-size, 12px) / 2));
271
+ }
272
+ /* Item side placement */
273
+ /* Item side placement moved to inline styles on card */
274
+
275
+ /* One-side overrides moved to inline styles on card */
276
+
277
+ /* Card appearance */
278
+ .timeline-card {
279
+ background: var(--vts-color-surfaceElevated);
280
+ box-shadow: var(--vts-elevation-1, 0 1px 3px rgba(0, 0, 0, 0.12));
281
+ }
282
+ .timeline-card.elevation-0 {
283
+ box-shadow: none;
284
+ }
285
+ .timeline-card.elevation-2 {
286
+ box-shadow: var(--vts-elevation-2, 0 4px 12px rgba(0, 0, 0, 0.12));
287
+ }
288
+ .timeline-card.elevation-3 {
289
+ box-shadow: var(--vts-elevation-3, 0 10px 20px rgba(0, 0, 0, 0.2));
290
+ }
291
+ .timeline-card.is-clickable {
292
+ cursor: pointer;
293
+ }
294
+
295
+ /* Alignment inside card */
296
+ .timeline-card.align-start {
297
+ text-align: left;
298
+ }
299
+ .timeline-card.align-center {
300
+ text-align: center;
301
+ }
302
+ .timeline-card.align-end {
303
+ text-align: right;
304
+ }
305
+ :dir(rtl) .timeline-card.align-start {
306
+ text-align: right;
307
+ }
308
+ :dir(rtl) .timeline-card.align-end {
309
+ text-align: left;
310
+ }
311
+
312
+ .timeline-title {
313
+ font-weight: 600;
314
+ }
315
+ .timeline-time {
316
+ color: var(--vts-color-textSecondary);
317
+ font-size: 0.8125rem;
318
+ }
319
+
320
+ /* Horizontal layout */
321
+ .timeline--horizontal .timeline-line {
322
+ left: 0;
323
+ right: 0;
324
+ /* Place rail through dot centers: padding-top (24px) + half dot size */
325
+ top: calc(24px + (var(--timeline-dot-size, 12px) / 2));
326
+ height: 2px;
327
+ width: auto;
328
+ background: var(--vts-color-borderHeavy);
329
+ }
330
+ .timeline--horizontal .timeline-line.is-dashed {
331
+ /* Horizontal dashed rail */
332
+ background-image: repeating-linear-gradient(
333
+ to right,
334
+ var(--vts-color-borderHeavy) 0,
335
+ var(--vts-color-borderHeavy) 4px,
336
+ transparent 4px,
337
+ transparent 8px
338
+ );
339
+ background-color: transparent;
340
+ }
341
+ .timeline-items--horizontal {
342
+ display: flex;
343
+ align-items: flex-start; /* ensure all items share the same top baseline */
344
+ justify-content: space-between;
345
+ position: relative;
346
+ }
347
+ .timeline-items--horizontal.equalize {
348
+ align-items: stretch;
349
+ }
350
+ .timeline-item-h {
351
+ position: relative;
352
+ display: flex;
353
+ flex-direction: column;
354
+ flex: 1 1 0;
355
+ }
356
+ .timeline-item-h .timeline-dot {
357
+ position: absolute;
358
+ left: 50%;
359
+ transform: translateX(-50%);
360
+ top: 0;
361
+ box-shadow: var(--vts-elevation-1, 0 1px 2px rgba(0, 0, 0, 0.1));
362
+ }
363
+
364
+ .timeline-items--horizontal.equalize .timeline-item-h .timeline-card {
365
+ flex: 1 1 auto;
366
+ }
367
+ </style>
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <div class="v-timeline-item">
3
+ <!-- Opposite -->
4
+ <div class="v-timeline-item__opposite vts-py-2 vts-px-4">
5
+ <slot name="opposite" />
6
+ </div>
7
+
8
+ <!-- Dot -->
9
+ <div v-if="!hideDot" class="v-timeline-item__dot vts-rounded-circle vts-mt-3" :style="{ background: color }">
10
+ <slot name="icon">
11
+ <span v-if="icon" class="v-timeline-item__icon">{{ icon }}</span>
12
+ </slot>
13
+ </div>
14
+
15
+ <!-- Content -->
16
+ <div class="v-timeline-item__content vts-py-2 vts-px-4 vts-rounded-md">
17
+ <slot />
18
+ </div>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { computed, inject } from 'vue'
24
+
25
+ const timeline = inject<any>('timeline')
26
+
27
+ const props = withDefaults(
28
+ defineProps<{
29
+ color?: string
30
+ icon?: string
31
+ dot?: boolean
32
+ hideDot?: boolean
33
+ }>(),
34
+ {
35
+ color: '#1976D2',
36
+ dot: true
37
+ }
38
+ )
39
+
40
+ const classes = computed(() => ({
41
+ 'v-timeline-item': true,
42
+ 'v-timeline-item--alternate': timeline?.align === 'alternate'
43
+ }))
44
+ </script>
45
+
46
+
47
+
48
+ <style scoped>
49
+ .v-timeline-item {
50
+ display: flex;
51
+ position: relative;
52
+ min-height: 48px;
53
+ }
54
+
55
+ .v-timeline-item__opposite,
56
+ .v-timeline-item__content {
57
+ width: 45%;
58
+ }
59
+
60
+ .v-timeline-item__dot {
61
+ width: 20px;
62
+ height: 20px;
63
+ position: relative;
64
+ z-index: 1;
65
+ }
66
+
67
+ .v-timeline-item__icon {
68
+ color: white;
69
+ font-size: 12px;
70
+ display: flex;
71
+ justify-content: center;
72
+ align-items: center;
73
+ height: 100%;
74
+ }
75
+
76
+ .v-timeline-item__content {
77
+ background: #fff;
78
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
79
+ }
80
+ </style>