@xenterprises/nuxt-x-marketing 1.4.5 → 1.4.6
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/CHANGELOG.md +6 -0
- package/app/error.vue +96 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
30
30
|
section and its sample product data were dropped with them. Every other section of the
|
|
31
31
|
demo page is unchanged.
|
|
32
32
|
|
|
33
|
+
## [1.4.6] - 2026-09-06
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- Ships `app/error.vue`: branded 404 / 500 (and other status) page with marketing chrome (`XHeaderNav`, `XFooter`), plain copy, and a home CTA via `clearError({ redirect: "/" })`. Consumers override with their own `app/error.vue`.
|
|
38
|
+
|
|
33
39
|
## [1.4.5] - 2026-09-03
|
|
34
40
|
|
|
35
41
|
### Fixed
|
package/app/error.vue
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="min-h-screen flex flex-col">
|
|
3
|
+
<XHeaderNav v-if="headerActive" />
|
|
4
|
+
|
|
5
|
+
<main class="flex-grow flex items-center">
|
|
6
|
+
<UApp>
|
|
7
|
+
<div class="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-24 md:py-32">
|
|
8
|
+
<div class="max-w-xl">
|
|
9
|
+
<p class="xText-eyebrow text-primary-500 mb-4">
|
|
10
|
+
{{ codeLabel }}
|
|
11
|
+
</p>
|
|
12
|
+
<h1 class="xText-display xText-balance">
|
|
13
|
+
{{ title }}
|
|
14
|
+
</h1>
|
|
15
|
+
<p class="mt-6 text-xl text-neutral-600 dark:text-neutral-300">
|
|
16
|
+
{{ description }}
|
|
17
|
+
</p>
|
|
18
|
+
<div class="mt-10 flex flex-wrap gap-4">
|
|
19
|
+
<UButton size="xl" color="primary" @click="goHome">
|
|
20
|
+
Back home
|
|
21
|
+
</UButton>
|
|
22
|
+
<UButton
|
|
23
|
+
v-if="isServerError"
|
|
24
|
+
size="xl"
|
|
25
|
+
color="neutral"
|
|
26
|
+
variant="outline"
|
|
27
|
+
@click="goHome"
|
|
28
|
+
>
|
|
29
|
+
Try again
|
|
30
|
+
</UButton>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</UApp>
|
|
35
|
+
</main>
|
|
36
|
+
|
|
37
|
+
<XFooter v-if="footerActive" />
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
40
|
+
|
|
41
|
+
<script setup>
|
|
42
|
+
/**
|
|
43
|
+
* Layer default error page for 404 / 500 (and other status codes).
|
|
44
|
+
* Replaces Nuxt's stock error UI. Consumers override with their own app/error.vue.
|
|
45
|
+
* error.vue is a full app replacement (not wrapped by app.vue), so chrome is inlined.
|
|
46
|
+
*/
|
|
47
|
+
const props = defineProps({
|
|
48
|
+
error: {
|
|
49
|
+
type: Object,
|
|
50
|
+
required: true,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const appConfig = useAppConfig();
|
|
55
|
+
const xMarketing = appConfig?.xMarketing;
|
|
56
|
+
|
|
57
|
+
const headerActive = computed(() => xMarketing?.header?.active !== false);
|
|
58
|
+
const footerActive = computed(() => xMarketing?.footer?.active !== false);
|
|
59
|
+
|
|
60
|
+
const status = computed(() => {
|
|
61
|
+
const code = props.error?.statusCode ?? props.error?.status;
|
|
62
|
+
return typeof code === "number" ? code : Number(code) || 500;
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const isNotFound = computed(() => status.value === 404);
|
|
66
|
+
const isServerError = computed(() => status.value >= 500);
|
|
67
|
+
|
|
68
|
+
const codeLabel = computed(() => String(status.value));
|
|
69
|
+
|
|
70
|
+
const title = computed(() => {
|
|
71
|
+
if (isNotFound.value) return "Page not found";
|
|
72
|
+
if (isServerError.value) return "Something broke";
|
|
73
|
+
return "Something went wrong";
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const description = computed(() => {
|
|
77
|
+
if (isNotFound.value) {
|
|
78
|
+
return "That page is gone, or the link is wrong.";
|
|
79
|
+
}
|
|
80
|
+
if (isServerError.value) {
|
|
81
|
+
return "We hit a problem on our side. Try again in a minute.";
|
|
82
|
+
}
|
|
83
|
+
return props.error?.statusMessage || props.error?.message || "Please try again.";
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const siteName = computed(() => xMarketing?.name);
|
|
87
|
+
|
|
88
|
+
useSeoMeta({
|
|
89
|
+
title: () => (siteName.value ? `${title.value} | ${siteName.value}` : title.value),
|
|
90
|
+
robots: "noindex",
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
function goHome() {
|
|
94
|
+
clearError({ redirect: "/" });
|
|
95
|
+
}
|
|
96
|
+
</script>
|