@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,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Rules when editing theme component source (tsx / json / slots).
|
|
3
|
+
globs: pages/**/*,shared/**/*,library/**/*
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Theme source folders
|
|
8
|
+
|
|
9
|
+
You are editing **theme source**, not a hand-maintained `dist/data.json`.
|
|
10
|
+
|
|
11
|
+
## Structure
|
|
12
|
+
|
|
13
|
+
- Prefer page-level: `pages/<page>/components/hero.tsx` — builds to published `sections.main`
|
|
14
|
+
- Legacy: `pages/<page>/sections/<id>/components/` still works (do not mix with flat `components/` on the same page)
|
|
15
|
+
- Leaf file: `export const meta` (+ `propsSchema`) + `function App() { … }`
|
|
16
|
+
- Folder layout (`hero/component.tsx` + `slots/` / `children/`) only when nesting or colocated helpers are needed
|
|
17
|
+
- Type props: `type Props = FeeefLivePropsOf<typeof propsSchema>` then `const p = props as Props`
|
|
18
|
+
- `satisfies FeeefComponentMeta<typeof propsSchema>` keeps `meta.props` aligned with the schema
|
|
19
|
+
- Prefer **slots** + `slotsLayout` for chrome instead of extra section keys (`header` / `footer`)
|
|
20
|
+
|
|
21
|
+
## Rules
|
|
22
|
+
|
|
23
|
+
1. Do not put JSX inside `.json` meta files.
|
|
24
|
+
2. Custom components: flat `<name>.tsx` with `export const meta` + `function App()` (legacy folder ok).
|
|
25
|
+
3. Set `"order"` so sibling order is deterministic.
|
|
26
|
+
4. Slot folder names must match `slotsSchema` keys.
|
|
27
|
+
5. After edits: `npm run build` (or rely on `npm run dev` watch).
|
|
28
|
+
6. Read `docs/03-CUSTOM-COMPONENTS.md` before writing JSX.
|
|
29
|
+
7. Read `docs/05-ANTI-PATTERNS.md` before inventing patterns.
|
|
30
|
+
8. If UI exists on another page, use `shared/components/<id>.tsx` — do not duplicate.
|
|
31
|
+
9. Do not mix `pages/<page>/components/` and `pages/<page>/sections/` on the same page.
|
|
32
|
+
10. Prefer `feeef template add page|component` / `remove` over hand-creating trees (keeps manifest + starter meta in sync).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: feeef-filterator
|
|
3
|
+
description: >-
|
|
4
|
+
Feeef filterator + products/categories list APIs for PLPs, related products,
|
|
5
|
+
and search grids in theme custom components. Canonical: docs/14-FILTERATOR.md.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Feeef Filterator
|
|
9
|
+
|
|
10
|
+
Read **`docs/14-FILTERATOR.md`** before changing product/category fetch logic.
|
|
11
|
+
|
|
12
|
+
- Always pass `store_id`
|
|
13
|
+
- Prefer server `in_stock` / `price_min` / `filterator` over client-only filtering
|
|
14
|
+
- Related products = same category / random / sold — no dedicated related API
|
|
15
|
+
- `media` values are URL strings; link to `/products/…`
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: feeef-theme
|
|
3
|
+
description: >-
|
|
4
|
+
Author Feeef theme packages (pages/shared/library, custom react-live components,
|
|
5
|
+
TemplateData build, order forms, i18n, filterator, dark/light). Use when editing
|
|
6
|
+
this theme's component.json, component.jsx/tsx, locales, or publishing with feeef.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Feeef Theme Skill
|
|
10
|
+
|
|
11
|
+
## First action
|
|
12
|
+
|
|
13
|
+
1. `AGENTS.md`
|
|
14
|
+
2. `docs/00-INDEX.md`
|
|
15
|
+
3. Task-specific doc from the cheat-sheet
|
|
16
|
+
4. Skim `docs/05-ANTI-PATTERNS.md` before writing JSON/JSX
|
|
17
|
+
|
|
18
|
+
## Workflows
|
|
19
|
+
|
|
20
|
+
### Edit a component
|
|
21
|
+
|
|
22
|
+
1. Open the folder under `pages/…/components/` or `shared/components/`
|
|
23
|
+
2. Edit `component.json` + `component.jsx` / `.tsx`
|
|
24
|
+
3. `npm run build` && hard-refresh `npm run dev`
|
|
25
|
+
|
|
26
|
+
### Shared chrome
|
|
27
|
+
|
|
28
|
+
1. Canonical folder: `shared/components/<id>/`
|
|
29
|
+
2. Placements: `{ "$ref": "shared.<id>", "instanceId": "…", "props": { } }`
|
|
30
|
+
3. See `docs/07-SHARED-COMPONENTS.md`
|
|
31
|
+
|
|
32
|
+
### Order / COD
|
|
33
|
+
|
|
34
|
+
1. Read `docs/08-ORDER-FORM.md` first
|
|
35
|
+
2. `POST /api/orders/create` only; draft + pending; geo rules; anti-abuse
|
|
36
|
+
|
|
37
|
+
### Special pages
|
|
38
|
+
|
|
39
|
+
`docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md` — single `main` + slots.
|
|
40
|
+
|
|
41
|
+
### Lists / PLP
|
|
42
|
+
|
|
43
|
+
`docs/14-FILTERATOR.md` + skill `feeef-filterator`.
|
|
44
|
+
|
|
45
|
+
### TS / imports
|
|
46
|
+
|
|
47
|
+
`docs/16-AUTHORING-TS-IMPORTS.md` — build bundles into react-live `code`.
|
|
48
|
+
|
|
49
|
+
## Invariants
|
|
50
|
+
|
|
51
|
+
- Top-level custom fields — never under `props`
|
|
52
|
+
- `function App()` in published `code`
|
|
53
|
+
- CSS vars for brand colors
|
|
54
|
+
- Stable `instanceId`
|
|
55
|
+
- Repeated UI → `shared/` + `$ref`
|
|
56
|
+
- Orders → create API + draft/pending contract
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Feeef Theme — Quick Reference
|
|
2
|
+
|
|
3
|
+
## Commands (theme root)
|
|
4
|
+
|
|
5
|
+
| npm script | Effect |
|
|
6
|
+
|---|---|
|
|
7
|
+
| `build` | source → `dist/data.json` |
|
|
8
|
+
| `check` | validate |
|
|
9
|
+
| `dev` | preview |
|
|
10
|
+
| `publish` | upload (+ optional `--apply`) |
|
|
11
|
+
|
|
12
|
+
## Custom component JSON
|
|
13
|
+
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"order": 0,
|
|
17
|
+
"type": "custom",
|
|
18
|
+
"instanceId": "custom_example",
|
|
19
|
+
"title": "Example",
|
|
20
|
+
"propsSchema": {
|
|
21
|
+
"heading": { "type": "string" }
|
|
22
|
+
},
|
|
23
|
+
"props": { "heading": "Hello" },
|
|
24
|
+
"slotsSchema": {},
|
|
25
|
+
"slots": {}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## JSX skeleton
|
|
30
|
+
|
|
31
|
+
```jsx
|
|
32
|
+
function App() {
|
|
33
|
+
const storeCtx = useStore();
|
|
34
|
+
const store = storeCtx?.store;
|
|
35
|
+
return (
|
|
36
|
+
<section style={{ color: "hsl(var(--foreground))" }}>
|
|
37
|
+
<h1>{props.heading}</h1>
|
|
38
|
+
{props.slots?.body}
|
|
39
|
+
</section>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Shared placement
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"order": 0,
|
|
49
|
+
"$ref": "shared.footer",
|
|
50
|
+
"instanceId": "contact_footer_1",
|
|
51
|
+
"props": {}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Order form (quick)
|
|
56
|
+
|
|
57
|
+
- `POST /api/orders/create` only
|
|
58
|
+
- Draft when phone digits === country length; pending reuses draft `id`
|
|
59
|
+
- See `docs/08-ORDER-FORM.md`
|
|
60
|
+
|
|
61
|
+
## Pages
|
|
62
|
+
|
|
63
|
+
| Page | Path | Rule |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| product | `/products/:id` | `main` only — layout in slots |
|
|
66
|
+
| checkout | `/checkout` | `main` only |
|
|
67
|
+
| thank_you | `/thanks` | `main` only |
|
|
68
|
+
|
|
69
|
+
## Colors / i18n / lists
|
|
70
|
+
|
|
71
|
+
- Colors: `hsl(var(--primary))` — `docs/12-DARK-LIGHT-THEME.md`
|
|
72
|
+
- Copy: `t('key')` + `locales/*.json` — `docs/13-TEMPLATE-I18N.md`
|
|
73
|
+
- Products: filterator / list params — `docs/14-FILTERATOR.md`
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"typescript.tsdk": "node_modules/typescript/lib",
|
|
3
|
+
"typescript.enablePromptUseWorkspaceTsdk": true,
|
|
4
|
+
"typescript.tsserver.maxTsServerMemory": 3072,
|
|
5
|
+
"files.associations": {
|
|
6
|
+
"**/components/**/*.tsx": "typescriptreact",
|
|
7
|
+
"**/components/**/*.jsx": "javascriptreact",
|
|
8
|
+
"**/component.tsx": "typescriptreact",
|
|
9
|
+
"**/component.jsx": "javascriptreact"
|
|
10
|
+
},
|
|
11
|
+
"editor.defaultFormatter": null,
|
|
12
|
+
"js/ts.implicitProjectConfig.checkJs": false
|
|
13
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# AGENTS — Feeef Theme (READ BEFORE EDITING)
|
|
2
|
+
|
|
3
|
+
You are editing a **Feeef theme package** (this folder). Mistakes break the merchant
|
|
4
|
+
editor, the storefront preview, and published stores. Follow this file exactly.
|
|
5
|
+
|
|
6
|
+
## Mandatory mental model
|
|
7
|
+
|
|
8
|
+
1. **One JSON contract** — `TemplateData` (built into `dist/data.json`) is what Feeef stores and renders. `dist/schema.json` is the editor schema.
|
|
9
|
+
2. **Source vs dist** — edit `schema.ts`, `pages/`, `shared/`, `library/`, `locales/`, `props.json`; run `npm run build`. Do not hand-edit large `dist/*` as the source of truth.
|
|
10
|
+
3. **Theme schema is yours** — `schema.ts` (`satisfies FeeefThemeSchema`) controls pages/layouts/root `propsSchema`. Build merges Lithium built-ins into `dist/schema.json` for publish.
|
|
11
|
+
4. **`type: "custom"` is react-live** — published `code` is a **string** evaluated in a sandbox. It must expose top-level `function App() { … }`. Author with a flat file like `hero.tsx`: `export const meta` (include `propsSchema`) + `App`. Type props via `FeeefLivePropsOf<typeof propsSchema>`. Local/`npm` imports are **bundled at build time** (see `docs/16-AUTHORING-TS-IMPORTS.md`). Use a folder (`hero/component.tsx`) only when you need `slots/` / `children/` or colocated modules.
|
|
12
|
+
5. **`code` / `propsSchema` / `slotsSchema` / `slots` / `slotsLayout` are TOP-LEVEL** on the component object — never nest them under `props`.
|
|
13
|
+
6. **Planes stay separate** — schema (editable fields) ≠ merchant content (`props`) ≠ renderer.
|
|
14
|
+
|
|
15
|
+
## Before you change anything
|
|
16
|
+
|
|
17
|
+
1. Read [`docs/00-INDEX.md`](./docs/00-INDEX.md) and the doc for your task.
|
|
18
|
+
2. Custom JSX/TSX → [`docs/03-CUSTOM-COMPONENTS.md`](./docs/03-CUSTOM-COMPONENTS.md) + skim [`docs/05-ANTI-PATTERNS.md`](./docs/05-ANTI-PATTERNS.md).
|
|
19
|
+
3. Order / COD / checkout forms → [`docs/08-ORDER-FORM.md`](./docs/08-ORDER-FORM.md) **first**.
|
|
20
|
+
4. Folder layout / CLI → [`docs/04-WORKFLOW.md`](./docs/04-WORKFLOW.md).
|
|
21
|
+
5. Shared chrome → [`docs/07-SHARED-COMPONENTS.md`](./docs/07-SHARED-COMPONENTS.md).
|
|
22
|
+
6. Checkout / thanks / product pages → [`docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md`](./docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md).
|
|
23
|
+
7. Dark/light → [`docs/12-DARK-LIGHT-THEME.md`](./docs/12-DARK-LIGHT-THEME.md).
|
|
24
|
+
8. Multilang → [`docs/13-TEMPLATE-I18N.md`](./docs/13-TEMPLATE-I18N.md).
|
|
25
|
+
9. Product grids / filters → [`docs/14-FILTERATOR.md`](./docs/14-FILTERATOR.md).
|
|
26
|
+
10. After edits: `npm run build` (or `npm run check`), then hard-refresh `npm run dev`.
|
|
27
|
+
|
|
28
|
+
## Hard rules (never violate)
|
|
29
|
+
|
|
30
|
+
| Rule | Why |
|
|
31
|
+
|---|---|
|
|
32
|
+
| Do not put `code` / `propsSchema` / `slots*` inside `props` | Breaks editor + renderer |
|
|
33
|
+
| Prefer `React.useState` (not bare `useState`) in custom code | Merchant editor scope |
|
|
34
|
+
| Prefer `hsl(var(--primary))` over decoration color ints | Dark/light CSS tokens |
|
|
35
|
+
| Use `Link` / `RouterNav` / `useRouter()` for in-app nav | Slot-context routers are stubs |
|
|
36
|
+
| Keep `instanceId` stable when editing existing components | Selection + React keys |
|
|
37
|
+
| `children` only for `grid` / `flex` / `container` | Other types use `slots` |
|
|
38
|
+
| Empty section **keys** optional; published JSON still has `sections` object | Flat disk → `sections.main`; legacy multi-section keys still work |
|
|
39
|
+
| UI on 2+ pages → `shared/components/` + `$ref` | No duplicated chrome JSX |
|
|
40
|
+
| Custom order forms → `docs/08-ORDER-FORM.md` | Draft, geo, create API, anti-abuse |
|
|
41
|
+
| Never re-bootstrap shipping on every `cartCtx` change | Wipes state/city |
|
|
42
|
+
| Add to cart = `addCurrentItemToCart` (or `cart.add`) | Not `updateCurrentItem({})` theater |
|
|
43
|
+
| Submit orders via `POST /api/orders/create` | Not browser `ff.orders.send` |
|
|
44
|
+
| Do not invent unknown registry `type` strings | Prefer `custom` or built-ins |
|
|
45
|
+
| Do not bypass order anti-abuse checks | Honeypot, dwell, in-flight lock |
|
|
46
|
+
|
|
47
|
+
## Theme layout
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
schema.ts # theme-owned schema overlay
|
|
51
|
+
props.json # default root props
|
|
52
|
+
pages/<page>/components/ # preferred — builds to sections.main
|
|
53
|
+
<name>.tsx
|
|
54
|
+
pages/<page>/sections/<id>/… # legacy multi-section (compat)
|
|
55
|
+
shared/components/<id>.tsx
|
|
56
|
+
library/components/<id>.tsx
|
|
57
|
+
locales/{en,ar,…}.json
|
|
58
|
+
feeef.template.json
|
|
59
|
+
dist/data.json # TemplateData
|
|
60
|
+
dist/schema.json # merged editor schema (not hand-edited)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Prefer a single `main` stack + component **slots** for chrome. Do not mix flat `components/` and `sections/` on one page.
|
|
64
|
+
|
|
65
|
+
## Local commands
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
feeef signin
|
|
69
|
+
feeef use # bind a store
|
|
70
|
+
npm install # once — React/TS types for the editor
|
|
71
|
+
|
|
72
|
+
# Scaffold (prefer these over hand-creating folders)
|
|
73
|
+
feeef template add page <pageId> # pages/<id>/components/
|
|
74
|
+
feeef template add component <pageId> <name> # starter <name>.tsx
|
|
75
|
+
feeef template remove page <pageId> --yes
|
|
76
|
+
feeef template remove component <pageId> <name> --yes
|
|
77
|
+
|
|
78
|
+
npm run build # → dist/data.json
|
|
79
|
+
npm run check
|
|
80
|
+
npm run typecheck # optional IDE/tsc
|
|
81
|
+
npm run dev # preview
|
|
82
|
+
npm run publish -- --apply
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**AI / agents:** use `feeef template add page|component` (and `remove`) instead of inventing folder trees by hand. New pages are flat `components/` → published `sections.main`. Do not mix flat `components/` with `sections/` on the same page.
|
|
86
|
+
|
|
87
|
+
Editor: `tsconfig.json` + `types/feeef-live-scope.d.ts` + `types/feeef-template-schema.d.ts` explain react-live globals and `FeeefThemeSchema` to VS Code / Cursor.
|
|
88
|
+
|
|
89
|
+
## Companion docs
|
|
90
|
+
|
|
91
|
+
| Doc | When |
|
|
92
|
+
|---|---|
|
|
93
|
+
| [`docs/03-CUSTOM-COMPONENTS.md`](./docs/03-CUSTOM-COMPONENTS.md) | JSX sandbox + scope |
|
|
94
|
+
| [`docs/04-WORKFLOW.md`](./docs/04-WORKFLOW.md) | Build / preview / publish |
|
|
95
|
+
| [`docs/05-ANTI-PATTERNS.md`](./docs/05-ANTI-PATTERNS.md) | Common AI mistakes |
|
|
96
|
+
| [`docs/07-SHARED-COMPONENTS.md`](./docs/07-SHARED-COMPONENTS.md) | `$ref` / shared |
|
|
97
|
+
| [`docs/08-ORDER-FORM.md`](./docs/08-ORDER-FORM.md) | COD / checkout contract |
|
|
98
|
+
| [`docs/09-THEME-PORTING.md`](./docs/09-THEME-PORTING.md) | Full-theme craft lessons |
|
|
99
|
+
| [`docs/10-SCHEMA-LIBRARY.md`](./docs/10-SCHEMA-LIBRARY.md) | Theme library catalog |
|
|
100
|
+
| [`docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md`](./docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md) | Special pages |
|
|
101
|
+
| [`docs/12-DARK-LIGHT-THEME.md`](./docs/12-DARK-LIGHT-THEME.md) | Theme mode + tokens |
|
|
102
|
+
| [`docs/13-TEMPLATE-I18N.md`](./docs/13-TEMPLATE-I18N.md) | `locales` + `t()` |
|
|
103
|
+
| [`docs/14-FILTERATOR.md`](./docs/14-FILTERATOR.md) | Product/category lists |
|
|
104
|
+
| [`docs/16-AUTHORING-TS-IMPORTS.md`](./docs/16-AUTHORING-TS-IMPORTS.md) | TSX + npm imports |
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Feeef theme
|
|
2
|
+
|
|
3
|
+
This folder is a **Node.js package** (see `package.json`). Scripts wrap the global `feeef` CLI — install it once (`npm link` from the Feeef `cli/` package, or `npm install -g @feeef.dev/cli`).
|
|
4
|
+
|
|
5
|
+
**AI / Cursor:** read [`AGENTS.md`](./AGENTS.md) and [`docs/00-INDEX.md`](./docs/00-INDEX.md) first. Rules and skills live under [`.cursor/`](./.cursor/).
|
|
6
|
+
|
|
7
|
+
Author components under `pages/<page>/components/<name>.tsx` (`export const meta` + `function App()`). Build maps them to published `sections.main`. Legacy `sections/<id>/` still works. Local `import`s are bundled at `npm run build` into react-live `code` (`react` stays provided by the storefront).
|
|
8
|
+
|
|
9
|
+
Editor: `tsconfig.json` + `types/feeef-live-scope.d.ts` teach VS Code / Cursor about live-scope globals (`props`, `t`, `useStore`, …). Run `npm install` once after init.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
feeef signin
|
|
13
|
+
feeef use # or: feeef use <store-id-or-slug>
|
|
14
|
+
|
|
15
|
+
npm run build # → dist/data.json
|
|
16
|
+
npm run check
|
|
17
|
+
npm run dev # → http://{slug}.localhost.feeef.org:3456
|
|
18
|
+
npm run publish -- --apply
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
See `feeef template --help`.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Theme docs — index
|
|
2
|
+
|
|
3
|
+
Read [`../AGENTS.md`](../AGENTS.md) first. Jump by task below.
|
|
4
|
+
|
|
5
|
+
| # | Doc | Contents |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| 00 | This file | Navigation |
|
|
8
|
+
| 03 | [CUSTOM-COMPONENTS](./03-CUSTOM-COMPONENTS.md) | react-live, scope API, slots |
|
|
9
|
+
| 04 | [WORKFLOW](./04-WORKFLOW.md) | Build, preview, publish from this package |
|
|
10
|
+
| 05 | [ANTI-PATTERNS](./05-ANTI-PATTERNS.md) | What not to do (high signal) |
|
|
11
|
+
| 07 | [SHARED-COMPONENTS](./07-SHARED-COMPONENTS.md) | `shared/` + `$ref` |
|
|
12
|
+
| 08 | [ORDER-FORM](./08-ORDER-FORM.md) | COD / checkout contract |
|
|
13
|
+
| 09 | [THEME-PORTING](./09-THEME-PORTING.md) | Craft / cart / search / PLP lessons |
|
|
14
|
+
| 10 | [SCHEMA-LIBRARY](./10-SCHEMA-LIBRARY.md) | Drag-drop theme library |
|
|
15
|
+
| 11 | [PAGES](./11-PAGES-CHECKOUT-THANKS-PRODUCT.md) | checkout / thanks / product |
|
|
16
|
+
| 12 | [DARK-LIGHT](./12-DARK-LIGHT-THEME.md) | Dark / light / system |
|
|
17
|
+
| 13 | [I18N](./13-TEMPLATE-I18N.md) | `locales/*.json` + `t()` |
|
|
18
|
+
| 14 | [FILTERATOR](./14-FILTERATOR.md) | Product / category lists |
|
|
19
|
+
| 16 | [TS-IMPORTS](./16-AUTHORING-TS-IMPORTS.md) | TypeScript + npm imports |
|
|
20
|
+
|
|
21
|
+
## Task cheat-sheet
|
|
22
|
+
|
|
23
|
+
| Task | Read |
|
|
24
|
+
|---|---|
|
|
25
|
+
| Edit custom JSX/TSX | 03, 05, 16 |
|
|
26
|
+
| Shared header/footer | **07** |
|
|
27
|
+
| Order / COD form | **08** |
|
|
28
|
+
| Checkout / thanks / PDP | **11** |
|
|
29
|
+
| Dark / light | **12** |
|
|
30
|
+
| Translations | **13** |
|
|
31
|
+
| Product grids / filters | **14** |
|
|
32
|
+
| Port / polish a full theme | **09** |
|
|
33
|
+
| Build / preview / publish | **04** |
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Custom Components (react-live)
|
|
2
|
+
|
|
3
|
+
> Theme package copy — paths assume this theme folder is the project root.
|
|
4
|
+
|
|
5
|
+
Full API: `docs/03-CUSTOM-COMPONENTS.md`.
|
|
6
|
+
Architecture: `docs/03-CUSTOM-COMPONENTS.md`.
|
|
7
|
+
|
|
8
|
+
## What a custom component is
|
|
9
|
+
|
|
10
|
+
A `TemplateDataComponent` with:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"type": "custom",
|
|
15
|
+
"instanceId": "…",
|
|
16
|
+
"title": "…",
|
|
17
|
+
"code": "function App() { … }",
|
|
18
|
+
"propsSchema": { … },
|
|
19
|
+
"props": { … },
|
|
20
|
+
"slotsSchema": { … },
|
|
21
|
+
"slots": { … },
|
|
22
|
+
"slotsLayout": { … }
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`code` is executed by `CustomLive` (`components/system/custom-live.tsx`) via **react-live**. Authoring may use `component.tsx` and local/npm `import`s — the **theme build** (esbuild) emits a single `code` string. There is still **no browser bundler** at runtime: `react` / `react-dom` stay in the live scope (do not import them expecting a separate React copy).
|
|
27
|
+
|
|
28
|
+
## Required code shape
|
|
29
|
+
|
|
30
|
+
```jsx
|
|
31
|
+
function App() {
|
|
32
|
+
const storeCtx = useStore();
|
|
33
|
+
// …
|
|
34
|
+
return <div>…</div>;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- Entry must be **`function App()`** (warning if missing; may not render).
|
|
39
|
+
- Prefer **`React.useState` / `React.useEffect` / …** — merchant preview may not inject bare hooks.
|
|
40
|
+
- No `import` / `export` / `require`.
|
|
41
|
+
|
|
42
|
+
## Injected scope (no imports needed)
|
|
43
|
+
|
|
44
|
+
| Symbol | Use |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `React` | Hooks, Fragment |
|
|
47
|
+
| `props` | Instance props |
|
|
48
|
+
| `props.slots` | Pre-rendered slot children (`props.slots?.sections`) |
|
|
49
|
+
| `SlotContextBridge` | Provide context to slot children |
|
|
50
|
+
| `useSlotContext(key)` | Read parent slot context |
|
|
51
|
+
| `useStore()` | `{ store }` or null — **null-check** |
|
|
52
|
+
| `useFeeefCart()` | `{ cart, count, store }` or null |
|
|
53
|
+
| `useCurrentProduct()` | `{ product }` — product pages |
|
|
54
|
+
| `useFeeef` | SDK instance or null |
|
|
55
|
+
| `useTheme()` | next-themes |
|
|
56
|
+
| `useTemplate()` | read-only template state |
|
|
57
|
+
| `t(key, params?)` | Theme locales (`data.i18n`) — see [13-TEMPLATE-I18N.md](./13-TEMPLATE-I18N.md) |
|
|
58
|
+
| `useFeeefT()` / `useFeeefLocale()` | Theme i18n hooks |
|
|
59
|
+
| `useRouter` / `usePathname` / `useSearchParams` | next/navigation |
|
|
60
|
+
| `Link` | next/link — prefer over `<a>` |
|
|
61
|
+
| `RouterNav` | clickable block with stopPropagation for nested cards |
|
|
62
|
+
| `SlotsLayout` | Renders `props.slotsLayout` (sm/md/lg row/column trees) with `props.slots` — prefer over hardcoding slot order |
|
|
63
|
+
| `dartColorToCssColor` | convert Flutter color ints from **props** |
|
|
64
|
+
|
|
65
|
+
For product markdown details use registry **`product_body`** (reads `product.body`), not CustomLive HTML injection.
|
|
66
|
+
|
|
67
|
+
## Styling rules
|
|
68
|
+
|
|
69
|
+
- Brand colors: `hsl(var(--primary))`, `hsl(var(--primary-foreground))`, `hsl(var(--background))`, …
|
|
70
|
+
- Corners: `var(--corners-card)`, `var(--corners-buttons-large)`, …
|
|
71
|
+
- **Do not** assign `store.decoration.primary` directly (Flutter AARRGGBB int).
|
|
72
|
+
- Prefer store fields for chrome: `store.logoUrl`, `store.name`, `store.contacts`, …
|
|
73
|
+
- **Dark / light:** ride native tokens (`:root` / `.dark`). Do not invent a parallel palette. Full contract: [12-DARK-LIGHT-THEME.md](./12-DARK-LIGHT-THEME.md).
|
|
74
|
+
- Toggle: `const { resolvedTheme, setTheme } = useTheme();`
|
|
75
|
+
|
|
76
|
+
## Slots in JSX
|
|
77
|
+
|
|
78
|
+
Parent:
|
|
79
|
+
|
|
80
|
+
```jsx
|
|
81
|
+
<SlotContextBridge value={{ shell: { isOpen, setIsOpen } }}>
|
|
82
|
+
{props.slots?.sections}
|
|
83
|
+
</SlotContextBridge>
|
|
84
|
+
{props.slots?.footer}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Child (in slot):
|
|
88
|
+
|
|
89
|
+
```jsx
|
|
90
|
+
const shell = useSlotContext("shell");
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Never** use slot context for navigation (`routerNav` stubs). Use `Link` / `RouterNav` / `useRouter()`.
|
|
94
|
+
|
|
95
|
+
## Product media
|
|
96
|
+
|
|
97
|
+
- `product.photoUrl` — cover image string.
|
|
98
|
+
- `product.media` — **`string[]` of URLs**, not `{ url }[]`.
|
|
99
|
+
|
|
100
|
+
## Cart
|
|
101
|
+
|
|
102
|
+
```jsx
|
|
103
|
+
const cartCtx = useFeeefCart();
|
|
104
|
+
if (!cartCtx) return null;
|
|
105
|
+
cartCtx.cart.add({ product, quantity: 1, variantPath: "Color/Red" });
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Kit authoring
|
|
109
|
+
|
|
110
|
+
In `…/my-comp/`:
|
|
111
|
+
|
|
112
|
+
- `component.json` — meta (no `code` string when using jsx file)
|
|
113
|
+
- `component.jsx` — the `function App()` source → compiled into `code`
|
|
114
|
+
- `slots/<slotId>/<child>/` — nested components
|
|
115
|
+
|
|
116
|
+
See [04-WORKFLOW.md](./04-WORKFLOW.md).
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Theme workflow (this package)
|
|
2
|
+
|
|
3
|
+
This folder is a **Node.js theme package**. Scripts wrap the Feeef CLI (`feeef`).
|
|
4
|
+
|
|
5
|
+
## Setup (once)
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install Feeef CLI globally (or npm link from the Feeef cli package)
|
|
9
|
+
feeef signin
|
|
10
|
+
feeef use # pick one of your stores
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Everyday loop
|
|
14
|
+
|
|
15
|
+
1. Add pages/components with the CLI (or edit under `pages/`, `shared/`, `library/`, `locales/`).
|
|
16
|
+
2. `npm run build` → writes `dist/data.json` (+ locales).
|
|
17
|
+
3. `npm run dev` → pushes a **draft** preview to your store and opens `https://{slug}.…/?preview=…` (live theme unchanged).
|
|
18
|
+
4. Ship: `npm run publish -- --apply` (or `feeef template publish --apply`).
|
|
19
|
+
|
|
20
|
+
| Script / command | Effect |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `feeef template add page <id>` | Create `pages/<id>/` + update `feeef.template.json` |
|
|
23
|
+
| `feeef template add component <page> <name>` | Starter `<name>.tsx` (meta + App) |
|
|
24
|
+
| `feeef template remove page <id>` | Delete page folder + manifest entry |
|
|
25
|
+
| `feeef template remove component <page> <name>` | Delete component file/folder |
|
|
26
|
+
| `npm run build` | Compile source → `dist/` |
|
|
27
|
+
| `npm run check` | Validate without relying on a dirty dist |
|
|
28
|
+
| `npm run dev` | Watch/build + remote draft preview (never overwrites live) |
|
|
29
|
+
| `npm run publish` | Upload template + locales (+ optional install) |
|
|
30
|
+
|
|
31
|
+
Exit draft preview in the browser via the banner (**Exit preview**) or `/?preview=0`.
|
|
32
|
+
|
|
33
|
+
### Scaffold examples
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
feeef template add page products
|
|
37
|
+
feeef template add component products grid --title "Product grid"
|
|
38
|
+
feeef template remove component products grid --yes
|
|
39
|
+
feeef template remove page products --yes
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Legacy themes that already use `sections/`: `add component` writes under `sections/main/components/` (or pass `--section header`).
|
|
43
|
+
|
|
44
|
+
## Source layout
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
feeef.template.json
|
|
48
|
+
schema.ts # theme-owned schema overlay (typed)
|
|
49
|
+
props.json # default root props (data)
|
|
50
|
+
pages/<page>/page.json
|
|
51
|
+
pages/<page>/components/ # preferred (→ published sections.main)
|
|
52
|
+
<name>.tsx # leaf: export const meta + App
|
|
53
|
+
<name>.json # leaf built-in / no code
|
|
54
|
+
<name>/ # only when slots/ or children/ needed
|
|
55
|
+
component.tsx
|
|
56
|
+
slots/… | children/…
|
|
57
|
+
pages/<page>/sections/<section>/components/ # legacy multi-section (still supported)
|
|
58
|
+
shared/components/<id>.tsx
|
|
59
|
+
library/components/<id>.tsx
|
|
60
|
+
locales/en.json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Do **not** mix `pages/<page>/components/` and `pages/<page>/sections/` on the same page.
|
|
64
|
+
|
|
65
|
+
### Theme schema (`schema.ts`)
|
|
66
|
+
|
|
67
|
+
Controls what the merchant editor sees for **this** theme (pages, layouts, root `propsSchema`). Build merges it with Lithium built-ins → `dist/schema.json` (publish uploads that as `StoreTemplate.schema`).
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
export const schema = {
|
|
71
|
+
name: "my-theme",
|
|
72
|
+
version: "0.1.0",
|
|
73
|
+
schema: "1.0",
|
|
74
|
+
propsSchema: { theme: { type: "object", /* … */ } },
|
|
75
|
+
pages: {
|
|
76
|
+
home: {
|
|
77
|
+
name: "Home",
|
|
78
|
+
path: "/",
|
|
79
|
+
sections: { main: {} },
|
|
80
|
+
layout: { sm: [{ type: "column", children: ["main"] }] },
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
} as const satisfies FeeefThemeSchema;
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Types: `types/feeef-template-schema.d.ts`. Fallback: `schema.json` (same shape).
|
|
87
|
+
|
|
88
|
+
## Custom components
|
|
89
|
+
locales/en.json
|
|
90
|
+
feeef.template.json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Do **not** mix `pages/<page>/components/` and `pages/<page>/sections/` on the same page.
|
|
94
|
+
|
|
95
|
+
## Custom components
|
|
96
|
+
|
|
97
|
+
- Prefer page-level `components/hero.tsx` — `export const meta` + `function App() { … }`
|
|
98
|
+
- Use a folder only when you need `slots/` or `children/` (or colocated helpers)
|
|
99
|
+
- Chrome / layout: use **slots** + `slotsLayout` on a shell component (not extra section keys)
|
|
100
|
+
- Type-safe props from schema:
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
const propsSchema = { heading: { type: "string" } } as const;
|
|
104
|
+
|
|
105
|
+
export const meta = {
|
|
106
|
+
type: "custom",
|
|
107
|
+
title: "Hero",
|
|
108
|
+
order: 0,
|
|
109
|
+
propsSchema,
|
|
110
|
+
props: { heading: "" },
|
|
111
|
+
} as const satisfies FeeefComponentMeta<typeof propsSchema>;
|
|
112
|
+
|
|
113
|
+
type Props = FeeefLivePropsOf<typeof propsSchema>;
|
|
114
|
+
|
|
115
|
+
function App() {
|
|
116
|
+
const p = props as Props; // p.heading: string
|
|
117
|
+
return <h1>{p.heading}</h1>;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- Build strips `meta` and bundles into react-live `code` (see [16-AUTHORING-TS-IMPORTS.md](./16-AUTHORING-TS-IMPORTS.md))
|
|
122
|
+
- `react` stays provided by the storefront — do not bundle a second React
|
|
123
|
+
|
|
124
|
+
## Do not
|
|
125
|
+
|
|
126
|
+
- Commit hand-tweaked `dist/data.json` as the only source of truth
|
|
127
|
+
- Put `code` / schemas under `props`
|
|
128
|
+
- Call `ff.orders.send` from custom checkout (use `POST /api/orders/create` — [08](./08-ORDER-FORM.md))
|
|
129
|
+
- Set production env overrides meant for local preview only
|