@fluid-app/fluid-cli-theme-dev 0.1.63 → 0.1.64

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 (137) hide show
  1. package/README.md +1 -1
  2. package/dist/dist-cli-preview/.vite/manifest.json +225 -225
  3. package/dist/dist-cli-preview/account-screens.js +1 -1
  4. package/dist/dist-cli-preview/chunks/{Breadcrumb-CZ-skiUy.js → Breadcrumb-BQKo8hPc.js} +1 -1
  5. package/dist/dist-cli-preview/chunks/{Combobox-BGiCYa56.js → Combobox-cf11L_T-.js} +4 -4
  6. package/dist/dist-cli-preview/chunks/{ContactsScreen-vsNgy_gn.js → ContactsScreen-gIiy4u7c.js} +1160 -1155
  7. package/dist/dist-cli-preview/chunks/{MemberManagementProviders-DMwkh3JW.js → MemberManagementProviders-C1bwc3tB.js} +258 -224
  8. package/dist/dist-cli-preview/chunks/{MessagingScreen-DzJOwPGH.js → MessagingScreen-B8ZxAE0L.js} +3904 -3927
  9. package/dist/dist-cli-preview/chunks/{MobileActionSheet-DqVPgFKI.js → MobileActionSheet-DMeTsLlK.js} +100 -100
  10. package/dist/dist-cli-preview/chunks/{MySiteScreen-BSmWlCKA.js → MySiteScreen-Dtw1rsF9.js} +69 -69
  11. package/dist/dist-cli-preview/chunks/OrdersScreen-C-b6i5jB.js +9 -0
  12. package/dist/dist-cli-preview/chunks/{OrdersScreen-CVEl9FnN.js → OrdersScreen-D9HfcTaa.js} +247 -249
  13. package/dist/dist-cli-preview/chunks/{ProfileScreen-BC5gyJDY.js → ProfileScreen-DwXozaLs.js} +1051 -965
  14. package/dist/dist-cli-preview/chunks/{SubscriptionsScreen-CFM4Pufg.js → SubscriptionsScreen-CIdYNpWT.js} +3 -3
  15. package/dist/dist-cli-preview/chunks/{account-screen-runtime-DxhJm6Qd.js → account-screen-runtime-DYMunv0A.js} +2482 -2407
  16. package/dist/dist-cli-preview/chunks/ar-DaN3xEy4.js +351 -0
  17. package/dist/dist-cli-preview/chunks/{arrow-left-UFKI-PQf.js → arrow-left-Bd7dJtIV.js} +1 -1
  18. package/dist/dist-cli-preview/chunks/bg-D3Np0de3.js +351 -0
  19. package/dist/dist-cli-preview/chunks/bn-BDSehnZ3.js +351 -0
  20. package/dist/dist-cli-preview/chunks/{cli-preview-DunPfnjU.js → cli-preview-BT_ARKjk.js} +13 -13
  21. package/dist/dist-cli-preview/chunks/{client.gen-CSTBgfxj.js → client.gen-Ck6Pm2jV.js} +246 -236
  22. package/dist/dist-cli-preview/chunks/contacts-ChSWj70z.js +4 -0
  23. package/dist/dist-cli-preview/chunks/{countries-api-adapter-B3usO25w.js → countries-api-adapter-lxSE748x.js} +2 -2
  24. package/dist/dist-cli-preview/chunks/{create-card-entry-container-DHgsbSyr.js → create-card-entry-container-D6kSC2Aw.js} +20726 -20509
  25. package/dist/dist-cli-preview/chunks/cs-CrmATj4L.js +351 -0
  26. package/dist/dist-cli-preview/chunks/da-CmJdErjd.js +351 -0
  27. package/dist/dist-cli-preview/chunks/de-C0KTNBZq.js +351 -0
  28. package/dist/dist-cli-preview/chunks/el-BOQs49GU.js +351 -0
  29. package/dist/dist-cli-preview/chunks/es-Dt3VSQPu.js +351 -0
  30. package/dist/dist-cli-preview/chunks/fi-B8UZ7eJL.js +351 -0
  31. package/dist/dist-cli-preview/chunks/fr-BomEiNL0.js +351 -0
  32. package/dist/dist-cli-preview/chunks/he-CfmnXjsr.js +351 -0
  33. package/dist/dist-cli-preview/chunks/{hey-api-client-DSvKWGPq.js → hey-api-client-DGRBsZ7Y.js} +3 -3
  34. package/dist/dist-cli-preview/chunks/hi-CTk5zGoJ.js +351 -0
  35. package/dist/dist-cli-preview/chunks/hr-DaNToqEm.js +351 -0
  36. package/dist/dist-cli-preview/chunks/hu-lcAuIwez.js +351 -0
  37. package/dist/dist-cli-preview/chunks/id-CEThcKZG.js +351 -0
  38. package/dist/dist-cli-preview/chunks/it-BCRCoDOg.js +351 -0
  39. package/dist/dist-cli-preview/chunks/ja-BIkFdIfq.js +351 -0
  40. package/dist/dist-cli-preview/chunks/ko-CD3bk6gv.js +351 -0
  41. package/dist/dist-cli-preview/chunks/{log-out-CBUq5Hd-.js → log-out-CSPZjXTK.js} +1 -1
  42. package/dist/dist-cli-preview/chunks/{map-pin-DHfjSyoR.js → map-pin-B2ScoijR.js} +1 -1
  43. package/dist/dist-cli-preview/chunks/messaging-Bq5UPkvG.js +4 -0
  44. package/dist/dist-cli-preview/chunks/{mount-account-screen-pc1VISwF.js → mount-account-screen-C_CdoGir.js} +2453 -2392
  45. package/dist/dist-cli-preview/chunks/ms-DI4mGa5X.js +351 -0
  46. package/dist/dist-cli-preview/chunks/mysite-DcpuKsuW.js +4 -0
  47. package/dist/dist-cli-preview/chunks/nl-B-XAD3Ra.js +351 -0
  48. package/dist/dist-cli-preview/chunks/no-C_NmYGbe.js +351 -0
  49. package/dist/dist-cli-preview/chunks/orders-B_57xKkq.js +4 -0
  50. package/dist/dist-cli-preview/chunks/pl-mQRzJZEW.js +351 -0
  51. package/dist/dist-cli-preview/chunks/{plus-C-lo0pFM.js → plus-CocoE5gC.js} +1 -1
  52. package/dist/dist-cli-preview/chunks/profile-BfM2KxKe.js +4 -0
  53. package/dist/dist-cli-preview/chunks/pt-BYMWPjog.js +351 -0
  54. package/dist/dist-cli-preview/chunks/ro-B98EuFQI.js +351 -0
  55. package/dist/dist-cli-preview/chunks/ru-DBO9IasC.js +351 -0
  56. package/dist/dist-cli-preview/chunks/schemas-D94nZk5x.js +5374 -0
  57. package/dist/dist-cli-preview/chunks/{screen-route-slug-utils-B254xI_J.js → screen-route-slug-utils-BDjSpDoe.js} +1 -1
  58. package/dist/dist-cli-preview/chunks/{sheet-haptics-context-D2WUiXJm.js → sheet-haptics-context-iOjKcNDj.js} +1 -1
  59. package/dist/dist-cli-preview/chunks/{sidebar-CMSWZCPS.js → sidebar-Ckzom4Xc.js} +12 -12
  60. package/dist/dist-cli-preview/chunks/sk-hRvNJfiN.js +351 -0
  61. package/dist/dist-cli-preview/chunks/{store-api-context-BIdILNWL.js → store-api-context-B96Ip2FB.js} +1 -1
  62. package/dist/dist-cli-preview/chunks/subscriptions-8VtIA4w9.js +4 -0
  63. package/dist/dist-cli-preview/chunks/sv-noYtTQbO.js +351 -0
  64. package/dist/dist-cli-preview/chunks/th-CJCAKsR-.js +351 -0
  65. package/dist/dist-cli-preview/chunks/tl-Bx8pJ7p7.js +351 -0
  66. package/dist/dist-cli-preview/chunks/tr-C4tCNiV7.js +351 -0
  67. package/dist/dist-cli-preview/chunks/{trash-2-Bq4IqH0j.js → trash-2-wVweQZMw.js} +4 -4
  68. package/dist/dist-cli-preview/chunks/uk-xFjXQDP3.js +351 -0
  69. package/dist/dist-cli-preview/chunks/{use-optional-store-Csor1Z3z.js → use-optional-store-lZUz976C.js} +2 -2
  70. package/dist/dist-cli-preview/chunks/use-store-DVmgsDXy.js +103 -0
  71. package/dist/dist-cli-preview/chunks/{useInfiniteQuery-BpFtQ7DH.js → useInfiniteQuery-Dtzov9uh.js} +1 -1
  72. package/dist/dist-cli-preview/chunks/{user-BGrQJ1GJ.js → user-B81IrSgp.js} +1 -1
  73. package/dist/dist-cli-preview/chunks/{users-DBL0isYy.js → users-BXTjoCUz.js} +1 -1
  74. package/dist/dist-cli-preview/chunks/vi-BAvhRTgb.js +351 -0
  75. package/dist/dist-cli-preview/chunks/zh_CN-Cyq9zeex.js +351 -0
  76. package/dist/dist-cli-preview/chunks/zh_TW-DFM5MhMA.js +351 -0
  77. package/dist/index.mjs +346 -32
  78. package/dist/index.mjs.map +1 -1
  79. package/dist/skills/themes-cart-feedback/SKILL.md +9 -14
  80. package/dist/skills/themes-review/SKILL.md +40 -34
  81. package/dist/skills/themes-review/references/blocks-vs-sections.md +2 -2
  82. package/dist/skills/themes-review/references/dead-code.md +1 -1
  83. package/dist/skills/themes-review/references/dynamism.md +9 -3
  84. package/dist/skills/themes-review/references/editor-attributes.md +25 -26
  85. package/dist/skills/themes-review/references/examples.md +3 -4
  86. package/dist/skills/themes-review/references/fairshare-attributes.md +5 -5
  87. package/dist/skills/themes-review/references/global-settings.md +56 -67
  88. package/dist/skills/themes-review/references/liquid-correctness.md +10 -15
  89. package/dist/skills/themes-review/references/media-tag.md +8 -7
  90. package/dist/skills/themes-review/references/navigation.md +18 -13
  91. package/dist/skills/themes-review/references/security-accessibility.md +11 -6
  92. package/dist/skills/themes-review/references/setting-types.md +136 -77
  93. package/dist/skills/themes-settings-schema/SKILL.md +15 -2
  94. package/package.json +2 -2
  95. package/dist/dist-cli-preview/chunks/OrdersScreen-d4fJE_dm.js +0 -9
  96. package/dist/dist-cli-preview/chunks/ar-B7NQmkZ1.js +0 -341
  97. package/dist/dist-cli-preview/chunks/bg-CxfL8rZN.js +0 -341
  98. package/dist/dist-cli-preview/chunks/bn-CdhHCK--.js +0 -341
  99. package/dist/dist-cli-preview/chunks/contacts-CpYlEgAq.js +0 -4
  100. package/dist/dist-cli-preview/chunks/cs-DTe-xGeI.js +0 -341
  101. package/dist/dist-cli-preview/chunks/da-B8Cl_vkl.js +0 -341
  102. package/dist/dist-cli-preview/chunks/de-D8cYy8G-.js +0 -341
  103. package/dist/dist-cli-preview/chunks/el-Chjin2JW.js +0 -341
  104. package/dist/dist-cli-preview/chunks/es-mp8RwFN4.js +0 -341
  105. package/dist/dist-cli-preview/chunks/fi-91gcpxoy.js +0 -341
  106. package/dist/dist-cli-preview/chunks/fr-ekvUCKTH.js +0 -341
  107. package/dist/dist-cli-preview/chunks/he-B7QiuquT.js +0 -341
  108. package/dist/dist-cli-preview/chunks/hi-DNNhi7ud.js +0 -341
  109. package/dist/dist-cli-preview/chunks/hr-CAwxMKX_.js +0 -341
  110. package/dist/dist-cli-preview/chunks/hu-D_oQwH4Q.js +0 -341
  111. package/dist/dist-cli-preview/chunks/id-oeAszBoo.js +0 -341
  112. package/dist/dist-cli-preview/chunks/isAfter-BUGgByEf.js +0 -1414
  113. package/dist/dist-cli-preview/chunks/it-Dme6GXSG.js +0 -341
  114. package/dist/dist-cli-preview/chunks/ja-CRnvQNCa.js +0 -341
  115. package/dist/dist-cli-preview/chunks/ko-8mk8A3_I.js +0 -341
  116. package/dist/dist-cli-preview/chunks/messaging-DkyH4CPP.js +0 -4
  117. package/dist/dist-cli-preview/chunks/ms-Bs0GvdOw.js +0 -341
  118. package/dist/dist-cli-preview/chunks/mysite-wvfITV7T.js +0 -4
  119. package/dist/dist-cli-preview/chunks/nl-tsI6lLxl.js +0 -341
  120. package/dist/dist-cli-preview/chunks/no-DMot6qX0.js +0 -341
  121. package/dist/dist-cli-preview/chunks/orders-c13r499A.js +0 -4
  122. package/dist/dist-cli-preview/chunks/pl-DmTxONNg.js +0 -341
  123. package/dist/dist-cli-preview/chunks/profile-CoWo9Sxe.js +0 -4
  124. package/dist/dist-cli-preview/chunks/pt-DgmwnAV-.js +0 -341
  125. package/dist/dist-cli-preview/chunks/ro-B4M17oRc.js +0 -341
  126. package/dist/dist-cli-preview/chunks/ru-BS2gZnbs.js +0 -341
  127. package/dist/dist-cli-preview/chunks/schemas-9_ZwC5nC.js +0 -3977
  128. package/dist/dist-cli-preview/chunks/sk-BdDjjHfn.js +0 -341
  129. package/dist/dist-cli-preview/chunks/subscriptions-BHALQrcU.js +0 -4
  130. package/dist/dist-cli-preview/chunks/sv-CW7FL5HA.js +0 -341
  131. package/dist/dist-cli-preview/chunks/th-BYBMKmSh.js +0 -341
  132. package/dist/dist-cli-preview/chunks/tl-CDigaLsK.js +0 -341
  133. package/dist/dist-cli-preview/chunks/tr-PxiurNCr.js +0 -341
  134. package/dist/dist-cli-preview/chunks/uk-B4aYnJ8t.js +0 -341
  135. package/dist/dist-cli-preview/chunks/vi-BoKSdzH3.js +0 -341
  136. package/dist/dist-cli-preview/chunks/zh_CN-DrCrXsZC.js +0 -341
  137. package/dist/dist-cli-preview/chunks/zh_TW-JmyC1W5K.js +0 -341
