sprintify-ui 0.0.179 → 0.0.180

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 (31) hide show
  1. package/dist/sprintify-ui.es.js +7850 -7684
  2. package/dist/style.css +1 -1
  3. package/dist/types/src/components/BaseDataIterator.vue.d.ts +52 -13
  4. package/dist/types/src/components/BaseDataIteratorSectionBox.vue.d.ts +23 -0
  5. package/dist/types/src/components/BaseDataIteratorSectionButton.vue.d.ts +20 -0
  6. package/dist/types/src/components/{BaseDataTableToggleColumns.vue.d.ts → BaseDataIteratorSectionColumns.vue.d.ts} +6 -40
  7. package/dist/types/src/components/BaseDataIteratorSectionModal.vue.d.ts +29 -0
  8. package/dist/types/src/components/BaseDataTable.vue.d.ts +50 -11
  9. package/dist/types/src/components/BaseDataTableRowAction.vue.d.ts +18 -0
  10. package/dist/types/src/components/BaseMenu.vue.d.ts +9 -0
  11. package/dist/types/src/components/BaseMenuItem.vue.d.ts +9 -0
  12. package/dist/types/src/components/BaseTable.vue.d.ts +2 -17
  13. package/dist/types/src/index.d.ts +12 -0
  14. package/dist/types/src/types/index.d.ts +15 -0
  15. package/package.json +1 -1
  16. package/src/assets/main.css +23 -0
  17. package/src/components/BaseActionItem.vue +3 -1
  18. package/src/components/BaseDataIterator.vue +123 -85
  19. package/src/components/BaseDataIteratorSectionBox.vue +33 -0
  20. package/src/components/BaseDataIteratorSectionButton.vue +34 -0
  21. package/src/components/{BaseDataTableToggleColumns.vue → BaseDataIteratorSectionColumns.vue} +3 -3
  22. package/src/components/BaseDataIteratorSectionModal.vue +41 -0
  23. package/src/components/BaseDataTable.stories.js +45 -14
  24. package/src/components/BaseDataTable.vue +219 -78
  25. package/src/components/BaseDataTableRowAction.vue +28 -0
  26. package/src/components/BaseMenu.vue +7 -0
  27. package/src/components/BaseMenuItem.vue +17 -1
  28. package/src/components/BaseTable.vue +37 -85
  29. package/src/lang/en.json +3 -0
  30. package/src/lang/fr.json +3 -0
  31. package/src/types/index.ts +17 -0
@@ -8,7 +8,7 @@
8
8
  >
9
9
  <div
10
10
  class="min-w-0"
11
- :class="{ 'col-span-1': !mobileLayout, 'col-span-2': mobileLayout }"
11
+ :class="{ 'col-span-1': !compactLayout, 'col-span-2': compactLayout }"
12
12
  >
13
13
  <!-- Header -->
14
14
  <div class="mb-4 flex space-x-2 empty:mb-0">
@@ -52,19 +52,18 @@
52
52
  </div>
53
53
  </div>
54
54
 
55
- <!-- Filters (mobile) -->
56
- <button
57
- v-if="mobileLayout && hasFilters"
58
- class="btn flex h-11 items-center justify-center py-1 text-base shadow-sm"
59
- type="button"
60
- @click="showFilters = true"
61
- >
62
- <BaseIcon
63
- class="h-6 w-6 text-slate-500 xs:mr-2"
64
- icon="heroicons:adjustments-horizontal-solid"
65
- />
66
- <span class="hidden xs:block">{{ $t('sui.filters') }}</span>
67
- </button>
55
+ <template v-if="compactLayout">
56
+ <template
57
+ v-for="(section, i) in sectionsInternal"
58
+ :key="section.name"
59
+ >
60
+ <BaseDataIteratorSectionButton
61
+ :section="section"
62
+ @open="openSection(i)"
63
+ >
64
+ </BaseDataIteratorSectionButton>
65
+ </template>
66
+ </template>
68
67
 
69
68
  <!-- Menu -->
70
69
  <BaseMenu
@@ -99,8 +98,8 @@
99
98
 
100
99
  <!-- Pagination -->
101
100
 
