sprintify-ui 0.0.177 → 0.0.179

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.
@@ -50,8 +50,9 @@
50
50
  :toggle="false"
51
51
  :clickable="false"
52
52
  custom-key="actions"
53
+ class="overflow-hidden"
53
54
  >
54
- <div class="flex justify-end text-right">
55
+ <div class="flex justify-end gap-1 text-right">
55
56
  <slot name="rowActions" :row="row" />
56
57
 
57
58
  <router-link
@@ -59,7 +60,9 @@
59
60
  :to="editUrl(row)"
60
61
  :disabled="!canUpdate(row)"
61
62
  >
62
- <button class="btn btn-white bg-transparent p-2">
63
+ <button
64
+ class="btn btn-white border border-slate-300 p-2 shadow-sm"
65
+ >
63
66
  <BaseIcon
64
67
  icon="heroicons:cog-6-tooth-solid"
65
68
  class="text-slate-500"
@@ -70,7 +73,7 @@
70
73
  <button
71
74
  v-if="deleteButton && deleteUrl"
72
75
  type="button"
73
- class="btn btn-white bg-transparent p-2"
76
+ class="btn btn-white border border-slate-300 p-2 shadow-sm"
74
77
  :disabled="!canDelete(row)"
75
78
  @click="onDeleteClick(row)"
76
79
  >
@@ -190,6 +193,7 @@ import BaseEmptyState from '../svg/BaseEmptyState.vue';
190
193
  import { RouteLocationRaw } from 'vue-router';
191
194
 
192
195
  const i18n = useI18n();
196
+ const router = useRouter();
193
197
 
194
198
  const http = config.http;
195
199
 
