sprintify-ui 0.10.87 → 0.11.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 (116) hide show
  1. package/dist/{BaseCkeditor-Laq0HbvP.js → BaseCkeditor-Dcqohrsz.js} +14 -14
  2. package/dist/sprintify-ui.es.js +12480 -12553
  3. package/dist/style.css +2 -2
  4. package/dist/types/components/BaseActionItem.vue.d.ts +11 -5
  5. package/dist/types/components/BaseAddressForm.vue.d.ts +1 -1
  6. package/dist/types/components/BaseAlert.vue.d.ts +3 -21
  7. package/dist/types/components/BaseApp.vue.d.ts +2 -9
  8. package/dist/types/components/BaseAutocomplete.vue.d.ts +19 -643
  9. package/dist/types/components/BaseAutocompleteDrawer.vue.d.ts +21 -104
  10. package/dist/types/components/BaseAutocompleteFetch.vue.d.ts +26 -1045
  11. package/dist/types/components/BaseAvatarGroup.vue.d.ts +1 -1
  12. package/dist/types/components/BaseBadge.vue.d.ts +3 -20
  13. package/dist/types/components/BaseBelongsTo.vue.d.ts +19 -1022
  14. package/dist/types/components/BaseBelongsToFetch.vue.d.ts +10 -745
  15. package/dist/types/components/BaseButton.vue.d.ts +6 -77
  16. package/dist/types/components/BaseButtonGroup.vue.d.ts +3 -159
  17. package/dist/types/components/BaseCard.vue.d.ts +2 -23
  18. package/dist/types/components/BaseCardRow.vue.d.ts +2 -16
  19. package/dist/types/components/BaseCkeditor.vue.d.ts +1 -1
  20. package/dist/types/components/BaseClipboard.vue.d.ts +2 -42
  21. package/dist/types/components/BaseCollapse.vue.d.ts +2 -26
  22. package/dist/types/components/BaseContainer.vue.d.ts +2 -12
  23. package/dist/types/components/BaseCounter.vue.d.ts +1 -1
  24. package/dist/types/components/BaseCropper.vue.d.ts +3 -35
  25. package/dist/types/components/BaseDataIterator.vue.d.ts +18 -11
  26. package/dist/types/components/BaseDataIteratorSectionBox.vue.d.ts +2 -10
  27. package/dist/types/components/BaseDataIteratorSectionModal.vue.d.ts +2 -16
  28. package/dist/types/components/BaseDataTable.vue.d.ts +54 -2141
  29. package/dist/types/components/BaseDataTableTemplate.vue.d.ts +2 -584
  30. package/dist/types/components/BaseDatePicker.vue.d.ts +2 -2
  31. package/dist/types/components/BaseDescriptionList.vue.d.ts +2 -7
  32. package/dist/types/components/BaseDescriptionListItem.vue.d.ts +2 -9
  33. package/dist/types/components/BaseDialog.vue.d.ts +3 -110
  34. package/dist/types/components/BaseDisplayRelativeTime.vue.d.ts +2 -51
  35. package/dist/types/components/BaseDraggable.vue.d.ts +2 -18
  36. package/dist/types/components/BaseDropdown.vue.d.ts +2 -147
  37. package/dist/types/components/BaseDropdownAutocomplete.vue.d.ts +3 -124
  38. package/dist/types/components/BaseField.vue.d.ts +3 -99
  39. package/dist/types/components/BaseFilePicker.vue.d.ts +2 -28
  40. package/dist/types/components/BaseFilePickerCrop.vue.d.ts +2 -80
  41. package/dist/types/components/BaseFileUploader.vue.d.ts +3 -173
  42. package/dist/types/components/BaseForm.vue.d.ts +3 -150
  43. package/dist/types/components/BaseGantt.vue.d.ts +40 -1141
  44. package/dist/types/components/BaseHasMany.vue.d.ts +18 -577
  45. package/dist/types/components/BaseHasManyFetch.vue.d.ts +3 -589
  46. package/dist/types/components/BaseInput.vue.d.ts +3 -3
  47. package/dist/types/components/BaseInputError.vue.d.ts +2 -19
  48. package/dist/types/components/BaseInputPercent.vue.d.ts +1 -1
  49. package/dist/types/components/BaseLayoutSidebar.vue.d.ts +2 -112
  50. package/dist/types/components/BaseLayoutSidebarConfigurable.vue.d.ts +2 -113
  51. package/dist/types/components/BaseLayoutStacked.vue.d.ts +2 -52
  52. package/dist/types/components/BaseLayoutStackedConfigurable.vue.d.ts +2 -117
  53. package/dist/types/components/BaseLazy.vue.d.ts +2 -13
  54. package/dist/types/components/BaseMediaGallery.vue.d.ts +3 -3
  55. package/dist/types/components/BaseMediaGalleryItem.vue.d.ts +1 -1
  56. package/dist/types/components/BaseMediaLibrary.vue.d.ts +3 -207
  57. package/dist/types/components/BaseMediaList.vue.d.ts +3 -3
  58. package/dist/types/components/BaseMediaListItem.vue.d.ts +1 -1
  59. package/dist/types/components/BaseMediaPictures.vue.d.ts +3 -3
  60. package/dist/types/components/BaseMediaPicturesItem.vue.d.ts +1 -1
  61. package/dist/types/components/BaseMenu.vue.d.ts +2 -209
  62. package/dist/types/components/BaseMenuItem.vue.d.ts +1 -1
  63. package/dist/types/components/BaseModalCenter.vue.d.ts +2 -83
  64. package/dist/types/components/BaseModalSide.vue.d.ts +2 -80
  65. package/dist/types/components/BaseNavbar.vue.d.ts +2 -83
  66. package/dist/types/components/BasePassword.vue.d.ts +1 -1
  67. package/dist/types/components/BaseRadioGroup.vue.d.ts +2 -107
  68. package/dist/types/components/BaseReadMore.vue.d.ts +2 -28
  69. package/dist/types/components/BaseRichText.vue.d.ts +1 -1
  70. package/dist/types/components/BaseSelect.vue.d.ts +4 -148
  71. package/dist/types/components/BaseShortcut.vue.d.ts +1 -1
  72. package/dist/types/components/BaseSideNavigation.vue.d.ts +2 -7
  73. package/dist/types/components/BaseSideNavigationItem.vue.d.ts +3 -19
  74. package/dist/types/components/BaseSkeleton.vue.d.ts +1 -1
  75. package/dist/types/components/BaseSwitch.vue.d.ts +3 -120
  76. package/dist/types/components/BaseSystemAlert.vue.d.ts +3 -55
  77. package/dist/types/components/BaseTabItem.vue.d.ts +4 -27
  78. package/dist/types/components/BaseTable.vue.d.ts +3 -24
  79. package/dist/types/components/BaseTableBody.vue.d.ts +2 -4
  80. package/dist/types/components/BaseTableCell.vue.d.ts +6 -36
  81. package/dist/types/components/BaseTableColumn.vue.d.ts +4 -4
  82. package/dist/types/components/BaseTableHead.vue.d.ts +2 -9
  83. package/dist/types/components/BaseTableHeader.vue.d.ts +4 -40
  84. package/dist/types/components/BaseTableRow.vue.d.ts +4 -38
  85. package/dist/types/components/BaseTabs.vue.d.ts +2 -16
  86. package/dist/types/components/BaseTagAutocomplete.vue.d.ts +25 -571
  87. package/dist/types/components/BaseTagAutocompleteFetch.vue.d.ts +3 -796
  88. package/dist/types/components/BaseTextarea.vue.d.ts +1 -1
  89. package/dist/types/components/BaseTextareaAutoresize.vue.d.ts +1 -1
  90. package/dist/types/components/BaseTimePicker.vue.d.ts +1 -1
  91. package/dist/types/components/BaseTooltip.vue.d.ts +2 -35
  92. package/dist/types/services/gantt/types.d.ts +18 -8
  93. package/package.json +6 -9
  94. package/src/changelog.mdx +1 -1
  95. package/src/components/BaseAssign.mdx +1 -1
  96. package/src/components/BaseAutocomplete.stories.js +10 -0
  97. package/src/components/BaseAutocomplete.vue +11 -1
  98. package/src/components/BaseAutocompleteDrawer.vue +52 -1
  99. package/src/components/BaseAutocompleteFetch.stories.js +6 -0
  100. package/src/components/BaseAutocompleteFetch.vue +15 -0
  101. package/src/components/BaseBelongsTo.stories.js +5 -0
  102. package/src/components/BaseBelongsTo.vue +10 -0
  103. package/src/components/BaseBelongsToFetch.stories.js +6 -0
  104. package/src/components/BaseBelongsToFetch.vue +9 -0
  105. package/src/components/BaseForm.mdx +1 -1
  106. package/src/components/BaseGantt.mdx +79 -0
  107. package/src/components/BaseGantt.stories.js +25 -10
  108. package/src/components/BaseGantt.vue +192 -58
  109. package/src/components/BaseHasMany.stories.js +5 -0
  110. package/src/components/BaseHasMany.vue +10 -0
  111. package/src/components/BaseHasManyFetch.stories.js +12 -0
  112. package/src/components/BaseTagAutocomplete.stories.js +5 -0
  113. package/src/components/BaseTagAutocomplete.vue +34 -1
  114. package/src/components/BaseTagAutocompleteFetch.stories.js +6 -0
  115. package/src/services/gantt/format.ts +30 -7
  116. package/src/services/gantt/types.ts +18 -8
