@codecavepro/brand 3.2.3 → 3.2.5
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.
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
2
|
+
import { nextTick, onMounted, ref, watch } from 'vue'
|
|
3
|
+
import gsap from 'gsap'
|
|
4
|
+
import { SplitText } from 'gsap/SplitText'
|
|
5
5
|
|
|
6
6
|
const props = defineProps<{
|
|
7
7
|
text1: string
|
|
8
8
|
text2: string
|
|
9
9
|
}>()
|
|
10
10
|
|
|
11
|
+
const typingEffectContainer = ref<HTMLElement | null>(null)
|
|
11
12
|
const splitAnimation = () => {
|
|
13
|
+
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!typingEffectContainer.value) {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
|
|
12
21
|
gsap.registerPlugin(SplitText)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
22
|
+
|
|
23
|
+
const split = SplitText.create(
|
|
24
|
+
typingEffectContainer.value.querySelectorAll('.split-text span'),
|
|
25
|
+
{
|
|
26
|
+
type: 'words, chars'
|
|
27
|
+
}
|
|
28
|
+
)
|
|
16
29
|
gsap.from(split.chars, {
|
|
17
30
|
opacity: 0.5,
|
|
18
31
|
duration: 0.1,
|
|
@@ -29,7 +42,7 @@ watch(() => [props.text1, props.text2],
|
|
|
29
42
|
</script>
|
|
30
43
|
|
|
31
44
|
<template>
|
|
32
|
-
<div class="flex flex-col items-center leading-[130%] text-heading-md md:text-heading-lg font-bold">
|
|
45
|
+
<div ref="typingEffectContainer" class="flex flex-col items-center leading-[130%] text-heading-md md:text-heading-lg font-bold">
|
|
33
46
|
<h2 :key="text1" class="split-text">
|
|
34
47
|
<span class="block text-heading">{{ text1 }}</span>
|
|
35
48
|
<span class="block text-action">{{ text2 }}</span>
|
|
@@ -54,6 +54,7 @@ const createFormField = <T,>(name: keyof ContactFormDefinition, value: T): FormF
|
|
|
54
54
|
const formData = ref({
|
|
55
55
|
email: createFormField('email', ''),
|
|
56
56
|
firstName: createFormField('firstName', ''),
|
|
57
|
+
lastName: createFormField('lastName', ''),
|
|
57
58
|
companyName: createFormField('companyName', ''),
|
|
58
59
|
linkedinCompanyPage: createFormField('linkedinCompanyPage', ''),
|
|
59
60
|
services: createFormField('services', ''),
|
|
@@ -122,6 +123,7 @@ const validateRequiredFields = () => {
|
|
|
122
123
|
const resetForm = () => {
|
|
123
124
|
formData.value.email.value = '';
|
|
124
125
|
formData.value.firstName.value = '';
|
|
126
|
+
formData.value.lastName.value = '';
|
|
125
127
|
formData.value.companyName.value = '';
|
|
126
128
|
formData.value.linkedinCompanyPage.value = '';
|
|
127
129
|
formData.value.description.value = '';
|
|
@@ -134,6 +136,7 @@ const resetForm = () => {
|
|
|
134
136
|
const currentValues = (): ContactFormValues => ({
|
|
135
137
|
email: formData.value.email.value,
|
|
136
138
|
firstName: formData.value.firstName.value,
|
|
139
|
+
lastName: formData.value.lastName.value,
|
|
137
140
|
companyName: formData.value.companyName.value,
|
|
138
141
|
linkedinCompanyPage: formData.value.linkedinCompanyPage.value,
|
|
139
142
|
services: formData.value.services.value,
|
|
@@ -231,14 +234,14 @@ fields.forEach((key) => {
|
|
|
231
234
|
})
|
|
232
235
|
|
|
233
236
|
const companyNamePattern = /[^\p{L}\p{N} &]/u;
|
|
234
|
-
const
|
|
237
|
+
const namePattern = /[^\p{L} ]/u;
|
|
235
238
|
|
|
236
239
|
const createSanitizer = (pattern) => {
|
|
237
240
|
return (value) => value.replace(pattern, '');
|
|
238
241
|
};
|
|
239
242
|
|
|
240
243
|
const sanitizeCompanyName = createSanitizer(companyNamePattern);
|
|
241
|
-
const
|
|
244
|
+
const sanitizeName = createSanitizer(namePattern);
|
|
242
245
|
|
|
243
246
|
const preventInvalidInput = (event, pattern) => {
|
|
244
247
|
if (event.data && pattern.test(event.data)) {
|
|
@@ -254,10 +257,11 @@ const preventInvalidInput = (event, pattern) => {
|
|
|
254
257
|
<fieldset class="space-y-2">
|
|
255
258
|
<InputText id="email" v-model="formData.email.value" :isRequired=formData.email.required :label=formData.email.label type="email" :isError="!!formData.email.error" :errorMessage="formData.email.error" :placeholder="formData.email.placeholder ?? ''" autocomplete="email" />
|
|
256
259
|
<div class="flex flex-col xl:flex-row gap-2">
|
|
257
|
-
<InputText id="firstname" v-model="formData.firstName.value" @beforeinput="event => preventInvalidInput(event,
|
|
258
|
-
<InputText id="
|
|
260
|
+
<InputText id="firstname" v-model="formData.firstName.value" @beforeinput="event => preventInvalidInput(event, namePattern)" @update:model-value="value => { formData.firstName.value = sanitizeName(value) }" :isRequired="formData.firstName.required" :label="formData.firstName.label" type="text" :isError="!!formData.firstName.error" :errorMessage="formData.firstName.error" :placeholder="formData.firstName.placeholder ?? ''" autocomplete="given-name" />
|
|
261
|
+
<InputText id="lastname" v-model="formData.lastName.value" @beforeinput="event => preventInvalidInput(event, namePattern)" @update:model-value="value => { formData.lastName.value = sanitizeName(value) }" :isRequired="formData.lastName.required" :label="formData.lastName.label" type="text" :isError="!!formData.lastName.error" :errorMessage="formData.lastName.error" :placeholder="formData.lastName.placeholder ?? ''" autocomplete="family-name" />
|
|
259
262
|
</div>
|
|
260
263
|
<div class="flex flex-col xl:flex-row gap-2">
|
|
264
|
+
<InputText id="companyName" v-model="formData.companyName.value" @beforeinput="event => preventInvalidInput(event, companyNamePattern)" @update:model-value="value => { formData.companyName.value = sanitizeCompanyName(value) }" :isRequired="formData.companyName.required" :label="formData.companyName.label" type="text" :isError="!!formData.companyName.error" :errorMessage="formData.companyName.error" :placeholder="formData.companyName.placeholder ?? ''" />
|
|
261
265
|
<InputText id="linkedinCompanyPage" v-model="formData.linkedinCompanyPage.value" :isRequired=formData.linkedinCompanyPage.required :label=formData.linkedinCompanyPage.label type="text" :isError="!!formData.linkedinCompanyPage.error" :errorMessage="formData.linkedinCompanyPage.error" :placeholder="formData.linkedinCompanyPage.placeholder ?? ''" />
|
|
262
266
|
</div>
|
|
263
267
|
</fieldset>
|
|
@@ -26,6 +26,7 @@ export interface CrmFormFieldSpec {
|
|
|
26
26
|
export type ContactFormFieldName =
|
|
27
27
|
| 'email'
|
|
28
28
|
| 'firstName'
|
|
29
|
+
| 'lastName'
|
|
29
30
|
| 'companyName'
|
|
30
31
|
| 'linkedinCompanyPage'
|
|
31
32
|
| 'services'
|
|
@@ -40,6 +41,7 @@ export type ContactFormDefinition = Record<ContactFormFieldName, CrmFormFieldSpe
|
|
|
40
41
|
export interface ContactFormValues {
|
|
41
42
|
email: string;
|
|
42
43
|
firstName: string;
|
|
44
|
+
lastName: string;
|
|
43
45
|
companyName: string;
|
|
44
46
|
linkedinCompanyPage: string;
|
|
45
47
|
services: string;
|
package/package.json
CHANGED