@mundogamernetwork/shared-ui 1.1.16 → 1.1.18
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.
- package/components/ui/MgAppInstallBanner.vue +258 -0
- package/components/ui/MgCampaignBannerCarousel.vue +141 -0
- package/package.json +2 -2
- package/pages/media-kit/[slug].vue +587 -150
- package/public/imgs/app-banner-logo-community-dark.svg +11 -0
- package/public/imgs/app-banner-logo-community-light.svg +11 -0
- package/public/imgs/app-banner-logo-jobs-dark.svg +15 -0
- package/public/imgs/app-banner-logo-jobs-light.svg +15 -0
- package/public/imgs/qrCode_app.svg +1 -0
- package/public/imgs/qrCode_app_jobs.svg +1 -0
- package/services/campaignBannersService.ts +39 -0
- package/stores/appInstallBanner.ts +137 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const colorMode = useColorMode();
|
|
3
|
+
const store = useAppInstallBannerStore();
|
|
4
|
+
const locale = useNuxtApp().$i18n.locale;
|
|
5
|
+
|
|
6
|
+
onMounted(async () => {
|
|
7
|
+
await store.fetchBanner();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const banner = computed(() => store.banner);
|
|
11
|
+
const isVisible = computed(() => store.isVisible);
|
|
12
|
+
|
|
13
|
+
const logoUrl = computed(() => {
|
|
14
|
+
if (!banner.value) return null;
|
|
15
|
+
return colorMode.preference === "light"
|
|
16
|
+
? banner.value.logo_light_url
|
|
17
|
+
: (banner.value.logo_dark_url ?? banner.value.logo_light_url);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const qrCodeUrl = computed(() => {
|
|
21
|
+
if (!banner.value) return null;
|
|
22
|
+
return colorMode.preference === "light"
|
|
23
|
+
? (banner.value.qr_code_url ?? banner.value.qr_code_url_dark)
|
|
24
|
+
: (banner.value.qr_code_url_dark ?? banner.value.qr_code_url);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const hasLogo = computed(() => !!logoUrl.value);
|
|
28
|
+
const hasQrCode = computed(() => !!qrCodeUrl.value);
|
|
29
|
+
|
|
30
|
+
function handleClose() {
|
|
31
|
+
store.dismiss();
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<div v-if="isVisible && banner" class="mg-app-install-banner">
|
|
37
|
+
<div class="mg-app-install-banner__container" :class="colorMode.preference">
|
|
38
|
+
<div v-if="hasLogo" class="mg-app-install-banner__logo" :class="colorMode.preference">
|
|
39
|
+
<img :src="logoUrl!" :alt="$t('more.app.modal_popup.title')" />
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="mg-app-install-banner__content">
|
|
43
|
+
<p class="mg-app-install-banner__title">{{ $t("more.app.modal_popup.title") }}</p>
|
|
44
|
+
<p class="mg-app-install-banner__text">{{ $t("more.app.modal_popup.text") }}</p>
|
|
45
|
+
<div class="mg-app-install-banner__actions">
|
|
46
|
+
<nuxt-link :href="`/${locale}/app`" class="mg-app-install-banner__link">
|
|
47
|
+
<span class="mg-app-install-banner__link-big">{{ $t("more.app.modal_popup.action") }}</span>
|
|
48
|
+
<span class="mg-app-install-banner__link-small">{{ $t("more.app.modal_popup.action") }}</span>
|
|
49
|
+
</nuxt-link>
|
|
50
|
+
|
|
51
|
+
<!-- Apple App Store icon -->
|
|
52
|
+
<a v-if="banner.ios_url" :href="banner.ios_url" target="_blank" rel="noopener" aria-label="App Store">
|
|
53
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="15" viewBox="0 0 14 15" fill="none">
|
|
54
|
+
<g clip-path="url(#mg-app-banner-apple)">
|
|
55
|
+
<path d="M9.78425 0.507006C9.7545 0.473756 8.68262 0.520131 7.74987 1.53251C6.81712 2.54401 6.96062 3.70426 6.98162 3.73401C7.00262 3.76376 8.31162 3.81013 9.14725 2.63326C9.98287 1.45638 9.814 0.541131 9.78425 0.507006ZM12.684 10.7734C12.642 10.6894 10.6496 9.69363 10.8351 7.77913C11.0206 5.86376 12.3007 5.33876 12.3209 5.28188C12.341 5.22501 11.7985 4.59063 11.2236 4.26951C10.8015 4.0431 10.3344 3.91339 9.856 3.88976C9.7615 3.88713 9.43337 3.80663 8.75875 3.99126C8.31425 4.11288 7.31237 4.50663 7.03675 4.52238C6.76025 4.53813 5.93775 4.06563 5.05312 3.94051C4.487 3.83113 3.88675 4.05513 3.45712 4.22751C3.02837 4.39901 2.21287 4.88726 1.64237 6.18488C1.07187 7.48163 1.37025 9.53613 1.58375 10.1749C1.79725 10.8128 2.13062 11.8584 2.69762 12.6214C3.20162 13.4824 3.87012 14.08 4.14925 14.283C4.42837 14.486 5.21587 14.6208 5.76187 14.3416C6.20112 14.0721 6.99387 13.9173 7.30712 13.9286C7.6195 13.94 8.2355 14.0634 8.86637 14.4003C9.366 14.5726 9.8385 14.5009 10.3119 14.3084C10.7852 14.115 11.4704 13.3818 12.2701 11.8951C12.5737 11.2039 12.712 10.8303 12.684 10.7734Z" :fill="colorMode.preference === 'light' ? '#0D0D0D' : 'white'" />
|
|
56
|
+
</g>
|
|
57
|
+
<defs>
|
|
58
|
+
<clipPath id="mg-app-banner-apple"><rect width="14" height="14" fill="white" transform="translate(0 0.5)" /></clipPath>
|
|
59
|
+
</defs>
|
|
60
|
+
</svg>
|
|
61
|
+
</a>
|
|
62
|
+
|
|
63
|
+
<!-- Google Play icon -->
|
|
64
|
+
<a v-if="banner.android_url" :href="banner.android_url" target="_blank" rel="noopener" aria-label="Google Play">
|
|
65
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="13" viewBox="0 0 12 13" fill="none">
|
|
66
|
+
<g clip-path="url(#mg-app-banner-play)">
|
|
67
|
+
<path d="M8.85047 8.46295C10.372 7.62749 11.5255 6.99088 11.6249 6.94138C11.943 6.77226 12.2714 6.3246 11.6249 5.97688C11.4162 5.86753 10.2923 5.25074 8.85047 4.45532L6.85162 6.47399L8.85047 8.4629V8.46295Z" fill="#FFD900" />
|
|
68
|
+
<path d="M6.85173 6.47388L0.487183 12.8884C0.636573 12.9082 0.805229 12.8686 1.00407 12.7593C1.42154 12.5307 5.84711 10.1139 8.85057 8.4633L6.85173 6.47388Z" fill="#3378DD" />
|
|
69
|
+
<path d="M6.85167 6.47393L8.85052 4.4652C8.85052 4.4652 1.45167 0.427338 1.00402 0.188978C0.835359 0.0890876 0.646359 0.0594157 0.477234 0.0890876L6.85167 6.47393Z" fill="#00EE76" />
|
|
70
|
+
<path d="M6.85177 6.47396L0.477328 0.0891113C0.218625 0.148924 0 0.377486 0 0.844924V12.1327C0 12.5605 0.169172 12.8686 0.487219 12.8984L6.85177 6.47396Z" fill="#00D3FF" />
|
|
71
|
+
</g>
|
|
72
|
+
<defs>
|
|
73
|
+
<clipPath id="mg-app-banner-play"><rect width="12" height="12.8438" fill="white" transform="translate(0 0.078125)" /></clipPath>
|
|
74
|
+
</defs>
|
|
75
|
+
</svg>
|
|
76
|
+
</a>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<img
|
|
81
|
+
v-if="hasQrCode"
|
|
82
|
+
class="mg-app-install-banner__qrcode"
|
|
83
|
+
:src="qrCodeUrl!"
|
|
84
|
+
width="70"
|
|
85
|
+
height="70"
|
|
86
|
+
alt="QR Code"
|
|
87
|
+
/>
|
|
88
|
+
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
class="mg-app-install-banner__close"
|
|
92
|
+
@click="handleClose"
|
|
93
|
+
:aria-label="$t('common.close')"
|
|
94
|
+
>
|
|
95
|
+
<MGIcon icon="close" />
|
|
96
|
+
</button>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</template>
|
|
100
|
+
|
|
101
|
+
<style lang="scss" scoped>
|
|
102
|
+
.mg-app-install-banner {
|
|
103
|
+
position: absolute;
|
|
104
|
+
bottom: 0.5rem;
|
|
105
|
+
right: 2rem;
|
|
106
|
+
z-index: 10;
|
|
107
|
+
|
|
108
|
+
@media (max-width: 430px) {
|
|
109
|
+
left: 0;
|
|
110
|
+
right: 0;
|
|
111
|
+
bottom: 0;
|
|
112
|
+
width: 100vw;
|
|
113
|
+
padding: 0 1rem;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.mg-app-install-banner__container {
|
|
118
|
+
min-height: 8rem;
|
|
119
|
+
border: 1px solid var(--banner-border-color);
|
|
120
|
+
border-bottom: none;
|
|
121
|
+
background: var(--banner-bg);
|
|
122
|
+
display: flex;
|
|
123
|
+
position: relative;
|
|
124
|
+
transition: border ease 0.3s, background ease 0.3s;
|
|
125
|
+
|
|
126
|
+
@media (max-width: 430px) {
|
|
127
|
+
min-height: 6.25rem;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.mg-app-install-banner__logo {
|
|
132
|
+
height: 8rem;
|
|
133
|
+
width: 8rem;
|
|
134
|
+
flex-shrink: 0;
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
justify-content: center;
|
|
138
|
+
transition: background ease 0.3s;
|
|
139
|
+
|
|
140
|
+
&.light {
|
|
141
|
+
background: linear-gradient(135deg, #eaedf0 0%, #c9d2dd 100%);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
&.dark {
|
|
145
|
+
background: linear-gradient(135deg, rgba(28, 57, 92, 0.1) 0%, #1c395c 100%);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
img {
|
|
149
|
+
width: 70%;
|
|
150
|
+
height: auto;
|
|
151
|
+
object-fit: contain;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@media (max-width: 430px) {
|
|
155
|
+
width: 5rem;
|
|
156
|
+
height: 5rem;
|
|
157
|
+
margin: 0.63rem 0;
|
|
158
|
+
margin-left: 0.88rem;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.mg-app-install-banner__content {
|
|
163
|
+
display: flex;
|
|
164
|
+
flex-direction: column;
|
|
165
|
+
padding: 1.25rem 1.5rem 1.25rem 1rem;
|
|
166
|
+
flex: 1;
|
|
167
|
+
|
|
168
|
+
@media (max-width: 430px) {
|
|
169
|
+
padding-top: 1rem;
|
|
170
|
+
padding-bottom: 1.12rem;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.mg-app-install-banner__title {
|
|
175
|
+
margin: 0;
|
|
176
|
+
font-size: 0.875rem;
|
|
177
|
+
color: var(--section-title-fg);
|
|
178
|
+
transition: color ease 0.3s;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.mg-app-install-banner__text {
|
|
182
|
+
margin: 0.5rem 0 0;
|
|
183
|
+
color: var(--text-secondary-color);
|
|
184
|
+
font-size: 0.75rem;
|
|
185
|
+
|
|
186
|
+
@media (max-width: 430px) {
|
|
187
|
+
margin-top: 0;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.mg-app-install-banner__actions {
|
|
192
|
+
display: flex;
|
|
193
|
+
align-items: center;
|
|
194
|
+
column-gap: 0.5rem;
|
|
195
|
+
margin-top: 0.75rem;
|
|
196
|
+
|
|
197
|
+
@media (max-width: 430px) {
|
|
198
|
+
margin-top: 1rem;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.mg-app-install-banner__link {
|
|
203
|
+
font-size: 0.75rem;
|
|
204
|
+
color: var(--banner-link-color);
|
|
205
|
+
transition: color ease 0.3s;
|
|
206
|
+
|
|
207
|
+
.mg-app-install-banner__link-big {
|
|
208
|
+
display: block;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.mg-app-install-banner__link-small {
|
|
212
|
+
display: none;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@media (max-width: 430px) {
|
|
216
|
+
.mg-app-install-banner__link-big {
|
|
217
|
+
display: none;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.mg-app-install-banner__link-small {
|
|
221
|
+
display: block;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.mg-app-install-banner__qrcode {
|
|
227
|
+
margin: 0.88rem 1.25rem 0.88rem 0;
|
|
228
|
+
height: 6.25rem;
|
|
229
|
+
width: 6.25rem;
|
|
230
|
+
object-fit: contain;
|
|
231
|
+
|
|
232
|
+
@media (max-width: 430px) {
|
|
233
|
+
display: none;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.mg-app-install-banner__close {
|
|
238
|
+
position: absolute;
|
|
239
|
+
top: 0;
|
|
240
|
+
right: 0;
|
|
241
|
+
width: 2.125rem;
|
|
242
|
+
height: 2.125rem;
|
|
243
|
+
border-radius: 100%;
|
|
244
|
+
background: var(--banner-button-bg);
|
|
245
|
+
display: flex;
|
|
246
|
+
align-items: center;
|
|
247
|
+
justify-content: center;
|
|
248
|
+
transform: translate(50%, -50%);
|
|
249
|
+
border: none;
|
|
250
|
+
cursor: pointer;
|
|
251
|
+
transition: background ease 0.3s;
|
|
252
|
+
|
|
253
|
+
i {
|
|
254
|
+
color: var(--section-title-fg);
|
|
255
|
+
transition: color ease 0.3s;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
</style>
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { fetchCampaignBanners, clickCampaignBanner } from "../../services/campaignBannersService";
|
|
3
|
+
|
|
4
|
+
const props = withDefaults(
|
|
5
|
+
defineProps<{
|
|
6
|
+
platform: string;
|
|
7
|
+
page: string;
|
|
8
|
+
interval?: number;
|
|
9
|
+
}>(),
|
|
10
|
+
{ interval: 5000 },
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
const { locale } = useI18n();
|
|
14
|
+
const isMobile = ref(false);
|
|
15
|
+
const currentIndex = ref(0);
|
|
16
|
+
let timer: ReturnType<typeof setInterval> | null = null;
|
|
17
|
+
|
|
18
|
+
const { data: banners } = await useAsyncData(
|
|
19
|
+
`mg-campaign-banners-${props.platform}-${props.page}-${locale.value}`,
|
|
20
|
+
() => fetchCampaignBanners(props.platform, props.page, locale.value),
|
|
21
|
+
{ default: () => [], lazy: true, server: false },
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const hasBanners = computed(() => (banners.value?.length ?? 0) > 0);
|
|
25
|
+
const currentBanner = computed(() => banners.value?.[currentIndex.value] ?? null);
|
|
26
|
+
|
|
27
|
+
const imageUrl = computed(() => {
|
|
28
|
+
if (!currentBanner.value) return "";
|
|
29
|
+
return isMobile.value && currentBanner.value.url_image_mobile
|
|
30
|
+
? currentBanner.value.url_image_mobile
|
|
31
|
+
: currentBanner.value.url_image;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const startCarousel = () => {
|
|
35
|
+
if ((banners.value?.length ?? 0) <= 1) return;
|
|
36
|
+
timer = setInterval(() => {
|
|
37
|
+
currentIndex.value = (currentIndex.value + 1) % (banners.value?.length ?? 1);
|
|
38
|
+
}, props.interval);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const handleClick = () => {
|
|
42
|
+
if (!currentBanner.value) return;
|
|
43
|
+
clickCampaignBanner(currentBanner.value.id);
|
|
44
|
+
window.open(currentBanner.value.link, "_blank");
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const goTo = (index: number) => {
|
|
48
|
+
currentIndex.value = index;
|
|
49
|
+
if (timer) clearInterval(timer);
|
|
50
|
+
startCarousel();
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const checkMobile = () => {
|
|
54
|
+
isMobile.value = window.innerWidth < 768;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
onMounted(() => {
|
|
58
|
+
checkMobile();
|
|
59
|
+
window.addEventListener("resize", checkMobile);
|
|
60
|
+
startCarousel();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
onUnmounted(() => {
|
|
64
|
+
if (timer) clearInterval(timer);
|
|
65
|
+
window.removeEventListener("resize", checkMobile);
|
|
66
|
+
});
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<template>
|
|
70
|
+
<div v-if="hasBanners" class="mg-campaign-banner-carousel mb-4">
|
|
71
|
+
<div
|
|
72
|
+
class="mg-campaign-banner-slide"
|
|
73
|
+
role="button"
|
|
74
|
+
tabindex="0"
|
|
75
|
+
@click="handleClick"
|
|
76
|
+
@keydown.enter="handleClick"
|
|
77
|
+
>
|
|
78
|
+
<img
|
|
79
|
+
:src="imageUrl"
|
|
80
|
+
:alt="currentBanner?.title || ''"
|
|
81
|
+
class="mg-campaign-banner-img img-fluid"
|
|
82
|
+
loading="eager"
|
|
83
|
+
decoding="async"
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
<div v-if="(banners?.length ?? 0) > 1" class="mg-campaign-banner-indicators">
|
|
87
|
+
<button
|
|
88
|
+
v-for="(_, i) in banners"
|
|
89
|
+
:key="i"
|
|
90
|
+
type="button"
|
|
91
|
+
:class="{ active: i === currentIndex }"
|
|
92
|
+
@click.stop="goTo(i)"
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</template>
|
|
97
|
+
|
|
98
|
+
<style lang="scss" scoped>
|
|
99
|
+
.mg-campaign-banner-carousel {
|
|
100
|
+
position: relative;
|
|
101
|
+
width: 100%;
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.mg-campaign-banner-slide {
|
|
106
|
+
cursor: pointer;
|
|
107
|
+
display: block;
|
|
108
|
+
width: 100%;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.mg-campaign-banner-img {
|
|
112
|
+
display: block;
|
|
113
|
+
width: 100%;
|
|
114
|
+
height: auto;
|
|
115
|
+
object-fit: cover;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.mg-campaign-banner-indicators {
|
|
119
|
+
position: absolute;
|
|
120
|
+
bottom: 8px;
|
|
121
|
+
left: 50%;
|
|
122
|
+
transform: translateX(-50%);
|
|
123
|
+
display: flex;
|
|
124
|
+
gap: 6px;
|
|
125
|
+
align-items: center;
|
|
126
|
+
|
|
127
|
+
button {
|
|
128
|
+
width: 8px;
|
|
129
|
+
height: 8px;
|
|
130
|
+
padding: 0;
|
|
131
|
+
border: 0;
|
|
132
|
+
background: rgba(255, 255, 255, 0.5);
|
|
133
|
+
cursor: pointer;
|
|
134
|
+
transition: background 0.2s;
|
|
135
|
+
|
|
136
|
+
&.active {
|
|
137
|
+
background: #fff;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
</style>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mundogamernetwork/shared-ui",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.18",
|
|
4
4
|
"description": "Mundo Gamer Network - Shared UI Layer (Nuxt 3)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
@@ -40,4 +40,4 @@
|
|
|
40
40
|
"nuxt": "^3.15.4",
|
|
41
41
|
"typescript": "^5.0.0"
|
|
42
42
|
}
|
|
43
|
-
}
|
|
43
|
+
}
|