@feeef.dev/cli 0.2.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/LICENSE +6 -0
- package/README.md +94 -0
- package/dist/bin.js +2752 -0
- package/dist/bin.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +2730 -0
- package/dist/index.js.map +1 -0
- package/package.json +67 -0
- package/scaffolds/blank/.cursor/rules/feeef-theme.mdc +34 -0
- package/scaffolds/blank/.cursor/rules/filterator.mdc +13 -0
- package/scaffolds/blank/.cursor/rules/order-form.mdc +17 -0
- package/scaffolds/blank/.cursor/rules/theme-source.mdc +32 -0
- package/scaffolds/blank/.cursor/skills/feeef-filterator/SKILL.md +15 -0
- package/scaffolds/blank/.cursor/skills/feeef-theme/SKILL.md +56 -0
- package/scaffolds/blank/.cursor/skills/feeef-theme/reference.md +73 -0
- package/scaffolds/blank/.vscode/extensions.json +3 -0
- package/scaffolds/blank/.vscode/settings.json +13 -0
- package/scaffolds/blank/AGENTS.md +104 -0
- package/scaffolds/blank/README.md +21 -0
- package/scaffolds/blank/docs/00-INDEX.md +33 -0
- package/scaffolds/blank/docs/03-CUSTOM-COMPONENTS.md +116 -0
- package/scaffolds/blank/docs/04-WORKFLOW.md +129 -0
- package/scaffolds/blank/docs/05-ANTI-PATTERNS.md +80 -0
- package/scaffolds/blank/docs/07-SHARED-COMPONENTS.md +144 -0
- package/scaffolds/blank/docs/08-ORDER-FORM.md +376 -0
- package/scaffolds/blank/docs/09-THEME-PORTING.md +211 -0
- package/scaffolds/blank/docs/10-SCHEMA-LIBRARY.md +127 -0
- package/scaffolds/blank/docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md +81 -0
- package/scaffolds/blank/docs/12-DARK-LIGHT-THEME.md +164 -0
- package/scaffolds/blank/docs/13-TEMPLATE-I18N.md +320 -0
- package/scaffolds/blank/docs/14-FILTERATOR.md +433 -0
- package/scaffolds/blank/docs/16-AUTHORING-TS-IMPORTS.md +73 -0
- package/scaffolds/blank/feeef.template.json +7 -0
- package/scaffolds/blank/locales/README.md +4 -0
- package/scaffolds/blank/locales/ar.json +10 -0
- package/scaffolds/blank/locales/en.json +10 -0
- package/scaffolds/blank/package-lock.json +1975 -0
- package/scaffolds/blank/package.json +23 -0
- package/scaffolds/blank/pages/home/components/hero.tsx +34 -0
- package/scaffolds/blank/pages/home/page.json +3 -0
- package/scaffolds/blank/props.json +6 -0
- package/scaffolds/blank/schema.ts +49 -0
- package/scaffolds/blank/tsconfig.json +24 -0
- package/scaffolds/blank/types/feeef-live-scope.d.ts +162 -0
- package/scaffolds/blank/types/feeef-template-schema.d.ts +84 -0
- package/vendor/template-kit/README.md +64 -0
- package/vendor/template-kit/bin/dev.mjs +61 -0
- package/vendor/template-kit/bin/feeef-template.mjs +212 -0
- package/vendor/template-kit/data/lithium-schema.json +4733 -0
- package/vendor/template-kit/lib/build.mjs +377 -0
- package/vendor/template-kit/lib/compile-component.mjs +188 -0
- package/vendor/template-kit/lib/component-meta.mjs +481 -0
- package/vendor/template-kit/lib/library.mjs +168 -0
- package/vendor/template-kit/lib/locales.mjs +68 -0
- package/vendor/template-kit/lib/paths.mjs +84 -0
- package/vendor/template-kit/lib/shared.mjs +268 -0
- package/vendor/template-kit/lib/theme-schema.mjs +300 -0
- package/vendor/template-kit/lib/unpack.mjs +324 -0
- package/vendor/template-kit/lib/validate.mjs +207 -0
- package/vendor/template-kit/schemas/component.schema.json +55 -0
- package/vendor/template-kit/schemas/template.schema.json +18 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "feeef-theme",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Feeef Lithium theme",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=18"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "feeef template build",
|
|
12
|
+
"check": "feeef template check",
|
|
13
|
+
"dev": "feeef template dev",
|
|
14
|
+
"publish": "feeef template publish",
|
|
15
|
+
"typecheck": "tsc --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/react": "^19.0.0",
|
|
20
|
+
"@types/react-dom": "^19.0.0",
|
|
21
|
+
"typescript": "^5.4.5"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const propsSchema = {
|
|
2
|
+
heading: { type: "string", name: "Heading" },
|
|
3
|
+
subtitle: { type: "text", name: "Subtitle" },
|
|
4
|
+
} as const;
|
|
5
|
+
|
|
6
|
+
export const meta = {
|
|
7
|
+
type: "custom",
|
|
8
|
+
title: "Hero",
|
|
9
|
+
order: 0,
|
|
10
|
+
propsSchema,
|
|
11
|
+
props: {
|
|
12
|
+
heading: "",
|
|
13
|
+
subtitle: "",
|
|
14
|
+
},
|
|
15
|
+
} as const satisfies FeeefComponentMeta<typeof propsSchema>;
|
|
16
|
+
|
|
17
|
+
type Props = FeeefLivePropsOf<typeof propsSchema>;
|
|
18
|
+
|
|
19
|
+
function App() {
|
|
20
|
+
const p = props as Props;
|
|
21
|
+
return (
|
|
22
|
+
<section style={{ padding: "4rem 1.5rem", textAlign: "center" }}>
|
|
23
|
+
<h1 style={{ fontSize: "2rem", marginBottom: "0.75rem" }}>
|
|
24
|
+
{p.heading || t("home.heroHeading")}
|
|
25
|
+
</h1>
|
|
26
|
+
<p style={{ opacity: 0.8, marginBottom: "1.5rem" }}>
|
|
27
|
+
{p.subtitle || t("home.heroText")}
|
|
28
|
+
</p>
|
|
29
|
+
<a href="/products" style={{ textDecoration: "underline" }}>
|
|
30
|
+
{t("home.shopNow")}
|
|
31
|
+
</a>
|
|
32
|
+
</section>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme schema overlay — merged with Lithium built-ins at `npm run build`.
|
|
3
|
+
* Published as `StoreTemplate.schema` (via `dist/schema.json`).
|
|
4
|
+
*/
|
|
5
|
+
export const schema = {
|
|
6
|
+
name: "blank",
|
|
7
|
+
version: "0.1.0",
|
|
8
|
+
schema: "1.0",
|
|
9
|
+
propsSchema: {
|
|
10
|
+
theme: {
|
|
11
|
+
name: "Theme",
|
|
12
|
+
type: "object",
|
|
13
|
+
propsSchema: {
|
|
14
|
+
mode: {
|
|
15
|
+
name: "Color mode",
|
|
16
|
+
type: "string",
|
|
17
|
+
tool: {
|
|
18
|
+
type: "select",
|
|
19
|
+
options: ["light", "dark", "system"],
|
|
20
|
+
},
|
|
21
|
+
default: "system",
|
|
22
|
+
},
|
|
23
|
+
rounded: {
|
|
24
|
+
name: "Corner roundness %",
|
|
25
|
+
type: "number",
|
|
26
|
+
tool: { type: "slider", min: 0, max: 500, step: 1 },
|
|
27
|
+
default: 100,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
pages: {
|
|
33
|
+
home: {
|
|
34
|
+
name: "Home",
|
|
35
|
+
path: "/",
|
|
36
|
+
sections: {
|
|
37
|
+
main: {},
|
|
38
|
+
},
|
|
39
|
+
layout: {
|
|
40
|
+
sm: [
|
|
41
|
+
{
|
|
42
|
+
type: "column",
|
|
43
|
+
children: ["main"],
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
} as const satisfies FeeefThemeSchema;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"checkJs": false,
|
|
10
|
+
"strict": false,
|
|
11
|
+
"noImplicitAny": false,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"allowSyntheticDefaultImports": true,
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"isolatedModules": true,
|
|
18
|
+
"noUnusedLocals": false,
|
|
19
|
+
"noUnusedParameters": false,
|
|
20
|
+
"types": []
|
|
21
|
+
},
|
|
22
|
+
"include": ["types", "pages", "shared", "library", "schema.ts"],
|
|
23
|
+
"exclude": ["node_modules", "dist"]
|
|
24
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient types for Feeef theme component `.tsx` files.
|
|
3
|
+
*
|
|
4
|
+
* Custom components run in react-live: these names are injected at runtime
|
|
5
|
+
* (no imports). This file teaches VS Code / tsserver those globals and
|
|
6
|
+
* derives props types from `propsSchema`.
|
|
7
|
+
*
|
|
8
|
+
* @see docs/03-CUSTOM-COMPONENTS.md
|
|
9
|
+
* @see docs/04-WORKFLOW.md
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/// <reference types="react" />
|
|
13
|
+
|
|
14
|
+
// ─── propsSchema → TypeScript ───────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
/** Field definition inside `meta.propsSchema` (Lithium PropDef). */
|
|
17
|
+
type FeeefPropDef = {
|
|
18
|
+
type:
|
|
19
|
+
| "string"
|
|
20
|
+
| "number"
|
|
21
|
+
| "boolean"
|
|
22
|
+
| "text"
|
|
23
|
+
| "array"
|
|
24
|
+
| "object"
|
|
25
|
+
| "color"
|
|
26
|
+
| "image"
|
|
27
|
+
| (string & {});
|
|
28
|
+
tool?: unknown;
|
|
29
|
+
default?: unknown;
|
|
30
|
+
items?: FeeefPropDef | { type: string; propsSchema?: FeeefPropsSchema };
|
|
31
|
+
propsSchema?: FeeefPropsSchema;
|
|
32
|
+
name?: string;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type FeeefPropsSchema = Record<string, FeeefPropDef>;
|
|
37
|
+
|
|
38
|
+
/** Map a single PropDef to a TS value type. */
|
|
39
|
+
type FeeefPropValue<D> = D extends { type: "number" }
|
|
40
|
+
? number
|
|
41
|
+
: D extends { type: "boolean" }
|
|
42
|
+
? boolean
|
|
43
|
+
: D extends { type: "array"; items: infer I }
|
|
44
|
+
? FeeefPropValue<I>[]
|
|
45
|
+
: D extends { type: "object"; propsSchema: infer PS extends FeeefPropsSchema }
|
|
46
|
+
? FeeefPropsFromSchema<PS>
|
|
47
|
+
: D extends { type: "string" | "text" | "color" | "image" }
|
|
48
|
+
? string
|
|
49
|
+
: D extends { type: string }
|
|
50
|
+
? unknown
|
|
51
|
+
: unknown;
|
|
52
|
+
|
|
53
|
+
/** Props object inferred from a `propsSchema` const. */
|
|
54
|
+
type FeeefPropsFromSchema<S> = {
|
|
55
|
+
[K in keyof S]: S[K] extends FeeefPropDef ? FeeefPropValue<S[K]> : unknown;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Live `props` shape for a schema: schema fields + slots chrome.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const propsSchema = { heading: { type: "string" } } as const;
|
|
64
|
+
* type Props = FeeefLivePropsOf<typeof propsSchema>;
|
|
65
|
+
* function App() {
|
|
66
|
+
* const p = props as Props;
|
|
67
|
+
* return <h1>{p.heading}</h1>;
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
type FeeefLivePropsOf<S> = FeeefPropsFromSchema<S> & {
|
|
72
|
+
slots?: Record<string, React.ReactNode | React.ReactNode[] | undefined>;
|
|
73
|
+
slotsLayout?: unknown;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Use with `satisfies` so `meta.props` must match `meta.propsSchema`.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* export const meta = { …, propsSchema, props } as const satisfies FeeefComponentMeta<typeof propsSchema>;
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
type FeeefComponentMeta<
|
|
85
|
+
S extends FeeefPropsSchema = FeeefPropsSchema,
|
|
86
|
+
> = {
|
|
87
|
+
type?: string;
|
|
88
|
+
instanceId?: string;
|
|
89
|
+
title?: string;
|
|
90
|
+
order?: number;
|
|
91
|
+
propsSchema?: S;
|
|
92
|
+
props?: FeeefPropsFromSchema<S>;
|
|
93
|
+
slotsSchema?: Record<string, { name?: string | null; maxChildren?: number | null }>;
|
|
94
|
+
slotsLayout?: unknown;
|
|
95
|
+
slots?: Record<string, unknown> | null;
|
|
96
|
+
children?: unknown[] | null;
|
|
97
|
+
refId?: string;
|
|
98
|
+
refVersion?: number;
|
|
99
|
+
[key: string]: unknown;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/** Untyped fallback (marketplace / legacy). Prefer `FeeefLivePropsOf<typeof propsSchema>`. */
|
|
103
|
+
interface FeeefLiveProps {
|
|
104
|
+
[key: string]: any;
|
|
105
|
+
slots?: Record<string, any>;
|
|
106
|
+
slotsLayout?: any;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
declare const React: typeof import("react");
|
|
110
|
+
|
|
111
|
+
/** Template props for this component (react-live scope). Cast with `FeeefLivePropsOf<…>`. */
|
|
112
|
+
declare const props: FeeefLiveProps;
|
|
113
|
+
|
|
114
|
+
declare const useState: typeof import("react").useState;
|
|
115
|
+
declare const useEffect: typeof import("react").useEffect;
|
|
116
|
+
declare const useLayoutEffect: typeof import("react").useLayoutEffect;
|
|
117
|
+
declare const useRef: typeof import("react").useRef;
|
|
118
|
+
declare const useMemo: typeof import("react").useMemo;
|
|
119
|
+
declare const useCallback: typeof import("react").useCallback;
|
|
120
|
+
|
|
121
|
+
declare function useStore(): any;
|
|
122
|
+
declare function useFeeef(): any;
|
|
123
|
+
declare function useFeeefCart(): any;
|
|
124
|
+
declare function useCurrentProduct(): any;
|
|
125
|
+
declare function useTemplate(): any;
|
|
126
|
+
declare function useTheme(): any;
|
|
127
|
+
|
|
128
|
+
declare function t(key: string, params?: any): string;
|
|
129
|
+
declare function useFeeefT(): typeof t;
|
|
130
|
+
declare function useFeeefLocale(): string;
|
|
131
|
+
declare function getFeeefLocale(): string;
|
|
132
|
+
declare function getFeeefDir(): "rtl" | "ltr";
|
|
133
|
+
|
|
134
|
+
declare function useRouter(): any;
|
|
135
|
+
declare function usePathname(): string;
|
|
136
|
+
declare function useSearchParams(): any;
|
|
137
|
+
|
|
138
|
+
declare const Link: React.ComponentType<any>;
|
|
139
|
+
|
|
140
|
+
/** Nav helper — object API and/or JSX depending on theme code. */
|
|
141
|
+
declare const RouterNav: React.ComponentType<any> & {
|
|
142
|
+
push: (href: string) => void;
|
|
143
|
+
replace: (href: string) => void;
|
|
144
|
+
[key: string]: any;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
declare const SlotsLayout: React.ComponentType<any>;
|
|
148
|
+
declare const SlotContextBridge: React.ComponentType<any>;
|
|
149
|
+
declare function useSlotContext(key: string): any;
|
|
150
|
+
|
|
151
|
+
declare function dartColorToCssColor(dartColor: any): string | null;
|
|
152
|
+
declare function convertDartColorToCssNumber(dartColor: any): number | null;
|
|
153
|
+
declare function cssColorToHslString(color: any): string | null;
|
|
154
|
+
|
|
155
|
+
interface Window {
|
|
156
|
+
fbq?: (...args: any[]) => void;
|
|
157
|
+
[key: string]: any;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
interface CSSProperties {
|
|
161
|
+
[key: `--${string}`]: string | number | undefined;
|
|
162
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript types for theme-owned `schema.ts` overlays.
|
|
3
|
+
*
|
|
4
|
+
* Author with:
|
|
5
|
+
* ```ts
|
|
6
|
+
* export const schema = { … } as const satisfies FeeefThemeSchema;
|
|
7
|
+
* ```
|
|
8
|
+
*
|
|
9
|
+
* Build merges this with Lithium built-ins → `dist/schema.json`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** Field definition (same shape as component propsSchema / Lithium PropDef). */
|
|
13
|
+
type FeeefSchemaPropDef = {
|
|
14
|
+
type:
|
|
15
|
+
| "string"
|
|
16
|
+
| "number"
|
|
17
|
+
| "boolean"
|
|
18
|
+
| "text"
|
|
19
|
+
| "array"
|
|
20
|
+
| "object"
|
|
21
|
+
| "color"
|
|
22
|
+
| "image"
|
|
23
|
+
| (string & {});
|
|
24
|
+
name?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
default?: unknown;
|
|
27
|
+
tool?: unknown;
|
|
28
|
+
items?: FeeefSchemaPropDef | { type: string; propsSchema?: FeeefSchemaPropsMap };
|
|
29
|
+
propsSchema?: FeeefSchemaPropsMap;
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type FeeefSchemaPropsMap = Record<string, FeeefSchemaPropDef>;
|
|
34
|
+
|
|
35
|
+
/** Built-in / catalog component entry in schema.components. */
|
|
36
|
+
type FeeefSchemaComponentDef = {
|
|
37
|
+
name?: string;
|
|
38
|
+
category?: string;
|
|
39
|
+
description?: string;
|
|
40
|
+
acceptsChildren?: boolean;
|
|
41
|
+
propsSchema?: FeeefSchemaPropsMap;
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** One section key under a page (e.g. main). */
|
|
46
|
+
type FeeefSchemaSectionDef = {
|
|
47
|
+
propsSchema?: FeeefSchemaPropsMap;
|
|
48
|
+
[key: string]: unknown;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** Responsive layout node used by the merchant editor. */
|
|
52
|
+
type FeeefSchemaLayoutNode = {
|
|
53
|
+
type: string;
|
|
54
|
+
children?: Array<string | FeeefSchemaLayoutNode>;
|
|
55
|
+
[key: string]: unknown;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
type FeeefSchemaPageDef = {
|
|
59
|
+
name?: string;
|
|
60
|
+
path?: string;
|
|
61
|
+
description?: string;
|
|
62
|
+
propsSchema?: FeeefSchemaPropsMap;
|
|
63
|
+
sections: Record<string, FeeefSchemaSectionDef>;
|
|
64
|
+
layout?: Record<string, FeeefSchemaLayoutNode[]>;
|
|
65
|
+
[key: string]: unknown;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Theme schema overlay (and full packaged schema shape).
|
|
70
|
+
*
|
|
71
|
+
* - `pages` + `propsSchema` are theme-controlled.
|
|
72
|
+
* - `components` is optional; merged onto Lithium built-ins at build.
|
|
73
|
+
*/
|
|
74
|
+
type FeeefThemeSchema = {
|
|
75
|
+
name: string;
|
|
76
|
+
version: string;
|
|
77
|
+
/** Schema format version (Lithium uses `"1.0"`). */
|
|
78
|
+
schema?: string;
|
|
79
|
+
propsSchema?: FeeefSchemaPropsMap;
|
|
80
|
+
pages: Record<string, FeeefSchemaPageDef>;
|
|
81
|
+
components?: Record<string, FeeefSchemaComponentDef>;
|
|
82
|
+
library?: unknown[];
|
|
83
|
+
[key: string]: unknown;
|
|
84
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Feeef Template Kit
|
|
2
|
+
|
|
3
|
+
Author Lithium templates as a **folder tree** (real `.jsx` files + JSON schemas), then compile to the `data.json` blob Feeef already understands.
|
|
4
|
+
|
|
5
|
+
**AI / engineer docs (start here):** [`../templates/AGENTS.md`](../templates/AGENTS.md) · [`../templates/docs/`](../templates/docs/)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
pages/home/sections/header/components/dawn-shell/
|
|
10
|
+
component.json # type, props, propsSchema, slotsSchema, …
|
|
11
|
+
component.jsx # function App() { … } → becomes "code"
|
|
12
|
+
slots/sections/… # nested components
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick demo (from `storefront/`)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# 1) Split the Dawn theme into a source tree
|
|
19
|
+
npm run template:unpack
|
|
20
|
+
|
|
21
|
+
# 2) Compile back to dist/data.json
|
|
22
|
+
npm run template:build
|
|
23
|
+
|
|
24
|
+
# 3) Run Lithium with the local override (dev only)
|
|
25
|
+
npm run template:dev
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Open the storefront, edit any `component.jsx`, save — with `template:watch` (or `template:dev`) the dist file rebuilds; refresh the page to see it.
|
|
29
|
+
|
|
30
|
+
## Commands
|
|
31
|
+
|
|
32
|
+
| Script | What it does |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `npm run template:unpack` | `templates/down/data.json` → `templates/dawn-src/` |
|
|
35
|
+
| `npm run template:build` | `dawn-src/` → `dawn-src/dist/data.json` |
|
|
36
|
+
| `npm run template:check` | Validate without writing |
|
|
37
|
+
| `npm run template:watch` | Rebuild on file change |
|
|
38
|
+
| `npm run template:dev` | Watch + `next dev` with `FEEEF_TEMPLATE_DATA_PATH` set |
|
|
39
|
+
|
|
40
|
+
CLI entry: `node template-kit/bin/feeef-template.mjs <cmd>`.
|
|
41
|
+
|
|
42
|
+
## Dev override
|
|
43
|
+
|
|
44
|
+
When `NODE_ENV=development` and `FEEEF_TEMPLATE_DATA_PATH` points at a `data.json` file, Lithium's server-only `getTemplate()` (`utils/get-template.ts`) loads that file on every request (no cache) instead of `store.metadata.templateData`. Production ignores the env var. The loader is intentionally separate from `@/utils/template` so `node:fs` never enters the client bundle.
|
|
45
|
+
|
|
46
|
+
## Conventions
|
|
47
|
+
|
|
48
|
+
| Disk | Maps to |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `feeef.template.json` | Manifest (name, page order) |
|
|
51
|
+
| `props.json` | Root `props` (theme, …) |
|
|
52
|
+
| `pages/<id>/page.json` | Page `props` |
|
|
53
|
+
| `…/components/<name>/component.json` | Component meta (+ `order`) |
|
|
54
|
+
| `component.jsx` | `code` (custom components) |
|
|
55
|
+
| `slots/<slotId>/<child>/` | `slots[slotId][]` |
|
|
56
|
+
| `children/<child>/` | `children[]` (grid/flex/container) |
|
|
57
|
+
| `shared/components/<id>/` | Theme library — placements use `$ref: "shared.<id>"` |
|
|
58
|
+
| `$ref` / `shared` in placement json | Expanded at build (not left in dist) |
|
|
59
|
+
|
|
60
|
+
Add `"$schema": "../../template-kit/schemas/component.schema.json"` in `component.json` for IDE autocomplete.
|
|
61
|
+
|
|
62
|
+
## Shared components
|
|
63
|
+
|
|
64
|
+
See [`../templates/docs/07-SHARED-COMPONENTS.md`](../templates/docs/07-SHARED-COMPONENTS.md). UI reused across pages **must** live under `shared/components/`.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build once, then run template:watch + next dev with FEEEF_TEMPLATE_DATA_PATH.
|
|
4
|
+
* Usage (from storefront/): node template-kit/bin/dev.mjs
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { buildTemplate } from "../lib/build.mjs";
|
|
11
|
+
|
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const storefrontRoot = path.resolve(__dirname, "../..");
|
|
14
|
+
const srcDir = path.join(storefrontRoot, "templates/dawn-src");
|
|
15
|
+
const dataPath = path.join(srcDir, "dist/data.json");
|
|
16
|
+
const libraryPath = path.join(srcDir, "dist/schema.library.json");
|
|
17
|
+
const cli = path.join(__dirname, "feeef-template.mjs");
|
|
18
|
+
|
|
19
|
+
function run() {
|
|
20
|
+
try {
|
|
21
|
+
buildTemplate({ srcDir, outPath: dataPath, write: true });
|
|
22
|
+
console.log(`[template-kit] dist ready → ${path.relative(storefrontRoot, dataPath)}`);
|
|
23
|
+
} catch (e) {
|
|
24
|
+
console.error(`[template-kit] initial build failed: ${e.message || e}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const env = {
|
|
29
|
+
...process.env,
|
|
30
|
+
FEEEF_TEMPLATE_DATA_PATH: dataPath,
|
|
31
|
+
FEEEF_TEMPLATE_LIBRARY_PATH: libraryPath,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const watch = spawn(
|
|
35
|
+
process.execPath,
|
|
36
|
+
[cli, "watch", srcDir, "-o", dataPath],
|
|
37
|
+
{ cwd: storefrontRoot, env, stdio: "inherit" },
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const next = spawn(
|
|
41
|
+
"npx",
|
|
42
|
+
["next", "dev", "--turbopack"],
|
|
43
|
+
{ cwd: storefrontRoot, env, stdio: "inherit", shell: true },
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const shutdown = (code) => {
|
|
47
|
+
watch.kill("SIGTERM");
|
|
48
|
+
next.kill("SIGTERM");
|
|
49
|
+
process.exit(code ?? 0);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
watch.on("exit", (code) => {
|
|
53
|
+
if (code && code !== 0) shutdown(code);
|
|
54
|
+
});
|
|
55
|
+
next.on("exit", (code) => shutdown(code ?? 0));
|
|
56
|
+
|
|
57
|
+
process.on("SIGINT", () => shutdown(0));
|
|
58
|
+
process.on("SIGTERM", () => shutdown(0));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
run();
|