@@ -8,7 +8,7 @@
8
8
  <!-- Sidebar -->
9
9
  <div
10
10
  class="border-r border-slate-300 relative shrink-0"
11
- :style="{ minWidth: `${SIDEBAR_WIDTH}px` }"
11
+ :style="{ width: `${props.sidebarWidth}px` }"
12
12
  >
13
13
  <!-- Top-left Corner-->
14
14
  <div
@@ -30,22 +30,68 @@
30
30
  <li
31
31
  v-for="row in rowsInternal"
32
32
  :key="row.id"
33
- class="border-b border-slate-300 flex last:border-none"
34
- :style="{
35
- height: `${props.rowHeight}px`,
36
- }"
37
- @click="$emit('row:click', row)"
33
+ class="block border-b border-slate-300 last:border-none"
38
34
  >
39
- <slot
40
- name="sidebarItem"
41
- :row="row"
35
+ <div
36
+ :style="{
37
+ height: row.height + 'px',
38
+ }"
39
+ class="w-full flex overflow-hidden"
42
40
  >
43
- <div class="px-2 flex items-center">
44
- <p class="font-semibold text-sm">
45
- {{ row.name }}
46
- </p>
41
+ <button
42
+ type="button"
43
+ class="p-1 shrink-0 block"
44
+ @click="toggleRow(row.id)"
45
+ >
46
+ <BaseIcon
47
+ icon="mdi:chevron-down"
48
+ :class="{
49
+ 'rotate-0': isRowExpanded(row.id),
50
+ '-rotate-90': !isRowExpanded(row.id),
51
+ }"
52
+ class="transition-transform duration-200"
53
+ />
54
+ </button>
55
+ <div
56
+ class="w-full overflow-hidden grow"
57
+ @click="$emit('row:click', row)"
58
+ >
59
+ <slot
60
+ name="sidebarRow"
61
+ :row="row"
62
+ >
63
+ <div class="px-1 py-1 h-full flex items-center">
64
+ <p class="font-semibold leading-tight truncate text-xs">
65
+ {{ row.name }}
66
+ </p>
67
+ </div>
68
+ </slot>
69
+ </div>
70
+ </div>
71
+ <template
72
+ v-if="isRowExpanded(row.id)"
73
+ >
74
+ <div
75
+ v-for="item in row.items"
76
+ :key="item.id"
77
+ :style="{
78
+ height: item.height + 'px'
79
+ }"
80
+ class="w-full border-t overflow-hidden"
81
+ @click="$emit('item:click', item)"
82
+ >
83
+ <slot
84
+ name="sidebarItem"
85
+ :item="item"
86
+ >
87
+ <div class="pr-1 pl-4 py-1 h-full flex items-center">
88
+ <p class="leading-tight truncate text-slate-600 text-xs">
89
+ {{ item.name }}
90
+ </p>
91
+ </div>
92
+ </slot>
47
93
  </div>
