@stackonward/cli 1.3.3 → 1.4.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 (61) hide show
  1. package/dist/index.js +33 -34
  2. package/dist/index.js.map +1 -1
  3. package/dist/resources/components/nuxt/site-source/app/app.vue +4 -2
  4. package/dist/resources/components/nuxt/site-source/app/assets/css/site-shell.css +50 -50
  5. package/dist/resources/components/nuxt/site-source/app/components/{site/ApplicationHeader.vue → app/Header.vue} +3 -3
  6. package/dist/resources/components/nuxt/site-source/app/components/{site/ApplicationShell.vue → app/Shell.vue} +2 -2
  7. package/dist/resources/components/nuxt/site-source/app/components/{site/ApplicationSidebar.vue → app/Sidebar.vue} +2 -2
  8. package/dist/resources/components/nuxt/site-source/app/components/{ui/CheckoutStatus.vue → checkout/Status.vue} +8 -3
  9. package/dist/resources/components/nuxt/site-source/app/components/{ui/CheckoutSummary.vue → checkout/Summary.vue} +11 -11
  10. package/dist/resources/components/nuxt/site-source/app/components/{site/CookieConsent.vue → consent/Banner.vue} +3 -3
  11. package/dist/resources/components/nuxt/site-source/app/components/{site/ContentArticlePage.vue → content/Article.vue} +3 -3
  12. package/dist/resources/components/nuxt/site-source/app/components/{site/ContentListPage.vue → content/List.vue} +2 -2
  13. package/dist/resources/components/nuxt/site-source/app/components/{ui/GoogleSignInButton.vue → google/SignInButton.vue} +3 -3
  14. package/dist/resources/components/nuxt/site-source/app/components/{site/LocaleSwitcher.vue → locale/Menu.vue} +2 -2
  15. package/dist/resources/components/nuxt/site-source/app/components/site/{MarketingFooter.vue → Footer.vue} +8 -8
  16. package/dist/resources/components/nuxt/site-source/app/components/site/{MarketingHeader.vue → Header.vue} +27 -27
  17. package/dist/resources/components/nuxt/site-source/app/components/site/Shell.vue +29 -0
  18. package/dist/resources/components/nuxt/site-source/app/components/{site/ThemeSwitcher.vue → theme/Menu.vue} +2 -2
  19. package/dist/resources/components/nuxt/site-source/app/components/ui/{BaseButton.vue → Button.vue} +1 -8
  20. package/dist/resources/components/nuxt/site-source/app/components/ui/InfiniteScroll.vue +2 -2
  21. package/dist/resources/components/nuxt/site-source/app/components/{ui/YoutubeEmbed.vue → youtube/Embed.vue} +10 -2
  22. package/dist/resources/components/nuxt/site-source/app/composables/useConsent.ts +8 -10
  23. package/dist/resources/components/nuxt/site-source/app/composables/useNavigation.ts +9 -14
  24. package/dist/resources/components/nuxt/site-source/app/composables/useSeo.ts +3 -1
  25. package/dist/resources/components/nuxt/site-source/app/composables/useSiteShell.ts +19 -22
  26. package/dist/resources/components/nuxt/site-source/app/consent/types.ts +59 -0
  27. package/dist/resources/components/nuxt/site-source/app/content/types.ts +17 -0
  28. package/dist/resources/components/nuxt/site-source/app/layouts/app.vue +2 -2
  29. package/dist/resources/components/nuxt/site-source/app/layouts/default.vue +2 -2
  30. package/dist/resources/components/nuxt/site-source/app/navigation/types.ts +68 -0
  31. package/dist/resources/components/nuxt/site-source/app/plugins/consent.ts +2 -2
  32. package/dist/resources/components/nuxt/site-source/app/site/config.ts +35 -0
  33. package/dist/resources/components/registry.json +63 -51
  34. package/dist/resources/registry.json +6 -6
  35. package/dist/resources/templates/nuxt/README.md +3 -3
  36. package/dist/resources/templates/nuxt/app/app.config.ts +1 -1
  37. package/dist/resources/templates/nuxt/app/i18n/locales/en.json +1 -1
  38. package/dist/resources/templates/nuxt/app/pages/app/index.vue +1 -1
  39. package/dist/resources/templates/nuxt/app/pages/authors/[slug].vue +2 -2
  40. package/dist/resources/templates/nuxt/app/pages/blog/[slug].vue +4 -3
  41. package/dist/resources/templates/nuxt/app/pages/blog/category/[category].vue +2 -2
  42. package/dist/resources/templates/nuxt/app/pages/blog/index.vue +2 -2
  43. package/dist/resources/templates/nuxt/app/pages/legal/cookies.vue +3 -3
  44. package/dist/resources/templates/nuxt/app/pages/legal/privacy.vue +2 -2
  45. package/dist/resources/templates/nuxt/app/pages/legal/terms.vue +2 -2
  46. package/dist/resources/templates/nuxt/app/pages/ui/index.vue +45 -45
  47. package/dist/resources/templates/nuxt/nuxt.config.ts +4 -10
  48. package/dist/resources/templates/nuxt/package.json +2 -2
  49. package/dist/resources/templates/nuxt/test/e2e/rendering.test.ts +1 -0
  50. package/dist/resources/templates/nuxt/test/unit/consent.test.ts +4 -7
  51. package/package.json +3 -3
  52. package/dist/resources/components/nuxt/site-source/app/components/site/MarketingShell.vue +0 -33
  53. package/dist/resources/components/nuxt/site-source/app/types/site-shell.ts +0 -172
  54. /package/dist/resources/components/nuxt/site-source/app/components/{site/ConsentSettingsButton.vue → consent/Settings.vue} +0 -0
  55. /package/dist/resources/components/nuxt/site-source/app/components/{site/StaticPage.vue → content/Document.vue} +0 -0
  56. /package/dist/resources/components/nuxt/site-source/app/components/{site/ToastViewport.vue → feedback/Toast.vue} +0 -0
  57. /package/dist/resources/components/nuxt/site-source/app/components/site/{SiteBrand.vue → Brand.vue} +0 -0
  58. /package/dist/resources/components/nuxt/site-source/app/components/ui/{BaseGradientBorder.vue → GradientBorder.vue} +0 -0
  59. /package/dist/resources/components/nuxt/site-source/app/components/ui/{BaseModal.vue → Modal.vue} +0 -0
  60. /package/dist/resources/components/nuxt/site-source/app/components/ui/{BasePopover.vue → Popover.vue} +0 -0
  61. /package/dist/resources/components/nuxt/site-source/app/components/ui/{BaseText.vue → Text.vue} +0 -0
