@zohofinance/commerce 1.0.0 → 1.0.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 (127) hide show
  1. package/README.md +61 -0
  2. package/package.json +2 -2
  3. package/ts-dist/mocks/init-theme/.claude/CLAUDE.md +6 -0
  4. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/SKILL.md +242 -0
  5. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/inputs/figma.md +81 -0
  6. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/inputs/screenshot.md +54 -0
  7. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/inputs/url.md +88 -0
  8. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/spec-table.md +102 -0
  9. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/verification/accessibility.md +110 -0
  10. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/verification/performance.md +127 -0
  11. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/verification/tokens.md +87 -0
  12. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/verification/visual-diff.md +123 -0
  13. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/SKILL.md +605 -0
  14. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/design-tokens.md +105 -0
  15. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/page-json-contract.md +58 -0
  16. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/qa-accessibility.md +35 -0
  17. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/reference-lookup.md +94 -0
  18. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/section-anatomy.md +109 -0
  19. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/SKILL.md +313 -0
  20. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/agent-hierarchy.md +142 -0
  21. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/ask-developer.md +113 -0
  22. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/bootstrap.md +260 -0
  23. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/build-metrics.md +89 -0
  24. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/code-quality.md +186 -0
  25. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/common-pages-agent.md +97 -0
  26. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/dev-server-and-urls.md +127 -0
  27. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/exemplars.md +79 -0
  28. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/figma-discovery.md +138 -0
  29. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/figma-extraction.md +132 -0
  30. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/image-sources.md +84 -0
  31. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/inputs/guidelines-frame.md +178 -0
  32. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/page-builder.md +322 -0
  33. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/page-orchestrator.md +199 -0
  34. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/parallel-fanout.md +152 -0
  35. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/scripts/a11y.mjs +129 -0
  36. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/scripts/lint-section.mjs +502 -0
  37. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/scripts/perf.mjs +134 -0
  38. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/scripts/pixel-diff.mjs +206 -0
  39. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/scripts/record-build-metrics.mjs +118 -0
  40. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/section-builder.md +131 -0
  41. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/subagent-escalation.md +75 -0
  42. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/transcription-rules.md +98 -0
  43. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/verification.md +227 -0
  44. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/visual-verify-loop.md +117 -0
  45. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/_index.md +4 -0
  46. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/assets.md +105 -0
  47. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/best-practices.md +212 -0
  48. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/custom-scripts.md +294 -0
  49. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/i18n.md +155 -0
  50. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/introduction.md +91 -0
  51. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/layouts.md +158 -0
  52. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/pages.md +156 -0
  53. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/reference/_index.md +4 -0
  54. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/reference/filters.md +419 -0
  55. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/reference/global-objects.md +415 -0
  56. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/reference/schema-types.md +926 -0
  57. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/reference/tags.md +259 -0
  58. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/sections.md +203 -0
  59. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/setup-guide.md +424 -0
  60. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/snippets.md +70 -0
  61. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/theme-structure.md +252 -0
  62. package/ts-dist/mocks/init-theme/.cursor/PLAYBOOK.md +144 -0
  63. package/ts-dist/mocks/init-theme/.cursor/README.md +6 -0
  64. package/ts-dist/mocks/init-theme/.cursor/agents/figma-desktop-mobile-parallel.md +48 -0
  65. package/ts-dist/mocks/init-theme/.cursor/agents/visual-compare.md +221 -0
  66. package/ts-dist/mocks/init-theme/.cursor/commands/add-field.md +83 -0
  67. package/ts-dist/mocks/init-theme/.cursor/commands/add-theme-setting.md +200 -0
  68. package/ts-dist/mocks/init-theme/.cursor/commands/assemble-page.md +72 -0
  69. package/ts-dist/mocks/init-theme/.cursor/commands/audit-page.md +57 -0
  70. package/ts-dist/mocks/init-theme/.cursor/commands/build-page-sections.md +110 -0
  71. package/ts-dist/mocks/init-theme/.cursor/commands/build-section.md +418 -0
  72. package/ts-dist/mocks/init-theme/.cursor/commands/build-theme.md +307 -0
  73. package/ts-dist/mocks/init-theme/.cursor/commands/compare-section.md +358 -0
  74. package/ts-dist/mocks/init-theme/.cursor/commands/create-theme.md +77 -0
  75. package/ts-dist/mocks/init-theme/.cursor/commands/extract-tokens.md +43 -0
  76. package/ts-dist/mocks/init-theme/.cursor/commands/fix-section.md +92 -0
  77. package/ts-dist/mocks/init-theme/.cursor/commands/impact.md +50 -0
  78. package/ts-dist/mocks/init-theme/.cursor/commands/qa-a11y.md +66 -0
  79. package/ts-dist/mocks/init-theme/.cursor/commands/qa-i18n.md +110 -0
  80. package/ts-dist/mocks/init-theme/.cursor/commands/qa-layout.md +127 -0
  81. package/ts-dist/mocks/init-theme/.cursor/commands/qa-performance.md +72 -0
  82. package/ts-dist/mocks/init-theme/.cursor/commands/qa-section.md +84 -0
  83. package/ts-dist/mocks/init-theme/.cursor/commands/qa-sections.md +48 -0
  84. package/ts-dist/mocks/init-theme/.cursor/commands/qa-theme.md +85 -0
  85. package/ts-dist/mocks/init-theme/.cursor/commands/redesign-section.md +177 -0
  86. package/ts-dist/mocks/init-theme/.cursor/commands/refactor-section.md +185 -0
  87. package/ts-dist/mocks/init-theme/.cursor/commands/sync-theme-settings.md +132 -0
  88. package/ts-dist/mocks/init-theme/.cursor/commands/validate-page.md +60 -0
  89. package/ts-dist/mocks/init-theme/.cursor/commands/validate-section-group.md +88 -0
  90. package/ts-dist/mocks/init-theme/.cursor/commands/validate-theme-settings.md +119 -0
  91. package/ts-dist/mocks/init-theme/.cursor/examples/design-instructions-template.md +151 -0
  92. package/ts-dist/mocks/init-theme/.cursor/mcp.json +18 -0
  93. package/ts-dist/mocks/init-theme/.cursor/rules/README.md +160 -0
  94. package/ts-dist/mocks/init-theme/.cursor/rules/accessibility.mdc +24 -0
  95. package/ts-dist/mocks/init-theme/.cursor/rules/add-field.mdc +222 -0
  96. package/ts-dist/mocks/init-theme/.cursor/rules/add-theme-setting.mdc +39 -0
  97. package/ts-dist/mocks/init-theme/.cursor/rules/assemble-page.mdc +130 -0
  98. package/ts-dist/mocks/init-theme/.cursor/rules/audit-page.mdc +92 -0
  99. package/ts-dist/mocks/init-theme/.cursor/rules/build-section.mdc +178 -0
  100. package/ts-dist/mocks/init-theme/.cursor/rules/build-theme.mdc +47 -0
  101. package/ts-dist/mocks/init-theme/.cursor/rules/compare-section.mdc +94 -0
  102. package/ts-dist/mocks/init-theme/.cursor/rules/create-theme.mdc +78 -0
  103. package/ts-dist/mocks/init-theme/.cursor/rules/css.mdc +137 -0
  104. package/ts-dist/mocks/init-theme/.cursor/rules/design-spec-extraction.mdc +255 -0
  105. package/ts-dist/mocks/init-theme/.cursor/rules/extract-tokens.mdc +43 -0
  106. package/ts-dist/mocks/init-theme/.cursor/rules/figma-mcp-resolution.mdc +40 -0
  107. package/ts-dist/mocks/init-theme/.cursor/rules/fix-section.mdc +154 -0
  108. package/ts-dist/mocks/init-theme/.cursor/rules/general.mdc +30 -0
  109. package/ts-dist/mocks/init-theme/.cursor/rules/i18n.mdc +85 -0
  110. package/ts-dist/mocks/init-theme/.cursor/rules/javascript.mdc +85 -0
  111. package/ts-dist/mocks/init-theme/.cursor/rules/liquid-no-hardcoded-strings.mdc +42 -0
  112. package/ts-dist/mocks/init-theme/.cursor/rules/liquid.mdc +171 -0
  113. package/ts-dist/mocks/init-theme/.cursor/rules/mobile-desktop-setting-meta.mdc +34 -0
  114. package/ts-dist/mocks/init-theme/.cursor/rules/naming-convention.mdc +64 -0
  115. package/ts-dist/mocks/init-theme/.cursor/rules/pages.mdc +120 -0
  116. package/ts-dist/mocks/init-theme/.cursor/rules/performance.mdc +51 -0
  117. package/ts-dist/mocks/init-theme/.cursor/rules/qa-section.mdc +134 -0
  118. package/ts-dist/mocks/init-theme/.cursor/rules/redesign-section.mdc +147 -0
  119. package/ts-dist/mocks/init-theme/.cursor/rules/schema-sync.mdc +110 -0
  120. package/ts-dist/mocks/init-theme/.cursor/rules/schema.mdc +360 -0
  121. package/ts-dist/mocks/init-theme/.cursor/rules/share-urls.mdc +68 -0
  122. package/ts-dist/mocks/init-theme/.cursor/skills/browser-verify.md +128 -0
  123. package/ts-dist/mocks/init-theme/.cursor/skills/design-tokens.md +105 -0
  124. package/ts-dist/mocks/init-theme/.cursor/skills/page-json-contract.md +87 -0
  125. package/ts-dist/mocks/init-theme/.cursor/skills/qa-accessibility.md +35 -0
  126. package/ts-dist/mocks/init-theme/.cursor/skills/reference-lookup.md +88 -0
  127. package/ts-dist/mocks/init-theme/.cursor/skills/section-anatomy.md +173 -0