48
- </slot>
94
+ </template>
49
95
  </li>
50
96
  </ul>
51
97
  </div>
@@ -138,49 +184,95 @@
138
184
 
139
185
  <ul
140
186
  ref="itemsRef"
141
- class="relative w-full overflow-scroll grow"
187
+ class="relative block w-full overflow-scroll grow"
142
188
  >
143
189
  <li
144
190
  v-for="row in rowsInternal"
145
191
  :key="row.id"
146
- class="border-b relative border-slate-300 last:border-none"
147
192
  :style="{
148
- height: `${props.rowHeight}px`,
149
193
  width: `${width}px`,
150
194
  }"
195
+ class="border-b border-slate-300 w-full"
151
196
  >
152
- <button
153
- v-for="item in row.items"
154
- :key="item.id"
155
- type="button"
156
- class="absolute flex"
197
+ <div
198
+ class="block relative"
157
199
  :style="{
158
- transform: `translate(${item.x}px, ${item.y}px)`,
159
- height: item.height + 'px',
160
- width: item.width + 'px',
200
+ height: `${row.height}px`,
161
201
  }"
162
- :title="`${item.name} - ${item.start.toFormat('yyyy-MM-dd HH:mm:ss')} - ${item.end.toFormat('yyyy-MM-dd HH:mm:ss')}`"
163
- @click="$emit('item:click', item)"
164
202
  >
