sprintify-ui 0.2.22 → 0.2.24

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 +2267 -2143
  2. package/dist/style.css +1 -1
  3. package/dist/types/src/components/BaseBadge.vue.d.ts +6 -0
  4. package/dist/types/src/components/BaseBreadcrumbs.vue.d.ts +11 -1
  5. package/dist/types/src/components/BaseDataIterator.vue.d.ts +15 -0
  6. package/dist/types/src/components/BaseDataIteratorSectionButton.vue.d.ts +8 -0
  7. package/dist/types/src/components/BaseDataIteratorSectionColumns.vue.d.ts +20 -0
  8. package/dist/types/src/components/BaseDataTable.vue.d.ts +21 -0
  9. package/dist/types/src/components/BaseDataTableRowAction.vue.d.ts +11 -1
  10. package/dist/types/src/components/BaseTable.vue.d.ts +9 -0
  11. package/dist/types/src/components/BaseTableColumn.vue.d.ts +1 -1
  12. package/dist/types/src/index.d.ts +2 -0
  13. package/package.json +1 -1
  14. package/src/components/BaseBadge.vue +10 -1
  15. package/src/components/BaseBreadcrumbs.stories.js +7 -2
  16. package/src/components/BaseBreadcrumbs.vue +23 -18
  17. package/src/components/BaseDataIterator.vue +49 -12
  18. package/src/components/BaseDataIteratorSectionButton.vue +16 -5
  19. package/src/components/BaseDataTable.stories.js +65 -35
  20. package/src/components/BaseDataTable.vue +38 -6
  21. package/src/components/BaseDataTableRowAction.vue +23 -4
  22. package/src/components/BaseHeader.stories.js +6 -0
  23. package/src/components/BaseHeader.vue +12 -9
  24. package/src/components/BaseMenu.stories.js +4 -0
  25. package/src/components/BaseMenuItem.vue +44 -17
  26. package/src/components/BaseTable.vue +34 -16
  27. package/src/components/BaseTableColumn.vue +1 -1
  28. package/src/index.ts +4 -1
  29. package/src/lang/en.json +2 -1
  30. package/src/lang/fr.json +2 -1
  31. package/src/utils/colors.ts +1 -1
@@ -74,6 +74,10 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
74
74
  default: undefined;
75
75
  type: NumberConstructor;
76
76
  };