@@ -9,112 +9,171 @@
9
9
  - Visual & media
10
10
  - Layout
11
11
  - Organization
12
- - Resource — single
13
- - Resource — list (multiple)
12
+ - Resource — resolved by Fluid
13
+ - Resource — unresolved pickers
14
14
  - Common type mistakes — find and fix
15
15
 
16
16
 
17
- These are the canonical setting types. **Any `type:` value not in this list is rejected by the validator** (`fluid theme lint --json`).
17
+ These are the canonical setting types. **Any `type:` value not in this list is rejected by the validator** (`fluid theme lint --json`). "Saves" is what Liquid receives in `section.settings.<id>` / `block.settings.<id>`.
18
+
19
+ Section and block settings render the same control for each type, with one exception: blocks do not accept `image` (the block panel shows the word "Unknown"). Use `image_picker`. Section and block controls ignore `unit` and `placeholder`.
18
20
 
19
21
  ### Input
20
22
 
21
- | `type` | Stores | Notes |
22
- | --------------- | ----------- | --------------------------------------------------------- |
23
- | `text` | string | Single-line. |
24
- | `plaintext` | string | Single-line, no formatting allowed. |
25
- | `textarea` | string | Multi-line, no formatting. |
26
- | `richtext` | HTML string | WYSIWYG. **Render with `{{ value }}` — do not `escape`.** |
27
- | `rich_text` | HTML string | Alias for `richtext`. Prefer `richtext`. |
28
- | `html` | HTML string | Raw HTML editor. Same render rule as `richtext`. |
29
- | `html_textarea` | HTML string | Multi-line raw HTML. Same render rule. |
30
- | `url` | string | Validated URL input. |
23
+ | `type` | Saves | Notes |
24
+ | ----------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
25
+ | `plaintext` | string | Single-line input, no formatting. **The only plain-text type in section/block schemas** — use it for anything that lands in an attribute, CSS value, URL, or script. |
26
+ | `text` | HTML fragment | Compact rich-text editor: bold, italic, underline, strikethrough, links, alignment, text styles, and a variable picker. Render raw; do not `escape`. |
27
+ | `textarea`, `richtext`, `rich_text` | HTML fragment | Full rich-text editor: everything in `text` plus lists, code blocks, images, indentation. Render raw inside a block element (`<div>`, not `<p>`). |
28
+ | `html`, `html_textarea` | HTML string | Raw HTML textarea. Render raw. |
29
+ | `url` | string | URL field with a picker for store destinations (pages, products, collections, …). |
30
+
31
+ The variable picker inserts Liquid such as `{{ company.name }}` into the saved HTML; Fluid renders Liquid in saved setting values before the template reads them.
32
+
33
+ > **Global settings differ.** In `config/settings_schema.json` the Theme panel renders `text` as a **plain input** and `textarea` as a compact rich-text editor, and it has no `plaintext`. So a global `settings.<id>` of type `text` is a plain string — escape it like any other plain string. Only section and block `text` settings save HTML.
31
34
 