165
- <slot
166
- name="item"
167
- :item="item"
203
+ <button
204
+ type="button"
205
+ class="absolute flex"
206
+ :style="{
207
+ transform: `translate(${row.x}px, ${row.y}px)`,
208
+ height: row.barHeight + 'px',
209
+ width: row.width + 'px',
210
+ }"
211
+ :title="`${row.name} - ${row.start.toFormat('yyyy-MM-dd HH:mm:ss')} - ${row.end.toFormat('yyyy-MM-dd HH:mm:ss')}`"
212
+ @click="$emit('row:click', row)"
168
213
  >
169
- <div
214
+ <slot
215
+ name="row"
216
+ :row="row"
217
+ >
218
+ <div
219
+ :style="{
220
+ backgroundColor: 'gray',
221
+ }"
222
+ class="flex w-full h-full items-center rounded hover:opacity-80 duration-200"
223
+ >
224
+ <p
225
+ class="text-white text-xs px-2 py-1 truncate"
226
+ style="text-shadow: 0.5px 0.5px rgba(0,0,0,0.1);"
227
+ >
228
+ {{ row.name }}
229
+ </p>
230
+ </div>
231
+ </slot>
232
+ </button>
233
+ </div>
234
+
235
+ <div v-if="isRowExpanded(row.id)">
236
+ <div
237
+ v-for="item in row.items"
238
+ :key="row.id + '-' + item.id"
239
+ class="block border-t relative border-slate-200 w-full"
240
+ :style="{
241
+ height: `${item.height}px`,
242
+ }"
243
+ >
244
+ <button
245
+ type="button"
246
+ class="absolute flex"
170
247
  :style="{
171
- backgroundColor: item.color,
248
+ transform: `translate(${item.x}px, ${item.y}px)`,
249
+ height: item.barHeight + 'px',
250
+ width: item.width + 'px',
172
251
  }"
173
- class="flex w-full h-full items-center rounded hover:opacity-80 duration-200"
252
+ :title="`${item.name} - ${item.start.toFormat('yyyy-MM-dd HH:mm:ss')} - ${item.end.toFormat('yyyy-MM-dd HH:mm:ss')}`"
253
+ @click="$emit('item:click', item)"
174
254
  >
175
- <p
176
- class="text-white text-xs font-medium px-2 py-1 truncate"
177
- style="text-shadow: 0.5px 0.5px rgba(0,0,0,0.1);"
255
+ <slot
256
+ name="item"
257
+ :item="item"
178
258
  >