@@ -0,0 +1,926 @@
1
+ ---
2
+ title: "Schema Types"
3
+ weight: 13
4
+ ---
5
+
6
+ # Schema Types
7
+
8
+ Schema defines how sections and settings are customized in the Zoho Commerce admin panel. Each setting type has specific properties, default value formats, and output behavior.
9
+
10
+ ## Schema Structure
11
+
12
+ ```json
13
+ {
14
+ "name": "t:sections.hero_banner.name",
15
+ "category": "Banner",
16
+ "tag": "section",
17
+ "class": "section",
18
+ "available_in": {"templates": ["index", "category", "collection"]},
19
+ "settings": [
20
+ {
21
+ "type": "text",
22
+ "id": "section_title",
23
+ "label": "t:sections.hero_banner.settings.title.label",
24
+ "default": "Welcome",
25
+ "meta": "desktop"
26
+ }
27
+ ],
28
+ "blocks": [
29
+ {
30
+ "type": "button",
31
+ "name": "t:sections.hero_banner.blocks.button.name",
32
+ "limit": 2,
33
+ "settings": [
34
+ {
35
+ "type": "text",
36
+ "id": "button_text",
37
+ "label": "t:sections.hero_banner.blocks.button.settings.text.label",
38
+ "default": "Shop Now"
39
+ }
40
+ ]
41
+ }
42
+ ]
43
+ }
44
+ ```
45
+
46
+ ### Core Properties
47
+
48
+ | Property | Type | Required | Description |
49
+ |----------|------|----------|-------------|
50
+ | `name` | string | Yes | Display name in admin (use `t:` prefix for translations) |
51
+ | `category` | string | No | Section category for grouping in admin |
52
+ | `tag` | string | No | HTML element for wrapper (default: `div`) |
53
+ | `class` | string | No | CSS class for section wrapper |
54
+ | `available_in` | object | No | Templates where section can be used |
55
+ | `settings` | array | Yes | Array of setting definitions |
56
+ | `blocks` | array | No | Repeatable content blocks |
57
+ | `limit` | number | No | Maximum instances of this section per page |
58
+
59
+ ### available_in Property
60
+
61
+ Controls where a section can be added:
62
+
63
+ ```json
64
+ {
65
+ "available_in": {
66
+ "templates": ["index", "category", "collection", "product", "search", "header-group", "footer-group"]
67
+ }
68
+ }
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Setting Types
74
+
75
+ ### Setting Meta Property
76
+
77
+ Use the `meta` property to group settings for desktop/mobile views in the admin UI:
78
+
79
+ ```json
80
+ {
81
+ "type": "range",
82
+ "id": "desktop_padding",
83
+ "label": "Desktop Padding",
84
+ "default": 10,
85
+ "min": 0,
86
+ "max": 50,
87
+ "step": 1,
88
+ "meta": "desktop"
89
+ },
90
+ {
91
+ "type": "range",
92
+ "id": "mobile_padding",
93
+ "label": "Mobile Padding",
94
+ "default": 5,
95
+ "min": 0,
96
+ "max": 30,
97
+ "step": 1,
98
+ "meta": "mobile"
99
+ }
100
+ ```
101
+
102
+ For theme-level settings in `settings/schema.json`, use `meta` to group as component or global settings:
103
+
104
+ ```json
105
+ {
106
+ "name": "t:settings_schema.colors.name",
107
+ "settings": [...],
108
+ "meta": "global_settings"
109
+ }
110
+ ```
111
+
112
+ ---
113
+
114
+ ### header
115
+
116
+ Visual divider to group related settings in the admin panel. Does not produce any output value.
117
+
118
+ ```json
119
+ {
120
+ "type": "header",
121
+ "content": "Layout Settings",
122
+ "meta": "desktop"
123
+ }
124
+ ```
125
+
126
+ | Property | Type | Required | Description |
127
+ |----------|------|----------|-------------|
128
+ | `type` | `"header"` | Yes | Setting type |
129
+ | `content` | string | Yes | Header label text |
130
+ | `meta` | string | No | Grouping (`desktop`, `mobile`, `global_settings`, `component_settings`) |
131
+
132
+ **Output:** None — used only for admin UI organization.
133
+
134
+ ---
135
+
136
+ ### text
137
+
138
+ Single-line text input.
139
+
140
+ ```json
141
+ {
142
+ "type": "text",
143
+ "id": "heading",
144
+ "label": "t:sections.hero.settings.heading.label",
145
+ "placeholder": "Enter heading text",
146
+ "default": "Welcome to our store",
147
+ "meta": "desktop"
148
+ }
149
+ ```
150
+
151
+ | Property | Type | Required | Description |
152
+ |----------|------|----------|-------------|
153
+ | `type` | `"text"` | Yes | Setting type |
154
+ | `id` | string | Yes | Unique identifier |
155
+ | `label` | string | Yes | Display label |
156
+ | `placeholder` | string | No | Hint text |
157
+ | `default` | string | Yes | Initial value |
158
+ | `meta` | string | No | Grouping for admin UI |
159
+
160
+ **Output:** `{{ section.settings.heading | escape }}` → `"Welcome to our store"`
161
+
162
+ > **Use for:** headings (`<h1>`–`<h6>`), titles, eyebrows, badges, button/CTA labels — any short plain text.
163
+ > **Do not use for:** multi-line body copy — use `richtext` instead.
164
+
165
+ ---
166
+
167
+ ### richtext
168
+
169
+ Multi-line rich text editor with HTML formatting.
170
+
171
+ ```json
172
+ {
173
+ "type": "richtext",
174
+ "id": "description",
175
+ "label": "t:sections.hero.settings.description.label",
176
+ "default": "<p>Enter your description here</p>"
177
+ }
178
+ ```
179
+
180
+ | Property | Type | Required | Description |
181
+ |----------|------|----------|-------------|
182
+ | `type` | `"richtext"` | Yes | Setting type |
183
+ | `id` | string | Yes | Unique identifier |
184
+ | `label` | string | Yes | Display label |
185
+ | `default` | string (HTML) | Yes | Initial HTML content |
186
+
187
+ **Output:** `{{ section.settings.description }}` → `"<p>Enter your description here</p>"`
188
+
189
+ > The output contains raw HTML. Use `{{ section.settings.description | raw }}` in templates.
190
+ >
191
+ > **When to use:** `richtext` for paragraphs, descriptions, answers, and multi-line body copy only.
192
+ > **When NOT to use:** headings, titles, eyebrows, badges, or button labels — use `text` instead (see `text` type above).
193
+
194
+ ---
195
+
196
+ ### color
197
+
198
+ Color picker returning a hex color value.
199
+
200
+ ```json
201
+ {
202
+ "type": "color",
203
+ "id": "primary_color",
204
+ "label": "t:sections.hero.settings.primary_color.label",
205
+ "default": "#854d0e"
206
+ }
207
+ ```
208
+
209
+ | Property | Type | Required | Description |
210
+ |----------|------|----------|-------------|
211
+ | `type` | `"color"` | Yes | Setting type |
212
+ | `id` | string | Yes | Unique identifier |
213
+ | `label` | string | Yes | Display label |
214
+ | `default` | string (hex) | Yes | Hex color code (e.g., `#854d0e`) |
215
+
216
+ **Output:** `{{ section.settings.primary_color }}` → `"#854d0e"`
217
+
218
+ **With filters:**
219
+ ```liquid
220
+ {{ section.settings.primary_color | color_component: "red" }}
221
+ ```
222
+ **Output:** `133`
223
+
224
+ ---
225
+
226
+ ### select
227
+
228
+ Dropdown menu with predefined options.
229
+
230
+ ```json
231
+ {
232
+ "type": "select",
233
+ "id": "layout_style",
234
+ "label": "t:sections.hero.settings.layout_style.label",
235
+ "options": [
236
+ { "value": "grid", "label": "t:sections.hero.settings.layout_style.options.grid" },
237
+ { "value": "list", "label": "t:sections.hero.settings.layout_style.options.list" },
238
+ { "value": "carousel", "label": "t:sections.hero.settings.layout_style.options.carousel" }
239
+ ],
240
+ "default": { "display_name": "t:sections.hero.settings.layout_style.default", "value": "grid" }
241
+ }
242
+ ```
243
+
244
+ | Property | Type | Required | Description |
245
+ |----------|------|----------|-------------|
246
+ | `type` | `"select"` | Yes | Setting type |
247
+ | `id` | string | Yes | Unique identifier |
248
+ | `label` | string | Yes | Display label |
249
+ | `options` | array | Yes | Array of `{ value, label }` objects |
250
+ | `default` | object | Yes | Object with `display_name` and `value` |
251
+
252
+ **Output:** `{{ section.settings.layout_style.value }}` → `"grid"`
253
+
254
+ ---
255
+
256
+ ### radio
257
+
258
+ Radio button group for selecting one option from a set. Similar to select but displayed as radio buttons.
259
+
260
+ ```json
261
+ {
262
+ "type": "radio",
263
+ "id": "text_alignment",
264
+ "label": "t:sections.hero.settings.text_alignment.label",
265
+ "options": [
266
+ { "value": "left", "label": "t:sections.hero.settings.text_alignment.options.left" },
267
+ { "value": "center", "label": "t:sections.hero.settings.text_alignment.options.center" },
268
+ { "value": "right", "label": "t:sections.hero.settings.text_alignment.options.right" }
269
+ ],
270
+ "default": { "display_name": "t:sections.hero.settings.text_alignment.default", "value": "center" }
271
+ }
272
+ ```
273
+
274
+ | Property | Type | Required | Description |
275
+ |----------|------|----------|-------------|
276
+ | `type` | `"radio"` | Yes | Setting type |
277
+ | `id` | string | Yes | Unique identifier |
278
+ | `label` | string | Yes | Display label |
279
+ | `options` | array | Yes | Array of `{ value, label }` objects |
280
+ | `default` | object | Yes | Object with `display_name` and `value` |
281
+
282
+ **Output:** `{{ section.settings.text_alignment.value }}` → `"center"`
283
+
284
+ ---
285
+
286
+ ### preview_layout
287
+
288
+ Layout selector that renders options as visual layout previews in the admin panel. Functionally identical to `select` and `radio`, but displays each option as a clickable layout thumbnail rather than a dropdown or radio button. Use this when the setting controls visual placement or alignment and a preview aids the user.
289
+
290
+ ```json
291
+ {
292
+ "type": "preview_layout",
293
+ "id": "content_alignment",
294
+ "label": "t:sections.banner.settings.content_alignment.label",
295
+ "options": [
296
+ { "value": "left", "label": "t:sections.banner.settings.content_alignment.options.left" },
297
+ { "value": "center", "label": "t:sections.banner.settings.content_alignment.options.center" },
298
+ { "value": "right", "label": "t:sections.banner.settings.content_alignment.options.right" }
299
+ ],
300
+ "default": { "display_name": "t:sections.banner.settings.content_alignment.default", "value": "left" },
301
+ "meta": "desktop"
302
+ }
303
+ ```
304
+
305
+ | Property | Type | Required | Description |
306
+ |----------|------|----------|-------------|
307
+ | `type` | `"preview_layout"` | Yes | Setting type |
308
+ | `id` | string | Yes | Unique identifier |
309
+ | `label` | string | Yes | Display label |
310
+ | `options` | array | Yes | Array of `{ value, label }` objects |
311
+ | `default` | object | Yes | Object with `display_name` and `value` |
312
+ | `meta` | string | No | Grouping (`desktop`, `mobile`) |
313
+
314
+ **Output:** `{{ section.settings.content_alignment.value }}` → `"left"`
315
+
316
+ ```liquid
317
+ <div class="banner-content
318
+ {% if section.settings.content_alignment.value == 'center' %}justify-center
319
+ {% elsif section.settings.content_alignment.value == 'right' %}justify-end
320
+ {% endif %}">
321
+ ...
322
+ </div>
323
+ ```
324
+
325
+ > Use `preview_layout` instead of `select` or `radio` when the setting controls layout or alignment — it helps admins visualize the effect before applying it.
326
+
327
+ ---
328
+
329
+ ### checkbox
330
+
331
+ Boolean toggle (true/false).
332
+
333
+ ```json
334
+ {
335
+ "type": "checkbox",
336
+ "id": "show_price",
337
+ "label": "t:sections.product.settings.show_price.label",
338
+ "default": true
339
+ }
340
+ ```
341
+
342
+ | Property | Type | Required | Description |
343
+ |----------|------|----------|-------------|
344
+ | `type` | `"checkbox"` | Yes | Setting type |
345
+ | `id` | string | Yes | Unique identifier |
346
+ | `label` | string | Yes | Display label |
347
+ | `default` | boolean | Yes | `true` or `false` |
348
+
349
+ **Output:** `{{ section.settings.show_price }}` → `true`
350
+
351
+ ```liquid
352
+ {% if section.settings.show_price %}
353
+ <p class="price">{{ product.price }}</p>
354
+ {% endif %}
355
+ ```
356
+
357
+ ---
358
+
359
+ ### range
360
+
361
+ Numeric slider with min, max, and step constraints.
362
+
363
+ ```json
364
+ {
365
+ "type": "range",
366
+ "id": "products_per_row",
367
+ "label": "t:sections.collection.settings.products_per_row.label",
368
+ "min": 1,
369
+ "max": 6,
370
+ "step": 1,
371
+ "unit": "cols",
372
+ "default": 4,
373
+ "meta": "desktop"
374
+ }
375
+ ```
376
+
377
+ | Property | Type | Required | Description |
378
+ |----------|------|----------|-------------|
379
+ | `type` | `"range"` | Yes | Setting type |
380
+ | `id` | string | Yes | Unique identifier |
381
+ | `label` | string | Yes | Display label |
382
+ | `min` | number | Yes | Minimum value |
383
+ | `max` | number | Yes | Maximum value |
384
+ | `step` | number | Yes | Increment value |
385
+ | `unit` | string | No | Display unit (e.g., `px`, `%`, `cols`, `rem`) |
386
+ | `default` | number | Yes | Must be within `min`–`max` range |
387
+ | `meta` | string | No | Grouping (`desktop`, `mobile`) |
388
+
389
+ **Output:** `{{ section.settings.products_per_row }}` → `4`
390
+
391
+ ---
392
+
393
+ ### image_picker
394
+
395
+ Image upload and selection. Returns an object with `url` and `enable_customisation` properties. When `enable_customisation` is true, the runtime value also includes `alt_text` and `filters` for image transformations.
396
+
397
+ **Schema definition** (only `url` and `enable_customisation` are needed):
398
+
399
+ ```json
400
+ {
401
+ "type": "image_picker",
402
+ "id": "banner_image",
403
+ "label": "t:sections.banner.settings.banner_image.label",
404
+ "default": {
405
+ "url": "home_banner.webp",
406
+ "enable_customisation": true
407
+ },
408
+ "meta": "desktop"
409
+ }
410
+ ```
411
+
412
+ | Property | Type | Required | Description |
413
+ |----------|------|----------|-------------|
414
+ | `type` | `"image_picker"` | Yes | Setting type |
415
+ | `id` | string | Yes | Unique identifier |
416
+ | `label` | string | Yes | Display label |
417
+ | `default` | object | Yes | Object with `url` and `enable_customisation` |
418
+ | `default.url` | string | Yes | Default image filename (just the filename, not full path) or empty string |
419
+ | `default.enable_customisation` | boolean | Yes | Allow admin users to customize the image with filters and transformations |
420
+ | `meta` | string | No | Grouping (`desktop`, `mobile`) |
421
+
422
+ **Runtime output value** (when `enable_customisation` is true):
423
+
424
+ ```json
425
+ {
426
+ "url": "https://cdn.example.com/uploads/example-image.webp",
427
+ "enable_customisation": true,
428
+ "alt_text": "",
429
+ "filters": {
430
+ "scale_y": 1,
431
+ "rotate": 0,
432
+ "scale_x": 1,
433
+ "filter": "brightness(70%) contrast(120%)",
434
+ "position_x": 0,
435
+ "position_y": 0,
436
+ "opacity": 100
437
+ }
438
+ }
439
+ ```
440
+
441
+ **Output:**
442
+ ```liquid
443
+ {{ section.settings.banner_image.url }}
444
+ ```
445
+ **Output:** `"home_banner.webp"` for theme assets (use `| asset_url` for resolution), or a full CDN URL when the admin uploads a custom image
446
+
447
+ **Accessing filters:**
448
+ ```liquid
449
+ {{ section.settings.banner_image.filters.opacity }}
450
+ {{ section.settings.banner_image.filters.filter }}
451
+ {{ section.settings.banner_image.filters.rotate }}
452
+ {{ section.settings.banner_image.alt_text }}
453
+ ```
454
+
455
+ > **Important:**
456
+ > - The schema definition only requires `url` and `enable_customisation`. The `alt_text` and `filters` are part of the runtime output value.
457
+ > - For theme asset images, use just the filename (e.g., `"home_banner.webp"`). Always pipe through the `asset_url` filter for full URL resolution: `{{ img.url | asset_url }}`. When users upload a custom image through admin, the URL will be a full CDN URL.
458
+
459
+ ---
460
+
461
+ ### Applying Image Filters (Customisation)
462
+
463
+ When `enable_customisation` is true on an `image_picker` setting, the runtime output includes a `filters` object with transformation data. Apply these as inline CSS:
464
+
465
+ #### Filters Object Properties
466
+
467
+ | Property | Type | Description |
468
+ |----------|------|-------------|
469
+ | `opacity` | number | Image opacity (0–100) |
470
+ | `filter` | string | CSS filter chain — supports preset filters and individual functions: `blur()`, `grayscale()`, `brightness()`, `contrast()`, `sepia()`, `saturate()` |
471
+ | `position_x` | number | Horizontal translate offset (percentage) |
472
+ | `position_y` | number | Vertical translate offset (percentage) |
473
+ | `scale_x` | number | Horizontal scale factor (negative values flip the image) |
474
+ | `scale_y` | number | Vertical scale factor (negative values flip the image) |
475
+ | `rotate` | number | Rotation in degrees |
476
+
477
+ **Usage as `<img>` element (always center the image):**
478
+ ```liquid
479
+ {% assign img = section.settings.banner_image %}
480
+ {% if img.url != blank %}
481
+ <img
482
+ src="{{ img.url | asset_url }}"
483
+ alt="{{ img.alt_text }}"
484
+ loading="lazy"
485
+ style="
486
+ transform: rotate({{ img.filters.rotate }}deg) scale({{ img.filters.scale_x }}, {{ img.filters.scale_y }}) translate({{ img.filters.position_x }}%, {{ img.filters.position_y }}%);
487
+ transform-origin: center center;
488
+ filter: {{ img.filters.filter }};
489
+ opacity: {{ img.filters.opacity }};
490
+ object-fit: cover;
491
+ object-position: center;
492
+ ">
493
+ {% endif %}
494
+ ```
495
+
496
+ **Usage as background image (always center the background):**
497
+ ```liquid
498
+ {% assign img = section.settings.banner_image %}
499
+ {% if img.url != blank %}
500
+ <div style="
501
+ background-image: url('{{ img.url | asset_url }}');
502
+ background-position: center center;
503
+ background-size: cover;
504
+ transform: rotate({{ img.filters.rotate }}deg) scale({{ img.filters.scale_x }}, {{ img.filters.scale_y }}) translate({{ img.filters.position_x }}%, {{ img.filters.position_y }}%);
505
+ transform-origin: center center;
506
+ filter: {{ img.filters.filter }};
507
+ opacity: {{ img.filters.opacity }};
508
+ "></div>
509
+ {% endif %}
510
+ ```
511
+
512
+ > **Important:** Always set `transform-origin: center center` so transformations align with the editor. Always center images (`object-position: center` for `<img>`, `background-position: center` for backgrounds) to keep the view stable and properly editable in the admin editor.
513
+
514
+ ---
515
+
516
+ ### url
517
+
518
+ URL input field.
519
+
520
+ ```json
521
+ {
522
+ "type": "url",
523
+ "id": "cta_link",
524
+ "label": "t:sections.hero.settings.cta_link.label",
525
+ "default": { "display_name": "t:sections.hero.settings.cta_link.default", "handle": "collections/all-products" }
526
+ }
527
+ ```
528
+
529
+ | Property | Type | Required | Description |
530
+ |----------|------|----------|-------------|
531
+ | `type` | `"url"` | Yes | Setting type |
532
+ | `id` | string | Yes | Unique identifier |
533
+ | `label` | string | Yes | Display label |
534
+ | `default` | object | Yes | Object with `display_name` (translation key) and `handle` (URL path) |
535
+
536
+ **Output:** `{{ section.settings.cta_link.handle }}` → `"collections/all-products"`
537
+
538
+ > **Note:** For URL settings, the recommended default is `collections/all-products` which points to the all-products collection page. Use the `handle` property to access the URL path.
539
+
540
+ ---
541
+
542
+ ### category
543
+
544
+ Zoho Commerce product category selector. Returns the selected category object.
545
+
546
+ ```json
547
+ {
548
+ "type": "category",
549
+ "id": "featured_category",
550
+ "label": "t:sections.featured.settings.category.label"
551
+ }
552
+ ```
553
+
554
+ | Property | Type | Required | Description |
555
+ |----------|------|----------|-------------|
556
+ | `type` | `"category"` | Yes | Setting type |
557
+ | `id` | string | Yes | Unique identifier |
558
+ | `label` | string | Yes | Display label |
559
+
560
+ **Output:** Returns category object — access properties:
561
+ ```liquid
562
+ {{ section.settings.featured_category.title }}
563
+ {{ section.settings.featured_category.url }}
564
+ {{ section.settings.featured_category.products }}
565
+ {{ section.settings.featured_category.products_count }}
566
+ ```
567
+
568
+ ---
569
+
570
+ ### collection
571
+
572
+ Product collection selector. Returns the selected collection object.
573
+
574
+ ```json
575
+ {
576
+ "type": "collection",
577
+ "id": "featured_collection",
578
+ "label": "Featured Collection"
579
+ }
580
+ ```
581
+
582
+ | Property | Type | Required | Description |
583
+ |----------|------|----------|-------------|
584
+ | `type` | `"collection"` | Yes | Setting type |
585
+ | `id` | string | Yes | Unique identifier |
586
+ | `label` | string | Yes | Display label |
587
+
588
+ **Output:** Returns collection object — access properties:
589
+ ```liquid
590
+ {{ section.settings.featured_collection.title }}
591
+ {{ section.settings.featured_collection.url }}
592
+ {{ section.settings.featured_collection.products }}
593
+ {{ section.settings.featured_collection.products_count }}
594
+ ```
595
+
596
+ ---
597
+
598
+ ### blog
599
+
600
+ Blog selector. Returns the selected blog object.
601
+
602
+ ```json
603
+ {
604
+ "type": "blog",
605
+ "id": "featured_blog",
606
+ "label": "Featured Blog"
607
+ }
608
+ ```
609
+
610
+ | Property | Type | Required | Description |
611
+ |----------|------|----------|-------------|
612
+ | `type` | `"blog"` | Yes | Setting type |
613
+ | `id` | string | Yes | Unique identifier |
614
+ | `label` | string | Yes | Display label |
615
+
616
+ **Output:** Returns blog object — access properties:
617
+ ```liquid
618
+ {{ section.settings.featured_blog.title }}
619
+ {{ section.settings.featured_blog.url }}
620
+ {{ section.settings.featured_blog.articles }}
621
+ ```
622
+
623
+ ---
624
+
625
+ ### menu
626
+
627
+ Navigation menu selector. Returns the selected menu object.
628
+
629
+ ```json
630
+ {
631
+ "type": "menu",
632
+ "id": "main_menu",
633
+ "label": "Main Navigation"
634
+ }
635
+ ```
636
+
637
+ | Property | Type | Required | Description |
638
+ |----------|------|----------|-------------|
639
+ | `type` | `"menu"` | Yes | Setting type |
640
+ | `id` | string | Yes | Unique identifier |
641
+ | `label` | string | Yes | Display label |
642
+
643
+ **Output:** Returns menu object — access properties:
644
+ ```liquid
645
+ {% for link in section.settings.main_menu.links %}
646
+ <a href="{{ link.url }}">{{ link.title }}</a>
647
+ {% endfor %}
648
+ ```
649
+
650
+ ---
651
+
652
+ ## Conditional Visibility
653
+
654
+ Use `visible_if` to show or hide settings based on other setting values. This is a powerful feature that helps keep the admin UI clean by only showing relevant options.
655
+
656
+ ### Syntax
657
+
658
+ The `visible_if` property uses a Liquid-like conditional expression:
659
+
660
+ ```json
661
+ {
662
+ "settings": [
663
+ {
664
+ "type": "checkbox",
665
+ "id": "show_subtitle",
666
+ "label": "t:sections.hero.settings.show_subtitle.label",
667
+ "default": false
668
+ },
669
+ {
670
+ "type": "text",
671
+ "id": "subtitle",
672
+ "label": "t:sections.hero.settings.subtitle.label",
673
+ "default": "Your tagline here",
674
+ "visible_if": "{{ section.settings.show_subtitle }}"
675
+ }
676
+ ]
677
+ }
678
+ ```
679
+
680
+ ### Complex Conditions
681
+
682
+ You can use more complex conditions to compare values:
683
+
684
+ ```json
685
+ {
686
+ "settings": [
687
+ {
688
+ "type": "image_picker",
689
+ "id": "desktop_banner_img",
690
+ "label": "Desktop Banner Image",
691
+ "default": { "url": "home_banner.webp", "enable_customisation": true },
692
+ "meta": "desktop"
693
+ },
694
+ {
695
+ "type": "color",
696
+ "id": "desktop_bg_color",
697
+ "label": "Background Color (Fallback)",
698
+ "default": "#FFFAF3",
699
+ "visible_if": "{{ section.settings.desktop_banner_img.url == null or section.settings.desktop_banner_img.url == '' }}",
700
+ "meta": "desktop"
701
+ }
702
+ ]
703
+ }
704
+ ```
705
+
706
+ ### Best Practices for visible_if
707
+
708
+ - **Use for dependent settings** — Show subtitle text field only when "Show Subtitle" is checked
709
+ - **Reduce clutter** — Hide advanced options unless a feature is enabled
710
+ - **Group related settings** — Combine with `meta` to organize desktop/mobile specific options
711
+ - **Keep conditions simple** — Complex conditions can be hard to debug
712
+
713
+ ### Common Use Cases
714
+
715
+ | Scenario | visible_if Expression |
716
+ |----------|----------------------|
717
+ | Show when checkbox is true | `"{{ section.settings.show_feature }}"` |
718
+ | Show when checkbox is false | `"{{ section.settings.show_feature == false }}"` |
719
+ | Show when image is empty | `"{{ section.settings.image.url == null or section.settings.image.url == '' }}"` |
720
+ | Show when select has value | `"{{ section.settings.layout.value == 'custom' }}"` |
721
+
722
+ ---
723
+
724
+ ## Translation Keys
725
+
726
+ Use `t:` prefix in labels for multi-language admin interfaces:
727
+
728
+ ```json
729
+ {
730
+ "type": "text",
731
+ "id": "title",
732
+ "label": "t:sections.hero.settings.title.label",
733
+ "default": "Welcome"
734
+ }
735
+ ```
736
+
737
+ The translation is defined in `i18n/en.schema.json`:
738
+
739
+ ```json
740
+ {
741
+ "sections": {
742
+ "hero": {
743
+ "settings": {
744
+ "title": {
745
+ "label": "Section Title"
746
+ }
747
+ }
748
+ }
749
+ }
750
+ }
751
+ ```
752
+
753
+ ---
754
+
755
+ ## Complete Section Example
756
+
757
+ A full section using multiple setting types and blocks:
758
+
759
+ ```liquid
760
+ <section class="hero-banner" style="background-color: {{ section.settings.bg_color }}">
761
+ {% if section.settings.bg_image.url != blank %}
762
+ {% assign img = section.settings.bg_image %}
763
+ <img
764
+ src="{{ img.url }}"
765
+ alt="{{ img.alt_text }}"
766
+ class="hero-bg"
767
+ style="
768
+ object-fit: cover;
769
+ object-position: center;
770
+ transform: rotate({{ img.filters.rotate }}deg) scale({{ img.filters.scale_x }}, {{ img.filters.scale_y }}) translate({{ img.filters.position_x }}%, {{ img.filters.position_y }}%);
771
+ transform-origin: center center;
772
+ filter: {{ img.filters.filter }};
773
+ opacity: {{ img.filters.opacity }};
774
+ ">
775
+ {% endif %}
776
+
777
+ <div class="hero-content" style="text-align: {{ section.settings.text_align.value }}">
778
+ <h1>{{ section.settings.heading }}</h1>
779
+
780
+ {% if section.settings.show_subtitle %}
781
+ <p>{{ section.settings.subtitle }}</p>
782
+ {% endif %}
783
+
784
+ {% for block in section.blocks %}
785
+ {% if block.type == 'button' %}
786
+ <a href="{{ block.settings.link.handle }}" class="btn" {{ block.zcommerce_attributes }}>
787
+ {{ block.settings.label }}
788
+ </a>
789
+ {% endif %}
790
+ {% endfor %}
791
+ </div>
792
+ </section>
793
+
794
+ {% schema %}
795
+ {
796
+ "name": "t:sections.hero_banner.name",
797
+ "category": "Banner",
798
+ "tag": "section",
799
+ "class": "section hero-section",
800
+ "available_in": {"templates": ["index", "category", "collection"]},
801
+ "settings": [
802
+ {
803
+ "type": "header",
804
+ "content": "t:sections.hero_banner.settings.content_header",
805
+ "meta": "desktop"
806
+ },
807
+ {
808
+ "type": "text",
809
+ "id": "heading",
810
+ "label": "t:sections.hero_banner.settings.heading.label",
811
+ "default": "Welcome to Our Store"
812
+ },
813
+ {
814
+ "type": "checkbox",
815
+ "id": "show_subtitle",
816
+ "label": "t:sections.hero_banner.settings.show_subtitle.label",
817
+ "default": true
818
+ },
819
+ {
820
+ "type": "text",
821
+ "id": "subtitle",
822
+ "label": "t:sections.hero_banner.settings.subtitle.label",
823
+ "default": "Discover amazing products",
824
+ "visible_if": "{{ section.settings.show_subtitle }}"
825
+ },
826
+ {
827
+ "type": "header",
828
+ "content": "t:sections.hero_banner.settings.appearance_header",
829
+ "meta": "desktop"
830
+ },
831
+ {
832
+ "type": "color",
833
+ "id": "bg_color",
834
+ "label": "t:sections.hero_banner.settings.bg_color.label",
835
+ "default": "#1a1a2e"
836
+ },
837
+ {
838
+ "type": "image_picker",
839
+ "id": "bg_image",
840
+ "label": "t:sections.hero_banner.settings.bg_image.label",
841
+ "default": {
842
+ "url": "hero_banner.webp",
843
+ "enable_customisation": true
844
+ },
845
+ "meta": "desktop"
846
+ },
847
+ {
848
+ "type": "select",
849
+ "id": "text_align",
850
+ "label": "t:sections.hero_banner.settings.text_align.label",
851
+ "options": [
852
+ { "value": "left", "label": "t:sections.hero_banner.settings.text_align.options.left" },
853
+ { "value": "center", "label": "t:sections.hero_banner.settings.text_align.options.center" },
854
+ { "value": "right", "label": "t:sections.hero_banner.settings.text_align.options.right" }
855
+ ],
856
+ "default": { "display_name": "t:sections.hero_banner.settings.text_align.default", "value": "center" }
857
+ },
858
+ {
859
+ "type": "range",
860
+ "id": "desktop_padding",
861
+ "label": "t:sections.hero_banner.settings.padding.label",
862
+ "min": 0,
863
+ "max": 100,
864
+ "step": 10,
865
+ "unit": "px",
866
+ "default": 50,
867
+ "meta": "desktop"
868
+ },
869
+ {
870
+ "type": "range",
871
+ "id": "mobile_padding",
872
+ "label": "t:sections.hero_banner.settings.padding.label",
873
+ "min": 0,
874
+ "max": 60,
875
+ "step": 5,
876
+ "unit": "px",
877
+ "default": 20,
878
+ "meta": "mobile"
879
+ }
880
+ ],
881
+ "blocks": [
882
+ {
883
+ "type": "button",
884
+ "name": "t:sections.hero_banner.blocks.button.name",
885
+ "limit": 2,
886
+ "settings": [
887
+ {
888
+ "type": "text",
889
+ "id": "label",
890
+ "label": "t:sections.hero_banner.blocks.button.settings.label.label",
891
+ "default": "Shop Now"
892
+ },
893
+ {
894
+ "type": "url",
895
+ "id": "link",
896
+ "label": "t:sections.hero_banner.blocks.button.settings.link.label",
897
+ "default": { "display_name": "t:sections.hero_banner.blocks.button.settings.link.default", "handle": "collections/all-products" }
898
+ }
899
+ ]
900
+ }
901
+ ]
902
+ }
903
+ {% endschema %}
904
+ ```
905
+
906
+ ---
907
+
908
+ ## Quick Reference
909
+
910
+ | Type | Default Format | Output Type | Admin UI |
911
+ |------|---------------|-------------|----------|
912
+ | `header` | N/A | None | Section divider |
913
+ | `text` | `"string"` | string | Text input |
914
+ | `richtext` | `"<p>html</p>"` | HTML string | Rich editor |
915
+ | `color` | `"#hexcode"` | string | Color picker |
916
+ | `select` | `{ "display_name": "...", "value": "..." }` | object | Dropdown |
917
+ | `radio` | `{ "display_name": "...", "value": "..." }` | object | Radio buttons |
918
+ | `preview_layout` | `{ "display_name": "...", "value": "..." }` | object | Visual layout picker |
919
+ | `checkbox` | `true` / `false` | boolean | Toggle |
920
+ | `range` | `number` | number | Slider |
921
+ | `image_picker` | `{ "url": "filename.webp", "enable_customisation": true }` | object (`url`, `enable_customisation`, `alt_text`, `filters`) | Image uploader |
922
+ | `url` | `{ "display_name": "...", "handle": "collections/all-products" }` | object | URL input |
923
+ | `category` | N/A | object | Category picker |
924
+ | `collection` | N/A | object | Collection picker |
925
+ | `blog` | N/A | object | Blog picker |
926
+ | `menu` | N/A | object | Menu picker |