@xenterprises/nuxt-x-marketing 1.4.5 → 1.4.7
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
CHANGED
|
@@ -30,6 +30,18 @@ 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.7] - 2026-09-06
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- `XXLegal` and `XFooterXLegal` show the X Enterprises logo as display-only (no link), matching the marketing page standard.
|
|
38
|
+
|
|
39
|
+
## [1.4.6] - 2026-09-06
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- 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`.
|
|
44
|
+
|
|
33
45
|
## [1.4.5] - 2026-09-03
|
|
34
46
|
|
|
35
47
|
### Fixed
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
<footer
|
|
3
3
|
class="bg-gray-900 text-gray-400 text-xs relative overflow-visible pt-2"
|
|
4
4
|
>
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
</a>
|
|
5
|
+
<img
|
|
6
|
+
v-if="resolvedLogo.src"
|
|
7
|
+
:src="resolvedLogo.src"
|
|
8
|
+
:alt="resolvedLogo.alt"
|
|
9
|
+
class="h-6 w-6 mx-auto -mt-4 relative z-10"
|
|
10
|
+
/>
|
|
12
11
|
<div
|
|
13
12
|
class="flex flex-col md:flex-row justify-between items-center px-6 pt-3 pb-5 max-w-screen-2xl mx-auto gap-4"
|
|
14
13
|
>
|
|
@@ -43,7 +42,7 @@ const props = defineProps({
|
|
|
43
42
|
type: Array,
|
|
44
43
|
default: null,
|
|
45
44
|
},
|
|
46
|
-
/** Logo object { src, alt
|
|
45
|
+
/** Logo object { src, alt } (defaults to X Enterprises logo). href is ignored; logo is display-only. */
|
|
47
46
|
logo: {
|
|
48
47
|
type: Object,
|
|
49
48
|
default: null,
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
<footer
|
|
3
3
|
class="bg-gray-900 text-gray-400 text-xs relative overflow-visible pt-2"
|
|
4
4
|
>
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
</a>
|
|
5
|
+
<img
|
|
6
|
+
v-if="resolvedLogo.src"
|
|
7
|
+
:src="resolvedLogo.src"
|
|
8
|
+
:alt="resolvedLogo.alt"
|
|
9
|
+
class="h-6 w-6 mx-auto -mt-4 relative z-10"
|
|
10
|
+
/>
|
|
12
11
|
<div
|
|
13
12
|
class="flex flex-col md:flex-row justify-between items-center px-6 pt-3 pb-5 max-w-screen-2xl mx-auto gap-4"
|
|
14
13
|
>
|
|
@@ -38,6 +37,7 @@
|
|
|
38
37
|
/**
|
|
39
38
|
* XXLegal — X Enterprises branded legal footer bar
|
|
40
39
|
* Defaults to X Enterprises copyright, logo, and legal links.
|
|
40
|
+
* XE logo is display-only (no link), per marketing page standard.
|
|
41
41
|
* Pass props to override any defaults for white-label use.
|
|
42
42
|
*/
|
|
43
43
|
const props = defineProps({
|
|
@@ -51,7 +51,7 @@ const props = defineProps({
|
|
|
51
51
|
type: Array,
|
|
52
52
|
default: null,
|
|
53
53
|
},
|
|
54
|
-
/** Logo object { src, alt
|
|
54
|
+
/** Logo object { src, alt } (defaults to X Enterprises logo). Pass false to hide. href is ignored; logo is display-only. */
|
|
55
55
|
logo: {
|
|
56
56
|
type: [Object, Boolean],
|
|
57
57
|
default: null,
|
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>
|