179
- {{ item.name }}
180
- </p>
181
- </div>
182
- </slot>
183
- </button>
259
+ <div
260
+ :style="{
261
+ backgroundColor: item.color,
262
+ }"
263
+ class="flex w-full h-full items-center rounded hover:opacity-80 duration-200"
264
+ >
265
+ <p
266
+ class="text-white text-xs px-2 py-1 truncate"
267
+ style="text-shadow: 0.5px 0.5px rgba(0,0,0,0.1);"
268
+ >
269
+ {{ item.name }}
270
+ </p>
271
+ </div>
272
+ </slot>
273
+ </button>
274
+ </div>
275
+ </div>
184
276
  </li>
185
277
  </ul>
186
278
 
@@ -264,31 +356,55 @@
264
356
  <script lang="ts" setup>
265
357
  import { useElementSize, useScroll } from '@vueuse/core';
266
358
  import { Format } from '@/services/gantt/format';
267
- import { FormatConfig, GanttRow, GanttRowFormatted, Group, Tick, NowLine } from '@/services/gantt/types';
268
- import { debounce } from 'lodash';
359
+ import { FormatConfig, GanttRow, GanttRowFormatted, Group, Tick, NowLine, GanttItemFormatted } from '@/services/gantt/types';
360
+ import { cloneDeep, debounce } from 'lodash';
269
361
  import { slate } from 'tailwindcss/colors';
362
+ import { VNode } from 'vue';
363
+
364
+ interface Props {
365
+ /**
366
+ * Rows to display in the Gantt chart
367
+ */
368
+ rows: GanttRow[];
369
+ /**
370
+ * Width of the sidebar in pixels
371
+ */
372
+ sidebarWidth?: number;
373
+ /**
374
+ * Height of each row in pixels
375
+ */
376
+ rowHeight?: number;
377
+ /**
378
+ * Maximum height of the Gantt chart in pixels. The chart will be scrollable if the content exceeds this height.
379
+ */
380
+ maxHeight?: number;
381
+ /**
382
+ * Whether to include a "now" line in the Gantt chart
383
+ */
384
+ includeToday?: boolean;
385
+ }
270
386
 
