PluginProbe ʕ •ᴥ•ʔ
Hostinger Reach – AI-Powered Email Marketing for WordPress / 1.5.9
Hostinger Reach – AI-Powered Email Marketing for WordPress v1.5.9
1.7.2 1.7.1 1.7.0 1.6.0 1.5.9 1.5.8 1.5.7 1.5.6 1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5.0 1.4.12 1.4.11 1.4.10 1.4.9 1.4.8 1.4.7 trunk 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6
hostinger-reach / frontend / vue / components / Hero.vue
hostinger-reach / frontend / vue / components Last commit date
Modals 1 month ago skeletons 5 months ago ActionButton.vue 5 months ago ActionButtonsSection.vue 5 months ago Banner.vue 3 months ago FAQ.vue 5 months ago FormItem.vue 2 months ago FormsSection.vue 11 months ago Hero.vue 1 month ago Integrations.vue 4 months ago Pagination.vue 10 months ago PluginEntriesTable.vue 4 months ago PluginEntry.vue 5 months ago PluginExpansion.vue 8 months ago SyncStatusLabel.vue 6 months ago Tabs.vue 9 months ago Toggle.vue 10 months ago UsageCard.vue 10 months ago UsageCardsRow.vue 1 year ago UsageCardsSection.vue 1 year ago WooCommerce.vue 5 months ago WooCommerceEntriesTable.vue 4 months ago
Hero.vue
395 lines
1 <script setup lang="ts">
2 import { HNotificationRow } from '@hostinger/hcomponents';
3 import { computed } from 'vue';
4
5 import reachBackgroundImage from '@/assets/images/backgrounds/reach-welcome-background.png';
6 import reachBackgroundImageMobile from '@/assets/images/backgrounds/reach-welcome-background-mobile.png';
7 import reachLogo from '@/assets/images/icons/reach-logo.svg';
8 import { useReachUrls } from '@/composables/useReachUrls';
9 import { translate } from '@/utils/translate';
10
11 const { reachBaseDomain } = useReachUrls();
12
13 const reachDashboardUrl = computed(() => `https://${reachBaseDomain.value}`);
14
15 interface Props {
16 isConnectedToAnotherSite?: boolean;
17 isButtonLoading?: boolean;
18 isTemporary?: boolean;
19 isNotActive?: boolean;
20 domain: string;
21 onGetStarted: () => void;
22 onManualApiKeyClick?: () => void;
23 }
24
25 const props = withDefaults(defineProps<Props>(), {
26 isConnectedToAnotherSite: false,
27 isButtonLoading: false,
28 isNotActive: false,
29 onManualApiKeyClick: () => {}
30 });
31 </script>
32
33 <template>
34 <section class="hero" role="main" aria-labelledby="hero-heading">
35 <header class="hero__header">
36 <div class="hero__header-content">
37 <div class="hero__header-brand">
38 <img :src="reachLogo" :alt="translate('hostinger_reach_header_logo_alt')" class="hero__header-logo" />
39 </div>
40 <HButton
41 variant="outline"
42 target="_blank"
43 color="neutral"
44 size="small"
45 icon-append="ic-launch-16"
46 :to="reachDashboardUrl"
47 >
48 {{ translate('hostinger_reach_header_go_to_reach_button') }}
49 </HButton>
50 </div>
51 </header>
52
53 <HCard border-radius="20px" padding="0" border-color="neutral--200">
54 <div class="hero__image">
55 <img
56 :src="reachBackgroundImage"
57 :alt="translate('hostinger_reach_hero_background_alt')"
58 role="img"
59 style="display: none"
60 />
61 <img
62 :src="reachBackgroundImageMobile"
63 :alt="translate('hostinger_reach_hero_background_alt')"
64 class="hero__background"
65 role="img"
66 />
67 </div>
68 <div
69 style="
70 background-image: url('/wp-content/plugins/hostinger-reach/frontend/dist/assets/reach-welcome-background.png');
71 "
72 class="hero__content"
73 >
74 <div class="hero__content-wrapper">
75 <HText id="hero-heading" as="h1" variant="heading-1">
76 {{ translate('hostinger_reach_welcome_view_title') }}
77 </HText>
78 <HText id="hero-description" as="p" variant="body-2 h-mb-24">
79 {{ translate('hostinger_reach_welcome_view_description') }}
80 </HText>
81 <template v-if="!isConnectedToAnotherSite && !isTemporary && !isNotActive">
82 <div class="hero__actions">
83 <HButton
84 color="primary"
85 size="small"
86 :is-loading="props.isButtonLoading"
87 aria-describedby="hero-description"
88 :aria-label="translate('hostinger_reach_welcome_view_start_button')"
89 @click="onGetStarted"
90 >
91 {{ translate('hostinger_reach_welcome_view_start_button') }}
92 </HButton>
93 <HButton variant="text" color="neutral" size="small" @click="onManualApiKeyClick">
94 {{ translate('hostinger_reach_api_key_modal_link') }}
95 </HButton>
96 </div>
97 </template>
98 </div>
99 </div>
100 <div v-if="!isButtonLoading && (isTemporary || isNotActive)" class="hero__info">
101 <HNotificationRow
102 variant="warning"
103 :description="
104 isTemporary
105 ? translate('hostinger_reach_welcome_view_description_temporary')
106 : translate('hostinger_reach_welcome_view_description_not_active')
107 "
108 :primary-action-text="
109 isTemporary
110 ? translate('hostinger_reach_welcome_view_temporary_button')
111 : translate('hostinger_reach_welcome_view_not_active_button')
112 "
113 @primary-action-click="onGetStarted"
114 />
115 </div>
116 <div class="hero__footer" role="contentinfo" aria-label="Site information">
117 <HIcon class="h-mr-8" name="ic-globe-16" color="neutral--300" aria-hidden="true" />
118 <HText as="p" variant="body-2-bold" color="neutral--500">
119 {{ domain }}
120 </HText>
121 </div>
122 </HCard>
123 </section>
124 </template>
125
126 <style scoped lang="scss">
127 .hero {
128 display: flex;
129 align-items: center;
130 flex-direction: column;
131 max-width: 780px;
132 margin: 40px auto 16px auto;
133
134 @media (max-width: 1024px) {
135 max-width: 90%;
136 margin: 32px auto 16px auto;
137 }
138
139 @media (max-width: 768px) {
140 flex-direction: column;
141 text-align: left;
142 padding: 24px 16px;
143 gap: 32px;
144 margin: 20px auto 16px auto;
145 }
146
147 @media (max-width: 480px) {
148 padding: 16px 8px;
149 gap: 24px;
150 margin: 16px auto 12px auto;
151 }
152
153 &__banner {
154 display: flex;
155 width: 100%;
156 align-items: center;
157 justify-content: space-between;
158 gap: 16px;
159
160 @media (max-width: 768px) {
161 flex-direction: column;
162 align-items: flex-start;
163 gap: 12px;
164 }
165
166 @media (max-width: 480px) {
167 gap: 8px;
168 }
169 }
170
171 &__banner-content {
172 display: flex;
173 flex-direction: column;
174 gap: 4px;
175
176 @media (max-width: 768px) {
177 width: 100%;
178 }
179 }
180
181 &__content {
182 flex: 1;
183 padding: 28px;
184 width: 100%;
185 border-radius: 20px;
186 background-size: cover;
187 background-position: right;
188 background-repeat: no-repeat;
189
190 @media (max-width: 768px) {
191 padding: 24px 24px 0;
192 background: none;
193 border-radius: 0;
194 }
195 }
196
197 &__image {
198 width: 100%;
199 display: flex;
200 justify-content: center;
201 position: relative;
202 overflow: hidden;
203 margin-bottom: 0;
204 border-bottom: 1px solid var(--neutral--50);
205
206 @media (min-width: 768px) {
207 display: none;
208 }
209 }
210
211 &__background {
212 width: 100%;
213 height: auto;
214 border-top-right-radius: 20px;
215 border-top-left-radius: 20px;
216 border-bottom-right-radius: 0;
217 border-bottom-left-radius: 0;
218 }
219
220 &__content-wrapper {
221 display: flex;
222 flex-direction: column;
223 gap: 10px;
224
225 @media (min-width: 768px) {
226 width: 50%;
227 max-width: 345px;
228 }
229 }
230
231 &__info {
232 padding: 24px;
233 border-top: 1px solid var(--neutral--50);
234
235 @media (max-width: 768px) {
236 padding-top: 0;
237 padding-bottom: 24px;
238 }
239 }
240
241 &__actions {
242 display: flex;
243 align-items: center;
244 gap: 12px;
245 }
246
247 &__manual-link {
248 appearance: none;
249 background: transparent;
250 border: 0;
251 color: var(--primary--500);
252 cursor: pointer;
253 font: inherit;
254 text-decoration: underline;
255 }
256
257 &__api-key-box {
258 display: flex;
259 flex-direction: column;
260 gap: 8px;
261 max-width: 420px;
262 }
263
264 &__api-key-label {
265 color: var(--neutral--700);
266 font-weight: 600;
267 }
268
269 &__api-key-input {
270 width: 100%;
271 border: 1px solid var(--neutral--200);
272 border-radius: 8px;
273 padding: 8px 12px;
274 font-size: 14px;
275 }
276
277 &__api-actions {
278 display: flex;
279 gap: 12px;
280 align-items: center;
281 }
282
283 &__footer {
284 width: 100%;
285 display: flex;
286 align-items: center;
287 padding: 16px 24px 20px 24px;
288 border-bottom-left-radius: 20px;
289 background: var(--neutral--50);
290 border-bottom-right-radius: 20px;
291
292 @media (max-width: 768px) {
293 padding: 16px;
294 }
295 }
296
297 &__header {
298 width: 100%;
299 margin-bottom: 20px;
300
301 @media (max-width: 768px) {
302 padding: 0 12px;
303 margin-bottom: 16px;
304 }
305
306 @media (max-width: 480px) {
307 padding: 0 8px;
308 margin-bottom: 12px;
309 }
310 }
311
312 &__warning-snackbar {
313 display: flex;
314 align-items: center;
315 }
316
317 &__header-content {
318 display: flex;
319 justify-content: space-between;
320 align-items: center;
321 width: 100%;
322
323 @media (max-width: 768px) {
324 flex-direction: column;
325 gap: 16px;
326 align-items: flex-start;
327 }
328
329 @media (max-width: 480px) {
330 gap: 12px;
331 }
332
333 :deep(.h-button-v2) {
334 @media (max-width: 768px) {
335 width: 100%;
336 }
337 }
338 }
339
340 &__header-brand {
341 display: flex;
342 align-items: center;
343 gap: 12px;
344
345 @media (max-width: 480px) {
346 gap: 8px;
347 }
348 }
349
350 &__header-logo {
351 height: 28px;
352 width: auto;
353
354 @media (max-width: 768px) {
355 height: 24px;
356 }
357
358 @media (max-width: 480px) {
359 height: 20px;
360 }
361 }
362
363 &__header-title {
364 margin-bottom: 12px;
365 color: var(--neutral--700);
366 }
367
368 &__warning-snackbar {
369 margin-bottom: 24px;
370 }
371 }
372
373 :deep(.h-card) {
374 width: 100%;
375 }
376
377 :deep(.h-notification-row) {
378 border: 1px solid #ffd28c;
379 @media (max-width: 768px) {
380 padding: 0;
381 }
382 }
383
384 @media (max-width: 320px) {
385 .hero {
386 padding: 12px 4px;
387 gap: 20px;
388
389 &__content {
390 padding: 12px 12px 0px 12px;
391 }
392 }
393 }
394 </style>
395