32
35
  ### Number & selection
33
36
 
34
- | `type` | Required extras | Notes |
35
- | ---------- | ------------------------------------- | --------------------------------------------------------------- |
36
- | `range` | `min`, `max`, `step` | Slider. Optional `unit`. |
37
- | `number` | — | Free numeric input (no slider). Prefer `range` when bounded. |
38
- | `select` | `options` array of `{ value, label }` | Dropdown. |
39
- | `radio` | `options` array of `{ value, label }` | Radio group. |
40
- | `checkbox` | — | Boolean. **Always set `default:`** so the value is never `nil`. |
37
+ | `type` | Saves | Notes |
38
+ | ---------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------- |
39
+ | `range` | number | Slider. `min`/`max`/`step` fall back to `0`/`100`/`1` when missing — always set them. |
40
+ | `number` | number, or `""` when cleared | Free numeric field. Optional `min`/`max`/`step` clamp entries. Give it a Liquid fallback (`\| default: 0`). |
41
+ | `select` | the option `value`, **as a string** | `options`: array of `{ "label", "value" }`, or an option-group ID string. |
42
+ | `radio` | the option `value`, **as a string** | Segmented buttons. Same `options` shape as `select`. |
43
+ | `checkbox` | `true` / `false` | **Always set `default:`.** |
41
44
 
