@finema/core 2.18.2 → 2.19.1
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.
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/components/Dialog/index.vue +20 -19
- package/dist/runtime/components/Form/Fields.vue +5 -0
- package/dist/runtime/components/Form/InputSearch/index.vue +79 -0
- package/dist/runtime/components/Form/InputSearch/index.vue.d.ts +13 -0
- package/dist/runtime/components/Form/InputSearch/types.d.ts +16 -0
- package/dist/runtime/components/Form/InputSearch/types.js +0 -0
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/EmptyState.vue +3 -3
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/FailedState.vue +6 -6
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/LoadingState.vue +5 -5
- package/dist/runtime/components/Form/InputUploadDropzoneAuto/SuccessState.vue +7 -7
- package/dist/runtime/components/Form/types.d.ts +3 -1
- package/dist/runtime/components/Form/types.js +1 -0
- package/dist/runtime/components/Table/index.vue +88 -100
- package/dist/runtime/composables/useConfig.d.ts +2 -2
- package/dist/runtime/composables/useConfig.js +4 -4
- package/dist/runtime/styles/main.css +1 -1
- package/dist/runtime/theme/dialog.d.ts +6 -4
- package/dist/runtime/theme/dialog.js +7 -5
- package/dist/runtime/theme/uploadFileDropzone.d.ts +11 -9
- package/dist/runtime/theme/uploadFileDropzone.js +11 -9
- package/package.json +1 -1
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<AlertDialogRoot :open="true">
|
|
3
3
|
<AlertDialogPortal>
|
|
4
|
-
<AlertDialogOverlay :class="
|
|
4
|
+
<AlertDialogOverlay :class="theme.overlay()" />
|
|
5
5
|
<AlertDialogContent
|
|
6
|
-
:class="
|
|
6
|
+
:class="theme.base()"
|
|
7
7
|
>
|
|
8
8
|
<Icon
|
|
9
9
|
v-if="!propsSafe.isHideIcon"
|
|
10
10
|
:name="getIcon"
|
|
11
|
-
:class="
|
|
11
|
+
:class="theme.icon()"
|
|
12
12
|
/>
|
|
13
|
-
<div :class="
|
|
14
|
-
<AlertDialogTitle :class="
|
|
13
|
+
<div :class="theme.wrapper()">
|
|
14
|
+
<AlertDialogTitle :class="theme.title()">
|
|
15
15
|
{{ propsSafe.title }}
|
|
16
16
|
</AlertDialogTitle>
|
|
17
17
|
<AlertDialogDescription
|
|
18
18
|
v-if="propsSafe.description"
|
|
19
|
-
:class="
|
|
19
|
+
:class="theme.description()"
|
|
20
20
|
>
|
|
21
21
|
{{ propsSafe.description }}
|
|
22
22
|
</AlertDialogDescription>
|
|
23
23
|
|
|
24
|
-
<div :class="
|
|
24
|
+
<div :class="theme.buttonGroup()">
|
|
25
25
|
<Button
|
|
26
26
|
v-if="propsSafe.isShowCancelBtn"
|
|
27
27
|
type="button"
|
|
28
28
|
color="neutral"
|
|
29
29
|
variant="outline"
|
|
30
|
-
:class="
|
|
30
|
+
:class="theme.cancelButton()"
|
|
31
31
|
@click="emits('close', false)"
|
|
32
32
|
>
|
|
33
33
|
{{ propsSafe.cancelText }}
|
|
34
34
|
</Button>
|
|
35
35
|
<Button
|
|
36
36
|
type="button"
|
|
37
|
-
:color="propsSafe.isConfirm ?
|
|
38
|
-
:class="
|
|
37
|
+
:color="propsSafe.isConfirm ? staticTheme.confirmColor : propsSafe.type"
|
|
38
|
+
:class="theme.confirmButton()"
|
|
39
39
|
@click="emits('close', true)"
|
|
40
40
|
>
|
|
41
41
|
{{ propsSafe.confirmText }}
|
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
AlertDialogTitle
|
|
58
58
|
} from "reka-ui";
|
|
59
59
|
import { computed, useAttrs } from "vue";
|
|
60
|
-
import {
|
|
60
|
+
import { useUiIconConfig, useUiConfig, useUiStaticConfig } from "../../composables/useConfig";
|
|
61
61
|
import { dialogTheme } from "#core/theme/dialog";
|
|
62
62
|
import { DialogType } from "#core/composables/useDialog";
|
|
63
63
|
const emits = defineEmits();
|
|
@@ -66,7 +66,8 @@ const props = withDefaults(defineProps(), {
|
|
|
66
66
|
cancelText: "\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01"
|
|
67
67
|
});
|
|
68
68
|
const attrs = useAttrs();
|
|
69
|
-
const
|
|
69
|
+
const icons = useUiIconConfig("dialog");
|
|
70
|
+
const staticTheme = useUiStaticConfig("dialog");
|
|
70
71
|
const propsSafe = computed(() => {
|
|
71
72
|
if (props.title) {
|
|
72
73
|
return props;
|
|
@@ -82,22 +83,22 @@ const getIcon = computed(() => {
|
|
|
82
83
|
return propsSafe.value.icon;
|
|
83
84
|
}
|
|
84
85
|
if (propsSafe.value.isConfirm) {
|
|
85
|
-
return
|
|
86
|
+
return icons.iconConfirm;
|
|
86
87
|
}
|
|
87
88
|
switch (propsSafe.value.type) {
|
|
88
89
|
case DialogType.SUCCESS:
|
|
89
|
-
return
|
|
90
|
+
return icons.iconSuccess;
|
|
90
91
|
case DialogType.ERROR:
|
|
91
|
-
return
|
|
92
|
+
return icons.iconError;
|
|
92
93
|
case DialogType.INFO:
|
|
93
|
-
return
|
|
94
|
+
return icons.iconInfo;
|
|
94
95
|
case DialogType.WARNING:
|
|
95
|
-
return
|
|
96
|
+
return icons.iconWarning;
|
|
96
97
|
default:
|
|
97
|
-
return
|
|
98
|
+
return icons.iconInfo;
|
|
98
99
|
}
|
|
99
100
|
});
|
|
100
|
-
const
|
|
101
|
+
const theme = computed(() => useUiConfig(dialogTheme, "dialog")({
|
|
101
102
|
color: propsSafe.value.isConfirm ? void 0 : propsSafe.value.type,
|
|
102
103
|
confirm: propsSafe.value.isConfirm
|
|
103
104
|
}));
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
import { computed } from "vue";
|
|
21
21
|
import FormInputTextarea from "./InputTextarea/index.vue";
|
|
22
22
|
import FormInputText from "./InputText/index.vue";
|
|
23
|
+
import FormInputSearch from "./InputSearch/index.vue";
|
|
23
24
|
import FormInputNumber from "./InputNumber/index.vue";
|
|
24
25
|
import FormInputToggle from "./InputToggle/index.vue";
|
|
25
26
|
import FormInputCheckbox from "./InputCheckbox/index.vue";
|
|
@@ -45,6 +46,10 @@ const componentMap = {
|
|
|
45
46
|
component: FormInputText,
|
|
46
47
|
props: {}
|
|
47
48
|
},
|
|
49
|
+
[INPUT_TYPES.SEARCH]: {
|
|
50
|
+
component: FormInputSearch,
|
|
51
|
+
props: {}
|
|
52
|
+
},
|
|
48
53
|
[INPUT_TYPES.TEXTAREA]: {
|
|
49
54
|
component: FormInputTextarea,
|
|
50
55
|
props: {}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<FieldWrapper v-bind="wrapperProps">
|
|
3
|
+
<Input
|
|
4
|
+
:model-value="value"
|
|
5
|
+
:disabled="wrapperProps.disabled"
|
|
6
|
+
:leading-icon="leadingIcon || searchIcon || 'i-heroicons-magnifying-glass'"
|
|
7
|
+
:trailing-icon="trailingIcon"
|
|
8
|
+
:loading="loading"
|
|
9
|
+
:loading-icon="loadingIcon"
|
|
10
|
+
:name="name"
|
|
11
|
+
:placeholder="wrapperProps.placeholder || 'Search...'"
|
|
12
|
+
type="text"
|
|
13
|
+
:autofocus="!!autoFocus"
|
|
14
|
+
:icon="icon"
|
|
15
|
+
:readonly="readonly"
|
|
16
|
+
:ui="ui"
|
|
17
|
+
@update:model-value="onInput"
|
|
18
|
+
>
|
|
19
|
+
<template #trailing>
|
|
20
|
+
<Button
|
|
21
|
+
v-if="clearable && value && value.length > 0"
|
|
22
|
+
color="neutral"
|
|
23
|
+
class="p-0"
|
|
24
|
+
variant="link"
|
|
25
|
+
:icon="clearIcon || 'i-heroicons-x-mark'"
|
|
26
|
+
:padded="false"
|
|
27
|
+
title="ล้างการค้นหา"
|
|
28
|
+
@click="onClear"
|
|
29
|
+
/>
|
|
30
|
+
</template>
|
|
31
|
+
</Input>
|
|
32
|
+
</FieldWrapper>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup>
|
|
36
|
+
import { useFieldHOC } from "#core/composables/useForm";
|
|
37
|
+
import FieldWrapper from "#core/components/Form/FieldWrapper.vue";
|
|
38
|
+
const emits = defineEmits(["change", "search", "clear"]);
|
|
39
|
+
const props = defineProps({
|
|
40
|
+
leadingIcon: { type: null, required: false },
|
|
41
|
+
trailingIcon: { type: null, required: false },
|
|
42
|
+
loading: { type: Boolean, required: false },
|
|
43
|
+
loadingIcon: { type: null, required: false },
|
|
44
|
+
icon: { type: String, required: false },
|
|
45
|
+
clearable: { type: Boolean, required: false, default: true },
|
|
46
|
+
clearIcon: { type: String, required: false },
|
|
47
|
+
searchIcon: { type: String, required: false },
|
|
48
|
+
form: { type: Object, required: false },
|
|
49
|
+
name: { type: String, required: true },
|
|
50
|
+
errorMessage: { type: String, required: false },
|
|
51
|
+
label: { type: null, required: false },
|
|
52
|
+
description: { type: String, required: false },
|
|
53
|
+
hint: { type: String, required: false },
|
|
54
|
+
rules: { type: null, required: false },
|
|
55
|
+
autoFocus: { type: Boolean, required: false },
|
|
56
|
+
placeholder: { type: String, required: false },
|
|
57
|
+
disabled: { type: Boolean, required: false },
|
|
58
|
+
readonly: { type: Boolean, required: false },
|
|
59
|
+
required: { type: Boolean, required: false },
|
|
60
|
+
help: { type: String, required: false },
|
|
61
|
+
ui: { type: null, required: false }
|
|
62
|
+
});
|
|
63
|
+
const {
|
|
64
|
+
value,
|
|
65
|
+
wrapperProps,
|
|
66
|
+
handleChange
|
|
67
|
+
} = useFieldHOC(props);
|
|
68
|
+
const onInput = (newValue) => {
|
|
69
|
+
handleChange(newValue);
|
|
70
|
+
emits("change", newValue);
|
|
71
|
+
emits("search", newValue);
|
|
72
|
+
};
|
|
73
|
+
const onClear = () => {
|
|
74
|
+
handleChange("");
|
|
75
|
+
emits("change", "");
|
|
76
|
+
emits("clear");
|
|
77
|
+
emits("search", "");
|
|
78
|
+
};
|
|
79
|
+
</script>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ISearchFieldProps } from '#core/components/Form/InputSearch/types';
|
|
2
|
+
declare const _default: import("vue").DefineComponent<ISearchFieldProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
3
|
+
search: (...args: any[]) => void;
|
|
4
|
+
clear: (...args: any[]) => void;
|
|
5
|
+
change: (...args: any[]) => void;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<ISearchFieldProps> & Readonly<{
|
|
7
|
+
onSearch?: ((...args: any[]) => any) | undefined;
|
|
8
|
+
onClear?: ((...args: any[]) => any) | undefined;
|
|
9
|
+
onChange?: ((...args: any[]) => any) | undefined;
|
|
10
|
+
}>, {
|
|
11
|
+
clearable: boolean;
|
|
12
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { IFieldProps, IFormFieldBase, INPUT_TYPES } from '#core/components/Form/types';
|
|
2
|
+
export interface ISearchFieldProps extends IFieldProps {
|
|
3
|
+
leadingIcon?: any;
|
|
4
|
+
trailingIcon?: any;
|
|
5
|
+
loading?: boolean;
|
|
6
|
+
loadingIcon?: any;
|
|
7
|
+
icon?: string;
|
|
8
|
+
clearable?: boolean;
|
|
9
|
+
clearIcon?: string;
|
|
10
|
+
searchIcon?: string;
|
|
11
|
+
}
|
|
12
|
+
export type ISearchField = IFormFieldBase<INPUT_TYPES.SEARCH, ISearchFieldProps, {
|
|
13
|
+
change?: (value: string) => void;
|
|
14
|
+
search?: (value: string) => void;
|
|
15
|
+
clear?: () => void;
|
|
16
|
+
}>;
|
|
File without changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="theme.placeholderWrapper()">
|
|
3
3
|
<Icon
|
|
4
|
-
:name="
|
|
4
|
+
:name="icons.uploadIcon"
|
|
5
5
|
:class="theme.labelIcon()"
|
|
6
6
|
/>
|
|
7
7
|
<div :class="theme.labelWrapper()">
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
</template>
|
|
24
24
|
|
|
25
25
|
<script setup>
|
|
26
|
-
import {
|
|
26
|
+
import { useUiIconConfig } from "#imports";
|
|
27
27
|
defineProps({
|
|
28
28
|
theme: { type: null, required: true },
|
|
29
29
|
selectFileLabel: { type: String, required: true },
|
|
@@ -31,5 +31,5 @@ defineProps({
|
|
|
31
31
|
placeholder: { type: String, required: false }
|
|
32
32
|
});
|
|
33
33
|
defineEmits(["openFile"]);
|
|
34
|
-
const
|
|
34
|
+
const icons = useUiIconConfig("uploadFileDropzone");
|
|
35
35
|
</script>
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
</p>
|
|
17
17
|
<Button
|
|
18
18
|
variant="link"
|
|
19
|
-
:icon="
|
|
19
|
+
:icon="icons.actionRetryIcon"
|
|
20
20
|
:class="theme.actionRetryBtnClass()"
|
|
21
21
|
color="primary"
|
|
22
22
|
@click="$emit('retry')"
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
</Button>
|
|
26
26
|
</div>
|
|
27
27
|
<Icon
|
|
28
|
-
:name="
|
|
28
|
+
:name="icons.actionDeleteIcon"
|
|
29
29
|
:class="theme.actionDeleteIconClass()"
|
|
30
30
|
title="ลบไฟล์"
|
|
31
31
|
@click="$emit('delete')"
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
<script setup>
|
|
38
38
|
import { isImage } from "#core/helpers/componentHelper";
|
|
39
|
-
import {
|
|
39
|
+
import { useUiIconConfig } from "#imports";
|
|
40
40
|
const props = defineProps({
|
|
41
41
|
theme: { type: null, required: true },
|
|
42
42
|
selectedFile: { type: null, required: true },
|
|
@@ -44,11 +44,11 @@ const props = defineProps({
|
|
|
44
44
|
retryLabel: { type: String, required: true }
|
|
45
45
|
});
|
|
46
46
|
defineEmits(["retry", "delete"]);
|
|
47
|
-
const
|
|
47
|
+
const icons = useUiIconConfig("uploadFileDropzone");
|
|
48
48
|
const getFileIcon = (file) => {
|
|
49
49
|
if (isImage(file)) {
|
|
50
|
-
return
|
|
50
|
+
return icons.placeholderImgIcon;
|
|
51
51
|
}
|
|
52
|
-
return
|
|
52
|
+
return icons.filePreviewIcon;
|
|
53
53
|
};
|
|
54
54
|
</script>
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
</div>
|
|
18
18
|
<div>
|
|
19
19
|
<Icon
|
|
20
|
-
:name="
|
|
20
|
+
:name="icons.loadingIcon"
|
|
21
21
|
:class="theme.onLoadingLoadingIconClass()"
|
|
22
22
|
/>
|
|
23
23
|
</div>
|
|
@@ -27,19 +27,19 @@
|
|
|
27
27
|
|
|
28
28
|
<script setup>
|
|
29
29
|
import { isImage } from "#core/helpers/componentHelper";
|
|
30
|
-
import {
|
|
30
|
+
import { useUiIconConfig } from "#imports";
|
|
31
31
|
const props = defineProps({
|
|
32
32
|
theme: { type: null, required: true },
|
|
33
33
|
selectedFile: { type: null, required: true },
|
|
34
34
|
percent: { type: Number, required: true },
|
|
35
35
|
uploadingLabel: { type: String, required: true }
|
|
36
36
|
});
|
|
37
|
-
const
|
|
37
|
+
const icons = useUiIconConfig("uploadFileDropzone");
|
|
38
38
|
const getFileIcon = (file) => {
|
|
39
39
|
if (isImage(file)) {
|
|
40
|
-
return
|
|
40
|
+
return icons.placeholderImgIcon;
|
|
41
41
|
}
|
|
42
|
-
return
|
|
42
|
+
return icons.filePreviewIcon;
|
|
43
43
|
};
|
|
44
44
|
const getFileSize = (file) => {
|
|
45
45
|
const size = file.size;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
</div>
|
|
14
14
|
<div v-else>
|
|
15
15
|
<Icon
|
|
16
|
-
:name="
|
|
16
|
+
:name="icons.filePreviewIcon"
|
|
17
17
|
:class="theme.onPreviewPreviewFileClass()"
|
|
18
18
|
/>
|
|
19
19
|
</div>
|
|
@@ -35,27 +35,27 @@
|
|
|
35
35
|
class="flex"
|
|
36
36
|
>
|
|
37
37
|
<Icon
|
|
38
|
-
:name="
|
|
38
|
+
:name="icons.actionPreviewIcon"
|
|
39
39
|
:class="theme.actionIconClass()"
|
|
40
40
|
title="ดูตัวอย่าง"
|
|
41
41
|
/>
|
|
42
42
|
</a>
|
|
43
43
|
<Icon
|
|
44
44
|
v-if="isImageFromPath(value.path) || isVideoFromPath(value.path)"
|
|
45
|
-
:name="
|
|
45
|
+
:name="icons.actionPreviewIcon"
|
|
46
46
|
:class="theme.actionIconClass()"
|
|
47
47
|
title="ดูตัวอย่าง"
|
|
48
48
|
@click="$emit('preview')"
|
|
49
49
|
/>
|
|
50
50
|
<Icon
|
|
51
|
-
:name="
|
|
51
|
+
:name="icons.actionDownloadIcon"
|
|
52
52
|
:class="theme.actionIconClass()"
|
|
53
53
|
title="ดาวน์โหลดไฟล์"
|
|
54
54
|
@click="$emit('download')"
|
|
55
55
|
/>
|
|
56
56
|
<Icon
|
|
57
57
|
v-if="!disabled && !readonly"
|
|
58
|
-
:name="
|
|
58
|
+
:name="icons.actionDeleteIcon"
|
|
59
59
|
:class="theme.actionIconClass()"
|
|
60
60
|
title="ลบไฟล์"
|
|
61
61
|
@click="$emit('delete')"
|
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
isVideoFromPath,
|
|
73
73
|
useFileSize
|
|
74
74
|
} from "#core/helpers/componentHelper";
|
|
75
|
-
import {
|
|
75
|
+
import { useUiIconConfig } from "#imports";
|
|
76
76
|
defineProps({
|
|
77
77
|
theme: { type: null, required: true },
|
|
78
78
|
value: { type: Object, required: true },
|
|
@@ -80,7 +80,7 @@ defineProps({
|
|
|
80
80
|
readonly: { type: Boolean, required: false }
|
|
81
81
|
});
|
|
82
82
|
defineEmits(["preview", "download", "delete"]);
|
|
83
|
-
const
|
|
83
|
+
const icons = useUiIconConfig("uploadFileDropzone");
|
|
84
84
|
const getFileSizeFromValue = (fileValue) => {
|
|
85
85
|
const allocate = useFileSize(fileValue.size || 0);
|
|
86
86
|
return allocate.isSelectedFileUseMb.value ? `${allocate.selectedFileSizeMb.value} MB` : `${allocate.selectedFileSizeKb.value} KB`;
|
|
@@ -3,6 +3,7 @@ import type { FormContext } from 'vee-validate';
|
|
|
3
3
|
import type { IUploadDropzoneAutoField } from './InputUploadDropzoneAuto/types.js';
|
|
4
4
|
import type { IDateTimeRangeField } from './InputDateTimeRange/date_range_time_field.types.js';
|
|
5
5
|
import type { ITextField } from '#core/components/Form/InputText/types';
|
|
6
|
+
import type { ISearchField } from '#core/components/Form/InputSearch/types';
|
|
6
7
|
import type { ITextareaField } from '#core/components/Form/InputTextarea/types';
|
|
7
8
|
import type { IToggleField } from '#core/components/Form/InputToggle/types';
|
|
8
9
|
import type { ISelectField } from '#core/components/Form/InputSelect/types';
|
|
@@ -14,6 +15,7 @@ import type { IRadioField } from '#core/components/Form/InputRadio/types';
|
|
|
14
15
|
import type { IWYSIWYGField } from '#core/components/Form/InputWYSIWYG/types';
|
|
15
16
|
export declare const enum INPUT_TYPES {
|
|
16
17
|
TEXT = "TEXT",
|
|
18
|
+
SEARCH = "SEARCH",
|
|
17
19
|
NUMBER = "NUMBER",
|
|
18
20
|
TEXTAREA = "TEXTAREA",
|
|
19
21
|
PASSWORD = "PASSWORD",
|
|
@@ -64,7 +66,7 @@ export interface IFormFieldBase<I extends INPUT_TYPES, P extends IFieldProps, O>
|
|
|
64
66
|
props: P;
|
|
65
67
|
on?: O;
|
|
66
68
|
}
|
|
67
|
-
export type IFormField = ITextField | INumberField | ITextareaField | IToggleField | ISelectField | ICheckboxField | ISelectMultipleField | IRadioField | IDateTimeField | IDateTimeRangeField | IUploadDropzoneAutoField | IWYSIWYGField | IFormFieldBase<INPUT_TYPES.COMPONENT, any, any>;
|
|
69
|
+
export type IFormField = ITextField | ISearchField | INumberField | ITextareaField | IToggleField | ISelectField | ICheckboxField | ISelectMultipleField | IRadioField | IDateTimeField | IDateTimeRangeField | IUploadDropzoneAutoField | IWYSIWYGField | IFormFieldBase<INPUT_TYPES.COMPONENT, any, any>;
|
|
68
70
|
export interface IFileValue {
|
|
69
71
|
url: string;
|
|
70
72
|
path?: string;
|
|
@@ -1,98 +1,98 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div ref="tableContainer">
|
|
3
|
-
<div
|
|
4
|
-
v-if="options.isEnabledSearch"
|
|
2
|
+
<div ref="tableContainer">
|
|
3
|
+
<div
|
|
4
|
+
v-if="options.isEnabledSearch"
|
|
5
5
|
:class="theme.searchContainer({
|
|
6
6
|
class: [ui?.searchContainer]
|
|
7
|
-
})"
|
|
8
|
-
>
|
|
9
|
-
<Input
|
|
10
|
-
v-model="q"
|
|
11
|
-
icon="i-heroicons-magnifying-glass"
|
|
12
|
-
:placeholder="options.searchPlaceholder || '\u0E04\u0E49\u0E19\u0E2B\u0E32....'"
|
|
13
|
-
/>
|
|
14
|
-
</div>
|
|
15
|
-
<UTable
|
|
16
|
-
v-bind="$attrs"
|
|
17
|
-
:loading="options.status.isLoading"
|
|
18
|
-
:data="options.rawData"
|
|
19
|
-
:columns="options.columns"
|
|
20
|
-
>
|
|
21
|
-
<template #empty>
|
|
22
|
-
<slot
|
|
23
|
-
v-if="options.status.isLoading"
|
|
24
|
-
name="loading"
|
|
25
|
-
>
|
|
26
|
-
<Loader
|
|
27
|
-
:loading="true"
|
|
28
|
-
/>
|
|
29
|
-
</slot>
|
|
30
|
-
<slot
|
|
31
|
-
v-else-if="options.status.isError"
|
|
32
|
-
name="error"
|
|
33
|
-
>
|
|
34
|
-
<div
|
|
35
|
-
class="flex h-[200px] items-center justify-center text-2xl text-error-400"
|
|
36
|
-
>
|
|
37
|
-
{{ StringHelper.getError(options.status.errorData) }}
|
|
38
|
-
</div>
|
|
39
|
-
</slot>
|
|
40
|
-
|
|
41
|
-
<slot
|
|
42
|
-
v-else
|
|
43
|
-
name="error"
|
|
44
|
-
>
|
|
45
|
-
<Empty />
|
|
46
|
-
</slot>
|
|
47
|
-
</template>
|
|
48
|
-
<template
|
|
49
|
-
v-for="column in options.columns.filter((item) => !!item.type)"
|
|
50
|
-
#[`${column.accessorKey}-cell`]="{ row }"
|
|
51
|
-
:key="column.accessorKey"
|
|
52
|
-
>
|
|
53
|
-
<component
|
|
54
|
-
:is="column.type === COLUMN_TYPES.COMPONENT ? column.component : columnTypeComponents[column.type]"
|
|
55
|
-
v-if="column.type === COLUMN_TYPES.COMPONENT || columnTypeComponents[column.type]"
|
|
56
|
-
:value="transformValue(column, row)"
|
|
57
|
-
:column="column"
|
|
58
|
-
:row="row"
|
|
59
|
-
/>
|
|
60
|
-
</template>
|
|
61
|
-
<template
|
|
62
|
-
v-for="(_, slotName) of $slots"
|
|
63
|
-
#[slotName]="slotProps"
|
|
64
|
-
>
|
|
65
|
-
<slot
|
|
66
|
-
:name="slotName"
|
|
67
|
-
v-bind="slotProps || {}"
|
|
68
|
-
/>
|
|
69
|
-
</template>
|
|
70
|
-
</UTable>
|
|
71
|
-
|
|
72
|
-
<div
|
|
73
|
-
v-if="!options.isHidePagination"
|
|
7
|
+
})"
|
|
8
|
+
>
|
|
9
|
+
<Input
|
|
10
|
+
v-model="q"
|
|
11
|
+
icon="i-heroicons-magnifying-glass"
|
|
12
|
+
:placeholder="options.searchPlaceholder || '\u0E04\u0E49\u0E19\u0E2B\u0E32....'"
|
|
13
|
+
/>
|
|
14
|
+
</div>
|
|
15
|
+
<UTable
|
|
16
|
+
v-bind="$attrs"
|
|
17
|
+
:loading="options.status.isLoading"
|
|
18
|
+
:data="options.rawData"
|
|
19
|
+
:columns="options.columns"
|
|
20
|
+
>
|
|
21
|
+
<template #empty>
|
|
22
|
+
<slot
|
|
23
|
+
v-if="options.status.isLoading"
|
|
24
|
+
name="loading"
|
|
25
|
+
>
|
|
26
|
+
<Loader
|
|
27
|
+
:loading="true"
|
|
28
|
+
/>
|
|
29
|
+
</slot>
|
|
30
|
+
<slot
|
|
31
|
+
v-else-if="options.status.isError"
|
|
32
|
+
name="error"
|
|
33
|
+
>
|
|
34
|
+
<div
|
|
35
|
+
class="flex h-[200px] items-center justify-center text-2xl text-error-400"
|
|
36
|
+
>
|
|
37
|
+
{{ StringHelper.getError(options.status.errorData) }}
|
|
38
|
+
</div>
|
|
39
|
+
</slot>
|
|
40
|
+
|
|
41
|
+
<slot
|
|
42
|
+
v-else
|
|
43
|
+
name="error"
|
|
44
|
+
>
|
|
45
|
+
<Empty />
|
|
46
|
+
</slot>
|
|
47
|
+
</template>
|
|
48
|
+
<template
|
|
49
|
+
v-for="column in options.columns.filter((item) => !!item.type)"
|
|
50
|
+
#[`${column.accessorKey}-cell`]="{ row }"
|
|
51
|
+
:key="column.accessorKey"
|
|
52
|
+
>
|
|
53
|
+
<component
|
|
54
|
+
:is="column.type === COLUMN_TYPES.COMPONENT ? column.component : columnTypeComponents[column.type]"
|
|
55
|
+
v-if="column.type === COLUMN_TYPES.COMPONENT || columnTypeComponents[column.type]"
|
|
56
|
+
:value="transformValue(column, row)"
|
|
57
|
+
:column="column"
|
|
58
|
+
:row="row"
|
|
59
|
+
/>
|
|
60
|
+
</template>
|
|
61
|
+
<template
|
|
62
|
+
v-for="(_, slotName) of $slots"
|
|
63
|
+
#[slotName]="slotProps"
|
|
64
|
+
>
|
|
65
|
+
<slot
|
|
66
|
+
:name="slotName"
|
|
67
|
+
v-bind="slotProps || {}"
|
|
68
|
+
/>
|
|
69
|
+
</template>
|
|
70
|
+
</UTable>
|
|
71
|
+
|
|
72
|
+
<div
|
|
73
|
+
v-if="!options.isHidePagination"
|
|
74
74
|
:class="theme.paginationContainer({
|
|
75
75
|
class: [ui?.paginationContainer]
|
|
76
|
-
})"
|
|
77
|
-
>
|
|
78
|
-
<p
|
|
76
|
+
})"
|
|
77
|
+
>
|
|
78
|
+
<p
|
|
79
79
|
:class="theme.paginationInfo({
|
|
80
80
|
class: [ui?.paginationInfo]
|
|
81
|
-
})"
|
|
82
|
-
>
|
|
83
|
-
{{ pageBetween }} รายการ จากทั้งหมด {{ totalCountWithComma }} รายการ
|
|
84
|
-
</p>
|
|
85
|
-
<Pagination
|
|
86
|
-
v-if="options.pageOptions.totalPage > 1"
|
|
87
|
-
v-model:page="page"
|
|
88
|
-
:default-page="options.pageOptions?.currentPage || 1"
|
|
89
|
-
:items-per-page="options.pageOptions.limit"
|
|
90
|
-
:total="options.pageOptions.totalCount"
|
|
91
|
-
:to="options.isPreventRouteChange ? void 0 : to"
|
|
92
|
-
@update:page="onPageChange"
|
|
93
|
-
/>
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
81
|
+
})"
|
|
82
|
+
>
|
|
83
|
+
{{ pageBetween }} รายการ จากทั้งหมด {{ totalCountWithComma }} รายการ
|
|
84
|
+
</p>
|
|
85
|
+
<Pagination
|
|
86
|
+
v-if="options.pageOptions.totalPage > 1"
|
|
87
|
+
v-model:page="page"
|
|
88
|
+
:default-page="options.pageOptions?.currentPage || 1"
|
|
89
|
+
:items-per-page="options.pageOptions.limit"
|
|
90
|
+
:total="options.pageOptions.totalCount"
|
|
91
|
+
:to="options.isPreventRouteChange ? void 0 : to"
|
|
92
|
+
@update:page="onPageChange"
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
96
|
</template>
|
|
97
97
|
|
|
98
98
|
<script setup>
|
|
@@ -148,18 +148,6 @@ watch(
|
|
|
148
148
|
useWatchChange(() => props.options?.pageOptions?.currentPage, (value) => {
|
|
149
149
|
page.value = value;
|
|
150
150
|
});
|
|
151
|
-
useWatchChange(() => props.options?.pageOptions?.request?.params, () => {
|
|
152
|
-
if (props.options?.isPreventRouteChange) return;
|
|
153
|
-
const params = props.options?.pageOptions?.request?.params || {};
|
|
154
|
-
const cleanParams = Object.fromEntries(
|
|
155
|
-
Object.entries(params).filter(
|
|
156
|
-
([key, value]) => value !== null && value !== void 0 && value !== ""
|
|
157
|
-
)
|
|
158
|
-
);
|
|
159
|
-
router.replace({
|
|
160
|
-
query: cleanParams
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
151
|
const pageBetween = computed(() => {
|
|
164
152
|
const rawDataLength = props.options.rawData?.length;
|
|
165
153
|
const pageOpts = props.options.pageOptions;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { core as Core } from '../../core.config.js';
|
|
2
2
|
export declare const useCoreConfig: () => typeof Core;
|
|
3
3
|
export declare const useUiConfig: (config: object, name: string) => any;
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
4
|
+
export declare const useUiIconConfig: (name: string) => any;
|
|
5
|
+
export declare const useUiStaticConfig: (name: string) => any;
|
|
@@ -9,9 +9,9 @@ export const useUiConfig = (config, name) => {
|
|
|
9
9
|
...appConfig.ui[name] || {}
|
|
10
10
|
});
|
|
11
11
|
};
|
|
12
|
-
export const
|
|
13
|
-
return appConfig.ui[name].
|
|
12
|
+
export const useUiIconConfig = (name) => {
|
|
13
|
+
return appConfig.ui[name].icons;
|
|
14
14
|
};
|
|
15
|
-
export const
|
|
16
|
-
return appConfig.ui;
|
|
15
|
+
export const useUiStaticConfig = (name) => {
|
|
16
|
+
return appConfig.ui[name].slots;
|
|
17
17
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@import "tailwindcss";@import "@nuxt/ui";@plugin "@tailwindcss/typography";@source inline("prose");@theme
|
|
1
|
+
@import "tailwindcss";@import "@nuxt/ui";@plugin "@tailwindcss/typography";@source inline("prose");@theme{--font-sans:"Noto Sans Thai","Noto Sans Thai Looped","Public Sans",sans-serif}@theme static{--color-main:#232c5a;--color-main-50:#f4f4f7;--color-main-100:#e9eaef;--color-main-200:#c8cad6;--color-main-300:#a7abbd;--color-main-400:#656b8c;--color-main-500:#232c5a;--color-main-600:#202851;--color-main-700:#151a36;--color-main-800:#101429;--color-main-900:#0b0d1b;--color-main-950:#0b0d1b;--color-secondary:#ee8b36;--color-secondary-50:#fdf1e7;--color-secondary-100:#f9d6b8;--color-secondary-200:#f5bb89;--color-secondary-300:#f1a05a;--color-secondary-400:#ed852b;--color-secondary-500:#d46b12;--color-secondary-600:#a5540e;--color-secondary-700:#763c0a;--color-secondary-800:#472406;--color-secondary-900:#180c02;--color-info:#0d8cee;--color-info-50:#f3f9fe;--color-info-100:#e7f4fd;--color-info-200:#ebf6ff;--color-info-300:#9ed1f8;--color-info-400:#56aff3;--color-info-500:#0d8cee;--color-info-600:#0c7ed6;--color-info-700:#08548f;--color-info-800:#063f6b;--color-info-900:#042a47;--color-error:#f25555;--color-error-50:#fef7f7;--color-error-100:#feeeee;--color-error-200:#ffdfdf;--color-error-300:#fabbbb;--color-error-400:#f68888;--color-error-500:#f25555;--color-error-600:#da4d4d;--color-error-700:#913333;--color-error-800:#6d2626;--color-error-900:#491a1a;--color-success:#3fb061;--color-success-50:#f5fbf7;--color-success-100:#ecf7ef;--color-success-200:#daeee0;--color-success-300:#b2dfc0;--color-success-400:#79c890;--color-success-500:#3fb061;--color-success-600:#399e57;--color-success-700:#266a3a;--color-success-800:#1c4f2c;--color-success-900:#13351d;--color-warning:#ff9a35;--color-warning-50:#fffaf5;--color-warning-100:#fff5eb;--color-warning-200:#fef1cc;--color-warning-300:#ffd7ae;--color-warning-400:#ffb872;--color-warning-500:#ff9a35;--color-warning-600:#e68b30;--color-warning-700:#995c20;--color-warning-800:#734518;--color-warning-900:#4d2e10}::-webkit-scrollbar{-webkit-appearance:none;height:10px;width:10px}::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.3);border-radius:4px;box-shadow:0 0 1px hsla(0,0%,100%,.5)}:root{--dp-font-family:inherit!important}.dp__theme_light{--dp-primary-color:var(--color-main)!important;--dp-primary-disabled-color:var(--color-main-200)!important}#__nuxt,body,html{@apply w-full h-full}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
export declare const dialogTheme: {
|
|
2
|
-
|
|
3
|
-
base: string;
|
|
4
|
-
overlay: string;
|
|
5
|
-
icon: string;
|
|
2
|
+
icons: {
|
|
6
3
|
iconSuccess: string;
|
|
7
4
|
iconInfo: string;
|
|
8
5
|
iconWarning: string;
|
|
9
6
|
iconError: string;
|
|
10
7
|
iconConfirm: string;
|
|
8
|
+
};
|
|
9
|
+
slots: {
|
|
10
|
+
base: string;
|
|
11
|
+
overlay: string;
|
|
12
|
+
icon: string;
|
|
11
13
|
wrapper: string;
|
|
12
14
|
confirmColor: string;
|
|
13
15
|
title: string;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
export const dialogTheme = {
|
|
2
|
-
|
|
3
|
-
base: "flex space-x-4 shadow-lg ring ring-default z-[100] text-sm fixed top-[50%] left-[50%] max-h-[85vh] w-[90vw] max-w-[500px] translate-x-[-50%] translate-y-[-50%] rounded-lg bg-white p-[25px] focus:outline-none",
|
|
4
|
-
overlay: "fixed inset-0 bg-elevated/75 backdrop-blur",
|
|
5
|
-
icon: "size-12",
|
|
2
|
+
icons: {
|
|
6
3
|
iconSuccess: "i-heroicons-check-circle",
|
|
7
4
|
iconInfo: "i-heroicons-information-circle",
|
|
8
5
|
iconWarning: "i-heroicons-exclamation-circle",
|
|
9
6
|
iconError: "i-heroicons-x-circle",
|
|
10
|
-
iconConfirm: "i-heroicons-information-circle"
|
|
7
|
+
iconConfirm: "i-heroicons-information-circle"
|
|
8
|
+
},
|
|
9
|
+
slots: {
|
|
10
|
+
base: "flex space-x-4 shadow-lg ring ring-default z-[100] text-sm fixed top-[50%] left-[50%] max-h-[85vh] w-[90vw] max-w-[500px] translate-x-[-50%] translate-y-[-50%] rounded-lg bg-white p-[25px] focus:outline-none",
|
|
11
|
+
overlay: "fixed inset-0 bg-elevated/75 backdrop-blur",
|
|
12
|
+
icon: "size-12",
|
|
11
13
|
wrapper: "flex flex-col w-full",
|
|
12
14
|
confirmColor: "info",
|
|
13
15
|
title: "font-bold text-lg",
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
export declare const uploadFileDropzoneTheme: {
|
|
2
|
+
icons: {
|
|
3
|
+
filePreviewIcon: string;
|
|
4
|
+
uploadIcon: string;
|
|
5
|
+
placeholderImgIcon: string;
|
|
6
|
+
failedImgIcon: string;
|
|
7
|
+
loadingIcon: string;
|
|
8
|
+
actionPreviewIcon: string;
|
|
9
|
+
actionDownloadIcon: string;
|
|
10
|
+
actionDeleteIcon: string;
|
|
11
|
+
actionRetryIcon: string;
|
|
12
|
+
};
|
|
2
13
|
slots: {
|
|
3
14
|
base: string;
|
|
4
15
|
wrapper: string;
|
|
@@ -7,11 +18,6 @@ export declare const uploadFileDropzoneTheme: {
|
|
|
7
18
|
placeholderWrapper: string;
|
|
8
19
|
placeholder: string;
|
|
9
20
|
labelWrapper: string;
|
|
10
|
-
filePreviewIcon: string;
|
|
11
|
-
uploadIcon: string;
|
|
12
|
-
placeholderImgIcon: string;
|
|
13
|
-
failedImgIcon: string;
|
|
14
|
-
loadingIcon: string;
|
|
15
21
|
labelIcon: string;
|
|
16
22
|
onLoadingWrapper: string;
|
|
17
23
|
onLoadingPlaceholderWrapper: string;
|
|
@@ -30,10 +36,6 @@ export declare const uploadFileDropzoneTheme: {
|
|
|
30
36
|
actionWrapper: string;
|
|
31
37
|
actionIconClass: string;
|
|
32
38
|
actionDeleteIconClass: string;
|
|
33
|
-
actionPreviewIcon: string;
|
|
34
|
-
actionDownloadIcon: string;
|
|
35
|
-
actionDeleteIcon: string;
|
|
36
|
-
actionRetryIcon: string;
|
|
37
39
|
actionRetryBtnClass: string;
|
|
38
40
|
};
|
|
39
41
|
variants: {
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
export const uploadFileDropzoneTheme = {
|
|
2
|
+
icons: {
|
|
3
|
+
filePreviewIcon: "i-heroicons:document-text-solid",
|
|
4
|
+
uploadIcon: "ri:upload-cloud-2-line",
|
|
5
|
+
placeholderImgIcon: "i-material-symbols:imagesmode-outline",
|
|
6
|
+
failedImgIcon: "i-material-symbols:imagesmode-outline",
|
|
7
|
+
loadingIcon: "i-svg-spinners:180-ring-with-bg",
|
|
8
|
+
actionPreviewIcon: "ic:outline-remove-red-eye",
|
|
9
|
+
actionDownloadIcon: "material-symbols:download",
|
|
10
|
+
actionDeleteIcon: "material-symbols:delete",
|
|
11
|
+
actionRetryIcon: "stash:arrow-retry"
|
|
12
|
+
},
|
|
2
13
|
slots: {
|
|
3
14
|
base: "relative w-full text-base p-4 transition rounded-md flex items-center justify-center ring-1 bg-white ring-gray-300",
|
|
4
15
|
wrapper: "flex flex-col items-center w-full",
|
|
@@ -7,11 +18,6 @@ export const uploadFileDropzoneTheme = {
|
|
|
7
18
|
placeholderWrapper: "py-4 flex flex-col items-center justify-center",
|
|
8
19
|
placeholder: "text-gray-400 text-center font-light text-sm truncate",
|
|
9
20
|
labelWrapper: "flex items-center space-x-2 text-gray-400 text-center",
|
|
10
|
-
filePreviewIcon: "i-heroicons:document-text-solid",
|
|
11
|
-
uploadIcon: "ri:upload-cloud-2-line",
|
|
12
|
-
placeholderImgIcon: "i-material-symbols:imagesmode-outline",
|
|
13
|
-
failedImgIcon: "i-material-symbols:imagesmode-outline",
|
|
14
|
-
loadingIcon: "i-svg-spinners:180-ring-with-bg",
|
|
15
21
|
labelIcon: "size-6 text-gray-400 text-center mb-3",
|
|
16
22
|
// Loading state
|
|
17
23
|
onLoadingWrapper: "flex items-center space-x-4 w-full",
|
|
@@ -34,10 +40,6 @@ export const uploadFileDropzoneTheme = {
|
|
|
34
40
|
actionWrapper: "flex items-center space-x-2",
|
|
35
41
|
actionIconClass: "size-6 text-dimmed hover:text-dimmed-600 cursor-pointer transition-colors",
|
|
36
42
|
actionDeleteIconClass: "size-6 text-(--ui-color-error-500) hover:text-(--ui-color-error-600) cursor-pointer transition-colors",
|
|
37
|
-
actionPreviewIcon: "ic:outline-remove-red-eye",
|
|
38
|
-
actionDownloadIcon: "material-symbols:download",
|
|
39
|
-
actionDeleteIcon: "material-symbols:delete",
|
|
40
|
-
actionRetryIcon: "stash:arrow-retry",
|
|
41
43
|
actionRetryBtnClass: "px-0"
|
|
42
44
|
},
|
|
43
45
|
variants: {
|