@@ -224,6 +228,16 @@ const props = defineProps({
224
228
  type: Object as PropType<DataTableQuery>,
225
229
  },
226
230
 
231
+ /**
232
+ * Show url for router link
233
+ */
234
+ showUrl: {
235
+ default: undefined,
236
+ type: Function as PropType<
237
+ ((row: CollectionItem) => RouteLocationRaw) | undefined
238
+ >,
239
+ },
240
+
227
241
  /**
228
242
  * Show/Hide edit button
229
243
  */
@@ -237,7 +251,9 @@ const props = defineProps({
237
251
  */
238
252
  editUrl: {
239
253
  default: undefined,
240
- type: Function as PropType<(row: CollectionItem) => RouteLocationRaw>,
254
+ type: Function as PropType<
255
+ ((row: CollectionItem) => RouteLocationRaw) | undefined
256
+ >,
241
257
  },
242
258
 
243
259
  /**
@@ -253,7 +269,7 @@ const props = defineProps({
253
269
  */
254
270
  deleteUrl: {
255
271
  default: undefined,
256
- type: Function as PropType<(row: CollectionItem) => string>,
272
+ type: Function as PropType<((row: CollectionItem) => string) | undefined>,
257
273
  },
258
274
 
259
275
  /**
@@ -368,6 +384,9 @@ const dataIterator = ref<null | InstanceType<typeof BaseDataIterator>>(null);
368
384
  */
369
385
 
370
386
  function onCellClick(payload: CollectionItem) {
387
+ if (props.showUrl) {
388
+ router.push(props.showUrl(payload));
389
+ }
371
390
  emit('cell-click', payload);
372
391
  }
373
392
 
@@ -9,7 +9,7 @@ export default {
9
9
  (story) => ({
10
10
  components: { story, BaseForm },
11
11
  template: `
12
- <BaseForm method="post" url="https://api.com/todos/422" :data="{}">
12
+ <BaseForm method="post" url="https://faker.witify.io/api/todos/422" :data="{}">
13
13
  <story/>
14
14
  <button type="submit" class="btn btn-primary mt-5">Submit</button>
15
15
  </BaseForm>`,
@@ -17,7 +17,7 @@ export default {
17
17
  max: null,
18
18
  min: 2,
19
19
  acceptedExtensions: ['jpg', 'png'],
20
- uploadUrl: 'https://api.com/upload',
20
+ uploadUrl: 'https://faker.witify.io/upload',
21
21
  maxSize: 500 * 1024,
22
22
  currentMedia: [
23
23
  mediaModel,
@@ -1,11 +1,15 @@
1
1
  <template>
2
- <div class="relative w-full overflow-hidden">
2
+ <div
3
+ class="relative w-full overflow-hidden"
4
+ :class="maxHeight ? 'base-table--has-max-height' : ''"
5
+ >
3
6
  <div ref="slot" style="display: none">
4
7
  <slot />
5
8
  </div>
6
9
 
7
10
  <div class="flex flex-col">
8
11
  <div
12
+ ref="scrollable"
9
13
  class="overflow-x-auto overflow-y-auto"
10
14
  data-scroll-lock-scrollable
11
15
  :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }"
@@ -15,11 +19,17 @@
15
19
  <table class="min-w-full border-separate border-spacing-0">
16
20
  <thead v-if="newColumns.length" ref="thead">
17
21
  <tr>
18
- <th v-if="showDetailRowIcon" class="th" />
22
+ <th
23
+ v-if="showDetailRowIcon"
24
+ class="th"
25
+ :style="detailsStyles"
26
+ />
19
27
  <th
20
28
  v-if="checkable && checkboxPosition === 'left'"
21
- class="th py-0 pl-3"
29
+ class="th group cursor-pointer py-0 pl-3"
22
30
  align="left"
31
+ :style="checkStyles"
32
+ @click="checkAll"
23
33
  >
24
34
  <div class="flex items-center">
25
35
  <input
@@ -28,7 +38,6 @@
28
38
  :checked="isAllChecked"
29
39
  :disabled="isAllUncheckable"
30
40
  :class="checkboxStyle"
31
- @change="checkAll"
32
41
  />
33
42
  </div>
34
43
  </th>
@@ -36,8 +45,11 @@
36
45
  v-for="(column, index) in visibleColumns"
37
46
  :key="column.newKey + ':' + index + 'header'"
38
47
  v-bind="column.thAttrs && column.thAttrs(column)"
39
- :style="column.style"
40
- class="th py-2 pl-3 pr-3 text-left"
48
+ :style="[
49
+ column.style,
50
+ index == 0 ? firstColStyles : { position: 'relative' },
51
+ ]"
52
+ class="th group py-2 pl-3 pr-3 text-left"
41
53
  @click.stop="sort(column, undefined, $event as any)"
42
54
  >
43
55
  <button
@@ -49,26 +61,45 @@
49
61
  column.sortable && currentSortColumn === column,
50
62
  }"
51
63
  >
52
- <span class="mr-1 whitespace-nowrap">{{
53
- column.label
54
- }}</span>
55
- <span
56
- v-show="column.sortable && currentSortColumn === column"
57
- >
58
- <BaseIcon
59
- icon="mdi:chevron-down"
60
- class="h-5 w-5 duration-300"
61
- :class="{
62
- 'rotate-180': isAsc,
63
- }"
64
- />
64
+ <span class="whitespace-nowrap text-xs text-slate-500">
65
+ {{ column.label }}
65
66
  </span>
67
+ <div
68
+ v-if="column.sortable"
69
+ class="w-3"
70
+ :class="[
71
+ currentSortColumn === column
72
+ ? ''
73
+ : 'opacity-0 duration-200 group-hover:opacity-100',
74
+ ]"
75
+ >
76
+ <svg
77
+ viewBox="0 0 24 24"
78
+ class="absolute top-1/2 h-5 w-5 -translate-y-1/2"
79
+ >
80
+ <g transform="translate(0 -3)">
81
+ <path
82
+ :opacity="!isAsc ? '0.5' : '1'"
83
+ fill="currentColor"
84
+ d="M8.71 12.29L11.3 9.7a.996.996 0 0 1 1.41 0l2.59 2.59c.63.63.18 1.71-.71 1.71H9.41c-.89 0-1.33-1.08-.7-1.71z"
85
+ ></path>
86
+ </g>
87
+ <g transform="translate(0 3)">
88
+ <path
89
+ :opacity="isAsc ? '0.5' : '1'"
90
+ fill="currentColor"
91
+ d="m8.71 11.71l2.59 2.59c.39.39 1.02.39 1.41 0l2.59-2.59c.63-.63.18-1.71-.71-1.71H9.41c-.89 0-1.33 1.08-.7 1.71z"
92
+ ></path>
93
+ </g>
94
+ </svg>
95
+ </div>
66
96
  </button>
67
97
  </th>
68
98
  <th
69
99
  v-if="checkable && checkboxPosition === 'right'"
70
- class="th pr-3"
100
+ class="th group cursor-pointer pr-3"
71
101
  align="right"
102
+ @click="checkAll"
72
103
  >
73
104
  <input
74
105
  autocomplete="off"
@@ -76,7 +107,6 @@
76
107
  :checked="isAllChecked"
77
108
  :disabled="isAllUncheckable"
78
109
  :class="checkboxStyle"
79
- @change="checkAll"
80
110
  />
81
111
  </th>
82
112
  </tr>
@@ -144,33 +174,35 @@
144
174
  v-for="(row, index) in data"
145
175
  :key="getRowIndex(row, index)"
146
176
  >
147
- <tr>
177
+ <tr class="item-row">
148
178
  <td
149
179
  v-if="showDetailRowIcon"
150
- class="pl-3"
180
+ class="group cursor-pointer bg-white pl-3"
151
181
  :class="borderBottomClasses(index, row)"
152
- style="width: 36px"
182
+ :style="detailsStyles"
183
+ @click.stop="toggleDetails(row)"
153
184
  >
154
185
  <button
155
186
  type="button"
156
- class="mr-0 flex h-8 w-8 appearance-none items-center justify-center rounded-full border-0 bg-white text-slate-400 duration-300 hover:bg-slate-100 hover:text-slate-700"
157
- :class="{
158
- 'rotate-180': isVisibleDetailRow(row),
159
- }"
160
- @click.stop="toggleDetails(row)"
187
+ class="mr-0 flex h-5 w-5 appearance-none items-center justify-center rounded-full border border-slate-300 bg-white text-slate-400 shadow duration-100 group-hover:text-slate-600 group-hover:shadow-md"
161
188
  >
162
189
  <BaseIcon
163
190
  v-if="hasDetailedVisible(row)"
164
191
  icon="mdi:chevron-down"
165
- class="h-5 w-5"
192
+ class="h-5 w-5 duration-300"
193
+ :class="{
194
+ 'rotate-180': isVisibleDetailRow(row),
195
+ }"
166
196
  />
167
197
  </button>
168
198
  </td>
169
199
 
170
200
  <td
171
201
  v-if="checkable && checkboxPosition === 'left'"
172
- class="pl-3"
202
+ class="group z-[1] cursor-pointer bg-white pl-3"
203
+ :style="checkStyles"
173
204
  :class="borderBottomClasses(index, row)"
205
+ @click="checkRow(row, index, $event as MouseEvent)"
174
206
  >
175
207
  <div class="flex items-center">
176
208
  <input
@@ -179,7 +211,6 @@
179
211
  :disabled="!isRowCheckable(row)"
180
212
  :checked="isRowChecked(row)"
181
213
  :class="checkboxStyle"
182
- @click="checkRow(row, index, $event as MouseEvent)"
183
214
  />
184
215
  </div>
185
216
  </td>
@@ -192,8 +223,15 @@
192
223
  scoped
193
224
  name="default"
194
225
  tag="td"
195
- class="py-3 pl-3 pr-3 text-sm"
196
- :class="borderBottomClasses(index, row)"
226
+ class="bg-white py-3 pl-3 pr-3 text-sm"
227
+ :style="[
228
+ column.style,
229
+ colindex === 0 ? firstColStyles : {},
230
+ ]"
231
+ :class="[
232
+ borderBottomClasses(index, row),
233
+ column.clickable ? 'cursor-pointer' : '',
234
+ ]"
197
235
  :data-label="column.label"
