adminforth 1.1.29 → 1.1.30

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 (41) hide show
  1. package/dist/index.js +0 -1
  2. package/dist/plugins/AccessControl/index.js +3 -56
  3. package/dist/plugins/ForeignInlineListPlugin/custom/InlineList.vue +2 -2
  4. package/dist/plugins/ForeignInlineListPlugin/index.js +0 -1
  5. package/dist/plugins/plugins/ForeignInlineListPlugin/custom/InlineList.vue +248 -0
  6. package/dist/spa/index.html +2 -2
  7. package/dist/spa/package-lock.json +1 -189
  8. package/dist/spa/package.json +1 -6
  9. package/dist/spa/spa/src/components/ResourceListTable.vue +2 -2
  10. package/dist/spa/spa/src/components/ShowTableItem.vue +14 -0
  11. package/dist/spa/spa/src/views/HomeView.vue +8 -0
  12. package/dist/spa/spa/src/views/ListView.vue +2 -2
  13. package/dist/spa/spa/src/views/ShowView.vue +2 -2
  14. package/dist/spa/src/App.vue +57 -76
  15. package/dist/spa/src/components/AcceptModal.vue +1 -1
  16. package/dist/spa/src/components/CustomDatePicker.vue +3 -3
  17. package/dist/spa/src/components/CustomDateRangePicker.vue +3 -3
  18. package/dist/spa/src/components/Dropdown.vue +4 -13
  19. package/dist/spa/src/components/Filters.vue +22 -55
  20. package/dist/spa/src/components/MenuLink.vue +2 -2
  21. package/dist/spa/src/components/ResourceForm.vue +99 -157
  22. package/dist/spa/src/components/ValueRenderer.vue +1 -11
  23. package/dist/spa/src/router/index.ts +2 -3
  24. package/dist/spa/src/stores/core.ts +33 -22
  25. package/dist/spa/src/utils.ts +3 -5
  26. package/dist/spa/src/views/CreateView.vue +7 -15
  27. package/dist/spa/src/views/EditView.vue +8 -36
  28. package/dist/spa/src/views/HomeView.vue +8 -0
  29. package/dist/spa/src/views/ListView.vue +23 -35
  30. package/dist/spa/src/views/LoginView.vue +1 -1
  31. package/dist/spa/src/views/ResourceParent.vue +1 -1
  32. package/dist/spa/src/views/ShowView.vue +9 -20
  33. package/dist/spa/tailwind.config.js +2 -5
  34. package/index.ts +0 -1
  35. package/package.json +1 -1
  36. package/plugins/ForeignInlineListPlugin/custom/InlineList.vue +2 -2
  37. package/plugins/ForeignInlineListPlugin/index.ts +0 -1
  38. package/spa/src/components/ResourceListTable.vue +2 -2
  39. package/spa/src/views/ListView.vue +2 -2
  40. package/spa/src/views/ShowView.vue +2 -2
  41. package/dist/spa/src/components/CustomRangePicker.vue +0 -148
@@ -65,7 +65,7 @@
65
65
  </BreadcrumbsWithButtons>
66
66
 
67
67
  <!-- table -->
68
- <div class="relative overflow-x-auto shadow-list-table-shadow dark:shadow-black dark:s">
68
+ <div class="relative overflow-x-auto shadow-md sm:rounded-lg dark:shadow-2xl">
69
69
 
70
70
 
71
71
  <!-- skelet loader -->
@@ -90,7 +90,7 @@
90
90
  </div>
91
91
 
92
92
  <table v-else class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
93
- <thead class="text-xs text-view-table-heading-text bg-list-view-table-heading dark:bg-gray-700 dark:text-gray-400">
93
+ <thead class="text-xs text-gray-700 bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
94
94
  <tr>
95
95
  <th scope="col" class="p-4">
96
96
  <div v-if="rows && rows.length" class="flex items-center">
@@ -127,7 +127,7 @@
127
127
  </tr>
128
128
  </thead>
129
129
  <tbody>
