easycomponentstools 1.0.0-dev.0
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/.idea/EasyComponents.iml +8 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/jsLinters/eslint.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/php.xml +19 -0
- package/.idea/prettier.xml +7 -0
- package/.prettierrc +9 -0
- package/dist/easyComponents.es.js +35624 -0
- package/dist/easyComponents.umd.js +27 -0
- package/dist/easycomponents.css +2 -0
- package/dist/src/components/Form/EasyForm.vue.d.ts +24 -0
- package/dist/src/components/Form/MenuActions.vue.d.ts +7 -0
- package/dist/src/components/Form/types/DatePicker.vue.d.ts +16 -0
- package/dist/src/components/Form/types/FileInput.vue.d.ts +16 -0
- package/dist/src/components/Form/types/Gallery.vue.d.ts +7 -0
- package/dist/src/components/Form/types/Input.vue.d.ts +12 -0
- package/dist/src/components/Form/types/MapAutoComplete.vue.d.ts +20 -0
- package/dist/src/components/Form/types/Number.vue.d.ts +12 -0
- package/dist/src/components/Form/types/Password.vue.d.ts +12 -0
- package/dist/src/components/Form/types/RangeDatePicker.vue.d.ts +16 -0
- package/dist/src/components/Form/types/Selects.vue.d.ts +16 -0
- package/dist/src/components/Form/types/SelectsAutoComplete.vue.d.ts +16 -0
- package/dist/src/components/Form/types/Switch.vue.d.ts +16 -0
- package/dist/src/components/Form/types/Tags.vue.d.ts +16 -0
- package/dist/src/components/Form/types/TextArea.vue.d.ts +12 -0
- package/dist/src/components/Form/types/map/CustomMapAutoComplete.vue.d.ts +7 -0
- package/dist/src/composables/useHelpers.d.ts +9 -0
- package/dist/src/composables/useMap.d.ts +41 -0
- package/dist/src/lang/el/form.d.ts +5 -0
- package/dist/src/lang/el/index.d.ts +7 -0
- package/dist/src/lang/en/form.d.ts +5 -0
- package/dist/src/lang/en/index.d.ts +7 -0
- package/dist/src/main.d.ts +6 -0
- package/dist/src/stores/useInfo.d.ts +7 -0
- package/dist/src/types/form.d.ts +48 -0
- package/dist/src/types/gallery.d.ts +4 -0
- package/dist/src/types/map.d.ts +32 -0
- package/dist/src/types/plugins.d.ts +14 -0
- package/dist/src/types/table.d.ts +79 -0
- package/eslint.config.ts +26 -0
- package/package.json +54 -0
- package/src/components/Form/EasyForm.vue +194 -0
- package/src/components/Form/MenuActions.vue +40 -0
- package/src/components/Form/types/DatePicker.vue +103 -0
- package/src/components/Form/types/FileInput.vue +68 -0
- package/src/components/Form/types/Gallery.vue +28 -0
- package/src/components/Form/types/Input.vue +23 -0
- package/src/components/Form/types/MapAutoComplete.vue +83 -0
- package/src/components/Form/types/Number.vue +24 -0
- package/src/components/Form/types/Password.vue +53 -0
- package/src/components/Form/types/RangeDatePicker.vue +133 -0
- package/src/components/Form/types/Selects.vue +24 -0
- package/src/components/Form/types/SelectsAutoComplete.vue +24 -0
- package/src/components/Form/types/Switch.vue +24 -0
- package/src/components/Form/types/Tags.vue +59 -0
- package/src/components/Form/types/TextArea.vue +23 -0
- package/src/components/Form/types/map/CustomMapAutoComplete.vue +83 -0
- package/src/composables/useHelpers.ts +48 -0
- package/src/composables/useMap.ts +104 -0
- package/src/lang/el/form.ts +4 -0
- package/src/lang/el/index.ts +5 -0
- package/src/lang/en/form.ts +4 -0
- package/src/lang/en/index.ts +5 -0
- package/src/main.ts +59 -0
- package/src/scss/app.scss +57 -0
- package/src/shims-scss.d.ts +3 -0
- package/src/stores/useInfo.ts +10 -0
- package/src/types/form.ts +63 -0
- package/src/types/gallery.ts +4 -0
- package/src/types/map.ts +33 -0
- package/src/types/plugins.ts +15 -0
- package/src/types/table.ts +80 -0
- package/tsconfig.json +9 -0
- package/vite.config.ts +19 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-dialog v-model="dialog" max-width="380">
|
|
3
|
+
<template #activator="{ props: activatorProps }">
|
|
4
|
+
<v-text-field
|
|
5
|
+
v-model="dateText"
|
|
6
|
+
:class="input.required ? 'required_field' : null"
|
|
7
|
+
readonly
|
|
8
|
+
:label="input.label"
|
|
9
|
+
clearable
|
|
10
|
+
:rules="input.validation && input.validation.length !== 0 ? input.validation : []"
|
|
11
|
+
v-bind="{ ...input.options, ...activatorProps }"
|
|
12
|
+
variant="underlined"
|
|
13
|
+
@click:clear="clear"
|
|
14
|
+
>
|
|
15
|
+
</v-text-field>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<v-card>
|
|
19
|
+
<v-card-text>
|
|
20
|
+
<v-date-picker v-if="isDate" v-model="date" multiple="range" />
|
|
21
|
+
<v-time-picker
|
|
22
|
+
v-if="isStartTime && input.options.enableTime"
|
|
23
|
+
v-model="startTime"
|
|
24
|
+
format="24hr"
|
|
25
|
+
></v-time-picker>
|
|
26
|
+
<v-time-picker
|
|
27
|
+
v-if="isEndTime && input.options.enableTime"
|
|
28
|
+
v-model="endTime"
|
|
29
|
+
format="24hr"
|
|
30
|
+
></v-time-picker>
|
|
31
|
+
</v-card-text>
|
|
32
|
+
<v-card-actions>
|
|
33
|
+
<v-btn @click="cancel">
|
|
34
|
+
{{ $i18n.t('form.cancel') }}
|
|
35
|
+
</v-btn>
|
|
36
|
+
<v-btn @click="getDate"> OK </v-btn>
|
|
37
|
+
</v-card-actions>
|
|
38
|
+
</v-card>
|
|
39
|
+
</v-dialog>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<script setup lang="ts">
|
|
43
|
+
import { Ref, ref, watch } from 'vue'
|
|
44
|
+
import useHelpers from '../../../composables/useHelpers'
|
|
45
|
+
import { InputDTO } from '../../../types/form'
|
|
46
|
+
import { useI18n } from 'vue-i18n'
|
|
47
|
+
|
|
48
|
+
type propsType = {
|
|
49
|
+
input: InputDTO
|
|
50
|
+
}
|
|
51
|
+
const props = defineProps<propsType>()
|
|
52
|
+
const { dateFormatter, dateTimeFormatter, timeFormatter, dateValue, dateTimeValue } = useHelpers()
|
|
53
|
+
const $i18n = useI18n()
|
|
54
|
+
const date: Ref<Date[] | string[]> = ref([])
|
|
55
|
+
const startTime: Ref<string> = ref('')
|
|
56
|
+
const endTime: Ref<string> = ref('')
|
|
57
|
+
const dateText: Ref<string> = ref('')
|
|
58
|
+
const dialog: Ref<boolean> = ref(false)
|
|
59
|
+
const isDate: Ref<boolean> = ref(true)
|
|
60
|
+
const isStartTime: Ref<boolean> = ref(false)
|
|
61
|
+
const isEndTime: Ref<boolean> = ref(false)
|
|
62
|
+
const rangeDateTimeValue = defineModel<string[]>()
|
|
63
|
+
|
|
64
|
+
watch(
|
|
65
|
+
rangeDateTimeValue,
|
|
66
|
+
(v) => {
|
|
67
|
+
if (!v) return
|
|
68
|
+
date.value = v
|
|
69
|
+
if (Array.isArray(date.value) && date.value.length > 1) {
|
|
70
|
+
const startDate = props.input.options.enableTime
|
|
71
|
+
? dateTimeFormatter(date.value[0])
|
|
72
|
+
: dateFormatter(date.value[0])
|
|
73
|
+
const endDate = props.input.options.enableTime
|
|
74
|
+
? dateTimeFormatter(date.value[date.value.length - 1])
|
|
75
|
+
: dateFormatter(date.value[date.value.length - 1])
|
|
76
|
+
dateText.value = `${startDate}~${endDate}`
|
|
77
|
+
const startDateModel = new Date(date.value[0])
|
|
78
|
+
const endDateModel = new Date(date.value[date.value.length - 1])
|
|
79
|
+
if (props.input.options.enableTime) {
|
|
80
|
+
startTime.value = timeFormatter(startDateModel)
|
|
81
|
+
endTime.value = timeFormatter(endDateModel)
|
|
82
|
+
}
|
|
83
|
+
date.value = [startDateModel, endDateModel]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{ deep: true, immediate: true }
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
const getDate = () => {
|
|
90
|
+
if (isDate.value) {
|
|
91
|
+
if (props.input.options.enableTime) {
|
|
92
|
+
isStartTime.value = true
|
|
93
|
+
isDate.value = false
|
|
94
|
+
isEndTime.value = false
|
|
95
|
+
} else {
|
|
96
|
+
dateText.value = `${dateFormatter(date.value[0])}~${dateFormatter(date.value[date.value.length - 1])}`
|
|
97
|
+
rangeDateTimeValue.value = [
|
|
98
|
+
`${dateValue(date.value[0])}`,
|
|
99
|
+
`${dateValue(date.value[date.value.length - 1])}`,
|
|
100
|
+
]
|
|
101
|
+
dialog.value = false
|
|
102
|
+
}
|
|
103
|
+
} else if (isStartTime.value && props.input.options.enableTime) {
|
|
104
|
+
isStartTime.value = false
|
|
105
|
+
isDate.value = false
|
|
106
|
+
isEndTime.value = true
|
|
107
|
+
} else if (isEndTime.value && props.input.options.enableTime) {
|
|
108
|
+
const startDateTime = `${dateValue(date.value[0])} ${startTime.value}`
|
|
109
|
+
const endDateTime = `${dateValue(date.value[date.value.length - 1])} ${endTime.value}`
|
|
110
|
+
dateText.value = `${dateTimeFormatter(startDateTime)}~${dateTimeFormatter(endDateTime)}`
|
|
111
|
+
rangeDateTimeValue.value = [
|
|
112
|
+
`${dateTimeValue(startDateTime)}`,
|
|
113
|
+
`${dateTimeValue(endDateTime)}`,
|
|
114
|
+
]
|
|
115
|
+
isDate.value = true
|
|
116
|
+
isStartTime.value = false
|
|
117
|
+
isEndTime.value = false
|
|
118
|
+
dialog.value = false
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const cancel = () => {
|
|
122
|
+
isDate.value = true
|
|
123
|
+
isStartTime.value = false
|
|
124
|
+
isEndTime.value = false
|
|
125
|
+
dialog.value = false
|
|
126
|
+
}
|
|
127
|
+
const clear = () => {
|
|
128
|
+
date.value = []
|
|
129
|
+
rangeDateTimeValue.value = []
|
|
130
|
+
}
|
|
131
|
+
</script>
|
|
132
|
+
|
|
133
|
+
<style scoped lang="scss"></style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-select
|
|
3
|
+
v-model="value"
|
|
4
|
+
:class="input.required ? 'required_field' : null"
|
|
5
|
+
:label="input.label"
|
|
6
|
+
v-bind="{ ...input.options }"
|
|
7
|
+
:rules="input.validation && input.validation.length !== 0 ? input.validation : []"
|
|
8
|
+
@update:model-value="
|
|
9
|
+
(v: string) => (typeof input.onChange === 'function' ? input.onChange(v) : null)
|
|
10
|
+
"
|
|
11
|
+
/>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { InputDTO } from '../../../types/form'
|
|
16
|
+
|
|
17
|
+
type propsType = {
|
|
18
|
+
input: InputDTO
|
|
19
|
+
}
|
|
20
|
+
defineProps<propsType>()
|
|
21
|
+
const value = defineModel<string>()
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<style scoped></style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-autocomplete
|
|
3
|
+
v-model="value"
|
|
4
|
+
:class="input.required ? 'required_field' : null"
|
|
5
|
+
:label="input.label"
|
|
6
|
+
v-bind="{ ...input.options }"
|
|
7
|
+
:rules="input.validation && input.validation.length !== 0 ? input.validation : []"
|
|
8
|
+
@update:model-value="
|
|
9
|
+
(v: string) => (typeof input.onChange === 'function' ? input.onChange(v) : null)
|
|
10
|
+
"
|
|
11
|
+
/>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { InputDTO } from '../../../types/form'
|
|
16
|
+
|
|
17
|
+
type propsType = {
|
|
18
|
+
input: InputDTO
|
|
19
|
+
}
|
|
20
|
+
defineProps<propsType>()
|
|
21
|
+
const value = defineModel<string>()
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<style scoped></style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-switch
|
|
3
|
+
v-model="value"
|
|
4
|
+
:label="input.label"
|
|
5
|
+
v-bind="{ ...input.options }"
|
|
6
|
+
color="primary"
|
|
7
|
+
hide-details
|
|
8
|
+
inset
|
|
9
|
+
:true-value="1"
|
|
10
|
+
:false-value="0"
|
|
11
|
+
/>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { InputDTO } from '../../../types/form'
|
|
16
|
+
|
|
17
|
+
type propsType = {
|
|
18
|
+
input: InputDTO
|
|
19
|
+
}
|
|
20
|
+
defineProps<propsType>()
|
|
21
|
+
const value = defineModel<number>()
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<style scoped></style>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-autocomplete
|
|
3
|
+
v-model="selectedTags"
|
|
4
|
+
v-model:search="search"
|
|
5
|
+
:items="tags"
|
|
6
|
+
:class="input.required ? 'required_field' : null"
|
|
7
|
+
:label="input.label"
|
|
8
|
+
v-bind="{ ...input.options }"
|
|
9
|
+
multiple
|
|
10
|
+
chips
|
|
11
|
+
deletable-chips
|
|
12
|
+
allow-new
|
|
13
|
+
hide-no-data
|
|
14
|
+
:rules="input.validation && input.validation.length !== 0 ? input.validation : []"
|
|
15
|
+
@update:search="onSearchChange"
|
|
16
|
+
@update:model-value="
|
|
17
|
+
(v: string[]) => (typeof input.onChange === 'function' ? input.onChange(v) : null)
|
|
18
|
+
"
|
|
19
|
+
>
|
|
20
|
+
<!-- Custom Chip Rendering -->
|
|
21
|
+
<template #chip="{ item, index }">
|
|
22
|
+
<v-chip :closable="true" @click:close="removeTag(index)">
|
|
23
|
+
{{ item }}
|
|
24
|
+
</v-chip>
|
|
25
|
+
</template>
|
|
26
|
+
</v-autocomplete>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
import { Ref, ref } from 'vue'
|
|
31
|
+
import { InputDTO } from '../../../types/form'
|
|
32
|
+
|
|
33
|
+
type propsType = {
|
|
34
|
+
input: InputDTO
|
|
35
|
+
}
|
|
36
|
+
defineProps<propsType>()
|
|
37
|
+
const tags: Ref<string[]> = ref([])
|
|
38
|
+
const search: Ref<string> = ref('')
|
|
39
|
+
const selectedTags = defineModel<string[]>()
|
|
40
|
+
|
|
41
|
+
const removeTag = (index: number) => {
|
|
42
|
+
selectedTags.value?.splice(index, 1)
|
|
43
|
+
}
|
|
44
|
+
const onSearchChange = (value: string) => {
|
|
45
|
+
if (value.includes(',')) {
|
|
46
|
+
const newTag = value.replace(',', '').trim()
|
|
47
|
+
if (newTag && !tags.value.includes(newTag)) {
|
|
48
|
+
tags.value.push(newTag)
|
|
49
|
+
selectedTags.value?.push(newTag)
|
|
50
|
+
}
|
|
51
|
+
if (newTag && !selectedTags.value?.includes(newTag)) {
|
|
52
|
+
selectedTags.value?.push(newTag)
|
|
53
|
+
}
|
|
54
|
+
search.value = ''
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<style scoped></style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-textarea
|
|
3
|
+
v-model="value"
|
|
4
|
+
:class="input.required ? 'required_field' : null"
|
|
5
|
+
:label="input.label"
|
|
6
|
+
v-bind="{ ...input.options }"
|
|
7
|
+
:rules="input.validation && input.validation.length !== 0 ? input.validation : []"
|
|
8
|
+
@keyup.enter="emit('submit')"
|
|
9
|
+
/>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup lang="ts">
|
|
13
|
+
import { InputDTO } from '../../../types/form'
|
|
14
|
+
|
|
15
|
+
type propsType = {
|
|
16
|
+
input: InputDTO
|
|
17
|
+
}
|
|
18
|
+
defineProps<propsType>()
|
|
19
|
+
const value = defineModel<string>()
|
|
20
|
+
const emit = defineEmits(['submit'])
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<style scoped></style>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-autocomplete
|
|
3
|
+
v-model:search="searchValue"
|
|
4
|
+
:class="$attrs.class"
|
|
5
|
+
:label="label"
|
|
6
|
+
:items="items"
|
|
7
|
+
clearable
|
|
8
|
+
:loading="loading"
|
|
9
|
+
@keydown.enter="search"
|
|
10
|
+
@update:model-value="change"
|
|
11
|
+
@click:clear="clear"
|
|
12
|
+
>
|
|
13
|
+
<template #append-inner>
|
|
14
|
+
<v-btn elevation="0" @click="search">
|
|
15
|
+
<i class="icon-search" style="color: #282828" />
|
|
16
|
+
</v-btn>
|
|
17
|
+
</template>
|
|
18
|
+
</v-autocomplete>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
import { ref } from 'vue'
|
|
23
|
+
type Item = {
|
|
24
|
+
title: string
|
|
25
|
+
value: string
|
|
26
|
+
}
|
|
27
|
+
type propsType = {
|
|
28
|
+
label: string
|
|
29
|
+
getPlaces?: any
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const props = defineProps<propsType>()
|
|
33
|
+
const emit = defineEmits(['place_changed'])
|
|
34
|
+
const searchValue = ref<string>('')
|
|
35
|
+
const items = ref<Item[]>([])
|
|
36
|
+
const loading = ref<boolean>(false)
|
|
37
|
+
|
|
38
|
+
const clear = () => {
|
|
39
|
+
searchValue.value = ''
|
|
40
|
+
items.value = []
|
|
41
|
+
}
|
|
42
|
+
const change = async (place_id: string) => {
|
|
43
|
+
if (!place_id) return
|
|
44
|
+
if (!props.getPlaces) return
|
|
45
|
+
|
|
46
|
+
loading.value = true
|
|
47
|
+
const places = await props.getPlaces(place_id)
|
|
48
|
+
emit('place_changed', places)
|
|
49
|
+
loading.value = false
|
|
50
|
+
}
|
|
51
|
+
const search = async () => {
|
|
52
|
+
if (!searchValue.value) return
|
|
53
|
+
|
|
54
|
+
const request = {
|
|
55
|
+
input: searchValue.value,
|
|
56
|
+
includedRegionCodes: ['gr', 'en'],
|
|
57
|
+
}
|
|
58
|
+
const data: Item[] = []
|
|
59
|
+
loading.value = true
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const { suggestions } =
|
|
63
|
+
await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(request)
|
|
64
|
+
|
|
65
|
+
suggestions.forEach((suggestion) => {
|
|
66
|
+
if (suggestion.placePrediction) {
|
|
67
|
+
data.push({
|
|
68
|
+
title: suggestion.placePrediction.text.toString(),
|
|
69
|
+
value: suggestion.placePrediction.placeId,
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
items.value = JSON.parse(JSON.stringify(data))
|
|
74
|
+
} catch (e) {
|
|
75
|
+
console.error(e)
|
|
76
|
+
} finally {
|
|
77
|
+
loading.value = false
|
|
78
|
+
searchValue.value = ''
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<style scoped lang="scss"></style>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import moment from 'moment-timezone'
|
|
2
|
+
import { useInfo } from '../stores/useInfo'
|
|
3
|
+
|
|
4
|
+
export default function useHelpers() {
|
|
5
|
+
const nowFormatter = () => {
|
|
6
|
+
const timeZone = useInfo().timeZone
|
|
7
|
+
const tz = moment.tz(timeZone)
|
|
8
|
+
return tz.format('LLLL')
|
|
9
|
+
}
|
|
10
|
+
const nowValue = () => {
|
|
11
|
+
const timeZone = useInfo().timeZone
|
|
12
|
+
const tz = moment.tz(timeZone)
|
|
13
|
+
return tz.format('yyyy-MM-DDTHH:mm:ss')
|
|
14
|
+
}
|
|
15
|
+
const dateTimeFormatter = (dateTime: string | Date) => {
|
|
16
|
+
const timeZone = useInfo().timeZone
|
|
17
|
+
const tz = moment.tz(dateTime, timeZone)
|
|
18
|
+
return tz.format('LLLL')
|
|
19
|
+
}
|
|
20
|
+
const dateFormatter = (date: string | Date) => {
|
|
21
|
+
const timeZone = useInfo().timeZone
|
|
22
|
+
const tz = moment.tz(date, timeZone)
|
|
23
|
+
return tz.format('LL')
|
|
24
|
+
}
|
|
25
|
+
const timeFormatter = (value: string | Date) => {
|
|
26
|
+
const timeZone = useInfo().timeZone
|
|
27
|
+
const theTime = moment.tz(value, timeZone)
|
|
28
|
+
return theTime.format('HH:mm')
|
|
29
|
+
}
|
|
30
|
+
const dateValue = (date: string | Date) => {
|
|
31
|
+
const tz = moment.tz(date, useInfo().timeZone)
|
|
32
|
+
return tz.format('YYYY-MM-DD')
|
|
33
|
+
}
|
|
34
|
+
const dateTimeValue = (date: string | Date) => {
|
|
35
|
+
const tz = moment.tz(date, useInfo().timeZone)
|
|
36
|
+
return tz.format('YYYY-MM-DDTHH:mm:ss')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
nowFormatter,
|
|
41
|
+
nowValue,
|
|
42
|
+
dateFormatter,
|
|
43
|
+
dateTimeFormatter,
|
|
44
|
+
dateValue,
|
|
45
|
+
dateTimeValue,
|
|
46
|
+
timeFormatter,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { ComponentPublicInstance, onBeforeMount, onBeforeUnmount, ref } from 'vue'
|
|
2
|
+
import { DocumentWithFullscreen, MapDTO, MapOptions } from '../types/map'
|
|
3
|
+
|
|
4
|
+
export default function useMap() {
|
|
5
|
+
const map = ref<MapDTO | null>(null)
|
|
6
|
+
const mapOptions = ref<MapOptions>({
|
|
7
|
+
zoomControl: true,
|
|
8
|
+
mapTypeControl: false,
|
|
9
|
+
scaleControl: true,
|
|
10
|
+
streetViewControl: true,
|
|
11
|
+
rotateControl: false,
|
|
12
|
+
fullscreenControl: false,
|
|
13
|
+
disableDefaultUi: false,
|
|
14
|
+
styles: [
|
|
15
|
+
{
|
|
16
|
+
featureType: 'poi',
|
|
17
|
+
stylers: [
|
|
18
|
+
{
|
|
19
|
+
visibility: 'off',
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
featureType: 'transit',
|
|
25
|
+
stylers: [
|
|
26
|
+
{
|
|
27
|
+
visibility: 'off',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
zoom: 18,
|
|
33
|
+
key: 0,
|
|
34
|
+
})
|
|
35
|
+
const fullScreenButtonKey = ref<number>(0)
|
|
36
|
+
|
|
37
|
+
const addMap = (mapRef: ComponentPublicInstance, cardMapRef: ComponentPublicInstance) => {
|
|
38
|
+
map.value = {
|
|
39
|
+
cardMapRef: cardMapRef,
|
|
40
|
+
mapRef: mapRef,
|
|
41
|
+
isFullScreen: false,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const toggleFullscreen = async () => {
|
|
45
|
+
if (!map.value) return
|
|
46
|
+
const el: DocumentWithFullscreen = document as DocumentWithFullscreen
|
|
47
|
+
if (!el.fullscreenElement) {
|
|
48
|
+
if (typeof map.value.cardMapRef.$el.requestFullscreen === 'function') {
|
|
49
|
+
await map.value.cardMapRef.$el.requestFullscreen()
|
|
50
|
+
} else if (typeof map.value.cardMapRef.$el.mozRequestFullScreen === 'function') {
|
|
51
|
+
// Firefox
|
|
52
|
+
await map.value.cardMapRef.$el.mozRequestFullScreen()
|
|
53
|
+
} else if (typeof map.value.cardMapRef.$el.webkitRequestFullscreen === 'function') {
|
|
54
|
+
// Chrome, Safari, and Opera
|
|
55
|
+
await map.value.cardMapRef.$el.webkitRequestFullscreen()
|
|
56
|
+
} else if (typeof map.value.cardMapRef.$el.msRequestFullscreen === 'function') {
|
|
57
|
+
// IE/Edge
|
|
58
|
+
await map.value.cardMapRef.$el.msRequestFullscreen()
|
|
59
|
+
}
|
|
60
|
+
map.value.isFullScreen = true
|
|
61
|
+
} else {
|
|
62
|
+
if (typeof el.exitFullscreen === 'function') {
|
|
63
|
+
await document.exitFullscreen()
|
|
64
|
+
} else if (typeof el.mozCancelFullScreen === 'function') {
|
|
65
|
+
// Firefox
|
|
66
|
+
el.mozCancelFullScreen()
|
|
67
|
+
} else if (typeof el.webkitExitFullscreen === 'function') {
|
|
68
|
+
// Chrome, Safari, and Opera
|
|
69
|
+
el.webkitExitFullscreen()
|
|
70
|
+
} else if (typeof el.msExitFullscreen === 'function') {
|
|
71
|
+
// IE/Edge
|
|
72
|
+
el.msExitFullscreen()
|
|
73
|
+
}
|
|
74
|
+
map.value.isFullScreen = false
|
|
75
|
+
}
|
|
76
|
+
fullScreenButtonKey.value++
|
|
77
|
+
}
|
|
78
|
+
const isFullScreen = () => {
|
|
79
|
+
if (!map.value) return
|
|
80
|
+
return map.value.isFullScreen
|
|
81
|
+
}
|
|
82
|
+
const onFullscreenChange = () => {
|
|
83
|
+
if (!map.value) return
|
|
84
|
+
const el: DocumentWithFullscreen = document as DocumentWithFullscreen
|
|
85
|
+
map.value.isFullScreen = !!el.fullscreenElement
|
|
86
|
+
fullScreenButtonKey.value++
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
onBeforeMount(() => {
|
|
90
|
+
window.addEventListener('fullscreenchange', onFullscreenChange)
|
|
91
|
+
})
|
|
92
|
+
onBeforeUnmount(() => {
|
|
93
|
+
window.removeEventListener('fullscreenchange', onFullscreenChange)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
mapOptions,
|
|
98
|
+
fullScreenButtonKey,
|
|
99
|
+
|
|
100
|
+
addMap,
|
|
101
|
+
toggleFullscreen,
|
|
102
|
+
isFullScreen,
|
|
103
|
+
}
|
|
104
|
+
}
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { App } from 'vue'
|
|
2
|
+
import { en, el } from 'vuetify/locale'
|
|
3
|
+
import { pluginsPropertiesDTO } from './types/plugins'
|
|
4
|
+
import { createVuetify } from 'vuetify/framework'
|
|
5
|
+
import * as components from 'vuetify/components'
|
|
6
|
+
import * as directives from 'vuetify/directives'
|
|
7
|
+
import { VFileUpload } from 'vuetify/labs/components'
|
|
8
|
+
import { createI18n } from 'vue-i18n'
|
|
9
|
+
import langEn from '../src/lang/en'
|
|
10
|
+
import langEl from '../src/lang/el'
|
|
11
|
+
import { createPinia } from 'pinia'
|
|
12
|
+
import { useInfo } from './stores/useInfo'
|
|
13
|
+
import EasyForm from './components/Form/EasyForm.vue'
|
|
14
|
+
import './scss/app.scss'
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
install(app: App, props: pluginsPropertiesDTO) {
|
|
18
|
+
useInfo().timeZone = props.timeZone
|
|
19
|
+
const vuetify = createVuetify({
|
|
20
|
+
components: {
|
|
21
|
+
...components,
|
|
22
|
+
VFileUpload,
|
|
23
|
+
},
|
|
24
|
+
directives,
|
|
25
|
+
defaults: {},
|
|
26
|
+
theme: {
|
|
27
|
+
defaultTheme: 'customTheme',
|
|
28
|
+
themes: {
|
|
29
|
+
customTheme: {
|
|
30
|
+
colors: props.colors,
|
|
31
|
+
variables: {
|
|
32
|
+
'font-family': props.fontFamily,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
locale: {
|
|
38
|
+
locale: props.locale,
|
|
39
|
+
fallback: props.locale,
|
|
40
|
+
messages: {
|
|
41
|
+
en: { ...en },
|
|
42
|
+
el: { ...el },
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
const i18n = createI18n({
|
|
47
|
+
legacy: false,
|
|
48
|
+
locale: props.locale ?? 'en',
|
|
49
|
+
messages: {
|
|
50
|
+
en: langEn,
|
|
51
|
+
el: langEl,
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
app.use(createPinia())
|
|
55
|
+
app.use(vuetify)
|
|
56
|
+
app.use(i18n)
|
|
57
|
+
app.component('EasyForm', EasyForm)
|
|
58
|
+
},
|
|
59
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
@use 'vuetify/styles';
|
|
2
|
+
@import "../../node_modules/lucide-static/font/lucide.css";
|
|
3
|
+
@import "../../node_modules/@mdi/font/css/materialdesignicons.min.css";
|
|
4
|
+
|
|
5
|
+
.mainform {
|
|
6
|
+
.required_field label:after{
|
|
7
|
+
color: red;
|
|
8
|
+
content: ' *';
|
|
9
|
+
display:inline;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.cardMap{
|
|
14
|
+
&:fullscreen{
|
|
15
|
+
.vue-map-container{
|
|
16
|
+
height: 100% !important;
|
|
17
|
+
}
|
|
18
|
+
.vue-map{
|
|
19
|
+
height: 100% !important;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.v-progress-linear--active{
|
|
24
|
+
height: 6px !important;
|
|
25
|
+
}
|
|
26
|
+
.fullscreen_btn{
|
|
27
|
+
position: absolute;
|
|
28
|
+
top: 5px;
|
|
29
|
+
right: 10px;
|
|
30
|
+
color: #595959 !important;
|
|
31
|
+
background: #fff !important;
|
|
32
|
+
box-shadow: none !important;
|
|
33
|
+
|
|
34
|
+
&:hover, &:focus{
|
|
35
|
+
color: #595959 !important;
|
|
36
|
+
background: #fff !important;
|
|
37
|
+
box-shadow: none !important;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
i{
|
|
41
|
+
font-size: 20px;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.v-carousel{
|
|
47
|
+
.v-carousel-item{
|
|
48
|
+
.delete_btn{
|
|
49
|
+
right: 0;
|
|
50
|
+
position: absolute;
|
|
51
|
+
border-radius: 0;
|
|
52
|
+
}
|
|
53
|
+
img{
|
|
54
|
+
background: #242424;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|