pesanle-theme 0.1.0 → 0.1.1
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 +46 -6
- package/dist/cli.js +22 -4
- package/package.json +2 -10
package/README.md
CHANGED
|
@@ -20,9 +20,9 @@ Liquid-shaped language and **compiled** to a JavaScript render function:
|
|
|
20
20
|
there is no interpreter at request time, and an unknown filter, a typo'd drop
|
|
21
21
|
property or a missing snippet fails the push, not a shopper's page.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
The same theme can be browsed and edited in the dashboard — **Online store →
|
|
24
|
+
Themes → Code theme** — with a file tree, an editor and a live preview of the
|
|
25
|
+
draft. The CLI and the dashboard write the same draft.
|
|
26
26
|
|
|
27
27
|
## Commands
|
|
28
28
|
|
|
@@ -59,14 +59,54 @@ my-theme/
|
|
|
59
59
|
templates/index.tpl home
|
|
60
60
|
templates/product.tpl a product page
|
|
61
61
|
templates/catalog.tpl the catalogue
|
|
62
|
+
templates/page.tpl a seller's custom page
|
|
63
|
+
templates/pages/about.tpl a page of the theme's own, at /about
|
|
62
64
|
snippets/product-card.tpl a partial
|
|
65
|
+
sections/featured.tpl an editor-visible section with a schema
|
|
63
66
|
assets/theme.css scoped under .theme
|
|
64
67
|
```
|
|
65
68
|
|
|
66
69
|
A route the theme does not define is drawn by the platform's default theme,
|
|
67
|
-
so a project can start with one page and grow.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
so a project can start with one page and grow. Pages are addressed by file
|
|
71
|
+
name: `templates/pages/about.tpl` answers `/about`. A seller's page built in
|
|
72
|
+
the dashboard answers `/<slug>` (and `/pages/<slug>`) and is drawn by
|
|
73
|
+
`templates/page.tpl` with its sections in the `pageBody` slot. Interactive
|
|
74
|
+
pieces — the buy box, reviews, the cart drawer, the order-tracking form —
|
|
75
|
+
arrive as host slots; a theme never ships its own JavaScript.
|
|
76
|
+
|
|
77
|
+
## The language in one screen
|
|
78
|
+
|
|
79
|
+
Output and text:
|
|
80
|
+
|
|
81
|
+
```liquid
|
|
82
|
+
<h1>{{ product.title }}</h1>
|
|
83
|
+
<p>{{ product.price | money }}</p>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Tags: `{% if %} / {% elsif %} / {% else %}` (with `and`, `or`, `==`, `!=`,
|
|
87
|
+
`<`, `>`, `contains`), `{% unless %}`, `{% for x in list %}…{% else %}…{% endfor %}`,
|
|
88
|
+
`{% render 'snippet', key: value %}` (a partial, with its own scope),
|
|
89
|
+
`{% slot 'productPurchase' %}` (a host island), `{% schema %}` (a section's
|
|
90
|
+
settings, in JSON), `{% comment %}…{% endcomment %}`.
|
|
91
|
+
|
|
92
|
+
Filters: `default`, `upcase`, `downcase`, `capitalize`, `strip`,
|
|
93
|
+
`strip_newlines`, `handleize`, `url_encode`, `json`, `truncate`, `replace`,
|
|
94
|
+
`append`, `prepend`, `split`, `join`, `size`, `first`, `last`, `slice`,
|
|
95
|
+
`reverse`, `uniq`, `compact`, `map`, `where`, `sort`, `sum`, `date`, `plus`,
|
|
96
|
+
`minus`, `times`, `divided_by`, `modulo`, `abs`, `floor`, `ceil`, `round`,
|
|
97
|
+
`money`, `link_url`, `image_url`, `video_url`, `page_url`.
|
|
98
|
+
|
|
99
|
+
Drops: `shop`, `page`, `settings`, `section`, `product`, `collection`,
|
|
100
|
+
`category`, `article`, `blog`, `articles`, `search`, `listing`, `collections`,
|
|
101
|
+
`categories`, `latest`, `products`, `vouchers`, `branches`, `cart`,
|
|
102
|
+
`customer`, and `routes` (`home`, `products`, `search`, `cart`, `account`,
|
|
103
|
+
`order_tracking`).
|
|
104
|
+
|
|
105
|
+
A wrong filter, an unknown drop property or a missing snippet is a **compile
|
|
106
|
+
error**: `push` reports the file and line and writes nothing. The language
|
|
107
|
+
deliberately has no `assign`, no `include` with arbitrary scope, no `{% raw %}`
|
|
108
|
+
and no way to emit `<script>`, `style="…"`, `on*` handlers or `javascript:`
|
|
109
|
+
URLs — a theme is markup, and interactivity is the host's.
|
|
70
110
|
|
|
71
111
|
## Requirements
|
|
72
112
|
|
package/dist/cli.js
CHANGED
|
@@ -381,18 +381,36 @@ ${u(`[${F}]`)} ${T($)}`)}function V($){console.log(` ${z0("OK")} ${$}`)}funct
|
|
|
381
381
|
}
|
|
382
382
|
`,L0=`# Theme project
|
|
383
383
|
|
|
384
|
-
A storefront theme for Pesanle, authored in the compiled template language
|
|
385
|
-
|
|
384
|
+
A storefront theme for Pesanle, authored in the compiled template language —
|
|
385
|
+
HTML-first and Liquid-shaped. Every page is a file:
|
|
386
|
+
|
|
387
|
+
layout/theme.tpl the shell around every page of the shop
|
|
388
|
+
templates/index.tpl home
|
|
389
|
+
templates/product.tpl a product page
|
|
390
|
+
templates/catalog.tpl the catalogue
|
|
391
|
+
templates/pages/about.tpl a page of the theme's own, at /about
|
|
392
|
+
snippets/product-card.tpl a partial
|
|
393
|
+
assets/theme.css styles, scoped under .theme
|
|
394
|
+
|
|
395
|
+
Host slots draw the interactive pieces the platform owns, so a theme ships no
|
|
396
|
+
JavaScript: {% slot 'productPurchase' %}, {% slot 'productReviews' %},
|
|
397
|
+
{% slot 'pageBody' %}, {% slot 'cartTrigger' %}, {% slot 'cartDrawer' %} and
|
|
398
|
+
{% slot 'orderTracking' %}. A wrong filter, an unknown drop property or a
|
|
399
|
+
missing snippet fails \`push\` with the file and line — never a shopper's page.
|
|
400
|
+
|
|
401
|
+
The same theme can be edited in the dashboard: Online store → Themes → Code
|
|
402
|
+
theme, with a file tree, an editor and a live preview of the draft.
|
|
386
403
|
|
|
387
404
|
\`\`\`bash
|
|
388
405
|
pesanle-theme push # compile and write the shop's draft
|
|
389
406
|
pesanle-theme publish # make the draft live
|
|
407
|
+
pesanle-theme preview # a signed link that draws the draft
|
|
390
408
|
pesanle-theme pull # write the live theme back into this folder
|
|
391
409
|
pesanle-theme status # the shop, its engine, and both versions
|
|
392
410
|
\`\`\`
|
|
393
411
|
|
|
394
|
-
The
|
|
395
|
-
|
|
412
|
+
The shop and theme name live in \`.pesanle.json\`; \`pesanle-theme login\`
|
|
413
|
+
stores the token for this machine in \`~/.pesanle/credentials.json\`.
|
|
396
414
|
`;function _0(){return{"layout/theme.tpl":G0,"templates/index.tpl":M0,"templates/product.tpl":q0,"templates/catalog.tpl":I0,"snippets/product-card.tpl":R0,"templates/pages/about.tpl":O0,"assets/theme.css":D0,"README.md":L0}}function c($){let K=[],N=[];for(let[W,b]of Object.entries(_0())){let Q=J0($.dir,W);if(B0(Q)&&!$.force){N.push(W);continue}X0(H0(Q),{recursive:!0}),Y0(Q,b),K.push(W)}return{written:K,skipped:N}}function U0($){let K={command:$[0]??"",dir:"",shop:"",name:"",api:"",email:"",engine:"",force:!1,draft:!1,push:!1,noEngine:!1},N=$.slice(1);for(let W=0;W<N.length;W+=1){let b=N[W],[Q,B]=b.startsWith("--")?b.split("=",2):["",""],Z=()=>B??N[++W]??"";switch(Q){case"--dir":K.dir=Z();break;case"--shop":K.shop=Z();break;case"--name":K.name=Z();break;case"--api":K.api=Z();break;case"--email":K.email=Z();break;case"--force":K.force=!0;break;case"--draft":K.draft=!0;break;case"--push":K.push=!0;break;case"--no-engine":K.noEngine=!0;break;case"":if(!K.dir)K.dir=b;else if(!K.engine&&P(b))K.engine=b;break;default:throw Error(`Unknown flag "${b}".`)}}if(K.command==="engine"&&!K.engine&&P(K.dir))K.engine=K.dir,K.dir="";return K}function P($){return $==="template"||$==="page-builder"}function j0($){let K=M();if(!K)throw Error('Not signed in. Run "pesanle-theme login" first.');return new H({api:O($)||K.api,token:K.token})}function J($){let K=d($.dir||"."),N=D(K),W=$.shop||N?.shop||"";if(!W)throw Error('No shop given: pass --shop <slug>, or run "pesanle-theme init --shop <slug>" to write .pesanle.json.');return{dir:K,shop:W,name:$.name||N?.name||w(K),api:j0($.api)}}function P0($){for(let K of $.diagnostics){let N=K.file?`${K.file}${K.loc?.start?.line?`:${K.loc.start.line}:${K.loc.start.column??1}`:""} `:"";console.error(` ${N}${K.code?`${K.code}: `:""}${K.message}`)}}async function w0($){let K=O($.api),N=$.email||process.env.PESANLE_EMAIL||await h("Email");if(!N)throw Error("An email is required.");let W=await p("Password (hidden)","PESANLE_PASSWORD"),b=$.name||`pesanle-theme on ${w(process.env.HOME??"this machine")}`;X("Sign in");let B=await new H({api:K}).login(N,W,b);v({api:K,token:B.token,email:B.user.email,name:b}),V(`Signed in as ${B.user.name} <${B.user.email}>`),z(`API: ${K}`),z("Next: pesanle-theme init ./my-theme --shop <shop>")}async function A0(){let $=M();if(X("Sign out"),!$){z("Not signed in.");return}try{await new H({api:$.api,token:$.token}).logout(),V("Token revoked")}catch(K){R(K.message)}k(),V("Signed out on this machine")}async function C0($){let K=M();if(!K)throw Error('Not signed in. Run "pesanle-theme login" first.');let W=await new H({api:O($.api)||K.api,token:K.token}).me();V(`${W.name} <${W.email}>`),z(`API: ${K.api}`)}async function S0($){let K=d($.dir||".");j(K,{recursive:!0});let N=$.name||w(K);X("Scaffold");let W=c({dir:K,name:N,force:$.force});V(`${W.written.length} files written${W.skipped.length?`, ${W.skipped.length} kept`:""}`);for(let b of W.skipped)z(`kept ${b}`);if($.shop)L(K,{shop:$.shop,name:N}),V(`.pesanle.json points at "${$.shop}"`);else R("No --shop given: add .pesanle.json (or pass --shop) before pushing.");console.log(`
|
|
397
415
|
${N} is ready.`),z(`cd ${$.dir||"."} && pesanle-theme push`)}async function o($){let K=J($);X("Compile & push");let N=m(K.dir);if(Object.keys(N).length===0)throw Error(`No theme files under ${K.dir}. A theme needs at least templates/index.tpl \u2014 run "pesanle-theme init" first.`);let W=await K.api.push(K.shop,N,K.name);if(V(`${Object.keys(N).length} files \u2192 version ${W.version}`),W.warnings.length>0){R(`${W.warnings.length} warning(s)`);for(let b of W.warnings)z(`${b.file??""}${b.file?": ":""}${b.message}`)}if(!$.noEngine)V("Shop is on the template engine");z("Make it live with: pesanle-theme publish")}async function E0($){if($.push)await o($);let K=J($);X("Publish");let N=await K.api.publish(K.shop);V(`Live \u2014 version ${N.version}`),z(N.url)}async function y0($){let K=J($);X("Preview");let N=await K.api.preview(K.shop);V(`Draft version ${N.version}`),console.log(`
|
|
398
416
|
${T("Open:")} ${N.url}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pesanle-theme",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Compile and push a storefront theme to a Pesanle shop: scaffold, draft, publish, preview.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,15 +23,7 @@
|
|
|
23
23
|
"cli",
|
|
24
24
|
"template"
|
|
25
25
|
],
|
|
26
|
-
"
|
|
27
|
-
"type": "git",
|
|
28
|
-
"url": "git+https://github.com/ridhotamma/pesanle.git",
|
|
29
|
-
"directory": "packages/theme-cli"
|
|
30
|
-
},
|
|
31
|
-
"homepage": "https://github.com/ridhotamma/pesanle/blob/main/docs/THEME-CLI.md",
|
|
32
|
-
"bugs": {
|
|
33
|
-
"url": "https://github.com/ridhotamma/pesanle/issues"
|
|
34
|
-
},
|
|
26
|
+
"homepage": "https://pesanle.id",
|
|
35
27
|
"publishConfig": {
|
|
36
28
|
"access": "public"
|
|
37
29
|
},
|