create-smoodly-app 0.0.44 → 0.0.46

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 (387) hide show
  1. package/README.md +15 -10
  2. package/dist/index.js +75 -33
  3. package/package.json +2 -2
  4. package/templates/astro-blank/AGENTS.md +55 -0
  5. package/templates/astro-blank/CLAUDE.md +1 -0
  6. package/templates/astro-blank/README.md +88 -0
  7. package/templates/astro-blank/_gitignore +5 -0
  8. package/templates/astro-blank/astro.config.ts +15 -0
  9. package/templates/astro-blank/package.json +24 -0
  10. package/templates/astro-blank/scripts/seed.ts +80 -0
  11. package/templates/astro-blank/src/components/LocaleNav.astro +15 -0
  12. package/templates/astro-blank/src/components/elements/Button.schema.ts +22 -0
  13. package/templates/astro-blank/src/components/pages/Home.schema.ts +17 -0
  14. package/templates/astro-blank/src/components/pages/Page.schema.ts +14 -0
  15. package/templates/astro-blank/src/components/sections/Text.schema.ts +24 -0
  16. package/templates/astro-blank/src/elements/button.astro +10 -0
  17. package/templates/astro-blank/src/entry-pages/posts.astro +23 -0
  18. package/templates/astro-blank/src/layouts/Layout.astro +25 -0
  19. package/templates/astro-blank/src/live.config.ts +13 -0
  20. package/templates/astro-blank/src/page-types/home.astro +15 -0
  21. package/templates/astro-blank/src/page-types/page.astro +15 -0
  22. package/templates/astro-blank/src/pages/404.astro +7 -0
  23. package/templates/astro-blank/src/sections/text.astro +18 -0
  24. package/templates/astro-blank/src/smoodly/collections.ts +24 -0
  25. package/templates/astro-blank/src/smoodly/config.ts +28 -0
  26. package/templates/astro-blank/src/smoodly/elements.ts +5 -0
  27. package/templates/astro-blank/src/smoodly/globals.ts +18 -0
  28. package/templates/astro-blank/src/smoodly/sections.ts +5 -0
  29. package/templates/astro-blank/src/smoodly/toolsets.ts +14 -0
  30. package/templates/astro-blank/src/styles/global.css +57 -0
  31. package/templates/astro-blank/supabase/migrations/20260926120000_smoodly_v1.sql +535 -0
  32. package/templates/astro-blank/supabase/migrations/20260926130000_smoodly_v2.sql +26 -0
  33. package/templates/astro-blank/supabase/migrations/20260926140000_smoodly_v3.sql +38 -0
  34. package/templates/astro-blank/supabase/migrations/20260926150000_smoodly_v4.sql +41 -0
  35. package/templates/astro-blank/supabase/migrations/20260929120000_smoodly_v5.sql +56 -0
  36. package/templates/astro-blank/supabase/migrations/20260929135523_smoodly_v6.sql +200 -0
  37. package/templates/astro-blank/supabase/migrations/20260930040956_smoodly_v7.sql +84 -0
  38. package/templates/astro-blank/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
  39. package/templates/astro-blank/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
  40. package/templates/{blank/supabase/migrations/20260930041056_smoodly_views.sql → astro-blank/supabase/migrations/20261007200100_smoodly_views.sql} +1 -1
  41. package/templates/astro-blank/tsconfig.json +17 -0
  42. package/templates/astro-blank-intl/AGENTS.md +55 -0
  43. package/templates/astro-blank-intl/CLAUDE.md +1 -0
  44. package/templates/astro-blank-intl/README.md +89 -0
  45. package/templates/astro-blank-intl/_gitignore +5 -0
  46. package/templates/astro-blank-intl/astro.config.ts +17 -0
  47. package/templates/astro-blank-intl/package.json +24 -0
  48. package/templates/astro-blank-intl/scripts/seed.ts +80 -0
  49. package/templates/astro-blank-intl/src/components/LocaleNav.astro +15 -0
  50. package/templates/astro-blank-intl/src/components/elements/Button.schema.ts +22 -0
  51. package/templates/astro-blank-intl/src/components/pages/Home.schema.ts +17 -0
  52. package/templates/astro-blank-intl/src/components/pages/Page.schema.ts +14 -0
  53. package/templates/astro-blank-intl/src/components/sections/Text.schema.ts +24 -0
  54. package/templates/astro-blank-intl/src/elements/button.astro +10 -0
  55. package/templates/astro-blank-intl/src/entry-pages/posts.astro +23 -0
  56. package/templates/astro-blank-intl/src/layouts/Layout.astro +25 -0
  57. package/templates/astro-blank-intl/src/live.config.ts +13 -0
  58. package/templates/astro-blank-intl/src/page-types/home.astro +15 -0
  59. package/templates/astro-blank-intl/src/page-types/page.astro +15 -0
  60. package/templates/astro-blank-intl/src/pages/404.astro +7 -0
  61. package/templates/astro-blank-intl/src/sections/text.astro +18 -0
  62. package/templates/astro-blank-intl/src/smoodly/collections.ts +24 -0
  63. package/templates/astro-blank-intl/src/smoodly/config.ts +29 -0
  64. package/templates/astro-blank-intl/src/smoodly/elements.ts +5 -0
  65. package/templates/astro-blank-intl/src/smoodly/globals.ts +18 -0
  66. package/templates/astro-blank-intl/src/smoodly/sections.ts +5 -0
  67. package/templates/astro-blank-intl/src/smoodly/toolsets.ts +14 -0
  68. package/templates/astro-blank-intl/src/styles/global.css +57 -0
  69. package/templates/astro-blank-intl/supabase/migrations/20260926120000_smoodly_v1.sql +535 -0
  70. package/templates/astro-blank-intl/supabase/migrations/20260926130000_smoodly_v2.sql +26 -0
  71. package/templates/astro-blank-intl/supabase/migrations/20260926140000_smoodly_v3.sql +38 -0
  72. package/templates/astro-blank-intl/supabase/migrations/20260926150000_smoodly_v4.sql +41 -0
  73. package/templates/astro-blank-intl/supabase/migrations/20260929120000_smoodly_v5.sql +56 -0
  74. package/templates/astro-blank-intl/supabase/migrations/20260929135523_smoodly_v6.sql +200 -0
  75. package/templates/astro-blank-intl/supabase/migrations/20260930040956_smoodly_v7.sql +84 -0
  76. package/templates/astro-blank-intl/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
  77. package/templates/astro-blank-intl/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
  78. package/templates/{blank-intl/supabase/migrations/20260930041056_smoodly_views.sql → astro-blank-intl/supabase/migrations/20261007200100_smoodly_views.sql} +1 -1
  79. package/templates/astro-blank-intl/tsconfig.json +17 -0
  80. package/templates/astro-blank-intl.tsconfig.json +24 -0
  81. package/templates/astro-blank.tsconfig.json +24 -0
  82. package/templates/astro-lorem/AGENTS.md +55 -0
  83. package/templates/astro-lorem/CLAUDE.md +1 -0
  84. package/templates/astro-lorem/README.md +60 -0
  85. package/templates/astro-lorem/_gitignore +5 -0
  86. package/templates/astro-lorem/astro.config.ts +15 -0
  87. package/templates/astro-lorem/package.json +24 -0
  88. package/templates/astro-lorem/public/images/about_main.jpg +0 -0
  89. package/templates/astro-lorem/public/images/article_photo.jpg +0 -0
  90. package/templates/astro-lorem/public/images/hero_image.jpg +0 -0
  91. package/templates/astro-lorem/public/images/home_section_2.jpg +0 -0
  92. package/templates/astro-lorem/scripts/seed.ts +405 -0
  93. package/templates/astro-lorem/src/components/ArticleCard.astro +19 -0
  94. package/templates/astro-lorem/src/components/articles.ts +42 -0
  95. package/templates/astro-lorem/src/components/elements/Callout.schema.ts +24 -0
  96. package/templates/astro-lorem/src/components/elements/Cta.schema.ts +21 -0
  97. package/templates/astro-lorem/src/components/news.ts +13 -0
  98. package/templates/astro-lorem/src/components/pages/Articles.schema.ts +20 -0
  99. package/templates/astro-lorem/src/components/pages/Home.schema.ts +26 -0
  100. package/templates/astro-lorem/src/components/pages/News.schema.ts +17 -0
  101. package/templates/astro-lorem/src/components/pages/Page.schema.ts +24 -0
  102. package/templates/astro-lorem/src/components/sections/FavouriteArticles.schema.ts +17 -0
  103. package/templates/astro-lorem/src/components/sections/Footer.schema.ts +31 -0
  104. package/templates/astro-lorem/src/components/sections/Header.schema.ts +21 -0
  105. package/templates/astro-lorem/src/components/sections/Hero.schema.ts +24 -0
  106. package/templates/astro-lorem/src/components/sections/ImageText.schema.ts +30 -0
  107. package/templates/astro-lorem/src/components/sections/PageHero.schema.ts +21 -0
  108. package/templates/astro-lorem/src/components/sections/People.schema.ts +15 -0
  109. package/templates/astro-lorem/src/components/sections/Points.schema.ts +21 -0
  110. package/templates/astro-lorem/src/components/sections/Quote.schema.ts +23 -0
  111. package/templates/astro-lorem/src/elements/callout.astro +13 -0
  112. package/templates/astro-lorem/src/elements/cta.astro +15 -0
  113. package/templates/astro-lorem/src/entry-pages/articles.astro +71 -0
  114. package/templates/astro-lorem/src/entry-pages/news.astro +29 -0
  115. package/templates/astro-lorem/src/layouts/Layout.astro +39 -0
  116. package/templates/astro-lorem/src/live.config.ts +20 -0
  117. package/templates/astro-lorem/src/messages/en.json +7 -0
  118. package/templates/astro-lorem/src/messages/fi.json +7 -0
  119. package/templates/astro-lorem/src/page-types/articlesIndex.astro +24 -0
  120. package/templates/astro-lorem/src/page-types/home.astro +14 -0
  121. package/templates/astro-lorem/src/page-types/newsIndex.astro +28 -0
  122. package/templates/astro-lorem/src/page-types/page.astro +27 -0
  123. package/templates/astro-lorem/src/pages/404.astro +7 -0
  124. package/templates/astro-lorem/src/sections/favouriteArticles.astro +26 -0
  125. package/templates/astro-lorem/src/sections/footer.astro +37 -0
  126. package/templates/astro-lorem/src/sections/header.astro +27 -0
  127. package/templates/astro-lorem/src/sections/hero.astro +28 -0
  128. package/templates/astro-lorem/src/sections/imageText.astro +22 -0
  129. package/templates/astro-lorem/src/sections/pageHero.astro +20 -0
  130. package/templates/astro-lorem/src/sections/peopleSection.astro +24 -0
  131. package/templates/astro-lorem/src/sections/points.astro +33 -0
  132. package/templates/astro-lorem/src/sections/quote.astro +16 -0
  133. package/templates/astro-lorem/src/smoodly/collections.ts +63 -0
  134. package/templates/astro-lorem/src/smoodly/config.ts +48 -0
  135. package/templates/astro-lorem/src/smoodly/elements.ts +6 -0
  136. package/templates/astro-lorem/src/smoodly/globals.ts +29 -0
  137. package/templates/astro-lorem/src/smoodly/sections.ts +18 -0
  138. package/templates/astro-lorem/src/smoodly/toolsets.ts +16 -0
  139. package/templates/astro-lorem/src/strings.ts +17 -0
  140. package/templates/astro-lorem/src/styles/global.css +228 -0
  141. package/templates/astro-lorem/supabase/migrations/20260926120000_smoodly_v1.sql +535 -0
  142. package/templates/astro-lorem/supabase/migrations/20260926130000_smoodly_v2.sql +26 -0
  143. package/templates/astro-lorem/supabase/migrations/20260926140000_smoodly_v3.sql +38 -0
  144. package/templates/astro-lorem/supabase/migrations/20260926150000_smoodly_v4.sql +41 -0
  145. package/templates/astro-lorem/supabase/migrations/20260929120000_smoodly_v5.sql +56 -0
  146. package/templates/astro-lorem/supabase/migrations/20260929135523_smoodly_v6.sql +200 -0
  147. package/templates/astro-lorem/supabase/migrations/20260930040956_smoodly_v7.sql +84 -0
  148. package/templates/astro-lorem/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
  149. package/templates/astro-lorem/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
  150. package/templates/{lorem/supabase/migrations/20260930041056_smoodly_views.sql → astro-lorem/supabase/migrations/20261007200100_smoodly_views.sql} +1 -1
  151. package/templates/astro-lorem/tsconfig.json +17 -0
  152. package/templates/astro-lorem-intl/AGENTS.md +55 -0
  153. package/templates/astro-lorem-intl/CLAUDE.md +1 -0
  154. package/templates/astro-lorem-intl/README.md +62 -0
  155. package/templates/astro-lorem-intl/_gitignore +5 -0
  156. package/templates/astro-lorem-intl/astro.config.ts +17 -0
  157. package/templates/astro-lorem-intl/package.json +24 -0
  158. package/templates/astro-lorem-intl/public/images/about_main.jpg +0 -0
  159. package/templates/astro-lorem-intl/public/images/article_photo.jpg +0 -0
  160. package/templates/astro-lorem-intl/public/images/hero_image.jpg +0 -0
  161. package/templates/astro-lorem-intl/public/images/home_section_2.jpg +0 -0
  162. package/templates/astro-lorem-intl/scripts/seed.ts +405 -0
  163. package/templates/astro-lorem-intl/src/components/ArticleCard.astro +19 -0
  164. package/templates/astro-lorem-intl/src/components/articles.ts +42 -0
  165. package/templates/astro-lorem-intl/src/components/elements/Callout.schema.ts +24 -0
  166. package/templates/astro-lorem-intl/src/components/elements/Cta.schema.ts +21 -0
  167. package/templates/astro-lorem-intl/src/components/news.ts +13 -0
  168. package/templates/astro-lorem-intl/src/components/pages/Articles.schema.ts +20 -0
  169. package/templates/astro-lorem-intl/src/components/pages/Home.schema.ts +26 -0
  170. package/templates/astro-lorem-intl/src/components/pages/News.schema.ts +17 -0
  171. package/templates/astro-lorem-intl/src/components/pages/Page.schema.ts +24 -0
  172. package/templates/astro-lorem-intl/src/components/sections/FavouriteArticles.schema.ts +17 -0
  173. package/templates/astro-lorem-intl/src/components/sections/Footer.schema.ts +31 -0
  174. package/templates/astro-lorem-intl/src/components/sections/Header.schema.ts +21 -0
  175. package/templates/astro-lorem-intl/src/components/sections/Hero.schema.ts +24 -0
  176. package/templates/astro-lorem-intl/src/components/sections/ImageText.schema.ts +30 -0
  177. package/templates/astro-lorem-intl/src/components/sections/PageHero.schema.ts +21 -0
  178. package/templates/astro-lorem-intl/src/components/sections/People.schema.ts +15 -0
  179. package/templates/astro-lorem-intl/src/components/sections/Points.schema.ts +21 -0
  180. package/templates/astro-lorem-intl/src/components/sections/Quote.schema.ts +23 -0
  181. package/templates/astro-lorem-intl/src/elements/callout.astro +13 -0
  182. package/templates/astro-lorem-intl/src/elements/cta.astro +15 -0
  183. package/templates/astro-lorem-intl/src/entry-pages/articles.astro +71 -0
  184. package/templates/astro-lorem-intl/src/entry-pages/news.astro +29 -0
  185. package/templates/astro-lorem-intl/src/layouts/Layout.astro +39 -0
  186. package/templates/astro-lorem-intl/src/live.config.ts +20 -0
  187. package/templates/astro-lorem-intl/src/messages/en.json +7 -0
  188. package/templates/astro-lorem-intl/src/messages/fi.json +7 -0
  189. package/templates/astro-lorem-intl/src/page-types/articlesIndex.astro +24 -0
  190. package/templates/astro-lorem-intl/src/page-types/home.astro +14 -0
  191. package/templates/astro-lorem-intl/src/page-types/newsIndex.astro +28 -0
  192. package/templates/astro-lorem-intl/src/page-types/page.astro +27 -0
  193. package/templates/astro-lorem-intl/src/pages/404.astro +7 -0
  194. package/templates/astro-lorem-intl/src/sections/favouriteArticles.astro +26 -0
  195. package/templates/astro-lorem-intl/src/sections/footer.astro +37 -0
  196. package/templates/astro-lorem-intl/src/sections/header.astro +27 -0
  197. package/templates/astro-lorem-intl/src/sections/hero.astro +28 -0
  198. package/templates/astro-lorem-intl/src/sections/imageText.astro +22 -0
  199. package/templates/astro-lorem-intl/src/sections/pageHero.astro +20 -0
  200. package/templates/astro-lorem-intl/src/sections/peopleSection.astro +24 -0
  201. package/templates/astro-lorem-intl/src/sections/points.astro +33 -0
  202. package/templates/astro-lorem-intl/src/sections/quote.astro +16 -0
  203. package/templates/astro-lorem-intl/src/smoodly/collections.ts +63 -0
  204. package/templates/astro-lorem-intl/src/smoodly/config.ts +48 -0
  205. package/templates/astro-lorem-intl/src/smoodly/elements.ts +6 -0
  206. package/templates/astro-lorem-intl/src/smoodly/globals.ts +29 -0
  207. package/templates/astro-lorem-intl/src/smoodly/sections.ts +18 -0
  208. package/templates/astro-lorem-intl/src/smoodly/toolsets.ts +16 -0
  209. package/templates/astro-lorem-intl/src/strings.ts +17 -0
  210. package/templates/astro-lorem-intl/src/styles/global.css +228 -0
  211. package/templates/astro-lorem-intl/supabase/migrations/20260926120000_smoodly_v1.sql +535 -0
  212. package/templates/astro-lorem-intl/supabase/migrations/20260926130000_smoodly_v2.sql +26 -0
  213. package/templates/astro-lorem-intl/supabase/migrations/20260926140000_smoodly_v3.sql +38 -0
  214. package/templates/astro-lorem-intl/supabase/migrations/20260926150000_smoodly_v4.sql +41 -0
  215. package/templates/astro-lorem-intl/supabase/migrations/20260929120000_smoodly_v5.sql +56 -0
  216. package/templates/astro-lorem-intl/supabase/migrations/20260929135523_smoodly_v6.sql +200 -0
  217. package/templates/astro-lorem-intl/supabase/migrations/20260930040956_smoodly_v7.sql +84 -0
  218. package/templates/astro-lorem-intl/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
  219. package/templates/astro-lorem-intl/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
  220. package/templates/{lorem-intl/supabase/migrations/20260930041056_smoodly_views.sql → astro-lorem-intl/supabase/migrations/20261007200100_smoodly_views.sql} +1 -1
  221. package/templates/astro-lorem-intl/tsconfig.json +17 -0
  222. package/templates/astro-lorem-intl.tsconfig.json +24 -0
  223. package/templates/astro-lorem.tsconfig.json +24 -0
  224. package/templates/blank/AGENTS.md +23 -16
  225. package/templates/blank/README.md +20 -15
  226. package/templates/blank/app/(smoodly)/admin/[[...segments]]/route.ts +8 -0
  227. package/templates/blank/components/elements/Button.schema.ts +22 -0
  228. package/templates/blank/components/elements/Button.tsx +2 -20
  229. package/templates/blank/components/pages/Home.schema.ts +17 -0
  230. package/templates/blank/components/pages/Home.tsx +2 -16
  231. package/templates/blank/components/pages/Page.schema.ts +14 -0
  232. package/templates/blank/components/pages/Page.tsx +2 -14
  233. package/templates/blank/components/pages/Post.tsx +5 -4
  234. package/templates/blank/components/sections/Text.schema.ts +24 -0
  235. package/templates/blank/components/sections/Text.tsx +7 -27
  236. package/templates/blank/package.json +1 -1
  237. package/templates/blank/scripts/seed.ts +2 -2
  238. package/templates/blank/smoodly/config.ts +8 -7
  239. package/templates/blank/smoodly/elements.ts +4 -4
  240. package/templates/blank/smoodly/globals.ts +4 -2
  241. package/templates/blank/smoodly/richtext.tsx +4 -5
  242. package/templates/blank/smoodly/sections.ts +4 -4
  243. package/templates/blank/smoodly/server.ts +22 -44
  244. package/templates/blank/smoodly/toolsets.ts +2 -2
  245. package/templates/blank/smoodly/views.ts +15 -0
  246. package/templates/blank/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
  247. package/templates/blank/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
  248. package/templates/blank/supabase/migrations/20261007200100_smoodly_views.sql +20 -0
  249. package/templates/blank-intl/AGENTS.md +23 -16
  250. package/templates/blank-intl/README.md +20 -15
  251. package/templates/blank-intl/app/(smoodly)/admin/[[...segments]]/route.ts +8 -0
  252. package/templates/blank-intl/components/elements/Button.schema.ts +22 -0
  253. package/templates/blank-intl/components/elements/Button.tsx +2 -20
  254. package/templates/blank-intl/components/pages/Home.schema.ts +17 -0
  255. package/templates/blank-intl/components/pages/Home.tsx +2 -16
  256. package/templates/blank-intl/components/pages/Page.schema.ts +14 -0
  257. package/templates/blank-intl/components/pages/Page.tsx +2 -14
  258. package/templates/blank-intl/components/pages/Post.tsx +5 -4
  259. package/templates/blank-intl/components/sections/Text.schema.ts +24 -0
  260. package/templates/blank-intl/components/sections/Text.tsx +7 -27
  261. package/templates/blank-intl/package.json +1 -1
  262. package/templates/blank-intl/scripts/seed.ts +2 -2
  263. package/templates/blank-intl/smoodly/config.ts +8 -7
  264. package/templates/blank-intl/smoodly/elements.ts +4 -4
  265. package/templates/blank-intl/smoodly/globals.ts +4 -2
  266. package/templates/blank-intl/smoodly/richtext.tsx +4 -5
  267. package/templates/blank-intl/smoodly/sections.ts +4 -4
  268. package/templates/blank-intl/smoodly/server.ts +22 -44
  269. package/templates/blank-intl/smoodly/toolsets.ts +2 -2
  270. package/templates/blank-intl/smoodly/views.ts +15 -0
  271. package/templates/blank-intl/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
  272. package/templates/blank-intl/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
  273. package/templates/blank-intl/supabase/migrations/20261007200100_smoodly_views.sql +20 -0
  274. package/templates/lorem/AGENTS.md +23 -16
  275. package/templates/lorem/README.md +3 -3
  276. package/templates/lorem/app/(smoodly)/admin/[[...segments]]/route.ts +8 -0
  277. package/templates/lorem/components/elements/Callout.schema.ts +24 -0
  278. package/templates/lorem/components/elements/Callout.tsx +2 -24
  279. package/templates/lorem/components/elements/Cta.schema.ts +21 -0
  280. package/templates/lorem/components/elements/Cta.tsx +2 -21
  281. package/templates/lorem/components/pages/Article.tsx +1 -1
  282. package/templates/lorem/components/pages/Articles.schema.ts +20 -0
  283. package/templates/lorem/components/pages/Articles.tsx +2 -20
  284. package/templates/lorem/components/pages/Home.schema.ts +26 -0
  285. package/templates/lorem/components/pages/Home.tsx +2 -26
  286. package/templates/lorem/components/pages/News.schema.ts +17 -0
  287. package/templates/lorem/components/pages/News.tsx +2 -17
  288. package/templates/lorem/components/pages/NewsPost.tsx +1 -1
  289. package/templates/lorem/components/pages/Page.schema.ts +24 -0
  290. package/templates/lorem/components/pages/Page.tsx +2 -24
  291. package/templates/lorem/components/sections/FavouriteArticles.schema.ts +17 -0
  292. package/templates/lorem/components/sections/FavouriteArticles.tsx +2 -17
  293. package/templates/lorem/components/sections/Footer.schema.ts +31 -0
  294. package/templates/lorem/components/sections/Footer.tsx +4 -32
  295. package/templates/lorem/components/sections/Header.schema.ts +21 -0
  296. package/templates/lorem/components/sections/Header.tsx +2 -21
  297. package/templates/lorem/components/sections/Hero.schema.ts +24 -0
  298. package/templates/lorem/components/sections/Hero.tsx +2 -24
  299. package/templates/lorem/components/sections/ImageText.schema.ts +30 -0
  300. package/templates/lorem/components/sections/ImageText.tsx +2 -30
  301. package/templates/lorem/components/sections/PageHero.schema.ts +21 -0
  302. package/templates/lorem/components/sections/PageHero.tsx +2 -21
  303. package/templates/lorem/components/sections/People.schema.ts +15 -0
  304. package/templates/lorem/components/sections/People.tsx +2 -14
  305. package/templates/lorem/components/sections/Points.schema.ts +21 -0
  306. package/templates/lorem/components/sections/Points.tsx +2 -21
  307. package/templates/lorem/components/sections/Quote.schema.ts +23 -0
  308. package/templates/lorem/components/sections/Quote.tsx +2 -23
  309. package/templates/lorem/package.json +1 -1
  310. package/templates/lorem/scripts/seed.ts +18 -18
  311. package/templates/lorem/smoodly/collections.ts +2 -2
  312. package/templates/lorem/smoodly/config.ts +14 -15
  313. package/templates/lorem/smoodly/elements.ts +5 -5
  314. package/templates/lorem/smoodly/globals.ts +10 -7
  315. package/templates/lorem/smoodly/richtext.tsx +5 -5
  316. package/templates/lorem/smoodly/sections.ts +12 -13
  317. package/templates/lorem/smoodly/server.ts +22 -44
  318. package/templates/lorem/smoodly/toolsets.ts +3 -3
  319. package/templates/lorem/smoodly/views.ts +33 -0
  320. package/templates/lorem/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
  321. package/templates/lorem/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
  322. package/templates/lorem/supabase/migrations/20261007200100_smoodly_views.sql +58 -0
  323. package/templates/lorem-intl/AGENTS.md +23 -16
  324. package/templates/lorem-intl/README.md +3 -3
  325. package/templates/lorem-intl/app/(smoodly)/admin/[[...segments]]/route.ts +8 -0
  326. package/templates/lorem-intl/components/elements/Callout.schema.ts +24 -0
  327. package/templates/lorem-intl/components/elements/Callout.tsx +2 -24
  328. package/templates/lorem-intl/components/elements/Cta.schema.ts +21 -0
  329. package/templates/lorem-intl/components/elements/Cta.tsx +2 -21
  330. package/templates/lorem-intl/components/pages/Article.tsx +1 -1
  331. package/templates/lorem-intl/components/pages/Articles.schema.ts +20 -0
  332. package/templates/lorem-intl/components/pages/Articles.tsx +2 -20
  333. package/templates/lorem-intl/components/pages/Home.schema.ts +26 -0
  334. package/templates/lorem-intl/components/pages/Home.tsx +2 -26
  335. package/templates/lorem-intl/components/pages/News.schema.ts +17 -0
  336. package/templates/lorem-intl/components/pages/News.tsx +2 -17
  337. package/templates/lorem-intl/components/pages/NewsPost.tsx +1 -1
  338. package/templates/lorem-intl/components/pages/Page.schema.ts +24 -0
  339. package/templates/lorem-intl/components/pages/Page.tsx +2 -24
  340. package/templates/lorem-intl/components/sections/FavouriteArticles.schema.ts +17 -0
  341. package/templates/lorem-intl/components/sections/FavouriteArticles.tsx +2 -17
  342. package/templates/lorem-intl/components/sections/Footer.schema.ts +31 -0
  343. package/templates/lorem-intl/components/sections/Footer.tsx +4 -32
  344. package/templates/lorem-intl/components/sections/Header.schema.ts +21 -0
  345. package/templates/lorem-intl/components/sections/Header.tsx +2 -21
  346. package/templates/lorem-intl/components/sections/Hero.schema.ts +24 -0
  347. package/templates/lorem-intl/components/sections/Hero.tsx +2 -24
  348. package/templates/lorem-intl/components/sections/ImageText.schema.ts +30 -0
  349. package/templates/lorem-intl/components/sections/ImageText.tsx +2 -30
  350. package/templates/lorem-intl/components/sections/PageHero.schema.ts +21 -0
  351. package/templates/lorem-intl/components/sections/PageHero.tsx +2 -21
  352. package/templates/lorem-intl/components/sections/People.schema.ts +15 -0
  353. package/templates/lorem-intl/components/sections/People.tsx +2 -14
  354. package/templates/lorem-intl/components/sections/Points.schema.ts +21 -0
  355. package/templates/lorem-intl/components/sections/Points.tsx +2 -21
  356. package/templates/lorem-intl/components/sections/Quote.schema.ts +23 -0
  357. package/templates/lorem-intl/components/sections/Quote.tsx +2 -23
  358. package/templates/lorem-intl/package.json +1 -1
  359. package/templates/lorem-intl/scripts/seed.ts +18 -18
  360. package/templates/lorem-intl/smoodly/collections.ts +2 -2
  361. package/templates/lorem-intl/smoodly/config.ts +14 -15
  362. package/templates/lorem-intl/smoodly/elements.ts +5 -5
  363. package/templates/lorem-intl/smoodly/globals.ts +10 -7
  364. package/templates/lorem-intl/smoodly/richtext.tsx +5 -5
  365. package/templates/lorem-intl/smoodly/sections.ts +12 -13
  366. package/templates/lorem-intl/smoodly/server.ts +22 -44
  367. package/templates/lorem-intl/smoodly/toolsets.ts +3 -3
  368. package/templates/lorem-intl/smoodly/views.ts +33 -0
  369. package/templates/lorem-intl/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
  370. package/templates/lorem-intl/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
  371. package/templates/lorem-intl/supabase/migrations/20261007200100_smoodly_views.sql +58 -0
  372. package/templates/blank/app/(smoodly)/admin/[[...segments]]/page.tsx +0 -1
  373. package/templates/blank/app/(smoodly)/admin/layout.tsx +0 -15
  374. package/templates/blank/smoodly/admin.tsx +0 -6
  375. package/templates/blank/smoodly/ops.ts +0 -11
  376. package/templates/blank-intl/app/(smoodly)/admin/[[...segments]]/page.tsx +0 -1
  377. package/templates/blank-intl/app/(smoodly)/admin/layout.tsx +0 -15
  378. package/templates/blank-intl/smoodly/admin.tsx +0 -6
  379. package/templates/blank-intl/smoodly/ops.ts +0 -11
  380. package/templates/lorem/app/(smoodly)/admin/[[...segments]]/page.tsx +0 -1
  381. package/templates/lorem/app/(smoodly)/admin/layout.tsx +0 -15
  382. package/templates/lorem/smoodly/admin.tsx +0 -6
  383. package/templates/lorem/smoodly/ops.ts +0 -11
  384. package/templates/lorem-intl/app/(smoodly)/admin/[[...segments]]/page.tsx +0 -1
  385. package/templates/lorem-intl/app/(smoodly)/admin/layout.tsx +0 -15
  386. package/templates/lorem-intl/smoodly/admin.tsx +0 -6
  387. package/templates/lorem-intl/smoodly/ops.ts +0 -11