77
+ size: {
78
+ type: PropType<"sm" | "md">;
79
+ default: string;
80
+ };
77
81
  }, {
78
82
  newColumns: import("vue").ComputedRef<{
79
83
  id: string;
@@ -171,6 +175,10 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
171
175
  default: undefined;
172
176
  type: NumberConstructor;
173
177
  };
178
+ size: {
179
+ type: PropType<"sm" | "md">;
180
+ default: string;
181
+ };
174
182
  }>> & {
175
183
  onCheck?: ((...args: any[]) => any) | undefined;
176
184
  onSort?: ((...args: any[]) => any) | undefined;
@@ -182,6 +190,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
182
190
  "onCell-click"?: ((...args: any[]) => any) | undefined;
183
191
  }, {
184
192
  data: Row[];
193
+ size: "sm" | "md";
185
194
  loading: boolean;
186
195
  sortField: string;
187
196
  sortDirection: string;
@@ -79,7 +79,7 @@ declare const _default: import("vue").DefineComponent<{
79
79
  }, {
80
80
  style(): {
81
81
  width: string | undefined;
82
- padding: string;
82
+ padding: string | undefined;
83
83
  };
84
84
  }, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
85
85
  label: {
@@ -20,6 +20,7 @@ declare const messages: {
20
20
  apply_filters: string;
21
21
  authentication_code: string;
22
22
  autocomplete_placeholder: string;
23
+ bulk_actions: string;
23
24
  cancel: string;
24
25
  city: string;
25
26
  clear: string;
@@ -108,6 +109,7 @@ declare const messages: {
108
109
  apply_filters: string;
109
110
  authentication_code: string;
110
111
  autocomplete_placeholder: string;
112
+ bulk_actions: string;
111
113
  cancel: string;
112
114
  city: string;
113
115
  clear: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sprintify-ui",
3
- "version": "0.2.22",
3
+ "version": "0.2.24",
4
4
  "scripts": {
5
5
  "build": "rimraf dist && vue-tsc && vite build",
6
6
  "build-fast": "rimraf dist && vite build",
@@ -25,6 +25,7 @@ const props = withDefaults(
25
25
  size?: 'sm' | 'base' | 'lg';
26
26
  icon?: string;
27
27
  wrap?: boolean;
28
+ bordered?: boolean;
28
29
  }>(),
29
30
  {
30
31
  contrast: 'high',
@@ -37,10 +38,18 @@ const props = withDefaults(
37
38
  const colorStyle = computed((): Record<string, string> => {
38
39
  const config = getColorConfig(props.color, props.contrast == 'high');
39
40
 
40
- return {
41
+ const styles: Record<string, string> = {
41
42
  backgroundColor: config.backgroundColor,
42
43
  color: config.textColor,
43
44
  };
45
+
46
+ if (props.bordered) {
47
+ styles.borderColor = config.borderColor;
48
+ styles.borderWidth = '1px';
49
+ styles.borderStyle = 'solid';
50
+ }
51
+
52
+ return styles;
44
53
  });
45
54
 
46
55
  const wrapClasses = computed(() => {
@@ -3,7 +3,7 @@ import BaseBreadcrumbs from './BaseBreadcrumbs.vue';
3
3
  const breadcrumbs = [
4
4
  {
5
5
  label: 'Home',
6
- icon: 'heroicons:home-solid',
6
+ icon: 'heroicons:home-20-solid',
7
7
  to: '/',
8
8
  },
9
9
  {
@@ -23,7 +23,12 @@ const breadcrumbs = [
23
23
  export default {
24
24
  title: 'Layout/BaseBreadcrumbs',
25
25
  component: BaseBreadcrumbs,
26
- argTypes: {},
26
+ argTypes: {
27
+ size: {
28
+ control: { type: 'select' },
29
+ options: ['sm', 'md']
30
+ }
31
+ },
27
32
  args: {
28
33
  breadcrumbs: breadcrumbs,
29
34
  },
@@ -7,26 +7,21 @@
7
7
  >
8
8
  <ol
9
9
  role="list"
10
- class="flex items-center space-x-3"
10
+ class="flex items-center space-x-2"
11
11
  >
12
12
  <li
13
13
  v-for="(breadcrumb, index) in breadcrumbs"
14
14
  :key="index"
15
15
  >
16
16
  <div class="flex items-center">
17
- <svg
17
+ <div
18
18
  v-if="index > 0"
19
- class="h-5 w-5 flex-shrink-0 text-gray-400"
20
- viewBox="0 0 20 20"
21
- fill="currentColor"
22
- aria-hidden="true"
19
+ class="text-gray-300"
20
+ :class="{ 'text-xs': size == 'md', 'text-[10px]': size == 'sm' }"
23
21
  >
24
- <path
25
- fill-rule="evenodd"
26
- d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z"
27
- clip-rule="evenodd"
28
- />
29
- </svg>
22
+ /
23
+ </div>
24
+
30
25
  <RouterLink
31
26
  v-slot="{ href, navigate, isExactActive }"
32
27
  :to="breadcrumb.to"
@@ -36,7 +31,7 @@
36
31
  :href="href"
37
32
  class="text-sm"
38
33
  :class="[
39
- { 'ml-3': index > 0 },
34
+ { 'ml-2': index > 0 },
40
35
  isExactActive
41
36
  ? 'text-primary-600'
42
37
  : 'text-slate-500 hover:text-slate-700',
@@ -44,9 +39,15 @@
44
39
  @click.prevent="navigate()"
45
40
  >
46
41
  <span v-if="breadcrumb.icon">
47
- <BaseIcon :icon="breadcrumb.icon" />
42
+ <BaseIcon
43
+ :icon="breadcrumb.icon"
44
+ :class="{ 'h-4 w-4': size == 'md', 'h-3 w-3': size == 'sm' }"
45
+ />
48
46
  </span>
49
- <span v-else>
47
+ <span
48
+ v-else
49
+ :class="{ 'text-sm': size == 'md', 'text-xs': size == 'sm' }"
50
+ >
50
51
  {{ truncate(breadcrumb.label) }}
51
52
  </span>
52
53
  </a>
@@ -61,7 +62,7 @@
61
62
  :to="mobileBreadcrumb.to"
62
63
  class="block text-slate-500 sm:hidden"
63
64
  >
64
- <div class="flex items-center text-sm">
65
+ <div class="flex items-center">
65
66
  <svg
66
67
  class="-ml-1 mr-1 h-5 w-5 flex-shrink-0 text-gray-400"
67
68
  viewBox="0 0 20 20"
@@ -72,9 +73,9 @@
72
73
  fill-rule="evenodd"
73
74
  d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z"
74
75
  clip-rule="evenodd"
75
- />
76
+ ></path>
76
77
  </svg>
77
- <span>
78
+ <span :class="{ 'text-sm': size == 'md', 'text-xs': size == 'sm' }">
78
79
  {{ mobileBreadcrumb.label }}
79
80
  </span>
80
81
  </div>
@@ -93,6 +94,10 @@ const props = defineProps({
93
94
  required: true,
94
95
  type: Array as PropType<Breadcrumb[]>,
95
96
  },
97
+ size: {
98
+ type: String as PropType<'sm' | 'md'>,
99
+ default: 'md',
100
+ },
96
101
  });
97
102
 
98
103
  const mobileBreadcrumb = computed((): Breadcrumb | undefined => {
@@ -11,18 +11,34 @@
11
11
  :class="{ 'col-span-1': !compactLayout, 'col-span-2': compactLayout }"
12
12
  >
13
13
  <!-- Header -->
14
- <div class="mb-4 flex space-x-2 empty:mb-0">
14
+ <div
15
+ class="flex space-x-2 empty:mb-0"
16
+ :class="{
17
+ 'mb-2.5': size == 'sm',
18
+ 'mb-4': size == 'md',
19
+ }"
20
+ >
15
21
  <!-- Search bar -->
16
22
  <div
17
23
  v-if="searchable"
18
24
  class="grow"
19
25
  >
20
- <div class="relative h-11">
26
+ <div
27
+ class="relative"
28
+ :class="{
29
+ 'h-9': size == 'sm',
30
+ 'h-11': size == 'md',
31
+ }"
32
+ >
21
33
  <div
22
34
  class="pointer-events-none absolute left-0 top-0 flex h-full items-center justify-center pl-2.5"
23
35
  >
24
36
  <BaseIcon
25
- class="h-6 w-6 text-slate-400"
37
+ class="text-slate-400"
38
+ :class="{
39
+ 'h-5 w-5': size == 'sm',
40
+ 'h-6 w-6': size == 'md',
41
+ }"
26
42
  icon="heroicons:magnifying-glass"
27
43
  />
28
44
  </div>
@@ -30,7 +46,11 @@
30
46
  ref="searchInput"
31
47
  v-model="searchQuery"
32
48
  type="text"
33
- class="h-11 w-full overflow-hidden rounded-md border border-slate-300 bg-white pl-10 pr-9 shadow-sm"
49
+ class="w-full h-full py-0 overflow-hidden rounded-md border border-slate-300 bg-white shadow-sm"
50
+ :class="{
51
+ 'pl-9 pr-8': size == 'sm',
52
+ 'pl-10 pr-9': size == 'md',
53
+ }"
34
54
  :placeholder="t('sui.autocomplete_placeholder')"
35
55
  @input="onSearch"
36
56
  >
@@ -41,13 +61,14 @@
41
61
  <button
42
62
  type="button"
43
63
  class="flex appearance-none items-center rounded p-1 hover:bg-slate-100"
44
- @click="
45
- searchQuery = '';
46
- onSearch('');
47
- "
64
+ @click="searchQuery = ''; onSearch('');"
48
65
  >
49
66
  <BaseIcon
50
- class="h-6 w-6 text-slate-500"
67
+ class="text-slate-500"
68
+ :class="{
69
+ 'h-5 w-5': size == 'sm',
70
+ 'h-6 w-6': size == 'md',
71
+ }"
51
72
  icon="heroicons:x-mark"
52
73
  />
53
74
  </button>
@@ -62,6 +83,7 @@
62
83
  >
63
84
  <BaseDataIteratorSectionButton
64
85
  :section="section"
86
+ :size="size"
65
87
  @open="openSection(i)"
66
88
  />
67
89
  </template>
@@ -71,13 +93,18 @@
71
93
  <BaseMenu
72
94
  v-if="actions && actions.length"
73
95
  tw-menu="w-52"
96
+ :size="size == 'sm' ? 'xs' : 'sm'"
74
97
  :items="actions"
75
98
  >
76
99
  <template #button="{ open }">
77
100
  <div
78
- class="flex h-11 w-11 items-center justify-center rounded-md border border-slate-300 bg-white shadow-sm duration-150 hover:bg-slate-50"
101
+ class="flex items-center justify-center rounded-md border border-slate-300 bg-white shadow-sm duration-150 hover:bg-slate-50"
79
102
  :class="[
80
103
  open ? 'ring-2 ring-primary-500 ring-offset-2' : false,
104
+ {
105
+ 'h-9 w-9': size == 'sm',
106
+ 'h-11 w-11': size == 'md',
107
+ }
81
108
  ]"
82
109
  >
83
110
  <BaseIcon icon="heroicons-solid:dots-vertical" />
@@ -277,6 +304,14 @@ const props = defineProps({
277
304
  type: String as PropType<'default' | 'compact'>,
278
305
  },
279
306
 
307
+ /**
308
+ * Overall size and spacing of the component
309
+ */
310
+ size: {
311
+ default: 'md',
312
+ type: String as PropType<'sm' | 'md'>,
313
+ },
314
+
280
315
  /**
281
316
  * Sections
282
317
  */
@@ -334,6 +369,8 @@ const searchQuery = ref('');
334
369
 
335
370
  let lastUrl = '';
336
371
  let lastQueryHash = '';
372
+
373
+ // eslint-disable-next-line vue/no-setup-props-destructure
337
374
  const query = ref<DataTableQuery>(cloneDeep(props.defaultQuery));
338
375
  const slots = useSlots();
339
376
 
@@ -705,7 +742,7 @@ const paginationStart = computed(() => {
705
742
 
706
743
  return (
707
744
  paginationMetadata.value.per_page *
708
- (paginationMetadata.value.current_page - 1) +
745
+ (paginationMetadata.value.current_page - 1) +
709
746
  1
710
747
  );
711
748
  });
@@ -756,7 +793,7 @@ const sectionsInternal = computed<DataIteratorSection[]>(() => {
756
793
  name: 'filters',
757
794
  title: t('sui.filters'),
758
795
  closeText: t('sui.apply_filters'),
759
- icon: 'heroicons:adjustments-horizontal-solid',
796
+ icon: 'heroicons:adjustments-horizontal',
760
797
  opened: true,
761
798
  },
762
799
  ...sections,
@@ -1,7 +1,12 @@
1
1
  <template>
2
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']"
3
+ class="btn flex items-center justify-center text-base shadow-sm"
4
+ :class="[
5
+ width > 600 ? 'px-4' : 'px-3.5',
6
+ {
7
+ 'h-9': size == 'sm',
8
+ 'h-11': size == 'md',
9
+ }]"
5
10
  type="button"
6
11
  @click="open()"
7
12
  >
@@ -12,12 +17,17 @@
12
17
  <span
13
18
  v-if="section.title && width > 600"
14
19
  class="ml-2 whitespace-pre text-sm"
15
- >{{ section.title }}</span>
20
+ >
21
+ {{ section.title }}
22
+ </span>
16
23
  <BaseBadge
17
24
  v-if="section.count"
18
25
  class="ml-2"
19
- :label="section.count"
20
- />
26
+ color="blue"
27
+ :size="size == 'sm' ? 'sm' : 'base'"
28
+ >
29
+ {{ section.count }}
30
+ </BaseBadge>
21
31
  </button>
22
32
  </template>
23
33
 
@@ -28,6 +38,7 @@ import BaseBadge from './BaseBadge.vue';
28
38
 
29
39
  defineProps<{
30
40
  section: DataIteratorSection;
41
+ size: 'sm' | 'md';
31
42
  }>();
32
43
 
33
44
  const emit = defineEmits<{
@@ -6,17 +6,20 @@ import BaseBadge from './BaseBadge.vue';
6
6
  import BaseAppNotifications from './BaseAppNotifications.vue';
7
7
  import BaseAppDialogs from './BaseAppDialogs.vue';
8
8
  import { onBeforeUnmount } from 'vue';
9
+ import { DateTime } from 'luxon';
9
10
 
10
11
  export default {
11
12
  title: 'Data/BaseDataTable',
12
13
  component: BaseDataTable,
13
14
  argTypes: {
14
15
  layout: {
15
- control: {
16
- type: 'select',
17
- options: ['default', 'compact'],
18
- },
16
+ control: { type: 'select' },
17
+ options: ['default', 'compact'],
19
18
  },
19
+ size: {
20
+ control: { type: 'select' },
21
+ options: ['sm', 'md'],
22
+ }
20
23
  },
21
24
  args: {
22
25
  url: 'https://effettandem.com/api/content/articles',
@@ -50,21 +53,35 @@ const template = `
50
53
  >
51
54
  <div class="max-w-[200px]">
52
55
  <div class="font-medium text-slate-900 leading-tight truncate">
53
- {{ row.title }}
56
+ {{ row.title.slice(0, 30) }}...
54
57
  </div>
55
- <p class="text-xs leading-tight mt-1 text-slate-500 line-clamp-2">
56
- {{ row.subtitle }}
57
- </p>
58
- </div>
59
58
  </BaseTableColumn>
60
59
 
61
60
  <BaseTableColumn
62
61
  v-slot="{ row }"
63
- label="VIP"
62
+ label="URL"
63
+ field="website_url"
64
+ sortable
65
+ >
66
+ <a :href="row.website_url" target="_blank" class="btn btn-xs whitespace-pre space-x-1.5 shadow-sm">
67
+ <span class="whitespace-pre">Open website</span>
68
+ <BaseIcon icon="heroicons:arrow-top-right-on-square-20-solid" class="w-4 h-4 inline-block" />
69
+ </a>
70
+ </BaseTableColumn>
71
+
72
+ <BaseTableColumn
73
+ v-slot="{ row }"
74
+ label="Access Level"
64
75
  field="access_level"
65
76
  sortable
66
77
  >
67
- <BaseBoolean :model-value="row.access_level == 'vip'" />
78
+ <BaseBadge
79
+ contrast="low"
80
+ :color="row.access_level == 'public' ? 'green' : 'gray'"
81
+ bordered
82
+ >
83
+ {{ row.access_level }}
84
+ </BaseBadge>
68
85
  </BaseTableColumn>
69
86
 
70
87
  <BaseTableColumn
@@ -76,9 +93,9 @@ const template = `
76
93
  :toggle="true"
77
94
  :toggle-default="false"
78
95
  >
79
- <div class="whitespace-pre">
96
+ <BaseBadge color="blue" contrast="low" bordered>
80
97
  {{ Math.round(row.votes_avg_score) }} / 5
81
- </div>
98
+ </BaseBadge>
82
99
  </BaseTableColumn>
83
100
 
84
101
  <BaseTableColumn
@@ -90,40 +107,38 @@ const template = `
90
107
  :toggle="true"
91
108
  sortable
92
109
  >
93
- <BaseBadge>
94
- <span class="whitespace-pre">{{ row.owner?.name }}</span>
95
- </BaseBadge>
110
+ <span class="text-slate-600 whitespace-pre">{{ row.owner?.name }}</span>
96
111
  </BaseTableColumn>
97
112
 
98
113
  <BaseTableColumn
99
114
  v-slot="{ row }"
100
- label="Select"
101
- :clickable="false"
102
- padding="0px"
115
+ label="Created at"
116
+ field="created_at"
117
+ sortable
103
118
  >
104
- <select class="select border border-slate-300 rounded text-xs">
105
- <option>Option 1</option>
106
- </select>
119
+ <p class="text-slate-600 text-sm">{{ DateTime.fromISO(row.created_at).toLocaleString() }}</p>
107
120
  </BaseTableColumn>
108
121
 
109
122
  <BaseTableColumn
110
123
  v-slot="{ row }"
111
- label="Access level"
112
- field="access_level"
113
- sortable
124
+ label="Select"
125
+ :clickable="false"
126
+ padding="0px"
114
127
  >
115
- <BaseBadge>
116
- {{ row.access_level }}
117
- </BaseBadge>
128
+ <select class="select border-none text-sm rounded text-slate-600 focus:z-10 focus:ring-2 bg-transparent">
129
+ <option>Option 1</option>
130
+ <option>Option 2</option>
131
+ </select>
118
132
  </BaseTableColumn>
119
133
 
120
134
  <template #detail="{ row }">
121
- <div class="p-4 text-sm">
122
- <p>ID : {{ row.id }}</p>
123
- <p>Created at : {{ row.created_at }}</p>
135
+ <div class="p-4 text-xs">
136
+ <p>ID : <span class="font-mono">{{ row.id }}</span></p>
137
+ <p>Created at : <span class="font-mono">{{ row.created_at }}</span></p>
124
138
  </div>
125
139
  </template>
126
140
 
141
+
127
142
  <template #test>
128
143
  <div>
129
144
  Section Test
@@ -189,7 +204,7 @@ const templateSetup = (args) => {
189
204
  lastFetch.value = new Date();
190
205
  }
191
206
 
192
- return { args, onCellClick, ownerIsVisible: true, onFetch, lastFetch };
207
+ return { args, onCellClick, ownerIsVisible: true, onFetch, lastFetch, DateTime };
193
208
  };
194
209
 
195
210
  const Template = (args) => ({
@@ -219,12 +234,12 @@ Demo.args = {
219
234
  actions: [
220
235
  {
221
236
  label: 'Open Google',
222
- icon: 'heroicons:link',
237
+ icon: 'heroicons:link-20-solid',
223
238
  href: 'https://google.com',
224
239
  },
225
240
  {
226
241
  label: 'Export',
227
- icon: 'heroicons:table-cells',
242
+ icon: 'heroicons:arrow-down-tray',
228
243
  action: () => alert('export!'),
229
244
  },
230
245
  { line: true },
@@ -262,6 +277,21 @@ Demo.args = {
262
277
  ],
263
278
  };
264
279
 
280
+ export const Small = Template.bind({});
281
+ Small.args = {
282
+ editUrl() {
283
+ return '/';
284
+ },
285
+ deleteUrl() {
286
+ return '/';
287
+ },
288
+ size: 'sm',
289
+ searchable: true,
290
+ toggleable: true,
291
+ actions: [],
292
+ };
293
+
294
+
265
295
  const VIfOnBaseTableColumn = (args) => ({
266
296
  components: templateComponents,
267
297
  setup() {
@@ -338,4 +368,4 @@ Simple.args = {
338
368
  searchable: false,
339
369
  toggleable: false,
340
370
  actions: [],
341
- };
371
+ };