@mundogamernetwork/shared-ui 1.8.8 → 1.8.13
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 +3 -6
- package/components/PlatformIcon.vue +61 -0
- package/components/keys/KeyCampaignDashboardCard.vue +7 -4
- package/components/keys/KeyCampaignsCarousel.vue +101 -11
- package/nuxt.config.ts +4 -0
- package/package.json +5 -5
- package/pages/key-campaigns/index.vue +11 -1
- package/pages/media-kit/[slug].vue +5 -21
- package/pages/presskit/game/[slug].vue +2 -2
- package/services/campaignService.ts +3 -2
package/assets/kit/kit-base.css
CHANGED
|
@@ -725,18 +725,15 @@ body:has(.kit-press) {
|
|
|
725
725
|
margin: 0;
|
|
726
726
|
}
|
|
727
727
|
.kit-footer__cta {
|
|
728
|
-
display: inline-block;
|
|
729
|
-
padding: 8px 20px;
|
|
730
|
-
border: 1px solid var(--kit-accent, #FDB215);
|
|
731
728
|
color: var(--kit-accent, #FDB215);
|
|
732
729
|
font-size: 0.8rem;
|
|
733
730
|
font-weight: 600;
|
|
734
731
|
text-decoration: none;
|
|
735
|
-
|
|
732
|
+
border-bottom: 1px solid transparent;
|
|
733
|
+
transition: border-color 0.15s;
|
|
736
734
|
}
|
|
737
735
|
.kit-footer__cta:hover {
|
|
738
|
-
|
|
739
|
-
color: #000;
|
|
736
|
+
border-bottom-color: var(--kit-accent, #FDB215);
|
|
740
737
|
}
|
|
741
738
|
|
|
742
739
|
/* ── Scroll offset for sticky anchor nav ────────────────────────────*/
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// Inline SVG per platform instead of Font Awesome <i class="fa-..."> classes —
|
|
3
|
+
// shared-ui can't control whether a consuming app wires up FA as a classic
|
|
4
|
+
// webfont/CSS kit or as SVG Vue components (agency-frontend uses the latter,
|
|
5
|
+
// via @fortawesome/vue-fontawesome, and only registers the solid icon set —
|
|
6
|
+
// no brands set at all), so raw `<i class="fa-brands fa-tiktok">` silently
|
|
7
|
+
// renders nothing there. Built from simple SVG primitives (circle/rect/line),
|
|
8
|
+
// not memorized brand path data, so correctness doesn't depend on visually
|
|
9
|
+
// checking curve coordinates.
|
|
10
|
+
defineProps<{
|
|
11
|
+
platform: string
|
|
12
|
+
}>()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<svg v-if="platform === 'x'" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
17
|
+
<line x1="4" y1="4" x2="20" y2="20" /><line x1="20" y1="4" x2="4" y2="20" />
|
|
18
|
+
</svg>
|
|
19
|
+
<svg v-else-if="platform === 'youtube'" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
20
|
+
<rect x="2" y="5" width="20" height="14" rx="4" />
|
|
21
|
+
<polygon points="10,9 10,15 15,12" fill="currentColor" stroke="none" />
|
|
22
|
+
</svg>
|
|
23
|
+
<svg v-else-if="platform === 'instagram'" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
24
|
+
<rect x="3" y="3" width="18" height="18" rx="5" />
|
|
25
|
+
<circle cx="12" cy="12" r="4" />
|
|
26
|
+
<circle cx="17.5" cy="6.5" r="1" fill="currentColor" stroke="none" />
|
|
27
|
+
</svg>
|
|
28
|
+
<svg v-else-if="platform === 'facebook'" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
29
|
+
<circle cx="12" cy="12" r="9" />
|
|
30
|
+
<text x="12" y="16.5" text-anchor="middle" font-size="11" font-weight="700" fill="currentColor" stroke="none">f</text>
|
|
31
|
+
</svg>
|
|
32
|
+
<svg v-else-if="platform === 'linkedin'" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
33
|
+
<rect x="3" y="3" width="18" height="18" rx="3" />
|
|
34
|
+
<text x="12" y="16" text-anchor="middle" font-size="9" font-weight="700" fill="currentColor" stroke="none">in</text>
|
|
35
|
+
</svg>
|
|
36
|
+
<svg v-else-if="platform === 'discord'" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
37
|
+
<rect x="3" y="6" width="18" height="12" rx="6" />
|
|
38
|
+
<circle cx="9" cy="12" r="1.3" fill="currentColor" stroke="none" />
|
|
39
|
+
<circle cx="15" cy="12" r="1.3" fill="currentColor" stroke="none" />
|
|
40
|
+
</svg>
|
|
41
|
+
<svg v-else-if="platform === 'twitch'" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
42
|
+
<rect x="3" y="4" width="18" height="13" rx="1" />
|
|
43
|
+
<line x1="9" y1="7" x2="9" y2="13" /><line x1="15" y1="7" x2="15" y2="13" />
|
|
44
|
+
</svg>
|
|
45
|
+
<svg v-else-if="platform === 'tiktok'" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
46
|
+
<circle cx="9" cy="17" r="3" />
|
|
47
|
+
<line x1="12" y1="17" x2="12" y2="5" />
|
|
48
|
+
<path d="M12 5c0 2.5 2 4.5 4.5 4.5" />
|
|
49
|
+
</svg>
|
|
50
|
+
<svg v-else-if="platform === 'telegram'" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round">
|
|
51
|
+
<path d="M3 12.5 20 4l-3.5 16-5-4-3 3-1-5.5z" />
|
|
52
|
+
</svg>
|
|
53
|
+
<span v-else class="platform-icon-fallback">{{ platform.slice(0, 2).toUpperCase() }}</span>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<style scoped>
|
|
57
|
+
.platform-icon-fallback {
|
|
58
|
+
font-size: 11px;
|
|
59
|
+
font-weight: 700;
|
|
60
|
+
}
|
|
61
|
+
</style>
|
|
@@ -22,7 +22,7 @@ const props = defineProps<{
|
|
|
22
22
|
isUpcoming?: boolean;
|
|
23
23
|
streamer_type?: number | null;
|
|
24
24
|
type?: string | null;
|
|
25
|
-
platforms?: Array<{ id: number; name: string; slug?: string | null } | string>;
|
|
25
|
+
platforms?: Array<{ id: number; name: string; slug?: string | null; alternative_name?: string | null } | string>;
|
|
26
26
|
};
|
|
27
27
|
publicMode?: boolean;
|
|
28
28
|
baseRoute?: string;
|
|
@@ -65,9 +65,12 @@ const PLATFORM_ABBR: Record<string, string> = {
|
|
|
65
65
|
"linux": "Linux", "ios": "iOS", "android": "Android", "gog": "GOG",
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
// The API already resolves an abbreviated name per platform (community.platforms
|
|
69
|
+
// .alternative_name, e.g. "Playstation 4" → "PS4") — prefer that over the static
|
|
70
|
+
// map below, which only exists as a fallback for older responses that omit it.
|
|
71
|
+
function platformAbbr(p: { name: string; alternative_name?: string | null } | string): string {
|
|
72
|
+
if (typeof p === "string") return PLATFORM_ABBR[p.toLowerCase()] ?? p;
|
|
73
|
+
return p.alternative_name || PLATFORM_ABBR[p.name.toLowerCase()] || p.name;
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
function cardTierLabel(tier: string | null | undefined): string {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { ref, onMounted, inject } from "vue"
|
|
3
3
|
import { fetchCampaigns } from "../../services/campaignService"
|
|
4
|
-
import KeyCampaignDashboardCard from "./KeyCampaignDashboardCard.vue"
|
|
5
4
|
|
|
6
5
|
const props = defineProps<{
|
|
7
6
|
excludeId?: number | null
|
|
@@ -11,10 +10,16 @@ const props = defineProps<{
|
|
|
11
10
|
}>()
|
|
12
11
|
|
|
13
12
|
const mgPlatform = props.mgPlatform || (inject<string>("mgPlatform", "MGTV"))
|
|
13
|
+
const locale = useNuxtApp().$i18n.locale
|
|
14
14
|
|
|
15
15
|
const items = ref<any[]>([])
|
|
16
16
|
const loading = ref(true)
|
|
17
17
|
|
|
18
|
+
const detailRoute = (item: any) =>
|
|
19
|
+
props.publicMode
|
|
20
|
+
? `/${locale.value}/${props.baseRoute ?? 'key-campaigns'}/${item.slug}`
|
|
21
|
+
: `/${locale.value}/dashboard/${props.baseRoute ?? 'key-campaigns'}/${item.slug}`
|
|
22
|
+
|
|
18
23
|
onMounted(async () => {
|
|
19
24
|
try {
|
|
20
25
|
const res = await fetchCampaigns(
|
|
@@ -49,13 +54,31 @@ onMounted(async () => {
|
|
|
49
54
|
</div>
|
|
50
55
|
|
|
51
56
|
<div v-else class="kc-carousel__track">
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
<NuxtLink
|
|
58
|
+
v-for="item in items"
|
|
59
|
+
:key="item.id"
|
|
60
|
+
:to="detailRoute(item)"
|
|
61
|
+
class="kc-carousel__card"
|
|
62
|
+
>
|
|
63
|
+
<div class="kc-carousel__thumb">
|
|
64
|
+
<img
|
|
65
|
+
v-if="item.cover_src || item.cover"
|
|
66
|
+
:src="item.cover_src || item.cover"
|
|
67
|
+
:alt="item.name"
|
|
68
|
+
/>
|
|
69
|
+
<div v-else class="kc-carousel__thumb-placeholder">
|
|
70
|
+
<i class="mg-icon mg-icon-game-key" />
|
|
71
|
+
</div>
|
|
72
|
+
<span v-if="!item.is_open" class="kc-carousel__closed">{{ $t("keys.campaigns.closed") }}</span>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="kc-carousel__info">
|
|
75
|
+
<div class="kc-carousel__name">{{ item.name }}</div>
|
|
76
|
+
<div class="kc-carousel__avail">
|
|
77
|
+
{{ item.available_count ?? 0 }}/{{ item.total_count ?? item.quantity ?? "?" }}
|
|
78
|
+
{{ $t("keys.campaigns.available") }}
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
</NuxtLink>
|
|
59
82
|
</div>
|
|
60
83
|
</div>
|
|
61
84
|
</template>
|
|
@@ -90,14 +113,81 @@ onMounted(async () => {
|
|
|
90
113
|
}
|
|
91
114
|
|
|
92
115
|
&__skeleton {
|
|
93
|
-
flex: 0 0
|
|
94
|
-
height:
|
|
116
|
+
flex: 0 0 180px;
|
|
117
|
+
height: 140px;
|
|
95
118
|
background: var(--bg-app-badge);
|
|
96
119
|
animation: pulse 1.4s ease-in-out infinite;
|
|
97
120
|
}
|
|
98
121
|
|
|
99
122
|
&__card {
|
|
100
|
-
flex: 0 0
|
|
123
|
+
flex: 0 0 180px;
|
|
124
|
+
display: flex;
|
|
125
|
+
flex-direction: column;
|
|
126
|
+
text-decoration: none;
|
|
127
|
+
color: inherit;
|
|
128
|
+
border: 1px solid var(--button-secondary-default-bg);
|
|
129
|
+
transition: border-color 0.15s;
|
|
130
|
+
|
|
131
|
+
&:hover { border-color: var(--key-accent, var(--primary, #D297FF)); }
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&__thumb {
|
|
135
|
+
position: relative;
|
|
136
|
+
width: 100%;
|
|
137
|
+
height: 101px;
|
|
138
|
+
overflow: hidden;
|
|
139
|
+
background: var(--bg-app-badge);
|
|
140
|
+
|
|
141
|
+
img {
|
|
142
|
+
width: 100%;
|
|
143
|
+
height: 100%;
|
|
144
|
+
object-fit: cover;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
&__thumb-placeholder {
|
|
149
|
+
width: 100%;
|
|
150
|
+
height: 100%;
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
justify-content: center;
|
|
154
|
+
color: var(--secondary-info-fg);
|
|
155
|
+
font-size: 24px;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
&__closed {
|
|
159
|
+
position: absolute;
|
|
160
|
+
inset: 0;
|
|
161
|
+
display: flex;
|
|
162
|
+
align-items: center;
|
|
163
|
+
justify-content: center;
|
|
164
|
+
background: var(--overlay-dark, rgba(0, 0, 0, 0.55));
|
|
165
|
+
font-size: 11px;
|
|
166
|
+
font-weight: 700;
|
|
167
|
+
color: var(--card-article-title, #fff);
|
|
168
|
+
letter-spacing: 0.5px;
|
|
169
|
+
text-transform: uppercase;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
&__info {
|
|
173
|
+
padding: 8px 10px;
|
|
174
|
+
display: flex;
|
|
175
|
+
flex-direction: column;
|
|
176
|
+
gap: 4px;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
&__name {
|
|
180
|
+
font-size: 12px;
|
|
181
|
+
font-weight: 600;
|
|
182
|
+
color: var(--card-article-title);
|
|
183
|
+
overflow: hidden;
|
|
184
|
+
text-overflow: ellipsis;
|
|
185
|
+
white-space: nowrap;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
&__avail {
|
|
189
|
+
font-size: 11px;
|
|
190
|
+
color: var(--secondary-info-fg);
|
|
101
191
|
}
|
|
102
192
|
}
|
|
103
193
|
|
package/nuxt.config.ts
CHANGED
|
@@ -65,6 +65,10 @@ export default defineNuxtConfig({
|
|
|
65
65
|
// this reaches every consuming app automatically — matches the storesDirs
|
|
66
66
|
// pattern below. @vue-leaflet/vue-leaflet ships untranspiled ESM that
|
|
67
67
|
// breaks Nuxt's build without this, needed by MediaKit/MapCountries.vue.
|
|
68
|
+
// Safe now that leaflet/@vue-leaflet are real dependencies (not
|
|
69
|
+
// peerDependencies) of this package — every consumer gets them
|
|
70
|
+
// transitively via node_modules hoisting, so the module this transpile
|
|
71
|
+
// entry points at always actually exists to resolve.
|
|
68
72
|
build: {
|
|
69
73
|
transpile: ['@vue-leaflet/vue-leaflet'],
|
|
70
74
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mundogamernetwork/shared-ui",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.13",
|
|
4
4
|
"description": "Mundo Gamer Network - Shared UI Layer (Nuxt 3)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
@@ -30,25 +30,25 @@
|
|
|
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",
|
|
34
33
|
"axios": ">=1.0.0",
|
|
35
34
|
"hls.js": ">=1.5.0",
|
|
36
35
|
"laravel-echo": ">=1.15.0",
|
|
37
|
-
"leaflet": ">=1.9.0",
|
|
38
36
|
"nuxt": ">=3.13.0",
|
|
39
37
|
"pinia": ">=2.1.0",
|
|
40
38
|
"pusher-js": ">=8.0.0",
|
|
41
39
|
"vue": ">=3.5.0"
|
|
42
40
|
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
|
43
|
+
"leaflet": "^1.9.4"
|
|
44
|
+
},
|
|
43
45
|
"devDependencies": {
|
|
44
46
|
"@pinia-plugin-persistedstate/nuxt": "^1.2.1",
|
|
45
47
|
"@pinia/nuxt": "^0.5.5",
|
|
46
48
|
"@types/leaflet": "^1.9.18",
|
|
47
|
-
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
|
48
49
|
"axios": "^1.18.1",
|
|
49
50
|
"hls.js": "^1.6.16",
|
|
50
51
|
"laravel-echo": "^2.3.7",
|
|
51
|
-
"leaflet": "^1.9.4",
|
|
52
52
|
"nuxt": "^3.15.4",
|
|
53
53
|
"pinia": "^2.3.1",
|
|
54
54
|
"pusher-js": "^8.5.0",
|
|
@@ -1178,7 +1178,12 @@ onUnmounted(() => {
|
|
|
1178
1178
|
|
|
1179
1179
|
.cards {
|
|
1180
1180
|
display: flex;
|
|
1181
|
-
|
|
1181
|
+
// Cards in the same row have wildly different content amounts
|
|
1182
|
+
// (a badge here, an extra wrapped platform tag there, "days
|
|
1183
|
+
// remaining" not always present) — stretch instead of
|
|
1184
|
+
// flex-start so every card in a row shares the row's height,
|
|
1185
|
+
// with .buttons pinned to the bottom (see .text/.buttons below).
|
|
1186
|
+
align-items: stretch;
|
|
1182
1187
|
gap: 24px;
|
|
1183
1188
|
height: 100%;
|
|
1184
1189
|
flex-flow: wrap;
|
|
@@ -1235,6 +1240,7 @@ onUnmounted(() => {
|
|
|
1235
1240
|
}
|
|
1236
1241
|
|
|
1237
1242
|
.text {
|
|
1243
|
+
flex: 1;
|
|
1238
1244
|
min-height: 170px;
|
|
1239
1245
|
|
|
1240
1246
|
.card-name {
|
|
@@ -1307,6 +1313,10 @@ onUnmounted(() => {
|
|
|
1307
1313
|
justify-content: space-between;
|
|
1308
1314
|
align-items: center;
|
|
1309
1315
|
width: 100%;
|
|
1316
|
+
// Pins the buttons row to the bottom of .text (now
|
|
1317
|
+
// flex:1) regardless of how much content sits above
|
|
1318
|
+
// it — every card's actions line up on the same row.
|
|
1319
|
+
margin-top: auto;
|
|
1310
1320
|
|
|
1311
1321
|
.btn-share {
|
|
1312
1322
|
background: transparent;
|
|
@@ -4,6 +4,7 @@ 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
6
|
import MapCountries from '../../components/MediaKit/MapCountries.vue';
|
|
7
|
+
import PlatformIcon from '../../components/PlatformIcon.vue';
|
|
7
8
|
|
|
8
9
|
const route = useRoute();
|
|
9
10
|
const slug = computed(() => route.params.slug as string);
|
|
@@ -121,14 +122,6 @@ const PLATFORM_LABEL: Record<string, string> = {
|
|
|
121
122
|
linkedin: 'LinkedIn', bluesky: 'Bluesky',
|
|
122
123
|
};
|
|
123
124
|
|
|
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
|
-
|
|
132
125
|
const socials = computed(() => {
|
|
133
126
|
const s = streamer.value?.social_links || {};
|
|
134
127
|
return Object.entries(s).filter(([, v]) => v).map(([k, v]) => ({ platform: k, url: v as string }));
|
|
@@ -358,8 +351,7 @@ function onDownload() {
|
|
|
358
351
|
|
|
359
352
|
<div v-if="socials.length" class="mk-socials no-print">
|
|
360
353
|
<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')">
|
|
361
|
-
<
|
|
362
|
-
<span v-else class="mk-soc-fallback">{{ (PLATFORM_LABEL[s.platform] || s.platform).slice(0, 2).toUpperCase() }}</span>
|
|
354
|
+
<PlatformIcon :platform="s.platform" />
|
|
363
355
|
</a>
|
|
364
356
|
</div>
|
|
365
357
|
</aside>
|
|
@@ -396,7 +388,7 @@ function onDownload() {
|
|
|
396
388
|
<a v-for="p in platforms" :key="p.platform" class="mk-platform" :href="p.url || undefined" target="_blank" rel="noopener" @click="track('click')">
|
|
397
389
|
<div class="pl-head">
|
|
398
390
|
<span class="pl-name-group">
|
|
399
|
-
<
|
|
391
|
+
<PlatformIcon class="pl-icon" :platform="p.platform" />
|
|
400
392
|
<span class="pl-name">{{ PLATFORM_LABEL[p.platform] || p.platform }}</span>
|
|
401
393
|
</span>
|
|
402
394
|
<span v-if="p.verified" class="pl-verified" :title="$t('kit.media.verified')">✓</span>
|
|
@@ -646,10 +638,8 @@ function onDownload() {
|
|
|
646
638
|
<MediaKitWallBlock :user-id="userId" @wall-status="hasMural = $event" />
|
|
647
639
|
</section>
|
|
648
640
|
|
|
649
|
-
<footer class="mk-footer">
|
|
650
|
-
<p
|
|
651
|
-
<a v-if="!isPremium" :href="`${agencyBase}/dashboard/media-kit`" target="_blank" rel="noopener" class="kit-footer__cta">{{ $t('kit.media.create_yours') }}</a>
|
|
652
|
-
<p class="mk-footer-meta">{{ $t('kit.media.generated') }} {{ kit.generated_at?.slice(0, 10) }}</p>
|
|
641
|
+
<footer v-if="!isPremium" class="mk-footer">
|
|
642
|
+
<p class="kit-footer__text">{{ $t('kit.press.made_with') }} <strong>Mundo Gamer Agency</strong> · <a :href="`${agencyBase}/dashboard/media-kit`" target="_blank" rel="noopener" class="kit-footer__cta">{{ $t('kit.media.create_yours') }}</a></p>
|
|
653
643
|
</footer>
|
|
654
644
|
</div>
|
|
655
645
|
</template>
|
|
@@ -821,7 +811,6 @@ function onDownload() {
|
|
|
821
811
|
|
|
822
812
|
&:hover { border-color: var(--kit-accent); color: var(--kit-accent); }
|
|
823
813
|
}
|
|
824
|
-
.mk-soc-fallback { font-size: 11px; font-weight: 700; }
|
|
825
814
|
|
|
826
815
|
/* Buttons (shared) */
|
|
827
816
|
.kit-btn {
|
|
@@ -1095,11 +1084,6 @@ function onDownload() {
|
|
|
1095
1084
|
text-align: center;
|
|
1096
1085
|
strong { color: var(--kit-accent); font-weight: 700; }
|
|
1097
1086
|
}
|
|
1098
|
-
.mk-footer-meta {
|
|
1099
|
-
color: var(--kit-muted);
|
|
1100
|
-
font-size: 13px;
|
|
1101
|
-
margin: 0;
|
|
1102
|
-
}
|
|
1103
1087
|
|
|
1104
1088
|
/* Responsive */
|
|
1105
1089
|
@media (max-width: 840px) {
|
|
@@ -619,8 +619,8 @@ useHead(() => ({
|
|
|
619
619
|
</section>
|
|
620
620
|
|
|
621
621
|
<footer class="kit-footer">
|
|
622
|
-
<p v-if="!kit.no_branding" class="kit-footer__text">{{ $t('kit.press.made_with') }} <strong>Mundo Gamer Agency</strong></p>
|
|
623
|
-
<a :href="kit.create_kit_url || `${agencyBase}/presskit`" target="_blank" rel="noopener" class="kit-footer__cta">{{ $t('kit.press.create_yours') }}</a>
|
|
622
|
+
<p v-if="!kit.no_branding" class="kit-footer__text">{{ $t('kit.press.made_with') }} <strong>Mundo Gamer Agency</strong> · <a :href="kit.create_kit_url || `${agencyBase}/presskit`" target="_blank" rel="noopener" class="kit-footer__cta">{{ $t('kit.press.create_yours') }}</a></p>
|
|
623
|
+
<a v-else :href="kit.create_kit_url || `${agencyBase}/presskit`" target="_blank" rel="noopener" class="kit-footer__cta">{{ $t('kit.press.create_yours') }}</a>
|
|
624
624
|
</footer>
|
|
625
625
|
</template>
|
|
626
626
|
</div>
|
|
@@ -157,7 +157,7 @@ export interface Campaign {
|
|
|
157
157
|
status?: number | boolean
|
|
158
158
|
quantity?: number
|
|
159
159
|
request_user_status?: number
|
|
160
|
-
platforms?: Array<{ id: number; name: string; slug: string }>
|
|
160
|
+
platforms?: Array<{ id: number; name: string; slug: string; alternative_name?: string | null }>
|
|
161
161
|
regions?: Array<{ id: number; name: string; slug: string }>
|
|
162
162
|
requests?: Array<{ id: number; key_item_id?: number; admin_notes?: string }>
|
|
163
163
|
company?: { name: string; email?: string; twitter?: string; thumbnail_url?: string }
|
|
@@ -187,6 +187,7 @@ export interface Platform {
|
|
|
187
187
|
id: number
|
|
188
188
|
name: string
|
|
189
189
|
slug: string
|
|
190
|
+
alternative_name?: string | null
|
|
190
191
|
}
|
|
191
192
|
|
|
192
193
|
export interface CampaignsResponse {
|
|
@@ -332,7 +333,7 @@ export const fetchCampaignBySlug = async (slug: string) => {
|
|
|
332
333
|
request_id: k.requests?.[0]?.id,
|
|
333
334
|
request_item_id: k.requests?.[0]?.key_item_id,
|
|
334
335
|
request_admin_notes: k.requests?.[0]?.admin_notes ?? null,
|
|
335
|
-
platforms: (k.platforms || []).map((p: any) => ({ id: p.id, name: p.name, slug: p.slug })),
|
|
336
|
+
platforms: (k.platforms || []).map((p: any) => ({ id: p.id, name: p.name, slug: p.slug, alternative_name: p.alternative_name ?? null })),
|
|
336
337
|
regions: (k.regions || []).map((r: any) => ({ id: r.id, name: r.name, slug: r.slug })),
|
|
337
338
|
}
|
|
338
339
|
}
|