198
236
  :props="{ row, column, index, colindex, toggleDetails }"
199
237
  @click="
@@ -203,9 +241,10 @@
203
241
 
204
242
  <td
205
243
  v-if="checkable && checkboxPosition === 'right'"
206
- class="pr-3"
244
+ class="group cursor-pointer pr-3"
207
245
  :class="borderBottomClasses(index, row)"
208
246
  align="right"
247
+ @click="checkRow(row, index, $event as MouseEvent)"
209
248
  >
210
249
  <input
211
250
  type="checkbox"
@@ -213,7 +252,6 @@
213
252
  :disabled="!isRowCheckable(row)"
214
253
  :checked="isRowChecked(row)"
215
254
  :class="checkboxStyle"
216
- @click="checkRow(row, index, $event as MouseEvent)"
217
255
  />
218
256
  </td>
219
257
  </tr>
@@ -253,7 +291,7 @@
253
291
  >
254
292
  <div
255
293
  v-if="loading"
256
- class="absolute inset-0 flex h-full w-full items-start justify-center"
294
+ class="absolute inset-0 z-[1] flex h-full w-full items-start justify-center"
257
295
  >
258
296
  <div class="absolute h-full w-full bg-white bg-opacity-60" />
259
297
 
@@ -281,13 +319,15 @@ export default {
281
319
  import { PropType, ref } from 'vue';
282
320
  import { BaseTableColumn, MenuItemInterface, Row } from '@/types';
283
321
  import SlotComponent from './SlotComponent';
284
- import { useResizeObserver } from '@vueuse/core';
322
+ import { useResizeObserver, useScroll } from '@vueuse/core';
285
323
  import { debounce, isArray } from 'lodash';
286
324
  import BaseMenu from './BaseMenu.vue';
287
325
  import BaseSpinnerLarge from '../svg/BaseSpinnerLarge.vue';
288
326
 
289
327
  const checkboxStyle =
290
- 'disabled:bg-slate-100 disabled:border-slate-300 disabled:cursor-not-allowed border-slate-400 rounded';
328
+ 'disabled:bg-slate-100 group-hover:shadow-md disabled:border-slate-300 disabled:cursor-not-allowed duration-300 cursor-pointer focus:ring-blue-300 border border-slate-300 shadow h-[18px] w-[18px] rounded';
329
+ const DETAIL_ROW_WIDTH = 36;
330
+ const CHECK_ROW_WIDTH = 36;
291
331
 
292
332
  provide('table', getCurrentInstance());
293
333
 
@@ -749,7 +789,7 @@ function removeColumn(column: BaseTableColumn) {
749
789
  );
750
790
  }
