@xenterprises/nuxt-x-marketing 1.8.0 → 1.9.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.
package/CHANGELOG.md CHANGED
@@ -30,6 +30,22 @@ 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.9.0] - 2026-10-12
34
+
35
+ All additions are opt-in; with none of them used, rendered HTML and pixels are identical to 1.8.0.
36
+
37
+ ### Added
38
+
39
+ - **`XXLegal` affiliate disclosure** (`disclosure` prop, or `appConfig.xMarketing.footer.disclosure`),
40
+ shaped `{ before, link: { label, to }, after? }`. Renders one `<p>` above the copyright row with a
41
+ same-tab `NuxtLink` inline. Follows the 1.8.0 `container` prop and `xMarketing.container: '7xl'`.
42
+ `disclosure: false` suppresses an appConfig value on one instance.
43
+
44
+ ### Fixed
45
+
46
+ - **`XXSkipLink`** now moves focus to the target on activation (adds `tabindex="-1"` when the
47
+ target is not focusable), so the next Tab continues inside main content. No style changes.
48
+
33
49
  ## [1.8.0] - 2026-10-12
34
50
 
35
51
  All additions are opt-in; with none of them used, rendered HTML and pixels are identical to 1.7.0.
package/app/app.config.ts CHANGED
@@ -57,6 +57,9 @@ export default defineAppConfig({
57
57
  footer: {
58
58
  /** Set false to opt out of the default footer in the shipped shell. */
59
59
  active: true as boolean,
60
+ /** 1.9.0 opt-in affiliate disclosure rendered by XXLegal:
61
+ * { before: string, link: { label, to }, after?: string } */
62
+ disclosure: undefined as undefined | { before: string; link: { label: string; to: string }; after?: string },
60
63
  logo: {
61
64
  src: undefined,
62
65
  alt: undefined,
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <footer
3
+ v-if="!resolvedDisclosure"
3
4
  class="bg-gray-900 text-gray-400 text-xs relative overflow-visible pt-2"
4
5
  >
5
6
  <img
@@ -13,6 +14,40 @@
13
14
  {{ resolvedCopyright }}
14
15
  </div>
15
16
 
17
+ <nav
18
+ v-if="resolvedLinks.length"
19
+ class="text-center md:text-right flex flex-wrap justify-center gap-4"
20
+ >
21
+ <a
22
+ v-for="link in resolvedLinks"
23
+ :key="link.label"
24
+ :href="link.href"
25
+ class="hover:underline"
26
+ target="_blank"
27
+ >
28
+ {{ link.label }}
29
+ </a>
30
+ </nav>
31
+ </div>
32
+ </footer>
33
+ <footer
34
+ v-else
35
+ class="bg-gray-900 text-gray-400 text-xs relative overflow-visible pt-2"
36
+ >
37
+ <img
38
+ v-if="resolvedLogo.src"
39
+ :src="resolvedLogo.src"
40
+ :alt="resolvedLogo.alt"
41
+ class="h-6 w-6 mx-auto -mt-4 relative z-10"
42
+ />
43
+ <p :class="disclosureClass" data-x-disclosure>
44
+ {{ resolvedDisclosure.before }}<NuxtLink :to="resolvedDisclosure.link.to" class="underline hover:text-white">{{ resolvedDisclosure.link.label }}</NuxtLink>{{ resolvedDisclosure.after }}
45
+ </p>
46
+ <div :class="innerClass">
47
+ <div class="text-center md:text-left">
48
+ {{ resolvedCopyright }}
49
+ </div>
50
+
16
51
  <nav
17
52
  v-if="resolvedLinks.length"
18
53
  class="text-center md:text-right flex flex-wrap justify-center gap-4"
@@ -58,6 +93,15 @@ const props = defineProps({
58
93
  default: "",
59
94
  validator: (v) => ["", "default", "lg"].includes(v),
60
95
  },
96
+ /**
97
+ * Affiliate disclosure (1.9.0+, opt-in). { before, link: { label, to }, after? } rendered as one
98
+ * <p> with a same-tab NuxtLink inline, above the copyright row. Falls back to
99
+ * appConfig.xMarketing.footer.disclosure. Pass false to suppress the appConfig value.
100
+ */
101
+ disclosure: {
102
+ type: [Object, Boolean],
103
+ default: null,
104
+ },
61
105
  /** Logo object { src, alt } (defaults to X Enterprises logo). Pass false to hide. href is ignored; logo is display-only. */
62
106
  logo: {
63
107
  type: [Object, Boolean],
@@ -73,6 +117,20 @@ const innerClass = computed(() => {
73
117
  : "flex flex-col md:flex-row justify-between items-center px-6 pt-3 pb-5 max-w-screen-2xl mx-auto gap-4";
74
118
  });
75
119
 
120
+ const isDisclosure = (d) =>
121
+ !!d && typeof d === "object" && typeof d.before === "string" && !!d.link && !!d.link.label && !!d.link.to;
122
+ const resolvedDisclosure = computed(() => {
123
+ if (props.disclosure === false) return null;
124
+ const d = props.disclosure || appConfig?.xMarketing?.footer?.disclosure;
125
+ return isDisclosure(d) ? { before: d.before, link: d.link, after: d.after || "" } : null;
126
+ });
127
+ const disclosureClass = computed(() => {
128
+ const c = props.container || (appConfig?.xMarketing?.container === "7xl" ? "lg" : "default");
129
+ return c === "lg"
130
+ ? "px-4 sm:px-6 lg:px-8 pt-3 max-w-7xl mx-auto text-center md:text-left"
131
+ : "px-6 pt-3 max-w-screen-2xl mx-auto text-center md:text-left";
132
+ });
133
+
76
134
  // Default X Enterprises values
77
135
  const defaultLogo = {
78
136
  src: "https://cdn.x.enterprises/logo-x.png",
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <a :href="`#${target}`" class="x-skip-link">{{ label }}</a>
2
+ <a :href="`#${target}`" class="x-skip-link" @click="onActivate">{{ label }}</a>
3
3
  </template>
4
4
 
5
5
  <script setup>
@@ -8,7 +8,7 @@
8
8
  * Visually hidden until focused (first Tab), then shown top-left.
9
9
  * Pair with <main id="main"> (or set target).
10
10
  */
11
- defineProps({
11
+ const props = defineProps({
12
12
  /** id of the main content element, without # */
13
13
  target: {
14
14
  type: String,
@@ -20,4 +20,13 @@ defineProps({
20
20
  default: "Skip to content",
21
21
  },
22
22
  });
23
+
24
+ /** 1.9.0: move focus to the target so the next Tab continues from main content. */
25
+ function onActivate() {
26
+ if (typeof document === "undefined") return;
27
+ const el = document.getElementById(props.target);
28
+ if (!el) return;
29
+ if (!el.hasAttribute("tabindex") && el.tabIndex < 0) el.setAttribute("tabindex", "-1");
30
+ el.focus();
31
+ }
23
32
  </script>
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@xenterprises/nuxt-x-marketing",
3
3
  "license": "SEE LICENSE IN LICENSE",
4
4
  "type": "module",
5
- "version": "1.8.0",
5
+ "version": "1.9.0",
6
6
  "main": "./nuxt.config.ts",
7
7
  "scripts": {
8
8
  "dev": "nuxi dev .playground",