102
- <div v-if="paginationMetadata" class="mt-5">
103
- <p class="text-center text-xs text-slate-400 sm:text-right">
101
+ <div v-if="paginationMetadata" class="mt-4">
102
+ <p class="text-center text-sm text-slate-400 sm:text-right">
104
103
  {{
105
104
  (paginationMetadata.current_page - 1) *
106
105
  paginationMetadata.per_page +
@@ -128,74 +127,46 @@
128
127
  </div>
129
128
  </div>
130
129
 
131
- <div v-if="!mobileLayout" ref="sidebar">
132
- <slot
133
- name="sidebarTop"
134
- :pagination-metadata="paginationMetadata"
135
- ></slot>
136
-
137
- <div v-if="hasFilters" class="mb-4">
138
- <BaseCard>
139
- <BaseCardRow size="sm">
140
- <button
141
- type="button"
142
- class="flex w-full items-center justify-between"
143
- @click="showFilterDesktop = !showFilterDesktop"
144
- >
145
- <h2 class="font-semibold">
146
- {{ $t('sui.filters') }}
147
- </h2>
148
-
149
- <BaseIcon
150
- :icon="
151
- showFilterDesktop
152
- ? 'heroicons:chevron-down'
153
- : 'heroicons:chevron-up'
154
- "
155
- ></BaseIcon>
156
- </button>
157
-
158
- <div v-show="showFilterDesktop" class="mt-4 space-y-3">
159
- <slot
160
- name="filters"
161
- :query="query"
162
- :update-query="updateFilterQuery"
163
- :update-query-value="updateFilterQueryValue"
164
- />
165
- </div>
166
- </BaseCardRow>
167
- </BaseCard>
168
- </div>
169
-
170
- <slot
171
- name="sidebarBottom"
172
- :pagination-metadata="paginationMetadata"
173
- ></slot>
174
- </div>
175
- </div>
176
-
177
- <BaseModalSide v-if="hasFilters" v-model="showFilters">
178
- <div class="px-4 py-5">
179
- <h2 class="mb-4 font-semibold">
180
- {{ $t('sui.filters') }}
181
- </h2>
182
-
130
+ <div v-if="!compactLayout" ref="sidebar">
183
131
  <div class="space-y-3">
184
132
  <slot
185
- name="filters"
186
- :query="query"
187
- :update-query="updateFilterQuery"
188
- :update-query-value="updateFilterQueryValue"
189
- />
190
- </div>
133
+ name="sidebarTop"
134
+ :pagination-metadata="paginationMetadata"
135
+ ></slot>
136
+
137
+ <template v-for="section in sectionsInternal" :key="section.name">
138
+ <BaseDataIteratorSectionBox :section="section">
139
+ <slot
140
+ :name="section.name"
141
+ :query="query"
142
+ :update-query="updateFilterQuery"
143
+ :update-query-value="updateFilterQueryValue"
144
+ />
145
+ </BaseDataIteratorSectionBox>
146
+ </template>
191
147
 
192
- <div>
193
- <button class="btn btn-primary mt-4" @click="showFilters = false">
194
- {{ $t('sui.apply_filters') }}
195
- </button>
148
+ <slot
149
+ name="sidebarBottom"
150
+ :pagination-metadata="paginationMetadata"
151
+ ></slot>
196
152
  </div>
197
153
  </div>
198
- </BaseModalSide>
154
+ </div>
155
+
156
+ <template v-for="(section, i) in sectionsInternal" :key="section.name">
157
+ <BaseDataIteratorSectionModal
158
+ :section="section"
159
+ :model-value="sectionModalActive == i"
160
+ @update:model-value="closeSection"
161
+ >
162
+ <slot
163
+ :name="section.name"
164
+ :query="query"
165
+ :update-query="updateFilterQuery"
166
+ :update-query-value="updateFilterQueryValue"
167
+ />
168
+ </BaseDataIteratorSectionModal>
169
+ </template>
199
170
  </div>
200
171
  </template>
201
172
 
@@ -218,6 +189,7 @@ import hash from 'object-hash';
218
189
  import { PropType } from 'vue';
219
190
  import {
220
191
  Collection,
192
+ DataIteratorSection,
221
193
  DataTableQuery,
222
194
  MenuItemInterface,
223
195
  PaginatedCollection,
@@ -225,13 +197,13 @@ import {
225
197
  } from '@/types';
226
198
 
227
199
  import BaseMenu from './BaseMenu.vue';
228
- import BaseCard from './BaseCard.vue';
229
- import BaseCardRow from './BaseCardRow.vue';
230
200
  import BasePagination from './BasePagination.vue';
231
- import BaseModalSide from './BaseModalSide.vue';
232
201
  import { config } from '@/index';
233
202
  import { useMutationObserver, useResizeObserver } from '@vueuse/core';
234
203
  import { useHasPaginatedData } from '@/composables/paginatedData';
204
+ import BaseDataIteratorSectionButton from './BaseDataIteratorSectionButton.vue';
205
+ import BaseDataIteratorSectionModal from './BaseDataIteratorSectionModal.vue';
206
+ import BaseDataIteratorSectionBox from './BaseDataIteratorSectionBox.vue';
235
207
 
236
208
  const props = defineProps({
237
209
  /**
@@ -286,8 +258,25 @@ const props = defineProps({
286
258
  default: false,
287
259
  type: Boolean,
288
260
  },
261
+
262
+ /**
263
+ * Layout type
264
+ */
265
+ layout: {
266
+ default: 'default',
267
+ type: String as PropType<'default' | 'compact'>,
268
+ },
269
+
270
+ /**
271
+ * Sections
272
+ */
273
+ sections: {
274
+ default: undefined,
275
+ type: Array as PropType<DataIteratorSection[]>,
276
+ },
289
277
  });
290
278
 
279
+ const i18n = useI18n();
291
280
  const http = config.http;
292
281
 
293
282
  defineEmits([
@@ -322,7 +311,6 @@ useResizeObserver(dataIteratorNode, () => {
322
311
  const firstLoad = ref(false);
323
312
  const loading = ref(true);
324
313
  const error = ref(false);
325
- const showFilters = ref(false);
326
314
  const searchQuery = ref('');
327
315
 
328
316
  let lastUrl = '';
@@ -330,7 +318,10 @@ let lastQueryHash = '';
330
318
  const query = ref<DataTableQuery>(cloneDeep(props.defaultQuery));
331
319
  const slots = useSlots();
332
320
 
333
- const mobileLayout = computed(() => {
321
+ const compactLayout = computed(() => {
322
+ if (props.layout === 'compact') {
323
+ return true;
324
+ }
334
325
  return width.value < 1024;
335
326
  });
336
327
 
@@ -364,7 +355,7 @@ onMounted(() => {
364
355
  });
365
356
 
366
357
  watch(
367
- () => mobileLayout.value,
358
+ () => compactLayout.value,
368
359
  () => {
369
360
  // After the sidebar appears...
370
361
  nextTick(() => {
@@ -685,6 +676,53 @@ onMounted(() => {
685
676
  updateSearchInput();
686
677
  });
687
678
 
679
+ /*
680
+ |--------------------------------------------------------------------------
681
+ | Sections
682
+ |--------------------------------------------------------------------------
683
+ */
684
+
685
+ const sectionModalActive = ref<null | number>(null);
686
+
687
+ const sectionsInternal = computed<DataIteratorSection[]>(() => {
688
+ const sections = props.sections ?? [];
689
+
690
+ if (hasFilters.value) {
691
+ return [
692
+ {
693
+ name: 'filters',
694
+ title: i18n.t('sui.filters'),
695
+ closeText: i18n.t('sui.apply_filters'),
696
+ icon: 'heroicons:adjustments-horizontal-solid',
697
+ opened: true,
698
+ },
699
+ ...sections,
700
+ ];
701
+ }
702
+
703
+ return sections;
704
+ });
705
+
706
+ function openSection(index: number) {
707
+ if (sectionsInternal.value[index]) {
708
+ sectionModalActive.value = index;
709
+ } else {
710
+ sectionModalActive.value = null;
711
+ }
712
+ }
713
+
714
+ function closeSection() {
715
+ sectionModalActive.value = null;
716
+ }
717
+
718
+ /*
719
+ |--------------------------------------------------------------------------
720
+ | Provide
721
+ |--------------------------------------------------------------------------
722
+ */
723
+
724
+ provide('dataIterator:width', width);
725
+
688
726
  /*
689
727
  |--------------------------------------------------------------------------
690
728
  | Exposed API
@@ -0,0 +1,33 @@
1
+ <template>
2
+ <BaseCard>
3
+ <button
4
+ type="button"
5
+ class="flex w-full items-center justify-between px-4 py-3"
6
+ @click="active = !active"
7
+ >
8
+ <h2 class="text-sm font-semibold">
9
+ {{ section.title }}
10
+ </h2>
11
+
12
+ <BaseIcon
13
+ class="h-5 w-5 text-slate-500 duration-300"
14
+ :class="active ? 'rotate-90 transform' : ''"
15
+ icon="heroicons:chevron-right-20-solid"
16
+ ></BaseIcon>
17
+ </button>
18
+ <div v-show="active" class="border-t border-slate-300 py-5 px-4">
19
+ <slot />
20
+ </div>
21
+ </BaseCard>
22
+ </template>
23
+
24
+ <script lang="ts" setup>
25
+ import { DataIteratorSection } from '@/types';
26
+ import { BaseCard, BaseIcon } from '.';
27
+
28
+ const props = defineProps<{
29
+ section: DataIteratorSection;
30
+ }>();
31
+
32
+ const active = ref<boolean>(props.section.opened ?? false);
33
+ </script>
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <button
3
+ class="btn flex h-11 items-center justify-center py-1 text-base shadow-sm"
4
+ :class="[width > 600 ? 'px-4' : 'px-3.5']"
5
+ type="button"
6
+ @click="open()"
7
+ >
8
+ <BaseIcon class="h-5 w-5 text-slate-500" :icon="section.icon" />
9
+ <span
10
+ v-if="section.title && width > 600"
11
+ class="ml-2 whitespace-pre text-sm"
12
+ >{{ section.title }}</span
13
+ >
14
+ </button>
15
+ </template>
16
+
17
+ <script lang="ts" setup>
18
+ import { DataIteratorSection } from '@/types';
19
+ import { BaseIcon } from '.';
20
+
21
+ defineProps<{
22
+ section: DataIteratorSection;
23
+ }>();
24
+
25
+ const emit = defineEmits<{
26
+ (event: 'open'): void;
27
+ }>();
28
+
29
+ const width = inject('dataIterator:width', ref(0));
30
+
31
+ function open() {
32
+ emit('open');
33
+ }
34
+ </script>
@@ -1,15 +1,15 @@
1
1
  <template>
2
2
  <ul>
3
3
  <li v-for="col in toggleableColumns" :key="col.newKey">
4
- <label>
4
+ <label class="cursor-pointer">
5
5
  <input
6
6
  :checked="visibleColumns.includes(col.newKey)"
7
7
  type="checkbox"
8
- class="mr-1.5 h-3.5 w-3.5 rounded focus:ring-1 focus:ring-primary-300 focus:ring-offset-1"
8
+ class="mr-2 h-3.5 w-3.5 cursor-pointer rounded focus:ring-1 focus:ring-primary-300 focus:ring-offset-1"
9
9
  :value="col.newKey"
10
10
  @change="onVisibleColumnChange($event, col.newKey)"
11
11
  />
12
- <span class="text-xs text-slate-600">
12
+ <span class="text-xs text-slate-700">
13
13
  {{ col.label }}
14
14
  </span>
15
15
  </label>
@@ -0,0 +1,41 @@
1
+ <template>
2
+ <BaseModalSide
3
+ :model-value="modelValue"
4
+ @update:model-value="emit('update:modelValue', $event)"
5
+ >
6
+ <div>
7
+ <div class="border-b border-slate-300 p-4">
8
+ <h2 class="text-base font-semibold">
9
+ {{ section.title }}
10
+ </h2>
11
+ </div>
12
+
13
+ <div class="py-5 px-4">
14
+ <slot />
15
+ </div>
16
+
17
+ <div class="border-t border-slate-300 p-4">
18
+ <button
19
+ class="btn btn-primary w-full sm:w-auto"
20
+ @click="emit('update:modelValue', false)"
21
+ >
22
+ {{ section.closeText }}
23
+ </button>
24
+ </div>
25
+ </div>
26
+ </BaseModalSide>
27
+ </template>
28
+
29
+ <script lang="ts" setup>
30
+ import { DataIteratorSection } from '@/types';
31
+ import BaseModalSide from './BaseModalSide.vue';
32
+
33
+ defineProps<{
34
+ modelValue: boolean;
35
+ section: DataIteratorSection;
36
+ }>();
37
+
38
+ const emit = defineEmits<{
39
+ (event: 'update:modelValue', value: boolean): void;
40
+ }>();
41
+ </script>
@@ -9,7 +9,14 @@ import BaseAppDialogs from './BaseAppDialogs.vue';
9
9
  export default {
10
10
  title: 'Data/BaseDataTable',
11
11
  component: BaseDataTable,
12
- argTypes: {},
12
+ argTypes: {
13
+ layout: {
14
+ control: {
15
+ type: 'select',
16
+ options: ['default', 'compact'],
17
+ },
18
+ },
19
+ },
13
20
  args: {
14
21
  url: 'https://effettandem.com/api/content/articles',
15
22
  urlQuery: {
@@ -99,6 +106,12 @@ const template = `
99
106
  </div>
100
107
  </template>
101
108
 
109
+ <template #test>
110
+ <div>
111
+ Section Test
112
+ </div>
113
+ </template>
114
+
102
115
  <template #filters="{ query, updateQueryValue }">
103
116
  <div class="space-y-3">
104
117
  <div>
@@ -107,7 +120,7 @@ const template = `
107
120
  </p>
108
121
  <BaseSelect
109
122
  :model-value="query.type ?? null"
110
- class="w-full rounded border-slate-300"
123
+ class="w-full rounded border-slate-300 text-base sm:text-sm"
111
124
  placeholder="-"
112
125
  @update:model-value="updateQueryValue('type', $event)"
113
126
  >
@@ -125,7 +138,7 @@ const template = `
125
138
  </p>
126
139
  <BaseSelect
127
140
  :model-value="query.access_level ?? null"
128
- class="w-full rounded border-slate-300"
141
+ class="w-full rounded border-slate-300 text-base sm:text-sm"
129
142
  placeholder="-"
130
143
  @update:model-value="updateQueryValue('access_level', $event)"
131
144
  >
@@ -170,7 +183,19 @@ const Template = (args) => ({
170
183
  export const Demo = Template.bind({});
171
184
 
172
185
  Demo.args = {
186
+ showUrl() {
187
+ return '/';
188
+ },
189
+ editUrl() {
190
+ return '/';
191
+ },
192
+ deleteUrl() {
193
+ return '/';
194
+ },
195
+ detailed: true,
173
196
  searchable: true,
197
+ maxHeight: 300,
198
+ checkable: true,
174
199
  actions: [
175
200
  {
176
201
  label: 'Open Google',
@@ -190,7 +215,6 @@ Demo.args = {
190
215
  color: 'danger',
191
216
  },
192
217
  ],
193
- checkable: true,
194
218
  checkableActions: [
195
219
  {
196
220
  label: 'Delete all',
@@ -199,16 +223,23 @@ Demo.args = {
199
223
  },
200
224
  },
201
225
  ],
202
- detailed: true,
203
- showUrl() {
204
- return '/';
205
- },
206
- editUrl() {
207
- return '/';
208
- },
209
- deleteUrl() {
210
- return '/';
211
- },
226
+ rowActions: [
227
+ {
228
+ label: 'Open Google',
229
+ icon: 'heroicons:link',
230
+ action() {
231
+ alert('hit');
232
+ },
233
+ },
234
+ ],
235
+ sections: [
236
+ {
237
+ name: 'test',
238
+ title: 'Section Test',
239
+ icon: 'heroicons:link',
240
+ closeText: 'Close',
241
+ },
242
+ ],
212
243
  };
213
244
 
214
245
  const SimpleTemplate = (args) => ({