@hostlink/nuxt-light 1.0.11 → 1.1.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/runtime/components/l-app.vue +1 -1
- package/dist/runtime/components/l-banner.vue +1 -1
- package/dist/runtime/components/l-date-picker.vue +52 -15
- package/dist/runtime/components/l-editor.vue +127 -0
- package/dist/runtime/components/l-field.vue +24 -9
- package/dist/runtime/components/l-file-upload.vue +31 -4
- package/dist/runtime/components/l-input.vue +40 -64
- package/dist/runtime/components/l-item.vue +12 -13
- package/dist/runtime/components/l-list.vue +17 -14
- package/dist/runtime/components/l-login.vue +2 -2
- package/dist/runtime/components/l-page.vue +28 -67
- package/dist/runtime/components/l-tab.vue +3 -2
- package/dist/runtime/components/l-table.vue +18 -17
- package/dist/runtime/components/l-tabs.vue +9 -4
- package/dist/runtime/formkit/Editor.vue +25 -0
- package/dist/runtime/formkit/Repeater.vue +5 -6
- package/dist/runtime/formkit/index.mjs +7 -1
- package/dist/runtime/lib/getID.d.ts +1 -1
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -3,7 +3,7 @@ import { useLight, watch } from "#imports";
|
|
|
3
3
|
import { useRuntimeConfig } from 'nuxt/app'
|
|
4
4
|
import { setApiUrl } from '@hostlink/light'
|
|
5
5
|
import { Dialog } from 'quasar'
|
|
6
|
-
import { q } from '
|
|
6
|
+
import { q } from '#imports'
|
|
7
7
|
import { useRoute } from "#vue-router";
|
|
8
8
|
const config = useRuntimeConfig();
|
|
9
9
|
setApiUrl(config?.public?.apiBase ?? '/api/');
|
|
@@ -1,15 +1,37 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, computed
|
|
2
|
+
import { ref, computed } from "vue";
|
|
3
3
|
import { useLight } from '#imports';
|
|
4
4
|
|
|
5
5
|
import { type QDateProps } from "quasar";
|
|
6
|
+
import { useI18n } from 'vue-i18n';
|
|
7
|
+
|
|
8
|
+
const { t } = useI18n();
|
|
6
9
|
|
|
7
10
|
export interface LDatePickerProps extends QDateProps {
|
|
8
11
|
label?: string
|
|
9
12
|
required?: boolean
|
|
13
|
+
hideBottomSpace?: boolean
|
|
14
|
+
filled?: boolean
|
|
15
|
+
outlined?: boolean
|
|
16
|
+
standout?: boolean
|
|
17
|
+
rounded?: boolean
|
|
18
|
+
dense?: boolean
|
|
19
|
+
square?: boolean
|
|
20
|
+
stackLabel?: boolean
|
|
21
|
+
rules?: any[]
|
|
10
22
|
}
|
|
11
23
|
|
|
12
|
-
const props = defineProps<LDatePickerProps>()
|
|
24
|
+
const props = withDefaults(defineProps<LDatePickerProps>(), {
|
|
25
|
+
hideBottomSpace: true,
|
|
26
|
+
filled: undefined,
|
|
27
|
+
outlined: undefined,
|
|
28
|
+
standout: undefined,
|
|
29
|
+
rounded: undefined,
|
|
30
|
+
dense: undefined,
|
|
31
|
+
square: undefined,
|
|
32
|
+
stackLabel: undefined,
|
|
33
|
+
mask: "YYYY-MM-DD",
|
|
34
|
+
})
|
|
13
35
|
|
|
14
36
|
const light = useLight();
|
|
15
37
|
|
|
@@ -55,26 +77,41 @@ if (!props.range) {
|
|
|
55
77
|
});
|
|
56
78
|
}
|
|
57
79
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
80
|
+
const input_attrs = computed(() => {
|
|
81
|
+
const attrs: any = {
|
|
82
|
+
label: props.label,
|
|
83
|
+
rules: rules,
|
|
84
|
+
hideBottomSpace: props.hideBottomSpace,
|
|
85
|
+
mask: props.range ? "####-##-## - ####-##-##" : "####-##-##"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (props.filled == undefined) attrs.filled = light.getStyle("inputFilled");
|
|
89
|
+
if (props.outlined == undefined) attrs.outlined = light.getStyle("inputOutlined");
|
|
90
|
+
if (props.standout == undefined) attrs.standout = light.getStyle("inputStandout");
|
|
91
|
+
if (props.rounded == undefined) attrs.rounded = light.getStyle("inputRounded");
|
|
92
|
+
if (props.dense == undefined) attrs.dense = light.getStyle("inputDense");
|
|
93
|
+
if (props.square == undefined) attrs.square = light.getStyle("inputSquare");
|
|
94
|
+
if (props.stackLabel == undefined) attrs.stackLabel = light.getStyle("inputStackLabel");
|
|
95
|
+
|
|
96
|
+
if (props.label) {
|
|
97
|
+
attrs.label = t(props.label);
|
|
98
|
+
}
|
|
99
|
+
return attrs;
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const date_attrs = computed(() => {
|
|
103
|
+
const { label, rules, hideBottomSpace, filled, outlined, standout, rounded, dense, square, stackLabel, ...rest } = props;
|
|
104
|
+
return rest;
|
|
105
|
+
});
|
|
67
106
|
|
|
68
|
-
const mask = props.range ? "####-##-## - ####-##-##" : "####-##-##";
|
|
69
107
|
|
|
70
108
|
</script>
|
|
71
109
|
<template>
|
|
72
|
-
<q-input v-bind="
|
|
73
|
-
:mask="mask">
|
|
110
|
+
<q-input v-bind="input_attrs" v-model="localValue" :rules="rules">
|
|
74
111
|
<template v-slot:prepend>
|
|
75
112
|
<q-btn icon="sym_o_event" round dense flat>
|
|
76
113
|
<q-popup-proxy cover transition-show="scale" transition-hide="scale" ref="popup">
|
|
77
|
-
<q-date v-
|
|
114
|
+
<q-date v-bind="date_attrs" v-model="localValue">
|
|
78
115
|
<div class="row items-center justify-end">
|
|
79
116
|
<q-btn v-close-popup label="Close" color="primary" flat />
|
|
80
117
|
</div>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref, useAttrs } from "vue";
|
|
3
|
+
import { type QEditorProps, useQuasar } from "quasar"
|
|
4
|
+
|
|
5
|
+
const $q = useQuasar();
|
|
6
|
+
|
|
7
|
+
export interface LEditorProps extends QEditorProps {
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
12
|
+
|
|
13
|
+
const props = withDefaults(defineProps<LEditorProps>(), {
|
|
14
|
+
modelValue: "",
|
|
15
|
+
placeholder: "type something",
|
|
16
|
+
dense: false,
|
|
17
|
+
toolbar: undefined,
|
|
18
|
+
fonts: undefined,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const localValue = computed({
|
|
22
|
+
get: () => props.modelValue,
|
|
23
|
+
set: (value) => emit('update:modelValue', value)
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const attrs = computed(() => {
|
|
27
|
+
const a = { ...props };
|
|
28
|
+
if (props.toolbar === undefined) a.toolbar = newToolBar;
|
|
29
|
+
if (props.fonts === undefined) a.fonts = newFonts;
|
|
30
|
+
return a;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
const newToolBar = [
|
|
35
|
+
[
|
|
36
|
+
{
|
|
37
|
+
label: $q.lang.editor.align,
|
|
38
|
+
icon: $q.iconSet.editor.align,
|
|
39
|
+
fixedLabel: true,
|
|
40
|
+
list: 'only-icons',
|
|
41
|
+
options: ['left', 'center', 'right', 'justify']
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
label: $q.lang.editor.align,
|
|
45
|
+
icon: $q.iconSet.editor.align,
|
|
46
|
+
fixedLabel: true,
|
|
47
|
+
options: ['left', 'center', 'right', 'justify']
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
['bold', 'italic', 'strike', 'underline', 'subscript', 'superscript'],
|
|
51
|
+
['token', 'hr', 'link', 'custom_btn'],
|
|
52
|
+
['print', 'fullscreen'],
|
|
53
|
+
[
|
|
54
|
+
{
|
|
55
|
+
label: $q.lang.editor.formatting,
|
|
56
|
+
icon: $q.iconSet.editor.formatting,
|
|
57
|
+
list: 'no-icons',
|
|
58
|
+
options: [
|
|
59
|
+
'p',
|
|
60
|
+
'h1',
|
|
61
|
+
'h2',
|
|
62
|
+
'h3',
|
|
63
|
+
'h4',
|
|
64
|
+
'h5',
|
|
65
|
+
'h6',
|
|
66
|
+
'code'
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
label: $q.lang.editor.fontSize,
|
|
71
|
+
icon: $q.iconSet.editor.fontSize,
|
|
72
|
+
fixedLabel: true,
|
|
73
|
+
fixedIcon: true,
|
|
74
|
+
list: 'no-icons',
|
|
75
|
+
options: [
|
|
76
|
+
'size-1',
|
|
77
|
+
'size-2',
|
|
78
|
+
'size-3',
|
|
79
|
+
'size-4',
|
|
80
|
+
'size-5',
|
|
81
|
+
'size-6',
|
|
82
|
+
'size-7'
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
label: $q.lang.editor.defaultFont,
|
|
87
|
+
icon: $q.iconSet.editor.font,
|
|
88
|
+
fixedIcon: true,
|
|
89
|
+
list: 'no-icons',
|
|
90
|
+
options: [
|
|
91
|
+
'default_font',
|
|
92
|
+
'arial',
|
|
93
|
+
'arial_black',
|
|
94
|
+
'comic_sans',
|
|
95
|
+
'courier_new',
|
|
96
|
+
'impact',
|
|
97
|
+
'lucida_grande',
|
|
98
|
+
'times_new_roman',
|
|
99
|
+
'verdana'
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
'removeFormat'
|
|
103
|
+
],
|
|
104
|
+
['quote', 'unordered', 'ordered', 'outdent', 'indent'],
|
|
105
|
+
|
|
106
|
+
['undo', 'redo'],
|
|
107
|
+
['viewsource']
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
const newFonts = {
|
|
111
|
+
arial: 'Arial',
|
|
112
|
+
arial_black: 'Arial Black',
|
|
113
|
+
comic_sans: 'Comic Sans MS',
|
|
114
|
+
courier_new: 'Courier New',
|
|
115
|
+
impact: 'Impact',
|
|
116
|
+
lucida_grande: 'Lucida Grande',
|
|
117
|
+
times_new_roman: 'Times New Roman',
|
|
118
|
+
verdana: 'Verdana'
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
</script>
|
|
122
|
+
|
|
123
|
+
<template>
|
|
124
|
+
<div class="q-pa-md q-gutter-sm">
|
|
125
|
+
<q-editor v-bind="attrs" v-model="localValue" />
|
|
126
|
+
</div>
|
|
127
|
+
</template>
|
|
@@ -1,17 +1,32 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { useLight
|
|
3
|
-
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useLight } from '#imports';
|
|
3
|
+
import { computed } from 'vue';
|
|
4
|
+
import { useI18n } from 'vue-i18n';
|
|
5
|
+
|
|
6
|
+
import type { QFieldProps } from 'quasar';
|
|
7
|
+
|
|
8
|
+
const props = defineProps<QFieldProps>()
|
|
4
9
|
const light = useLight();
|
|
10
|
+
const { t } = useI18n();
|
|
5
11
|
|
|
6
|
-
const attrs = {
|
|
7
|
-
|
|
12
|
+
const attrs = computed(() => {
|
|
13
|
+
|
|
14
|
+
const a = {
|
|
15
|
+
...props,
|
|
8
16
|
outlined: light.getStyle("inputOutlined"),
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
if (props.label) {
|
|
20
|
+
a.label = t(props.label);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
return a;
|
|
25
|
+
});
|
|
26
|
+
|
|
12
27
|
</script>
|
|
13
28
|
<template>
|
|
14
|
-
<q-field v-bind="attrs"
|
|
29
|
+
<q-field v-bind="attrs">
|
|
15
30
|
<slot></slot>
|
|
16
31
|
</q-field>
|
|
17
32
|
</template>
|
|
@@ -64,6 +64,33 @@ const attrs = computed(() => {
|
|
|
64
64
|
return a;
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
+
|
|
68
|
+
//@param bytes Number of bytes.
|
|
69
|
+
//@param si True to use metric (SI) units, aka powers of 1000. False to use binary (IEC), aka powers of 1024.
|
|
70
|
+
//@param dp Number of decimal places to display.
|
|
71
|
+
const humanFileSize = (bytesSize, si = false, dp = 1) => {
|
|
72
|
+
const thresh = si ? 1000 : 1024;
|
|
73
|
+
|
|
74
|
+
if (Math.abs(bytesSize) < thresh) {
|
|
75
|
+
return bytesSize + ' B';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const units = si
|
|
79
|
+
? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
|
80
|
+
: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; //: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
|
81
|
+
let u = -1;
|
|
82
|
+
const r = 10 ** dp;
|
|
83
|
+
|
|
84
|
+
do {
|
|
85
|
+
bytesSize /= thresh;
|
|
86
|
+
++u;
|
|
87
|
+
} while (Math.round(Math.abs(bytesSize) * r) / r >= thresh && u < units.length - 1);
|
|
88
|
+
|
|
89
|
+
return bytesSize.toFixed(dp) + ' ' + units[u];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
67
94
|
const uploadFile = ref<File | null>(null);
|
|
68
95
|
const rename = ref(true);
|
|
69
96
|
|
|
@@ -82,7 +109,7 @@ const onUploadFile = async () => {
|
|
|
82
109
|
if (uploadFile.value.size > system.maxUploadSize) {
|
|
83
110
|
Dialog.create({
|
|
84
111
|
title: "Error",
|
|
85
|
-
message: "File size is too big. Max size is " + system.maxUploadSize
|
|
112
|
+
message: "File size is too big. Max size is " + humanFileSize(system.maxUploadSize, false, 0),
|
|
86
113
|
color: "negative"
|
|
87
114
|
});
|
|
88
115
|
return;
|
|
@@ -134,11 +161,11 @@ const onUploadFile = async () => {
|
|
|
134
161
|
<q-dialog v-model="show" persistent transition-show="scale" transition-hide="scale">
|
|
135
162
|
<l-card style="width:300px">
|
|
136
163
|
<q-card-section>
|
|
137
|
-
<q-file ref="file" v-model="uploadFile" name="file" :label="$t('File')" :accept="accept"
|
|
164
|
+
<q-file ref="file" v-model="uploadFile" name="file" :label="$t('File')" :accept="accept"
|
|
165
|
+
:hint="`Max upload size: ${humanFileSize(system.maxUploadSize, false, 0)}`"></q-file>
|
|
138
166
|
<!-- q-checkbox v-model="rename" :label="$t('Rename file if exists')"></q-checkbox-->
|
|
139
|
-
|
|
140
|
-
|
|
141
167
|
</q-card-section>
|
|
168
|
+
|
|
142
169
|
<q-card-actions align="right">
|
|
143
170
|
<q-btn flat :label="$t('Cancel')" color="primary" v-close-popup></q-btn>
|
|
144
171
|
<q-btn flat :label="$t('Upload')" color="primary" @click="onUploadFile"></q-btn>
|
|
@@ -1,49 +1,41 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { computed, ref
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref } from "vue";
|
|
3
3
|
import { useI18n } from 'vue-i18n';
|
|
4
4
|
import tc2sc from "../lib/tc2sc";
|
|
5
5
|
import { useLight } from '#imports';
|
|
6
6
|
|
|
7
|
+
import type { QInputProps } from "quasar";
|
|
8
|
+
export interface LInputProps extends QInputProps {
|
|
9
|
+
showPassword?: boolean;
|
|
10
|
+
translate?: boolean;
|
|
11
|
+
required?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
7
14
|
const i18n = useI18n();
|
|
8
15
|
const light = useLight();
|
|
9
16
|
|
|
10
|
-
const props = defineProps({
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
type: String,
|
|
23
|
-
default: ""
|
|
24
|
-
},
|
|
25
|
-
type: {
|
|
26
|
-
type: String,
|
|
27
|
-
default: "text"
|
|
28
|
-
},
|
|
29
|
-
showPassword: {
|
|
30
|
-
type: Boolean,
|
|
31
|
-
default: false
|
|
32
|
-
},
|
|
33
|
-
translate: {
|
|
34
|
-
type: Boolean,
|
|
35
|
-
default: false
|
|
36
|
-
}
|
|
17
|
+
const props = withDefaults(defineProps<LInputProps>(), {
|
|
18
|
+
showPassword: false,
|
|
19
|
+
translate: false,
|
|
20
|
+
outlined: undefined,
|
|
21
|
+
filled: undefined,
|
|
22
|
+
standout: undefined,
|
|
23
|
+
rounded: undefined,
|
|
24
|
+
dense: undefined,
|
|
25
|
+
square: undefined,
|
|
26
|
+
stackLabel: undefined,
|
|
27
|
+
required: false,
|
|
28
|
+
hideBottomSpace: true,
|
|
37
29
|
});
|
|
30
|
+
|
|
38
31
|
const emit = defineEmits(["update:modelValue"]);
|
|
39
32
|
|
|
40
33
|
//clone rules to new_rules
|
|
41
34
|
const new_rules = props.rules || [];
|
|
42
35
|
|
|
43
|
-
|
|
44
36
|
//has required prop (in properties)
|
|
45
|
-
if (props.required
|
|
46
|
-
new_rules.push(val => !!val || i18n.t('input_required', [i18n.t(props.label)]));
|
|
37
|
+
if (props.required) {
|
|
38
|
+
new_rules.push(val => !!val || i18n.t('input_required', [i18n.t(props.label ?? "")]));
|
|
47
39
|
}
|
|
48
40
|
|
|
49
41
|
if (props.type == "email") {
|
|
@@ -101,24 +93,11 @@ if (minLength) {
|
|
|
101
93
|
});
|
|
102
94
|
}
|
|
103
95
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
96
|
const localValue = computed({
|
|
110
97
|
get: () => props.modelValue,
|
|
111
98
|
set: (value) => emit('update:modelValue', value)
|
|
112
99
|
});
|
|
113
100
|
|
|
114
|
-
const localLabel = computed(() => {
|
|
115
|
-
if (props.required && !localValue.value) {
|
|
116
|
-
return i18n.t(props.label);
|
|
117
|
-
}
|
|
118
|
-
return i18n.t(props.label);
|
|
119
|
-
|
|
120
|
-
});
|
|
121
|
-
|
|
122
101
|
const isShowPassword = ref(false);
|
|
123
102
|
|
|
124
103
|
const localType = computed(() => {
|
|
@@ -128,8 +107,6 @@ const localType = computed(() => {
|
|
|
128
107
|
return props.type;
|
|
129
108
|
});
|
|
130
109
|
|
|
131
|
-
|
|
132
|
-
|
|
133
110
|
const localShowPassword = computed(() => {
|
|
134
111
|
if (props.type != "password") {
|
|
135
112
|
return false;
|
|
@@ -142,32 +119,31 @@ const localShowPassword = computed(() => {
|
|
|
142
119
|
if (!localValue.value) {
|
|
143
120
|
return false;
|
|
144
121
|
}
|
|
145
|
-
|
|
146
122
|
return true;
|
|
147
|
-
|
|
148
123
|
});
|
|
149
124
|
|
|
150
|
-
|
|
151
125
|
const onClickTc2Sc = () => {
|
|
152
126
|
localValue.value = tc2sc(localValue.value);
|
|
153
127
|
}
|
|
154
128
|
|
|
155
|
-
const attrs = {
|
|
156
|
-
...
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
129
|
+
const attrs = computed(() => {
|
|
130
|
+
const a = { ...props };
|
|
131
|
+
if (props.outlined === undefined) a.outlined = light.getStyle("inputOutlined");
|
|
132
|
+
if (props.filled === undefined) a.filled = light.getStyle("inputFilled");
|
|
133
|
+
if (props.standout === undefined) a.standout = light.getStyle("inputStandout");
|
|
134
|
+
if (props.rounded === undefined) a.rounded = light.getStyle("inputRounded");
|
|
135
|
+
if (props.dense === undefined) a.dense = light.getStyle("inputDense");
|
|
136
|
+
if (props.square === undefined) a.square = light.getStyle("inputSquare");
|
|
137
|
+
if (props.stackLabel === undefined) a.stackLabel = light.getStyle("inputStackLabel");
|
|
138
|
+
|
|
139
|
+
if (props.label) {
|
|
140
|
+
a.label = i18n.t(props.label);
|
|
141
|
+
}
|
|
142
|
+
return a;
|
|
143
|
+
})
|
|
168
144
|
</script>
|
|
169
145
|
<template>
|
|
170
|
-
<q-input v-bind="attrs"
|
|
146
|
+
<q-input v-bind="attrs" v-model="localValue" :rules="new_rules" :type="localType">
|
|
171
147
|
<template v-if="translate" #prepend>
|
|
172
148
|
<q-btn icon="sym_o_translate" flat dense rounded>
|
|
173
149
|
<q-menu dense>
|
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
|
|
3
|
-
label: {
|
|
4
|
-
type: String,
|
|
5
|
-
},
|
|
6
|
-
type: {
|
|
7
|
-
type: String,
|
|
8
|
-
default: "text"
|
|
9
|
-
}, name: {
|
|
10
|
-
type: String,
|
|
11
|
-
default: null
|
|
12
|
-
}
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { QItemProps } from 'quasar';
|
|
13
3
|
|
|
4
|
+
export interface LItemProps extends QItemProps {
|
|
5
|
+
label?: string;
|
|
6
|
+
type?: 'text' | 'caption';
|
|
7
|
+
name?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
withDefaults(defineProps<LItemProps>(), {
|
|
11
|
+
label: '',
|
|
12
|
+
type: 'text'
|
|
14
13
|
});
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
</script>
|
|
18
17
|
<template>
|
|
19
|
-
<q-item>
|
|
18
|
+
<q-item v-bind="$props">
|
|
20
19
|
<q-item-section>
|
|
21
20
|
<q-item-label>{{ $t(label) }}</q-item-label>
|
|
22
21
|
<q-item-label caption v-if="type == 'caption'">
|
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
import type { QListProps } from 'quasar';
|
|
4
|
+
|
|
5
|
+
export interface LListProps extends QListProps {
|
|
6
|
+
fields?: any[];
|
|
7
|
+
modelValue?: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const props = withDefaults(defineProps<LListProps>(), {
|
|
11
|
+
bordered: true,
|
|
12
|
+
separator: true,
|
|
13
|
+
dense: true,
|
|
14
|
+
});
|
|
11
15
|
|
|
12
16
|
function getTo(field) {
|
|
13
17
|
|
|
14
|
-
const raw=field.getRaw();
|
|
15
|
-
|
|
18
|
+
const raw = field.getRaw();
|
|
19
|
+
|
|
16
20
|
if (raw.to) {
|
|
17
21
|
if (raw.to instanceof Function) {
|
|
18
22
|
return raw.to(props.modelValue);
|
|
@@ -26,10 +30,9 @@ function getTo(field) {
|
|
|
26
30
|
return null;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
|
-
|
|
30
33
|
</script>
|
|
31
34
|
<template>
|
|
32
|
-
<q-list
|
|
35
|
+
<q-list v-bind="$props">
|
|
33
36
|
<template v-if="fields">
|
|
34
37
|
<l-item v-for="field in fields" :label="field.getRaw().label" :to="getTo(field)">
|
|
35
38
|
{{ field.getFormattedValue(props.modelValue) }}
|
|
@@ -194,8 +194,8 @@ onMounted(() => {
|
|
|
194
194
|
<q-form ref="form1">
|
|
195
195
|
<div class="q-gutter-sm">
|
|
196
196
|
<l-input v-model.trim="data.username" label="Username" :rules="[v => !!v || $t('Username is required')]"
|
|
197
|
-
clearable :outlined="false" />
|
|
198
|
-
<l-input v-model="data.password" label="Password" type="password" clearable show-password
|
|
197
|
+
clearable :outlined="false" stackLabel/>
|
|
198
|
+
<l-input v-model="data.password" label="Password" type="password" clearable show-password stackLabel
|
|
199
199
|
:rules="[v => !!v || $t('Password is required')]" @keydown.enter.prevent="submit" :outlined="false" />
|
|
200
200
|
<l-input v-if="twoFactorAuthentication" v-model="data.code" label="2FA code" required type="text" clearable>
|
|
201
201
|
</l-input>
|
|
@@ -1,75 +1,32 @@
|
|
|
1
|
-
<script setup>
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import { useHead, useLight } from "#imports";
|
|
3
3
|
import { useRouter, useRoute } from "vue-router"
|
|
4
4
|
import { model, getID } from '../'
|
|
5
|
+
import type { QPageProps } from "quasar";
|
|
6
|
+
import { computed } from 'vue'
|
|
5
7
|
|
|
6
8
|
const router = useRouter();
|
|
7
9
|
const route = useRoute();
|
|
8
10
|
const light = useLight();
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
type: String,
|
|
17
|
-
default: ""
|
|
18
|
-
},
|
|
19
|
-
backBtn: {
|
|
20
|
-
type: Boolean,
|
|
21
|
-
default: false
|
|
22
|
-
},
|
|
23
|
-
editBtn: {
|
|
24
|
-
type: Boolean,
|
|
25
|
-
default: false
|
|
26
|
-
},
|
|
27
|
-
deleteBtn: {
|
|
28
|
-
type: Boolean,
|
|
29
|
-
default: false
|
|
30
|
-
},
|
|
31
|
-
addBtn: {
|
|
32
|
-
type: Boolean,
|
|
33
|
-
default: false
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
let showToolbar = false;
|
|
38
|
-
let showBackBtn = false;
|
|
39
|
-
let showEditBtn = false;
|
|
40
|
-
let showAddBtn = false;
|
|
41
|
-
let showDeleteBtn = false;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (props.type == "edit") {
|
|
45
|
-
showToolbar = true
|
|
46
|
-
showBackBtn = true
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (props.type == "add") {
|
|
50
|
-
showToolbar = true
|
|
51
|
-
showBackBtn = true
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (props.type == "view") {
|
|
55
|
-
showToolbar = true
|
|
56
|
-
showBackBtn = true
|
|
12
|
+
export interface LPageProps extends QPageProps {
|
|
13
|
+
title?: string;
|
|
14
|
+
backBtn?: boolean;
|
|
15
|
+
editBtn?: boolean;
|
|
16
|
+
deleteBtn?: boolean;
|
|
17
|
+
addBtn?: boolean;
|
|
57
18
|
}
|
|
58
19
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (props.deleteBtn) {
|
|
65
|
-
showToolbar = true
|
|
66
|
-
showDeleteBtn = true
|
|
67
|
-
}
|
|
20
|
+
const props = withDefaults(defineProps<LPageProps>(), {
|
|
21
|
+
title: "",
|
|
22
|
+
backBtn: true,
|
|
23
|
+
});
|
|
68
24
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
25
|
+
const showToolbar = computed(() => {
|
|
26
|
+
if (props.backBtn || props.editBtn || props.deleteBtn || props.addBtn) {
|
|
27
|
+
return true
|
|
28
|
+
}
|
|
29
|
+
});
|
|
73
30
|
|
|
74
31
|
let title = props.title || route.path.split("/")[1].replace(/([a-z])(?=[A-Z])/g, '$1 ').replace(/([A-Z]*)(?=[A-Z][a-z])/g, '$1 ')
|
|
75
32
|
|
|
@@ -80,9 +37,13 @@ title = title.trim()
|
|
|
80
37
|
const module = route.path.split("/")[1];
|
|
81
38
|
const onDelete = async () => {
|
|
82
39
|
|
|
83
|
-
|
|
84
|
-
|
|
40
|
+
const id = getID();
|
|
41
|
+
if (id) {
|
|
42
|
+
if (await model(module).delete(id)) {
|
|
43
|
+
router.push(`/${module}`);
|
|
44
|
+
}
|
|
85
45
|
}
|
|
46
|
+
|
|
86
47
|
}
|
|
87
48
|
|
|
88
49
|
useHead({
|
|
@@ -99,10 +60,10 @@ useHead({
|
|
|
99
60
|
</q-breadcrumbs -->
|
|
100
61
|
|
|
101
62
|
<q-toolbar v-if="showToolbar">
|
|
102
|
-
<l-back-btn v-if="
|
|
103
|
-
<l-add-btn v-if="
|
|
104
|
-
<l-edit-btn v-if="
|
|
105
|
-
<l-delete-btn v-if="
|
|
63
|
+
<l-back-btn v-if="backBtn" />
|
|
64
|
+
<l-add-btn v-if="addBtn" />
|
|
65
|
+
<l-edit-btn v-if="editBtn" />
|
|
66
|
+
<l-delete-btn v-if="deleteBtn" @submit="onDelete" />
|
|
106
67
|
<q-toolbar-title>{{ $t(title) }}</q-toolbar-title>
|
|
107
68
|
</q-toolbar>
|
|
108
69
|
|
|
@@ -300,7 +300,7 @@ const onRequest = async (p: any) => {
|
|
|
300
300
|
name: true
|
|
301
301
|
}
|
|
302
302
|
},
|
|
303
|
-
setData(data: { data: Array<{ data: any }>, meta: { total:
|
|
303
|
+
setData(data: { data: Array<{ data: any }>, meta: { total: number, key: string, name: string } }) {
|
|
304
304
|
rows.value = data.data;
|
|
305
305
|
primaryKey.value = data.meta.key;
|
|
306
306
|
modelName.value = data.meta.name;
|
|
@@ -411,22 +411,23 @@ const onDelete = async (id: any) => {
|
|
|
411
411
|
}
|
|
412
412
|
}
|
|
413
413
|
|
|
414
|
-
const attrs = {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
}
|
|
414
|
+
const attrs = computed(() => {
|
|
415
|
+
return {
|
|
416
|
+
...{
|
|
417
|
+
dense: light.getStyle("tableDense"),
|
|
418
|
+
flat: light.getStyle("tableFlat"),
|
|
419
|
+
bordered: light.getStyle("tableBorder"),
|
|
420
|
+
separator: light.getStyle("tableSeparator"),
|
|
421
|
+
},
|
|
422
|
+
title: props.title,
|
|
423
|
+
loadingLabel: t(props.loadingLabel),
|
|
424
|
+
noDataLabel: t(props.noDataLabel),
|
|
425
|
+
rowsPerPageOptions: props.rowsPerPageOptions,
|
|
426
|
+
rowsPerPageLabel: t(props.rowsPerPageLabel),
|
|
427
|
+
selection: props.selection,
|
|
428
|
+
rowKey: props.rowKey,
|
|
429
|
+
}
|
|
430
|
+
});
|
|
430
431
|
|
|
431
432
|
const filter = ref('');
|
|
432
433
|
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { useLight } from '
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useLight } from '#imports'
|
|
3
3
|
import { useSlots, computed, ref } from 'vue';
|
|
4
|
+
import type { QTabsProps } from 'quasar';
|
|
5
|
+
|
|
6
|
+
interface LTabsProps extends QTabsProps {
|
|
7
|
+
|
|
8
|
+
}
|
|
4
9
|
|
|
5
10
|
const light = useLight();
|
|
6
|
-
const props = defineProps(
|
|
11
|
+
const props = defineProps<LTabsProps>()
|
|
7
12
|
const emit = defineEmits(["update:modelValue"])
|
|
8
13
|
const slots = useSlots();
|
|
9
14
|
const defaultSlots = slots.default();
|
|
@@ -32,7 +37,7 @@ const localValue = computed({
|
|
|
32
37
|
}
|
|
33
38
|
})
|
|
34
39
|
|
|
35
|
-
const color = light.getStyle("color"
|
|
40
|
+
const color = light.getStyle("color");
|
|
36
41
|
|
|
37
42
|
</script>
|
|
38
43
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { getErrorMessage } from 'formkit-quasar';
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
context: Object
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const { error, errorMessage } = getErrorMessage(props.context.node);
|
|
10
|
+
|
|
11
|
+
const value = computed({
|
|
12
|
+
get: () => props.context.value,
|
|
13
|
+
set: (val) => props.context.node.input(val)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
</script>
|
|
17
|
+
<template>
|
|
18
|
+
<l-editor v-model="value" :label="context.label" v-bind="context.attrs" :error="error" :type="context.inputType"
|
|
19
|
+
:error-message="errorMessage">
|
|
20
|
+
<slot></slot>
|
|
21
|
+
<!-- <template v-for="(s, name) in $slots" v-slot:[name]="props" :key="name">
|
|
22
|
+
<slot :name="name" v-bind="props ?? {}"></slot>
|
|
23
|
+
</template> -->
|
|
24
|
+
</l-editor>
|
|
25
|
+
</template>
|
|
@@ -59,12 +59,11 @@ const isAllowMoveDown = (index) => {
|
|
|
59
59
|
return index < localValue.value.length - 1
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
62
|
</script>
|
|
65
63
|
|
|
66
64
|
<template>
|
|
67
|
-
<FormKit type="list" v-model="localValue" dynamic #default="{ items, node, value }">
|
|
65
|
+
<FormKit type="list" v-model="localValue" dynamic #default="{ items, node, value }" :name="node.name">
|
|
66
|
+
|
|
68
67
|
|
|
69
68
|
<FormKit type="group" v-for="(item, index) in items " :index="index" :key="item">
|
|
70
69
|
|
|
@@ -76,7 +75,7 @@ const isAllowMoveDown = (index) => {
|
|
|
76
75
|
<div class="q-mb-sm">
|
|
77
76
|
<!-- up -->
|
|
78
77
|
<q-btn type="button" @click="onMoveUp(index)" icon="sym_o_arrow_upward" color="primary"
|
|
79
|
-
dense unelevated :disable="!isAllowMoveUp(index)"/>
|
|
78
|
+
dense unelevated :disable="!isAllowMoveUp(index)" />
|
|
80
79
|
</div>
|
|
81
80
|
|
|
82
81
|
<div class="q-mb-sm">
|
|
@@ -88,13 +87,13 @@ const isAllowMoveDown = (index) => {
|
|
|
88
87
|
<div class="q-mb-sm">
|
|
89
88
|
<!-- down -->
|
|
90
89
|
<q-btn type="button" @click="onMoveDown(index)" icon="sym_o_arrow_downward" color="primary"
|
|
91
|
-
dense unelevated :disable="!isAllowMoveDown(index)"/>
|
|
90
|
+
dense unelevated :disable="!isAllowMoveDown(index)" />
|
|
92
91
|
</div>
|
|
93
92
|
|
|
94
93
|
</div>
|
|
95
94
|
|
|
96
95
|
<div class="col">
|
|
97
|
-
<slot></slot>
|
|
96
|
+
<slot v-bind="{ value: localValue[index] }"></slot>
|
|
98
97
|
</div>
|
|
99
98
|
</div>
|
|
100
99
|
</q-card-section>
|
|
@@ -12,10 +12,16 @@ import FilePickerVue from "./FilePicker.vue";
|
|
|
12
12
|
import FileVue from "./File.vue";
|
|
13
13
|
import InputXlsxVue from "./InputXlsx.vue";
|
|
14
14
|
import FileUploadVue from "./FileUpload.vue";
|
|
15
|
+
import EditorVue from "./Editor.vue";
|
|
15
16
|
export const createLightPlugin = () => {
|
|
16
17
|
return (node) => {
|
|
17
18
|
let type = node.props.type + "";
|
|
18
19
|
switch (type) {
|
|
20
|
+
case "l-editor":
|
|
21
|
+
return node.define({
|
|
22
|
+
type: "input",
|
|
23
|
+
component: EditorVue
|
|
24
|
+
});
|
|
19
25
|
case "l-file-upload":
|
|
20
26
|
return node.define({
|
|
21
27
|
type: "input",
|
|
@@ -74,7 +80,7 @@ export const createLightPlugin = () => {
|
|
|
74
80
|
});
|
|
75
81
|
case "l-repeater":
|
|
76
82
|
return node.define({
|
|
77
|
-
type: "
|
|
83
|
+
type: "input",
|
|
78
84
|
props: ["min", "max"],
|
|
79
85
|
component: RepeaterVue
|
|
80
86
|
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: () =>
|
|
1
|
+
declare const _default: () => number | null;
|
|
2
2
|
export default _default;
|