130
- <tr v-if="!rows" class="bg-list-view-table-bg border-b dark:bg-gray-800 dark:border-gray-700">
130
+ <tr v-if="!rows" class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
131
131
  <td :colspan="coreStore.resourceColumns.length + 2">
132
132
 
133
133
  <div role="status"
@@ -171,7 +171,7 @@
171
171
  </div>
172
172
  </td>
173
173
  </tr>
174
- <tr v-else-if="rows.length === 0" class="bg-list-view-table-bg border-b dark:bg-gray-800 dark:border-gray-700">
174
+ <tr v-else-if="rows.length === 0" class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
175
175
  <td :colspan="coreStore.resourceColumns.length + 2">
176
176
 
177
177
  <div id="toast-simple"
@@ -185,7 +185,7 @@
185
185
  </tr>
186
186
 
187
187
  <tr v-else v-for="(row, rowI) in rows" :key="row.id"
188
- class="bg-list-view-table-bg border-b dark:bg-gray-800 border-list-view-border-color dark:border-gray-700 hover:bg-list-view-table-row-hover dark:hover:bg-gray-600">
188
+ class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
189
189
  <td class="w-4 p-4">
190
190
  <div class="flex items center">
191
191
  <input
@@ -198,12 +198,7 @@
198
198
  </div>
199
199
  </td>
200
200
  <td v-for="c in columnsListed" class="px-6 py-4">
201
- <!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
202
- <component
203
- :is="listComponentsPerColumn[c.name] || ValueRenderer"
204
- :column="c"
205
- :row="row"
206
- />
201
+ <ValueRenderer :column="c" :row="row"/>
207
202
  </td>
208
203
  <td class="flex items-center px-6 py-4">
209
204
 
@@ -315,28 +310,29 @@
315
310
  </template>
316
311
 
317
312
  <script setup>
313
+ import {ref, onMounted, watch, computed} from 'vue';
314
+ import {callAdminForthApi, getIcon} from '@/utils';
315
+ import {useRoute} from 'vue-router';
316
+ import {useCoreStore} from '@/stores/core';
317
+ import {useModalStore} from '@/stores/modal';
318
318
  import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
319
- import { useCoreStore } from '@/stores/core';
320
- import { useModalStore } from '@/stores/modal';
321
- import { callAdminForthApi, getIcon } from '@/utils';
322
- import { initFlowbite } from 'flowbite';
323
- import { computed, onMounted, ref, watch } from 'vue';
324
- import { useRoute } from 'vue-router';
319
+ import {initFlowbite} from 'flowbite'
325
320
 
326
321
  import ValueRenderer from '@/components/ValueRenderer.vue';
327
- import { getCustomComponent } from '@/utils';
328
322
 
329
323
  import {
330
- IconInboxOutline,
331
- IconPlusOutline
324
+ IconChevronDoubleLeftOutline,
325
+ IconChevronDoubleRightOutline,
326
+ IconInboxFullSolid,
327
+ IconInboxOutline,
328
+ IconPlusOutline
332
329
  } from '@iconify-prerendered/vue-flowbite';
333
330
 
334
331
  import {
335
- IconBanOutline,
336
- IconEyeSolid,
337
- IconFilterOutline,
338
- IconPenSolid,
339
- IconTrashBinSolid
332
+ IconEyeSolid,
333
+ IconTrashBinSolid,
334
+ IconPenSolid,
335
+ IconFilterOutline, IconBanOutline
340
336
  } from '@iconify-prerendered/vue-flowbite';
341
337
 
342
338
  import Filters from '@/components/Filters.vue';
@@ -361,6 +357,7 @@ const totalRows = ref(0);
361
357
  const allCheckedActions = ref([]);
362
358
  const allowedActions = ref({});
363
359
 
360
+
364
361
  const DEFAULT_PAGE_SIZE = 10;
365
362
 
366
363
  const columnsListed = computed(() => coreStore.resourceColumns?.filter(c => c.showIn.includes('list')));
