adminforth 2.4.0-next.26 → 2.4.0-next.261

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 (168) hide show
  1. package/commands/callTsProxy.js +14 -4
  2. package/commands/cli.js +10 -3
  3. package/commands/createApp/templates/api.ts.hbs +10 -0
  4. package/commands/createApp/templates/custom/tsconfig.json.hbs +2 -3
  5. package/commands/createApp/templates/index.ts.hbs +12 -1
  6. package/commands/createApp/utils.js +25 -8
  7. package/commands/createCustomComponent/configLoader.js +17 -4
  8. package/commands/createCustomComponent/main.js +1 -0
  9. package/commands/createCustomComponent/templates/customCrud/beforeActionButtons.vue.hbs +38 -0
  10. package/commands/createPlugin/templates/custom/tsconfig.json.hbs +2 -5
  11. package/commands/createPlugin/templates/package.json.hbs +1 -1
  12. package/commands/generateModels.js +30 -22
  13. package/dist/auth.d.ts +9 -1
  14. package/dist/auth.d.ts.map +1 -1
  15. package/dist/auth.js +21 -2
  16. package/dist/auth.js.map +1 -1
  17. package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
  18. package/dist/dataConnectors/baseConnector.js +46 -15
  19. package/dist/dataConnectors/baseConnector.js.map +1 -1
  20. package/dist/dataConnectors/clickhouse.d.ts.map +1 -1
  21. package/dist/dataConnectors/clickhouse.js +15 -0
  22. package/dist/dataConnectors/clickhouse.js.map +1 -1
  23. package/dist/dataConnectors/mongo.d.ts.map +1 -1
  24. package/dist/dataConnectors/mongo.js +50 -15
  25. package/dist/dataConnectors/mongo.js.map +1 -1
  26. package/dist/dataConnectors/mysql.d.ts.map +1 -1
  27. package/dist/dataConnectors/mysql.js +11 -0
  28. package/dist/dataConnectors/mysql.js.map +1 -1
  29. package/dist/dataConnectors/postgres.d.ts.map +1 -1
  30. package/dist/dataConnectors/postgres.js +43 -14
  31. package/dist/dataConnectors/postgres.js.map +1 -1
  32. package/dist/dataConnectors/sqlite.d.ts.map +1 -1
  33. package/dist/dataConnectors/sqlite.js +11 -0
  34. package/dist/dataConnectors/sqlite.js.map +1 -1
  35. package/dist/index.d.ts +2 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +23 -9
  38. package/dist/index.js.map +1 -1
  39. package/dist/modules/codeInjector.d.ts +2 -0
  40. package/dist/modules/codeInjector.d.ts.map +1 -1
  41. package/dist/modules/codeInjector.js +50 -6
  42. package/dist/modules/codeInjector.js.map +1 -1
  43. package/dist/modules/configValidator.d.ts +6 -0
  44. package/dist/modules/configValidator.d.ts.map +1 -1
  45. package/dist/modules/configValidator.js +184 -19
  46. package/dist/modules/configValidator.js.map +1 -1
  47. package/dist/modules/restApi.d.ts.map +1 -1
  48. package/dist/modules/restApi.js +164 -26
  49. package/dist/modules/restApi.js.map +1 -1
  50. package/dist/modules/styles.d.ts +499 -13
  51. package/dist/modules/styles.d.ts.map +1 -1
  52. package/dist/modules/styles.js +555 -31
  53. package/dist/modules/styles.js.map +1 -1
  54. package/dist/modules/utils.d.ts +7 -15
  55. package/dist/modules/utils.d.ts.map +1 -1
  56. package/dist/modules/utils.js +45 -68
  57. package/dist/modules/utils.js.map +1 -1
  58. package/dist/servers/express.d.ts +5 -0
  59. package/dist/servers/express.d.ts.map +1 -1
  60. package/dist/servers/express.js +40 -1
  61. package/dist/servers/express.js.map +1 -1
  62. package/dist/spa/index.html +1 -1
  63. package/dist/spa/package-lock.json +5 -4
  64. package/dist/spa/package.json +1 -1
  65. package/dist/spa/src/App.vue +58 -173
  66. package/dist/spa/src/adminforth.ts +42 -18
  67. package/dist/spa/src/afcl/BarChart.vue +2 -2
  68. package/dist/spa/src/afcl/Button.vue +6 -6
  69. package/dist/spa/src/afcl/ButtonGroup.vue +91 -0
  70. package/dist/spa/src/afcl/Card.vue +25 -0
  71. package/dist/spa/src/afcl/Checkbox.vue +21 -13
  72. package/dist/spa/src/afcl/CountryFlag.vue +4 -1
  73. package/dist/spa/src/{components/CustomDatePicker.vue → afcl/DatePicker.vue} +95 -9
  74. package/dist/spa/src/afcl/Dialog.vue +47 -27
  75. package/dist/spa/src/afcl/Dropzone.vue +12 -12
  76. package/dist/spa/src/afcl/Input.vue +5 -5
  77. package/dist/spa/src/afcl/JsonViewer.vue +25 -0
  78. package/dist/spa/src/afcl/LinkButton.vue +3 -3
  79. package/dist/spa/src/afcl/PieChart.vue +5 -5
  80. package/dist/spa/src/afcl/ProgressBar.vue +7 -7
  81. package/dist/spa/src/afcl/Select.vue +68 -34
  82. package/dist/spa/src/afcl/Skeleton.vue +6 -6
  83. package/dist/spa/src/afcl/Table.vue +213 -74
  84. package/dist/spa/src/afcl/Textarea.vue +31 -0
  85. package/dist/spa/src/afcl/Toggle.vue +32 -0
  86. package/dist/spa/src/afcl/Tooltip.vue +26 -18
  87. package/dist/spa/src/afcl/VerticalTabs.vue +16 -7
  88. package/dist/spa/src/afcl/index.ts +6 -3
  89. package/dist/spa/src/components/AcceptModal.vue +48 -14
  90. package/dist/spa/src/components/Breadcrumbs.vue +5 -5
  91. package/dist/spa/src/components/ColumnValueInput.vue +38 -18
  92. package/dist/spa/src/components/ColumnValueInputWrapper.vue +4 -3
  93. package/dist/spa/src/components/CustomDateRangePicker.vue +9 -8
  94. package/dist/spa/src/components/CustomRangePicker.vue +37 -8
  95. package/dist/spa/src/components/ErrorMessage.vue +21 -0
  96. package/dist/spa/src/components/Filters.vue +85 -39
  97. package/dist/spa/src/components/GroupsTable.vue +9 -8
  98. package/dist/spa/src/components/MenuLink.vue +90 -23
  99. package/dist/spa/src/components/ResourceForm.vue +94 -51
  100. package/dist/spa/src/components/ResourceListTable.vue +90 -80
  101. package/dist/spa/src/components/ResourceListTableVirtual.vue +86 -76
  102. package/dist/spa/src/components/ShowTable.vue +21 -15
  103. package/dist/spa/src/components/Sidebar.vue +470 -0
  104. package/dist/spa/src/components/SingleSkeletLoader.vue +6 -6
  105. package/dist/spa/src/components/SkeleteLoader.vue +3 -3
  106. package/dist/spa/src/components/ThreeDotsMenu.vue +73 -14
  107. package/dist/spa/src/components/Toast.vue +27 -9
  108. package/dist/spa/src/components/UserMenuSettingsButton.vue +69 -0
  109. package/dist/spa/src/components/ValueRenderer.vue +43 -16
  110. package/dist/spa/src/controls/BoolToggle.vue +34 -0
  111. package/dist/spa/src/i18n.ts +1 -1
  112. package/dist/spa/src/renderers/CompactField.vue +1 -1
  113. package/dist/spa/src/renderers/CompactUUID.vue +1 -1
  114. package/dist/spa/src/router/index.ts +8 -0
  115. package/dist/spa/src/shims-vue.d.ts +5 -0
  116. package/dist/spa/src/spa_types/core.ts +13 -1
  117. package/dist/spa/src/stores/core.ts +13 -1
  118. package/dist/spa/src/stores/filters.ts +29 -2
  119. package/dist/spa/src/stores/modal.ts +6 -1
  120. package/dist/spa/src/stores/toast.ts +22 -3
  121. package/dist/spa/src/types/Back.ts +158 -22
  122. package/dist/spa/src/types/Common.ts +81 -32
  123. package/dist/spa/src/types/FrontendAPI.ts +31 -5
  124. package/dist/spa/src/types/adapters/CaptchaAdapter.ts +34 -0
  125. package/dist/spa/src/types/adapters/EmailAdapter.ts +2 -2
  126. package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
  127. package/dist/spa/src/types/adapters/KeyValueAdapter.ts +16 -0
  128. package/dist/spa/src/types/adapters/index.ts +8 -0
  129. package/dist/spa/src/utils.ts +279 -9
  130. package/dist/spa/src/views/CreateView.vue +18 -19
  131. package/dist/spa/src/views/EditView.vue +25 -19
  132. package/dist/spa/src/views/ListView.vue +144 -87
  133. package/dist/spa/src/views/LoginView.vue +26 -35
  134. package/dist/spa/src/views/ResourceParent.vue +2 -2
  135. package/dist/spa/src/views/SettingsView.vue +121 -0
  136. package/dist/spa/src/views/ShowView.vue +59 -39
  137. package/dist/spa/src/websocket.ts +6 -1
  138. package/dist/spa/tsconfig.app.json +1 -1
  139. package/dist/spa/vite.config.ts +45 -2
  140. package/dist/types/Back.d.ts +134 -14
  141. package/dist/types/Back.d.ts.map +1 -1
  142. package/dist/types/Back.js +15 -0
  143. package/dist/types/Back.js.map +1 -1
  144. package/dist/types/Common.d.ts +96 -29
  145. package/dist/types/Common.d.ts.map +1 -1
  146. package/dist/types/Common.js.map +1 -1
  147. package/dist/types/FrontendAPI.d.ts +31 -3
  148. package/dist/types/FrontendAPI.d.ts.map +1 -1
  149. package/dist/types/FrontendAPI.js.map +1 -1
  150. package/dist/types/adapters/CaptchaAdapter.d.ts +30 -0
  151. package/dist/types/adapters/CaptchaAdapter.d.ts.map +1 -0
  152. package/dist/types/adapters/CaptchaAdapter.js +5 -0
  153. package/dist/types/adapters/CaptchaAdapter.js.map +1 -0
  154. package/dist/types/adapters/EmailAdapter.d.ts +1 -1
  155. package/dist/types/adapters/ImageVisionAdapter.d.ts +25 -0
  156. package/dist/types/adapters/ImageVisionAdapter.d.ts.map +1 -0
  157. package/dist/types/adapters/ImageVisionAdapter.js +2 -0
  158. package/dist/types/adapters/ImageVisionAdapter.js.map +1 -0
  159. package/dist/types/adapters/KeyValueAdapter.d.ts +10 -0
  160. package/dist/types/adapters/KeyValueAdapter.d.ts.map +1 -0
  161. package/dist/types/adapters/KeyValueAdapter.js +2 -0
  162. package/dist/types/adapters/KeyValueAdapter.js.map +1 -0
  163. package/dist/types/adapters/index.d.ts +9 -0
  164. package/dist/types/adapters/index.d.ts.map +1 -0
  165. package/dist/types/adapters/index.js +2 -0
  166. package/dist/types/adapters/index.js.map +1 -0
  167. package/package.json +4 -2
  168. package/dist/spa/src/types/adapters/index.js +0 -5
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <label class="inline-flex items-center cursor-pointer bor" :class="{'opacity-50' : props.disabled}">
3
+ <input :id="id"
4
+ type="checkbox"
5
+ value="" class="sr-only peer"
6
+ :disabled="props.disabled"
7
+ :checked="props.modelValue"
8
+ @change="$emit('update:modelValue', ($event.target as HTMLInputElement).checked)"
9
+ >
10
+ <div class="afcl-toggle border border-lightToggleBorderUnactive relative min-w-11 min-h-6 bg-lightToggleBgUnactive peer-focus:outline-none peer-focus:ring-4
11
+ peer-focus:ring-lightToggleRing dark:peer-focus:ring-darkToggleRing rounded-full peer dark:bg-darkToggleBgUnactive
12
+ peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:top-[2px] peer-checked:border-none
13
+ peer-checked:after:border-lightToggleBorderActive after:content-[''] after:absolute after:top-[1px]
14
+ after:start-[2px] after:bg-lightToggleCircleUnactive peer-checked:after:bg-lightToggleCircleActive dark:after:bg-darkToggleCircleUnactive after:border-lightToggleBgUnactive dark:after:border-darkToggleBgUnactive after:border after:rounded-full
15
+ after:h-5 after:w-5 after:transition-all dark:border-darkToggleBorderUnactive peer-checked:bg-lightToggleBgActive
16
+ dark:peer-checked:bg-darkToggleBgActive dark:peer-checked:after:border-darkToggleBorderActive dark:peer-checked:after:bg-darkToggleCircleActive">
17
+ </div>
18
+ <label :for="id" class="cursor-pointer ms-3 text-sm font-medium text-lightToggleText dark:text-darkToggleText">
19
+ <slot></slot>
20
+ </label>
21
+ </label>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ const props = defineProps({
26
+ modelValue: Boolean,
27
+ disabled: Boolean,
28
+ });
29
+
30
+ defineEmits(['update:modelValue']);
31
+ const id = `afcb-${Math.random().toString(36).substring(7)}`
32
+ </script>
@@ -1,30 +1,34 @@
1
1
  <template>