751
791
 
752
- const borderClasses = 'border-b border-slate-300';
792
+ const borderClasses = 'border-b border-slate-200';
753
793
 
754
794
  function borderBottomClasses(index: number, row: Record<string, any>): string {
755
795
  if (index < props.data.length - 1) {
@@ -800,6 +840,60 @@ function getRowIndex(row: Row, index: number): string {
800
840
  return index + '';
801
841
  }
802
842
 
843
+ // Sticky styles
844
+
845
+ const horizontalScrolling = ref(false);
846
+ const scrollable = ref<null | HTMLElement>(null);
847
+
848
+ const { x } = useScroll(scrollable);
849
+ watch(x, (value) => {
850
+ horizontalScrolling.value = value > 0;
851
+ });
852
+
853
+ const detailsStyles = computed<any>(() => {
854
+ if (props.detailed) {
855
+ return {
856
+ zIndex: 1,
857
+ position: 'sticky',
858
+ left: 0,
859
+ width: DETAIL_ROW_WIDTH + 'px',
860
+ minWidth: DETAIL_ROW_WIDTH + 'px',
861
+ maxWidth: DETAIL_ROW_WIDTH + 'px',
862
+ };
863
+ }
864
+ return {};
865
+ });
866
+
867
+ const checkStyles = computed<any>(() => {
868
+ if (props.checkable) {
869
+ return {
870
+ zIndex: 1,
871
+ position: 'sticky',
872
+ left: props.detailed ? DETAIL_ROW_WIDTH + 'px' : 0,
873
+ width: CHECK_ROW_WIDTH + 'px',
874
+ minWidth: CHECK_ROW_WIDTH + 'px',
875
+ maxWidth: CHECK_ROW_WIDTH + 'px',
876
+ };
877
+ }
878
+ return {};
879
+ });
880
+
881
+ const firstColStyles = computed<any>(() => {
882
+ let left = 0;
883
+ if (props.checkable) {
884
+ left += CHECK_ROW_WIDTH;
885
+ }
886
+ if (props.detailed) {
887
+ left += DETAIL_ROW_WIDTH;
888
+ }
889
+ return {
890
+ zIndex: 1,
891
+ position: 'sticky',
892
+ left: left + 'px',
893
+ borderRight: horizontalScrolling.value ? '1px solid #e2e8f0' : 'none',
894
+ };
895
+ });
896
+
803
897
  provide('addColumn', addColumn);
804
898
  provide('removeColumn', removeColumn);
805
899
  provide('nextSequence', nextSequence);
@@ -809,13 +903,20 @@ defineExpose({
809
903
  });
810
904
  </script>
811
905
 
812
- <style scoped>
906
+ <style lang="postcss" scoped>
813
907
  .th {
814
908
  @apply bg-slate-50;
909
+ @apply border-b border-slate-300;
910
+ }
911
+
912
+ .base-table--has-max-height .th {
815
913
  @apply sticky;
816
914
  @apply top-0;
817
915
  @apply z-[1];
818
- @apply border-b border-slate-300;
819
916
  @apply bg-opacity-75 backdrop-blur backdrop-filter;
820
917
  }
918
+
919
+ tbody tr.item-row:hover td {
920
+ @apply bg-slate-50;
921
+ }
821
922
  </style>
@@ -24,6 +24,10 @@ export default defineComponent({
24
24
  default: undefined,
25
25
  type: Number,
26
26
  },
27
+ padding: {
28
+ default: undefined,
29
+ type: String,
30
+ },
27
31
  numeric: {
28
32
  default: false,
29
33
  type: Boolean,
@@ -95,6 +99,7 @@ export default defineComponent({
95
99
  style() {
96
100
  return {
97
101
  width: this.width ? this.width + 'px' : undefined,
102
+ padding: this.padding ? this.padding : '0.5rem 0.75rem',
98
103
  };
99
104
  },
100
105
  },