@@ -379,7 +376,6 @@ async function selectAll(value) {
379
376
 
380
377
  const pageSize = computed(() => coreStore.resourceById[route.params.resourceId]?.pageSize || DEFAULT_PAGE_SIZE);
381
378
  const totalPages = computed(() => Math.ceil(totalRows.value / pageSize.value));
382
- let listComponentsPerColumn = {};
383
379
  const allFromThisPageChecked = computed(() => {
384
380
  if (!rows.value) return false;
385
381
  return rows.value.every((r) => checkboxes.value.includes(r.id));
@@ -423,7 +419,6 @@ async function getList() {
423
419
  path: '/get_resource_data',
424
420
  method: 'POST',
425
421
  body: {
426
- source: 'list',
427
422
  resourceId: route.params.resourceId,
428
423
  limit: pageSize.value,
429
424
  offset: (page.value - 1) * pageSize.value,
@@ -431,14 +426,7 @@ async function getList() {
431
426
  sort: sort.value,
432
427
  }
433
428
  });
434
- listComponentsPerColumn = coreStore.resourceColumns.reduce((acc, column) => {
435
- if (column.component?.list) {
436
- acc[column.name] = getCustomComponent(column.component.list);
437
- }
438
- return acc;
439
- }, {});
440
-
441
- fetchStatus.value.pending = false;
429
+ fetchStatus.value.pending = false;
442
430
  rows.value = data.data?.map(row => {
443
431
  row._primaryKeyValue = row[coreStore.resourceColumns.find(c => c.primaryKey).name];
444
432
  return row;
@@ -11,7 +11,7 @@
11
11
  <div id="authentication-modal" tabindex="-1" class=" overflow-y-auto overflow-x-hidden z-50 min-w-[400px] justify-center items-center md:inset-0 h-[calc(100%-1rem)] max-h-full">
12
12
  <div class="relative p-4 w-full max-w-md max-h-full">
13
13
  <!-- Modal content -->
14
- <div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black" >
14
+ <div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
15
15
  <!-- Modal header -->
16
16
  <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
17
17
  <h3 class="text-xl font-semibold text-gray-900 dark:text-white">
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :key="`${$route?.params.resourceId}---${$route?.params.primaryKey}`">
2
+ <div>
3
3
  <RouterView/>
4
4
  </div>
5
5
  </template>
@@ -27,10 +27,10 @@
27
27
  </div>
28
28
  <div
29
29
  v-else
30
- class="relative overflow-x-auto shadow-resourse-form-shadow "
30
+ class="relative overflow-x-auto shadow-md sm:rounded-lg"
31
31
  >
32
32
  <table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
33
- <thead class="text-xs text-gray-700 uppercase bg-form-view-heading dark:bg-gray-700 dark:text-gray-400">
33
+ <thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
34
34
  <tr>
35
35
  <th scope="col" class="px-6 py-3">
36
36
  Field
@@ -42,17 +42,13 @@
42
42
  </thead>
43
43
  <tbody>
44
44
  <tr v-for="column in coreStore.resourceColumns?.filter(c => c.showIn.includes('show'))" :key="column.name"
45
- class="bg-form-view-bg odd:dark:bg-gray-900 even:dark:bg-gray-800 border-b dark:border-gray-700"
45
+ class="odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800 border-b dark:border-gray-700"
46
46
  >
47
47
  <td class="px-6 py-4 whitespace-nowrap">
48
48
  {{ column.label }}
49
49
  </td>
50
50
  <td class="px-6 py-4 whitespace-nowrap whitespace-pre-wrap">
51
- <component
52
- :is="showComponentsPerColumn[column.name] || ValueRenderer"
53
- :column="column"
54
- :row="coreStore.record"
55
- />
51
+ <ValueRenderer :column="column" :row="coreStore.record" />
56
52
  </td>
57
53
  </tr>
58
54
 
@@ -67,19 +63,18 @@
67
63
 
68
64
  <script setup>
69
65
 
66
+ import { ref, computed, onMounted } from 'vue';
67
+ import { useRoute } from 'vue-router';
68
+ import { callAdminForthApi } from '@/utils';
70
69
  import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
71
- import ValueRenderer from '@/components/ValueRenderer.vue';
72
- import { useCoreStore } from '@/stores/core';
73
- import { getCustomComponent } from '@/utils';
74
70
  import { IconPenSolid, IconTrashBinSolid } from '@iconify-prerendered/vue-flowbite';
75
- import { onMounted, ref } from 'vue';
76
- import { useRoute } from 'vue-router';
71
+ import { useCoreStore } from '@/stores/core';
72
+ import ValueRenderer from '@/components/ValueRenderer.vue';
77
73
 
78
74
 
79
75
  const item = ref(null);
80
76
  const route = useRoute();
81
77
  const loading = ref(false);
82
- let showComponentsPerColumn = {};
83
78
 
84
79
  const coreStore = useCoreStore();
85
80
 
@@ -92,12 +87,6 @@ onMounted(async () => {
92
87
  resourceId: route.params.resourceId,
93
88
  primaryKey: route.params.primaryKey,
94
89
  });
95
- showComponentsPerColumn = coreStore.resourceColumns.reduce((acc, column) => {
96
- if (column.component?.show) {
97
- acc[column.name] = getCustomComponent(column.component.show);
98
- }
99
- return acc;
100
- }, {});
101
90
  loading.value = false;
102
91
  });
103
92
 
@@ -1,12 +1,9 @@
1
1
  /** @type {import('tailwindcss').Config} */
2
2
  export default {
3
- content: ["./src/**/*.{vue, js}","./src/*.{vue, js}", "./index.html", "./node_modules/flowbite/**/*.js"],
3
+ content: ["./src/**/*.{vue, js}", "./node_modules/flowbite/**/*.js"],
4
4
  theme: {
5
- extend: {
6
- /* IMPORTANT:ADMINFORTH TAILWIND STYLES */
7
- }
5
+ extend: {},
8
6
  },
9
-
10
7
  darkMode: 'class',
11
8
  plugins: [
12
9
  require('flowbite/plugin'),
package/index.ts CHANGED
@@ -786,7 +786,6 @@ class AdminForth implements AdminForthClass {
786
786
  await interpretResource(adminUser, resource, { requestBody: body }, ActionCheckSource.DisplayButtons);
787
787
 
788
788
  const { allowed, error } = checkAccess(source as AllowedActionsEnum, resource);
789
- console.log('allowed', allowed, error);
790
789
  if (!allowed) {
791
790
  return { error };
792
791
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "1.1.29",
3
+ "version": "1.1.30",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  v-if="checkboxes.length"
23
23
  data-tooltip-target="tooltip-remove-all"
24
24
  data-tooltip-placement="bottom"
25
- class="flex gap-1 items-center py-1 px-3 me-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
25
+ class="flex gap-1 items-center py-1 px-3 me-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-default border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
26
26
  >
27
27
  <IconBanOutline class="w-5 h-5 "/>
28
28
  <div id="tooltip-remove-all" role="tooltip"
@@ -37,7 +37,7 @@
37
37
  v-for="(action,i) in listResource?.options?.bulkActions"
38
38
  :key="action.id"
39
39
  @click="startBulkAction(action.id)"
40
- class="flex gap-1 items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
40
+ class="flex gap-1 items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-default border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
41
41
  :class="{'bg-red-100 text-red-800 border-red-400 dark:bg-red-700 dark:text-red-400 dark:border-red-400':action.state==='danger', 'bg-green-100 text-green-800 border-green-400 dark:bg-green-700 dark:text-green-400 dark:border-green-400':action.state==='success',
42
42
  'bg-blue-100 text-blue-800 border-blue-400 dark:bg-blue-700 dark:text-blue-400 dark:border-blue-400':action.state==='active',
43
43
  }"
@@ -43,7 +43,6 @@ export default class ForeignInlineListPlugin extends AdminForthPlugin {
43
43
  if (!this.foreignResource) {
44
44
  throw new Error(`ForeignInlineListPlugin: Resource with ID "${this.options.foreignResourceId}" not found`);
45
45
  }
46
- console.log('🔌 ForeignInlineListPlugin', this.options);
47
46
  resourceConfig.columns.push({
48
47
  name: `foreignInlineList_${this.foreignResource.resourceId}`,
49
48
  label: 'Foreign Inline List',
@@ -109,7 +109,7 @@
109
109
  <td :colspan="resource?.columns.length + 2">
110
110
 
111
111
  <div id="toast-simple"
112
- class=" mx-auto my-5 flex items-center w-full max-w-xs p-4 space-x-4 rtl:space-x-reverse text-gray-500 bg-white divide-x rtl:divide-x-reverse divide-gray-200 dark:text-gray-400 dark:divide-gray-700 space-x dark:bg-gray-800"
112
+ class=" mx-auto my-5 flex items-center w-full max-w-xs p-4 space-x-4 rtl:space-x-reverse text-gray-500 divide-x rtl:divide-x-reverse divide-gray-200 dark:text-gray-400 dark:divide-gray-700 space-x dark:bg-gray-800"
113
113
  role="alert">
114
114
  <IconInboxOutline class="w-6 h-6 text-gray-500 dark:text-gray-400"/>
115
115
  <div class="ps-4 text-sm font-normal">No items here yet</div>
@@ -208,7 +208,7 @@
208
208
  </table>
209
209
  </div>
210
210
  <!-- pagination -->
211
- <div class="flex flex-col items-center mt-4 xs:flex-row xs:justify-between xs:items-center"
211
+ <div class="flex flex-col items-center mt-4 mb-4 xs:flex-row xs:justify-between xs:items-center"
212
212
  v-if="rows && totalRows >= pageSize && totalRows > 0"
213
213
  >
214
214
  <!-- Help text -->
@@ -22,7 +22,7 @@
22
22
  v-if="checkboxes.length"
23
23
  data-tooltip-target="tooltip-remove-all"
24
24
  data-tooltip-placement="bottom"
25
- class="flex gap-1 items-center py-1 px-3 me-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
25
+ class="flex gap-1 items-center py-1 px-3 me-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 rounded-default"
26
26
  >
27
27
  <IconBanOutline class="w-5 h-5 "/>
28
28
 
@@ -38,7 +38,7 @@
38
38
  v-for="(action,i) in coreStore.resource?.options?.bulkActions"
39
39
  :key="action.id"
40
40
  @click="startBulkAction(action.id)"
41
- class="flex gap-1 items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
41
+ class="flex gap-1 items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-default border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
42
42
  :class="{'bg-red-100 text-red-800 border-red-400 dark:bg-red-700 dark:text-red-400 dark:border-red-400':action.state==='danger', 'bg-green-100 text-green-800 border-green-400 dark:bg-green-700 dark:text-green-400 dark:border-green-400':action.state==='success',
43
43
  'bg-blue-100 text-blue-800 border-blue-400 dark:bg-blue-700 dark:text-blue-400 dark:border-blue-400':action.state==='active',
44
44
  }"
@@ -10,14 +10,14 @@
10
10
  />
11
11
  <BreadcrumbsWithButtons>
12
12
  <RouterLink v-if="coreStore?.resourceOptions?.allowedActions?.edit" :to="{ name: 'resource-edit', params: { resourceId: $route.params.resourceId, primaryKey: $route.params.primaryKey } }"
13
- class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
13
+ class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-default border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
14
14
  >
15
15
  <IconPenSolid class="w-4 h-4" />
16
16
  Edit
17
17
  </RouterLink>
18
18
 
19
19
  <button v-if="coreStore?.resourceOptions?.allowedActions?.delete" @click="deleteRecord"
20
- class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
20
+ class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-white border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
21
21
  >
22
22
  <IconTrashBinSolid class="w-4 h-4" />
23
23
  Delete
@@ -1,148 +0,0 @@
1
- <template>
2
- <div class="flex flex-wrap gap-2">
3
- <input
4
- type="number" aria-describedby="helper-text-explanation"
5
- class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-20 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
6
- placeholder="From"
7
- v-model="start"
8
- >
9
-
10
- <input
11
- type="number" aria-describedby="helper-text-explanation"
12
- class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-20 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
13
- placeholder="To"
14
- v-model="end"
15
- >
16
-
17
- <button
18
- v-if="isChanged"
19
- type="button"
20
- class="flex items-center p-0.5 ml-auto px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
21
- @click="clear">Clear
22
- </button>
23
-
24
- <div class="w-full">
25
- <vue-slider
26
- class="custom-slider"
27
- :dot-size="20"
28
- height="7.99px"
29
- :min="minFormatted"
30
- :max="maxFormatted"
31
- v-model="sliderValue"
32
- @update:model-value="updateFromSlider($event)"
33
- />
34
- </div>
35
- </div>
36
- </template>
37
- <script setup lang="ts">
38
- import VueSlider from 'vue-slider-component';
39
- import 'vue-slider-component/theme/antd.css'
40
- import {computed, onMounted, ref, watch} from "vue";
41
- import debounce from 'debounce'
42
-
43
- const props = defineProps({
44
- valueStart: {
45
- default: '',
46
- },
47
- valueEnd: {
48
- default: '',
49
- },
50
- min: {
51
- default: 0,
52
- },
53
- max: {
54
- default: 10,
55
- },
56
- });
57
-
58
- const emit = defineEmits(['update:valueStart', 'update:valueEnd']);
59
-
60
- const minFormatted = computed(() => Math.floor(props.min));
61
- const maxFormatted = computed(() => Math.ceil(props.max));
62
-
63
- const isChanged = computed(() => {
64
- return start.value && start.value !== minFormatted.value || end.value && end.value !== maxFormatted.value;
65
- });
66
-
67
- const start = ref(props.valueStart);
68
- const end = ref(props.valueEnd);
69
-
70
- const sliderValue = ref([minFormatted.value, maxFormatted.value]);
71
-
72
- const updateFromSlider =
73
- debounce((value: [number, number]) => {
74
- start.value = value[0] === minFormatted.value ? '': value[0];
75
- end.value = value[1] === maxFormatted.value ? '': value[1];
76
- }, 500);
77
-
78
- onMounted(() => {
79
- updateStartFromProps();
80
- updateEndFromProps();
81
-
82
- watch(() => props.valueStart, (value) => {
83
- updateStartFromProps();
84
- });
85
-
86
- watch(() => props.valueEnd, (value) => {
87
- updateEndFromProps();
88
- });
89
- })
90
-
91
- function updateStartFromProps() {
92
- start.value = props.valueStart;
93
- setSliderValues(start.value, end.value)
94
- }
95
-
96
- function updateEndFromProps() {
97
- end.value = props.valueEnd;
98
- setSliderValues(start.value, end.value)
99
- }
100
-
101
- watch(start, () => {
102
- console.log('⚡ emit', start.value)
103
- emit('update:valueStart', start.value)
104
- })
105
-
106
- watch(end, () => {
107
- console.log('⚡ emit', end.value)
108
- emit('update:valueEnd', end.value);
109
- })
110
-
111
- const clear = () => {
112
- start.value = ''
113
- end.value = ''
114
- setSliderValues('', '')
115
- }
116
-
117
- function setSliderValues(start, end) {
118
- sliderValue.value = [start || minFormatted.value, end || maxFormatted.value];
119
- }
120
- </script>
121
-
122
- <style lang="scss" scoped>
123
- .custom-slider {
124
- &:deep(.vue-slider-rail) {
125
- background-color: rgb(229 231 235);
126
- }
127
-
128
- &:deep(.vue-slider-dot-handle) {
129
- background-color: #1c64f2;
130
- border: none;
131
- box-shadow: none;
132
- }
133
-
134
- &:deep(.vue-slider-dot-handle:hover) {
135
- background-color: #1c64f2;
136
- border: none;
137
- box-shadow: none;
138
- }
139
-
140
- &:deep(.vue-slider-process) {
141
- background-color: rgb(225 239 254);
142
- }
143
-
144
- &:deep(.vue-slider-process:hover) {
145
- background-color: rgb(225 239 254);
146
- }
147
- }
148
- </style>