@mundogamernetwork/shared-ui 1.4.1 → 1.4.2
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/assets/kit/kit-base.css +88 -0
- package/package.json +1 -1
- package/pages/presskit/game/[slug].vue +146 -0
package/assets/kit/kit-base.css
CHANGED
|
@@ -890,6 +890,94 @@ body:has(.kit-press) {
|
|
|
890
890
|
margin-top: 32px;
|
|
891
891
|
}
|
|
892
892
|
|
|
893
|
+
/* ── Press Kit's own key request flow (separate from the KeyBrowser
|
|
894
|
+
ecosystem widget) — auth wall, status states, and the request form. ── */
|
|
895
|
+
.kit-keys-mode-note {
|
|
896
|
+
font-size: 0.78rem;
|
|
897
|
+
color: var(--kit-muted, #8b92a0);
|
|
898
|
+
margin: -8px 0 0;
|
|
899
|
+
}
|
|
900
|
+
.kit-keys-loading {
|
|
901
|
+
height: 80px;
|
|
902
|
+
background: var(--kit-card, #1a1e27);
|
|
903
|
+
animation: kit-pulse 1.5s ease-in-out infinite;
|
|
904
|
+
}
|
|
905
|
+
@keyframes kit-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
|
|
906
|
+
.kit-keys-authwall,
|
|
907
|
+
.kit-keys-status {
|
|
908
|
+
display: flex;
|
|
909
|
+
flex-direction: column;
|
|
910
|
+
gap: 12px;
|
|
911
|
+
padding: 20px;
|
|
912
|
+
background: var(--kit-card, #1a1e27);
|
|
913
|
+
border: 1px solid var(--kit-line, #252a34);
|
|
914
|
+
}
|
|
915
|
+
.kit-keys-status p { margin: 0; color: var(--kit-text, #f4f6fa); font-size: 0.9rem; }
|
|
916
|
+
.kit-keys-status.status-rejected p { color: var(--kit-muted, #8b92a0); }
|
|
917
|
+
.kit-keys-code {
|
|
918
|
+
display: flex;
|
|
919
|
+
align-items: center;
|
|
920
|
+
gap: 12px;
|
|
921
|
+
flex-wrap: wrap;
|
|
922
|
+
}
|
|
923
|
+
.kit-keys-code code {
|
|
924
|
+
padding: 10px 16px;
|
|
925
|
+
background: var(--kit-bg, #13161c);
|
|
926
|
+
border: 1px dashed var(--kit-accent, #FDB215);
|
|
927
|
+
color: var(--kit-accent, #FDB215);
|
|
928
|
+
font-size: 0.95rem;
|
|
929
|
+
letter-spacing: 1px;
|
|
930
|
+
}
|
|
931
|
+
.kit-keys-form {
|
|
932
|
+
display: flex;
|
|
933
|
+
flex-direction: column;
|
|
934
|
+
gap: 14px;
|
|
935
|
+
}
|
|
936
|
+
.kit-keys-row {
|
|
937
|
+
display: flex;
|
|
938
|
+
gap: 14px;
|
|
939
|
+
flex-wrap: wrap;
|
|
940
|
+
}
|
|
941
|
+
.kit-keys-field {
|
|
942
|
+
display: flex;
|
|
943
|
+
flex-direction: column;
|
|
944
|
+
gap: 6px;
|
|
945
|
+
flex: 1;
|
|
946
|
+
min-width: 160px;
|
|
947
|
+
}
|
|
948
|
+
.kit-keys-field label {
|
|
949
|
+
font-size: 0.75rem;
|
|
950
|
+
text-transform: uppercase;
|
|
951
|
+
letter-spacing: 1px;
|
|
952
|
+
color: var(--kit-muted, #8b92a0);
|
|
953
|
+
}
|
|
954
|
+
.kit-keys-field select,
|
|
955
|
+
.kit-keys-field textarea {
|
|
956
|
+
background: var(--kit-card, #1a1e27);
|
|
957
|
+
border: 1px solid var(--kit-line, #252a34);
|
|
958
|
+
color: var(--kit-text, #f4f6fa);
|
|
959
|
+
padding: 10px 12px;
|
|
960
|
+
font-size: 0.9rem;
|
|
961
|
+
font-family: inherit;
|
|
962
|
+
resize: vertical;
|
|
963
|
+
}
|
|
964
|
+
.kit-keys-field select:focus,
|
|
965
|
+
.kit-keys-field textarea:focus {
|
|
966
|
+
outline: none;
|
|
967
|
+
border-color: var(--kit-accent, #FDB215);
|
|
968
|
+
}
|
|
969
|
+
.kit-keys-hint {
|
|
970
|
+
font-size: 0.75rem;
|
|
971
|
+
color: var(--kit-muted, #8b92a0);
|
|
972
|
+
}
|
|
973
|
+
.kit-keys-error {
|
|
974
|
+
font-size: 0.82rem;
|
|
975
|
+
color: #e74c3c;
|
|
976
|
+
}
|
|
977
|
+
.kit-keys-form .kit-btn {
|
|
978
|
+
align-self: flex-start;
|
|
979
|
+
}
|
|
980
|
+
|
|
893
981
|
/* ── Responsive ─────────────────────────────────────────────────────*/
|
|
894
982
|
@media (max-width: 900px) {
|
|
895
983
|
.kit-layout {
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { trackPressKitEvent } from '../../../services/pressKitService';
|
|
3
|
+
import { mgApiUrl } from '../../../services/httpService';
|
|
3
4
|
|
|
4
5
|
definePageMeta({ layout: 'blank' });
|
|
5
6
|
|
|
6
7
|
const route = useRoute();
|
|
7
8
|
const slug = route.params.slug as string;
|
|
9
|
+
const { t } = useI18n();
|
|
8
10
|
|
|
9
11
|
const runtimeConfig = useRuntimeConfig();
|
|
10
12
|
const cfg = (runtimeConfig.public?.mgSharedUi || {}) as Record<string, any>;
|
|
@@ -93,6 +95,80 @@ function onPoolsReady(count: number) {
|
|
|
93
95
|
keyPoolsVisible.value = count > 0;
|
|
94
96
|
}
|
|
95
97
|
|
|
98
|
+
// ── Press Kit's own key request flow ────────────────────────────────────────
|
|
99
|
+
// Deliberately separate from the KeyBrowser widget above (that's the
|
|
100
|
+
// ecosystem-wide Key Campaigns product). This talks to the Press-Kit-specific
|
|
101
|
+
// pool/request endpoints and respects the studio's own `keys_public` setting
|
|
102
|
+
// (instant auto-delivery vs. manual review, configured in the dashboard).
|
|
103
|
+
const KEY_REQUEST_PLATFORMS = ['steam', 'epic', 'gog', 'xbox', 'psn', 'other'];
|
|
104
|
+
const KEY_REQUEST_REGIONS = ['worldwide', 'NA', 'EU', 'BR', 'LATAM', 'APAC', 'other'];
|
|
105
|
+
|
|
106
|
+
const requestForm = ref({ platform: 'steam', region: 'worldwide', objectives: '' });
|
|
107
|
+
const myKeyRequest = ref<any>(null);
|
|
108
|
+
const keyRequestLoaded = ref(false);
|
|
109
|
+
const keyRequestAuthed = ref(true);
|
|
110
|
+
const keyRequestSubmitting = ref(false);
|
|
111
|
+
const keyRequestError = ref('');
|
|
112
|
+
const keyCopied = ref(false);
|
|
113
|
+
|
|
114
|
+
const showOwnKeySection = computed(() => !!kit.value?.has_available_keys || !!myKeyRequest.value);
|
|
115
|
+
|
|
116
|
+
async function loadMyKeyRequest() {
|
|
117
|
+
try {
|
|
118
|
+
const res: any = await $fetch(`${apiBase}/public/press-kits/${slug}/my-request`, { credentials: 'include' });
|
|
119
|
+
myKeyRequest.value = res?.data || null;
|
|
120
|
+
} catch (err: any) {
|
|
121
|
+
if (err?.statusCode === 401 || err?.response?.status === 401) keyRequestAuthed.value = false;
|
|
122
|
+
} finally {
|
|
123
|
+
keyRequestLoaded.value = true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function redirectToKeyLogin() {
|
|
128
|
+
window.location.href = mgApiUrl('login') + '?redirect_to=' + encodeURIComponent(window.location.href);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function submitOwnKeyRequest() {
|
|
132
|
+
if (!keyRequestAuthed.value) {
|
|
133
|
+
redirectToKeyLogin();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
keyRequestError.value = '';
|
|
137
|
+
keyRequestSubmitting.value = true;
|
|
138
|
+
try {
|
|
139
|
+
await $fetch(`${apiBase}/public/press-kits/${slug}/request-key`, {
|
|
140
|
+
method: 'POST',
|
|
141
|
+
credentials: 'include',
|
|
142
|
+
body: {
|
|
143
|
+
platform: requestForm.value.platform,
|
|
144
|
+
region: requestForm.value.region,
|
|
145
|
+
objectives: requestForm.value.objectives,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
await loadMyKeyRequest();
|
|
149
|
+
} catch (err: any) {
|
|
150
|
+
if (err?.statusCode === 401 || err?.response?.status === 401) {
|
|
151
|
+
keyRequestAuthed.value = false;
|
|
152
|
+
} else {
|
|
153
|
+
keyRequestError.value = err?.data?.message || t('kit.press.request_own_key_error');
|
|
154
|
+
}
|
|
155
|
+
} finally {
|
|
156
|
+
keyRequestSubmitting.value = false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function copyKeyCode(code: string) {
|
|
161
|
+
try {
|
|
162
|
+
await navigator.clipboard.writeText(code);
|
|
163
|
+
keyCopied.value = true;
|
|
164
|
+
setTimeout(() => { keyCopied.value = false; }, 2000);
|
|
165
|
+
} catch {}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
onMounted(() => {
|
|
169
|
+
if (kit.value?.id) loadMyKeyRequest();
|
|
170
|
+
});
|
|
171
|
+
|
|
96
172
|
// Scroll state for sticky CTA + back-to-top
|
|
97
173
|
const scrolled = ref(false);
|
|
98
174
|
let heroHeight = 0;
|
|
@@ -426,6 +502,76 @@ useHead(() => ({
|
|
|
426
502
|
/>
|
|
427
503
|
</section>
|
|
428
504
|
|
|
505
|
+
<!-- Press Kit's own key request flow — separate product from the
|
|
506
|
+
KeyBrowser ecosystem widget above. Respects the studio's own
|
|
507
|
+
keys_public setting (instant auto-delivery vs. manual review). -->
|
|
508
|
+
<section v-if="showOwnKeySection" id="request-key" class="kit-block kit-keys-section">
|
|
509
|
+
<h2 class="kit-keys-title">{{ $t('kit.press.request_own_key_title') }}</h2>
|
|
510
|
+
<p class="kit-keys-desc">{{ $t('kit.press.request_own_key_desc') }}</p>
|
|
511
|
+
<p class="kit-keys-mode-note">
|
|
512
|
+
{{ kit.keys_public ? $t('kit.press.request_own_key_public_note') : $t('kit.press.request_own_key_moderated_note') }}
|
|
513
|
+
</p>
|
|
514
|
+
|
|
515
|
+
<div v-if="!keyRequestLoaded" class="kit-keys-loading" />
|
|
516
|
+
|
|
517
|
+
<template v-else>
|
|
518
|
+
<div v-if="!keyRequestAuthed && !myKeyRequest" class="kit-keys-authwall">
|
|
519
|
+
<p>{{ $t('kit.press.request_own_key_login_required') }}</p>
|
|
520
|
+
<button type="button" class="kit-btn kit-btn-primary" @click="redirectToKeyLogin">
|
|
521
|
+
{{ $t('kit.press.request_own_key_login_btn') }}
|
|
522
|
+
</button>
|
|
523
|
+
</div>
|
|
524
|
+
|
|
525
|
+
<div v-else-if="myKeyRequest" class="kit-keys-status" :class="`status-${myKeyRequest.status}`">
|
|
526
|
+
<p v-if="myKeyRequest.status === 'pending'">{{ $t('kit.press.request_own_key_status_pending') }}</p>
|
|
527
|
+
<template v-else-if="myKeyRequest.status === 'approved'">
|
|
528
|
+
<p>{{ $t('kit.press.request_own_key_status_approved') }}</p>
|
|
529
|
+
<div class="kit-keys-code">
|
|
530
|
+
<code>{{ myKeyRequest.key }}</code>
|
|
531
|
+
<button type="button" class="kit-btn kit-btn-ghost kit-btn-sm" @click="copyKeyCode(myKeyRequest.key)">
|
|
532
|
+
{{ keyCopied ? $t('kit.press.request_own_key_copied') : $t('kit.press.request_own_key_copy') }}
|
|
533
|
+
</button>
|
|
534
|
+
</div>
|
|
535
|
+
</template>
|
|
536
|
+
<p v-else-if="myKeyRequest.status === 'rejected'">{{ $t('kit.press.request_own_key_status_rejected') }}</p>
|
|
537
|
+
</div>
|
|
538
|
+
|
|
539
|
+
<form v-else class="kit-keys-form" @submit.prevent="submitOwnKeyRequest">
|
|
540
|
+
<div class="kit-keys-row">
|
|
541
|
+
<div class="kit-keys-field">
|
|
542
|
+
<label>{{ $t('kit.press.request_own_key_platform') }}</label>
|
|
543
|
+
<select v-model="requestForm.platform">
|
|
544
|
+
<option v-for="p in KEY_REQUEST_PLATFORMS" :key="p" :value="p">{{ p }}</option>
|
|
545
|
+
</select>
|
|
546
|
+
</div>
|
|
547
|
+
<div class="kit-keys-field">
|
|
548
|
+
<label>{{ $t('kit.press.request_own_key_region') }}</label>
|
|
549
|
+
<select v-model="requestForm.region">
|
|
550
|
+
<option v-for="r in KEY_REQUEST_REGIONS" :key="r" :value="r">{{ r }}</option>
|
|
551
|
+
</select>
|
|
552
|
+
</div>
|
|
553
|
+
</div>
|
|
554
|
+
<div class="kit-keys-field">
|
|
555
|
+
<label>{{ $t('kit.press.request_own_key_objectives') }}</label>
|
|
556
|
+
<textarea
|
|
557
|
+
v-model="requestForm.objectives"
|
|
558
|
+
rows="3"
|
|
559
|
+
:placeholder="$t('kit.press.request_own_key_objectives_placeholder')"
|
|
560
|
+
/>
|
|
561
|
+
<span class="kit-keys-hint">{{ $t('kit.press.request_own_key_objectives_hint') }}</span>
|
|
562
|
+
</div>
|
|
563
|
+
<div v-if="keyRequestError" class="kit-keys-error">{{ keyRequestError }}</div>
|
|
564
|
+
<button
|
|
565
|
+
type="submit"
|
|
566
|
+
class="kit-btn kit-btn-primary"
|
|
567
|
+
:disabled="keyRequestSubmitting || requestForm.objectives.trim().length < 20"
|
|
568
|
+
>
|
|
569
|
+
{{ keyRequestSubmitting ? $t('kit.press.request_own_key_submitting') : $t('kit.press.request_own_key_submit') }}
|
|
570
|
+
</button>
|
|
571
|
+
</form>
|
|
572
|
+
</template>
|
|
573
|
+
</section>
|
|
574
|
+
|
|
429
575
|
<section v-if="kit.press_contact_email" id="contact" class="kit-block">
|
|
430
576
|
<div class="kit-cta">
|
|
431
577
|
<h2>{{ $t('kit.press.covering', { name: kit.name }) }}</h2>
|