42
45
  ### Visual & media
43
46
 
44
- Render `image` / `image_picker` / `video_picker` / `media_picker` values with the `media_tag` filter, not a hand-rolled `<img>`/`<video>` — see [Media rendering](media-tag.md).
45
-
46
- | `type` | Notes |
47
- | ------------------ | ----------------------------------------------------------------- |
48
- | `color` | Single color picker. |
49
- | `color_background` | Same as `color`, semantic name for fills. |
50
- | `font` | Font family. |
51
- | `font_picker` | Font family with Google Fonts + system fonts. |
52
- | `image` | Single image. |
53
- | `image_picker` | Single image. Prefer `image_picker` in new code (clearer intent). |
54
- | `video_picker` | Single video. |
55
- | `media_picker` | Image **or** video — use when both are acceptable. |
56
- | `text_alignment` | left / center / right control. |
47
+ Render `image` / `image_picker` / `video_picker` values with the `media_tag` filter, not a hand-rolled `<img>`/`<video>` — see [Media rendering](media-tag.md). A `media_picker` needs a branch: when `fluid_media_id` is positive the value is a Fluid media item, which must render as `<fluid-media-widget>` to keep its embed behavior (popover, inline shopping, CTAs); only a plain file (`fluid_media_id` `0` or absent) goes through `media_tag`. Compare with `> 0` — Liquid treats `0` as true.
48
+
49
+ | `type` | Saves | Notes |
50
+ | ----------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
51
+ | `color` | color string (`#e7f0ff`) | Section/block colors are plain strings. A global `settings.<color>` from `config/settings_schema.json` is a color value with `.rgb`, `.hue`, … |
52
+ | `color_background` | color string or `linear-gradient(...)` | **Not the same as `color`** — supports gradients. Apply with `background:`, never `background-color:`. |
53
+ | `font_picker`, `font` | the option `value` (CSS font family) | Offers the fonts in `options` (array or option group); without options, only system fonts. |
54
+ | `image_picker`, `image` | image URL string | `image` works in sections only. Prefer `image_picker`. |
55
+ | `video_picker` | video URL string | |
56
+ | `media_picker` | object `{ url, fluid_media_id, embed_type, embed_settings }` | Image **or** video plus embed options. Read `.url`. A positive `fluid_media_id` is a Fluid media item (render `<fluid-media-widget>`). |
57
+ | `text_alignment` | `left`, `center`, or `right` | Defaults to `left`. No `justify`. |
58
+
59
+ All three pickers get an editor-managed companion setting `<id>_alt` holding the alt text. Do not declare it; read it: `media_tag: alt: section.settings.<id>_alt`.
60
+
61
+ Pass the merchant's saved embed options through to the widget, or the embed ignores them. `embed_settings` can be missing, so each attribute is conditional:
62
+
63
+ | `embed_settings` key | Widget attribute |
64
+ | --- | --- |
65
+ | `autoOpen` | `auto-open="true"` |
66
+ | `width`, `height` (pixel numbers) | `width="<n>px"`, `height="<n>px"` — only when `responsive` is `false`; a responsive embed fills its container |
67
+ | `hideCta` | `cta-options-manual-override='{"type":"cart","enabled":false}'` (hides the CTA panel) |
68
+ | `responsive` | No widget attribute. The widget is responsive unless it has an explicit `width`/`height`, so a fixed-size embed is expressed by emitting the dimensions above — `responsive="false"` would be ignored |
69
+ | `fairShareVisible` | No widget attribute |
70
+
71
+ ```liquid
72
+ {%- assign media = section.settings.banner_media -%}
73
+ {%- if media != blank and media.url != blank -%}
74
+ {%- if media.fluid_media_id > 0 -%}
75
+ {%- assign embed = media.embed_settings -%}
76
+ <fluid-media-widget
77
+ media-id="{{ media.fluid_media_id }}"
78
+ embed-type="{{ media.embed_type | default: 'default' }}"
79
+ {% if embed.autoOpen %}auto-open="true"{% endif %}
80
+ {% if embed.responsive == false and embed.width != blank %}width="{{ embed.width }}px"{% endif %}
81
+ {% if embed.responsive == false and embed.height != blank %}height="{{ embed.height }}px"{% endif %}
82
+ {% if embed.hideCta %}cta-options-manual-override='{"type":"cart","enabled":false}'{% endif %}
83
+ ></fluid-media-widget>
84
+ {%- else -%}
85
+ {{ media | media_tag: alt: section.settings.banner_media_alt }}
86
+ {%- endif -%}
87
+ {%- endif -%}
88
+ ```
57
89
 
