@woodsportal/hubspot-kit 1.0.4 → 1.0.26
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 +9 -0
- package/README.md +4 -2
- package/dist/{chunk-JDGIAYHX.js → chunk-GTTIJVAR.js} +43 -3
- package/dist/chunk-GTTIJVAR.js.map +1 -0
- package/dist/cli.js +1400 -338
- package/dist/cli.js.map +1 -1
- package/dist/exec-U2OJATR3.js +12 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/examples/greenfield/module-hybrid-cdn/README.md +40 -3
- package/examples/greenfield/module-hybrid-cdn/public/fields.json +44 -1
- package/examples/greenfield/module-hybrid-cdn/src/app.tsx +8 -0
- package/examples/greenfield/module-hybrid-cdn/src/assets/css/main.dev.css +6 -1
- package/examples/greenfield/module-hybrid-cdn/src/cdn/app-entry.ts +32 -0
- package/examples/greenfield/module-hybrid-cdn/src/cdn/vendor-entry.ts +28 -0
- package/examples/greenfield/module-hybrid-cdn/src/components/layout/section-card.tsx +20 -0
- package/examples/greenfield/module-hybrid-cdn/src/components/layout/starter-nav.tsx +28 -0
- package/examples/greenfield/module-hybrid-cdn/src/components/layout/starter-shell.tsx +18 -0
- package/examples/greenfield/module-hybrid-cdn/src/config/router.ts +4 -0
- package/examples/greenfield/module-hybrid-cdn/src/config/routes.ts +5 -0
- package/examples/greenfield/module-hybrid-cdn/src/defaultData.ts +2 -7
- package/examples/greenfield/module-hybrid-cdn/src/features/starter/components/starter-guide-page.tsx +93 -0
- package/examples/greenfield/module-hybrid-cdn/src/features/starter/components/starter-home-page.tsx +21 -0
- package/examples/greenfield/module-hybrid-cdn/src/features/starter/components/starter-home.tsx +52 -0
- package/examples/greenfield/module-hybrid-cdn/src/features/starter/components/starter-single-page.tsx +17 -0
- package/examples/greenfield/module-hybrid-cdn/src/features/starter/content/woodscli-guide-content.ts +86 -0
- package/examples/greenfield/module-hybrid-cdn/src/features/starter/hooks/use-starter-preview.ts +47 -0
- package/examples/greenfield/module-hybrid-cdn/src/features/starter/index.ts +6 -0
- package/examples/greenfield/module-hybrid-cdn/src/hubspot/bootstrap.ts +10 -0
- package/examples/greenfield/module-hybrid-cdn/src/hubspot/default-data.ts +7 -0
- package/examples/greenfield/module-hybrid-cdn/src/integrations/tanstack-router/router.tsx +25 -0
- package/examples/greenfield/module-hybrid-cdn/src/main.tsx +4 -3
- package/examples/greenfield/module-hybrid-cdn/src/portal/mount-dev-preview.tsx +8 -0
- package/examples/greenfield/module-hybrid-cdn/src/portal/mount-portal.tsx +12 -0
- package/examples/greenfield/module-hybrid-cdn/src/routeTree.gen.ts +77 -0
- package/examples/greenfield/module-hybrid-cdn/src/routes/__root.tsx +15 -0
- package/examples/greenfield/module-hybrid-cdn/src/routes/guide.tsx +7 -0
- package/examples/greenfield/module-hybrid-cdn/src/routes/index.tsx +7 -0
- package/examples/greenfield/module-hybrid-cdn/tsconfig.json +20 -0
- package/examples/greenfield/module-monolith/public/fields.json +44 -1
- package/examples/greenfield/module-monolith/src/app.tsx +8 -0
- package/examples/greenfield/module-monolith/src/assets/css/main.dev.css +8 -0
- package/examples/greenfield/module-monolith/src/components/layout/section-card.tsx +20 -0
- package/examples/greenfield/module-monolith/src/components/layout/starter-nav.tsx +28 -0
- package/examples/greenfield/module-monolith/src/components/layout/starter-shell.tsx +18 -0
- package/examples/greenfield/module-monolith/src/config/router.ts +4 -0
- package/examples/greenfield/module-monolith/src/config/routes.ts +5 -0
- package/examples/greenfield/module-monolith/src/defaultData.ts +2 -7
- package/examples/greenfield/module-monolith/src/features/starter/components/starter-guide-page.tsx +93 -0
- package/examples/greenfield/module-monolith/src/features/starter/components/starter-home-page.tsx +21 -0
- package/examples/greenfield/module-monolith/src/features/starter/components/starter-home.tsx +52 -0
- package/examples/greenfield/module-monolith/src/features/starter/components/starter-single-page.tsx +17 -0
- package/examples/greenfield/module-monolith/src/features/starter/content/woodscli-guide-content.ts +86 -0
- package/examples/greenfield/module-monolith/src/features/starter/hooks/use-starter-preview.ts +47 -0
- package/examples/greenfield/module-monolith/src/features/starter/index.ts +6 -0
- package/examples/greenfield/module-monolith/src/hubspot/default-data.ts +7 -0
- package/examples/greenfield/module-monolith/src/hubspot/types.ts +17 -0
- package/examples/greenfield/module-monolith/src/integrations/tanstack-router/router.tsx +25 -0
- package/examples/greenfield/module-monolith/src/main.tsx +5 -0
- package/examples/greenfield/module-monolith/src/portal/mount-dev-preview.tsx +8 -0
- package/examples/greenfield/module-monolith/src/portal/mount-portal.tsx +12 -0
- package/examples/greenfield/module-monolith/src/routeTree.gen.ts +77 -0
- package/examples/greenfield/module-monolith/src/routes/__root.tsx +15 -0
- package/examples/greenfield/module-monolith/src/routes/guide.tsx +7 -0
- package/examples/greenfield/module-monolith/src/routes/index.tsx +7 -0
- package/examples/greenfield/module-monolith/tsconfig.json +20 -0
- package/package.json +4 -1
- package/scripts/check-hubspot-bundle-size.mjs +5 -2
- package/scripts/ensure-wphs-workspace.mjs +2 -1
- package/scripts/hubspot-module-postbuild.mjs +1 -1
- package/scripts/read-woodsportal-config.mjs +4 -1
- package/scripts/run-hubspot-module-postbuild.mjs +9 -4
- package/scripts/vite/bootstrap-shim-resolver.js +47 -0
- package/scripts/vite/ensure-dev-kit-shims.js +7 -1
- package/scripts/vite/react-dev-plugin-options.js +2 -1
- package/scripts/watch-hubspot.mjs +107 -17
- package/scripts/wphs-paths.mjs +1 -0
- package/scripts/write-audit-artifacts.mjs +2 -1
- package/src/dev/bootstrap-greenfield.tsx +59 -0
- package/src/dev/bootstrap.tsx +46 -0
- package/src/dev-module-config/__tests__/fixtures/fields.json +3014 -0
- package/src/dev-module-config/__tests__/fixtures/golden-module.fixture.ts +102 -0
- package/src/dev-module-config/__tests__/module-config-storage.test.ts +40 -0
- package/src/dev-module-config/__tests__/module-config-transform.test.ts +55 -0
- package/src/dev-module-config/__tests__/normalize-repeater-items.test.ts +46 -0
- package/src/dev-module-config/dev-module-display-name.ts +5 -0
- package/src/dev-module-config/runtime/module-config-bridge.ts +27 -0
- package/src/dev-module-config/runtime/module-config-runtime.ts +185 -0
- package/src/dev-module-config/schema/build-default-item.ts +7 -0
- package/src/dev-module-config/schema/deep-merge.ts +27 -0
- package/src/dev-module-config/schema/extract-defaults.ts +62 -0
- package/src/dev-module-config/schema/normalize-choices.ts +18 -0
- package/src/dev-module-config/schema/normalize-repeater-items.ts +31 -0
- package/src/dev-module-config/schema/parse-fields-json.ts +2 -0
- package/src/dev-module-config/schema/types.ts +75 -0
- package/src/dev-module-config/schema/validate-module-config.ts +81 -0
- package/src/dev-module-config/schema/visibility.ts +130 -0
- package/src/dev-module-config/storage/config-json.ts +46 -0
- package/src/dev-module-config/storage/workspace-store.ts +139 -0
- package/src/dev-module-config/transform/build-hubspot-data.ts +409 -0
- package/src/dev-module-config/ui/FieldRenderer.tsx +353 -0
- package/src/dev-module-config/ui/ModuleConfigAnimatedPresence.tsx +72 -0
- package/src/dev-module-config/ui/ModuleConfigCollapsible.tsx +43 -0
- package/src/dev-module-config/ui/ModuleConfigDockSideIcon.tsx +27 -0
- package/src/dev-module-config/ui/ModuleConfigOverlay.tsx +134 -0
- package/src/dev-module-config/ui/ModuleConfigPersistenceStatus.tsx +89 -0
- package/src/dev-module-config/ui/ModuleConfigShell.tsx +355 -0
- package/src/dev-module-config/ui/ModuleConfigThemeToggle.tsx +32 -0
- package/src/dev-module-config/ui/ModuleConfigUiContext.tsx +65 -0
- package/src/dev-module-config/ui/editors/DeveloperOptionsEditor.tsx +61 -0
- package/src/dev-module-config/ui/editors/MenuOptionsEditor.tsx +103 -0
- package/src/dev-module-config/ui/hubspot/HsColorField.tsx +106 -0
- package/src/dev-module-config/ui/hubspot/HsColorPickerPopover.tsx +210 -0
- package/src/dev-module-config/ui/hubspot/HsFieldLabel.tsx +24 -0
- package/src/dev-module-config/ui/hubspot/HsFieldWidgets.tsx +248 -0
- package/src/dev-module-config/ui/hubspot/HsImageField.tsx +112 -0
- package/src/dev-module-config/ui/hubspot/HsOccurrenceGroupEditor.tsx +243 -0
- package/src/dev-module-config/ui/hubspot/HsRepeaterList.tsx +178 -0
- package/src/dev-module-config/ui/hubspot/HsSectionHeader.tsx +20 -0
- package/src/dev-module-config/ui/hubspot/HsToggle.tsx +39 -0
- package/src/dev-module-config/ui/hubspot/HsToggleRow.tsx +30 -0
- package/src/dev-module-config/ui/hubspot/hs-color-palette.ts +11 -0
- package/src/dev-module-config/ui/hubspot/module-config-typography.ts +26 -0
- package/src/dev-module-config/ui/module-config-motion.css +134 -0
- package/src/dev-module-config/ui/module-config-motion.ts +28 -0
- package/src/dev-module-config/ui/module-config-overlay-side.ts +29 -0
- package/src/dev-module-config/ui/module-config-surfaces.ts +27 -0
- package/src/dev-module-config/ui/module-config-theme.css +489 -0
- package/src/dev-module-config/ui/module-config-toolbar-theme.ts +35 -0
- package/src/dev-module-config/ui/navigation/ModuleConfigNavContext.tsx +194 -0
- package/src/dev-module-config/ui/use-dev-module-config-live-revision.ts +22 -0
- package/src/dev-module-config/ui/use-hubspot-live-exports.ts +27 -0
- package/src/dev-module-config/ui/use-module-config.ts +124 -0
- package/src/routing/build-api-routes.ts +37 -0
- package/src/routing/route-format.ts +19 -0
- package/templates/module-hybrid-cdn/README.md +53 -3
- package/templates/module-hybrid-cdn/index.html +12 -1
- package/templates/module-hybrid-cdn/package.json +6 -2
- package/templates/module-hybrid-cdn/public/fields.json +44 -1
- package/templates/module-hybrid-cdn/src/app.tsx +8 -0
- package/templates/module-hybrid-cdn/src/assets/css/main.dev.css +6 -1
- package/templates/module-hybrid-cdn/src/cdn/app-entry.ts +32 -0
- package/templates/module-hybrid-cdn/src/cdn/vendor-entry.ts +28 -0
- package/templates/module-hybrid-cdn/src/components/layout/section-card.tsx +20 -0
- package/templates/module-hybrid-cdn/src/components/layout/starter-nav.tsx +28 -0
- package/templates/module-hybrid-cdn/src/components/layout/starter-shell.tsx +18 -0
- package/templates/module-hybrid-cdn/src/config/router.ts +4 -0
- package/templates/module-hybrid-cdn/src/config/routes.ts +5 -0
- package/templates/module-hybrid-cdn/src/defaultData.ts +2 -7
- package/templates/module-hybrid-cdn/src/features/starter/components/starter-guide-page.tsx +93 -0
- package/templates/module-hybrid-cdn/src/features/starter/components/starter-home-page.tsx +21 -0
- package/templates/module-hybrid-cdn/src/features/starter/components/starter-home.tsx +52 -0
- package/templates/module-hybrid-cdn/src/features/starter/components/starter-single-page.tsx +17 -0
- package/templates/module-hybrid-cdn/src/features/starter/content/woodscli-guide-content.ts +86 -0
- package/templates/module-hybrid-cdn/src/features/starter/hooks/starter-preview-values.ts +42 -0
- package/templates/module-hybrid-cdn/src/features/starter/hooks/use-starter-preview.dev.ts +17 -0
- package/templates/module-hybrid-cdn/src/features/starter/hooks/use-starter-preview.ts +30 -0
- package/templates/module-hybrid-cdn/src/features/starter/index.ts +6 -0
- package/templates/module-hybrid-cdn/src/hubspot/bootstrap.ts +10 -0
- package/templates/module-hybrid-cdn/src/hubspot/default-data.ts +7 -0
- package/templates/module-hybrid-cdn/src/hubspot/module-entry.tsx +9 -0
- package/templates/module-hybrid-cdn/src/integrations/tanstack-router/router.tsx +25 -0
- package/templates/module-hybrid-cdn/src/main.tsx +4 -3
- package/templates/module-hybrid-cdn/src/portal/mount-dev-preview.tsx +8 -0
- package/templates/module-hybrid-cdn/src/portal/mount-portal.tsx +12 -0
- package/templates/module-hybrid-cdn/src/routeTree.gen.ts +77 -0
- package/templates/module-hybrid-cdn/src/routes/__root.tsx +15 -0
- package/templates/module-hybrid-cdn/src/routes/guide.tsx +7 -0
- package/templates/module-hybrid-cdn/src/routes/index.tsx +7 -0
- package/templates/module-hybrid-cdn/tsconfig.json +20 -0
- package/templates/module-hybrid-cdn/vite.config.monolith.mjs +8 -0
- package/templates/module-monolith/README.md +59 -0
- package/templates/module-monolith/index.html +12 -0
- package/templates/module-monolith/package.json +10 -3
- package/templates/module-monolith/public/fields.json +44 -1
- package/templates/module-monolith/public/module.html +1 -0
- package/templates/module-monolith/src/app.tsx +8 -0
- package/templates/module-monolith/src/assets/css/main.dev.css +6 -1
- package/templates/module-monolith/src/components/layout/section-card.tsx +20 -0
- package/templates/module-monolith/src/components/layout/starter-nav.tsx +28 -0
- package/templates/module-monolith/src/components/layout/starter-shell.tsx +18 -0
- package/templates/module-monolith/src/config/router.ts +4 -0
- package/templates/module-monolith/src/config/routes.ts +5 -0
- package/templates/module-monolith/src/defaultData.ts +2 -7
- package/templates/module-monolith/src/features/starter/components/starter-guide-page.tsx +93 -0
- package/templates/module-monolith/src/features/starter/components/starter-home-page.tsx +21 -0
- package/templates/module-monolith/src/features/starter/components/starter-home.tsx +52 -0
- package/templates/module-monolith/src/features/starter/components/starter-single-page.tsx +17 -0
- package/templates/module-monolith/src/features/starter/content/woodscli-guide-content.ts +86 -0
- package/templates/module-monolith/src/features/starter/hooks/starter-preview-values.ts +42 -0
- package/templates/module-monolith/src/features/starter/hooks/use-starter-preview.dev.ts +17 -0
- package/templates/module-monolith/src/features/starter/hooks/use-starter-preview.ts +30 -0
- package/templates/module-monolith/src/features/starter/index.ts +6 -0
- package/templates/module-monolith/src/hubspot/default-data.ts +7 -0
- package/templates/module-monolith/src/hubspot/module-entry.tsx +9 -0
- package/templates/module-monolith/src/integrations/tanstack-router/router.tsx +25 -0
- package/templates/module-monolith/src/main.tsx +4 -3
- package/templates/module-monolith/src/portal/mount-dev-preview.tsx +8 -0
- package/templates/module-monolith/src/portal/mount-portal.tsx +12 -0
- package/templates/module-monolith/src/routeTree.gen.ts +77 -0
- package/templates/module-monolith/src/routes/__root.tsx +15 -0
- package/templates/module-monolith/src/routes/guide.tsx +7 -0
- package/templates/module-monolith/src/routes/index.tsx +7 -0
- package/templates/module-monolith/tsconfig.json +20 -0
- package/templates/module-monolith/vite.config.monolith.mjs +8 -0
- package/templates/module-monolith/woodscli.json +1 -0
- package/templates/shared/.env.dev.example +5 -0
- package/templates/shared/.env.prod.example +5 -0
- package/templates/shared/.env.stg.example +3 -0
- package/templates/shared/portal.cdn.json.example +8 -0
- package/templates/theme-starter/package.json +5 -2
- package/vite/vite.config.dev.mjs +9 -1
- package/vite/vite.config.monolith.mjs +22 -17
- package/dist/chunk-JDGIAYHX.js.map +0 -1
- package/dist/exec-K5C6LZP4.js +0 -10
- /package/dist/{exec-K5C6LZP4.js.map → exec-U2OJATR3.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -52,13 +52,17 @@ declare const WoodsPortalHsSchema: z.ZodObject<{
|
|
|
52
52
|
app: z.ZodDefault<z.ZodString>;
|
|
53
53
|
vendor: z.ZodDefault<z.ZodString>;
|
|
54
54
|
hubspotBootstrap: z.ZodDefault<z.ZodString>;
|
|
55
|
+
/** Monolith production IIFE entry (wp build --hubspot-only) */
|
|
56
|
+
module: z.ZodDefault<z.ZodString>;
|
|
55
57
|
localDev: z.ZodDefault<z.ZodString>;
|
|
56
58
|
}, "strip", z.ZodTypeAny, {
|
|
59
|
+
module: string;
|
|
57
60
|
app: string;
|
|
58
61
|
vendor: string;
|
|
59
62
|
hubspotBootstrap: string;
|
|
60
63
|
localDev: string;
|
|
61
64
|
}, {
|
|
65
|
+
module?: string | undefined;
|
|
62
66
|
app?: string | undefined;
|
|
63
67
|
vendor?: string | undefined;
|
|
64
68
|
hubspotBootstrap?: string | undefined;
|
|
@@ -87,10 +91,19 @@ declare const WoodsPortalHsSchema: z.ZodObject<{
|
|
|
87
91
|
fieldsJson?: string | undefined;
|
|
88
92
|
themeFieldsJson?: string | undefined;
|
|
89
93
|
}>>;
|
|
94
|
+
scaffold: z.ZodOptional<z.ZodObject<{
|
|
95
|
+
/** hash = woodsportal-client-frontend (HubSpot CMS); browser = local clean URLs; none = single page */
|
|
96
|
+
router: z.ZodDefault<z.ZodEnum<["hash", "browser", "none"]>>;
|
|
97
|
+
}, "strip", z.ZodTypeAny, {
|
|
98
|
+
router: "none" | "hash" | "browser";
|
|
99
|
+
}, {
|
|
100
|
+
router?: "none" | "hash" | "browser" | undefined;
|
|
101
|
+
}>>;
|
|
90
102
|
}, "strip", z.ZodTypeAny, {
|
|
91
103
|
configVersion: number;
|
|
92
104
|
projectType: "module-hybrid-cdn" | "module-monolith" | "theme-starter";
|
|
93
105
|
entries: {
|
|
106
|
+
module: string;
|
|
94
107
|
app: string;
|
|
95
108
|
vendor: string;
|
|
96
109
|
hubspotBootstrap: string;
|
|
@@ -121,6 +134,9 @@ declare const WoodsPortalHsSchema: z.ZodObject<{
|
|
|
121
134
|
srcDir: string;
|
|
122
135
|
themeJson: string;
|
|
123
136
|
} | undefined;
|
|
137
|
+
scaffold?: {
|
|
138
|
+
router: "none" | "hash" | "browser";
|
|
139
|
+
} | undefined;
|
|
124
140
|
}, {
|
|
125
141
|
projectType: "module-hybrid-cdn" | "module-monolith" | "theme-starter";
|
|
126
142
|
module: {
|
|
@@ -130,6 +146,7 @@ declare const WoodsPortalHsSchema: z.ZodObject<{
|
|
|
130
146
|
};
|
|
131
147
|
configVersion?: number | undefined;
|
|
132
148
|
entries?: {
|
|
149
|
+
module?: string | undefined;
|
|
133
150
|
app?: string | undefined;
|
|
134
151
|
vendor?: string | undefined;
|
|
135
152
|
hubspotBootstrap?: string | undefined;
|
|
@@ -155,6 +172,9 @@ declare const WoodsPortalHsSchema: z.ZodObject<{
|
|
|
155
172
|
env?: {
|
|
156
173
|
tiers?: ("dev" | "stg" | "prod")[] | undefined;
|
|
157
174
|
} | undefined;
|
|
175
|
+
scaffold?: {
|
|
176
|
+
router?: "none" | "hash" | "browser" | undefined;
|
|
177
|
+
} | undefined;
|
|
158
178
|
}>;
|
|
159
179
|
type WoodsPortalHsConfig = z.infer<typeof WoodsPortalHsSchema>;
|
|
160
180
|
declare const DEFAULT_WOODSPORTAL_HS: WoodsPortalHsConfig;
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,8 @@ var WoodsPortalHsSchema = z.object({
|
|
|
37
37
|
app: z.string().default("src/cdn/app-entry.ts"),
|
|
38
38
|
vendor: z.string().default("src/cdn/vendor-entry.ts"),
|
|
39
39
|
hubspotBootstrap: z.string().default("src/hubspot/bootstrap.ts"),
|
|
40
|
+
/** Monolith production IIFE entry (wp build --hubspot-only) */
|
|
41
|
+
module: z.string().default("src/hubspot/module-entry.tsx"),
|
|
40
42
|
localDev: z.string().default("src/main.tsx")
|
|
41
43
|
}).default({}),
|
|
42
44
|
env: z.object({
|
|
@@ -47,7 +49,11 @@ var WoodsPortalHsSchema = z.object({
|
|
|
47
49
|
adapter: z.string().default("./wphs.adapter.ts"),
|
|
48
50
|
fieldsJson: z.string().default("public/fields.json"),
|
|
49
51
|
themeFieldsJson: z.string().optional()
|
|
50
|
-
}).default({})
|
|
52
|
+
}).default({}),
|
|
53
|
+
scaffold: z.object({
|
|
54
|
+
/** hash = woodsportal-client-frontend (HubSpot CMS); browser = local clean URLs; none = single page */
|
|
55
|
+
router: z.enum(["hash", "browser", "none"]).default("hash")
|
|
56
|
+
}).optional()
|
|
51
57
|
});
|
|
52
58
|
var DEFAULT_WOODSPORTAL_HS = {
|
|
53
59
|
configVersion: CONFIG_VERSION,
|
|
@@ -66,6 +72,7 @@ var DEFAULT_WOODSPORTAL_HS = {
|
|
|
66
72
|
app: "src/cdn/app-entry.ts",
|
|
67
73
|
vendor: "src/cdn/vendor-entry.ts",
|
|
68
74
|
hubspotBootstrap: "src/hubspot/bootstrap.ts",
|
|
75
|
+
module: "src/hubspot/module-entry.tsx",
|
|
69
76
|
localDev: "src/main.tsx"
|
|
70
77
|
},
|
|
71
78
|
env: {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schema/woodsportal-hs.ts","../src/lib/config.ts","../src/adapters/types.ts","../src/lib/generic-field-mapper.ts"],"sourcesContent":["import { z } from 'zod'\n\nexport const CONFIG_VERSION = 1\n\nexport const WPHS_WORKSPACE_DIR = '.wphs' as const\n\nexport const WoodsPortalHsSchema = z.object({\n configVersion: z.number().int().default(CONFIG_VERSION),\n projectType: z.enum(['module-hybrid-cdn', 'module-monolith', 'theme-starter']),\n module: z.object({\n name: z.string().min(1),\n uploadPath: z.string().min(1),\n outDir: z.string().default('dist/WoodsPortal.Module'),\n }),\n theme: z\n .object({\n name: z.string().min(1),\n uploadPath: z.string().min(1),\n srcDir: z.string().default('src/theme'),\n themeJson: z.string().default('src/theme/theme.json'),\n })\n .optional(),\n cdn: z\n .object({\n mode: z.enum(['jsdelivr', 'custom', 'local', 'none']).default('jsdelivr'),\n buildIdFile: z.string().default('.portal-build-id'),\n mirror: z.string().default('portal.cdn.json'),\n })\n .default({}),\n entries: z\n .object({\n app: z.string().default('src/cdn/app-entry.ts'),\n vendor: z.string().default('src/cdn/vendor-entry.ts'),\n hubspotBootstrap: z.string().default('src/hubspot/bootstrap.ts'),\n localDev: z.string().default('src/main.tsx'),\n })\n .default({}),\n env: z\n .object({\n tiers: z.array(z.enum(['dev', 'stg', 'prod'])).default(['dev', 'stg', 'prod']),\n })\n .default({}),\n dev: z\n .object({\n moduleConfigDir: z.literal(WPHS_WORKSPACE_DIR).default(WPHS_WORKSPACE_DIR),\n adapter: z.string().default('./wphs.adapter.ts'),\n fieldsJson: z.string().default('public/fields.json'),\n themeFieldsJson: z.string().optional(),\n })\n .default({}),\n})\n\nexport type WoodsPortalHsConfig = z.infer<typeof WoodsPortalHsSchema>\n\nexport const DEFAULT_WOODSPORTAL_HS: WoodsPortalHsConfig = {\n configVersion: CONFIG_VERSION,\n projectType: 'module-hybrid-cdn',\n module: {\n name: 'woodsportal-module',\n uploadPath: 'dw-modules/woodsportal-module.module',\n outDir: 'dist/WoodsPortal.Module',\n },\n cdn: {\n mode: 'jsdelivr',\n buildIdFile: '.portal-build-id',\n mirror: 'portal.cdn.json',\n },\n entries: {\n app: 'src/cdn/app-entry.ts',\n vendor: 'src/cdn/vendor-entry.ts',\n hubspotBootstrap: 'src/hubspot/bootstrap.ts',\n localDev: 'src/main.tsx',\n },\n env: {\n tiers: ['dev', 'stg', 'prod'],\n },\n dev: {\n moduleConfigDir: WPHS_WORKSPACE_DIR,\n adapter: './wphs.adapter.ts',\n fieldsJson: 'public/fields.json',\n },\n}\n\nexport function isModuleProject(config: WoodsPortalHsConfig): boolean {\n return config.projectType === 'module-hybrid-cdn' || config.projectType === 'module-monolith'\n}\n\nexport function isThemeProject(config: WoodsPortalHsConfig): boolean {\n return config.projectType === 'theme-starter'\n}\n\nexport function usesCdnPipeline(config: WoodsPortalHsConfig): boolean {\n return config.projectType === 'module-hybrid-cdn' && config.cdn.mode !== 'none'\n}\n","import { readFileSync } from 'node:fs'\n\nimport {\n resolveProjectConfig,\n WOODSCLI_CONFIG_FILE,\n} from './config-files.js'\nimport { WoodsPortalHsSchema, type WoodsPortalHsConfig } from '../schema/woodsportal-hs.js'\nimport { WpHsError, ExitCode } from './errors.js'\nimport { findProjectRoot } from './paths.js'\n\nexport type LoadedProjectConfig = {\n root: string\n config: WoodsPortalHsConfig\n configPath: string\n configFileName: string\n}\n\nexport function loadConfig(projectRoot?: string): LoadedProjectConfig {\n const root = projectRoot ?? findProjectRoot()\n const resolved = resolveProjectConfig(root)\n\n if (!resolved) {\n throw new WpHsError(`Missing ${WOODSCLI_CONFIG_FILE}`, {\n exitCode: ExitCode.USER_ERROR,\n remediation: 'Run wp init or wp adopt. Legacy woodsportal.hs.json → run wp migrate --yes.',\n })\n }\n\n let raw: unknown\n try {\n raw = JSON.parse(readFileSync(resolved.path, 'utf8'))\n } catch (cause) {\n throw new WpHsError(`Invalid JSON in ${resolved.fileName}`, {\n exitCode: ExitCode.USER_ERROR,\n cause,\n })\n }\n\n const parsed = WoodsPortalHsSchema.safeParse(raw)\n if (!parsed.success) {\n throw new WpHsError(`${resolved.fileName} validation failed: ${parsed.error.message}`, {\n exitCode: ExitCode.USER_ERROR,\n remediation: 'Run wp config validate for details.',\n })\n }\n\n return {\n root,\n config: parsed.data,\n configPath: resolved.path,\n configFileName: resolved.fileName,\n }\n}\n\nexport function validateConfigFile(projectRoot?: string): {\n valid: boolean\n errors: string[]\n config?: WoodsPortalHsConfig\n} {\n try {\n const { config } = loadConfig(projectRoot)\n return { valid: true, errors: [], config }\n } catch (error) {\n if (error instanceof WpHsError) {\n return { valid: false, errors: [error.message] }\n }\n return { valid: false, errors: [String(error)] }\n }\n}\n","/** Must match dev-module-config/schema/types.ts */\nexport const MODULE_CONFIG_CHANGED = 'woodsportal:module-config-changed'\n\nexport type ModuleConfigBuiltState = {\n built: Record<string, unknown>\n}\n\n/** WoodsCLI consumer hook — mount app + sync module-config live data. */\nexport interface HubSpotKitAdapter {\n syncLiveData(built: Record<string, unknown>): void\n getDefaultHubSpotData?(): Record<string, unknown>\n mountDevApp?(root: unknown): void | Promise<void>\n}\n\nexport function bindAdapterToModuleConfig(adapter: HubSpotKitAdapter): void {\n if (typeof globalThis.window === 'undefined') return\n globalThis.window.addEventListener(MODULE_CONFIG_CHANGED, (event: Event) => {\n const detail = (event as CustomEvent<ModuleConfigBuiltState>).detail\n adapter.syncLiveData(detail.built)\n })\n}\n\nexport function syncAdapterFromModuleState(\n adapter: HubSpotKitAdapter,\n state: ModuleConfigBuiltState,\n): void {\n adapter.syncLiveData(state.built)\n}\n\n/** Minimal adapter for greenfield templates without a full app. */\nexport const defaultHubSpotKitAdapter: HubSpotKitAdapter = {\n syncLiveData(built) {\n const w = globalThis as typeof globalThis & { __WPHS_DATA__?: Record<string, unknown> }\n w.__WPHS_DATA__ = built\n },\n getDefaultHubSpotData() {\n return {}\n },\n}\n","/**\n * Generic fields.json → flat runtime object (WoodsCLI default transform).\n */\nexport type GenericFieldDefinition = {\n name: string\n type: string\n default?: unknown\n children?: GenericFieldDefinition[]\n}\n\nexport type GenericFieldValues = Record<string, unknown>\n\nfunction flattenField(\n field: GenericFieldDefinition,\n values: GenericFieldValues,\n out: Record<string, unknown>,\n): void {\n const key = field.name\n const value = values[key]\n\n if (field.type === 'group' && field.children && value && typeof value === 'object') {\n const groupValues = value as GenericFieldValues\n for (const child of field.children) {\n flattenField(child, groupValues, out)\n }\n return\n }\n\n if (field.type === 'repeater' && Array.isArray(value)) {\n out[key] = value\n return\n }\n\n out[key] = value ?? field.default ?? null\n}\n\nexport function mapFieldsToRuntime(\n schema: GenericFieldDefinition[],\n values: GenericFieldValues,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const field of schema) {\n flattenField(field, values, out)\n }\n return out\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/schema/woodsportal-hs.ts","../src/lib/config.ts","../src/adapters/types.ts","../src/lib/generic-field-mapper.ts"],"sourcesContent":["import { z } from 'zod'\n\nexport const CONFIG_VERSION = 1\n\nexport const WPHS_WORKSPACE_DIR = '.wphs' as const\n\nexport const WoodsPortalHsSchema = z.object({\n configVersion: z.number().int().default(CONFIG_VERSION),\n projectType: z.enum(['module-hybrid-cdn', 'module-monolith', 'theme-starter']),\n module: z.object({\n name: z.string().min(1),\n uploadPath: z.string().min(1),\n outDir: z.string().default('dist/WoodsPortal.Module'),\n }),\n theme: z\n .object({\n name: z.string().min(1),\n uploadPath: z.string().min(1),\n srcDir: z.string().default('src/theme'),\n themeJson: z.string().default('src/theme/theme.json'),\n })\n .optional(),\n cdn: z\n .object({\n mode: z.enum(['jsdelivr', 'custom', 'local', 'none']).default('jsdelivr'),\n buildIdFile: z.string().default('.portal-build-id'),\n mirror: z.string().default('portal.cdn.json'),\n })\n .default({}),\n entries: z\n .object({\n app: z.string().default('src/cdn/app-entry.ts'),\n vendor: z.string().default('src/cdn/vendor-entry.ts'),\n hubspotBootstrap: z.string().default('src/hubspot/bootstrap.ts'),\n /** Monolith production IIFE entry (wp build --hubspot-only) */\n module: z.string().default('src/hubspot/module-entry.tsx'),\n localDev: z.string().default('src/main.tsx'),\n })\n .default({}),\n env: z\n .object({\n tiers: z.array(z.enum(['dev', 'stg', 'prod'])).default(['dev', 'stg', 'prod']),\n })\n .default({}),\n dev: z\n .object({\n moduleConfigDir: z.literal(WPHS_WORKSPACE_DIR).default(WPHS_WORKSPACE_DIR),\n adapter: z.string().default('./wphs.adapter.ts'),\n fieldsJson: z.string().default('public/fields.json'),\n themeFieldsJson: z.string().optional(),\n })\n .default({}),\n scaffold: z\n .object({\n /** hash = woodsportal-client-frontend (HubSpot CMS); browser = local clean URLs; none = single page */\n router: z.enum(['hash', 'browser', 'none']).default('hash'),\n })\n .optional(),\n})\n\nexport type WoodsPortalHsConfig = z.infer<typeof WoodsPortalHsSchema>\n\nexport const DEFAULT_WOODSPORTAL_HS: WoodsPortalHsConfig = {\n configVersion: CONFIG_VERSION,\n projectType: 'module-hybrid-cdn',\n module: {\n name: 'woodsportal-module',\n uploadPath: 'dw-modules/woodsportal-module.module',\n outDir: 'dist/WoodsPortal.Module',\n },\n cdn: {\n mode: 'jsdelivr',\n buildIdFile: '.portal-build-id',\n mirror: 'portal.cdn.json',\n },\n entries: {\n app: 'src/cdn/app-entry.ts',\n vendor: 'src/cdn/vendor-entry.ts',\n hubspotBootstrap: 'src/hubspot/bootstrap.ts',\n module: 'src/hubspot/module-entry.tsx',\n localDev: 'src/main.tsx',\n },\n env: {\n tiers: ['dev', 'stg', 'prod'],\n },\n dev: {\n moduleConfigDir: WPHS_WORKSPACE_DIR,\n adapter: './wphs.adapter.ts',\n fieldsJson: 'public/fields.json',\n },\n}\n\nexport function isModuleProject(config: WoodsPortalHsConfig): boolean {\n return config.projectType === 'module-hybrid-cdn' || config.projectType === 'module-monolith'\n}\n\nexport function isThemeProject(config: WoodsPortalHsConfig): boolean {\n return config.projectType === 'theme-starter'\n}\n\nexport function usesCdnPipeline(config: WoodsPortalHsConfig): boolean {\n return config.projectType === 'module-hybrid-cdn' && config.cdn.mode !== 'none'\n}\n","import { readFileSync } from 'node:fs'\n\nimport {\n resolveProjectConfig,\n WOODSCLI_CONFIG_FILE,\n} from './config-files.js'\nimport { WoodsPortalHsSchema, type WoodsPortalHsConfig } from '../schema/woodsportal-hs.js'\nimport { WpHsError, ExitCode } from './errors.js'\nimport { findProjectRoot } from './paths.js'\n\nexport type LoadedProjectConfig = {\n root: string\n config: WoodsPortalHsConfig\n configPath: string\n configFileName: string\n}\n\nexport function loadConfig(projectRoot?: string): LoadedProjectConfig {\n const root = projectRoot ?? findProjectRoot()\n const resolved = resolveProjectConfig(root)\n\n if (!resolved) {\n throw new WpHsError(`Missing ${WOODSCLI_CONFIG_FILE}`, {\n exitCode: ExitCode.USER_ERROR,\n remediation: 'Run wp init or wp adopt. Legacy woodsportal.hs.json → run wp migrate --yes.',\n })\n }\n\n let raw: unknown\n try {\n raw = JSON.parse(readFileSync(resolved.path, 'utf8'))\n } catch (cause) {\n throw new WpHsError(`Invalid JSON in ${resolved.fileName}`, {\n exitCode: ExitCode.USER_ERROR,\n cause,\n })\n }\n\n const parsed = WoodsPortalHsSchema.safeParse(raw)\n if (!parsed.success) {\n throw new WpHsError(`${resolved.fileName} validation failed: ${parsed.error.message}`, {\n exitCode: ExitCode.USER_ERROR,\n remediation: 'Run wp config validate for details.',\n })\n }\n\n return {\n root,\n config: parsed.data,\n configPath: resolved.path,\n configFileName: resolved.fileName,\n }\n}\n\nexport function validateConfigFile(projectRoot?: string): {\n valid: boolean\n errors: string[]\n config?: WoodsPortalHsConfig\n} {\n try {\n const { config } = loadConfig(projectRoot)\n return { valid: true, errors: [], config }\n } catch (error) {\n if (error instanceof WpHsError) {\n return { valid: false, errors: [error.message] }\n }\n return { valid: false, errors: [String(error)] }\n }\n}\n","/** Must match dev-module-config/schema/types.ts */\nexport const MODULE_CONFIG_CHANGED = 'woodsportal:module-config-changed'\n\nexport type ModuleConfigBuiltState = {\n built: Record<string, unknown>\n}\n\n/** WoodsCLI consumer hook — mount app + sync module-config live data. */\nexport interface HubSpotKitAdapter {\n syncLiveData(built: Record<string, unknown>): void\n getDefaultHubSpotData?(): Record<string, unknown>\n mountDevApp?(root: unknown): void | Promise<void>\n}\n\nexport function bindAdapterToModuleConfig(adapter: HubSpotKitAdapter): void {\n if (typeof globalThis.window === 'undefined') return\n globalThis.window.addEventListener(MODULE_CONFIG_CHANGED, (event: Event) => {\n const detail = (event as CustomEvent<ModuleConfigBuiltState>).detail\n adapter.syncLiveData(detail.built)\n })\n}\n\nexport function syncAdapterFromModuleState(\n adapter: HubSpotKitAdapter,\n state: ModuleConfigBuiltState,\n): void {\n adapter.syncLiveData(state.built)\n}\n\n/** Minimal adapter for greenfield templates without a full app. */\nexport const defaultHubSpotKitAdapter: HubSpotKitAdapter = {\n syncLiveData(built) {\n const w = globalThis as typeof globalThis & { __WPHS_DATA__?: Record<string, unknown> }\n w.__WPHS_DATA__ = built\n },\n getDefaultHubSpotData() {\n return {}\n },\n}\n","/**\n * Generic fields.json → flat runtime object (WoodsCLI default transform).\n */\nexport type GenericFieldDefinition = {\n name: string\n type: string\n default?: unknown\n children?: GenericFieldDefinition[]\n}\n\nexport type GenericFieldValues = Record<string, unknown>\n\nfunction flattenField(\n field: GenericFieldDefinition,\n values: GenericFieldValues,\n out: Record<string, unknown>,\n): void {\n const key = field.name\n const value = values[key]\n\n if (field.type === 'group' && field.children && value && typeof value === 'object') {\n const groupValues = value as GenericFieldValues\n for (const child of field.children) {\n flattenField(child, groupValues, out)\n }\n return\n }\n\n if (field.type === 'repeater' && Array.isArray(value)) {\n out[key] = value\n return\n }\n\n out[key] = value ?? field.default ?? null\n}\n\nexport function mapFieldsToRuntime(\n schema: GenericFieldDefinition[],\n values: GenericFieldValues,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const field of schema) {\n flattenField(field, values, out)\n }\n return out\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,46 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Getting started
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This project was scaffolded with **WoodsCLI** (`@woodsportal/hubspot-kit`).
|
|
4
|
+
|
|
5
|
+
## Daily dev
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
|
-
|
|
8
|
+
yarn install
|
|
7
9
|
wp doctor
|
|
8
10
|
wp dev
|
|
9
11
|
```
|
|
12
|
+
|
|
13
|
+
Open the local URL, then **Ctrl+Shift+Z** (Mac **⌃⇧Z**) to edit module fields. Click **Apply changes** to refresh the starter preview.
|
|
14
|
+
|
|
15
|
+
## `src/` layout
|
|
16
|
+
|
|
17
|
+
| Path | Purpose |
|
|
18
|
+
|------|---------|
|
|
19
|
+
| `main.tsx` | Dev entry — loads styles and `mountDevPreview()` |
|
|
20
|
+
| `portal/` | Dev vs production mount (`mount-dev-preview`, `mount-portal`) |
|
|
21
|
+
| `routes/` | TanStack file routes — keep thin; import from `features/` |
|
|
22
|
+
| `features/starter/` | Demo home + developer guide (replace with your app) |
|
|
23
|
+
| `components/` | Shared layout and UI |
|
|
24
|
+
| `integrations/` | Router and third-party wiring |
|
|
25
|
+
| `cdn/` | Production vendor + app chunks (`wp build` / `wp deploy`) |
|
|
26
|
+
| `hubspot/` | HubSpot bootstrap, types, and dev fixtures |
|
|
27
|
+
| `config/` | Route constants and app config |
|
|
28
|
+
| `assets/css/` | Tailwind entry for local dev |
|
|
29
|
+
|
|
30
|
+
Kit runtime expects `src/defaultData.ts` (re-exports `hubspot/default-data.ts`).
|
|
31
|
+
|
|
32
|
+
## Docs (in the kit package)
|
|
33
|
+
|
|
34
|
+
After `npm install`, see:
|
|
35
|
+
|
|
36
|
+
- `node_modules/@woodsportal/hubspot-kit/docs/CLI-REFERENCE.md`
|
|
37
|
+
- `node_modules/@woodsportal/hubspot-kit/docs/MODULES.md`
|
|
38
|
+
- `node_modules/@woodsportal/hubspot-kit/docs/HUBSPOT-CLI-SETUP.md`
|
|
39
|
+
|
|
40
|
+
## HubSpot upload
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
cp hubspot.config.yml.example hubspot.config.yml
|
|
44
|
+
# add portal + personal access key
|
|
45
|
+
wp upload
|
|
46
|
+
```
|
|
@@ -1 +1,44 @@
|
|
|
1
|
-
[
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "title",
|
|
4
|
+
"label": "Portal title",
|
|
5
|
+
"type": "text",
|
|
6
|
+
"tab": "CONTENT",
|
|
7
|
+
"default": "My HubSpot Portal"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"name": "tagline",
|
|
11
|
+
"label": "Tagline",
|
|
12
|
+
"type": "text",
|
|
13
|
+
"tab": "CONTENT",
|
|
14
|
+
"help_text": "Subtitle shown under the hero title in the local dev preview.",
|
|
15
|
+
"default": "Customize this preview with Ctrl+Shift+Z, then replace StarterPage with your portal app."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "show_feature_cards",
|
|
19
|
+
"label": "Show feature cards",
|
|
20
|
+
"type": "boolean",
|
|
21
|
+
"display": "toggle",
|
|
22
|
+
"tab": "CONTENT",
|
|
23
|
+
"default": true
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "accent_color",
|
|
27
|
+
"label": "Accent color",
|
|
28
|
+
"type": "color",
|
|
29
|
+
"tab": "STYLE",
|
|
30
|
+
"default": { "color": "#0091ae", "opacity": 100 }
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "hero_style",
|
|
34
|
+
"label": "Hero style",
|
|
35
|
+
"type": "choice",
|
|
36
|
+
"tab": "STYLE",
|
|
37
|
+
"choices": [
|
|
38
|
+
["gradient", "Gradient"],
|
|
39
|
+
["minimal", "Minimal"],
|
|
40
|
+
["bold", "Bold"]
|
|
41
|
+
],
|
|
42
|
+
"default": "gradient"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { RouterProvider } from '@tanstack/react-router'
|
|
2
|
+
|
|
3
|
+
import { router } from '@/integrations/tanstack-router/router'
|
|
4
|
+
|
|
5
|
+
/** Root app shell — same pattern as woodsportal-client-frontend `App`. */
|
|
6
|
+
export function App() {
|
|
7
|
+
return <RouterProvider router={router} />
|
|
8
|
+
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
@import 'tailwindcss';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/* Kit dev-module-config — paths relative to this file (src/assets/css/) */
|
|
4
|
+
@source '../../../.wphs/.kit-module-config/**/*.{ts,tsx}';
|
|
5
|
+
@source '../../../.wphs/.kit-bootstrap.tsx';
|
|
6
|
+
@source '../../../.wphs/.kit-bootstrap-greenfield.tsx';
|
|
7
|
+
@source '../../../src/**/*.{ts,tsx}';
|
|
8
|
+
@source '../../../node_modules/@woodsportal/hubspot-kit/src/dev-module-config/**/*.{ts,tsx}';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDN application chunk — mounts after vendor.js (HubSpot require_js order).
|
|
3
|
+
*/
|
|
4
|
+
import { mountPortal } from '@/portal/mount-portal'
|
|
5
|
+
|
|
6
|
+
declare const __PORTAL_BUILD_ID__: string | undefined
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
interface Window {
|
|
10
|
+
WoodsPortal?: {
|
|
11
|
+
mount: typeof mountPortal
|
|
12
|
+
version: string
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const buildId =
|
|
18
|
+
typeof __PORTAL_BUILD_ID__ !== 'undefined' ? String(__PORTAL_BUILD_ID__) : 'dev'
|
|
19
|
+
|
|
20
|
+
window.WoodsPortal = {
|
|
21
|
+
mount: mountPortal,
|
|
22
|
+
version: buildId,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function autoMount() {
|
|
26
|
+
if (!document.getElementById('app')) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
await mountPortal()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
void autoMount()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDN vendor chunk — React + ReactDOM on `window` for the app IIFE externals.
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react'
|
|
5
|
+
import * as ReactDOM from 'react-dom'
|
|
6
|
+
import * as ReactDOMClient from 'react-dom/client'
|
|
7
|
+
import * as jsxRuntime from 'react/jsx-runtime'
|
|
8
|
+
import * as jsxDevRuntime from 'react/jsx-dev-runtime'
|
|
9
|
+
|
|
10
|
+
declare global {
|
|
11
|
+
interface Window {
|
|
12
|
+
WoodsPortalVendor?: {
|
|
13
|
+
React: typeof React
|
|
14
|
+
ReactDOM: typeof ReactDOM
|
|
15
|
+
ReactDOMClient: typeof ReactDOMClient
|
|
16
|
+
jsxRuntime: typeof jsxRuntime
|
|
17
|
+
jsxDevRuntime: typeof jsxDevRuntime
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
window.WoodsPortalVendor = {
|
|
23
|
+
React,
|
|
24
|
+
ReactDOM,
|
|
25
|
+
ReactDOMClient,
|
|
26
|
+
jsxRuntime,
|
|
27
|
+
jsxDevRuntime,
|
|
28
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
export function SectionCard({
|
|
4
|
+
title,
|
|
5
|
+
children,
|
|
6
|
+
className = '',
|
|
7
|
+
}: {
|
|
8
|
+
title: string
|
|
9
|
+
children: ReactNode
|
|
10
|
+
className?: string
|
|
11
|
+
}) {
|
|
12
|
+
return (
|
|
13
|
+
<section
|
|
14
|
+
className={`rounded-lg border border-[#cbd6e2] bg-white p-6 shadow-sm ${className}`}
|
|
15
|
+
>
|
|
16
|
+
<h2 className="text-base font-semibold text-[#33475b]">{title}</h2>
|
|
17
|
+
<div className="mt-4">{children}</div>
|
|
18
|
+
</section>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Link } from '@tanstack/react-router'
|
|
2
|
+
|
|
3
|
+
import { ROUTES } from '@/config/routes'
|
|
4
|
+
|
|
5
|
+
export function StarterNav() {
|
|
6
|
+
return (
|
|
7
|
+
<header className="border-b border-[#cbd6e2] bg-white/90 backdrop-blur">
|
|
8
|
+
<div className="mx-auto flex max-w-4xl items-center justify-between gap-4 px-6 py-3 sm:px-10">
|
|
9
|
+
<span className="text-sm font-semibold text-[#0091ae]">WoodsCLI starter</span>
|
|
10
|
+
<nav className="flex gap-4 text-sm font-medium">
|
|
11
|
+
<Link
|
|
12
|
+
to={ROUTES.home}
|
|
13
|
+
className="text-[#516f90] hover:text-[#0091ae] [&.active]:text-[#0091ae]"
|
|
14
|
+
activeOptions={{ exact: true }}
|
|
15
|
+
>
|
|
16
|
+
Home
|
|
17
|
+
</Link>
|
|
18
|
+
<Link
|
|
19
|
+
to={ROUTES.guide}
|
|
20
|
+
className="text-[#516f90] hover:text-[#0091ae] [&.active]:text-[#0091ae]"
|
|
21
|
+
>
|
|
22
|
+
Developer guide
|
|
23
|
+
</Link>
|
|
24
|
+
</nav>
|
|
25
|
+
</div>
|
|
26
|
+
</header>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
import { StarterNav } from './starter-nav'
|
|
4
|
+
|
|
5
|
+
export function StarterShell({
|
|
6
|
+
children,
|
|
7
|
+
showNav = true,
|
|
8
|
+
}: {
|
|
9
|
+
children: ReactNode
|
|
10
|
+
showNav?: boolean
|
|
11
|
+
}) {
|
|
12
|
+
return (
|
|
13
|
+
<div className="min-h-screen bg-[#eaf0f6] text-[#33475b]">
|
|
14
|
+
{showNav ? <StarterNav /> : null}
|
|
15
|
+
{children}
|
|
16
|
+
</div>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
export
|
|
3
|
-
dataSourceSet: [],
|
|
4
|
-
hubId: 'dev',
|
|
5
|
-
userData: {},
|
|
6
|
-
objectList: [] as unknown[],
|
|
7
|
-
}
|
|
1
|
+
/** Kit runtime imports `@/defaultData` — re-export from the hubspot slice. */
|
|
2
|
+
export { devDefaultData as defaultData } from './hubspot/default-data'
|
package/examples/greenfield/module-hybrid-cdn/src/features/starter/components/starter-guide-page.tsx
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { SectionCard } from '@/components/layout/section-card'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
DEV_WORKFLOW,
|
|
5
|
+
PROJECT_LAYOUT,
|
|
6
|
+
WOODSCLI_ABOUT,
|
|
7
|
+
WOODSCLI_COMMANDS,
|
|
8
|
+
} from '../content/woodscli-guide-content'
|
|
9
|
+
|
|
10
|
+
export function StarterGuidePage() {
|
|
11
|
+
return (
|
|
12
|
+
<main className="mx-auto max-w-4xl space-y-8 px-6 py-10 sm:px-10">
|
|
13
|
+
<div>
|
|
14
|
+
<h1 className="text-2xl font-semibold tracking-tight">Developer guide</h1>
|
|
15
|
+
<p className="mt-2 text-sm leading-relaxed text-[#516f90]">
|
|
16
|
+
Commands, project layout, and workflow for this WoodsCLI module. Routes live in{' '}
|
|
17
|
+
<code className="font-mono text-xs">src/routes/</code> and delegate to{' '}
|
|
18
|
+
<code className="font-mono text-xs">src/features/</code>.
|
|
19
|
+
</p>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<SectionCard title="About WoodsCLI">
|
|
23
|
+
<p className="text-sm leading-relaxed text-[#516f90]">{WOODSCLI_ABOUT.tagline}</p>
|
|
24
|
+
<p className="mt-3 text-sm leading-relaxed text-[#516f90]">{WOODSCLI_ABOUT.docsHint}</p>
|
|
25
|
+
</SectionCard>
|
|
26
|
+
|
|
27
|
+
<SectionCard title="Essential commands">
|
|
28
|
+
<ul className="divide-y divide-[#eaf0f6]">
|
|
29
|
+
{WOODSCLI_COMMANDS.map(({ cmd, desc }) => (
|
|
30
|
+
<li key={cmd} className="flex flex-col gap-1 py-3 first:pt-0 last:pb-0 sm:flex-row sm:gap-4">
|
|
31
|
+
<code className="shrink-0 rounded bg-[#eaf0f6] px-2 py-1 font-mono text-xs text-[#0091ae]">
|
|
32
|
+
{cmd}
|
|
33
|
+
</code>
|
|
34
|
+
<span className="text-sm leading-relaxed text-[#516f90]">{desc}</span>
|
|
35
|
+
</li>
|
|
36
|
+
))}
|
|
37
|
+
</ul>
|
|
38
|
+
</SectionCard>
|
|
39
|
+
|
|
40
|
+
<SectionCard title="Project layout">
|
|
41
|
+
<ul className="space-y-3">
|
|
42
|
+
{PROJECT_LAYOUT.map(({ path, note }) => (
|
|
43
|
+
<li key={path} className="text-sm leading-relaxed">
|
|
44
|
+
<code className="rounded bg-[#eaf0f6] px-1.5 py-0.5 font-mono text-xs text-[#33475b]">
|
|
45
|
+
{path}
|
|
46
|
+
</code>
|
|
47
|
+
<span className="mt-1 block text-[#516f90] sm:mt-0 sm:inline sm:before:content-['—_']">
|
|
48
|
+
{note}
|
|
49
|
+
</span>
|
|
50
|
+
</li>
|
|
51
|
+
))}
|
|
52
|
+
</ul>
|
|
53
|
+
</SectionCard>
|
|
54
|
+
|
|
55
|
+
<SectionCard title="Developer workflow">
|
|
56
|
+
<ol className="space-y-4">
|
|
57
|
+
{DEV_WORKFLOW.map(({ title: stepTitle, body }) => (
|
|
58
|
+
<li key={stepTitle}>
|
|
59
|
+
<h3 className="text-sm font-medium text-[#33475b]">{stepTitle}</h3>
|
|
60
|
+
<p className="mt-1 text-sm leading-relaxed text-[#516f90]">{body}</p>
|
|
61
|
+
</li>
|
|
62
|
+
))}
|
|
63
|
+
</ol>
|
|
64
|
+
</SectionCard>
|
|
65
|
+
|
|
66
|
+
<SectionCard title="Routing">
|
|
67
|
+
<p className="text-sm leading-relaxed text-[#516f90]">
|
|
68
|
+
This starter uses the same TanStack Router setup as{' '}
|
|
69
|
+
<code className="font-mono text-xs">woodsportal-client-frontend</code>: file routes under{' '}
|
|
70
|
+
<code className="font-mono text-xs">src/routes/</code>,{' '}
|
|
71
|
+
<code className="font-mono text-xs">src/app.tsx</code> with{' '}
|
|
72
|
+
<code className="font-mono text-xs">RouterProvider</code>, and{' '}
|
|
73
|
+
<strong>hash history</strong> by default (
|
|
74
|
+
<code className="font-mono text-xs">src/config/router.ts</code>) so routes work inside
|
|
75
|
+
HubSpot CMS embeds. Run <code className="font-mono text-xs">wp init</code> again on a new
|
|
76
|
+
folder to choose browser history or no router. Add{' '}
|
|
77
|
+
<code className="font-mono text-xs">src/routes/about.tsx</code> and restart{' '}
|
|
78
|
+
<code className="font-mono text-xs">wp dev</code> to regenerate{' '}
|
|
79
|
+
<code className="font-mono text-xs">routeTree.gen.ts</code>.
|
|
80
|
+
</p>
|
|
81
|
+
</SectionCard>
|
|
82
|
+
|
|
83
|
+
<SectionCard title="Customize this preview">
|
|
84
|
+
<p className="text-sm leading-relaxed text-[#516f90]">
|
|
85
|
+
Edit <code className="font-mono text-xs">public/fields.json</code> to add module fields,
|
|
86
|
+
then adjust <code className="font-mono text-xs">src/features/starter/</code> to bind them.
|
|
87
|
+
Replace the starter feature with your own under{' '}
|
|
88
|
+
<code className="font-mono text-xs">src/features/</code> when you outgrow the demo.
|
|
89
|
+
</p>
|
|
90
|
+
</SectionCard>
|
|
91
|
+
</main>
|
|
92
|
+
)
|
|
93
|
+
}
|
package/examples/greenfield/module-hybrid-cdn/src/features/starter/components/starter-home-page.tsx
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Link } from '@tanstack/react-router'
|
|
2
|
+
|
|
3
|
+
import { ROUTES } from '@/config/routes'
|
|
4
|
+
|
|
5
|
+
import { StarterHome } from './starter-home'
|
|
6
|
+
|
|
7
|
+
export function StarterHomePage() {
|
|
8
|
+
return (
|
|
9
|
+
<>
|
|
10
|
+
<StarterHome />
|
|
11
|
+
<div className="mx-auto max-w-4xl px-6 pb-10 sm:px-10">
|
|
12
|
+
<Link
|
|
13
|
+
to={ROUTES.guide}
|
|
14
|
+
className="inline-flex items-center rounded-md bg-[#0091ae] px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-[#007a8c]"
|
|
15
|
+
>
|
|
16
|
+
Open developer guide →
|
|
17
|
+
</Link>
|
|
18
|
+
</div>
|
|
19
|
+
</>
|
|
20
|
+
)
|
|
21
|
+
}
|
package/examples/greenfield/module-hybrid-cdn/src/features/starter/components/starter-home.tsx
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useStarterPreview } from '../hooks/use-starter-preview'
|
|
2
|
+
import { STARTER_FEATURES, WOODSCLI_ABOUT } from '../content/woodscli-guide-content'
|
|
3
|
+
|
|
4
|
+
function heroClass(style: ReturnType<typeof useStarterPreview>['heroStyle']): string {
|
|
5
|
+
if (style === 'minimal') {
|
|
6
|
+
return 'bg-[var(--mc-bg-shell,#f5f8fa)] text-[var(--mc-text,#33475b)] border-b border-[var(--mc-border,#cbd6e2)]'
|
|
7
|
+
}
|
|
8
|
+
if (style === 'bold') {
|
|
9
|
+
return 'bg-[#1c1c1f] text-white'
|
|
10
|
+
}
|
|
11
|
+
return 'bg-gradient-to-br from-[var(--starter-accent,#0091ae)] to-[#ff7a59] text-white'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function StarterHome() {
|
|
15
|
+
const { title, tagline, showFeatureCards, accentColor, heroStyle } = useStarterPreview()
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<>
|
|
19
|
+
<div style={{ ['--starter-accent' as string]: accentColor }}>
|
|
20
|
+
<section className={`px-6 py-14 sm:px-10 sm:py-16 ${heroClass(heroStyle)}`}>
|
|
21
|
+
<div className="mx-auto max-w-4xl">
|
|
22
|
+
<p className="mb-2 text-xs font-semibold uppercase tracking-widest opacity-80">
|
|
23
|
+
{WOODSCLI_ABOUT.package} · local dev
|
|
24
|
+
</p>
|
|
25
|
+
<h1 className="text-3xl font-semibold tracking-tight sm:text-4xl">{title}</h1>
|
|
26
|
+
<p className="mt-4 max-w-2xl text-base leading-relaxed opacity-90 sm:text-lg">{tagline}</p>
|
|
27
|
+
<p className="mt-6 text-sm opacity-75">
|
|
28
|
+
Module config overlay:{' '}
|
|
29
|
+
<kbd className="rounded bg-black/10 px-1.5 py-0.5 font-mono text-xs">Ctrl+Shift+Z</kbd>
|
|
30
|
+
{' · '}
|
|
31
|
+
Mac: <kbd className="rounded bg-black/10 px-1.5 py-0.5 font-mono text-xs">⌃⇧Z</kbd>
|
|
32
|
+
</p>
|
|
33
|
+
</div>
|
|
34
|
+
</section>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
{showFeatureCards ? (
|
|
38
|
+
<div className="mx-auto grid max-w-4xl gap-4 px-6 py-10 sm:grid-cols-3 sm:px-10">
|
|
39
|
+
{STARTER_FEATURES.map((feature) => (
|
|
40
|
+
<article
|
|
41
|
+
key={feature.title}
|
|
42
|
+
className="rounded-lg border border-[#cbd6e2] bg-white p-5 shadow-sm"
|
|
43
|
+
>
|
|
44
|
+
<h2 className="text-sm font-semibold text-[#0091ae]">{feature.title}</h2>
|
|
45
|
+
<p className="mt-2 text-sm leading-relaxed text-[#516f90]">{feature.body}</p>
|
|
46
|
+
</article>
|
|
47
|
+
))}
|
|
48
|
+
</div>
|
|
49
|
+
) : null}
|
|
50
|
+
</>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { StarterShell } from '@/components/layout/starter-shell'
|
|
2
|
+
|
|
3
|
+
import { StarterGuidePage } from './starter-guide-page'
|
|
4
|
+
import { StarterHome } from './starter-home'
|
|
5
|
+
|
|
6
|
+
/** Single-page starter when `wp init --router none` (no TanStack Router). */
|
|
7
|
+
export function StarterSinglePage() {
|
|
8
|
+
return (
|
|
9
|
+
<StarterShell showNav={false}>
|
|
10
|
+
<StarterHome />
|
|
11
|
+
<div className="mx-auto max-w-4xl px-6 sm:px-10">
|
|
12
|
+
<hr className="my-10 border-[#cbd6e2]" />
|
|
13
|
+
</div>
|
|
14
|
+
<StarterGuidePage />
|
|
15
|
+
</StarterShell>
|
|
16
|
+
)
|
|
17
|
+
}
|