@mundogamernetwork/shared-ui 1.13.1 → 1.13.3
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.
|
@@ -72,8 +72,12 @@ onMounted(async () => {
|
|
|
72
72
|
try {
|
|
73
73
|
const response = await fetchGamificationSummary();
|
|
74
74
|
summary.value = response?.data?.data ?? response?.data ?? null;
|
|
75
|
-
} catch {
|
|
76
|
-
// Never let a gamification hiccup break the header it sits in
|
|
75
|
+
} catch (error) {
|
|
76
|
+
// Never let a gamification hiccup break the header it sits in — but say
|
|
77
|
+
// so. Swallowing this silently made a deployed bar that renders nothing
|
|
78
|
+
// indistinguishable from a bar that was never deployed, and cost hours
|
|
79
|
+
// of bundle forensics to tell apart.
|
|
80
|
+
console.warn("[MgXpLevelBar] gamification dashboard unavailable", error);
|
|
77
81
|
summary.value = null;
|
|
78
82
|
} finally {
|
|
79
83
|
loaded.value = true;
|
|
@@ -82,13 +86,24 @@ onMounted(async () => {
|
|
|
82
86
|
</script>
|
|
83
87
|
|
|
84
88
|
<template>
|
|
89
|
+
<!--
|
|
90
|
+
The root renders unconditionally so the server and the client agree on
|
|
91
|
+
the node at hydration time. A v-if here produced a comment on the server
|
|
92
|
+
and an <a> on the client, and Vue bails out of hydrating a subtree whose
|
|
93
|
+
node type disagrees — leaving the server markup in place and never
|
|
94
|
+
mounting the component, so onMounted never ran and the bar was silently
|
|
95
|
+
dead. The skeleton is what both sides render before the fetch resolves.
|
|
96
|
+
-->
|
|
85
97
|
<a
|
|
86
|
-
v-if="loaded && level"
|
|
87
98
|
:href="destination"
|
|
88
99
|
class="mg-xp-bar"
|
|
89
|
-
:class="{
|
|
100
|
+
:class="{
|
|
101
|
+
'mg-xp-bar--compact': props.compact,
|
|
102
|
+
'mg-xp-bar--empty': loaded && !level,
|
|
103
|
+
}"
|
|
90
104
|
@click="emit('navigate')"
|
|
91
105
|
>
|
|
106
|
+
<template v-if="level">
|
|
92
107
|
<div class="mg-xp-bar__top">
|
|
93
108
|
<span class="mg-xp-bar__badge">{{ level.current_level }}</span>
|
|
94
109
|
|
|
@@ -107,6 +122,17 @@ onMounted(async () => {
|
|
|
107
122
|
<div class="mg-xp-bar__track">
|
|
108
123
|
<div class="mg-xp-bar__fill" :style="{ width: percent + '%' }" />
|
|
109
124
|
</div>
|
|
125
|
+
</template>
|
|
126
|
+
|
|
127
|
+
<template v-else>
|
|
128
|
+
<div class="mg-xp-bar__top">
|
|
129
|
+
<span class="mg-xp-bar__badge mg-xp-bar__skeleton" />
|
|
130
|
+
<div class="mg-xp-bar__meta">
|
|
131
|
+
<span class="mg-xp-bar__skeleton mg-xp-bar__skeleton--line" />
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
<div class="mg-xp-bar__track" />
|
|
135
|
+
</template>
|
|
110
136
|
</a>
|
|
111
137
|
</template>
|
|
112
138
|
|
|
@@ -228,6 +254,22 @@ onMounted(async () => {
|
|
|
228
254
|
transition: width 0.3s ease;
|
|
229
255
|
}
|
|
230
256
|
|
|
257
|
+
// Hidden only after the fetch resolves with nothing — a client-side change
|
|
258
|
+
// that happens well after hydration, so it cannot cause a mismatch.
|
|
259
|
+
&--empty {
|
|
260
|
+
display: none;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
&__skeleton {
|
|
264
|
+
background: rgba(128, 128, 128, 0.25);
|
|
265
|
+
border-color: transparent;
|
|
266
|
+
|
|
267
|
+
&--line {
|
|
268
|
+
height: 9px;
|
|
269
|
+
width: 70%;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
231
273
|
&--compact {
|
|
232
274
|
padding: 0.35rem 0.5rem;
|
|
233
275
|
}
|