58
90
  ### Layout
59
91
 
60
- | `type` | Notes |
61
- | ------------------ | ------------------------------- |
62
- | `media_fit` | cover / contain / fill control. |
63
- | `corner_radius` | Border-radius preset. |
64
- | `padding` | Padding scale picker. |
65
- | `border` | Border preset. |
66
- | `gradient_overlay` | Gradient editor for overlays. |
92
+ | `type` | Saves | Notes |
93
+ | ------------------ | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
94
+ | `media_fit` | `width`, `height`, or `fit` | Dropdown labelled Width / Height / Fit to Media. **Not** cover/contain/fill. |
95
+ | `corner_radius` | `{ "tl", "tr", "br", "bl", "linked" }` | Each corner is a pixel number or a `var(--…)` preset reference (from the `corner_radius` group). |
96
+ | `padding` | `{ "top", "bottom", "left", "right", "verticalLinked", "horizontalLinked" }` | Each side is a pixel number or a `var(--…)` preset reference (from the `padding` group). |
97
+ | `border` | `{ "width": "2px", "color": "#d0d5dd" }` | Width includes its unit. Color can be a `color_schema` preset reference. |
98
+ | `gradient_overlay` | `{ "enabled", "mode", "gradientType", "angle", "colors": [{ "color", "opacity", "position" }] }` | `mode`: `solid`/`gradient`; `gradientType`: `linear`/`radial`; opacity and position `0`–`100`. |
67
99
 