2
- <div ref="triggerEl" class="afcl-tooltip inline-flex items-center">
2
+ <div ref="triggerEl" class="afcl-tooltip inline-flex items-center" @mouseenter="mouseOn" @mouseleave="mouseOff">
3
3
  <slot></slot>
4
4
  </div>
5
- <div
6
- role="tooltip"
7
- class="absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white transition-opacity duration-300 bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700"
8
- ref="tooltip"
9
- >
10
- <slot name="tooltip"></slot>
11
- <div class="tooltip-arrow" data-popper-arrow></div>
12
- </div>
13
-
5
+ <teleport to="body" v-if="showTooltip">
6
+ <div
7
+ role="tooltip"
8
+ class="absolute z-20 invisible inline-block px-3 py-2 text-sm font-medium text-lightTooltipText dark:darkTooltipText transition-opacity duration-300 bg-lightTooltipBackground rounded-lg shadow-sm opacity-0 tooltip dark:bg-darkTooltipBackground"
9
+ ref="tooltip"
10
+ >
11
+ <slot name="tooltip"></slot>
12
+ <div class="tooltip-arrow" data-popper-arrow></div>
13
+ </div>
14
+ </teleport>
14
15
  </template>
15
16
 
16
17
  <script setup lang="ts">
17
- import { ref, onMounted, nextTick, onUnmounted, type Ref } from 'vue';
18
+ import { ref, nextTick, type Ref } from 'vue';
18
19
  import { Tooltip } from 'flowbite';
