@feeef.dev/cli 0.2.2 → 0.2.3
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/README.md +22 -5
- package/dist/bin.js +127 -16
- package/dist/bin.js.map +1 -1
- package/dist/index.js +127 -16
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/scaffolds/blank/.cursor/rules/feeef-theme.mdc +9 -7
- package/scaffolds/blank/.cursor/rules/theme-source.mdc +24 -17
- package/scaffolds/blank/.cursor/skills/feeef-theme/SKILL.md +21 -9
- package/scaffolds/blank/.cursor/skills/feeef-theme/reference.md +35 -30
- package/scaffolds/blank/AGENTS.md +7 -4
- package/scaffolds/blank/README.md +1 -1
- package/scaffolds/blank/docs/03-CUSTOM-COMPONENTS.md +68 -39
- package/scaffolds/blank/docs/04-WORKFLOW.md +7 -4
- package/scaffolds/blank/docs/05-ANTI-PATTERNS.md +7 -6
- package/scaffolds/blank/docs/07-SHARED-COMPONENTS.md +45 -77
- package/scaffolds/blank/docs/08-ORDER-FORM.md +1 -1
- package/scaffolds/blank/docs/10-SCHEMA-LIBRARY.md +21 -69
- package/scaffolds/blank/docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md +37 -22
- package/scaffolds/blank/docs/16-AUTHORING-TS-IMPORTS.md +38 -14
- package/scaffolds/blank/package-lock.json +4 -1918
- package/vendor/template-kit/lib/build.mjs +1 -1
- package/vendor/template-kit/lib/component-meta.mjs +92 -8
- package/vendor/template-kit/lib/unpack.mjs +295 -135
- package/vendor/template-kit/lib/validate.mjs +1 -1
|
@@ -7,8 +7,8 @@ Feeef has **two** reuse layers. Use the right one.
|
|
|
7
7
|
```mermaid
|
|
8
8
|
flowchart TB
|
|
9
9
|
subgraph authoring [Theme authoring - template-kit]
|
|
10
|
-
sharedDisk["shared/components/footer"]
|
|
11
|
-
placement["pages/.../
|
|
10
|
+
sharedDisk["shared/components/footer.tsx"]
|
|
11
|
+
placement["pages/.../footer.json\n$ref: shared.footer"]
|
|
12
12
|
build["template:build"]
|
|
13
13
|
dataJson["dist/data.json\nfully inlined components"]
|
|
14
14
|
sharedDisk --> build
|
|
@@ -30,13 +30,21 @@ flowchart TB
|
|
|
30
30
|
storeMeta --> resolve
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
## 1. Theme shared library (compile-time) — **prefer this
|
|
33
|
+
## 1. Theme shared library (compile-time) — **prefer this**
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
### Paths (flat TSX required for leaves)
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
| Kind | Path |
|
|
38
|
+
|---|---|
|
|
39
|
+
| **Leaf custom (preferred)** | `shared/components/<id>.tsx` — `export const meta` + `function App()` |
|
|
40
|
+
| **Leaf built-in / $ref stub** | `shared/components/<id>.json` or placement `.json` |
|
|
41
|
+
| **With slots/children** | `shared/components/<id>/<id>.tsx` + `slots/` / `children/` |
|
|
42
|
+
|
|
43
|
+
Do **not** ship customs as `component.json` + `component.jsx` pairs anymore. Meta belongs in `export const meta` inside the `.tsx` file.
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
### Placement (thin stub — do not copy JSX)
|
|
46
|
+
|
|
47
|
+
Place next to other page components (flat stack) or inside a shell’s `slots/`:
|
|
40
48
|
|
|
41
49
|
```json
|
|
42
50
|
{
|
|
@@ -44,101 +52,61 @@ Same shape as any component (`component.json` + optional `component.jsx` + slots
|
|
|
44
52
|
"$ref": "shared.footer",
|
|
45
53
|
"instanceId": "contact_footer_1",
|
|
46
54
|
"title": null,
|
|
47
|
-
"props": {
|
|
48
|
-
"social_media": [{ "platform": "instagram", "url": "https://instagram.com/feeef.dz" }]
|
|
49
|
-
}
|
|
55
|
+
"props": {}
|
|
50
56
|
}
|
|
51
57
|
```
|
|
52
58
|
|
|
53
59
|
Shorthand: `"shared": "footer"` instead of `"$ref": "shared.footer"`.
|
|
54
60
|
|
|
61
|
+
Example page stack (no nested Dawn-style shell required):
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
pages/home/components/
|
|
65
|
+
header.json → { "$ref": "shared.header", "order": 0, … }
|
|
66
|
+
hero.tsx
|
|
67
|
+
product-rail.tsx
|
|
68
|
+
footer.json → { "$ref": "shared.footer", "order": 99, … }
|
|
69
|
+
```
|
|
70
|
+
|
|
55
71
|
### What build does
|
|
56
72
|
|
|
57
|
-
1. Loads every `shared/components
|
|
73
|
+
1. Loads every entry under `shared/components/` (flat `.tsx` / `.json` or folders).
|
|
58
74
|
2. Expands each placement: clone shared definition → deep-merge `props` → keep placement `instanceId` / `title` / slot overrides.
|
|
59
75
|
3. Writes a normal `TemplateData` blob (**no `$ref` left** in `dist/data.json`).
|
|
60
76
|
|
|
61
|
-
Lithium never needs to know about `$ref` — the storefront only sees full components.
|
|
62
|
-
|
|
63
77
|
### Why this exists
|
|
64
78
|
|
|
65
|
-
- **One place to change design**
|
|
66
|
-
- Git-friendly: edit `shared/
|
|
67
|
-
- Matches
|
|
79
|
+
- **One place to change design** → every page updates on rebuild.
|
|
80
|
+
- Git-friendly: edit `shared/components/header.tsx` once.
|
|
81
|
+
- Matches historical `"$ref": "shared.navbar"` ideas as real disk files.
|
|
68
82
|
|
|
69
|
-
|
|
83
|
+
**Rule of thumb:** if the same UI appears on 2+ pages, it **must** live under `shared/` and be referenced — do not paste duplicate JSX.
|
|
70
84
|
|
|
71
|
-
|
|
72
|
-
|---|---|
|
|
73
|
-
| `dawn-footer` | Custom Dawn footer (JSX) |
|
|
74
|
-
| `dawn-header-bar` | Custom Dawn header bar (JSX) — chrome only, not a page shell |
|
|
75
|
-
| `dawn-storefront-shell` | Thin home/products page shell (`header` \| `sections` \| `footer`) |
|
|
76
|
-
| `dawn-thanks-shell` | Thin `/thanks` page shell (`header` \| `body` \| `footer`) |
|
|
77
|
-
| `dawn-order-form` | Legacy single-file COD (prefer field kit below) |
|
|
78
|
-
| `dawn-order-offers` | Offer list tiles (`price × minQuantity`) + per-slot variant loop (`" \| "`) |
|
|
79
|
-
| `dawn-order-qty` | Order form quantity |
|
|
80
|
-
| `dawn-order-name` | Order form name (+ section title) |
|
|
81
|
-
| `dawn-order-phone` | Order form phone (drives draft) |
|
|
82
|
-
| `dawn-order-email` | Order form email |
|
|
83
|
-
| `dawn-order-geo` | State + city row (slots: `stateSlot`, `citySlot`) |
|
|
84
|
-
| `dawn-order-state` / `dawn-order-city` | Wilaya / commune selects |
|
|
85
|
-
| `dawn-order-shipping` | Delivery type cards |
|
|
86
|
-
| `dawn-order-address` / `dawn-order-note` | Street + customer note |
|
|
87
|
-
| `dawn-order-actions` | Add to cart + Buy (place **last** in form content) |
|
|
88
|
-
| `dawn-order-success` | Post-order success UI |
|
|
89
|
-
|
|
90
|
-
**Also ship matching entries under `library/components/`** for editor drag-drop (docs/10). Keep library JSX in sync with `shared/` — library is copy-on-drop, not a live `$ref`.
|
|
91
|
-
|
|
92
|
-
Order-form fields are **shared + slot-ordered** on the PDP form manager — hide via `props.hide`, reorder by changing `order` / folder siblings, add/remove by adding/removing `$ref` placements. Behavior contract: [`08-ORDER-FORM.md`](./08-ORDER-FORM.md).
|
|
93
|
-
|
|
94
|
-
**Rule of thumb:** if the same UI appears on 2+ pages, it **must** live under `shared/` and be referenced — do not paste duplicate `component.jsx` / props.
|
|
85
|
+
Also ship matching entries under `library/components/` for editor drag-drop ([10-SCHEMA-LIBRARY.md](./10-SCHEMA-LIBRARY.md)). Library is **copy-on-drop**, not a live `$ref`.
|
|
95
86
|
|
|
96
87
|
## 2. Backend library references (runtime)
|
|
97
88
|
|
|
98
89
|
```json
|
|
99
90
|
{
|
|
100
91
|
"type": "reference",
|
|
101
|
-
"refId": "
|
|
102
|
-
"
|
|
103
|
-
"instanceId": "hero_on_home",
|
|
104
|
-
"props": { "title": "Override" },
|
|
105
|
-
"slots": {}
|
|
92
|
+
"refId": "…",
|
|
93
|
+
"props": {}
|
|
106
94
|
}
|
|
107
95
|
```
|
|
108
96
|
|
|
109
|
-
|
|
110
|
-
- Resolved in `getTemplate()` by `materializeTemplateReferences()` → becomes `type: "custom"`.
|
|
111
|
-
- Merchants reuse library blocks across stores; editing the library updates all refs (subject to versioning/policy).
|
|
112
|
-
|
|
113
|
-
**Do not confuse** `refId` (backend) with `$ref: "shared.*"` (disk kit). Different planes.
|
|
114
|
-
|
|
115
|
-
| | Kit `$ref` / `shared` | Runtime `type: "reference"` |
|
|
116
|
-
|---|---|---|
|
|
117
|
-
| When resolved | `template:build` | SSR `getTemplate` |
|
|
118
|
-
| Storage | Folders on disk | DB `template_components` |
|
|
119
|
-
| Audience | Theme engineers | Merchants / marketplace |
|
|
120
|
-
| In `data.json` | Expanded away | Kept until SSR |
|
|
121
|
-
|
|
122
|
-
## 3. Defaults.json `$ref` (legacy blank store)
|
|
97
|
+
Used after publish / marketplace install. Authoring-time `$ref: "shared.*"` is expanded at **build** and is different from runtime `type: "reference"`.
|
|
123
98
|
|
|
124
|
-
|
|
99
|
+
## Anti-patterns
|
|
125
100
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
3. Page-specific differences → **props overrides only** on the placement (URLs, labels), not a fork of the JSX.
|
|
133
|
-
4. Global look (colors, corners, fonts) → root `props.json` / CSS variables — not hardcoded in every custom component.
|
|
134
|
-
5. After edits: `npm run build` and spot-check every page that refs the shared id.
|
|
101
|
+
| Wrong | Right |
|
|
102
|
+
|---|---|
|
|
103
|
+
| Copy-paste header JSX onto home + products | One `shared/components/header.tsx` + two `$ref` stubs |
|
|
104
|
+
| `shared/components/header/component.json` + `component.jsx` for a leaf | Flat `shared/components/header.tsx` with `export const meta` |
|
|
105
|
+
| Invent deep `home-shell/slots/…` trees by hand when siblings work | Flat `pages/<page>/components/*` stack + `$ref` |
|
|
106
|
+
| Duplicate `instanceId` across placements | Unique `instanceId` per placement |
|
|
135
107
|
|
|
136
|
-
##
|
|
108
|
+
## Related
|
|
137
109
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
| Fork shared by duplicating folder “footer2” | Override `props` on the placement |
|
|
142
|
-
| Leave `$ref` in published `data.json` manually | Always run `template:build` |
|
|
143
|
-
| Use `type: "reference"` for local theme files | Kit `$ref` for themes; `reference` for DB library |
|
|
144
|
-
| Change shared + forget rebuild | `template:watch` / `template:dev` |
|
|
110
|
+
- Flat TSX authoring: [03-CUSTOM-COMPONENTS.md](./03-CUSTOM-COMPONENTS.md)
|
|
111
|
+
- Workflow: [04-WORKFLOW.md](./04-WORKFLOW.md)
|
|
112
|
+
- Order form fields as shared slots: [08-ORDER-FORM.md](./08-ORDER-FORM.md)
|
|
@@ -10,7 +10,7 @@ Canonical native implementation:
|
|
|
10
10
|
- Security: storefront order-create security checks
|
|
11
11
|
- Scope API: `docs/03-CUSTOM-COMPONENTS.md`
|
|
12
12
|
|
|
13
|
-
When writing a **custom** order form (`type: "custom"` / `
|
|
13
|
+
When writing a **custom** order form (`type: "custom"` / flat `.tsx`), you must reproduce this contract. Styling may change; behavior must not.
|
|
14
14
|
|
|
15
15
|
The shared Dawn form (`shared/components/dawn-order-form/`) is a **simplified visual reference** — it is **incomplete** vs native (no draft, no wilaya cascade, no security, calls `ff.orders.send` directly). Do **not** copy it as the behavioral source of truth.
|
|
16
16
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Schema Library (`schema.library.json`)
|
|
2
2
|
|
|
3
|
+
> Theme package copy — paths assume this theme folder is the project root.
|
|
4
|
+
|
|
3
5
|
Theme-bundled **drag-drop catalog** for the merchant template editor.
|
|
4
6
|
|
|
5
7
|
Components listed here can be **unused in `data.json`**. That is intentional: the theme ships extras the merchant can add later from the UI.
|
|
@@ -22,7 +24,7 @@ Components listed here can be **unused in `data.json`**. That is intentional: th
|
|
|
22
24
|
flowchart LR
|
|
23
25
|
schemaTs["schema.ts overlay"]
|
|
24
26
|
lithium["Lithium built-ins"]
|
|
25
|
-
disk["library/components/id
|
|
27
|
+
disk["library/components/id.tsx"]
|
|
26
28
|
build["template:build"]
|
|
27
29
|
schema["dist/schema.json"]
|
|
28
30
|
editor["Flutter Theme tab"]
|
|
@@ -35,93 +37,43 @@ flowchart LR
|
|
|
35
37
|
editor -->|"copy-on-drop"| data
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
## Authoring (
|
|
40
|
+
## Authoring (flat TSX)
|
|
39
41
|
|
|
40
42
|
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
schema.library.json
|
|
48
|
-
data.json
|
|
43
|
+
library/components/
|
|
44
|
+
promo-banner.tsx # preferred leaf: export const meta + App
|
|
45
|
+
# OR folder only when slots/children needed:
|
|
46
|
+
rich-block/
|
|
47
|
+
<id>.tsx
|
|
48
|
+
slots/…
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
### Catalog fields
|
|
51
|
+
### Catalog fields (from `export const meta` or legacy `.json`)
|
|
52
52
|
|
|
53
53
|
| Field | Role |
|
|
54
54
|
|---|---|
|
|
55
|
-
|
|
|
55
|
+
| folder / file name | Stable `id` in the library list (`libraryId`) |
|
|
56
56
|
| `title`, `subtitle`, `category`, `tags`, `imageUrl` | Editor card |
|
|
57
57
|
| `type` | Usually `custom`; may be a built-in registry type |
|
|
58
58
|
| `props` | Becomes `propsDefault` on drop |
|
|
59
|
-
| `code`
|
|
59
|
+
| `code` (built from `.tsx`) | Custom JSX |
|
|
60
60
|
| `propsSchema`, `slotsSchema`, `slotsLayout`, `slots`, `children` | Seeded on drop |
|
|
61
61
|
|
|
62
62
|
Build:
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
|
|
65
|
+
npm run build
|
|
66
66
|
# → dist/schema.library.json
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
##
|
|
70
|
-
|
|
71
|
-
```json
|
|
72
|
-
{
|
|
73
|
-
"version": "1.0",
|
|
74
|
-
"components": [
|
|
75
|
-
{
|
|
76
|
-
"id": "dawn-promo-banner",
|
|
77
|
-
"title": "Promo Banner",
|
|
78
|
-
"subtitle": null,
|
|
79
|
-
"category": "marketing",
|
|
80
|
-
"tags": ["banner"],
|
|
81
|
-
"imageUrl": null,
|
|
82
|
-
"type": "custom",
|
|
83
|
-
"code": "function App() { return <div>{props.text}</div>; }",
|
|
84
|
-
"propsSchema": { "text": { "type": "string" } },
|
|
85
|
-
"propsDefault": { "text": "Sale" },
|
|
86
|
-
"slotsSchema": null,
|
|
87
|
-
"slotsDefault": null,
|
|
88
|
-
"slotsLayout": null,
|
|
89
|
-
"children": null
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## Serving
|
|
69
|
+
## Anti-patterns
|
|
96
70
|
|
|
97
|
-
|
|
|
71
|
+
| Wrong | Right |
|
|
98
72
|
|---|---|
|
|
99
|
-
| `
|
|
100
|
-
|
|
|
101
|
-
| Dev | `FEEEF_TEMPLATE_LIBRARY_PATH` → kit `dist/schema.library.json` |
|
|
102
|
-
|
|
103
|
-
`StoreTemplate.schema` should include the same `library` array when publishing a theme so `TemplateFetchResult.fromStoreTemplate` exposes it via `rawSchema['library']`.
|
|
104
|
-
|
|
105
|
-
## Editor behavior
|
|
106
|
-
|
|
107
|
-
- Tab **Theme** lists `controller.themeLibraryEntries` (`rawSchema['library']`).
|
|
108
|
-
- Drop / tap → **inline copy** into `templateData` (`buildThemeLibraryComponent`).
|
|
109
|
-
- Not a live link to the theme file: later theme updates do **not** rewrite existing placements (unlike DB `reference`).
|
|
110
|
-
- Prefer `shared/` + `$ref` for compile-time consistency across pages you ship in `data.json`; use **library** for optional blocks merchants may add.
|
|
111
|
-
|
|
112
|
-
## vs `shared/`
|
|
113
|
-
|
|
114
|
-
| | `shared/components` | `library/components` |
|
|
115
|
-
|---|---|---|
|
|
116
|
-
| Purpose | DRY placements already in the theme tree | Optional catalog for the editor |
|
|
117
|
-
| Build | Inlined into `data.json` via `$ref` | Emitted as `schema.library.json` |
|
|
118
|
-
| Unused OK? | No (only if referenced) | **Yes** |
|
|
119
|
-
|
|
120
|
-
A component can exist in **both** (shared for shipped pages + library for drag-drop of the same block elsewhere).
|
|
73
|
+
| `library/components/x/component.json` + `component.jsx` for a leaf | Flat `library/components/x.tsx` |
|
|
74
|
+
| Duplicating library JSX into every page | Keep library for drag-drop; use `shared/` + `$ref` for live chrome |
|
|
121
75
|
|
|
122
|
-
##
|
|
76
|
+
## Related
|
|
123
77
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
3. When packing a `StoreTemplate`, merge `library` into `schema`.
|
|
127
|
-
4. Flutter insert = copy-on-drop, not `type: "reference"` (no DB id).
|
|
78
|
+
- Shared chrome: [07-SHARED-COMPONENTS.md](./07-SHARED-COMPONENTS.md)
|
|
79
|
+
- Custom TSX: [03-CUSTOM-COMPONENTS.md](./03-CUSTOM-COMPONENTS.md)
|
|
@@ -1,38 +1,50 @@
|
|
|
1
|
-
# Template Pages —
|
|
1
|
+
# Template Pages — single `main` + slots
|
|
2
2
|
|
|
3
3
|
> Theme package copy — paths assume this theme folder is the project root.
|
|
4
4
|
|
|
5
|
-
Canonical routes and the **single-`main`-section** pattern.
|
|
5
|
+
Canonical routes and the **single-`main`-section** pattern (preferred for all new themes).
|
|
6
6
|
|
|
7
7
|
## Page matrix
|
|
8
8
|
|
|
9
|
-
| Page id | Path |
|
|
9
|
+
| Page id | Path | Authoring | Notes |
|
|
10
10
|
|---|---|---|---|
|
|
11
|
-
| `
|
|
12
|
-
| `
|
|
13
|
-
| `
|
|
14
|
-
| `
|
|
15
|
-
| `products` | `/products` |
|
|
16
|
-
| `
|
|
11
|
+
| `home` | `/` | **`main` preferred** | Flat disk: `pages/home/components/`. Legacy `header\|hero\|main\|footer` still renders when `main` is empty. |
|
|
12
|
+
| `product` | `/p/:id` **and** `/products/:id` | **`main` only** | Both URLs render the same PDP. Prefer `/p/` for links. |
|
|
13
|
+
| `checkout` | `/checkout` | **`main` only** | Prefer registry `cart_order_form` in a form slot. |
|
|
14
|
+
| `thank_you` | `/thanks` | **`main` only** | Query params carry order context. Legacy `/thank-you` redirects. |
|
|
15
|
+
| `products` | `/products` | **`main` preferred** | Legacy multi-section keys when `main` empty. |
|
|
16
|
+
| `contact` | `/contact` | **`main` preferred** | Legacy named sections when `main` empty. |
|
|
17
17
|
|
|
18
|
-
## Pattern:
|
|
18
|
+
## Pattern: published `main` + optional slots
|
|
19
|
+
|
|
20
|
+
**Preferred disk layout for marketing pages** — flat sibling stack (builds to `sections.main`):
|
|
19
21
|
|
|
20
22
|
```text
|
|
21
|
-
pages
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
pages/home/components/
|
|
24
|
+
header.json # $ref shared.header
|
|
25
|
+
hero.tsx
|
|
26
|
+
rail.tsx
|
|
27
|
+
footer.json # $ref shared.footer
|
|
25
28
|
```
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
**When you need a shell with slots** (typical for product / checkout / thanks):
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
pages/product/components/product-shell/
|
|
34
|
+
product-shell.tsx # export const meta + slotsSchema
|
|
35
|
+
slots/header/….json # $ref
|
|
36
|
+
slots/body/….tsx
|
|
37
|
+
slots/form/….json # cart_order_form / product_order_form
|
|
38
|
+
slots/footer/….json
|
|
39
|
+
```
|
|
28
40
|
|
|
29
|
-
|
|
41
|
+
Do **not** invent deep nested trees by hand when a flat sibling stack is enough.
|
|
30
42
|
|
|
31
43
|
### Product runtime fallback
|
|
32
44
|
|
|
33
45
|
`ProductPageContent` prefers `main`. If `main` is empty, it still renders the legacy multi-section tree (`header` / `top` / `start` / `end` / `bottom` / `footer`) for older store blobs.
|
|
34
46
|
|
|
35
|
-
|
|
47
|
+
Home / products / contact use the same prefer-`main` rule via `lib/template/prefer-main-section.ts`.
|
|
36
48
|
|
|
37
49
|
## `/checkout`
|
|
38
50
|
|
|
@@ -68,14 +80,17 @@ New themes (Dawn) ship `main` + slots only.
|
|
|
68
80
|
|
|
69
81
|
## Authoring checklist
|
|
70
82
|
|
|
71
|
-
1.
|
|
72
|
-
2.
|
|
73
|
-
3. `
|
|
74
|
-
4.
|
|
75
|
-
5. Do **not** reintroduce multi-section keys on
|
|
83
|
+
1. Prefer flat `pages/<page>/components/<name>.tsx` (or a short stack of siblings + `$ref`)
|
|
84
|
+
2. For product / checkout / thanks: one shell **folder** only if you need slots (`header` | `body`/`form` | `footer`); otherwise flat stack
|
|
85
|
+
3. Chrome reused on 2+ pages → `shared/components/<id>.tsx` + `$ref` placements
|
|
86
|
+
4. `npm run build` then preview with `npm run dev` / `npm run dev`
|
|
87
|
+
5. Do **not** reintroduce multi-section keys on new themes
|
|
88
|
+
6. Do **not** invent deep nested shell trees when flat siblings work
|
|
76
89
|
|
|
77
90
|
## Related
|
|
78
91
|
|
|
79
92
|
- Order / COD contract: [08-ORDER-FORM.md](./08-ORDER-FORM.md)
|
|
80
93
|
- Architecture pages list: [01-ARCHITECTURE.md](./01-ARCHITECTURE.md)
|
|
81
94
|
- Schema library (optional drag-drop blocks): [10-SCHEMA-LIBRARY.md](./10-SCHEMA-LIBRARY.md)
|
|
95
|
+
- Folder kit: [04-WORKFLOW.md](./04-WORKFLOW.md)
|
|
96
|
+
- Flat TSX: [03-CUSTOM-COMPONENTS.md](./03-CUSTOM-COMPONENTS.md)
|
|
@@ -9,28 +9,54 @@ exposes top-level `function App()` — the same contract as plain JSX.
|
|
|
9
9
|
## What you write
|
|
10
10
|
|
|
11
11
|
```
|
|
12
|
-
#
|
|
12
|
+
# Required default (page-level → sections.main)
|
|
13
13
|
pages/home/components/hero.tsx
|
|
14
14
|
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
component.tsx
|
|
18
|
-
labels.ts
|
|
15
|
+
# Shared leaf
|
|
16
|
+
shared/components/header.tsx
|
|
19
17
|
|
|
20
|
-
#
|
|
18
|
+
# Folder ONLY when you need slots/children or colocated helpers
|
|
19
|
+
pages/product/components/product-shell/
|
|
20
|
+
product-shell.tsx
|
|
21
|
+
slots/body/gallery.tsx
|
|
22
|
+
|
|
23
|
+
# Legacy multi-section (compat only — do not use for new themes)
|
|
21
24
|
pages/home/sections/main/components/hero.tsx
|
|
22
25
|
```
|
|
23
26
|
|
|
27
|
+
```tsx
|
|
28
|
+
const propsSchema = {
|
|
29
|
+
heading: { type: "string", name: "Heading" },
|
|
30
|
+
} as const;
|
|
31
|
+
|
|
32
|
+
export const meta = {
|
|
33
|
+
type: "custom",
|
|
34
|
+
title: "Hero",
|
|
35
|
+
order: 0,
|
|
36
|
+
propsSchema,
|
|
37
|
+
props: { heading: "" },
|
|
38
|
+
} as const satisfies FeeefComponentMeta<typeof propsSchema>;
|
|
39
|
+
|
|
40
|
+
type Props = FeeefLivePropsOf<typeof propsSchema>;
|
|
41
|
+
|
|
42
|
+
function App() {
|
|
43
|
+
const p = props as Props;
|
|
44
|
+
return <h1>{p.heading}</h1>;
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Local/`npm` imports are allowed in authoring files and are **bundled** into `code`:
|
|
49
|
+
|
|
24
50
|
```tsx
|
|
25
51
|
import clsx from "clsx";
|
|
26
52
|
import { bannerLabel } from "./labels";
|
|
27
53
|
|
|
28
|
-
function App()
|
|
29
|
-
|
|
30
|
-
return <div className={clsx("hero")}>{text}</div>;
|
|
54
|
+
function App() {
|
|
55
|
+
return <div className={clsx("hero")}>{bannerLabel("Feeef")}</div>;
|
|
31
56
|
}
|
|
32
57
|
```
|
|
33
58
|
|
|
59
|
+
Keep `export const meta` in the same entry file (or the kit cannot load propsSchema).
|
|
34
60
|
## What the storefront receives
|
|
35
61
|
|
|
36
62
|
Build emits bundled / transpiled JS with:
|
|
@@ -60,14 +86,12 @@ npm install clsx # example
|
|
|
60
86
|
|
|
61
87
|
## Plain JSX (legacy)
|
|
62
88
|
|
|
63
|
-
`component.jsx` with **no** imports is copied into `code` unchanged (fast path).
|
|
64
|
-
|
|
65
|
-
## Init
|
|
66
|
-
|
|
67
|
-
This package came from `feeef template init`. Re-read `AGENTS.md` after upgrading the CLI.
|
|
89
|
+
Older `component.jsx` with **no** imports is still copied into `code` unchanged (fast path). **New work must use flat `.tsx` + `export const meta`.**
|
|
68
90
|
|
|
69
91
|
## Do not
|
|
70
92
|
|
|
71
93
|
- Expect browser-side bundling of theme `node_modules` — only build-time inlining
|
|
72
94
|
- Bundle `react` into component `code`
|
|
73
95
|
- Rely on Node builtins or server-only packages inside components
|
|
96
|
+
- Author customs as `component.json` + `component.jsx` pairs
|
|
97
|
+
- Create both `name.tsx` and `name/` for the same component id
|