PluginProbe
The Innovative Form Builder – IvyForms / 0.7
The Innovative Form Builder – IvyForms v0.7
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / frontend / src / views / admin / form-builder / fields / recaptcha / RecaptchaField.vue

RecaptchaField.vue in The Innovative Form Builder – IvyForms 0.7, at frontend/src/views/admin/form-builder/fields/recaptcha/RecaptchaField.vue

262 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <template>
2 <div class="ivyforms-form-builder-field-recaptcha">
3 <IvyFormItem>
4 <!-- Configured reCAPTCHA - show different widgets based on type -->
5 <div v-if="isConfigured">
6 <!-- v2 checkbox reCAPTCHA widget -->
7 <div v-if="recaptchaType === 'v2'" class="ivyforms-recaptcha-widget">
8 <div class="ivyforms-recaptcha-widget__header">
9 <div class="ivyforms-recaptcha-widget__checkbox">
10 <IvyIcon
11 name="check"
12 type="outline"
13 category="global"
14 size="s"
15 class="ivyforms-recaptcha-widget__icon"
16 />
17 </div>
18 <span class="ivyforms-recaptcha-widget__text"> {{ getLabel('not_a_robot') }}</span>
19 <div class="ivyforms-recaptcha-widget__logos">
20 <IvyIcon name="recaptcha-colored" type="fill" category="security" size="d" />
21 </div>
22 </div>
23 </div>
24
25 <!-- v3 and invisible reCAPTCHA - show "protected by reCAPTCHA" badge -->
26 <div v-else class="ivyforms-recaptcha-badge">
27 <div class="ivyforms-recaptcha-badge__icon">
28 <IvyIcon name="recaptcha-colored" type="fill" category="security" size="d" />
29 </div>
30 <div class="ivyforms-recaptcha-badge__content">
31 <div class="ivyforms-recaptcha-badge__text">
32 <span class="ivyforms-recaptcha-badge__protected"
33 >{{ getLabel('protected_by') }} reCAPTCHA</span
34 >
35 </div>
36 <div class="ivyforms-recaptcha-badge__links">
37 <a href="#" class="ivyforms-recaptcha-badge__link">{{ getLabel('privacy') }}</a>
38 <span class="ivyforms-recaptcha-badge__separator">-</span>
39 <a href="#" class="ivyforms-recaptcha-badge__link">{{ getLabel('terms') }}</a>
40 </div>
41 </div>
42 </div>
43 </div>
44
45 <!-- Warning message and configure link for unconfigured state -->
46 <div v-else class="ivyforms-recaptcha-warning">
47 <IvyNotification
48 state="warning"
49 :description="getLabel('recaptcha_not_configured')"
50 :show-button="false"
51 :show-link="true"
52 :link-text="getLabel('configure_now')"
53 :link-url="redirectToSettings()"
54 />
55 </div>
56 </IvyFormItem>
57 </div>
58 </template>
59
60 <script setup lang="ts">
61 import { computed } from 'vue'
62 import { useLabels } from '@/composables/useLabels.ts'
63 import { useSettingsStore } from '@/stores/useSettingsStore.ts'
64 import utilRedirect from '@/utils/utilRedirects.ts'
65 import { IVYFORMS_SETTINGS_PAGE } from '@/constants/pages.ts'
66
67 interface Props {
68 fieldIndex: number
69 }
70
71 defineProps<Props>()
72
73 const { getLabel } = useLabels()
74 const settingsStore = useSettingsStore()
75 const { getHashRedirectLink } = utilRedirect()
76
77 // Function to redirect to settings page
78 const redirectToSettings = () => {
79 return getHashRedirectLink(IVYFORMS_SETTINGS_PAGE, '/security/recaptcha')
80 }
81
82 // Computed properties to dynamically get values from the store
83 const isConfigured = computed(() => settingsStore.isRecaptchaConfigured)
84 const recaptchaType = computed(() => settingsStore.recaptchaType)
85 </script>
86
87 <style lang="scss" scoped>
88 .ivyforms-form-builder-field-recaptcha {
89 display: flex;
90 flex-direction: column;
91 padding: 12px 0;
92 cursor: default;
93 width: 100%;
94
95 :deep(.el-form-item__content) {
96 align-items: start;
97 width: 100%;
98 }
99
100 .ivyforms-form-item {
101 cursor: default;
102 margin-bottom: 0;
103 width: 100%;
104
105 :deep(.el-form-item) {
106 margin-bottom: 0;
107 width: 100%;
108 }
109 :deep(.el-form-item__label),
110 :deep(.ivyforms-form-item__label) {
111 display: flex;
112 align-items: center;
113 color: var(--map-base-text-0);
114 font-size: 14px;
115 font-style: normal;
116 font-weight: 500;
117 line-height: 20px;
118 margin-bottom: 0;
119 height: 0;
120 cursor: default !important;
121 }
122 }
123 }
124
125 // Configured reCAPTCHA widget that mimics real reCAPTCHA appearance
126 .ivyforms-recaptcha-widget {
127 border: 1px solid var(--map-base-dusk-stroke--2);
128 border-radius: 3px;
129 background: var(--map-ground-level-1-foreground);
130 padding: 12px 16px;
131 min-width: 280px;
132 max-width: 300px;
133
134 &__header {
135 display: flex;
136 align-items: center;
137 gap: 12px;
138 }
139
140 &__checkbox {
141 display: flex;
142 align-items: center;
143 justify-content: center;
144 width: 20px;
145 height: 20px;
146 border: 1px solid var(--map-base-dusk-stroke--1);
147 border-radius: 2px;
148 background: var(--map-ground-level-1-foreground);
149 color: var(--map-base-brand-symbol-0);
150
151 svg {
152 fill: var(--map-base-dusk-symbol-0);
153 }
154 }
155
156 &__text {
157 font-size: 14px;
158 color: var(--map-base-text-0);
159 flex: 1;
160 line-height: 1.2;
161 }
162
163 &__logos {
164 display: flex;
165 flex-direction: column;
166 align-items: center;
167 opacity: 0.8;
168 color: var(--map-base-dusk-symbol--1);
169 }
170 &__icon {
171 flex-shrink: 0;
172 fill: var(--map-base-dusk-symbol-2);
173 }
174 }
175
176 .ivyforms-recaptcha-warning {
177 width: 100%;
178 margin-top: 8px;
179
180 :deep(.ivyforms-notification__content) {
181 flex: none;
182 }
183 :deep(.ivyforms-icon__svg) {
184 width: auto;
185 }
186 }
187
188 // reCAPTCHA badge for v3 and invisible types (mimics "protected by reCAPTCHA")
189 .ivyforms-recaptcha-badge {
190 display: inline-flex;
191 align-items: stretch;
192 border-radius: 3px;
193 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
194 cursor: default;
195 user-select: none;
196 min-width: 156px;
197 overflow: hidden;
198
199 &__icon {
200 display: flex;
201 align-items: center;
202 justify-content: center;
203 background: var(--map-ground-level-1-foreground);
204 padding: 8px;
205 flex-shrink: 0;
206 }
207
208 &__content {
209 display: flex;
210 flex-direction: column;
211 background: var(--map-accent-blue-fill-0);
212 color: var(--primitive-white);
213 padding: 6px 8px;
214 flex: 1;
215 justify-content: center;
216 }
217
218 &__text {
219 display: flex;
220 flex-direction: column;
221 line-height: 1.2;
222 margin-bottom: 2px;
223 }
224
225 &__protected {
226 font-size: 11px;
227 color: var(--primitive-white);
228 font-weight: 400;
229 line-height: 12px;
230 margin-bottom: 1px;
231 }
232
233 &__recaptcha {
234 font-size: 12px;
235 font-weight: 500;
236 color: var(--primitive-white);
237 line-height: 14px;
238 }
239
240 &__links {
241 display: flex;
242 align-items: center;
243 gap: 3px;
244 font-size: 8px;
245 line-height: 10px;
246 }
247
248 &__link {
249 color: var(--primitive-white);
250 text-decoration: none;
251
252 &:hover {
253 text-decoration: underline;
254 }
255 }
256
257 &__separator {
258 margin: 0 1px;
259 }
260 }
261 </style>
262