@mundogamernetwork/shared-ui 1.0.0

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.
Files changed (87) hide show
  1. package/README.md +283 -0
  2. package/components/PressKit/AssetGallery.vue +349 -0
  3. package/components/PressKit/Awards.vue +100 -0
  4. package/components/PressKit/Credits.vue +78 -0
  5. package/components/PressKit/FactSheet.vue +204 -0
  6. package/components/PressKit/Hero.vue +143 -0
  7. package/components/PressKit/Quotes.vue +80 -0
  8. package/components/PressKit/VideoPlayer.vue +134 -0
  9. package/components/checkout/MgCartItemList.vue +214 -0
  10. package/components/checkout/MgCartSummary.vue +204 -0
  11. package/components/checkout/MgCheckoutSidebar.vue +230 -0
  12. package/components/checkout/MgGuestEmailForm.vue +97 -0
  13. package/components/checkout/MgPaymentMethodSelector.vue +162 -0
  14. package/components/checkout/MgPixQRCode.vue +222 -0
  15. package/components/indie-wall/IndieWallLeaderboard.vue +208 -0
  16. package/components/indie-wall/MuralCanvas.vue +481 -0
  17. package/components/indie-wall/StepBlock.vue +314 -0
  18. package/components/indie-wall/StepCustomize.vue +530 -0
  19. package/components/indie-wall/StepGoal.vue +169 -0
  20. package/components/indie-wall/StepPackage.vue +145 -0
  21. package/components/indie-wall/StepPay.vue +209 -0
  22. package/components/indie-wall/SupportStepper.vue +372 -0
  23. package/components/invoices/MgInvoiceDownload.vue +50 -0
  24. package/components/pricing/MgBillingToggle.vue +74 -0
  25. package/components/pricing/MgPricingCard.vue +245 -0
  26. package/components/ui/Header/MgMessageCard.vue +147 -0
  27. package/components/ui/Header/MgMessageModal.vue +414 -0
  28. package/components/ui/Header/MgNotificationCard.vue +200 -0
  29. package/components/ui/Header/MgNotificationsModal.vue +125 -0
  30. package/components/ui/MgAnnouncementBanner.vue +147 -0
  31. package/components/ui/MgBanners.vue +23 -0
  32. package/components/ui/MgHeaderComponent.vue +283 -0
  33. package/components/ui/MgHeaderUIConfig.vue +225 -0
  34. package/components/ui/MgHeaderUIUser.vue +301 -0
  35. package/components/ui/MgLoginModal.vue +156 -0
  36. package/components/ui/MgPromotionBanner.vue +185 -0
  37. package/composables/useLogout.ts +42 -0
  38. package/composables/useMgCheckout.ts +287 -0
  39. package/composables/useMgUserNotifications.ts +122 -0
  40. package/composables/usePaymentMethods.ts +75 -0
  41. package/composables/useSubscription.ts +163 -0
  42. package/middleware/auth.global.ts +40 -0
  43. package/nuxt.config.ts +31 -0
  44. package/package.json +40 -0
  45. package/pages/[slug]/index.vue +112 -0
  46. package/pages/about.vue +133 -0
  47. package/pages/blog.vue +430 -0
  48. package/pages/careers.vue +329 -0
  49. package/pages/contact.vue +339 -0
  50. package/pages/faq.vue +317 -0
  51. package/pages/health-check.vue +20 -0
  52. package/pages/icons.vue +58 -0
  53. package/pages/magazine/[slug].vue +209 -0
  54. package/pages/magazine/index.vue +267 -0
  55. package/pages/media-kit/[slug].vue +625 -0
  56. package/pages/mural/[slug].vue +1058 -0
  57. package/pages/partners.vue +290 -0
  58. package/pages/press.vue +237 -0
  59. package/pages/presskit/[slug].vue +191 -0
  60. package/pages/roadmap.vue +355 -0
  61. package/pages/status.vue +199 -0
  62. package/pages/team.vue +266 -0
  63. package/pages/wall/[slug].vue +11 -0
  64. package/plugins/auth.client.ts +17 -0
  65. package/plugins/echo.client.ts +132 -0
  66. package/services/authService.ts +95 -0
  67. package/services/chatService.ts +53 -0
  68. package/services/contactService.ts +35 -0
  69. package/services/documentService.ts +16 -0
  70. package/services/httpService.ts +95 -0
  71. package/services/indieWallService.ts +174 -0
  72. package/services/institutionalService.ts +248 -0
  73. package/services/mediaKitService.ts +51 -0
  74. package/services/notificationsService.ts +20 -0
  75. package/services/pressKitService.ts +55 -0
  76. package/stores/announcement.ts +129 -0
  77. package/stores/auth.ts +86 -0
  78. package/stores/chat.ts +150 -0
  79. package/stores/contact.ts +28 -0
  80. package/stores/document.ts +27 -0
  81. package/stores/index.ts +34 -0
  82. package/stores/institutional.ts +231 -0
  83. package/stores/login.ts +27 -0
  84. package/stores/notifications.ts +133 -0
  85. package/stores/promotion.ts +154 -0
  86. package/types/index.ts +135 -0
  87. package/utils/serialize.ts +29 -0
