@mundogamernetwork/shared-ui 1.0.0
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/README.md +283 -0
- package/components/PressKit/AssetGallery.vue +349 -0
- package/components/PressKit/Awards.vue +100 -0
- package/components/PressKit/Credits.vue +78 -0
- package/components/PressKit/FactSheet.vue +204 -0
- package/components/PressKit/Hero.vue +143 -0
- package/components/PressKit/Quotes.vue +80 -0
- package/components/PressKit/VideoPlayer.vue +134 -0
- package/components/checkout/MgCartItemList.vue +214 -0
- package/components/checkout/MgCartSummary.vue +204 -0
- package/components/checkout/MgCheckoutSidebar.vue +230 -0
- package/components/checkout/MgGuestEmailForm.vue +97 -0
- package/components/checkout/MgPaymentMethodSelector.vue +162 -0
- package/components/checkout/MgPixQRCode.vue +222 -0
- package/components/indie-wall/IndieWallLeaderboard.vue +208 -0
- package/components/indie-wall/MuralCanvas.vue +481 -0
- package/components/indie-wall/StepBlock.vue +314 -0
- package/components/indie-wall/StepCustomize.vue +530 -0
- package/components/indie-wall/StepGoal.vue +169 -0
- package/components/indie-wall/StepPackage.vue +145 -0
- package/components/indie-wall/StepPay.vue +209 -0
- package/components/indie-wall/SupportStepper.vue +372 -0
- package/components/invoices/MgInvoiceDownload.vue +50 -0
- package/components/pricing/MgBillingToggle.vue +74 -0
- package/components/pricing/MgPricingCard.vue +245 -0
- package/components/ui/Header/MgMessageCard.vue +147 -0
- package/components/ui/Header/MgMessageModal.vue +414 -0
- package/components/ui/Header/MgNotificationCard.vue +200 -0
- package/components/ui/Header/MgNotificationsModal.vue +125 -0
- package/components/ui/MgAnnouncementBanner.vue +147 -0
- package/components/ui/MgBanners.vue +23 -0
- package/components/ui/MgHeaderComponent.vue +283 -0
- package/components/ui/MgHeaderUIConfig.vue +225 -0
- package/components/ui/MgHeaderUIUser.vue +301 -0
- package/components/ui/MgLoginModal.vue +156 -0
- package/components/ui/MgPromotionBanner.vue +185 -0
- package/composables/useLogout.ts +42 -0
- package/composables/useMgCheckout.ts +287 -0
- package/composables/useMgUserNotifications.ts +122 -0
- package/composables/usePaymentMethods.ts +75 -0
- package/composables/useSubscription.ts +163 -0
- package/middleware/auth.global.ts +40 -0
- package/nuxt.config.ts +31 -0
- package/package.json +40 -0
- package/pages/[slug]/index.vue +112 -0
- package/pages/about.vue +133 -0
- package/pages/blog.vue +430 -0
- package/pages/careers.vue +329 -0
- package/pages/contact.vue +339 -0
- package/pages/faq.vue +317 -0
- package/pages/health-check.vue +20 -0
- package/pages/icons.vue +58 -0
- package/pages/magazine/[slug].vue +209 -0
- package/pages/magazine/index.vue +267 -0
- package/pages/media-kit/[slug].vue +625 -0
- package/pages/mural/[slug].vue +1058 -0
- package/pages/partners.vue +290 -0
- package/pages/press.vue +237 -0
- package/pages/presskit/[slug].vue +191 -0
- package/pages/roadmap.vue +355 -0
- package/pages/status.vue +199 -0
- package/pages/team.vue +266 -0
- package/pages/wall/[slug].vue +11 -0
- package/plugins/auth.client.ts +17 -0
- package/plugins/echo.client.ts +132 -0
- package/services/authService.ts +95 -0
- package/services/chatService.ts +53 -0
- package/services/contactService.ts +35 -0
- package/services/documentService.ts +16 -0
- package/services/httpService.ts +95 -0
- package/services/indieWallService.ts +174 -0
- package/services/institutionalService.ts +248 -0
- package/services/mediaKitService.ts +51 -0
- package/services/notificationsService.ts +20 -0
- package/services/pressKitService.ts +55 -0
- package/stores/announcement.ts +129 -0
- package/stores/auth.ts +86 -0
- package/stores/chat.ts +150 -0
- package/stores/contact.ts +28 -0
- package/stores/document.ts +27 -0
- package/stores/index.ts +34 -0
- package/stores/institutional.ts +231 -0
- package/stores/login.ts +27 -0
- package/stores/notifications.ts +133 -0
- package/stores/promotion.ts +154 -0
- package/types/index.ts +135 -0
- package/utils/serialize.ts +29 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
interface Award {
|
|
3
|
+
id: number;
|
|
4
|
+
title: string;
|
|
5
|
+
event?: string;
|
|
6
|
+
year?: number;
|
|
7
|
+
url?: string;
|
|
8
|
+
sort_order?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
awards: Award[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
defineProps<Props>();
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div v-if="awards.length" class="awards-section">
|
|
20
|
+
<h3 class="section-title">{{ $t('press_kit.awards') }}</h3>
|
|
21
|
+
<div class="awards-grid">
|
|
22
|
+
<a
|
|
23
|
+
v-for="award in awards"
|
|
24
|
+
:key="award.id"
|
|
25
|
+
:href="award.url || undefined"
|
|
26
|
+
:target="award.url ? '_blank' : undefined"
|
|
27
|
+
rel="noopener"
|
|
28
|
+
:class="['award-card', { 'no-link': !award.url }]"
|
|
29
|
+
>
|
|
30
|
+
<MGIcon icon="trophy" class="award-icon" />
|
|
31
|
+
<div class="award-info">
|
|
32
|
+
<span class="award-title">{{ award.title }}</span>
|
|
33
|
+
<span v-if="award.event || award.year" class="award-event">
|
|
34
|
+
{{ [award.event, award.year].filter(Boolean).join(' — ') }}
|
|
35
|
+
</span>
|
|
36
|
+
</div>
|
|
37
|
+
</a>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<style lang="scss" scoped>
|
|
43
|
+
.awards-section {
|
|
44
|
+
.section-title {
|
|
45
|
+
font-size: 1.2rem;
|
|
46
|
+
font-weight: 700;
|
|
47
|
+
color: #fff;
|
|
48
|
+
margin-bottom: 16px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.awards-grid {
|
|
52
|
+
display: grid;
|
|
53
|
+
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
|
54
|
+
gap: 12px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.award-card {
|
|
58
|
+
display: flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
gap: 14px;
|
|
61
|
+
background: #191B20;
|
|
62
|
+
border: 1px solid #1e2028;
|
|
63
|
+
padding: 16px;
|
|
64
|
+
text-decoration: none;
|
|
65
|
+
transition: background 0.2s, border-color 0.2s;
|
|
66
|
+
|
|
67
|
+
&:not(.no-link):hover {
|
|
68
|
+
background: #22252b;
|
|
69
|
+
border-color: #3a3d45;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&.no-link {
|
|
73
|
+
cursor: default;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.award-icon {
|
|
78
|
+
color: var(--color-primary, #FDB215);
|
|
79
|
+
font-size: 1.4rem;
|
|
80
|
+
flex-shrink: 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.award-info {
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: column;
|
|
86
|
+
gap: 2px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.award-title {
|
|
90
|
+
font-size: 0.95rem;
|
|
91
|
+
font-weight: 600;
|
|
92
|
+
color: #fff;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.award-event {
|
|
96
|
+
font-size: 0.8rem;
|
|
97
|
+
color: #888;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
</style>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
interface Credit {
|
|
3
|
+
id: number;
|
|
4
|
+
name: string;
|
|
5
|
+
role: string;
|
|
6
|
+
url?: string;
|
|
7
|
+
sort_order?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
credits: Credit[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
defineProps<Props>();
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<div v-if="credits.length" class="credits-section">
|
|
19
|
+
<h3 class="section-title">{{ $t('press_kit.credits') }}</h3>
|
|
20
|
+
<div class="credits-grid">
|
|
21
|
+
<div v-for="credit in credits" :key="credit.id" class="credit-item">
|
|
22
|
+
<span class="credit-role">{{ credit.role }}</span>
|
|
23
|
+
<a v-if="credit.url" :href="credit.url" target="_blank" rel="noopener" class="credit-name link">
|
|
24
|
+
{{ credit.name }}
|
|
25
|
+
</a>
|
|
26
|
+
<span v-else class="credit-name">{{ credit.name }}</span>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<style lang="scss" scoped>
|
|
33
|
+
.credits-section {
|
|
34
|
+
.section-title {
|
|
35
|
+
font-size: 1.2rem;
|
|
36
|
+
font-weight: 700;
|
|
37
|
+
color: #fff;
|
|
38
|
+
margin-bottom: 16px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.credits-grid {
|
|
42
|
+
display: grid;
|
|
43
|
+
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
44
|
+
gap: 16px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.credit-item {
|
|
48
|
+
background: #191B20;
|
|
49
|
+
border: 1px solid #1e2028;
|
|
50
|
+
padding: 16px;
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
gap: 4px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.credit-role {
|
|
57
|
+
font-size: 0.75rem;
|
|
58
|
+
color: #888;
|
|
59
|
+
text-transform: uppercase;
|
|
60
|
+
letter-spacing: 0.5px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.credit-name {
|
|
64
|
+
font-size: 0.95rem;
|
|
65
|
+
color: #fff;
|
|
66
|
+
font-weight: 500;
|
|
67
|
+
|
|
68
|
+
&.link {
|
|
69
|
+
color: #64D8FF;
|
|
70
|
+
text-decoration: none;
|
|
71
|
+
|
|
72
|
+
&:hover {
|
|
73
|
+
text-decoration: underline;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
</style>
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
kit: Record<string, any>;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const props = defineProps<Props>();
|
|
7
|
+
|
|
8
|
+
const facts = computed(() => {
|
|
9
|
+
const items: { label: string; value: string }[] = [];
|
|
10
|
+
const k = props.kit;
|
|
11
|
+
|
|
12
|
+
if (k.developer) items.push({ label: 'press_kit.developer', value: k.developer });
|
|
13
|
+
if (k.publisher) items.push({ label: 'press_kit.publisher_label', value: k.publisher });
|
|
14
|
+
if (k.release_date) items.push({ label: 'press_kit.release_date', value: k.release_date });
|
|
15
|
+
if (k.release_status) items.push({ label: 'press_kit.release_status', value: formatStatus(k.release_status) });
|
|
16
|
+
if (k.price) items.push({ label: 'press_kit.price', value: k.price });
|
|
17
|
+
if (k.monetization) items.push({ label: 'press_kit.monetization', value: formatMonetization(k.monetization) });
|
|
18
|
+
if (k.website_url) items.push({ label: 'press_kit.website', value: k.website_url });
|
|
19
|
+
if (k.press_contact_email) items.push({ label: 'press_kit.press_contact', value: k.press_contact_email });
|
|
20
|
+
|
|
21
|
+
return items;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const socialLinks = computed(() => {
|
|
25
|
+
if (!props.kit.social_links) return [];
|
|
26
|
+
const links = props.kit.social_links;
|
|
27
|
+
return Object.entries(links).filter(([, v]) => v).map(([key, url]) => ({ platform: key, url }));
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const storeLinks = computed(() => {
|
|
31
|
+
const links: { platform: string; url: string }[] = [];
|
|
32
|
+
if (props.kit.steam_url) links.push({ platform: 'Steam', url: props.kit.steam_url });
|
|
33
|
+
if (props.kit.epic_url) links.push({ platform: 'Epic Games', url: props.kit.epic_url });
|
|
34
|
+
return links;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
function formatStatus(status: string) {
|
|
38
|
+
return status.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function formatMonetization(m: string) {
|
|
42
|
+
return m.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
|
|
43
|
+
}
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<div class="fact-sheet">
|
|
48
|
+
<h3 class="section-title">{{ $t('press_kit.fact_sheet') }}</h3>
|
|
49
|
+
|
|
50
|
+
<div class="facts-list">
|
|
51
|
+
<div v-for="fact in facts" :key="fact.label" class="fact-item">
|
|
52
|
+
<span class="fact-label">{{ $t(fact.label) }}</span>
|
|
53
|
+
<span v-if="fact.value.startsWith('http')" class="fact-value">
|
|
54
|
+
<a :href="fact.value" target="_blank" rel="noopener">{{ fact.value }}</a>
|
|
55
|
+
</span>
|
|
56
|
+
<span v-else-if="fact.value.includes('@')" class="fact-value">
|
|
57
|
+
<a :href="`mailto:${fact.value}`">{{ fact.value }}</a>
|
|
58
|
+
</span>
|
|
59
|
+
<span v-else class="fact-value">{{ fact.value }}</span>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div v-if="kit.key_features?.length" class="key-features">
|
|
64
|
+
<h4>{{ $t('press_kit.key_features') }}</h4>
|
|
65
|
+
<ul>
|
|
66
|
+
<li v-for="(feature, idx) in kit.key_features" :key="idx">{{ feature }}</li>
|
|
67
|
+
</ul>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div v-if="storeLinks.length" class="store-links">
|
|
71
|
+
<h4>{{ $t('press_kit.available_on') }}</h4>
|
|
72
|
+
<div class="links-row">
|
|
73
|
+
<a v-for="link in storeLinks" :key="link.platform" :href="link.url" target="_blank" rel="noopener" class="store-badge">
|
|
74
|
+
{{ link.platform }}
|
|
75
|
+
</a>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div v-if="socialLinks.length" class="social-links">
|
|
80
|
+
<h4>{{ $t('press_kit.social_media') }}</h4>
|
|
81
|
+
<div class="links-row">
|
|
82
|
+
<a v-for="link in socialLinks" :key="link.platform" :href="link.url as string" target="_blank" rel="noopener" class="social-badge">
|
|
83
|
+
{{ link.platform }}
|
|
84
|
+
</a>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</template>
|
|
89
|
+
|
|
90
|
+
<style lang="scss" scoped>
|
|
91
|
+
.fact-sheet {
|
|
92
|
+
background: #191B20;
|
|
93
|
+
border: 1px solid #1e2028;
|
|
94
|
+
padding: 24px;
|
|
95
|
+
|
|
96
|
+
.section-title {
|
|
97
|
+
font-size: 1.2rem;
|
|
98
|
+
font-weight: 700;
|
|
99
|
+
color: var(--color-primary, #FDB215);
|
|
100
|
+
margin-bottom: 20px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.facts-list {
|
|
104
|
+
display: flex;
|
|
105
|
+
flex-direction: column;
|
|
106
|
+
gap: 12px;
|
|
107
|
+
margin-bottom: 24px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.fact-item {
|
|
111
|
+
display: flex;
|
|
112
|
+
flex-direction: column;
|
|
113
|
+
gap: 2px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.fact-label {
|
|
117
|
+
font-size: 0.75rem;
|
|
118
|
+
color: #888;
|
|
119
|
+
text-transform: uppercase;
|
|
120
|
+
letter-spacing: 0.5px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.fact-value {
|
|
124
|
+
font-size: 0.95rem;
|
|
125
|
+
color: #fff;
|
|
126
|
+
|
|
127
|
+
a {
|
|
128
|
+
color: #64D8FF;
|
|
129
|
+
text-decoration: none;
|
|
130
|
+
word-break: break-all;
|
|
131
|
+
|
|
132
|
+
&:hover {
|
|
133
|
+
text-decoration: underline;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.key-features {
|
|
139
|
+
margin-bottom: 24px;
|
|
140
|
+
|
|
141
|
+
h4 {
|
|
142
|
+
font-size: 0.9rem;
|
|
143
|
+
font-weight: 600;
|
|
144
|
+
color: #fff;
|
|
145
|
+
margin-bottom: 8px;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
ul {
|
|
149
|
+
list-style: none;
|
|
150
|
+
padding: 0;
|
|
151
|
+
margin: 0;
|
|
152
|
+
|
|
153
|
+
li {
|
|
154
|
+
padding: 6px 0;
|
|
155
|
+
color: #ccc;
|
|
156
|
+
font-size: 0.9rem;
|
|
157
|
+
border-bottom: 1px solid #2a2d35;
|
|
158
|
+
|
|
159
|
+
&:last-child {
|
|
160
|
+
border-bottom: none;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
&::before {
|
|
164
|
+
content: '•';
|
|
165
|
+
color: var(--color-primary, #FDB215);
|
|
166
|
+
margin-right: 8px;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.store-links, .social-links {
|
|
173
|
+
margin-bottom: 16px;
|
|
174
|
+
|
|
175
|
+
h4 {
|
|
176
|
+
font-size: 0.9rem;
|
|
177
|
+
font-weight: 600;
|
|
178
|
+
color: #fff;
|
|
179
|
+
margin-bottom: 8px;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.links-row {
|
|
184
|
+
display: flex;
|
|
185
|
+
flex-wrap: wrap;
|
|
186
|
+
gap: 8px;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.store-badge, .social-badge {
|
|
190
|
+
display: inline-block;
|
|
191
|
+
padding: 6px 14px;
|
|
192
|
+
background: #2a2d35;
|
|
193
|
+
border: 1px solid #3a3d45;
|
|
194
|
+
color: #fff;
|
|
195
|
+
font-size: 0.85rem;
|
|
196
|
+
text-decoration: none;
|
|
197
|
+
transition: background 0.2s;
|
|
198
|
+
|
|
199
|
+
&:hover {
|
|
200
|
+
background: #3a3d45;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
</style>
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
name: string;
|
|
4
|
+
tagline?: string;
|
|
5
|
+
heroImageUrl?: string;
|
|
6
|
+
logoUrl?: string;
|
|
7
|
+
trailerUrl?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const props = defineProps<Props>();
|
|
11
|
+
|
|
12
|
+
const showTrailer = ref(false);
|
|
13
|
+
|
|
14
|
+
const youtubeEmbedUrl = computed(() => {
|
|
15
|
+
if (!props.trailerUrl) return null;
|
|
16
|
+
const match = props.trailerUrl.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/)([\w-]+)/);
|
|
17
|
+
if (match) return `https://www.youtube.com/embed/${match[1]}?autoplay=1`;
|
|
18
|
+
return props.trailerUrl;
|
|
19
|
+
});
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<div class="press-kit-hero">
|
|
24
|
+
<div class="hero-banner" :style="heroImageUrl ? { backgroundImage: `url(${heroImageUrl})` } : {}">
|
|
25
|
+
<div class="hero-overlay">
|
|
26
|
+
<img v-if="logoUrl" :src="logoUrl" :alt="name" class="hero-logo" />
|
|
27
|
+
<h1 v-else class="hero-title">{{ name }}</h1>
|
|
28
|
+
<p v-if="tagline" class="hero-tagline">{{ tagline }}</p>
|
|
29
|
+
<button v-if="trailerUrl" class="btn-trailer" @click="showTrailer = true">
|
|
30
|
+
<MGIcon icon="play" /> {{ $t('press_kit.watch_trailer') }}
|
|
31
|
+
</button>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div v-if="showTrailer" class="trailer-modal" @click.self="showTrailer = false">
|
|
36
|
+
<div class="trailer-wrapper">
|
|
37
|
+
<button class="btn-close-trailer" @click="showTrailer = false">×</button>
|
|
38
|
+
<iframe
|
|
39
|
+
v-if="youtubeEmbedUrl"
|
|
40
|
+
:src="youtubeEmbedUrl"
|
|
41
|
+
frameborder="0"
|
|
42
|
+
allow="autoplay; encrypted-media"
|
|
43
|
+
allowfullscreen
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<style lang="scss" scoped>
|
|
51
|
+
.press-kit-hero {
|
|
52
|
+
.hero-banner {
|
|
53
|
+
position: relative;
|
|
54
|
+
height: 400px;
|
|
55
|
+
background-size: cover;
|
|
56
|
+
background-position: center;
|
|
57
|
+
background-color: #191B20;
|
|
58
|
+
overflow: hidden;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.hero-overlay {
|
|
62
|
+
position: absolute;
|
|
63
|
+
inset: 0;
|
|
64
|
+
background: linear-gradient(to top, rgba(0, 0, 0, 0.85) 0%, rgba(0, 0, 0, 0.3) 100%);
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
justify-content: flex-end;
|
|
68
|
+
align-items: flex-start;
|
|
69
|
+
padding: 40px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.hero-logo {
|
|
73
|
+
max-height: 80px;
|
|
74
|
+
max-width: 300px;
|
|
75
|
+
object-fit: contain;
|
|
76
|
+
margin-bottom: 12px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.hero-title {
|
|
80
|
+
font-size: 2.5rem;
|
|
81
|
+
font-weight: 700;
|
|
82
|
+
color: #fff;
|
|
83
|
+
margin-bottom: 8px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.hero-tagline {
|
|
87
|
+
font-size: 1.1rem;
|
|
88
|
+
color: #ccc;
|
|
89
|
+
margin-bottom: 16px;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.btn-trailer {
|
|
93
|
+
background: var(--color-primary, #FDB215);
|
|
94
|
+
color: #13161C;
|
|
95
|
+
border: none;
|
|
96
|
+
padding: 10px 24px;
|
|
97
|
+
font-weight: 600;
|
|
98
|
+
font-size: 0.95rem;
|
|
99
|
+
cursor: pointer;
|
|
100
|
+
display: flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
gap: 8px;
|
|
103
|
+
transition: opacity 0.2s;
|
|
104
|
+
|
|
105
|
+
&:hover {
|
|
106
|
+
opacity: 0.85;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.trailer-modal {
|
|
111
|
+
position: fixed;
|
|
112
|
+
inset: 0;
|
|
113
|
+
background: rgba(0, 0, 0, 0.9);
|
|
114
|
+
z-index: 9999;
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
justify-content: center;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.trailer-wrapper {
|
|
121
|
+
position: relative;
|
|
122
|
+
width: 80vw;
|
|
123
|
+
max-width: 900px;
|
|
124
|
+
aspect-ratio: 16 / 9;
|
|
125
|
+
|
|
126
|
+
iframe {
|
|
127
|
+
width: 100%;
|
|
128
|
+
height: 100%;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.btn-close-trailer {
|
|
133
|
+
position: absolute;
|
|
134
|
+
top: -40px;
|
|
135
|
+
right: 0;
|
|
136
|
+
background: none;
|
|
137
|
+
border: none;
|
|
138
|
+
color: #fff;
|
|
139
|
+
font-size: 2rem;
|
|
140
|
+
cursor: pointer;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
</style>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
interface Quote {
|
|
3
|
+
id: number;
|
|
4
|
+
quote: string;
|
|
5
|
+
source: string;
|
|
6
|
+
source_url?: string;
|
|
7
|
+
sort_order?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
quotes: Quote[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
defineProps<Props>();
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<div v-if="quotes.length" class="quotes-section">
|
|
19
|
+
<h3 class="section-title">{{ $t('press_kit.quotes') }}</h3>
|
|
20
|
+
<div class="quotes-list">
|
|
21
|
+
<blockquote v-for="q in quotes" :key="q.id" class="quote-card">
|
|
22
|
+
<p class="quote-text">“{{ q.quote }}”</p>
|
|
23
|
+
<footer class="quote-source">
|
|
24
|
+
—
|
|
25
|
+
<a v-if="q.source_url" :href="q.source_url" target="_blank" rel="noopener">{{ q.source }}</a>
|
|
26
|
+
<span v-else>{{ q.source }}</span>
|
|
27
|
+
</footer>
|
|
28
|
+
</blockquote>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<style lang="scss" scoped>
|
|
34
|
+
.quotes-section {
|
|
35
|
+
.section-title {
|
|
36
|
+
font-size: 1.2rem;
|
|
37
|
+
font-weight: 700;
|
|
38
|
+
color: #fff;
|
|
39
|
+
margin-bottom: 16px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.quotes-list {
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
gap: 16px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.quote-card {
|
|
49
|
+
background: #191B20;
|
|
50
|
+
border-left: 3px solid var(--color-primary, #FDB215);
|
|
51
|
+
border-top: 1px solid #1e2028;
|
|
52
|
+
border-right: 1px solid #1e2028;
|
|
53
|
+
border-bottom: 1px solid #1e2028;
|
|
54
|
+
padding: 20px 24px;
|
|
55
|
+
margin: 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.quote-text {
|
|
59
|
+
font-size: 1rem;
|
|
60
|
+
color: #ddd;
|
|
61
|
+
line-height: 1.6;
|
|
62
|
+
font-style: italic;
|
|
63
|
+
margin-bottom: 12px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.quote-source {
|
|
67
|
+
font-size: 0.85rem;
|
|
68
|
+
color: #888;
|
|
69
|
+
|
|
70
|
+
a {
|
|
71
|
+
color: #64D8FF;
|
|
72
|
+
text-decoration: none;
|
|
73
|
+
|
|
74
|
+
&:hover {
|
|
75
|
+
text-decoration: underline;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
</style>
|