@@ -1,6 +1,6 @@
1
1
  import { defineNuxtConfig } from "nuxt/config";
2
2
 
3
- const siteEnv = process.env.NUXT_PUBLIC_SITE_ENV || "development";
3
+ const environment = process.env.NUXT_PUBLIC_SITE_ENV || "development";
4
4
  const siteUrl = process.env.NUXT_PUBLIC_SITE_URL || "https://example.com";
5
5
  const gtmId = process.env.NUXT_PUBLIC_GTM_ID || "";
6
6
 
@@ -24,21 +24,15 @@ export default defineNuxtConfig({
24
24
  alwaysRedirect: false,
25
25
  },
26
26
  },
27
- components: [
28
- {
29
- path: "~/components",
30
- pathPrefix: false,
31
- },
32
- ],
33
27
  imports: {
34
28
  dirs: ["~/composables"],
35
29
  },
36
- googleTagManager: {
30
+ gtm: {
37
31
  id: gtmId,
38
32
  dataLayerName: process.env.NUXT_PUBLIC_ANALYTICS_DATA_LAYER || "dataLayer",
39
33
  analytics: {
40
34
  applicationId: "{{projectName}}",
41
- environment: siteEnv,
35
+ environment,
42
36
  debug: process.env.NUXT_PUBLIC_ANALYTICS_DEBUG === "true",
43
37
  consent: {
44
38
  required: process.env.NUXT_PUBLIC_ANALYTICS_REQUIRE_CONSENT !== "false",
@@ -70,7 +64,7 @@ export default defineNuxtConfig({
70
64
  },
71
65
  site: {
72
66
  url: process.env.NUXT_PUBLIC_SITE_URL || "",
73
- env: siteEnv,
67
+ environment,
74
68
  name: process.env.NUXT_PUBLIC_SITE_NAME || "{{projectName}}",
75
69
  description:
76
70
  process.env.NUXT_PUBLIC_SITE_DESCRIPTION || "Premium product media production workspace.",
@@ -29,9 +29,9 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@stackonward/api-client": "^0.0.2",
32
- "@stackonward/google-tag-manager-nuxt": "^0.2.3",
32
+ "@stackonward/google-tag-manager-nuxt": "^0.3.0",
33
33
  "@stackonward/nuxt-layer-base": "^0.0.3",
34
- "@stackonward/nuxt-site-shell": "^0.2.0"
34
+ "@stackonward/nuxt-site-shell": "^0.3.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@commitlint/cli": "^21.2.2",
@@ -8,6 +8,7 @@ describe("application rendering", () => {
8
8
  const html = await $fetch<string>("/");
9
9
 
10
10
  expect(html).toContain("<html");
11
+ expect(html).toContain("<title>Product Media Studio - generated-nuxt</title>");
11
12
  expect(html).toContain("<main");
12
13
  });
13
14
  });
@@ -1,10 +1,7 @@
1
1
  import { computed, ref } from "vue";
2
2
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
- import {
4
- ConsentLifecycleError,
5
- createSiteConsentController,
6
- } from "../../app/composables/useConsent";
7
- import type { ConsentState, SiteShellConsentConfig } from "../../app/types/site-shell";
3
+ import { ConsentLifecycleError, createConsentController } from "../../app/composables/useConsent";
4
+ import type { ConsentConfig, ConsentState } from "../../app/consent/types";
8
5
 
9
6
  class ControlledStorage implements Storage {
10
7
  readonly values = new Map<string, string>();
@@ -41,7 +38,7 @@ class ControlledStorage implements Storage {
41
38
  }
42
39
 
43
40
  const storageKey = "sample-analytics-consent-v1";
44
- const config: SiteShellConsentConfig = {
41
+ const config: ConsentConfig = {
45
42
  enabled: true,
46
43
  storageKey,
47
44
  policyRevision: "1",
@@ -112,7 +109,7 @@ describe("site consent controller", () => {
112
109
  persistence: "none",
113
110
  error: null,
114
111
  });
115
- const controller = createSiteConsentController({
112
+ const controller = createConsentController({
116
113
  state,
117
114
  config: computed(() => config),
118
115
  analytics: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackonward/cli",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "description": "StackOnward CLI for creating projects and installing reusable components and snippets",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -36,8 +36,8 @@
36
36
  "ora": "^8.0.0",
37
37
  "prompts": "^2.4.2",
38
38
  "zod": "4",
39
- "@stackonward/google-tag-manager": "0.1.1",
40
- "@stackonward/api-client": "0.0.2"
39
+ "@stackonward/api-client": "0.0.2",
40
+ "@stackonward/google-tag-manager": "0.2.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/fs-extra": "^11.0.4",
@@ -1,33 +0,0 @@
1
- <script setup lang="ts">
2
- const LazyMarketingHeader = defineLazyHydrationComponent(
3
- "idle",
4
- () => import("./MarketingHeader.vue"),
5
- );
6
- const LazyMarketingFooter = defineLazyHydrationComponent(
7
- "visible",
8
- () => import("./MarketingFooter.vue"),
9
- );
10
- </script>
11
-
12
- <template>
13
- <div class="marketing-shell">
14
- <slot name="header">
15
- <LazyMarketingHeader :hydrate-on-idle="800" />
16
- </slot>
17
-
18
- <main id="site-content" class="marketing-shell__main">
19
- <slot />
20
- </main>
21
-
22
- <slot name="footer">
23
- <LazyMarketingFooter hydrate-on-visible />
24
- </slot>
25
-
26
- <div class="site-floating-stack">
27
- <BackToTop />
28
- <slot name="consent">
29
- <CookieConsent />
30
- </slot>
31
- </div>
32
- </div>
33
- </template>
@@ -1,172 +0,0 @@
1
- import type { ComputedRef, DeepReadonly, Ref } from "vue";
2
-
3
- export interface LocalizedNavigationItemConfig {
4
- readonly labelKey: string;
5
- readonly to?: string;
6
- readonly external?: boolean;
7
- readonly descriptionKey?: string;
8
- readonly children?: readonly LocalizedNavigationItemConfig[];
9
- }
10
-
11
- export interface MarketingNavigationItem {
12
- readonly label: string;
13
- readonly to?: string;
14
- readonly external?: boolean;
15
- readonly description?: string;
16
- readonly children?: readonly MarketingNavigationItem[];
17
- }
18
-
19
- export interface AppNavigationItemConfig {
20
- readonly labelKey: string;
21
- readonly to: string;
22
- readonly icon?: string;
23
- readonly badge?: string;
24
- }
25
-
26
- export interface AppNavigationItem extends Omit<AppNavigationItemConfig, "labelKey"> {
27
- readonly label: string;
28
- }
29
-
30
- export interface NavigationGroupConfig {
31
- readonly labelKey?: string;
32
- readonly items: readonly AppNavigationItemConfig[];
33
- }
34
-
35
- export interface NavigationGroup {
36
- readonly label?: string;
37
- readonly items: readonly AppNavigationItem[];
38
- }
39
-
40
- export interface FooterGroupConfig {
41
- readonly titleKey: string;
42
- readonly links: readonly LocalizedNavigationItemConfig[];
43
- }
44
-
45
- export interface FooterGroup {
46
- readonly title: string;
47
- readonly links: readonly MarketingNavigationItem[];
48
- }
49
-
50
- export interface SocialLinkConfig {
51
- readonly labelKey: string;
52
- readonly href: string;
53
- }
54
-
55
- export interface SocialLink {
56
- readonly label: string;
57
- readonly href: string;
58
- }
59
-
60
- export interface ContentListItem {
61
- readonly title: string;
62
- readonly description?: string;
63
- readonly to: string;
64
- readonly category?: string;
65
- readonly date?: string;
66
- readonly author?: string;
67
- }
68
-
69
- export interface ContentArticle {
70
- readonly title: string;
71
- readonly description?: string;
72
- readonly category?: string;
73
- readonly author?: string;
74
- readonly date?: string;
75
- readonly updatedAt?: string;
76
- }
77
-
78
- export interface StorageDisclosureConfig {
79
- readonly name: string;
80
- readonly category: "necessary" | "preferences" | "analytics";
81
- readonly purposeKey: string;
82
- readonly retentionKey: string;
83
- readonly providerKey: string;
84
- }
85
-
86
- export interface SiteShellConsentConfig {
87
- readonly enabled: boolean;
88
- readonly storageKey: string;
89
- readonly policyRevision: string;
90
- readonly retentionDays: number;
91
- readonly policyPath: string;
92
- }
93
-
94
- export interface SiteShellConfig {
95
- readonly name: string;
96
- readonly descriptionKey: string;
97
- readonly url: string;
98
- readonly defaultLocale: string;
99
- readonly homePath: string;
100
- readonly appPath: string;
101
- readonly logoText: string;
102
- readonly primaryActionLabelKey: string;
103
- readonly secondaryActionLabelKey: string;
104
- readonly secondaryActionPath: string;
105
- readonly consent: SiteShellConsentConfig;
106
- readonly storageDisclosures: readonly StorageDisclosureConfig[];
107
- readonly navigation: {
108
- readonly marketing: readonly LocalizedNavigationItemConfig[];
109
- readonly app: readonly NavigationGroupConfig[];
110
- readonly footer: readonly FooterGroupConfig[];
111
- readonly legal: readonly LocalizedNavigationItemConfig[];
112
- readonly social: readonly SocialLinkConfig[];
113
- };
114
- readonly content: {
115
- readonly blogPath: string;
116
- readonly authorPath: string;
117
- readonly previewPath: string;
118
- readonly sitemapSourcePath: string;
119
- };
120
- }
121
-
122
- export interface ResolvedSiteNavigation {
123
- readonly marketingNav: Readonly<ComputedRef<readonly MarketingNavigationItem[]>>;
124
- readonly appNavGroups: Readonly<ComputedRef<readonly NavigationGroup[]>>;
125
- readonly footerGroups: Readonly<ComputedRef<readonly FooterGroup[]>>;
126
- readonly legalLinks: Readonly<ComputedRef<readonly MarketingNavigationItem[]>>;
127
- readonly socialLinks: Readonly<ComputedRef<readonly SocialLink[]>>;
128
- readonly primaryActionLabel: Readonly<ComputedRef<string>>;
129
- readonly secondaryActionLabel: Readonly<ComputedRef<string>>;
130
- }
131
-
132
- export type ConsentValue = "accepted" | "rejected";
133
-
134
- export type ConsentPersistenceError =
135
- | "read-failed"
136
- | "write-failed"
137
- | "clear-failed"
138
- | "write-and-clear-failed";
139
-
140
- export interface ConsentState {
141
- decision: ConsentValue | null;
142
- ready: boolean;
143
- settingsOpen: boolean;
144
- persistence: "none" | "persisted" | "cleared" | "cleanup-failed" | "session-only";
145
- error: ConsentPersistenceError | null;
146
- }
147
-
148
- export type ConsentInitializationResult =
149
- | { status: "restored"; value: ConsentValue }
150
- | { status: "undecided"; cleanup: "not-required" | "cleared" }
151
- | { status: "undecided"; cleanup: "failed"; error: "clear-failed" }
152
- | { status: "storage-unavailable"; error: "read-failed" };
153
-
154
- export type ConsentMutationResult =
155
- | { status: "persisted"; value: ConsentValue }
156
- | { status: "cleared"; value: "rejected"; error: "write-failed" }
157
- | {
158
- status: "session-only";
159
- value: ConsentValue;
160
- error: "write-failed" | "write-and-clear-failed";
161
- };
162
-
163
- export interface SiteConsentController {
164
- readonly state: DeepReadonly<Ref<ConsentState>>;
165
- readonly visible: Readonly<ComputedRef<boolean>>;
166
- initialize(): ConsentInitializationResult;
167
- accept(): ConsentMutationResult;
168
- reject(): ConsentMutationResult;
169
- openSettings(): void;
170
- closeSettings(): void;
171
- dispose(): void;
172
- }