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.
Files changed (3) hide show
  1. package/README.md +46 -6
  2. package/dist/cli.js +22 -4
  3. 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
- - CLI reference: <https://github.com/ridhotamma/pesanle/blob/main/docs/THEME-CLI.md>
24
- - Language reference: <https://github.com/ridhotamma/pesanle/blob/main/docs/TEMPLATE-LANGUAGE.md>
25
- - How the engine works: <https://github.com/ridhotamma/pesanle/blob/main/docs/TEMPLATE_ENGINE.md>
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. Interactive pieces — the buy
68
- box, reviews, the order-tracking form — arrive as host slots
69
- (`{% slot 'productPurchase' %}`); a theme never ships its own JavaScript.
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
- The reference is \`docs/TEMPLATE-LANGUAGE.md\` in the Pesanle repository.
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 API key comes from \`PESANLE_API_KEY\`; the shop and project live in
395
- \`.pesanle.json\`. The key is never written to the file.
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.0",
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
- "repository": {
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
  },