271
- const props = withDefaults(defineProps<{
272
- rows: GanttRow[],
273
- rowHeight?: number,
274
- rowPadding?: number,
275
- maxHeight?: number,
276
- includeToday?: boolean,
277
- }>(), {
387
+ const props = withDefaults(defineProps<Props>(), {
388
+ sidebarWidth: 150,
278
389
  rowHeight: 40,
279
- rowPadding: 4,
280
390
  maxHeight: undefined,
281
391
  includeToday: true,
282
392
  });
283
393
 
284
- defineEmits([
285
- 'item:click',
286
- 'row:click',
287
- ]);
394
+ defineEmits<{
395
+ (e: 'row:click', row: GanttRowFormatted): void;
396
+ (e: 'item:click', item: GanttItemFormatted): void;
397
+ }>();
398
+
399
+ defineSlots<{
400
+ sidebarRow: (props: { row: GanttRowFormatted }) => VNode[];
401
+ sidebarItem: (props: { item: GanttItemFormatted }) => VNode[];
402
+ row: (props: { row: GanttRowFormatted }) => VNode[];
403
+ item: (props: { item: GanttItemFormatted }) => VNode[];
404
+ }>();
288
405
 
289
406
  // Config
290
407
 
291
- const SIDEBAR_WIDTH = 120;
292
408
  const HEADER_HEIGHT = 40;
293
409
 
294
410
  // Init
@@ -308,9 +424,9 @@ const nowLine = ref<NowLine | null>(null);
308
424
  const config = computed<FormatConfig>(() => {
309
425
  return {
310
426
  rows: props.rows,
427
+ sidebarWidth: props.sidebarWidth,
311
428
  minWidth: contentSize.width.value,
312
429
  rowHeight: props.rowHeight,
313
- rowPadding: props.rowPadding,
314
430
  includeToday: props.includeToday,
315
431
  };
316
432
  });
@@ -328,6 +444,8 @@ function init() {
328
444
 
329
445
  nowLine.value = format.nowLine;
330
446
 
447
+ expandedRows.value = new Set(props.rows.map((r) => r.id));
448
+
331
449
  // Scroll to now line
332
450
 
333
451
  nextTick(() => {
@@ -370,7 +488,7 @@ const currentGroup = computed<Group | undefined>(() => {
370
488
 
371
489
  const offsetLeft = -scrollX.value;
372
490
 
373
- return groups.value
491
+ return cloneDeep(groups.value)
374
492
  // Sort by x descending
375
493
  .sort((a, b) => {
376
494
  return b.x - a.x;
@@ -381,4 +499,20 @@ const currentGroup = computed<Group | undefined>(() => {
381
499
  });
382
500
  });
383
501
 
502
+ // Toggle items
503
+
504
+ const expandedRows = ref<Set<string | number>>(new Set());
505
+
506
+ function toggleRow(rowId: string | number) {
507
+ if (expandedRows.value.has(rowId)) {
508
+ expandedRows.value.delete(rowId);
509
+ } else {
510
+ expandedRows.value.add(rowId);
511
+ }
512
+ }
513
+
514
+ function isRowExpanded(rowId: string | number): boolean {
515
+ return expandedRows.value.has(rowId);
516
+ }
517
+
384
518
  </script>
@@ -16,6 +16,11 @@ export default {
16
16
  options: options,
17
17
  field: "label",
18
18
  primaryKey: "value",
19
+ optionColor: (option) => {
20
+ if (option.type === "jedi") return "blue";
21
+ if (option.type === "sith") return "black";
22
+ return "gray";
23
+ }
19
24
  },
20
25
  decorators: [() => ({ template: '<div class="mb-36"><story/></div>' })],
21
26
  };
@@ -12,6 +12,8 @@
12
12
  :size="size"
13
13
  :has-error="hasError"
14
14
  :max="max"
15
+ :option-color="optionColor"
16
+ :option-icon="optionIcon"
15
17
  @update:model-value="onUpdate"
16
18
  >
17
19
  <template #items="itemProps">
@@ -96,6 +98,14 @@ const props = defineProps({
96
98
  default: false,
97
99
  type: Boolean,
98
100
  },
101
+ optionColor: {
102
+ default: undefined,
103
+ type: Function as PropType<(option: RawOption) => string>,
104
+ },
105
+ optionIcon: {
106
+ default: undefined,
107
+ type: Function as PropType<(option: RawOption) => string>,
108
+ },
99
109
  });
100
110
 
101
111
  const emit = defineEmits(['update:modelValue']);
@@ -22,6 +22,18 @@ export default {
22
22
  const params = QueryString.stringify({ filter: { id: ids } });
23
23
  return `https://faker.witify.io/api/todos?${params}`;
24
24
  },
25
+ optionColor: (option) => {
26
+ if (option.type === "work") return "green";
27
+ if (option.type === "personal") return "blue";
28
+ if (option.type === "family") return "purple";
29
+ return "gray";
30
+ },
31
+ optionIcon: (option) => {
32
+ if (option.type === "work") return "heroicons-solid:briefcase";
33
+ if (option.type === "personal") return "heroicons-solid:user-circle";
34
+ if (option.type === "family") return "heroicons-solid:home";
35
+ return "heroicons-solid:tag";
36
+ }
25
37
  },
26
38
  decorators: [() => ({ template: '<div class="mb-36"><story/></div>' })],
27
39
  };
@@ -22,6 +22,11 @@ export default {
22
22
  labelKey: "label",
23
23
  valueKey: "value",
24
24
  options: options,
25
+ optionColor: (option) => {
26
+ if (option.type === "jedi") return "blue";
27
+ if (option.type === "sith") return "black";
28
+ return "gray";
29
+ }
25
30
  },
26
31
  decorators: [() => ({ template: '<div class="mb-36"><story/></div>' })],
27
32
  };
@@ -17,8 +17,30 @@
17
17
  >
18
18
  <div
19
19
  :title="selection.label"
20
- class="truncate"
20
+ class="truncate flex gap-2 items-center"
21
21
  >
22
+ <div
23
+ v-if="optionIcon && selection.option"
24
+ class="shrink-0"
25
+ >
26
+ <BaseIcon
27
+ :icon="optionIcon(selection.option)"
28
+ class="shrink-0"
29
+ :color="optionColor ? optionColor(selection.option) : 'gray'"
30
+ />
31
+ </div>
32
+ <div
33
+ v-else-if="optionColor && selection.option"
34
+ class="shrink-0"
35
+ >
36
+ <div
37
+ class="shrink-0 rounded-full h-2.5 w-2.5"
38
+ :style="{
39
+ backgroundColor: optionColor(selection.option),
40
+ }"
41
+ />
42
+ </div>
43
+
22
44
  {{ selection.label }}
23
45
  </div>
24
46
 
@@ -70,6 +92,8 @@
70
92
  :loading="loading"
71
93
  :loading-bottom="loadingBottom"
72
94
  tw-drawer="p-1"
95
+ :option-color="optionColor"
96
+ :option-icon="optionIcon"
73
97
  :keywords="keywords"
74
98
  @select="onSelect"
75
99
  @scroll-bottom="emit('scrollBottom')"
@@ -112,6 +136,7 @@ import { t } from '@/i18n';
112
136
  import { Size, sizes } from '@/utils/sizes';
113
137
  import { autoUpdate, flip, offset, useFloating } from '@floating-ui/vue';
114
138
  import { useElementBounding } from '@vueuse/core';
139
+ import { BaseIcon } from '.';
115
140
 
116
141
  const snackbars = useSnackbarsStore();
117
142
 
@@ -193,6 +218,14 @@ const props = defineProps({
193
218
  default: true,
194
219
  type: Boolean,
195
220
  },
221
+ optionColor: {
222
+ default: undefined,
223
+ type: Function as PropType<(option: RawOption) => string>,
224
+ },
225
+ optionIcon: {
226
+ default: undefined,
227
+ type: Function as PropType<(option: RawOption) => string>,
228
+ },
196
229
  });
