@mundogamernetwork/shared-ui 1.8.7 → 1.8.9
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.
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<client-only>
|
|
3
|
+
<div ref="mapContainer" class="mk-map-container">
|
|
4
|
+
<l-map v-if="mapReady" :zoom="0.5" :center="[0, 0]" :use-global-leaflet="false">
|
|
5
|
+
<l-tile-layer url="https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png" layer-type="base"
|
|
6
|
+
attribution="OpenStreetMap" />
|
|
7
|
+
|
|
8
|
+
<l-circle-marker v-for="(country, index) in countries" :key="index"
|
|
9
|
+
:lat-lng="[country.latitude, country.longitude]"
|
|
10
|
+
:radius="calculateRadius(country.percent)" color="#FDB215" fill-opacity="0.6">
|
|
11
|
+
<l-tooltip :content="`${country.name}: ${country.percent}%`" />
|
|
12
|
+
</l-circle-marker>
|
|
13
|
+
</l-map>
|
|
14
|
+
</div>
|
|
15
|
+
</client-only>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup lang="ts">
|
|
19
|
+
// Ported from agency-frontend/components/MapCountries.vue (the old
|
|
20
|
+
// casting-details page's audience map) — same lib/tile source/marker
|
|
21
|
+
// styling, adapted to the media-kit's audience_geo field names
|
|
22
|
+
// (name/percent instead of localized_name/percentage).
|
|
23
|
+
import 'leaflet/dist/leaflet.css';
|
|
24
|
+
import { shallowRef, ref, onMounted } from 'vue';
|
|
25
|
+
|
|
26
|
+
defineProps<{
|
|
27
|
+
countries: {
|
|
28
|
+
latitude: number;
|
|
29
|
+
longitude: number;
|
|
30
|
+
percent: number;
|
|
31
|
+
name: string;
|
|
32
|
+
}[];
|
|
33
|
+
}>();
|
|
34
|
+
|
|
35
|
+
const mapContainer = ref<HTMLElement | null>(null);
|
|
36
|
+
const mapReady = ref(false);
|
|
37
|
+
const LMap = shallowRef();
|
|
38
|
+
const LTileLayer = shallowRef();
|
|
39
|
+
const LCircleMarker = shallowRef();
|
|
40
|
+
const LTooltip = shallowRef();
|
|
41
|
+
|
|
42
|
+
const calculateRadius = (percent: number) => {
|
|
43
|
+
return Math.max(2, percent * 0.3);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
if (import.meta.client) {
|
|
47
|
+
const { LMap: LMapComponent, LTileLayer: LTileLayerComponent, LCircleMarker: LCircleMarkerComponent, LTooltip: LTooltipComponent } = await import('@vue-leaflet/vue-leaflet');
|
|
48
|
+
LMap.value = LMapComponent;
|
|
49
|
+
LTileLayer.value = LTileLayerComponent;
|
|
50
|
+
LCircleMarker.value = LCircleMarkerComponent;
|
|
51
|
+
LTooltip.value = LTooltipComponent;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
onMounted(() => {
|
|
55
|
+
mapReady.value = true;
|
|
56
|
+
});
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<style scoped>
|
|
60
|
+
.mk-map-container {
|
|
61
|
+
height: 220px;
|
|
62
|
+
width: 100%;
|
|
63
|
+
position: relative;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:deep(.leaflet-container) {
|
|
67
|
+
height: 100% !important;
|
|
68
|
+
width: 100% !important;
|
|
69
|
+
background: #0a0a0f;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
:deep(.leaflet-bottom) {
|
|
73
|
+
bottom: 0;
|
|
74
|
+
display: none !important;
|
|
75
|
+
}
|
|
76
|
+
</style>
|
package/nuxt.config.ts
CHANGED
|
@@ -61,6 +61,13 @@ try {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export default defineNuxtConfig({
|
|
64
|
+
// Nuxt/c12 merges extended-layer config via defu (arrays concatenate), so
|
|
65
|
+
// this reaches every consuming app automatically — matches the storesDirs
|
|
66
|
+
// pattern below. @vue-leaflet/vue-leaflet ships untranspiled ESM that
|
|
67
|
+
// breaks Nuxt's build without this, needed by MediaKit/MapCountries.vue.
|
|
68
|
+
build: {
|
|
69
|
+
transpile: ['@vue-leaflet/vue-leaflet'],
|
|
70
|
+
},
|
|
64
71
|
components: [
|
|
65
72
|
{
|
|
66
73
|
path: `${packageRoot}/components`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mundogamernetwork/shared-ui",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.9",
|
|
4
4
|
"description": "Mundo Gamer Network - Shared UI Layer (Nuxt 3)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
@@ -30,9 +30,11 @@
|
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"@pinia-plugin-persistedstate/nuxt": ">=1.0.0",
|
|
32
32
|
"@pinia/nuxt": ">=0.5.0",
|
|
33
|
+
"@vue-leaflet/vue-leaflet": ">=0.10.0",
|
|
33
34
|
"axios": ">=1.0.0",
|
|
34
35
|
"hls.js": ">=1.5.0",
|
|
35
36
|
"laravel-echo": ">=1.15.0",
|
|
37
|
+
"leaflet": ">=1.9.0",
|
|
36
38
|
"nuxt": ">=3.13.0",
|
|
37
39
|
"pinia": ">=2.1.0",
|
|
38
40
|
"pusher-js": ">=8.0.0",
|
|
@@ -41,9 +43,12 @@
|
|
|
41
43
|
"devDependencies": {
|
|
42
44
|
"@pinia-plugin-persistedstate/nuxt": "^1.2.1",
|
|
43
45
|
"@pinia/nuxt": "^0.5.5",
|
|
46
|
+
"@types/leaflet": "^1.9.18",
|
|
47
|
+
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
|
44
48
|
"axios": "^1.18.1",
|
|
45
49
|
"hls.js": "^1.6.16",
|
|
46
50
|
"laravel-echo": "^2.3.7",
|
|
51
|
+
"leaflet": "^1.9.4",
|
|
47
52
|
"nuxt": "^3.15.4",
|
|
48
53
|
"pinia": "^2.3.1",
|
|
49
54
|
"pusher-js": "^8.5.0",
|
|
@@ -3,6 +3,7 @@ import { fetchPublicMediaKit, trackMediaKitEvent } from '../../services/mediaKit
|
|
|
3
3
|
import { sendMediaKitProposal } from '../../services/mediaKitProposalService';
|
|
4
4
|
import MediaKitWallBlock from '../../components/indie-wall/MediaKitWallBlock.vue';
|
|
5
5
|
import MgMediaKitStore from '../../components/MediaKit/MgMediaKitStore.vue';
|
|
6
|
+
import MapCountries from '../../components/MediaKit/MapCountries.vue';
|
|
6
7
|
|
|
7
8
|
const route = useRoute();
|
|
8
9
|
const slug = computed(() => route.params.slug as string);
|
|
@@ -78,10 +79,32 @@ const websiteUrl = computed<string | null>(() => streamer.value?.website ?? null
|
|
|
78
79
|
|
|
79
80
|
// ── D2 ecosystem data ──
|
|
80
81
|
const selectedGames = computed<string[]>(() => kit.value?.selected_games ?? []);
|
|
82
|
+
const languages = computed<any[]>(() => kit.value?.languages ?? []);
|
|
81
83
|
const audienceGeo = computed<any[]>(() => kit.value?.audience_geo ?? []);
|
|
84
|
+
// A handful of countries.latitude/longitude rows are historically unset —
|
|
85
|
+
// the list still renders those (name/percent don't need coordinates), the
|
|
86
|
+
// map just skips them.
|
|
87
|
+
const audienceGeoMappable = computed(() => audienceGeo.value.filter((c: any) => c.latitude != null && c.longitude != null));
|
|
82
88
|
const platformsPlayed = computed<any[]>(() => kit.value?.platforms_played ?? []);
|
|
83
89
|
const academyMentor = computed(() => kit.value?.academy_mentor ?? null);
|
|
84
90
|
const communityStats = computed(() => kit.value?.community ?? null);
|
|
91
|
+
// Business signals collected by the /trails-form onboarding wizard, exposed
|
|
92
|
+
// via PublicMediaKitController::getBusinessSignals() (2026-07-23 audit).
|
|
93
|
+
const businessSignals = computed<Record<string, any> | null>(() => kit.value?.business_signals ?? null);
|
|
94
|
+
const hasAvailabilitySection = computed(() =>
|
|
95
|
+
!!businessSignals.value && (
|
|
96
|
+
!!businessSignals.value.contact_type
|
|
97
|
+
|| !!businessSignals.value.availability_hour
|
|
98
|
+
|| !!businessSignals.value.availability_days
|
|
99
|
+
),
|
|
100
|
+
);
|
|
101
|
+
const hasSelfReportedMetrics = computed(() =>
|
|
102
|
+
!!businessSignals.value && (
|
|
103
|
+
!!businessSignals.value.avg_views_per_content
|
|
104
|
+
|| !!businessSignals.value.avg_monthly_views
|
|
105
|
+
|| !!businessSignals.value.audience_profile
|
|
106
|
+
),
|
|
107
|
+
);
|
|
85
108
|
const tvChannelLogin = computed<string | null>(() => streamer.value?.tv_channel_login ?? null);
|
|
86
109
|
const tvSiteUrl = import.meta.env.VITE_TV_SITE_URL || 'https://mundogamer.tv';
|
|
87
110
|
const tvChannelUrl = computed(() => tvChannelLogin.value
|
|
@@ -288,6 +311,10 @@ function onDownload() {
|
|
|
288
311
|
<div class="mk-badges">
|
|
289
312
|
<span v-if="streamer.platform" class="mk-badge plat">{{ streamer.platform }}</span>
|
|
290
313
|
<span v-if="streamer.tier && streamer.tier !== 'free'" class="mk-badge tier">{{ String(streamer.tier).toUpperCase() }}</span>
|
|
314
|
+
<span v-if="businessSignals?.available_for_campaigns === true" class="mk-badge available">{{ $t('kit.media.available_for_campaigns') }}</span>
|
|
315
|
+
<span v-else-if="businessSignals?.available_for_campaigns === false" class="mk-badge unavailable">{{ $t('kit.media.unavailable_for_campaigns') }}</span>
|
|
316
|
+
<span v-if="businessSignals?.accept_proposals === false" class="mk-badge muted">{{ $t('kit.media.not_accepting_proposals') }}</span>
|
|
317
|
+
<span v-if="businessSignals?.participated_in_campaigns" class="mk-badge muted">{{ $t('kit.media.past_campaigns') }}</span>
|
|
291
318
|
</div>
|
|
292
319
|
|
|
293
320
|
<div v-if="showShortlistBar" class="mk-internal-bar no-print">
|
|
@@ -347,7 +374,10 @@ function onDownload() {
|
|
|
347
374
|
|
|
348
375
|
<!-- ── TAB: PERFIL ── -->
|
|
349
376
|
<div class="mk-tabpanel" :class="{ active: activeTab === 0 }" data-print-tab="profile">
|
|
350
|
-
<
|
|
377
|
+
<section v-if="streamer.bio" class="kit-block" data-sec="about">
|
|
378
|
+
<h2>{{ $t('kit.media.about_title', { name: streamer.name }) }}</h2>
|
|
379
|
+
<p class="mk-bio">{{ streamer.bio }}</p>
|
|
380
|
+
</section>
|
|
351
381
|
|
|
352
382
|
<section v-if="academyMentor" class="kit-block" data-sec="academy">
|
|
353
383
|
<h2>{{ $t('kit.media.academy_mentor_title') }}</h2>
|
|
@@ -365,7 +395,10 @@ function onDownload() {
|
|
|
365
395
|
<div class="mk-platforms">
|
|
366
396
|
<a v-for="p in platforms" :key="p.platform" class="mk-platform" :href="p.url || undefined" target="_blank" rel="noopener" @click="track('click')">
|
|
367
397
|
<div class="pl-head">
|
|
368
|
-
<span class="pl-name">
|
|
398
|
+
<span class="pl-name-group">
|
|
399
|
+
<i v-if="PLATFORM_ICON[p.platform]" class="fa-brands pl-icon" :class="PLATFORM_ICON[p.platform]" />
|
|
400
|
+
<span class="pl-name">{{ PLATFORM_LABEL[p.platform] || p.platform }}</span>
|
|
401
|
+
</span>
|
|
369
402
|
<span v-if="p.verified" class="pl-verified" :title="$t('kit.media.verified')">✓</span>
|
|
370
403
|
</div>
|
|
371
404
|
<div class="pl-followers">{{ fmt(p.followers) }}</div>
|
|
@@ -377,8 +410,27 @@ function onDownload() {
|
|
|
377
410
|
</div>
|
|
378
411
|
</section>
|
|
379
412
|
|
|
413
|
+
<section v-if="hasSelfReportedMetrics" class="kit-block" data-sec="self-reported-metrics">
|
|
414
|
+
<h2>{{ $t('kit.media.self_reported_metrics') }}</h2>
|
|
415
|
+
<div class="mk-metrics">
|
|
416
|
+
<div v-if="businessSignals.avg_views_per_content" class="mk-metric">
|
|
417
|
+
<span class="val">{{ businessSignals.avg_views_per_content }}</span>
|
|
418
|
+
<span class="lab">{{ $t('kit.media.avg_views_per_content') }}</span>
|
|
419
|
+
</div>
|
|
420
|
+
<div v-if="businessSignals.avg_monthly_views" class="mk-metric">
|
|
421
|
+
<span class="val">{{ businessSignals.avg_monthly_views }}</span>
|
|
422
|
+
<span class="lab">{{ $t('kit.media.avg_monthly_views') }}</span>
|
|
423
|
+
</div>
|
|
424
|
+
<div v-if="businessSignals.audience_profile" class="mk-metric">
|
|
425
|
+
<span class="val val-sm">{{ businessSignals.audience_profile }}</span>
|
|
426
|
+
<span class="lab">{{ $t('kit.media.audience_profile') }}</span>
|
|
427
|
+
</div>
|
|
428
|
+
</div>
|
|
429
|
+
</section>
|
|
430
|
+
|
|
380
431
|
<section v-if="audienceGeo.length" class="kit-block" data-sec="geo">
|
|
381
432
|
<h2>{{ $t('kit.media.audience_geo') }}</h2>
|
|
433
|
+
<MapCountries v-if="audienceGeoMappable.length" :countries="audienceGeoMappable" class="mk-geo-map no-print" />
|
|
382
434
|
<div class="mk-geo">
|
|
383
435
|
<div v-for="c in audienceGeo" :key="c.isocode" class="mk-bar">
|
|
384
436
|
<div class="top">
|
|
@@ -426,6 +478,30 @@ function onDownload() {
|
|
|
426
478
|
</div>
|
|
427
479
|
</section>
|
|
428
480
|
|
|
481
|
+
<!-- Languages the creator works in — was on the old casting-details
|
|
482
|
+
page, dropped when it was consolidated into this shared builder. -->
|
|
483
|
+
<section v-if="languages.length" class="kit-block" data-sec="languages">
|
|
484
|
+
<h2>{{ $t('kit.media.languages') }}</h2>
|
|
485
|
+
<div class="mk-tags">
|
|
486
|
+
<span v-for="l in languages" :key="l.id" class="mk-tag">{{ l.name }}</span>
|
|
487
|
+
</div>
|
|
488
|
+
</section>
|
|
489
|
+
|
|
490
|
+
<section v-if="hasAvailabilitySection" class="kit-block" data-sec="availability-preference">
|
|
491
|
+
<h2>{{ $t('kit.media.availability_title') }}</h2>
|
|
492
|
+
<div class="mk-cols2">
|
|
493
|
+
<div v-if="businessSignals.contact_type" class="kit-card mk-pad">
|
|
494
|
+
<h3>{{ $t('kit.media.contact_type') }}</h3>
|
|
495
|
+
<span class="mk-tag">{{ businessSignals.contact_type }}</span>
|
|
496
|
+
</div>
|
|
497
|
+
<div v-if="businessSignals.availability_hour || businessSignals.availability_days" class="kit-card mk-pad">
|
|
498
|
+
<h3>{{ $t('kit.media.best_time') }}</h3>
|
|
499
|
+
<span v-if="businessSignals.availability_hour" class="mk-tag">{{ businessSignals.availability_hour }}</span>
|
|
500
|
+
<span v-if="businessSignals.availability_days" class="mk-tag">{{ businessSignals.availability_days }}</span>
|
|
501
|
+
</div>
|
|
502
|
+
</div>
|
|
503
|
+
</section>
|
|
504
|
+
|
|
429
505
|
<section v-if="platformsPlayed.length" class="kit-block" data-sec="platforms-played">
|
|
430
506
|
<h2>{{ $t('kit.media.platforms_played') }}</h2>
|
|
431
507
|
<div class="mk-platforms-played">
|
|
@@ -687,6 +763,9 @@ function onDownload() {
|
|
|
687
763
|
|
|
688
764
|
&.plat { background: var(--kit-surface-2); border: 1px solid var(--kit-line); }
|
|
689
765
|
&.tier { background: var(--kit-accent); color: var(--kit-accent-ink); }
|
|
766
|
+
&.available { background: rgba(74, 222, 128, .12); color: #4ade80; border: 1px solid rgba(74, 222, 128, .3); }
|
|
767
|
+
&.unavailable { background: rgba(239, 68, 68, .12); color: #ef4444; border: 1px solid rgba(239, 68, 68, .3); }
|
|
768
|
+
&.muted { background: rgba(139, 146, 160, .1); color: var(--kit-muted); border: 1px solid rgba(139, 146, 160, .2); }
|
|
690
769
|
}
|
|
691
770
|
|
|
692
771
|
.mk-internal-bar {
|
|
@@ -846,6 +925,8 @@ function onDownload() {
|
|
|
846
925
|
|
|
847
926
|
&:hover { border-color: var(--kit-accent); }
|
|
848
927
|
.pl-head { display: flex; align-items: center; justify-content: space-between; }
|
|
928
|
+
.pl-name-group { display: flex; align-items: center; gap: 6px; }
|
|
929
|
+
.pl-icon { font-size: 13px; color: var(--kit-accent); }
|
|
849
930
|
.pl-name { font-size: 12px; text-transform: uppercase; letter-spacing: 1px; color: var(--kit-muted); }
|
|
850
931
|
.pl-verified { color: #27ae60; font-weight: 700; }
|
|
851
932
|
.pl-followers { font-family: 'Rajdhani', sans-serif; font-weight: 700; font-size: 24px; }
|
|
@@ -853,6 +934,7 @@ function onDownload() {
|
|
|
853
934
|
}
|
|
854
935
|
|
|
855
936
|
/* Geo */
|
|
937
|
+
.mk-geo-map { margin-bottom: 16px; border: 1px solid var(--kit-line); }
|
|
856
938
|
.mk-geo { display: flex; flex-direction: column; gap: 10px; }
|
|
857
939
|
.mk-flag { width: 18px; height: 13px; object-fit: cover; margin-right: 8px; vertical-align: middle; }
|
|
858
940
|
|
|
@@ -981,7 +1063,7 @@ function onDownload() {
|
|
|
981
1063
|
.mk-metric {
|
|
982
1064
|
background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 20px 16px; text-align: center; position: relative; overflow: hidden;
|
|
983
1065
|
&::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 2px; background: var(--kit-accent); }
|
|
984
|
-
.val { font-family: 'Rajdhani', sans-serif; font-weight: 700; font-size: 30px; line-height: 1; &.accent { color: var(--kit-accent); } }
|
|
1066
|
+
.val { font-family: 'Rajdhani', sans-serif; font-weight: 700; font-size: 30px; line-height: 1; &.accent { color: var(--kit-accent); } &.val-sm { font-size: 16px; } }
|
|
985
1067
|
.lab { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--kit-muted); margin-top: 8px; }
|
|
986
1068
|
}
|
|
987
1069
|
.mk-period { color: var(--kit-muted); font-size: 13px; margin: -8px 0 16px; }
|