@codecavepro/brand 2.7.2 → 2.7.4

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.
@@ -21,7 +21,7 @@ const variantClass = computed(() => {
21
21
  case 'tertiary':
22
22
  return `${buttonBaseClass} px-6 py-1 border border-primary-500 hover:border-hovered`
23
23
  case 'icon':
24
- return `${buttonBaseClass} p-5 border border-primary-500 hover:border-primary-700`
24
+ return `${buttonBaseClass} p-5 border border-primary-500 hover:border-hovered`
25
25
  case 'ghost':
26
26
  return `${linkBaseClass} text-body-primary hover:text-primary-200 active:text-primary-200 font-bold px-6 py-2`
27
27
  case 'text':
@@ -135,7 +135,7 @@ const currentValues = (): ContactFormValues => ({
135
135
  })
136
136
 
137
137
  const isSubmitting = ref(false)
138
-
138
+ const isFormSubmitted = ref(false)
139
139
  const submitContactsForm = async () => {
140
140
  if (isSubmitting.value || !validateForm()) {
141
141
  return
@@ -149,12 +149,10 @@ const submitContactsForm = async () => {
149
149
  const result = await props.client.submit(values)
150
150
 
151
151
  if (result.ok) {
152
+ isFormSubmitted.value = true
152
153
  resetForm()
153
154
  showAlert('success')
154
155
  } else {
155
- /* The previous code logged the failure and showed nothing, so a visitor
156
- * whose enquiry never sent had no way to know. The wording below is a
157
- * placeholder for a writer -- see CCWEB2-325. */
158
156
  showAlert('error')
159
157
  }
160
158
 
@@ -189,6 +187,41 @@ watch(isAlertVisible, () => {
189
187
  })
190
188
  })
191
189
 
190
+ const validateField = (field) => {
191
+ if (isFormSubmitted.value) {
192
+ field.error = ''
193
+ return
194
+ }
195
+
196
+ if (field.required && !field.value) {
197
+ field.error = 'This field is required'
198
+ return
199
+ }
200
+
201
+ field.error = ''
202
+ }
203
+
204
+ const fields = [
205
+ 'email',
206
+ 'firstName',
207
+ 'companyName',
208
+ 'linkedinCompanyPage',
209
+ 'privacyPolicy'
210
+ ]
211
+
212
+ fields.forEach((key) => {
213
+ watch(
214
+ () => formData.value[key].value,
215
+ (value) => {
216
+ if (isFormSubmitted.value && value) {
217
+ isFormSubmitted.value = false
218
+ }
219
+
220
+ validateField(formData.value[key])
221
+ }
222
+ )
223
+ })
224
+
192
225
  </script>
193
226
 
194
227
  <template>
@@ -220,18 +253,18 @@ watch(isAlertVisible, () => {
220
253
  </div>
221
254
  </div>
222
255
  <GlowButton @click="submitContactsForm" title="Leave consultation request" class="self-center lg:self-start" />
223
- <div v-show="isAlertVisible" class="border border-action group absolute bottom-19.25 md:fixed z-50 left-1/2 -translate-x-1/2 md:top-24 form-alert flex gap-2 md:gap-8 items-center justify-between w-full h-fit max-w-139 bg-surface-secondary p-4 md:px-6 md:py-2.5 rounded-3xl">
256
+ </form>
257
+ <div v-show="isAlertVisible" class="border border-action group absolute bottom-19.25 md:fixed z-350 left-1/2 -translate-x-1/2 md:top-40 form-alert flex gap-2 md:gap-8 items-center justify-between w-full h-fit max-w-139 bg-surface-secondary p-4 md:px-6 md:py-2.5 rounded-3xl">
224
258
  <div v-if="alertKind === 'success'" class="w-8 h-8">
225
259
  <component :is="SuccessIcon" class="w-8 h-8" />
226
260
  </div>
227
- <p class="text-sm md:text-lg font-bold text-heading md:max-w-sm">
261
+ <p class="text-sm md:text-lg font-bold text-heading md:max-w-sm ">
228
262
  {{ alertKind ? ALERT_TEXT[alertKind] : '' }}
229
263
  </p>
230
264
  <button @click="alertKind = null" class="group-hover:text-action text-heading transition-colors cursor-pointer">
231
265
  <component :is="CloseIcon" />
232
266
  </button>
233
267
  </div>
234
- </form>
235
268
  </template>
236
269
 
237
270
  <style scoped>
@@ -75,9 +75,9 @@ const handleCloseMenu = () => {
75
75
 
76
76
  <template>
77
77
  <div>
78
- <div :class="`fixed z-50 top-0 w-full bg-surface-primary-transparent backdrop-blur-3xl border-b border-surface-quaternary`">
79
- <div :class="`h-full px-5 ${isMenuOpen ? 'pb-5' : 'pb-0'} flex flex-col gap-2 transition-all`">
80
- <div class="flex justify-between items-center py-1.5">
78
+ <div class="fixed z-50 top-0 w-full bg-surface-primary-transparent backdrop-blur-3xl border-b border-surface-quaternary">
79
+ <div :class="`px-5 ${isMenuOpen ? 'pb-5' : 'pb-0'} flex flex-col gap-2 transition-all max-h-screen`">
80
+ <div class="flex justify-between items-center py-1.5 shrink-0">
81
81
  <a :href="homeHref" class="px-1.5 hover:opacity-80 transition-opacity">
82
82
  <img :src="logo" alt="CODECAVE" />
83
83
  </a>
@@ -85,25 +85,28 @@ const handleCloseMenu = () => {
85
85
  <span></span>
86
86
  </button>
87
87
  </div>
88
- <nav v-if="isMenuOpen" class="h-full text-sm flex-1 overflow-y-auto min-h-0">
89
- <div v-if="isServicesOpen">
90
- <h2 class="text-center font-bold text-body-primary py-2.5">
88
+ <nav v-if="isMenuOpen" class="flex-1 min-h-0 overflow-y-auto text-sm">
89
+ <div v-if="isServicesOpen" class="h-full flex flex-col min-h-0">
90
+ <h2 class="text-center font-bold text-body-primary py-2.5 shrink-0">
91
91
  {{ servicesItem?.submenuTitle }}
92
92
  </h2>
93
- <slot name="services" />
94
- <button class="pt-4" @click="isServicesOpen = false">
95
- <component class="w-11 h-11 text-action" :is="BackIcon" />
93
+ <div class="flex-1 min-h-0 overflow-y-auto">
94
+ <slot name="services" />
95
+ </div>
96
+
97
+ <button class="pt-4 shrink-0" @click="isServicesOpen = false">
98
+ <component :is="BackIcon" class="w-11 h-11 text-action" />
96
99
  </button>
97
100
  </div>
98
- <ul v-else class="h-full flex flex-col items-center gap-3 justify-around px-4 pt-2">
101
+ <ul v-else class="flex flex-col items-center gap-3 px-4 pt-2 overflow-y-auto">
99
102
  <li v-for="(item, index) in items" :key="index">
100
103
  <div v-if="item.submenu?.length">
101
- <Button :title="item.name" variant="ghost" @click="isServicesOpen = true" class="transition-transform duration-150 pr-1">
102
- <Shevron class="rotate-270 ml-1" />
104
+ <Button :title="item.name" variant="ghost" class="pr-1 transition-transform duration-150" @click="isServicesOpen = true">
105
+ <Shevron class="ml-1 rotate-270" />
103
106
  </Button>
104
107
  </div>
105
108
  <Button v-else-if="item.emphasis" as="link" :href="item.link" :title="item.mobileTitle ?? item.name" variant="tertiary" @click="handleCloseMenu" />
106
- <Button v-else as="link" variant="ghost" :title="item.mobileTitle ?? item.name" :href="item.link" />
109
+ <Button v-else as="link" variant="ghost" :title="item.mobileTitle ?? item.name" :href="item.link" @click="handleCloseMenu" />
107
110
  </li>
108
111
  </ul>
109
112
  </nav>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codecavepro/brand",
3
- "version": "2.7.2",
3
+ "version": "2.7.4",
4
4
  "description": "CODECAVE design system — colour, typography and layout tokens as CSS custom properties and as a typed module.",
5
5
  "license": "Unlicense",
6
6
  "type": "module",