68
- ### Organization
100
+ These are objects. **Never interpolate one directly into CSS** (`padding: {{ section.settings.padding }}` prints a hash). Read each key, and append `px` only to plain numbers:
101
+
102
+ ```liquid
103
+ {%- assign pt = section.settings.padding.top -%}
104
+ padding-top: {% if pt contains 'var' %}{{ pt }}{% else %}{{ pt | default: 0 }}px{% endif %};
105
+ ```
69
106
 
70
- | `type` | Notes |
71
- | -------- | ----------------------------------------------------- |
72
- | `header` | Settings-panel divider. No `id`. Requires `content:`. |
107
+ ### Organization
73
108
 
74
- ### Resource — single
109
+ | `type` | Notes |
110
+ | -------- | ------------------------------------------------------------------------------------------------------------- |
111
+ | `header` | Starts a collapsible group in the settings panel. No `id`. Title from `content` (or `label`). Saves nothing. |
75
112
 
76
- These pick **one** resource. Settings hold the resource object/ID.
113
+ `visible_if` (on any setting or header) hides the control in the editor only — the saved value still reaches Liquid. Syntax: `{{ section.settings.x == 'grid' }}`, with `==`, `!=`, `<`, `>`, `<=`, `>=`, `contains`, `and`/`or`, `not`, parentheses. Block settings can also read `block.settings.*`. The theme panel ignores it.
77
114
 
78
- `product`, `collection`, `category`, `blog`, `post`, `enrollment`, `enrollment_pack`, `variant`, `forms`, `media`, `link_list`
115
+ ### Resource — resolved by Fluid
79
116
 
80
- > **Naming oddity:** `products`, `collections`, `categories`, `posts`, `enrollments` also exist in the _single_ bucket of the canonical list. Read this as **legacy aliases**. Always pair "I want multiple resources" with the `_list` types below — that is the unambiguous, list-shaped contract.
117
+ Fluid turns these into Liquid objects before the template reads them. An unset or unresolvable value is an **empty object** (`[]` for `product_list`), and Liquid treats an empty object as true — guard with `!= blank`, never a bare `{% if %}`.
81
118
 
82
- ### Resource — list (multiple)
119
+ | `type` | Picker | Liquid receives |
120
+ | ----------------- | --------------------- | ----------------------------------------------------------------- |
121
+ | `product` | one product | product |
122
+ | `variant` | one variant | variant |
123
+ | `collection` | one collection | collection |
124
+ | `category` | one category | category |
125
+ | `enrollment_pack` | one enrollment pack | enrollment pack |
126
+ | `link_list` | one menu | `{ title, handle, menu_items: [{ title, url, sub_menu_items }] }` |
127
+ | `product_list` | several products | array of products |
128
+ | `media` | **no editor control** | medium (set through presets only) |
83
129
 
84
- These pick **many** resources, stored as arrays. Always require `limit:`.
130
+ ### Resource — unresolved pickers
85
131
 
86
- `product_list`, `products_list`, `collection_list`, `collections_list`, `category_list`, `categories_list`, `posts_list`, `enrollment_list`, `enrollments_list`, `blog_list`, `blogs_list`, `post_list`, `enrollment_packs_list`
132
+ These open a picker but **Liquid receives the saved ID, or an array of IDs** — no object, so `.title` / `.url` render empty.
87
133
 
88
- **Canonical names to prefer in new code:**
134
+ | `type` | Picker | Liquid receives |
135
+ | ----------------------------------------------------------------------------- | ------------------------ | ---------------------------- |
136
+ | `post`, `blog` | one post | post ID |
137
+ | `enrollment` | one enrollment pack | enrollment pack ID |
138
+ | `forms` | one form | form ID |
139
+ | `products`, `products_list` | several products | array of product IDs |
140
+ | `collections`, `collections_list`, `collection_list` | several collections | array of collection IDs |
141
+ | `categories`, `categories_list`, `category_list` | several categories | array of category IDs |
142
+ | `posts`, `posts_list`, `post_list`, `blog_list`, `blogs_list` | several posts | array of post IDs |
143
+ | `enrollments`, `enrollments_list`, `enrollment_list`, `enrollment_packs_list` | several enrollment packs | array of enrollment pack IDs |
89
144
 
