@mundogamernetwork/shared-ui 1.8.4 → 1.8.6

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.
@@ -4,6 +4,7 @@ import MuralCanvas from './MuralCanvas.vue'
4
4
  import SupportStepper from './SupportStepper.vue'
5
5
 
6
6
  const props = defineProps<{ userId: number | string }>()
7
+ const emit = defineEmits<{ (e: 'wall-status', hasWall: boolean): void }>()
7
8
  const localePath = useLocalePath()
8
9
  const authStore = useAuthStore()
9
10
  const { locale } = useI18n()
@@ -102,8 +103,12 @@ async function load() {
102
103
  const res = await fetchStreamerActiveWalls(props.userId)
103
104
  const list = res.data?.data ?? res.data ?? []
104
105
  const first = Array.isArray(list) ? list.find((w: any) => w.show_on_media_kit) ?? list[0] : null
105
- if (!first) return
106
+ if (!first) {
107
+ emit('wall-status', false)
108
+ return
109
+ }
106
110
  wall.value = first
111
+ emit('wall-status', true)
107
112
  const [goalsRes, supRes] = await Promise.all([
108
113
  fetchPublicWallGoals(first.slug || first.id).catch(() => ({ data: { data: [] } })),
109
114
  getWallSupporters(first.slug || first.id, { per_page: 500 }),
@@ -112,6 +117,7 @@ async function load() {
112
117
  supporters.value = (supRes.data?.data ?? []).filter((p: any) => p.status)
113
118
  } catch {
114
119
  // no wall — renders nothing
120
+ emit('wall-status', false)
115
121
  } finally {
116
122
  loading.value = false
117
123
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mundogamernetwork/shared-ui",
3
- "version": "1.8.4",
3
+ "version": "1.8.6",
4
4
  "description": "Mundo Gamer Network - Shared UI Layer (Nuxt 3)",
5
5
  "type": "module",
6
6
  "main": "./nuxt.config.ts",
@@ -196,6 +196,12 @@
196
196
  </div>
197
197
 
198
198
  <div class="text">
199
+ <div class="card-name">{{ card.gameName || card.text }}</div>
200
+ <div v-if="card.studioName || card.regions.length" class="card-studio-row">
201
+ <span v-if="card.studioName" class="card-studio-name">{{ card.studioName }}</span>
202
+ <span v-if="card.studioName && card.regions.length" class="card-studio-sep">·</span>
203
+ <span v-if="card.regions.length">{{ card.regions.slice(0, 2).join(", ") }}</span>
204
+ </div>
199
205
  <div class="card-meta-row">
200
206
  <div class="days" v-if="card.time > 0 && card.user_can_access">
201
207
  <span>{{ card.time }}</span> {{ $t("keys.campaigns.days") }}
@@ -208,11 +214,17 @@
208
214
  </span>
209
215
  </div>
210
216
  <div v-if="card.platforms && card.platforms.length" class="card-platforms">
211
- <span v-for="p in card.platforms" :key="p" class="card-platform-tag">
217
+ <span v-for="p in card.platforms.slice(0, 4)" :key="p" class="card-platform-tag">
212
218
  {{ platformAbbr(p) }}
213
219
  </span>
220
+ <span v-if="card.platforms.length > 4" class="card-platform-tag card-platform-more">
221
+ +{{ card.platforms.length - 4 }}
222
+ </span>
223
+ </div>
224
+ <div v-if="card.available_count > 0 && card.user_can_access && !card.isExpired && !card.isUpcoming" class="card-availability">
225
+ {{ $t("keys.campaigns.keys_left", { n: card.available_count }) }}
214
226
  </div>
215
- {{ card.text }}
227
+ <div v-if="card.gameName && card.gameName !== card.text" class="card-campaign-name">{{ card.text }}</div>
216
228
 
217
229
  <div class="buttons">
218
230
  <template v-if="!card.user_can_access">
@@ -609,6 +621,8 @@ async function loadCampaigns(page = 1) {
609
621
  max_keys_for_user: item.max_keys_for_user || 1,
610
622
  platforms: (item.platforms || []).map((p: any) => p.name),
611
623
  gameName: item.game?.name || null,
624
+ studioName: item.company?.name || null,
625
+ regions: (item.regions || []).map((r: any) => r.name).filter(Boolean),
612
626
  userRequestSlug: null,
613
627
  }
614
628
  })
@@ -1204,12 +1218,54 @@ onUnmounted(() => {
1204
1218
  max-height: 174px;
1205
1219
  min-height: 174px;
1206
1220
  overflow: hidden;
1221
+ background: var(--body-bg-card, #101012);
1222
+ display: flex;
1223
+ align-items: center;
1224
+ justify-content: center;
1207
1225
  img { width: 100%; height: auto; display: flex; }
1226
+ // The no-cover fallback is a small centered logo, not a
1227
+ // banner — stretching it to 100% width (the normal-cover
1228
+ // rule above) distorts it badly. Contain it instead.
1229
+ &:has(img[src$="no-cover-img.jpg"]) img {
1230
+ width: 40%;
1231
+ height: auto;
1232
+ max-height: 60%;
1233
+ object-fit: contain;
1234
+ }
1208
1235
  }
1209
1236
  }
1210
1237
  }
1211
1238
 
1212
1239
  .text {
1240
+ min-height: 210px;
1241
+
1242
+ .card-name {
1243
+ font-size: 16px;
1244
+ font-weight: 700;
1245
+ color: var(--title-fg);
1246
+ }
1247
+
1248
+ .card-studio-row {
1249
+ font-size: 12px;
1250
+ color: var(--secondary-info-fg);
1251
+ font-weight: 400;
1252
+ display: flex;
1253
+ align-items: center;
1254
+ gap: 6px;
1255
+ }
1256
+
1257
+ .card-availability {
1258
+ font-size: 12px;
1259
+ color: var(--key-accent, var(--primary, #D297FF));
1260
+ font-weight: 600;
1261
+ }
1262
+
1263
+ .card-campaign-name {
1264
+ font-size: 13px;
1265
+ font-weight: 400;
1266
+ color: var(--secondary-info-fg);
1267
+ }
1268
+
1213
1269
  .card-meta-row {
1214
1270
  display: flex;
1215
1271
  align-items: center;
@@ -1254,6 +1310,10 @@ onUnmounted(() => {
1254
1310
  color: var(--secondary-info-fg);
1255
1311
  text-transform: uppercase;
1256
1312
  }
1313
+ .card-platform-more {
1314
+ border-style: dashed;
1315
+ opacity: 0.8;
1316
+ }
1257
1317
  }
1258
1318
 
1259
1319
  .buttons {
@@ -32,6 +32,7 @@ const loading = ref(true);
32
32
  const error = ref(false);
33
33
 
34
34
  const userId = computed(() => kit.value?.user_id);
35
+ const hasMural = ref(false);
35
36
  const influencerProId = computed<number | null>(() => kit.value?.influencer_professional_info_id ?? null);
36
37
  const isOwnKit = computed(() => !!authStore.user?.id && !!userId.value && String(authStore.user.id) === String(userId.value));
37
38
  const showShortlistBar = computed(() =>
@@ -73,6 +74,7 @@ const portfolioImages = computed(() => kit.value?.portfolio_images ?? streamer.v
73
74
  const brandLogos = computed(() => kit.value?.brand_logos ?? streamer.value?.brand_logos ?? []);
74
75
  const creatorStore = computed(() => kit.value?.creator_store ?? null);
75
76
  const customLinks = computed(() => kit.value?.custom_links ?? streamer.value?.custom_links ?? []);
77
+ const websiteUrl = computed<string | null>(() => streamer.value?.website ?? null);
76
78
 
77
79
  // ── D2 ecosystem data ──
78
80
  const selectedGames = computed<string[]>(() => kit.value?.selected_games ?? []);
@@ -253,7 +255,9 @@ function onDownload() {
253
255
  <div v-else-if="error || !kit" class="kit-state"><p>{{ $t('kit.media.not_available') }}</p></div>
254
256
 
255
257
  <template v-else>
256
- <div class="mk-cover" :class="{ 'has-image': coverUrl }" :style="coverStyle" />
258
+ <div class="mk-cover" :class="{ 'has-image': coverUrl }" :style="coverStyle">
259
+ <span v-if="!coverUrl" class="mk-cover-brand">MUNDO GAMER AGENCY</span>
260
+ </div>
257
261
 
258
262
  <div class="kit-wrap mk-layout">
259
263
  <!-- ══════════════ SIDEBAR ══════════════ -->
@@ -290,9 +294,12 @@ function onDownload() {
290
294
  </div>
291
295
 
292
296
  <!-- Personal link hub: replaces a separate link-in-bio service. -->
293
- <nav v-if="customLinks.length || tvChannelUrl || creatorStore || userId" class="mk-link-hub no-print" data-sec="links" :aria-label="$t('kit.media.quick_links')">
297
+ <nav v-if="customLinks.length || tvChannelUrl || websiteUrl || creatorStore || hasMural" class="mk-link-hub no-print" data-sec="links" :aria-label="$t('kit.media.quick_links')">
294
298
  <a v-if="tvChannelUrl" class="mk-link mk-link--tv" :href="tvChannelUrl" target="_blank" rel="noopener" @click="track('click')">
295
- <span>📺 {{ $t('kit.media.tv_channel') }}</span><b>↗</b>
299
+ <span>{{ $t('kit.media.tv_channel') }}</span><b>↗</b>
300
+ </a>
301
+ <a v-if="websiteUrl" class="mk-link" :href="websiteUrl" target="_blank" rel="noopener" @click="track('click')">
302
+ <span>{{ $t('kit.media.official_site') }}</span><b>↗</b>
296
303
  </a>
297
304
  <a v-for="(link, index) in customLinks" :key="`${link.url}-${index}`" class="mk-link" :href="link.url" target="_blank" rel="noopener" @click="track('click')">
298
305
  <span>{{ link.label }}</span><b>↗</b>
@@ -300,7 +307,7 @@ function onDownload() {
300
307
  <a v-if="creatorStore" class="mk-link" href="#store" @click="track('click')">
301
308
  <span>{{ $t('kit.media.visit_store') }}</span><b>↓</b>
302
309
  </a>
303
- <a v-if="userId" class="mk-link" href="#support" @click="track('click')">
310
+ <a v-if="hasMural" class="mk-link" href="#support" @click="track('click')">
304
311
  <span>{{ $t('kit.media.visit_mural') }}</span><b>↓</b>
305
312
  </a>
306
313
  </nav>
@@ -538,7 +545,7 @@ function onDownload() {
538
545
  </section>
539
546
 
540
547
  <section v-if="userId" id="support" class="kit-block" data-sec="support">
541
- <MediaKitWallBlock :user-id="userId" />
548
+ <MediaKitWallBlock :user-id="userId" @wall-status="hasMural = $event" />
542
549
  </section>
543
550
 
544
551
  <footer class="mk-footer">
@@ -589,6 +596,22 @@ function onDownload() {
589
596
  }
590
597
  }
591
598
 
599
+ .mk-cover-brand {
600
+ position: absolute;
601
+ top: 20px;
602
+ right: 24px;
603
+ font-family: 'Rajdhani', sans-serif;
604
+ font-weight: 700;
605
+ font-size: 13px;
606
+ letter-spacing: 3px;
607
+ color: rgba(255, 255, 255, .55);
608
+ pointer-events: none;
609
+
610
+ @media (max-width: 640px) {
611
+ display: none;
612
+ }
613
+ }
614
+
592
615
  /* ── Layout: sidebar + main ── */
593
616
  .mk-layout {
594
617
  display: grid;