@mundogamernetwork/shared-ui 1.8.6 → 1.8.8
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>
|
|
@@ -172,7 +172,7 @@ const detailRoute = computed(() =>
|
|
|
172
172
|
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="13" viewBox="0 0 16 17" fill="none">
|
|
173
173
|
<path d="M13.3333 4.1112L12.8666 3.64453L11.9333 4.57786L10.9333 3.64453L8.33329 4.1112L2.66663 9.77786L7.19996 14.3112L12.8666 8.64453L13.3333 6.04453L12.4 5.1112L13.3333 4.1112ZM12.6 6.24453L12.2666 8.3112L7.19996 13.3779L3.59996 9.77786L8.66663 4.7112L10.7333 4.3112L11.4666 5.04453L11 5.5112L10.5333 5.04453L9.99996 5.57786L11.4 6.97786L11.8666 6.5112L11.4 6.04453L11.8666 5.57786L12.6 6.24453Z" fill="#D297FF"/>
|
|
174
174
|
</svg>
|
|
175
|
-
{{ card.type }}
|
|
175
|
+
{{ typeof card.type === "string" ? card.type : card.type.name }}
|
|
176
176
|
</span>
|
|
177
177
|
</div>
|
|
178
178
|
</div>
|
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.8",
|
|
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",
|
|
@@ -130,7 +130,9 @@
|
|
|
130
130
|
<div
|
|
131
131
|
class="keys-badge"
|
|
132
132
|
v-if="card.available_count > 0 && card.user_can_access && !card.isExpired && !card.isUpcoming"
|
|
133
|
+
:title="$t('keys.campaigns.keys_left', { n: card.available_count })"
|
|
133
134
|
>
|
|
135
|
+
<i class="fa-solid fa-key" />
|
|
134
136
|
{{ card.available_count }}
|
|
135
137
|
</div>
|
|
136
138
|
|
|
@@ -221,10 +223,6 @@
|
|
|
221
223
|
+{{ card.platforms.length - 4 }}
|
|
222
224
|
</span>
|
|
223
225
|
</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 }) }}
|
|
226
|
-
</div>
|
|
227
|
-
<div v-if="card.gameName && card.gameName !== card.text" class="card-campaign-name">{{ card.text }}</div>
|
|
228
226
|
|
|
229
227
|
<div class="buttons">
|
|
230
228
|
<template v-if="!card.user_can_access">
|
|
@@ -1237,7 +1235,7 @@ onUnmounted(() => {
|
|
|
1237
1235
|
}
|
|
1238
1236
|
|
|
1239
1237
|
.text {
|
|
1240
|
-
min-height:
|
|
1238
|
+
min-height: 170px;
|
|
1241
1239
|
|
|
1242
1240
|
.card-name {
|
|
1243
1241
|
font-size: 16px;
|
|
@@ -1254,18 +1252,6 @@ onUnmounted(() => {
|
|
|
1254
1252
|
gap: 6px;
|
|
1255
1253
|
}
|
|
1256
1254
|
|
|
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
|
-
|
|
1269
1255
|
.card-meta-row {
|
|
1270
1256
|
display: flex;
|
|
1271
1257
|
align-items: center;
|
|
@@ -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
|
|
@@ -98,6 +121,14 @@ const PLATFORM_LABEL: Record<string, string> = {
|
|
|
98
121
|
linkedin: 'LinkedIn', bluesky: 'Bluesky',
|
|
99
122
|
};
|
|
100
123
|
|
|
124
|
+
// Font Awesome brand icon per platform — no entry means no official FA glyph
|
|
125
|
+
// exists yet (e.g. Kick), the template falls back to the 2-letter label.
|
|
126
|
+
const PLATFORM_ICON: Record<string, string> = {
|
|
127
|
+
instagram: 'fa-instagram', tiktok: 'fa-tiktok', youtube: 'fa-youtube', twitch: 'fa-twitch',
|
|
128
|
+
x: 'fa-x-twitter', facebook: 'fa-facebook', discord: 'fa-discord', telegram: 'fa-telegram',
|
|
129
|
+
linkedin: 'fa-linkedin', bluesky: 'fa-bluesky',
|
|
130
|
+
};
|
|
131
|
+
|
|
101
132
|
const socials = computed(() => {
|
|
102
133
|
const s = streamer.value?.social_links || {};
|
|
103
134
|
return Object.entries(s).filter(([, v]) => v).map(([k, v]) => ({ platform: k, url: v as string }));
|
|
@@ -110,6 +141,14 @@ const scheduleByDay = computed(() => {
|
|
|
110
141
|
return [0, 1, 2, 3, 4, 5, 6].map((d) => ({ d, key: DOW[d], slot: map[d] || null }));
|
|
111
142
|
});
|
|
112
143
|
|
|
144
|
+
// Sidebar "hire" CTA jumps to the rates tab — on mobile the tabs are further
|
|
145
|
+
// down the stacked layout, so switching activeTab alone can leave the change
|
|
146
|
+
// off-screen; scroll it into view too.
|
|
147
|
+
function goToRates() {
|
|
148
|
+
activeTab.value = 1;
|
|
149
|
+
document.getElementById('mk-tabs')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
150
|
+
}
|
|
151
|
+
|
|
113
152
|
// ── Tabs: template picks which one opens first, casting-details-style ──
|
|
114
153
|
const TAB_KEYS = ['profile', 'rates', 'performance'] as const;
|
|
115
154
|
const TEMPLATE_DEFAULT_TAB: Record<string, number> = {
|
|
@@ -272,6 +311,10 @@ function onDownload() {
|
|
|
272
311
|
<div class="mk-badges">
|
|
273
312
|
<span v-if="streamer.platform" class="mk-badge plat">{{ streamer.platform }}</span>
|
|
274
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>
|
|
275
318
|
</div>
|
|
276
319
|
|
|
277
320
|
<div v-if="showShortlistBar" class="mk-internal-bar no-print">
|
|
@@ -284,7 +327,8 @@ function onDownload() {
|
|
|
284
327
|
</div>
|
|
285
328
|
|
|
286
329
|
<div class="mk-actions no-print">
|
|
287
|
-
<a class="kit-btn kit-btn-primary" @click="
|
|
330
|
+
<a v-if="!isOwnKit" class="kit-btn kit-btn-primary" @click="goToRates">{{ $t('kit.media.hire') }}</a>
|
|
331
|
+
<a class="kit-btn" :class="isOwnKit ? 'kit-btn-primary' : 'kit-btn-ghost'" @click="onDownload">{{ $t('kit.media.download_pdf') }}</a>
|
|
288
332
|
<a v-if="streamer.contact_email" class="kit-btn kit-btn-ghost" :href="`mailto:${streamer.contact_email}`" @click="track('contact')">{{ $t('kit.media.contact') }}</a>
|
|
289
333
|
</div>
|
|
290
334
|
|
|
@@ -314,22 +358,26 @@ function onDownload() {
|
|
|
314
358
|
|
|
315
359
|
<div v-if="socials.length" class="mk-socials no-print">
|
|
316
360
|
<a v-for="s in socials" :key="s.platform" class="mk-soc" :href="s.url" target="_blank" rel="noopener" :title="PLATFORM_LABEL[s.platform] || s.platform" @click="track('click')">
|
|
317
|
-
|
|
361
|
+
<i v-if="PLATFORM_ICON[s.platform]" class="fa-brands" :class="PLATFORM_ICON[s.platform]" />
|
|
362
|
+
<span v-else class="mk-soc-fallback">{{ (PLATFORM_LABEL[s.platform] || s.platform).slice(0, 2).toUpperCase() }}</span>
|
|
318
363
|
</a>
|
|
319
364
|
</div>
|
|
320
365
|
</aside>
|
|
321
366
|
|
|
322
367
|
<!-- ══════════════ MAIN: TABS ══════════════ -->
|
|
323
368
|
<main class="mk-main">
|
|
324
|
-
<div class="mk-tabs no-print">
|
|
369
|
+
<div id="mk-tabs" class="mk-tabs no-print">
|
|
325
370
|
<button class="mk-tab" :class="{ active: activeTab === 0 }" @click="activeTab = 0">{{ $t('kit.media.tab_profile') }}</button>
|
|
326
|
-
<button
|
|
371
|
+
<button class="mk-tab" :class="{ active: activeTab === 1 }" @click="activeTab = 1">{{ $t('kit.media.tab_rates') }}</button>
|
|
327
372
|
<button v-if="hasPerformanceTab" class="mk-tab" :class="{ active: activeTab === 2 }" @click="activeTab = 2">{{ $t('kit.media.tab_performance') }}</button>
|
|
328
373
|
</div>
|
|
329
374
|
|
|
330
375
|
<!-- ── TAB: PERFIL ── -->
|
|
331
376
|
<div class="mk-tabpanel" :class="{ active: activeTab === 0 }" data-print-tab="profile">
|
|
332
|
-
<
|
|
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>
|
|
333
381
|
|
|
334
382
|
<section v-if="academyMentor" class="kit-block" data-sec="academy">
|
|
335
383
|
<h2>{{ $t('kit.media.academy_mentor_title') }}</h2>
|
|
@@ -347,7 +395,10 @@ function onDownload() {
|
|
|
347
395
|
<div class="mk-platforms">
|
|
348
396
|
<a v-for="p in platforms" :key="p.platform" class="mk-platform" :href="p.url || undefined" target="_blank" rel="noopener" @click="track('click')">
|
|
349
397
|
<div class="pl-head">
|
|
350
|
-
<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>
|
|
351
402
|
<span v-if="p.verified" class="pl-verified" :title="$t('kit.media.verified')">✓</span>
|
|
352
403
|
</div>
|
|
353
404
|
<div class="pl-followers">{{ fmt(p.followers) }}</div>
|
|
@@ -359,8 +410,27 @@ function onDownload() {
|
|
|
359
410
|
</div>
|
|
360
411
|
</section>
|
|
361
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
|
+
|
|
362
431
|
<section v-if="audienceGeo.length" class="kit-block" data-sec="geo">
|
|
363
432
|
<h2>{{ $t('kit.media.audience_geo') }}</h2>
|
|
433
|
+
<MapCountries v-if="audienceGeoMappable.length" :countries="audienceGeoMappable" class="mk-geo-map no-print" />
|
|
364
434
|
<div class="mk-geo">
|
|
365
435
|
<div v-for="c in audienceGeo" :key="c.isocode" class="mk-bar">
|
|
366
436
|
<div class="top">
|
|
@@ -408,6 +478,30 @@ function onDownload() {
|
|
|
408
478
|
</div>
|
|
409
479
|
</section>
|
|
410
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
|
+
|
|
411
505
|
<section v-if="platformsPlayed.length" class="kit-block" data-sec="platforms-played">
|
|
412
506
|
<h2>{{ $t('kit.media.platforms_played') }}</h2>
|
|
413
507
|
<div class="mk-platforms-played">
|
|
@@ -452,8 +546,12 @@ function onDownload() {
|
|
|
452
546
|
</div>
|
|
453
547
|
|
|
454
548
|
<!-- ── TAB: RATE CARDS ── -->
|
|
455
|
-
<div
|
|
456
|
-
<div class="mk-rc-
|
|
549
|
+
<div class="mk-tabpanel" :class="{ active: activeTab === 1 }" data-print-tab="rates">
|
|
550
|
+
<div v-if="!hasRatesTab" class="mk-rc-empty">
|
|
551
|
+
<p>{{ isOwnKit ? $t('kit.media.rates_empty_own') : $t('kit.media.rates_empty_viewer') }}</p>
|
|
552
|
+
<a v-if="!isOwnKit && streamer.contact_email" class="kit-btn kit-btn-primary" :href="`mailto:${streamer.contact_email}`" @click="track('contact')">{{ $t('kit.media.contact') }}</a>
|
|
553
|
+
</div>
|
|
554
|
+
<div v-else class="mk-rc-layout">
|
|
457
555
|
<div class="mk-rc-main">
|
|
458
556
|
<div v-if="bundles.length" class="mk-rc-group">
|
|
459
557
|
<h2>{{ $t('kit.media.rates_bundles') }}</h2>
|
|
@@ -665,6 +763,9 @@ function onDownload() {
|
|
|
665
763
|
|
|
666
764
|
&.plat { background: var(--kit-surface-2); border: 1px solid var(--kit-line); }
|
|
667
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); }
|
|
668
769
|
}
|
|
669
770
|
|
|
670
771
|
.mk-internal-bar {
|
|
@@ -715,11 +816,12 @@ function onDownload() {
|
|
|
715
816
|
display: flex; align-items: center; justify-content: center;
|
|
716
817
|
border: 1px solid var(--kit-line);
|
|
717
818
|
color: var(--kit-muted);
|
|
718
|
-
font-size:
|
|
819
|
+
font-size: 15px;
|
|
719
820
|
text-decoration: none;
|
|
720
821
|
|
|
721
822
|
&:hover { border-color: var(--kit-accent); color: var(--kit-accent); }
|
|
722
823
|
}
|
|
824
|
+
.mk-soc-fallback { font-size: 11px; font-weight: 700; }
|
|
723
825
|
|
|
724
826
|
/* Buttons (shared) */
|
|
725
827
|
.kit-btn {
|
|
@@ -823,6 +925,8 @@ function onDownload() {
|
|
|
823
925
|
|
|
824
926
|
&:hover { border-color: var(--kit-accent); }
|
|
825
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); }
|
|
826
930
|
.pl-name { font-size: 12px; text-transform: uppercase; letter-spacing: 1px; color: var(--kit-muted); }
|
|
827
931
|
.pl-verified { color: #27ae60; font-weight: 700; }
|
|
828
932
|
.pl-followers { font-family: 'Rajdhani', sans-serif; font-weight: 700; font-size: 24px; }
|
|
@@ -830,6 +934,7 @@ function onDownload() {
|
|
|
830
934
|
}
|
|
831
935
|
|
|
832
936
|
/* Geo */
|
|
937
|
+
.mk-geo-map { margin-bottom: 16px; border: 1px solid var(--kit-line); }
|
|
833
938
|
.mk-geo { display: flex; flex-direction: column; gap: 10px; }
|
|
834
939
|
.mk-flag { width: 18px; height: 13px; object-fit: cover; margin-right: 8px; vertical-align: middle; }
|
|
835
940
|
|
|
@@ -909,6 +1014,15 @@ function onDownload() {
|
|
|
909
1014
|
}
|
|
910
1015
|
|
|
911
1016
|
/* Rate cards / builder */
|
|
1017
|
+
.mk-rc-empty {
|
|
1018
|
+
display: flex;
|
|
1019
|
+
flex-direction: column;
|
|
1020
|
+
align-items: center;
|
|
1021
|
+
gap: 16px;
|
|
1022
|
+
text-align: center;
|
|
1023
|
+
padding: 60px 24px;
|
|
1024
|
+
color: var(--kit-muted);
|
|
1025
|
+
}
|
|
912
1026
|
.mk-rc-layout { display: grid; grid-template-columns: 1fr 260px; gap: 20px; align-items: start; }
|
|
913
1027
|
@media (max-width: 760px) { .mk-rc-layout { grid-template-columns: 1fr; } }
|
|
914
1028
|
.mk-rc-group { display: flex; flex-direction: column; gap: 1px; background: var(--kit-line); margin-bottom: 24px; }
|
|
@@ -949,7 +1063,7 @@ function onDownload() {
|
|
|
949
1063
|
.mk-metric {
|
|
950
1064
|
background: var(--kit-surface); border: 1px solid var(--kit-line); padding: 20px 16px; text-align: center; position: relative; overflow: hidden;
|
|
951
1065
|
&::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 2px; background: var(--kit-accent); }
|
|
952
|
-
.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; } }
|
|
953
1067
|
.lab { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--kit-muted); margin-top: 8px; }
|
|
954
1068
|
}
|
|
955
1069
|
.mk-period { color: var(--kit-muted); font-size: 13px; margin: -8px 0 16px; }
|