90
- | Resource | Use |
91
- | ----------------------- | ----------------------- |
92
- | Products (many) | `product_list` |
93
- | Collections (many) | `collection_list` |
94
- | Categories (many) | `category_list` |
95
- | Posts (many) | `posts_list` |
96
- | Enrollments (many) | `enrollment_list` |
97
- | Enrollment packs (many) | `enrollment_packs_list` |
98
- | Blogs (many) | `blog_list` |
145
+ > **The plural types are multi-select, not aliases of the singular ones.** `products` saves an array of unresolved IDs; `product` saves one resolved product. For several resolved products use `product_list` — it is the **only** list type Fluid resolves.
99
146
 
100
- The `*s_list` variants (`products_list`, `collections_list`, etc.) exist but are duplicative — flag them as a `nit` and suggest the canonical `*_list` form.
147
+ `limit:` caps any multi-select picker.
101
148
 
102
149
  ### Common type mistakes — find and fix
103
150
 
104
- | You see | What you do |
105
- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
106
- | `type: "text_area"` | **`blocker`.** Use `textarea` (one word). |
107
- | `type: "checkBox"` / `"image_pick"` | **`blocker`.** Mistyped — replace with the exact value from the lists above. |
108
- | `type: "product_list"` without `"limit":` | **`should`** — the field saves but has no defined cap. Always set `limit:`. |
109
- | `type: "range"` without `min`/`max`/`step` | **`blocker`.** Slider UI breaks. |
110
- | `type: "select"` or `"radio"` without `options:` | **`blocker`.** Empty dropdown / radio group. |
111
- | `type: "checkbox"` without `default:` | **`should`.** Truthiness is ambiguous on first render. Set `default: false` (or `true`). |
112
- | `type: "richtext"` rendered as `{{ value | escape }}` | **`blocker`.** Double-escapes HTML — users see `&lt;p&gt;`. Render raw: `{{ value }}`. |
113
- | Setting missing `id` / duplicate `id` | **`blocker`.** The validator will reject. |
114
- | Block missing `type` or `name` | **`blocker`.** Validator rejects. (`name` may be omitted only for `@app`, `@theme`, or named-block refs.) |
115
- | `"settings": { ... }` inside a block (object, not array) | **`blocker`.** Validator rejects — must be an array. |
116
- | `{% section 'foo' %}` with no `sections/foo/index.liquid` | **`blocker`.** Validator rejects. |
117
- | 2+ singular `product` settings playing the same role | **`should`.** Collapse to one `product_list`. See [next section](#selector-heuristic--singular--list). |
118
- | `products_list` instead of `product_list` | **`nit`.** Both valid; prefer `product_list`. |
151
+ | You see | Severity | What you do |
152
+ | --- | --- | --- |
153
+ | `type: "text_area"`, `"checkBox"`, `"image_pick"` | **`blocker`** | Lint rejects it. Use the exact value from the tables above. |
154
+ | Setting with no `id` | **`blocker`** | Lint does **not** catch a missing `id` (only empty or duplicate ones), but the editor cannot save the value. Add one. |
155
+ | Duplicate `id` | **`blocker`** | Lint rejects it. |
156
+ | Section/block `text` / `textarea` / `richtext` rendered with `\| escape` | **`blocker`** | Merchants see `&lt;strong&gt;`. Render raw: `{{ value }}`. |
157
+ | Section/block `text` / `textarea` value inside an HTML attribute, CSS, URL, or `<script>` | **`blocker`** | It is HTML. Change the setting to `plaintext`. |
158
+ | Global `settings.<id>` of type `text` rendered without `\| escape` | **`blocker`** | The Theme panel's `text` is a plain input, so its value is a plain string. Escape it (there is no `plaintext` in the Theme panel). |
159
+ | `media_picker` rendered only through `media_tag` | **`blocker`** | A Fluid media item (`fluid_media_id > 0`) loses its embed. Branch to `<fluid-media-widget>` (see Visual & media). |
160
+ | `<fluid-media-widget>` for a `media_picker` that ignores `embed_settings` | **`should`** | The merchant's auto-open, size, and hide-CTA choices are dropped. Map them to widget attributes (see Visual & media). |
161
+ | `textarea` / `richtext` output wrapped in `<p>` | **`should`** | Lists and paragraphs inside `<p>` are invalid HTML. Use `<div>`. |
162
+ | Resolved resource guarded with `{% if section.settings.product %}` | **`blocker`** | Always true (empty object). Use `!= blank`. |
163
+ | `collection_list` / `category_list` / `posts_list` / … iterated as objects (`item.title`) | **`blocker`** | These hold IDs. Model each item as a block with a singular resolved setting, or look the IDs up. |
164
+ | `padding` / `corner_radius` / `border` / `gradient_overlay` interpolated whole into CSS | **`blocker`** | Prints a hash. Read the keys (see Layout). |
165
+ | `color_background` applied with `background-color:` | **`should`** | Gradients are dropped. Use `background:`. |
166
+ | `image` setting in a block schema | **`blocker`** | Renders "Unknown" in the block panel. Use `image_picker`. |
167
+ | `unit` on a section/block setting, or `placeholder` on any section/block setting | **`nit`** | Ignored by the editor. Use `info` for helper text. |
168
+ | `type: "product_list"` without `limit:` | **`should`** | Set `limit:`. |
169
+ | `type: "range"` without `min`/`max`/`step` | **`should`** | Falls back to 0–100 in steps of 1. Set real bounds. |
170
+ | `type: "select"` or `"radio"` without `options:` | **`blocker`** | Empty control. |
171
+ | `type: "checkbox"` without `default:` | **`should`** | Set `default: false` (or `true`). |
172
+ | `disabled_on` in a section schema | **`should`** | Accepted but not applied. Use `enabled_on`. |
173
+ | Block missing `type` or `name` | **`blocker`** | Lint rejects it. (`name` may be omitted only for `@app`, `@theme`, or named-block refs.) |
174
+ | `"settings": { ... }` inside a block (object, not array) | **`blocker`** | Lint rejects it — must be an array. |
175
+ | `{% section 'foo' %}` with no `sections/foo/index.liquid` | **`blocker`** | Lint rejects it. |
176
+ | 2+ singular `product` settings playing the same role | **`should`** | Collapse to one `product_list`. See [the selector heuristic](../SKILL.md#selector-heuristic--singular--list). |
177
+ | `products_list` instead of `product_list` | **`blocker`** | Not an alias: `products_list` saves unresolved IDs. Use `product_list`. |
119
178
 
120
179
  ---
@@ -44,14 +44,27 @@ The outer array is **grouped, not flat**. Each object with a `name` becomes one
44
44
  | Group `name` | Behaviour |
45
45
  | --- | --- |
46
46
  | `typography` | **The only group rendered as text-preset cards.** Any other name renders a flat list, however the settings are shaped. |
47
+ | `color_schema`, `padding`, `corner_radius` | Flat list in the panel, but their settings are the presets that section and block color, padding, radius, border, and overlay controls offer. The names must match exactly. |
47
48
  | `custom_font_sizes`, `custom_colors` | Hidden from the panel. Builder-managed — presets a merchant creates from the rich-text toolbar land here. Do not hand-author them. |
48
- | `theme_info` | Metadata only, no `settings` array. |
49
+ | `theme_info` | Not read by Fluid (a Shopify convention). The panel drops it because it has no settings. |
49
50
  | anything else | Flat list of controls, in schema order. |
50
51
 
51
52
  Two things the panel silently drops, which surprise most authors:
52
53
 
53
54
  - **A setting without a string `id`, `type` *and* `label` is discarded.** That includes every `{"type": "header", "content": "…"}` — headers render in section schemas but **not** in the Themes panel. Do not rely on them to separate groups of settings; use a real group instead.
54
- - **A group whose settings all get discarded is dropped entirely.**
55
+ - **A group whose settings all get discarded is dropped entirely.** So is any entry without a `name` — a flat array of settings renders an empty panel.
56
+
57
+ The panel renders fewer types than a section schema. Anything else shows a red **Unsupported setting type** message:
58
+
59
+ | Category | Types the theme panel renders |
60
+ | --- | --- |
61
+ | Text | `text` (plain input), `textarea` (rich text), `url` |
62
+ | Numbers and choices | `range`, `number`, `select`, `radio`, `checkbox` |
63
+ | Color | `color`, `color_background` (solid colors only here) |
64
+ | Typography | `font_picker`, `font_weight` |
65
+ | Media | `image`, `image_picker`, `video_picker`, `media_picker` |
66
+
67
+ Notably absent: `plaintext`, `font`, `html`, layout types (`padding`, `corner_radius`, …), and every resource picker. `visible_if` is ignored in the panel.
55
68
 
56
69
  ## Step 2 — Fonts and weights
57
70
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluid-app/fluid-cli-theme-dev",
3
- "version": "0.1.63",
3
+ "version": "0.1.64",
4
4
  "description": "Fluid CLI plugin for theme developer workflows — dev server, push, pull, init",
5
5
  "files": [
6
6
  "dist",
@@ -21,7 +21,7 @@
21
21
  "access": "public"
22
22
  },
23
23
  "dependencies": {
24
- "@fluid-app/fluid-cli": "0.1.34",
24
+ "@fluid-app/fluid-cli": "0.1.35",
25
25
  "chalk": "^5.6.2",
26
26
  "chokidar": "^4.0.0",
27
27
  "commander": "^12.0.0",
@@ -1,9 +0,0 @@
1
- import { j as r } from "./account-screen-runtime-DxhJm6Qd.js";
2
- import { O as e } from "./OrdersScreen-CVEl9FnN.js";
3
- import { M as o } from "./MemberManagementProviders-DMwkh3JW.js";
4
- function t() {
5
- return /* @__PURE__ */ r.jsx(o, { children: /* @__PURE__ */ r.jsx(e, {}) });
6
- }
7
- export {
8
- t as OrdersScreen
9
- };