package/pages/faq.vue ADDED
@@ -0,0 +1,317 @@
1
+ <script setup lang="ts">
2
+ import { storeToRefs } from "pinia";
3
+
4
+ definePageMeta({ layout: "default" });
5
+
6
+ const institutionalStore = useInstitutionalStore();
7
+ const { isFaqOpened, faq } = storeToRefs(institutionalStore);
8
+
9
+ const searchTerm = ref("");
10
+
11
+ const showModal = ref(false);
12
+ const modalMessage = ref("");
13
+ const closeModal = () => {
14
+ showModal.value = false;
15
+ };
16
+
17
+ async function fetchFaqs() {
18
+ try {
19
+ const config = useRuntimeConfig();
20
+ const systemId = config.public.mgSharedUi?.systemId || import.meta.env.VITE_SYSTEM_ID;
21
+ await institutionalStore.fetchFaq({
22
+ filter: {
23
+ term: searchTerm.value,
24
+ status: 1,
25
+ platform_id: systemId,
26
+ },
27
+ page: "1",
28
+ per_page: "all",
29
+ });
30
+ } catch (error: any) {
31
+ const errorMessage = error.response?.data?.message;
32
+ modalMessage.value = errorMessage ?? "Could not load FAQs";
33
+ showModal.value = true;
34
+ }
35
+ }
36
+
37
+ onMounted(async () => {
38
+ fetchFaqs();
39
+ });
40
+
41
+ function toggleFaq(index: number) {
42
+ institutionalStore.toggleFaq(index);
43
+ }
44
+ </script>
45
+
46
+ <template>
47
+ <div id="faq" class="container faq">
48
+ <section>
49
+ <div class="header">
50
+ <div>
51
+ <h1 class="title-4">{{ $t("more.faq.title") }}</h1>
52
+ <p>{{ $t("more.faq.subtitle") }}</p>
53
+ </div>
54
+ </div>
55
+ <div class="container">
56
+ <div class="row">
57
+ <div class="col-8 offset-2">
58
+ <div class="search">
59
+ <input
60
+ v-model="searchTerm"
61
+ type="text"
62
+ :placeholder="$t('more.faq.text_search')"
63
+ @keyup.enter="fetchFaqs"
64
+ />
65
+ <button @click="fetchFaqs">
66
+ <MGIcon icon="search" />
67
+ </button>
68
+ </div>
69
+
70
+ <div v-if="faq && faq.data && faq.data.data">
71
+ <div v-if="faq.data.data.length === 0">
72
+ {{ $t("more.faq.no_data") }}
73
+ </div>
74
+ <div
75
+ v-for="(item, index) in faq.data.data"
76
+ v-else
77
+ :key="index"
78
+ class="faq__info"
79
+ >
80
+ <button
81
+ aria-controls="info"
82
+ class="faq__info__toggler"
83
+ @click="toggleFaq(index)"
84
+ >
85
+ {{ item.localized_title }}
86
+ <MGIcon icon="chevron-down" :class="{ rotate: isFaqOpened[index] }" />
87
+ </button>
88
+ <div v-if="isFaqOpened[index]" class="faq__info__text open">
89
+ {{ item.localized_description }}
90
+ </div>
91
+ </div>
92
+
93
+ <div class="press">
94
+ <div class="press__info">
95
+ <div class="press__info--title">
96
+ {{ $t("more.faq.card_title") }}
97
+ </div>
98
+ <div class="press__info--text">
99
+ {{ $t("more.faq.card_text") }}
100
+ <span class="press__info--text--span">
101
+ <a href="mailto:central@mundogamer.network">central@mundogamer.network</a>
102
+ </span>
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </div>
110
+ </section>
111
+
112
+ <div v-if="showModal" class="modal-overlay" @click.self="closeModal">
113
+ <div class="modal-content">
114
+ <p class="modal-message">{{ modalMessage }}</p>
115
+ <button class="modal-close-btn" @click="closeModal">
116
+ {{ $t("more.contact.message_popup.btn_close") }}
117
+ </button>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ </template>
122
+
123
+ <style lang="scss" scoped>
124
+ .faq {
125
+ color: var(--inactive);
126
+ font-size: 0.875rem;
127
+
128
+ .header {
129
+ position: relative;
130
+ height: 200px;
131
+ display: flex;
132
+ justify-content: center;
133
+ align-items: center;
134
+ font-size: 0.875rem;
135
+ margin-bottom: 2rem;
136
+
137
+ & > div {
138
+ width: 480px;
139
+ text-align: center;
140
+ }
141
+
142
+ &:before {
143
+ content: " ";
144
+ display: block;
145
+ position: absolute;
146
+ background: url("@/assets/images/bg-faq.png") no-repeat center center / cover;
147
+ width: 100%;
148
+ height: 100%;
149
+ top: 50%;
150
+ transform: translateY(-50%);
151
+ z-index: -1;
152
+ }
153
+ }
154
+
155
+ .search {
156
+ position: relative;
157
+ display: flex;
158
+ width: 100%;
159
+ margin-bottom: 32px;
160
+ height: 48px;
161
+ background: var(--search-bar-bg);
162
+ align-items: center;
163
+ gap: 4px;
164
+
165
+ input {
166
+ width: 100%;
167
+ height: 48px;
168
+ padding: 0.25rem 1rem;
169
+ border: 0;
170
+ border-bottom: 1px solid var(--search-bar-border-color);
171
+ outline: 0;
172
+ height: 32px;
173
+ padding-left: 0px;
174
+ background: var(--search-bar-bg);
175
+ font-size: 1rem;
176
+ color: var(--search-bar-fg);
177
+ }
178
+
179
+ button {
180
+ position: relative;
181
+ right: 1px;
182
+ width: 48px;
183
+ height: 48px;
184
+ border: 0;
185
+ outline: 0;
186
+ background: var(--search-bar-bg);
187
+ color: var(--search-bar-fg);
188
+ transition: 0.15s ease-in-out;
189
+ z-index: 1;
190
+
191
+ &:hover {
192
+ color: var(--search-bar-active-fg);
193
+ }
194
+ }
195
+ }
196
+
197
+ &__info {
198
+ display: flex;
199
+ flex-direction: column;
200
+ align-items: flex-start;
201
+ gap: 8px;
202
+ align-self: stretch;
203
+ margin-bottom: 16px;
204
+
205
+ &__toggler {
206
+ color: var(--card-cover-title);
207
+ justify-content: space-between;
208
+ display: flex;
209
+ height: 32px;
210
+ padding-left: 16px;
211
+ align-items: center;
212
+ align-self: stretch;
213
+ border-left: 2px solid var(--chip-text);
214
+ transition: color 0.5s ease-out;
215
+ background: transparent;
216
+ border-top: 0;
217
+ border-bottom: 0;
218
+ border-right: 0;
219
+
220
+ .rotate {
221
+ transform: rotate(180deg);
222
+ transition: 0.5s;
223
+ }
224
+
225
+ &:hover {
226
+ color: var(--faq-toggler-active-fg);
227
+ }
228
+ }
229
+
230
+ &__text {
231
+ color: var(--inactive);
232
+ font-size: 14px;
233
+ font-weight: 400;
234
+ line-height: 20px;
235
+
236
+ &.open {
237
+ display: block;
238
+ }
239
+ }
240
+ }
241
+
242
+ .press {
243
+ background-color: var(--chip-background-2);
244
+ padding: 16px;
245
+ display: flex;
246
+ flex-direction: column;
247
+ align-items: flex-start;
248
+ justify-content: center;
249
+ align-self: stretch;
250
+ margin-bottom: 24px;
251
+ margin-top: 24px;
252
+
253
+ &__info {
254
+ &--title {
255
+ color: var(--card-cover-title);
256
+ font-size: 14px;
257
+ font-weight: 600;
258
+ line-height: 20px;
259
+ margin-bottom: 16px;
260
+ }
261
+
262
+ &--text {
263
+ color: var(--card-cover-title);
264
+ font-size: 14px;
265
+ font-weight: 400;
266
+ line-height: 20px;
267
+
268
+ &--span {
269
+ color: var(--chip-text);
270
+ text-decoration-line: underline;
271
+ }
272
+ }
273
+ }
274
+ }
275
+ }
276
+
277
+ .modal-overlay {
278
+ position: fixed;
279
+ top: 0;
280
+ left: 0;
281
+ right: 0;
282
+ bottom: 0;
283
+ background-color: rgba(0, 0, 0, 0.6);
284
+ display: flex;
285
+ justify-content: center;
286
+ align-items: center;
287
+ z-index: 1000;
288
+
289
+ .modal-content {
290
+ background-color: #0a0a0a;
291
+ padding: 2rem;
292
+ max-width: 500px;
293
+ border-radius: 8px;
294
+ text-align: center;
295
+ }
296
+
297
+ .modal-message {
298
+ margin-bottom: 1.5rem;
299
+ font-size: 1.1rem;
300
+ color: #ffffff;
301
+ }
302
+
303
+ .modal-close-btn {
304
+ padding: 0.5rem 1rem;
305
+ font-size: 1rem;
306
+ border: 1px solid #060606;
307
+ border-radius: 4px;
308
+ background-color: #060606;
309
+ color: #ffffff;
310
+ cursor: pointer;
311
+
312
+ &:hover {
313
+ border-color: cyan;
314
+ }
315
+ }
316
+ }
317
+ </style>
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ definePageMeta({ layout: "default" });
3
+ </script>
4
+
5
+ <template>
6
+ <div id="health-check" class="health-check">
7
+ <p>OK</p>
8
+ </div>
9
+ </template>
10
+
11
+ <style lang="scss" scoped>
12
+ .health-check {
13
+ display: flex;
14
+ justify-content: center;
15
+ align-items: center;
16
+ min-height: 200px;
17
+ font-size: 24px;
18
+ color: var(--card-cover-title);
19
+ }
20
+ </style>
@@ -0,0 +1,58 @@
1
+ <script setup lang="ts">
2
+ definePageMeta({ layout: "default" });
3
+
4
+ const icons = [
5
+ "home", "search", "message", "bell", "gear", "user", "chevron-left",
6
+ "chevron-right", "chevron-down", "chevron-up", "close", "menu",
7
+ "link", "star", "heart", "share", "edit", "trash", "plus", "minus",
8
+ "check", "info", "warning", "error", "calendar", "clock", "download",
9
+ "upload", "filter", "sort", "grid", "list", "eye", "eye-off",
10
+ "lock", "unlock", "mail", "phone", "map", "globe", "flag",
11
+ ];
12
+ </script>
13
+
14
+ <template>
15
+ <div id="icons" class="icons-page">
16
+ <h1>Icon Library</h1>
17
+ <div class="icons-grid">
18
+ <div v-for="icon in icons" :key="icon" class="icon-item">
19
+ <MGIcon :icon="icon" size="2x" />
20
+ <span>{{ icon }}</span>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ </template>
25
+
26
+ <style lang="scss" scoped>
27
+ .icons-page {
28
+ padding: 32px;
29
+
30
+ h1 {
31
+ font-size: 24px;
32
+ font-weight: 600;
33
+ color: var(--card-cover-title);
34
+ margin-bottom: 24px;
35
+ }
36
+
37
+ .icons-grid {
38
+ display: grid;
39
+ grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
40
+ gap: 16px;
41
+ }
42
+
43
+ .icon-item {
44
+ display: flex;
45
+ flex-direction: column;
46
+ align-items: center;
47
+ gap: 8px;
48
+ padding: 16px;
49
+ background: var(--chip-background-2);
50
+ color: var(--inactive);
51
+
52
+ span {
53
+ font-size: 11px;
54
+ text-align: center;
55
+ }
56
+ }
57
+ }
58
+ </style>
@@ -0,0 +1,209 @@
1
+ <script setup lang="ts">
2
+ import { getMagazine, getMagazinePages, trackMagazineAnalytic } from "../../services/institutionalService";
3
+
4
+ definePageMeta({ layout: "default" });
5
+
6
+ const route = useRoute();
7
+ const slug = route.params.slug as string;
8
+
9
+ const magazine = ref<any>(null);
10
+ const pages = ref<any[]>([]);
11
+ const loading = ref(true);
12
+ const currentPageIndex = ref(0);
13
+
14
+ async function fetchMagazineData() {
15
+ loading.value = true;
16
+ try {
17
+ const [magResponse, pagesResponse] = await Promise.all([
18
+ getMagazine(slug),
19
+ getMagazinePages(slug),
20
+ ]);
21
+ magazine.value = magResponse.data?.data || magResponse.data;
22
+ pages.value = pagesResponse.data?.data || pagesResponse.data || [];
23
+
24
+ trackMagazineAnalytic(slug, "view").catch(() => {});
25
+ } catch {
26
+ throw createError({ statusCode: 404, statusMessage: "Magazine not found" });
27
+ } finally {
28
+ loading.value = false;
29
+ }
30
+ }
31
+
32
+ function nextPage() {
33
+ if (currentPageIndex.value < pages.value.length - 1) {
34
+ currentPageIndex.value++;
35
+ }
36
+ }
37
+
38
+ function prevPage() {
39
+ if (currentPageIndex.value > 0) {
40
+ currentPageIndex.value--;
41
+ }
42
+ }
43
+
44
+ const currentPage = computed(() => pages.value[currentPageIndex.value] || null);
45
+
46
+ onMounted(() => {
47
+ fetchMagazineData();
48
+ });
49
+ </script>
50
+
51
+ <template>
52
+ <div id="magazine-detail" class="container magazine-detail">
53
+ <div v-if="loading" class="loading">
54
+ <p>{{ $t("components.loading") }}</p>
55
+ </div>
56
+
57
+ <template v-else-if="magazine">
58
+ <div class="magazine-header">
59
+ <h1>{{ magazine.title }}</h1>
60
+ <p v-if="magazine.description">{{ magazine.description }}</p>
61
+ <div class="meta">
62
+ <span v-if="magazine.edition_number">{{ $t("more.magazine.edition") }} #{{ magazine.edition_number }}</span>
63
+ <span>{{ magazine.release_date || magazine.created_at }}</span>
64
+ </div>
65
+ </div>
66
+
67
+ <div v-if="pages.length > 0" class="magazine-reader">
68
+ <div class="page-content">
69
+ <img
70
+ v-if="currentPage?.image_url"
71
+ :src="currentPage.image_url"
72
+ :alt="`Page ${currentPageIndex + 1}`"
73
+ class="page-image"
74
+ />
75
+ <div v-else-if="currentPage?.content" class="page-text" v-html="currentPage.content"></div>
76
+ </div>
77
+
78
+ <div class="page-controls">
79
+ <button :disabled="currentPageIndex <= 0" @click="prevPage">
80
+ <MGIcon icon="chevron-left" />
81
+ {{ $t("components.previous") }}
82
+ </button>
83
+ <span>{{ currentPageIndex + 1 }} / {{ pages.length }}</span>
84
+ <button :disabled="currentPageIndex >= pages.length - 1" @click="nextPage">
85
+ {{ $t("components.next") }}
86
+ <MGIcon icon="chevron-right" />
87
+ </button>
88
+ </div>
89
+ </div>
90
+
91
+ <div v-else-if="magazine.pdf_url" class="magazine-pdf">
92
+ <a :href="magazine.pdf_url" target="_blank" rel="noopener" class="download-btn">
93
+ {{ $t("more.magazine.download_pdf") }}
94
+ </a>
95
+ </div>
96
+ </template>
97
+ </div>
98
+ </template>
99
+
100
+ <style lang="scss" scoped>
101
+ .magazine-detail {
102
+ color: var(--inactive);
103
+ padding: 24px 0;
104
+
105
+ .magazine-header {
106
+ text-align: center;
107
+ margin-bottom: 32px;
108
+
109
+ h1 {
110
+ font-size: 24px;
111
+ font-weight: 600;
112
+ color: var(--card-cover-title);
113
+ margin-bottom: 8px;
114
+ }
115
+
116
+ p {
117
+ font-size: 14px;
118
+ line-height: 20px;
119
+ max-width: 600px;
120
+ margin: 0 auto 12px;
121
+ }
122
+
123
+ .meta {
124
+ display: flex;
125
+ justify-content: center;
126
+ gap: 16px;
127
+ font-size: 12px;
128
+ color: var(--secondary-info-fg);
129
+ }
130
+ }
131
+
132
+ .magazine-reader {
133
+ max-width: 800px;
134
+ margin: 0 auto;
135
+ }
136
+
137
+ .page-content {
138
+ min-height: 500px;
139
+ display: flex;
140
+ justify-content: center;
141
+ align-items: center;
142
+ background: var(--chip-background-2);
143
+ margin-bottom: 16px;
144
+
145
+ .page-image {
146
+ max-width: 100%;
147
+ max-height: 80vh;
148
+ object-fit: contain;
149
+ }
150
+
151
+ .page-text {
152
+ padding: 32px;
153
+ font-size: 14px;
154
+ line-height: 22px;
155
+ }
156
+ }
157
+
158
+ .page-controls {
159
+ display: flex;
160
+ justify-content: center;
161
+ align-items: center;
162
+ gap: 24px;
163
+
164
+ button {
165
+ display: flex;
166
+ align-items: center;
167
+ gap: 4px;
168
+ padding: 8px 16px;
169
+ border: 1px solid var(--search-bar-border-color);
170
+ background: transparent;
171
+ color: var(--card-cover-title);
172
+ cursor: pointer;
173
+
174
+ &:disabled {
175
+ opacity: 0.5;
176
+ cursor: default;
177
+ }
178
+ }
179
+
180
+ span {
181
+ font-size: 14px;
182
+ color: var(--secondary-info-fg);
183
+ }
184
+ }
185
+
186
+ .magazine-pdf {
187
+ text-align: center;
188
+
189
+ .download-btn {
190
+ display: inline-block;
191
+ padding: 12px 32px;
192
+ border: 1px solid var(--chip-text);
193
+ color: var(--chip-text);
194
+ text-decoration: none;
195
+ font-size: 14px;
196
+
197
+ &:hover {
198
+ background: var(--chip-text);
199
+ color: var(--chip-background-2);
200
+ }
201
+ }
202
+ }
203
+
204
+ .loading {
205
+ text-align: center;
206
+ padding: 64px;
207
+ }
208
+ }
209
+ </style>