@dargmuesli/nuxt-vio 5.0.2 โ 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/components/vio/_/VioApp.vue +3 -7
- package/components/vio/_/VioError.vue +3 -2
- package/components/vio/form/input/VioFormInput.vue +25 -11
- package/components/vio/form/input/VioFormInputEmailAddress.vue +65 -0
- package/composables/useHeadDefault.ts +2 -3
- package/locales/de.json +3 -0
- package/locales/en.json +3 -0
- package/package.json +10 -10
- package/plugins/siteConfig.ts +7 -0
- package/tailwind.config.ts +3 -3
- package/utils/constants.ts +0 -1
- package/utils/form.ts +13 -12
@@ -2,7 +2,7 @@
|
|
2
2
|
<div :data-is-loading="isLoading" data-testid="is-loading">
|
3
3
|
<NuxtLayout>
|
4
4
|
<!-- `NuxtLayout` can't have mulitple child nodes (https://github.com/nuxt/nuxt/issues/21759) -->
|
5
|
-
<NuxtPage
|
5
|
+
<NuxtPage />
|
6
6
|
</NuxtLayout>
|
7
7
|
</div>
|
8
8
|
</template>
|
@@ -11,18 +11,17 @@
|
|
11
11
|
export interface Props {
|
12
12
|
ogImageAlt: string
|
13
13
|
ogImageComponent?: string
|
14
|
-
siteDescription: string
|
15
14
|
}
|
16
15
|
const props = withDefaults(defineProps<Props>(), {
|
17
16
|
ogImageComponent: undefined,
|
18
17
|
})
|
19
18
|
const ogImageAltProp = toRef(() => props.ogImageAlt)
|
20
19
|
const ogImageComponentProp = toRef(() => props.ogImageComponent)
|
21
|
-
const siteDescriptionProp = toRef(() => props.siteDescription)
|
22
20
|
|
23
21
|
const { $dayjs } = useNuxtApp()
|
24
22
|
const { locale } = useI18n()
|
25
23
|
const cookieControl = useCookieControl()
|
24
|
+
const siteConfig = useSiteConfig()
|
26
25
|
|
27
26
|
const { loadingIds, indicateLoadingDone } = useLoadingDoneIndicator('app')
|
28
27
|
|
@@ -61,9 +60,6 @@ watch(
|
|
61
60
|
)
|
62
61
|
|
63
62
|
// initialization
|
64
|
-
updateSiteConfig({
|
65
|
-
description: siteDescriptionProp.value,
|
66
|
-
})
|
67
63
|
defineOgImage({
|
68
64
|
alt: ogImageAltProp.value,
|
69
65
|
component: ogImageComponentProp.value,
|
@@ -73,7 +69,7 @@ useFavicons()
|
|
73
69
|
usePolyfills()
|
74
70
|
useSchemaOrg([
|
75
71
|
defineWebSite({
|
76
|
-
description:
|
72
|
+
description: siteConfig.description,
|
77
73
|
}),
|
78
74
|
])
|
79
75
|
init()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<template>
|
2
2
|
<div>
|
3
|
-
<h1>{{ `${statusCode} - ${statusReason}` }}</h1>
|
3
|
+
<h1>{{ `${statusCode ? `${statusCode} - ` : ''}${statusReason}` }}</h1>
|
4
4
|
<div>
|
5
5
|
{{ description }}
|
6
6
|
</div>
|
@@ -15,12 +15,13 @@
|
|
15
15
|
import { status } from '@http-util/status-i18n'
|
16
16
|
|
17
17
|
export interface Props {
|
18
|
-
statusCode
|
18
|
+
statusCode?: number
|
19
19
|
statusMessage?: string
|
20
20
|
description: string
|
21
21
|
stack?: string
|
22
22
|
}
|
23
23
|
const props = withDefaults(defineProps<Props>(), {
|
24
|
+
statusCode: undefined,
|
24
25
|
statusMessage: undefined,
|
25
26
|
stack: undefined,
|
26
27
|
})
|
@@ -16,7 +16,7 @@
|
|
16
16
|
'form-input-warning': warning,
|
17
17
|
'form-input-error': value?.$error,
|
18
18
|
}"
|
19
|
-
:for="
|
19
|
+
:for="idLabelFull"
|
20
20
|
>
|
21
21
|
<span>{{ title }}</span>
|
22
22
|
<span
|
@@ -36,7 +36,7 @@
|
|
36
36
|
<slot v-if="$slots.default" />
|
37
37
|
<input
|
38
38
|
v-else
|
39
|
-
:id="
|
39
|
+
:id="idLabelFull"
|
40
40
|
class="form-input"
|
41
41
|
:class="{
|
42
42
|
'rounded-r-none': $slots.icon,
|
@@ -58,14 +58,14 @@
|
|
58
58
|
</VioFormInputIconWrapper>
|
59
59
|
<VioFormInputIconWrapper
|
60
60
|
v-else-if="
|
61
|
-
validationProperty.$model && !validationProperty.$invalid
|
61
|
+
!!validationProperty.$model && !validationProperty.$invalid
|
62
62
|
"
|
63
63
|
>
|
64
64
|
<VioIconCheckCircle class="text-green-600" :title="t('valid')" />
|
65
65
|
</VioFormInputIconWrapper>
|
66
66
|
<VioFormInputIconWrapper
|
67
67
|
v-else-if="
|
68
|
-
validationProperty.$model && validationProperty.$invalid
|
68
|
+
!!validationProperty.$model && validationProperty.$invalid
|
69
69
|
"
|
70
70
|
>
|
71
71
|
<VioIconExclamationCircle
|
@@ -84,6 +84,10 @@
|
|
84
84
|
</span>
|
85
85
|
</div>
|
86
86
|
<div class="md:w-1/3" />
|
87
|
+
<div class="md:w-2/3">
|
88
|
+
<slot name="inputSuffix" />
|
89
|
+
</div>
|
90
|
+
<div class="md:w-1/3" />
|
87
91
|
<div class="md:w-2/3">
|
88
92
|
<slot name="stateSuccess" />
|
89
93
|
</div>
|
@@ -102,6 +106,10 @@
|
|
102
106
|
<div class="md:w-2/3">
|
103
107
|
<slot name="stateError" />
|
104
108
|
</div>
|
109
|
+
<div class="md:w-1/3" />
|
110
|
+
<div class="md:w-2/3">
|
111
|
+
<slot name="assistance" />
|
112
|
+
</div>
|
105
113
|
</div>
|
106
114
|
</div>
|
107
115
|
</template>
|
@@ -119,7 +127,7 @@ export interface Props {
|
|
119
127
|
idLabel?: string
|
120
128
|
placeholder?: string
|
121
129
|
success?: boolean
|
122
|
-
title
|
130
|
+
title: string
|
123
131
|
type?: string
|
124
132
|
validationProperty?: BaseValidation
|
125
133
|
value?: BaseValidation
|
@@ -135,14 +143,12 @@ const props = withDefaults(defineProps<Props>(), {
|
|
135
143
|
idLabel: undefined,
|
136
144
|
placeholder: undefined,
|
137
145
|
success: false,
|
138
|
-
title: undefined,
|
139
146
|
type: undefined,
|
140
147
|
validationProperty: undefined,
|
141
148
|
value: undefined,
|
142
149
|
valueFormatter: (x?: string) => x,
|
143
150
|
warning: false,
|
144
151
|
})
|
145
|
-
const typeProp = toRef(() => props.type)
|
146
152
|
|
147
153
|
const emit = defineEmits<{
|
148
154
|
icon: []
|
@@ -151,11 +157,19 @@ const emit = defineEmits<{
|
|
151
157
|
}>()
|
152
158
|
|
153
159
|
const { t } = useI18n()
|
160
|
+
const runtimeConfig = useRuntimeConfig()
|
161
|
+
|
162
|
+
// data
|
163
|
+
const idLabelFull = props.idLabel
|
164
|
+
? `maevsi-${runtimeConfig.public.vio.isInProduction ? 'prod' : 'dev'}-${
|
165
|
+
props.idLabel
|
166
|
+
}`
|
167
|
+
: undefined
|
154
168
|
|
155
169
|
// initialization
|
156
170
|
if (
|
157
171
|
!props.placeholder &&
|
158
|
-
|
172
|
+
props.type &&
|
159
173
|
![
|
160
174
|
'checkbox',
|
161
175
|
'datetime-local',
|
@@ -164,15 +178,15 @@ if (
|
|
164
178
|
'textarea',
|
165
179
|
'tiptap',
|
166
180
|
'radio',
|
167
|
-
].includes(
|
181
|
+
].includes(props.type)
|
168
182
|
) {
|
169
183
|
consola.warn(`placeholder is missing for ${props.idLabel}!`)
|
170
184
|
}
|
171
185
|
|
172
186
|
if (
|
173
187
|
!props.value &&
|
174
|
-
|
175
|
-
!['checkbox', 'select'].includes(
|
188
|
+
props.type &&
|
189
|
+
!['checkbox', 'select'].includes(props.type)
|
176
190
|
) {
|
177
191
|
consola.warn(`value is missing for ${props.idLabel}!`)
|
178
192
|
}
|
@@ -0,0 +1,65 @@
|
|
1
|
+
<template>
|
2
|
+
<VioFormInput
|
3
|
+
v-if="formInput"
|
4
|
+
:is-optional="isOptional"
|
5
|
+
:id-label="`input-${id}`"
|
6
|
+
:placeholder="t('globalPlaceholderEmailAddress')"
|
7
|
+
:title="title || t('emailAddress')"
|
8
|
+
type="email"
|
9
|
+
:value="formInput"
|
10
|
+
@input="emit('input', $event)"
|
11
|
+
>
|
12
|
+
<template #stateError>
|
13
|
+
<VioFormInputStateError
|
14
|
+
:form-input="formInput"
|
15
|
+
validation-property="email"
|
16
|
+
>
|
17
|
+
{{ t('globalValidationFormat') }}
|
18
|
+
</VioFormInputStateError>
|
19
|
+
<VioFormInputStateError
|
20
|
+
:form-input="formInput"
|
21
|
+
validation-property="lengthMax"
|
22
|
+
>
|
23
|
+
{{ t('globalValidationLength') }}
|
24
|
+
</VioFormInputStateError>
|
25
|
+
<VioFormInputStateError
|
26
|
+
v-if="isRequired"
|
27
|
+
:form-input="formInput"
|
28
|
+
validation-property="required"
|
29
|
+
>
|
30
|
+
{{ t('globalValidationRequired') }}
|
31
|
+
</VioFormInputStateError>
|
32
|
+
</template>
|
33
|
+
</VioFormInput>
|
34
|
+
</template>
|
35
|
+
|
36
|
+
<script setup lang="ts">
|
37
|
+
import type { BaseValidation } from '@vuelidate/core'
|
38
|
+
|
39
|
+
export interface Props {
|
40
|
+
formInput: BaseValidation
|
41
|
+
id?: string
|
42
|
+
isOptional?: boolean
|
43
|
+
isRequired?: boolean
|
44
|
+
title?: string
|
45
|
+
}
|
46
|
+
withDefaults(defineProps<Props>(), {
|
47
|
+
id: 'email-address',
|
48
|
+
isOptional: false,
|
49
|
+
isRequired: false,
|
50
|
+
title: undefined,
|
51
|
+
})
|
52
|
+
|
53
|
+
const emit = defineEmits<{
|
54
|
+
input: [event: string]
|
55
|
+
}>()
|
56
|
+
|
57
|
+
const { t } = useI18n()
|
58
|
+
</script>
|
59
|
+
|
60
|
+
<i18n lang="yaml">
|
61
|
+
de:
|
62
|
+
emailAddress: E-Mail-Adresse
|
63
|
+
en:
|
64
|
+
emailAddress: Email address
|
65
|
+
</i18n>
|
@@ -8,14 +8,13 @@ export const useHeadDefault = ({
|
|
8
8
|
extension?: UseSeoMetaInput
|
9
9
|
title: string | ComputedRef<string>
|
10
10
|
}) => {
|
11
|
-
const attrs = useAttrs()
|
12
11
|
const siteConfig = useSiteConfig()
|
13
12
|
|
14
13
|
const defaults: UseSeoMetaInput = {
|
15
|
-
description:
|
14
|
+
description: siteConfig.description,
|
16
15
|
msapplicationConfig: `/assets/static/favicon/browserconfig.xml?v=${CACHE_VERSION}`,
|
17
16
|
title,
|
18
|
-
twitterDescription:
|
17
|
+
twitterDescription: siteConfig.description,
|
19
18
|
twitterTitle: ref(
|
20
19
|
TITLE_TEMPLATE({
|
21
20
|
siteName: siteConfig.name,
|
package/locales/de.json
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
{
|
2
|
+
"globalPlaceholderEmailAddress": "e-mail{'@'}adres.se",
|
2
3
|
"globalPlaceholderUrl": "https://websei.te",
|
4
|
+
"globalSeoSiteDescription": "Vio ist {'@'}dargmueslis Nuxt layer.",
|
3
5
|
"globalStatusError": "Fehler",
|
4
6
|
"globalStatusLoading": "Lade...",
|
5
7
|
"globalValidationFailed": "Bitte รผberprรผfe deine Eingaben ๐",
|
8
|
+
"globalValidationFormat": "Falsches Format",
|
6
9
|
"globalValidationFormatIncorrect": "Falsches Format",
|
7
10
|
"globalValidationFormatUrlHttps": "Muss mit \"https://\" beginnen",
|
8
11
|
"globalValidationLength": "Zu lang",
|
package/locales/en.json
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
{
|
2
|
+
"globalPlaceholderEmailAddress": "email{'@'}addre.ss",
|
2
3
|
"globalPlaceholderUrl": "https://websi.te",
|
4
|
+
"globalSeoSiteDescription": "Vio is {'@'}dargmuesli's Nuxt layer.",
|
3
5
|
"globalStatusError": "Error",
|
4
6
|
"globalStatusLoading": "Loading...",
|
5
7
|
"globalValidationFailed": "Please check your input ๐",
|
8
|
+
"globalValidationFormat": "Incorrect format",
|
6
9
|
"globalValidationFormatIncorrect": "Incorrect format",
|
7
10
|
"globalValidationFormatUrlHttps": "Must start with \"https://\"",
|
8
11
|
"globalValidationLength": "Too long",
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@dargmuesli/nuxt-vio",
|
3
|
-
"version": "
|
3
|
+
"version": "7.0.0",
|
4
4
|
"repository": {
|
5
5
|
"type": "git",
|
6
6
|
"url": "git+https://github.com/dargmuesli/vio.git"
|
@@ -75,9 +75,9 @@
|
|
75
75
|
"@nuxtjs/html-validator": "1.5.2",
|
76
76
|
"@nuxtjs/i18n": "8.0.0-rc.4",
|
77
77
|
"@nuxtjs/tailwindcss": "6.8.0",
|
78
|
-
"@nuxtseo/module": "2.0.0-beta.
|
78
|
+
"@nuxtseo/module": "2.0.0-beta.30",
|
79
79
|
"@pinia/nuxt": "0.4.11",
|
80
|
-
"@playwright/test": "1.
|
80
|
+
"@playwright/test": "1.38.0",
|
81
81
|
"@tailwindcss/forms": "0.5.6",
|
82
82
|
"@tailwindcss/typography": "0.5.10",
|
83
83
|
"@types/cookie": "0.5.2",
|
@@ -92,33 +92,33 @@
|
|
92
92
|
"cookie": "0.5.0",
|
93
93
|
"cross-env": "7.0.3",
|
94
94
|
"dayjs": "2.0.0-alpha.4",
|
95
|
+
"eslint": "8.49.0",
|
95
96
|
"eslint-config-prettier": "9.0.0",
|
96
97
|
"eslint-plugin-compat": "4.2.0",
|
97
98
|
"eslint-plugin-nuxt": "4.0.0",
|
98
99
|
"eslint-plugin-prettier": "5.0.0",
|
99
100
|
"eslint-plugin-yml": "1.9.0",
|
100
|
-
"eslint": "8.49.0",
|
101
101
|
"is-https": "4.0.0",
|
102
102
|
"jiti": "1.20.0",
|
103
103
|
"jose": "4.14.6",
|
104
104
|
"lint-staged": "14.0.1",
|
105
105
|
"lodash-es": "4.17.21",
|
106
|
-
"nuxt": "3.7.
|
106
|
+
"nuxt": "3.7.3",
|
107
107
|
"pinia": "2.1.6",
|
108
|
-
"prettier-plugin-tailwindcss": "0.5.4",
|
109
108
|
"prettier": "3.0.3",
|
109
|
+
"prettier-plugin-tailwindcss": "0.5.4",
|
110
110
|
"serve": "14.2.1",
|
111
|
+
"stylelint": "15.10.3",
|
111
112
|
"stylelint-config-recommended-vue": "1.5.0",
|
112
113
|
"stylelint-config-standard": "34.0.0",
|
113
114
|
"stylelint-no-unsupported-browser-features": "7.0.0",
|
114
|
-
"stylelint": "15.10.3",
|
115
115
|
"sweetalert2": "11.7.27",
|
116
116
|
"tailwindcss": "3.3.3",
|
117
|
+
"vue": "3.3.4",
|
117
118
|
"vue-gtag": "2.0.1",
|
118
|
-
"vue-tsc": "1.8.11"
|
119
|
-
"vue": "3.3.4"
|
119
|
+
"vue-tsc": "1.8.11"
|
120
120
|
},
|
121
121
|
"peerDependencies": {
|
122
|
-
"playwright-core": "1.
|
122
|
+
"playwright-core": "1.38.0"
|
123
123
|
}
|
124
124
|
}
|
package/tailwind.config.ts
CHANGED
@@ -136,17 +136,17 @@ export default {
|
|
136
136
|
},
|
137
137
|
},
|
138
138
|
'.form-input-error': {
|
139
|
-
input: {
|
139
|
+
'.form-input': {
|
140
140
|
borderColor: theme('colors.red.500'),
|
141
141
|
},
|
142
142
|
},
|
143
143
|
'.form-input-success': {
|
144
|
-
input: {
|
144
|
+
'.form-input': {
|
145
145
|
borderColor: theme('colors.green.600'),
|
146
146
|
},
|
147
147
|
},
|
148
148
|
'.form-input-warning': {
|
149
|
-
input: {
|
149
|
+
'.form-input': {
|
150
150
|
borderColor: theme('colors.yellow.600'),
|
151
151
|
},
|
152
152
|
},
|
package/utils/constants.ts
CHANGED
@@ -49,7 +49,6 @@ export const TITLE_TEMPLATE = ({
|
|
49
49
|
siteName: string
|
50
50
|
title?: string
|
51
51
|
}) => (title && title !== siteName ? `${title} ยท ${siteName}` : siteName)
|
52
|
-
export const VALIDATION_SUGGESTION_TITLE_LENGTH_MAXIMUM = 300
|
53
52
|
export const VERIFICATION_FORMAT_UUID = helpers.regex(REGEX_UUID)
|
54
53
|
export const VIO_NUXT_BASE_CONFIG = ({
|
55
54
|
defaultLocale,
|
package/utils/form.ts
CHANGED
@@ -1,19 +1,20 @@
|
|
1
|
-
import
|
1
|
+
import { consola } from 'consola'
|
2
2
|
|
3
|
-
export const
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
export const isFormValid = async ({
|
4
|
+
v$,
|
5
|
+
isFormSent,
|
6
|
+
}: {
|
7
|
+
v$: any
|
8
|
+
isFormSent: Ref<boolean>
|
9
|
+
}): Promise<boolean> => {
|
9
10
|
v$.value.$touch()
|
10
11
|
|
11
|
-
const
|
12
|
-
isFormSent.value =
|
12
|
+
const isValid = await v$.value.$validate()
|
13
|
+
isFormSent.value = isValid
|
13
14
|
|
14
|
-
if (!
|
15
|
-
|
15
|
+
if (!isValid) {
|
16
|
+
consola.error('Form in invalid!')
|
16
17
|
}
|
17
18
|
|
18
|
-
return
|
19
|
+
return isValid
|
19
20
|
}
|