19
20
 
20
21
  const triggerEl = ref(null);
21
22
  const tooltip = ref(null);
22
-
23
+ const showTooltip = ref(false);
23
24
  const tp: Ref<Tooltip|null> = ref(null);
24
25
 
25
- onMounted(async () => {
26
- //await one tick when all is mounted
26
+ async function mouseOn() {
27
+ showTooltip.value = true;
27
28
  await nextTick();
29
+
30
+ tp.value?.destroy();
31
+
28
32
  tp.value = new Tooltip(
29
33
  tooltip.value,
30
34
  triggerEl.value,
@@ -33,11 +37,15 @@ onMounted(async () => {
33
37
  triggerType: 'hover',
34
38
  },
35
39
  );
36
- })
37
40
 
41
+ tp.value.show();
42
+ }
38
43
 
39
- onUnmounted(() => {
40
- //destroy tooltip
44
+ function mouseOff() {
45
+ tp.value?.hide();
41
46
  tp.value?.destroy();
42
- })
47
+ tp.value = null;
48
+ showTooltip.value = false;
49
+ }
50
+
43
51
  </script>
@@ -1,26 +1,26 @@
1
1
  <template>
2
2
  <div class="md:flex">
3
- <ul class="flex-column space-y space-y-4 text-sm font-medium text-gray-500 dark:text-gray-400 md:me-4 mb-4 md:mb-0">
3
+ <ul class="ps-6 flex-column space-y space-y-4 text-sm font-medium text-lightVerticalTabsText dark:text-darkVerticalTabsText md:me-4 mb-4 md:mb-0 md:mr-0 mr-6">
4
4
  <li v-for="tab in tabs" :key="`${tab}-tab-controll`">
5
5
  <a
6
6
  href="#"
7
- @click="activeTab = tab"
7
+ @click="setActiveTab(tab)"
8
8
  class="inline-flex items-center px-4 py-3 rounded-lg w-full"
9
- :class="tab === activeTab ? 'text-lightPrimaryContrast bg-lightPrimary active dark:bg-darkPrimary' : 'text-gray-500 dark:text-gray-400 hover:text-gray-700 bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:hover:text-white'"
9
+ :class="tab === activeTab ? 'text-lightVerticalTabsTextActive bg-lightVerticalTabsBackgroundActive active dark:bg-darkVerticalTabsBackgroundActive dark:text-darkVerticalTabsTextActive' : 'text-lightVerticalTabsText dark:text-darkVerticalTabsText hover:text-lightVerticalTabsTextHover bg-lightVerticalTabsBackground hover:bg-lightVerticalTabsBackgroundHover dark:bg-darkVerticalTabsBackground dark:hover:bg-darkVerticalTabsBackgroundHover dark:hover:darkVerticalTabsTextHover'"
10
10
  aria-current="page"
11
11
  >
12
12
  <slot :name="`tab:${tab}`"></slot>
13
13
  </a>
14
14
  </li>
15
15
  </ul>
16
- <div class="ps-6 text-medium text-gray-500 dark:text-gray-400 w-full ">
16
+ <div class="ps-6 text-medium text-lightVerticalTabsSlotText dark:text-darkVerticalTabsSlotText w-full ">
17
17
  <slot :name="activeTab"></slot>
18
18
  </div>
19
19
  </div>
20
20
  </template>
21
21
 
22
22
  <script setup lang="ts">
23
- import { onMounted, useSlots, ref, type Ref } from 'vue';
23
+ import { onMounted, useSlots, ref, type Ref } from 'vue';
24
24
  const tabs : Ref<string[]> = ref([]);
25
25
  const activeTab = ref('');
26
26
  const props = defineProps({
@@ -31,6 +31,11 @@
31
31
  const emites = defineEmits([
32
32
  'update:activeTab',
33
33
  ]);
34
+
35
+ defineExpose({
36
+ setActiveTab
37
+ });
38
+
34
39
  onMounted(() => {
35
40
  const slots = useSlots();
36
41
  tabs.value = Object.keys(slots).reduce((tbs: string[], tb: string) => {
@@ -44,6 +49,10 @@
44
49
  }
45
50
  });
46
51
 
47
-
48
-
52
+ function setActiveTab(tab: string) {
53
+ if (tabs.value.includes(tab)) {
54
+ activeTab.value = tab;
55
+ emites('update:activeTab', tab);
56
+ }
57
+ }
49
58
  </script>
@@ -19,6 +19,9 @@ export { default as Skeleton } from './Skeleton.vue';
19
19
  export { default as Dialog } from './Dialog.vue';
20
20
  export { default as MixedChart } from './MixedChart.vue';
21
21
  export { default as CountryFlag } from './CountryFlag.vue';
22
-
23
-
24
-
22
+ export { default as JsonViewer } from './JsonViewer.vue';
23
+ export { default as Toggle } from './Toggle.vue';
24
+ export { default as DatePicker } from './DatePicker.vue';
25
+ export { default as Textarea } from './Textarea.vue';
26
+ export { default as ButtonGroup } from './ButtonGroup.vue';
27
+ export { default as Card } from './Card.vue';
@@ -1,29 +1,23 @@
1
- <script setup lang="ts">
2
- import { useModalStore } from '@/stores/modal';
3
-
4
- const modalStore = useModalStore();
5
- </script>
6
-
7
1
  <template>
8
2
  <Teleport to="body">
9
- <div v-if="modalStore.isOpened" class="bg-gray-900/50 dark:bg-gray-900/80 overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-full max-h-full">
10
- <div class="relative p-4 w-full max-w-md max-h-full top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 " >
11
- <div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black">
12
- <button type="button"@click="modalStore.togleModal" class="absolute top-3 end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" >
3
+ <div ref="modalEl" tabindex="-1" aria-hidden="true" class="hidden fixed inset-0 z-[110] w-full h-full overflow-y-auto overflow-x-hidden flex items-center justify-center">
4
+ <div class="relative p-4 w-full max-w-md max-h-full" >
5
+ <div class="afcl-confirmation-container relative bg-lightAcceptModalBackground rounded-lg shadow dark:bg-darkAcceptModalBackground dark:shadow-black">
6
+ <button type="button" @click="modalStore.togleModal" class="absolute top-3 end-2.5 text-lightAcceptModalCloseIcon bg-transparent hover:bg-lightAcceptModalCloseIconHoverBackground hover:text-lightAcceptModalCloseIconHover rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:text-darkAcceptModalCloseIcon dark:hover:bg-darkAcceptModalCloseIconHoverBackground dark:hover:text-darkAcceptModalCloseIconHover" >
13
7
  <svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
14
8
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
15
9
  </svg>
16
10
  <span class="sr-only">{{ $t('Close modal') }}</span>
17
11
  </button>
18
12
  <div class="p-4 md:p-5 text-center">
19
- <svg class="mx-auto mb-4 text-gray-400 w-12 h-12 dark:text-gray-200" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
13
+ <svg class="mx-auto mb-4 text-lightAcceptModalWarningIcon w-12 h-12 dark:text-darkAcceptModalWarningIcon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
20
14
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 11V6m0 8h.01M19 10a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/>
21
15
  </svg>
22
- <h3 class="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">{{ modalStore?.modalContent?.content }}</h3>
23
- <button @click="()=>{ modalStore.onAcceptFunction(true);modalStore.togleModal()}" type="button" class="text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center">
16
+ <h3 class="afcl-confirmation-title mb-5 text-lg font-normal text-lightAcceptModalText dark:text-darkAcceptModalText">{{ modalStore?.modalContent?.content }}</h3>
17
+ <button @click="()=>{ modalStore.onAcceptFunction(true);modalStore.togleModal()}" type="button" class="afcl-confirmation-accept-button text-lightAcceptModalConfirmButtonText bg-lightAcceptModalConfirmButtonBackground hover:bg-lightAcceptModalConfirmButtonBackgroundHover focus:ring-4 focus:outline-none focus:ring-lightAcceptModalConfirmButtonFocus font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center dark:text-darkAcceptModalConfirmButtonText dark:bg-darkAcceptModalConfirmButtonBackground dark:hover:bg-darkAcceptModalConfirmButtonBackgroundHover dark:focus:ring-darkAcceptModalConfirmButtonFocus">
24
18
  {{ modalStore?.modalContent?.acceptText }}
25
19
  </button>
26
- <button @click="()=>{modalStore.onAcceptFunction(false);modalStore.togleModal()}" type="button" class="py-2.5 px-5 ms-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-lightPrimary 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">{{ modalStore?.modalContent?.cancelText }}</button>
20
+ <button @click="()=>{modalStore.onAcceptFunction(false);modalStore.togleModal()}" type="button" class="afcl-confirmation-cancel-button py-2.5 px-5 ms-3 text-sm font-medium text-lightAcceptModalCancelButtonText focus:outline-none bg-lightAcceptModalCancelButtonBackground rounded-lg border border-lightAcceptModalCancelButtonBorder hover:bg-lightAcceptModalCancelButtonBackgroundHover hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-lightAcceptModalCancelButtonFocus dark:focus:ring-darkAcceptModalCancelButtonFocus dark:bg-darkAcceptModalCancelButtonBackground dark:text-darkAcceptModalCancelButtonText dark:border-darkAcceptModalCancelButtonBorder dark:hover:text-darkAcceptModalCancelButtonTextHover dark:hover:bg-darkAcceptModalCancelButtonBackgroundHover">{{ modalStore?.modalContent?.cancelText }}</button>
27
21
  </div>
28
22
  </div>
29
23
  </div>
@@ -32,6 +26,46 @@ const modalStore = useModalStore();
32
26
  </Teleport>
33
27
  </template>
34
28
 
29
+ <script setup lang="ts">
30
+ import { watch, onMounted, nextTick, ref } from 'vue';
31
+ import { useModalStore } from '@/stores/modal';
32
+ import { Modal } from 'flowbite';
33
+
34
+ const modalStore = useModalStore();
35
+ const modalEl = ref(null);
36
+ const modal = ref(null);
37
+
38
+ watch( () => modalStore.isOpened, (newVal) => {
39
+ if (newVal) {
40
+ open();
41
+ } else {
42
+ close();
43
+ }
44
+ }
45
+ );
46
+
47
+ onMounted(async () => {
48
+ await nextTick();
49
+ modal.value = new Modal(
50
+ modalEl.value,
51
+ {
52
+ closable: true,
53
+ backdrop: 'static',
54
+ backdropClasses: "bg-gray-900/50 dark:bg-gray-900/80 fixed inset-0 z-[100]"
55
+ }
56
+ );
57
+ })
58
+
59
+ function open() {
60
+ modal.value?.show();
61
+ }
62
+
63
+ function close() {
64
+ modal.value?.hide();
65
+ }
66
+
67
+ </script>
68
+
35
69
  <style scoped>
36
70
  .modal {
37
71
  position: fixed;
@@ -2,7 +2,7 @@
2
2
  <nav class="flex" aria-label="Breadcrumb">
3
3
  <ol class="inline-flex items-center space-x-1 md:space-x-2 rtl:space-x-reverse flex-wrap">
4
4
  <li class="inline-flex items-center">
5
- <RouterLink :to="{name: 'home'}" class="inline-flex items-center text-sm font-medium text-gray-700 hover:text-lightPrimary dark:text-gray-400 dark:hover:text-white">
5
+ <RouterLink :to="{name: 'home'}" class="inline-flex items-center text-sm font-medium text-lightBreadcrumbsHomepageText hover:text-lightBreadcrumbsHomepageTextHover dark:text-darkBreadcrumbsHomepageText dark:hover:text-darkBreadcrumbsHomepageTextHover">
6
6
  <svg class="w-3 h-3 me-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
7
7
  <path d="m19.707 9.293-2-2-7-7a1 1 0 0 0-1.414 0l-7 7-2 2a1 1 0 0 0 1.414 1.414L2 10.414V18a2 2 0 0 0 2 2h3a1 1 0 0 0 1-1v-4a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v4a1 1 0 0 0 1 1h3a2 2 0 0 0 2-2v-7.586l.293.293a1 1 0 0 0 1.414-1.414Z"/>
8
8
  </svg>
@@ -11,19 +11,19 @@
11
11
  </li>
12
12
  <li>
13
13
  <div class="flex items-center">
14
- <svg class="rtl:rotate-180 w-3 h-3 text-gray-400 mx-1" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
14
+ <svg class="rtl:rotate-180 w-3 h-3 text-lightBreadcrumbsArrowIcon dark:text-darkBreadcrumbsArrowIcon mx-1" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
15
15
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 9 4-4-4-4"/>
16
16
  </svg>
17
- <RouterLink :to="{name: 'resource-list', params: { resourceId: $route.params.resourceId }}" class="text-sm font-medium text-gray-500 md:ms-2 dark:text-gray-400">{{ coreStore.resourceById[$route.params.resourceId]?.label }}</RouterLink>
17
+ <RouterLink :to="{name: 'resource-list', params: { resourceId: $route.params.resourceId }}" class="text-sm font-medium text-lightBreadcrumbsText md:ms-2 dark:text-darkBreadcrumbsText">{{ coreStore.resourceById[$route.params.resourceId]?.label }}</RouterLink>
18
18
  </div>
19
19
  </li>
20
20
 
21
21
  <li v-if="$route.params.primaryKey">
22
22
  <div class="flex items-center">
23
- <svg class="rtl:rotate-180 w-3 h-3 text-gray-400 mx-1" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
23
+ <svg class="rtl:rotate-180 w-3 h-3 text-lightBreadcrumbsArrowIcon dark:text-darkBreadcrumbsArrowIcon mx-1" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
24
24
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 9 4-4-4-4"/>
25
25
  </svg>
26
- <span class="ms-1 text-sm font-medium text-gray-500 md:ms-2 dark:text-gray-400
26
+ <span class="ms-1 text-sm font-medium text-lightBreadcrumbsText md:ms-2 dark:text-darkBreadcrumbsText
27
27
  max-w-80 truncate">
28
28
  {{ $route.name === 'resource-edit' ? $t('Edit') : $t('Show') }} {{ coreStore.record?._label }}</span>
29
29
  </div>
@@ -17,14 +17,29 @@
17
17
  <Select
18
18
  v-else-if="column.foreignResource"
19
19
  ref="input"
20
+ :key="`${column.name}-${(columnOptions[column.name] || []).length}`"
20
21
  class="w-full min-w-24"
21
22
  :options="columnOptions[column.name] || []"
23
+ :searchDisabled="!column.foreignResource.searchableFields"
24
+ @scroll-near-end="loadMoreOptions && loadMoreOptions(column.name)"
25
+ @search="(searchTerm) => {
26
+ if (column.foreignResource.searchableFields && onSearchInput && onSearchInput[column.name]) {
27
+ onSearchInput[column.name](searchTerm);
28
+ }
29
+ }"
22
30
  teleportToBody
23
31
  :placeholder = "columnOptions[column.name]?.length ?$t('Select...'): $t('There are no options available')"
24
32
  :modelValue="value"
25
33
  :readonly="(column.editReadonly && source === 'edit') || readonly"
26
34
  @update:modelValue="$emit('update:modelValue', $event)"
27
- />
35
+ >
36
+ <template #extra-item v-if="columnLoadingState && columnLoadingState[column.name]?.loading">
37
+ <div class="text-center text-gray-400 dark:text-gray-300 py-2 flex items-center justify-center gap-2">
38
+ <Spinner class="w-4 h-4" />
39
+ {{ $t('Loading...') }}
40
+ </div>
41
+ </template>
42
+ </Select>
28
43
  <Select
29
44
  v-else-if="column.enum"
30
45
  ref="input"
@@ -52,6 +67,7 @@
52
67
  step="1"
53
68
  class="w-40"
54
69
  placeholder="0"
70
+ :fullWidth="true"
55
71
  :min="![undefined, null].includes(column.minValue) ? column.minValue : ''"
56
72
  :max="![undefined, null].includes(column.maxValue) ? column.maxValue : ''"
57
73
  :prefix="column.inputPrefix"
@@ -60,7 +76,7 @@
60
76
  :modelValue="value"
61
77
  @update:modelValue="$emit('update:modelValue', $event)"
62
78
  />
63
- <CustomDatePicker
79
+ <DatePicker
64
80
  v-else-if="['datetime', 'date', 'time'].includes(type || column.type)"
65
81
  ref="input"
66
82
  :column="column"
@@ -76,6 +92,7 @@
76
92
  step="0.1"
77
93
  class="w-40"
78
94
  placeholder="0.0"
95
+ :fullWidth="true"
79
96
  :min="![undefined, null].includes(column.minValue) ? column.minValue : ''"
80
97
  :max="![undefined, null].includes(column.maxValue) ? column.maxValue : ''"
81
98
  :prefix="column.inputPrefix"
@@ -84,28 +101,25 @@
84
101
  @update:modelValue="$emit('update:modelValue', $event)"
85
102
  :readonly="(column.editReadonly && source === 'edit') || readonly"
86
103
  />
87
- <textarea
104
+ <Textarea
88
105
  v-else-if="['text', 'richtext'].includes(type || column.type)"
89
- ref="input"
90
- class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
91
106
  :placeholder="$t('Text')"
92
- :value="value"
93
- @input="$emit('update:modelValue', $event.target.value)"
107
+ :modelValue="value"
108
+ @update:modelValue="$emit('update:modelValue', $event)"
94
109
  :readonly="(column.editReadonly && source === 'edit') || readonly"
95
110
  />
96
- <textarea
111
+ <Textarea
97
112
  v-else-if="['json'].includes(type || column.type)"
98
- ref="input"
99
- class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-lightPrimary focus:border-lightPrimary dark:focus:ring-darkPrimary dark:focus:border-darkPrimary"
100
113
  :placeholder="$t('Text')"
101
- :value="value"
102
- @input="$emit('update:modelValue', $event.target.value)"
114
+ :modelValue="value"
115
+ @update:modelValue="$emit('update:modelValue', $event)"
103
116
  />
104
117
  <Input
105
118
  v-else
106
119
  ref="input"
107
120
  :type="!column.masked || unmasked[column.name] ? 'text' : 'password'"
108
121
  class="w-full"
122
+ :fullWidth="true"
109
123
  :placeholder="$t('Text')"
110
124
  :prefix="column.inputPrefix"
111
125
  :suffix="column.inputSuffix"
@@ -123,7 +137,7 @@
123
137
  class="h-6 inset-y-2 right-0 flex items-center px-2 pt-4 z-index-100 focus:outline-none"
124
138
  @click="$emit('delete')"
125
139
  >
126
- <IconTrashBinSolid class="w-6 h-6 text-gray-400"/>
140
+ <IconTrashBinSolid class="w-6 h-6 text-lightInputIcons dark:text-darkInputIcons"/>
127
141
  </button>
128
142
  <button
129
143
  v-else-if="column.masked"
@@ -131,18 +145,20 @@
131
145
  @click="$emit('update:unmasked')"
132
146
  class="h-6 inset-y-2 right-0 flex items-center px-2 pt-4 z-index-100 focus:outline-none"
133
147
  >
134
- <IconEyeSolid class="w-6 h-6 text-gray-400" v-if="!unmasked[column.name]"/>
135
- <IconEyeSlashSolid class="w-6 h-6 text-gray-400" v-else />
148
+ <IconEyeSolid class="w-6 h-6 text-lightInputIcons dark:text-darkInputIcons" v-if="!unmasked[column.name]"/>
149
+ <IconEyeSlashSolid class="w-6 h-6 text-lightInputIcons dark:text-darkInputIcons" v-else />
136
150
  </button>
137
151
  </div>
138
152
  </template>
139
153
 
140
154
  <script setup lang="ts">
141
155
  import { IconEyeSlashSolid, IconEyeSolid, IconTrashBinSolid } from '@iconify-prerendered/vue-flowbite';
142
- import CustomDatePicker from "@/components/CustomDatePicker.vue";
156
+ import DatePicker from "@/afcl/DatePicker.vue";
143
157
  import Select from '@/afcl/Select.vue';
144
158
  import Input from '@/afcl/Input.vue';
145
- import { ref } from 'vue';
159
+ import Spinner from '@/afcl/Spinner.vue';
160
+ import Textarea from '@/afcl/Textarea.vue';
161
+ import { ref, inject } from 'vue';
146
162
  import { getCustomComponent } from '@/utils';
147
163
  import { useI18n } from 'vue-i18n';
148
164
  import { useCoreStore } from '@/stores/core';
@@ -171,7 +187,11 @@
171
187
  }
172
188
  );
173
189
 
174
- const input = ref(null);
190
+ const columnLoadingState = inject('columnLoadingState', {} as any);
191
+ const onSearchInput = inject('onSearchInput', {} as any);
192
+ const loadMoreOptions = inject('loadMoreOptions', (() => {}) as any);
193
+
194
+ const input = ref<HTMLInputElement | null>(null);
175
195
 
176
196
  const getBooleanOptions = (column: any) => {
177
197
  const options: Array<{ label: string; value: boolean | null }> = [
@@ -13,12 +13,13 @@
13
13
  :currentValues="currentValues"
14
14
  :mode="mode"
15
15
  :columnOptions="columnOptions"
16
+ :unmasked="unmasked"
16
17
  :deletable="!column.editReadonly"
17
18
  @update:modelValue="setCurrentValue(column.name, $event, arrayItemIndex)"
18
19
  @update:unmasked="$emit('update:unmasked', column.name)"
19
20
  @update:inValidity="$emit('update:inValidity', { name: column.name, value: $event })"
20
21
  @update:emptiness="$emit('update:emptiness', { name: column.name, value: $event })"
21
- @delete="setCurrentValue(column.name, currentValues[column.name].filter((_, index) => index !== arrayItemIndex))"
22
+ @delete="setCurrentValue(column.name, currentValues[column.name].filter((_: any, index: any) => index !== arrayItemIndex))"
22
23
  />
23
24
  </div>
24
25
  <div class="flex items-center">
@@ -26,7 +27,7 @@
26
27
  v-if="!column.editReadonly"
27
28
  type="button"
28
29
  @click="addArrayItem"
29
- class="flex items-center py-1 px-3 me-2 text-sm font-medium rounded-default text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-lightPrimary 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"
30
+ class="flex items-center py-1 px-3 me-2 text-sm font-medium rounded-default text-lightInputText focus:outline-none bg-lightInputBackground rounded border border-lightInputBorder hover:bg-lightInputBackgroundHover hover:text-lightInputTextHover hover:border-lightInputBorderHover focus:z-10 focus:ring-4 focus:ring-lightInputFocusRing dark:focus:ring-darkInputFocusRing dark:bg-darkInputBackground dark:text-darkInputText dark:border-darkInputBorder dark:hover:darkInputTextHover dark:hover:bg-darkInputHover"
30
31
  :class="{'mt-2': currentValues[column.name].length}"
31
32
  >
32
33
  <IconPlusOutline class="w-4 h-4 me-2"/>
@@ -70,7 +71,7 @@
70
71
 
71
72
  const emit = defineEmits(['update:unmasked', 'update:inValidity', 'update:emptiness', 'focus-last-input']);
72
73
 
73
- const arrayItemRefs = ref([]);
74
+ const arrayItemRefs = ref<HTMLInputElement[]>([]);
74
75
 
75
76
  async function addArrayItem() {
76
77
  props.setCurrentValue(props.column.name, props.currentValues[props.column.name], props.currentValues[props.column.name].length);
@@ -3,21 +3,21 @@
3
3
  <div class="mx-auto grid grid-cols-2 gap-4 mb-2" :class="{hidden: column.type === 'time'}">
4
4
  <div class="relative">
5
5
  <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5 pointer-events-none">
6
- <IconCalendar class="w-4 h-4 text-gray-500 dark:text-gray-400"/>
6
+ <IconCalendar class="w-4 h-4 text-lightDatePickerIcon dark:text-darkDatePickerIcon"/>
7
7
  </div>
8
8
 
9
9
  <input ref="datepickerStartEl" type="text"
10
- class="bg-gray-50 border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full 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"
10
+ class="bg-lightDatePickerButtonBackground border leading-none border-lightDatePickerButtonBorder text-lightDatePickerButtonText placeholder-lightDatePickerPlaceHolder text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-darkDatePickerButtonBackground dark:border-darkDatePickerButtonBorder dark:placeholder-darkDatePickerPlaceHolder dark:text-darkDatePickerButtonText dark:focus:ring-blue-500 dark:focus:border-blue-500"
11
11
  :placeholder="$t('From')">
12
12
  </div>
13
13
 
14
14
  <div class="relative">
15
15
  <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5 pointer-events-none">
16
- <IconCalendar class="w-4 h-4 text-gray-500 dark:text-gray-400"/>
16
+ <IconCalendar class="w-4 h-4 text-lightDatePickerIcon dark:text-darkDatePickerIcon"/>
17
17
  </div>
18
18
 
19
19
  <input ref="datepickerEndEl" type="text"
20
- class="bg-gray-50 border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full 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"
20
+ class="bg-lightDatePickerButtonBackground border leading-none border-lightDatePickerButtonBorder text-lightDatePickerButtonText placeholder-lightDatePickerPlaceHolder text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-darkDatePickerButtonBackground dark:border-darkDatePickerButtonBorder dark:placeholder-darkDatePickerPlaceHolder dark:text-darkDatePickerButtonText dark:focus:ring-blue-500 dark:focus:border-blue-500"
21
21
  :placeholder="$t('To')">
22
22
  </div>
23
23
  </div>
@@ -27,11 +27,11 @@
27
27
  <div>
28
28
  <div class="relative">
29
29
  <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5 pointer-events-none">
30
- <IconTime class="w-4 h-4 text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-700"/>
30
+ <IconTime class="w-4 h-4 text-lightDatePickerIcon dark:text-darkDatePickerIcon bg-lightDatePickerButtonBackground dark:bg-darkDatePickerButtonBackground"/>
31
31
  </div>
32
32
 
33
33
  <input v-model="startTime" type="time" id="start-time"
34
- class="bg-gray-50 border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full 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"
34
+ class="bg-lightDatePickerButtonBackground border leading-none border-lightDatePickerButtonBorder text-lightDatePickerButtonText placeholder-lightDatePickerPlaceHolder text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-darkDatePickerButtonBackground dark:border-darkDatePickerButtonBorder dark:placeholder-darkDatePickerPlaceHolder dark:text-darkDatePickerButtonText dark:focus:ring-blue-500 dark:focus:border-blue-500"
35
35
  value="00:00" required/>
36
36
  </div>
37
37
  </div>
@@ -39,11 +39,11 @@
39
39
  <div>
40
40
  <div class="relative">
41
41
  <div class="absolute inset-y-0 end-0 top-0 flex items-center pe-3.5 pointer-events-none">
42
- <IconTime class="w-4 h-4 text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-700"/>
42
+ <IconTime class="w-4 h-4 text-lightDatePickerIcon dark:text-darkDatePickerIcon bg-lightDatePickerButtonBackground dark:bg-darkDatePickerButtonBackground"/>
43
43
  </div>
44
44
 
45
45
  <input v-model="endTime" type="time" id="end-time"
46
- class="bg-gray-50 border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full 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"
46
+ class="bg-lightDatePickerButtonBackground border leading-none border-lightDatePickerButtonBorder text-lightDatePickerButtonText placeholder-lightDatePickerPlaceHolder text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-darkDatePickerButtonBackground dark:border-darkDatePickerButtonBorder dark:placeholder-darkDatePickerPlaceHolder dark:text-darkDatePickerButtonText dark:focus:ring-blue-500 dark:focus:border-blue-500"
47
47
  value="00:00" required/>
48
48
  </div>
49
49
  </div>
@@ -172,6 +172,7 @@ function updateFromProps() {
172
172
  if (!props.valueEnd) {
173
173
  datepickerEndEl.value.value = '';
174
174
  endTime.value = '';
175
+ endDate.value = '';
175
176
  } else if (props.column.type === 'time') {
176
177
  endTime.value = props.valueEnd;
177
178
  } else {
@@ -4,7 +4,7 @@
4
4
  :min="minFormatted"
5
5
  :max="maxFormatted"
6
6
  type="number" aria-describedby="helper-text-explanation"
7
- 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"
7
+ class="bg-lightRangePickerInputBackground border border-lightRangePickerInputBorder text-lightRangePickerInputText placeholder-lightRangePickerInputPlaceholder text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-20 p-2.5 dark:bg-darkRangePickerInputBackground dark:border-darkRangePickerInputBorder dark:placeholder-darkRangePickerInputPlaceholder dark:text-darkRangePickerInputText dark:focus:ring-blue-500 dark:focus:border-blue-500"
8
8
  :placeholder="$t('From')"
9
9
  v-model="start"
10
10
  >
@@ -13,7 +13,7 @@
13
13
  :min="minFormatted"
14
14
  :max="maxFormatted"
15
15
  type="number" aria-describedby="helper-text-explanation"
16
- 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"
16
+ class="bg-lightRangePickerInputBackground border border-lightRangePickerInputBorder text-lightRangePickerInputText placeholder-lightRangePickerInputPlaceholder text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-20 p-2.5 dark:bg-darkRangePickerInputBackground dark:border-darkRangePickerInputBorder dark:placeholder-darkRangePickerInputPlaceholder dark:text-darkRangePickerInputText dark:focus:ring-blue-500 dark:focus:border-blue-500"
17
17
  :placeholder="$t('To')"
18
18
  v-model="end"
19
19
  >
@@ -21,7 +21,7 @@
21
21
  <button
22
22
  v-if="isChanged"
23
23
  type="button"
24
- 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-lightPrimary 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"
24
+ class="flex items-center p-0.5 ml-auto px-3 text-sm font-medium text-lightRangePickerButtonText focus:outline-none bg-lightRangePickerButtonBackground rounded border border-lightRangePickerButtonBorder hover:bg-lightRangePickerButtonBackgroundHover hover:text-lightRangePickerButtonTextHover focus:z-10 focus:ring-4 focus:ring-lightRangePickerFocusRing dark:focus:ring-darkRangePickerFocusRing dark:bg-darkRangePickerButtonBackground dark:text-darkRangePickerButtonText dark:border-darkRangePickerButtonBorder dark:hover:text-darkRangePickerButtonTextHover dark:hover:bg-darkRangePickerButtonBackgroundHover disabled:opacity-50 disabled:cursor-not-allowed"
25
25
  @click="clear">Clear
26
26
  </button>
27
27
 
@@ -57,15 +57,15 @@ const props = defineProps({
57
57
 
58
58
  const emit = defineEmits(['update:valueStart', 'update:valueEnd']);
59
59
 
60
- const minFormatted = computed(() => Math.floor(props.min));
61
- const maxFormatted = computed(() => Math.ceil(props.max));
60
+ const minFormatted = computed(() => Math.floor(<number>props.min));
61
+ const maxFormatted = computed(() => Math.ceil(<number>props.max));
62
62
 
63
63
  const isChanged = computed(() => {
64
64
  return start.value && start.value !== minFormatted.value || end.value && end.value !== maxFormatted.value;
65
65
  });
66
66
 
67
- const start = ref(props.valueStart);
68
- const end = ref(props.valueEnd);
67
+ const start = ref<string | number>(props.valueStart);
68
+ const end = ref<string | number>(props.valueEnd);
69
69
 
70
70
  const sliderValue = ref([minFormatted.value, maxFormatted.value]);
71
71
 
@@ -118,7 +118,7 @@ const clear = () => {
118
118
  setSliderValues('', '')
119
119
  }
120
120
 
121
- function setSliderValues(start, end) {
121
+ function setSliderValues(start: any, end: any) {
122
122
  sliderValue.value = [start || minFormatted.value, end || maxFormatted.value];
123
123
  }
124
124
  </script>
@@ -153,4 +153,33 @@ function setSliderValues(start, end) {
153
153
  @apply bg-lightPrimaryOpacity;
154
154
  }
155
155
  }
156
+
157
+ .dark .custom-slider {
158
+ &:deep(.vue-slider-rail) {
159
+ background-color: rgb(55 65 81); // gray-700
160
+ }
161
+
162
+ &:deep(.vue-slider-dot-handle) {
163
+ @apply bg-darkPrimary;
164
+ border: none;
165
+ box-shadow: none;
166
+ }
167
+
168
+ &:deep(.vue-slider-dot-handle:hover) {
169
+ @apply bg-darkPrimary;
170
+ filter: brightness(1.1);
171
+ border: none;
172
+ box-shadow: none;
173
+ }
174
+
175
+ &:deep(.vue-slider-process) {
176
+ @apply bg-darkPrimaryOpacity;
177
+ }
178
+
179
+ &:deep(.vue-slider-process:hover) {
180
+ filter: brightness(1.1);
181
+ @apply bg-darkPrimaryOpacity;
182
+ }
183
+ }
184
+
156
185
  </style>