197
230
 
198
231
  const emit = defineEmits([
@@ -16,6 +16,12 @@ export default {
16
16
  url: "https://faker.witify.io/api/todos",
17
17
  labelKey: "name",
18
18
  valueKey: "id",
19
+ optionColor: (option) => {
20
+ if (option.type === "work") return "green";
21
+ if (option.type === "personal") return "blue";
22
+ if (option.type === "family") return "purple";
23
+ return "gray";
24
+ },
19
25
  },
20
26
  decorators: [() => ({ template: '<div class="mb-36"><story/></div>' })],
21
27
  };
@@ -1,6 +1,9 @@
1
1
  import { DateTime } from "luxon";
2
2
  import { FormatConfig, GanttItem, GanttItemFormatted, GanttRow, GanttRowFormatted, NowLine } from "./types";
3
3
  import { Timescale } from "./timescale";
4
+ import { sum } from "lodash";
5
+
6
+ const PADDING_Y_ROW = 4;
4
7
 
5
8
  export class Format {
6
9
 
@@ -35,22 +38,36 @@ export class Format {
35
38
  row.items.forEach((item) => {
36
39
 
37
40
  const x = (item.start.toMillis() - min.toMillis()) * millisecondToPixel;
38
- const y = this.config.rowPadding;
41
+ const y = PADDING_Y_ROW;
39
42
  const width = item.milliseconds * millisecondToPixel;
40
- const height = this.config.rowHeight - (this.config.rowPadding * 2);
43
+ const height = item.height - PADDING_Y_ROW * 2;
41
44
 
42
45
  item.x = x;
43
46
  item.y = y;
44
47
  item.width = width;
45
- item.height = height;
48
+ item.barHeight = height;
46
49
  });
50
+
51
+ const x = Math.min(...row.items.map((item) => item.x));
52
+ const y = PADDING_Y_ROW;
53
+ const height = row.height - (PADDING_Y_ROW * 2);
54
+ const width = Math.max(...row.items.map((item) => item.x + item.width)) - x;
55
+ const start = DateTime.min(...row.items.map((item) => item.start)) as DateTime;
56
+ const end = DateTime.max(...row.items.map((item) => item.end)) as DateTime;
57
+
58
+ row.x = x;
59
+ row.y = y;
60
+ row.barHeight = height;
61
+ row.width = width;
62
+ row.start = start;
63
+ row.end = end;
47
64
  });
48
65
 
49
66
  const today = DateTime.local().startOf(timescale.scale.tick.step);
50
67
 
51
68
  let nowLine = null;
52
69
 
53
- if (today >= min && today <= max) {
70
+ if (today >= min && today <= max && this.config.includeToday) {
54
71
  nowLine = {
55
72
  x: (today.toMillis() - min.toMillis()) * millisecondToPixel,
56
73
  } as NowLine;
@@ -61,7 +78,7 @@ export class Format {
61
78
  min,
62
79
  max,
63
80
  millisecondToPixel,
64
- height: this.config.rowHeight * this.rows.length,
81
+ height: sum(rowsFormatted.map((r) => r.height + sum(r.items.map((i) => i.height)))),
65
82
  width: timescale.width,
66
83
  groups: timescale.groups,
67
84
  ticks: timescale.ticks,
@@ -85,7 +102,13 @@ export class Format {
85
102
  name: row.name,
86
103
  meta: row.meta,
87
104
  items: itemsFormatted,
88
- };
105
+ height: row.height ?? this.config.rowHeight,
106
+ width: 0,
107
+ start: DateTime.now(),
108
+ end: DateTime.now(),
109
+ x: 0,
110
+ y: 0,
111
+ } as GanttRowFormatted;
89
112
  }
90
113
 
91
114
  formatGanttItem(item: GanttItem): GanttItemFormatted {
@@ -104,7 +127,7 @@ export class Format {
104
127
  x: 0,
105
128
  y: 0,
106
129
  width: 0,
107
- height: 0,
130
+ height: item.height ?? this.config.rowHeight,
108
131
  } as GanttItemFormatted;
109
132
  }
110
133
 
@@ -4,6 +4,7 @@ export interface GanttItem {
4
4
  id: number | string;
5
5
  start: string;
6
6
  end: string;
7
+ height?: number;
7
8
  name: string;
8
9
  meta?: Record<string, unknown>;
9
10
  color: string;
@@ -14,34 +15,43 @@ export interface GanttRow {
14
15
  name: string;
15
16
  meta?: Record<string, unknown>;
16
17
  items: GanttItem[];
18
+ height?: number;
17
19
  }
18
20
 
19
21
  export interface GanttRowFormatted {
20
22
  id: number | string;
21
23
  name: string;
22
- meta?: Record<string, unknown>;
23
24
  items: GanttItemFormatted[];
25
+ height: number;
26
+ barHeight: number;
27
+ width: number;
28
+ start: DateTime;
29
+ end: DateTime;
30
+ x: number;
31
+ y: number;
32
+ meta?: Record<string, unknown>;
24
33
  }
25
34
 
26
35
  export interface GanttItemFormatted {
27
36
  id: number | string;
28
- start: DateTime;
29
- end: DateTime;
30
37
  name: string;
31
- meta?: Record<string, unknown>;
32
38
  color: string;
33
- milliseconds: number;
39
+ height: number;
40
+ barHeight: number;
41
+ width: number;
42
+ start: DateTime;
43
+ end: DateTime;
34
44
  x: number;
35
45
  y: number;
36
- width: number;
37
- height: number;
46
+ milliseconds: number;
47
+ meta?: Record<string, unknown>;
38
48
  }
39
49
 
40
50
  export interface FormatConfig {
41
51
  rows: GanttRow[];
52
+ sidebarWidth: number;
42
53
  minWidth: number;
43
54
  rowHeight: number;
44
- rowPadding: number;
45
55
  includeToday: boolean;
46
56
  }
47
57