@@ -1,24 +1,5 @@
1
- import { f, smoodly, type Props } from "smoodly";
2
-
3
- // A heading over one to six points, each an icon, a heading and a line
4
- // of text: the list field with min/max, and an object inside the list.
5
- export const pointsSchema = smoodly.schema.section({
6
- name: "points",
7
- title: "Points",
8
- description: "A heading and one to six points with an icon each.",
9
- fields: {
10
- heading: f.text(),
11
- points: f.list(f.object({
12
- icon: f.select([{ value: "circle", label: "Circle" }, { value: "square", label: "Square" }, { value: "diamond", label: "Diamond" }]),
13
- heading: f.text(),
14
- text: f.text(),
15
- })).min(1).max(6),
16
- },
17
- sample: {
18
- heading: "Quis autem vel eum",
19
- points: [{ icon: "circle", heading: "Iure reprehenderit", text: "Qui in ea voluptate velit esse quam nihil molestiae consequatur." }],
20
- },
21
- });
1
+ import { smoodly, type Props } from "smoodly/react";
2
+ import { pointsSchema } from "./Points.schema";
22
3
 
23
4
  const ICONS = {
24
5
  circle: <circle cx="20" cy="20" r="18" />,
@@ -0,0 +1,23 @@
1
+ import { f, smoodly } from "smoodly";
2
+
3
+ // A pull quote. Registered as a global item (smoodly/globals.ts): one row
4
+ // edited under Global content, placed on pages from the "+" picker's
5
+ // Global group as a linked node. The body zones also list it, because
6
+ // the picker offers a global item only where the zone allows its
7
+ // section — so an editor may also drop a one-off quote.
8
+ export const quoteSchema = smoodly.schema.section({
9
+ name: "quote",
10
+ title: "Quote",
11
+ description: "A pull quote with its attribution.",
12
+ fields: {
13
+ text: f.text().localized(),
14
+ attribution: f.text().localized(),
15
+ },
16
+ settings: {
17
+ background: f.radio([{ value: "paper", label: "Paper" }, { value: "ink", label: "Ink" }]).default("paper"),
18
+ },
19
+ sample: {
20
+ text: "Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit.",
21
+ attribution: "Jane Doe, Founder",
22
+ },
23
+ });
@@ -1,26 +1,5 @@
1
- import { f, smoodly, type Props } from "smoodly";
2
-
3
- // A pull quote. Registered as a global item (smoodly/globals.ts): one row
4
- // edited under Global content, placed on pages from the "+" picker's
5
- // Global group as a linked node. The body zones also list it, because
6
- // the picker offers a global item only where the zone allows its
7
- // section — so an editor may also drop a one-off quote.
8
- export const quoteSchema = smoodly.schema.section({
9
- name: "quote",
10
- title: "Quote",
11
- description: "A pull quote with its attribution.",
12
- fields: {
13
- text: f.text().localized(),
14
- attribution: f.text().localized(),
15
- },
16
- settings: {
17
- background: f.radio([{ value: "paper", label: "Paper" }, { value: "ink", label: "Ink" }]).default("paper"),
18
- },
19
- sample: {
20
- text: "Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit.",
21
- attribution: "Jane Doe, Founder",
22
- },
23
- });
1
+ import { smoodly, type Props } from "smoodly/react";
2
+ import { quoteSchema } from "./Quote.schema";
24
3
 
25
4
  const m = smoodly.marks(quoteSchema);
26
5
 
@@ -14,7 +14,7 @@
14
14
  "next": "^16.3.4",
15
15
  "react": "^19",
16
16
  "react-dom": "^19",
17
- "smoodly": "0.0.44"
17
+ "smoodly": "0.0.46"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@next/env": "^16.3.4",
@@ -24,12 +24,12 @@ loadEnvConfig(process.cwd());
24
24
  const { config } = await import("../smoodly/config");
25
25
  const { articles, news } = await import("../smoodly/collections");
26
26
  const { content, href, node } = await import("../smoodly/server");
27
- const { Hero } = await import("../components/sections/Hero");
28
- const { PageHero } = await import("../components/sections/PageHero");
29
- const { ImageText } = await import("../components/sections/ImageText");
30
- const { Points } = await import("../components/sections/Points");
31
- const { FavouriteArticles } = await import("../components/sections/FavouriteArticles");
32
- const { People } = await import("../components/sections/People");
27
+ const { heroSchema } = await import("../components/sections/Hero.schema");
28
+ const { pageHeroSchema } = await import("../components/sections/PageHero.schema");
29
+ const { imageTextSchema } = await import("../components/sections/ImageText.schema");
30
+ const { pointsSchema } = await import("../components/sections/Points.schema");
31
+ const { favouriteArticlesSchema } = await import("../components/sections/FavouriteArticles.schema");
32
+ const { peopleSchema } = await import("../components/sections/People.schema");
33
33
  const c = content();
34
34
 
35
35
  const EN = config.locales.default;
@@ -262,7 +262,7 @@ const quote: TreeNode = { id: "node-quote", type: "global", fields: { item: "quo
262
262
 
263
263
  // --- pages ----------------------------------------------------------
264
264
 
265
- const imageText = (locale: string, linkLabel: string) => node(ImageText, {
265
+ const imageText = (locale: string, linkLabel: string) => node(imageTextSchema, {
266
266
  image: img.home2,
267
267
  heading: "Duis aute irure dolor in reprehenderit",
268
268
  text: doc(
@@ -273,7 +273,7 @@ const imageText = (locale: string, linkLabel: string) => node(ImageText, {
273
273
  }, { id: "node-intro", settings: { imageSide: "left" } });
274
274
 
275
275
  const points: TreeNode = {
276
- ...node(Points, {
276
+ ...node(pointsSchema, {
277
277
  heading: "Quis autem vel eum",
278
278
  points: [
279
279
  { icon: "circle", heading: "Iure reprehenderit", text: "Qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat." },
@@ -285,7 +285,7 @@ const points: TreeNode = {
285
285
  styles: { spacingBottom: "lg" },
286
286
  };
287
287
 
288
- const favourites = (heading: string) => node(FavouriteArticles, { heading, items: [article.id] }, { id: "node-favourites" });
288
+ const favourites = (heading: string) => node(favouriteArticlesSchema, { heading, items: [article.id] }, { id: "node-favourites" });
289
289
 
290
290
  // The custom section (spec 2026-09-14 §6): the editor's own rows of
291
291
  // richtext columns, widths in twelfths; Smoodly renders its layout CSS.
@@ -309,7 +309,7 @@ const homeTree = (locale: string, t: { kicker: string; buttons: [string, string]
309
309
  zones: {
310
310
  // The locked hero's one node. Pages created in the admin get theirs
311
311
  // from the editor (fillLockedZones on load); a seeded tree brings its own.
312
- hero: [node(Hero, {
312
+ hero: [node(heroSchema, {
313
313
  kicker: t.kicker,
314
314
  heading: "Consectetur adipiscing elit sed do eiusmod",
315
315
  text: "Tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip.",
@@ -332,7 +332,7 @@ await seedCodePage("/", {
332
332
  // so the mount in the Pages list opens this page. Only a hero; the grid
333
333
  // is the view's own fetch.
334
334
  const articlesHero = (heading: string, text: string): Tree => ({
335
- zones: { hero: [node(PageHero, { heading, text }, { id: "node-articles-hero" })] },
335
+ zones: { hero: [node(pageHeroSchema, { heading, text }, { id: "node-articles-hero" })] },
336
336
  });
337
337
  await seedCodePage(`/${articlesSegment(EN)}`, {
338
338
  en: articlesHero("Articles", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt."),
@@ -348,22 +348,22 @@ const company = await seedPage({ slug: "company", title: "Company", template: nu
348
348
  // address (spec 2026-09-29 nested paths §3) — it shows under Company in
349
349
  // URL only; renaming Company never moves it.
350
350
  await seedCodePage(`/${newsAddress(EN)}`, {
351
- en: { zones: { hero: [node(PageHero, { heading: "News", text: "Lorem ipsum dolor sit amet — what is new at Lorem Co." }, { id: "node-news-hero" })] } },
352
- fi: { zones: { hero: [node(PageHero, { heading: "Uutiset", text: "Lorem ipsum dolor sit amet — mitä Lorem Co:lle kuuluu." }, { id: "node-news-hero" })] } },
351
+ en: { zones: { hero: [node(pageHeroSchema, { heading: "News", text: "Lorem ipsum dolor sit amet — what is new at Lorem Co." }, { id: "node-news-hero" })] } },
352
+ fi: { zones: { hero: [node(pageHeroSchema, { heading: "Uutiset", text: "Lorem ipsum dolor sit amet — mitä Lorem Co:lle kuuluu." }, { id: "node-news-hero" })] } },
353
353
  });
354
354
 
355
355
  const aboutTree = (t: { kicker: string; people: string; description: string }): Tree => ({
356
356
  fields: { showInNavigation: true },
357
357
  meta: { description: t.description },
358
358
  zones: {
359
- hero: [node(PageHero, {
359
+ hero: [node(pageHeroSchema, {
360
360
  kicker: t.kicker,
361
361
  heading: "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
362
362
  text: "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
363
363
  image: img.about,
364
364
  }, { id: "node-about-hero" })],
365
365
  body: [
366
- node(ImageText, {
366
+ node(imageTextSchema, {
367
367
  heading: "Duis aute irure dolor in reprehenderit",
368
368
  text: doc(
369
369
  p("In voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."),
@@ -372,7 +372,7 @@ const aboutTree = (t: { kicker: string; people: string; description: string }):
372
372
  ),
373
373
  }, { id: "node-about-text", settings: { imageSide: "left" } }),
374
374
  quote,
375
- node(People, { heading: t.people, people: [jane.id, john.id, anna.id, mark.id] }, { id: "node-people" }),
375
+ node(peopleSchema, { heading: t.people, people: [jane.id, john.id, anna.id, mark.id] }, { id: "node-people" }),
376
376
  ],
377
377
  },
378
378
  });
@@ -390,8 +390,8 @@ const teamTree = (t: { heading: string; text: string; people: string }): Tree =>
390
390
  fields: { showInNavigation: true },
391
391
  meta: { description: t.text },
392
392
  zones: {
393
- hero: [node(PageHero, { kicker: t.heading, heading: t.heading, text: t.text, image: img.about }, { id: "node-team-hero" })],
394
- body: [node(People, { heading: t.people, people: [jane.id, john.id, anna.id, mark.id] }, { id: "node-team-people" })],
393
+ hero: [node(pageHeroSchema, { kicker: t.heading, heading: t.heading, text: t.text, image: img.about }, { id: "node-team-hero" })],
394
+ body: [node(peopleSchema, { heading: t.people, people: [jane.id, john.id, anna.id, mark.id] }, { id: "node-team-people" })],
395
395
  },
396
396
  });
397
397
  await seedPage(
@@ -16,7 +16,7 @@ export const people = smoodly.collection({
16
16
  });
17
17
 
18
18
  // Articles are served at a path that is per locale — /posts/<slug> and
19
- // /fi/artikkelit/<slug> — and the Articles fixed page (components/pages/Articles.tsx) claims the same
19
+ // /fi/artikkelit/<slug> — and the Articles fixed page claims the same
20
20
  // segments, which makes it the collection's index page. Tags are f.tags(),
21
21
  // localized as a whole, so the Finnish row carries Finnish tags.
22
22
  export const articles = smoodly.collection({
@@ -42,7 +42,7 @@ export const articles = smoodly.collection({
42
42
  // News lives under the company: a nested address, owned by code whole
43
43
  // (spec 2026-09-29 nested paths). The Company page at /company is an
44
44
  // editor's page; renaming it never moves the news. The News fixed page
45
- // (components/pages/News.tsx) claims the same address, which makes it
45
+ // claims the same address, which makes it
46
46
  // the collection's index page.
47
47
  export const news = smoodly.collection({
48
48
  name: "news",
@@ -4,19 +4,17 @@ import { sections } from "./sections";
4
4
  import { globals } from "./globals";
5
5
  import { elements } from "./elements";
6
6
  import { article } from "./toolsets";
7
- import { RichText } from "./richtext";
8
- import { HomePage } from "@/components/pages/Home";
9
- import { ArticlesPage } from "@/components/pages/Articles";
10
- import { StandardPage } from "@/components/pages/Page";
11
- import { ArticlePage } from "@/components/pages/Article";
12
- import { NewsPage } from "@/components/pages/News";
13
- import { NewsPostPage } from "@/components/pages/NewsPost";
7
+ import { homeSchema } from "@/components/pages/Home.schema";
8
+ import { articlesSchema } from "@/components/pages/Articles.schema";
9
+ import { pageSchema } from "@/components/pages/Page.schema";
10
+ import { newsSchema } from "@/components/pages/News.schema";
14
11
 
15
12
  export { collections, sections, globals, elements };
16
13
 
17
- // The registry and the plain settings, one file. Runtime-free: nothing
18
- // here imports a route file or Next, so a script, the CLI's template
19
- // build and (later) the MCP server can load it outside the app.
14
+ // The registry of schemas and the plain settings, one file. It imports
15
+ // no component, no route file and no Next API, so a script, the CLI and
16
+ // (later) an MCP server can load it outside the app; smoodly/views.ts
17
+ // lists the components that render these schemas.
20
18
  export const config = defineConfig({
21
19
  registry: {
22
20
  sections,
@@ -24,7 +22,8 @@ export const config = defineConfig({
24
22
  elements,
25
23
  collections,
26
24
  globals,
27
- pages: [HomePage, ArticlesPage, StandardPage, ArticlePage, NewsPage, NewsPostPage],
25
+ // Page types. The entry pages are views: smoodly/views.ts lists them.
26
+ pages: [homeSchema, articlesSchema, pageSchema, newsSchema],
28
27
  },
29
28
  locales: { default: "en", supported: ["en"] },
30
29
  // Editors pick dates and times in this zone; the views format with it (an IANA name, never an offset).
@@ -34,7 +33,7 @@ export const config = defineConfig({
34
33
  // Nesting on: an editor can put pages three deep.
35
34
  pages: { tree: { depth: 3 } },
36
35
  // Smoodly's styles set (spacing, width, align) renders inline from
37
- // these CSS values; app/globals.css defines the variables per
36
+ // these CSS values; the site's stylesheet defines the variables per
38
37
  // breakpoint. Default stores nothing — a section looks as written.
39
38
  styles: {
40
39
  spacing: { sm: "var(--space-sm)", md: "var(--space-md)", lg: "var(--space-lg)" },
@@ -44,7 +43,7 @@ export const config = defineConfig({
44
43
  css: true,
45
44
  // The custom section (spec 2026-09-14 §6): the editor's own rows of
46
45
  // columns. The columns take the article toolset (headings, lists,
47
- // images, Callout and Cta) and render through the bound RichText, so
48
- // body images go through next/image like everywhere else.
49
- custom: { toolset: article, RichText },
46
+ // images, Callout and Cta); smoodly/views.ts binds the RichText that
47
+ // renders them, so body images go through next/image like everywhere else.
48
+ custom: { toolset: article },
50
49
  });
@@ -1,6 +1,6 @@
1
- // The site's element registrations, in one list: the config registers
2
- // them, toolsets embed them by value, and smoodly/richtext.tsx renders them.
3
- import { Callout } from "@/components/elements/Callout";
4
- import { Cta } from "@/components/elements/Cta";
1
+ // The element schemas a richtext body may embed; smoodly/views.ts lists
2
+ // the components that render them.
3
+ import { calloutSchema } from "@/components/elements/Callout.schema";
4
+ import { ctaSchema } from "@/components/elements/Cta.schema";
5
5
 
6
- export const elements = [Callout, Cta];
6
+ export const elements = [calloutSchema, ctaSchema];
@@ -1,15 +1,17 @@
1
1
  // Global content (spec 2026-09-07): code-declared singletons stored as
2
2
  // entries. `header` and `footer` are visual — the layout renders them;
3
3
  // `contact` is an object the footer reads through the layout; `quote` is
4
- // visual and placed on pages from the picker's Global group.
4
+ // visual and placed on pages from the picker's Global group. The three
5
+ // the layout renders on every page are `layout: true`: they come with
6
+ // the page's own read, so the layout's reads cost no database call.
5
7
  import { f, smoodly } from "smoodly";
6
- import { Header } from "@/components/sections/Header";
7
- import { Footer } from "@/components/sections/Footer";
8
- import { Quote } from "@/components/sections/Quote";
8
+ import { headerSchema } from "@/components/sections/Header.schema";
9
+ import { footerSchema } from "@/components/sections/Footer.schema";
10
+ import { quoteSchema } from "@/components/sections/Quote.schema";
9
11
 
10
- export const header = smoodly.global({ name: "header", title: "Header", section: Header });
12
+ export const header = smoodly.global({ name: "header", title: "Header", section: headerSchema, layout: true });
11
13
 
12
- export const footer = smoodly.global({ name: "footer", title: "Footer", section: Footer });
14
+ export const footer = smoodly.global({ name: "footer", title: "Footer", section: footerSchema, layout: true });
13
15
 
14
16
  export const contact = smoodly.global({
15
17
  name: "contact",
@@ -19,8 +21,9 @@ export const contact = smoodly.global({
19
21
  phone: f.text().optional(),
20
22
  address: f.text().localized(),
21
23
  },
24
+ layout: true,
22
25
  });
23
26
 
24
- export const quote = smoodly.global({ name: "quote", title: "Quote", section: Quote });
27
+ export const quote = smoodly.global({ name: "quote", title: "Quote", section: quoteSchema });
25
28
 
26
29
  export const globals = [header, footer, contact, quote];
@@ -1,7 +1,7 @@
1
- // The site's richtext renderer, bound once: it knows the elements a body
2
- // may embed and renders body images through <SmoodlyImage>. Sections and
3
- // entry pages import RichText from here, never from the package root.
1
+ // The site's bound RichText: the element components a body may embed,
2
+ // images through <SmoodlyImage>.
4
3
  import { createRichText } from "smoodly/richtext";
5
- import { elements } from "./elements";
4
+ import { Callout } from "@/components/elements/Callout";
5
+ import { Cta } from "@/components/elements/Cta";
6
6
 
7
- export const RichText = createRichText({ elements, sizes: "(min-width: 900px) 720px, 100vw" });
7
+ export const RichText = createRichText({ elements: [Callout, Cta], sizes: "(min-width: 900px) 720px, 100vw" });
@@ -1,19 +1,18 @@
1
- // The site's section registrations, in one list. config.ts puts it
2
- // in the registry and re-exports it, so the config, the stores (which walk
3
- // trees against these schemas) and the renderer all share one array.
1
+ // The site's section schemas, in one list. config.ts puts it in the
2
+ // registry; smoodly/views.ts lists the components that render them.
4
3
  // Header and Footer are here because their global items render through
5
4
  // them; no zone lists them, so the "+" picker never offers them. Quote
6
5
  // is both: its global item renders through it, and the body zones list
7
6
  // it so the global quote can be placed (the picker offers a global item
8
7
  // only where its section is allowed).
9
- import { Hero } from "@/components/sections/Hero";
10
- import { PageHero } from "@/components/sections/PageHero";
11
- import { ImageText } from "@/components/sections/ImageText";
12
- import { Points } from "@/components/sections/Points";
13
- import { FavouriteArticles } from "@/components/sections/FavouriteArticles";
14
- import { People } from "@/components/sections/People";
15
- import { Quote } from "@/components/sections/Quote";
16
- import { Header } from "@/components/sections/Header";
17
- import { Footer } from "@/components/sections/Footer";
8
+ import { heroSchema } from "@/components/sections/Hero.schema";
9
+ import { pageHeroSchema } from "@/components/sections/PageHero.schema";
10
+ import { imageTextSchema } from "@/components/sections/ImageText.schema";
11
+ import { pointsSchema } from "@/components/sections/Points.schema";
12
+ import { favouriteArticlesSchema } from "@/components/sections/FavouriteArticles.schema";
13
+ import { peopleSchema } from "@/components/sections/People.schema";
14
+ import { quoteSchema } from "@/components/sections/Quote.schema";
15
+ import { headerSchema } from "@/components/sections/Header.schema";
16
+ import { footerSchema } from "@/components/sections/Footer.schema";
18
17
 
19
- export const sections = [Hero, PageHero, ImageText, Points, FavouriteArticles, People, Quote, Header, Footer];
18
+ export const sections = [heroSchema, pageHeroSchema, imageTextSchema, pointsSchema, favouriteArticlesSchema, peopleSchema, quoteSchema, headerSchema, footerSchema];
@@ -5,22 +5,22 @@
5
5
  // SMOODLY_PUBLISHABLE_KEY (the `smoodlyEnv("admin")` calls below); whether the
6
6
  // secret is a service-role key or a cloud write key is invisible here.
7
7
  //
8
- // Lazy on purpose, the site and renderer included: config.ts imports the
9
- // page shapes, and a page shape may import this file to read through
10
- // `q` (components/pages/Articles.tsx). That is a cycle, and the
11
- // admin route enters it from config.ts — so nothing here may read the
12
- // config at module scope.
8
+ // Lazy on purpose: a page component imports this file to read through
9
+ // `q` (components/pages/Articles.tsx), and this file imports the
10
+ // components through ./views. That is a cycle, so nothing here reads
11
+ // views() or the env at module scope.
13
12
  import {
14
- createSmoodlyClient, createSmoodlySite, presenceConfig, smoodlyEnv, SupabaseAssetStore, SupabaseEntryStore, SupabaseMemberStore, SupabasePageStore, SupabasePathIndex, type PresenceConfig, type SmoodlySite,
13
+ createSmoodlyClient, createSmoodlySite, createSupabaseStores, presenceConfig, siteOptions, smoodlyEnv,
14
+ type PresenceConfig, type SmoodlySite, type SupabaseAssetStore, type SupabaseEntryStore, type SupabaseMemberStore, type SupabasePageStore,
15
15
  } from "smoodly";
16
- // The admin gate from `smoodly/admin`, which holds no client code: the site
17
- // routes import this file, and `smoodly/admin/next` would put the admin
18
- // shell in every live page's JavaScript.
16
+ // The admin's server pieces: the sign-in check and the content API. No browser code lives in the package's
17
+ // entries; the admin itself is prebuilt and served by app/(smoodly)/admin/[[...segments]]/route.ts.
19
18
  import { createSmoodlyContent, supabaseAdminAuth, type AdminAuth, type AuthConfig, type SmoodlyContent } from "smoodly/admin";
20
- import { createPageRenderer, createSmoodlyQueries, type PageRegistration } from "smoodly/next";
19
+ import { createPageRenderer, createSmoodlyQueries } from "smoodly/next";
21
20
  import { connection } from "next/server";
22
21
  import type { SupabaseClient } from "@supabase/supabase-js";
23
- import { collections, config, elements, sections, globals } from "./config";
22
+ import { collections, config, globals } from "./config";
23
+ import { views } from "./views";
24
24
 
25
25
  type Renderer = ReturnType<typeof createPageRenderer>;
26
26
  type Queries = ReturnType<typeof createSmoodlyQueries<typeof collections, typeof globals>>;
@@ -34,49 +34,27 @@ function bound(): Bound {
34
34
  if (cached) return cached;
35
35
  const env = smoodlyEnv();
36
36
  const db = createSmoodlyClient(env);
37
- // ONE path index for both stores: pages and entries share the URL space.
38
- // The index reads the code-owned addresses from the config (spec 2026-09-29 anchored paths §2).
39
- const paths = new SupabasePathIndex(db, config.anchors);
40
- const locales = config.locales;
41
- const entries = new SupabaseEntryStore(db, collections, { paths, locales, globals, elements });
42
- const pages = new SupabasePageStore(db, {
43
- sections, elements, entries, paths, locales,
44
- // The custom section's columns toolset, so a column's images count as usage (spec 2026-09-14 §6).
45
- custom: config.custom,
46
- homePageSlug: config.homePageSlug,
47
- // Code-owned addresses by owner: a fixed page's or a collection's path (spec 2026-09-29 nested paths §3).
48
- addresses: config.addresses,
49
- tree: config.pages?.tree,
50
- });
51
- // The media library: rows in `assets`, bytes in the public `media` bucket.
52
- const assets = new SupabaseAssetStore(db);
53
- // The admission table, read by the Members page (spec 2026-09-25 §4).
54
- const members = new SupabaseMemberStore(db);
37
+ // The stores, read off the config: pages, entries, the media library and the admission table.
38
+ const { pages, entries, assets, members, published } = createSupabaseStores(db, config);
55
39
  const auth = supabaseAdminAuth({ authUrl: env.authUrl, authKey: env.authKey, db });
56
- // The site layer's own view of the stores; nothing outside this file reads them.
57
- const stores = () => ({ pages, entries, assets });
58
40
  // The site layer: (locale, path) → page or entry, and the content API
59
41
  // `q` wraps below. Not exported — the app reads through `q`, which adds
60
42
  // draft awareness and the cache.
61
- const site = createSmoodlySite({ stores, collections, globals, sections, elements, locales, homePageSlug: config.homePageSlug, styles: config.styles, custom: config.custom, pages: config.registry.pages ?? [] });
62
- const renderer = createPageRenderer({
63
- site,
64
- sections,
65
- elements,
66
- pages: (config.registry.pages ?? []) as PageRegistration[],
67
- href,
68
- });
43
+ const site = createSmoodlySite(siteOptions(config, () => ({ pages, entries, assets, published })));
44
+ // The components, checked against the config's schemas here, on first use.
45
+ const renderer = createPageRenderer({ site, ...views(), href });
69
46
  // The read API (spec 2026-09-11): typed by the registry, draft-aware, cached under tags the admin expires.
70
47
  const q = createSmoodlyQueries({ site, collections, globals });
71
48
  cached = { db, pages, entries, assets, members, auth, site, renderer, q };
72
49
  return cached;
73
50
  }
74
51
 
75
- /** The admin's wiring, for `smoodly/ops.ts` only. Scripts write through `content()`. */
52
+ /** The admin's wiring, for the admin route only. Scripts write through `content()`. */
76
53
  export function adminDeps() {
77
54
  smoodlyEnv("admin"); // the admin signs in with the publishable key: a missing one is named here, not on a live page
78
- const { pages, entries, assets, members, auth } = bound();
79
- return { pages, entries, assets, members, auth, href };
55
+ const { pages, entries, assets, members, auth, site } = bound();
56
+ // The projector: a publish writes the finished documents a live page reads.
57
+ return { pages, entries, assets, members, auth, href, projector: site.projector };
80
58
  }
81
59
 
82
60
  /** Write content from code — seeds, migrations, route handlers (spec 2026-09-30 tester findings §1).
@@ -84,8 +62,8 @@ export function adminDeps() {
84
62
  * throws `SmoodlyContentError`. `content().pages.create(…)`, `.entries.create(…)`, `.globals.set(…)`,
85
63
  * `.media.upload(…)`; build tree nodes with `node(Section, fields)`. */
86
64
  export function content(): SmoodlyContent {
87
- const { pages, entries, assets, members } = bound();
88
- return createSmoodlyContent({ config, pages, entries, assets, members, href });
65
+ const { pages, entries, assets, members, site } = bound();
66
+ return createSmoodlyContent({ config, pages, entries, assets, members, href, projector: site.projector });
89
67
  }
90
68
 
91
69
  export { node } from "smoodly";
@@ -6,11 +6,11 @@
6
6
  // template build, which runs outside the app where the `@/` alias has
7
7
  // no mapping.
8
8
  import { smoodly } from "smoodly";
9
- import { Callout } from "../components/elements/Callout";
10
- import { Cta } from "../components/elements/Cta";
9
+ import { calloutSchema } from "../components/elements/Callout.schema";
10
+ import { ctaSchema } from "../components/elements/Cta.schema";
11
11
 
12
12
  export const article = smoodly.toolset({
13
13
  marks: ["bold", "italic", "link"],
14
14
  nodes: ["h2", "h3", "h4", "bulletList", "orderedList", "blockquote", "image"],
15
- elements: [Callout, Cta],
15
+ elements: [calloutSchema, ctaSchema],
16
16
  });
@@ -0,0 +1,33 @@
1
+ // The components that render the registered schemas. A function, not a
2
+ // value: a page component imports smoodly/server.ts, which imports this
3
+ // file, so the list must not be read while those modules are still
4
+ // loading. defineViews names a schema with no component, and a component
5
+ // with no schema, the first time the site renders.
6
+ import { defineViews } from "smoodly/react";
7
+ import { config } from "./config";
8
+ import { RichText } from "./richtext";
9
+ import { Hero } from "@/components/sections/Hero";
10
+ import { PageHero } from "@/components/sections/PageHero";
11
+ import { ImageText } from "@/components/sections/ImageText";
12
+ import { Points } from "@/components/sections/Points";
13
+ import { FavouriteArticles } from "@/components/sections/FavouriteArticles";
14
+ import { People } from "@/components/sections/People";
15
+ import { Quote } from "@/components/sections/Quote";
16
+ import { Header } from "@/components/sections/Header";
17
+ import { Footer } from "@/components/sections/Footer";
18
+ import { Callout } from "@/components/elements/Callout";
19
+ import { Cta } from "@/components/elements/Cta";
20
+ import { HomePage } from "@/components/pages/Home";
21
+ import { ArticlesPage } from "@/components/pages/Articles";
22
+ import { StandardPage } from "@/components/pages/Page";
23
+ import { ArticlePage } from "@/components/pages/Article";
24
+ import { NewsPage } from "@/components/pages/News";
25
+ import { NewsPostPage } from "@/components/pages/NewsPost";
26
+
27
+ export const views = () =>
28
+ defineViews(config, {
29
+ sections: [Hero, PageHero, ImageText, Points, FavouriteArticles, People, Quote, Header, Footer],
30
+ elements: [Callout, Cta],
31
+ pages: [HomePage, ArticlesPage, StandardPage, ArticlePage, NewsPage, NewsPostPage],
32
+ RichText,
33
+ });