create-smoodly-app 0.0.45 → 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.
- package/README.md +15 -10
- package/dist/index.js +75 -33
- package/package.json +2 -2
- package/templates/astro-blank/AGENTS.md +55 -0
- package/templates/astro-blank/CLAUDE.md +1 -0
- package/templates/astro-blank/README.md +88 -0
- package/templates/astro-blank/_gitignore +5 -0
- package/templates/astro-blank/astro.config.ts +15 -0
- package/templates/astro-blank/package.json +24 -0
- package/templates/astro-blank/scripts/seed.ts +80 -0
- package/templates/astro-blank/src/components/LocaleNav.astro +15 -0
- package/templates/astro-blank/src/components/elements/Button.schema.ts +22 -0
- package/templates/astro-blank/src/components/pages/Home.schema.ts +17 -0
- package/templates/astro-blank/src/components/pages/Page.schema.ts +14 -0
- package/templates/astro-blank/src/components/sections/Text.schema.ts +24 -0
- package/templates/astro-blank/src/elements/button.astro +10 -0
- package/templates/astro-blank/src/entry-pages/posts.astro +23 -0
- package/templates/astro-blank/src/layouts/Layout.astro +25 -0
- package/templates/astro-blank/src/live.config.ts +13 -0
- package/templates/astro-blank/src/page-types/home.astro +15 -0
- package/templates/astro-blank/src/page-types/page.astro +15 -0
- package/templates/astro-blank/src/pages/404.astro +7 -0
- package/templates/astro-blank/src/sections/text.astro +18 -0
- package/templates/astro-blank/src/smoodly/collections.ts +24 -0
- package/templates/astro-blank/src/smoodly/config.ts +28 -0
- package/templates/astro-blank/src/smoodly/elements.ts +5 -0
- package/templates/astro-blank/src/smoodly/globals.ts +18 -0
- package/templates/astro-blank/src/smoodly/sections.ts +5 -0
- package/templates/astro-blank/src/smoodly/toolsets.ts +14 -0
- package/templates/astro-blank/src/styles/global.css +57 -0
- package/templates/astro-blank/supabase/migrations/20260926120000_smoodly_v1.sql +535 -0
- package/templates/astro-blank/supabase/migrations/20260926130000_smoodly_v2.sql +26 -0
- package/templates/astro-blank/supabase/migrations/20260926140000_smoodly_v3.sql +38 -0
- package/templates/astro-blank/supabase/migrations/20260926150000_smoodly_v4.sql +41 -0
- package/templates/astro-blank/supabase/migrations/20260929120000_smoodly_v5.sql +56 -0
- package/templates/astro-blank/supabase/migrations/20260929135523_smoodly_v6.sql +200 -0
- package/templates/astro-blank/supabase/migrations/20260930040956_smoodly_v7.sql +84 -0
- package/templates/astro-blank/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
- package/templates/astro-blank/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
- package/templates/{blank/supabase/migrations/20260930041056_smoodly_views.sql → astro-blank/supabase/migrations/20261007200100_smoodly_views.sql} +1 -1
- package/templates/astro-blank/tsconfig.json +17 -0
- package/templates/astro-blank-intl/AGENTS.md +55 -0
- package/templates/astro-blank-intl/CLAUDE.md +1 -0
- package/templates/astro-blank-intl/README.md +89 -0
- package/templates/astro-blank-intl/_gitignore +5 -0
- package/templates/astro-blank-intl/astro.config.ts +17 -0
- package/templates/astro-blank-intl/package.json +24 -0
- package/templates/astro-blank-intl/scripts/seed.ts +80 -0
- package/templates/astro-blank-intl/src/components/LocaleNav.astro +15 -0
- package/templates/astro-blank-intl/src/components/elements/Button.schema.ts +22 -0
- package/templates/astro-blank-intl/src/components/pages/Home.schema.ts +17 -0
- package/templates/astro-blank-intl/src/components/pages/Page.schema.ts +14 -0
- package/templates/astro-blank-intl/src/components/sections/Text.schema.ts +24 -0
- package/templates/astro-blank-intl/src/elements/button.astro +10 -0
- package/templates/astro-blank-intl/src/entry-pages/posts.astro +23 -0
- package/templates/astro-blank-intl/src/layouts/Layout.astro +25 -0
- package/templates/astro-blank-intl/src/live.config.ts +13 -0
- package/templates/astro-blank-intl/src/page-types/home.astro +15 -0
- package/templates/astro-blank-intl/src/page-types/page.astro +15 -0
- package/templates/astro-blank-intl/src/pages/404.astro +7 -0
- package/templates/astro-blank-intl/src/sections/text.astro +18 -0
- package/templates/astro-blank-intl/src/smoodly/collections.ts +24 -0
- package/templates/astro-blank-intl/src/smoodly/config.ts +29 -0
- package/templates/astro-blank-intl/src/smoodly/elements.ts +5 -0
- package/templates/astro-blank-intl/src/smoodly/globals.ts +18 -0
- package/templates/astro-blank-intl/src/smoodly/sections.ts +5 -0
- package/templates/astro-blank-intl/src/smoodly/toolsets.ts +14 -0
- package/templates/astro-blank-intl/src/styles/global.css +57 -0
- package/templates/astro-blank-intl/supabase/migrations/20260926120000_smoodly_v1.sql +535 -0
- package/templates/astro-blank-intl/supabase/migrations/20260926130000_smoodly_v2.sql +26 -0
- package/templates/astro-blank-intl/supabase/migrations/20260926140000_smoodly_v3.sql +38 -0
- package/templates/astro-blank-intl/supabase/migrations/20260926150000_smoodly_v4.sql +41 -0
- package/templates/astro-blank-intl/supabase/migrations/20260929120000_smoodly_v5.sql +56 -0
- package/templates/astro-blank-intl/supabase/migrations/20260929135523_smoodly_v6.sql +200 -0
- package/templates/astro-blank-intl/supabase/migrations/20260930040956_smoodly_v7.sql +84 -0
- package/templates/astro-blank-intl/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
- package/templates/astro-blank-intl/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
- package/templates/{blank-intl/supabase/migrations/20260930041056_smoodly_views.sql → astro-blank-intl/supabase/migrations/20261007200100_smoodly_views.sql} +1 -1
- package/templates/astro-blank-intl/tsconfig.json +17 -0
- package/templates/astro-blank-intl.tsconfig.json +24 -0
- package/templates/astro-blank.tsconfig.json +24 -0
- package/templates/astro-lorem/AGENTS.md +55 -0
- package/templates/astro-lorem/CLAUDE.md +1 -0
- package/templates/astro-lorem/README.md +60 -0
- package/templates/astro-lorem/_gitignore +5 -0
- package/templates/astro-lorem/astro.config.ts +15 -0
- package/templates/astro-lorem/package.json +24 -0
- package/templates/astro-lorem/public/images/about_main.jpg +0 -0
- package/templates/astro-lorem/public/images/article_photo.jpg +0 -0
- package/templates/astro-lorem/public/images/hero_image.jpg +0 -0
- package/templates/astro-lorem/public/images/home_section_2.jpg +0 -0
- package/templates/astro-lorem/scripts/seed.ts +405 -0
- package/templates/astro-lorem/src/components/ArticleCard.astro +19 -0
- package/templates/astro-lorem/src/components/articles.ts +42 -0
- package/templates/astro-lorem/src/components/elements/Callout.schema.ts +24 -0
- package/templates/astro-lorem/src/components/elements/Cta.schema.ts +21 -0
- package/templates/astro-lorem/src/components/news.ts +13 -0
- package/templates/astro-lorem/src/components/pages/Articles.schema.ts +20 -0
- package/templates/astro-lorem/src/components/pages/Home.schema.ts +26 -0
- package/templates/astro-lorem/src/components/pages/News.schema.ts +17 -0
- package/templates/astro-lorem/src/components/pages/Page.schema.ts +24 -0
- package/templates/astro-lorem/src/components/sections/FavouriteArticles.schema.ts +17 -0
- package/templates/astro-lorem/src/components/sections/Footer.schema.ts +31 -0
- package/templates/astro-lorem/src/components/sections/Header.schema.ts +21 -0
- package/templates/astro-lorem/src/components/sections/Hero.schema.ts +24 -0
- package/templates/astro-lorem/src/components/sections/ImageText.schema.ts +30 -0
- package/templates/astro-lorem/src/components/sections/PageHero.schema.ts +21 -0
- package/templates/astro-lorem/src/components/sections/People.schema.ts +15 -0
- package/templates/astro-lorem/src/components/sections/Points.schema.ts +21 -0
- package/templates/astro-lorem/src/components/sections/Quote.schema.ts +23 -0
- package/templates/astro-lorem/src/elements/callout.astro +13 -0
- package/templates/astro-lorem/src/elements/cta.astro +15 -0
- package/templates/astro-lorem/src/entry-pages/articles.astro +71 -0
- package/templates/astro-lorem/src/entry-pages/news.astro +29 -0
- package/templates/astro-lorem/src/layouts/Layout.astro +39 -0
- package/templates/astro-lorem/src/live.config.ts +20 -0
- package/templates/astro-lorem/src/messages/en.json +7 -0
- package/templates/astro-lorem/src/messages/fi.json +7 -0
- package/templates/astro-lorem/src/page-types/articlesIndex.astro +24 -0
- package/templates/astro-lorem/src/page-types/home.astro +14 -0
- package/templates/astro-lorem/src/page-types/newsIndex.astro +28 -0
- package/templates/astro-lorem/src/page-types/page.astro +27 -0
- package/templates/astro-lorem/src/pages/404.astro +7 -0
- package/templates/astro-lorem/src/sections/favouriteArticles.astro +26 -0
- package/templates/astro-lorem/src/sections/footer.astro +37 -0
- package/templates/astro-lorem/src/sections/header.astro +27 -0
- package/templates/astro-lorem/src/sections/hero.astro +28 -0
- package/templates/astro-lorem/src/sections/imageText.astro +22 -0
- package/templates/astro-lorem/src/sections/pageHero.astro +20 -0
- package/templates/astro-lorem/src/sections/peopleSection.astro +24 -0
- package/templates/astro-lorem/src/sections/points.astro +33 -0
- package/templates/astro-lorem/src/sections/quote.astro +16 -0
- package/templates/astro-lorem/src/smoodly/collections.ts +63 -0
- package/templates/astro-lorem/src/smoodly/config.ts +48 -0
- package/templates/astro-lorem/src/smoodly/elements.ts +6 -0
- package/templates/astro-lorem/src/smoodly/globals.ts +29 -0
- package/templates/astro-lorem/src/smoodly/sections.ts +18 -0
- package/templates/astro-lorem/src/smoodly/toolsets.ts +16 -0
- package/templates/astro-lorem/src/strings.ts +17 -0
- package/templates/astro-lorem/src/styles/global.css +228 -0
- package/templates/astro-lorem/supabase/migrations/20260926120000_smoodly_v1.sql +535 -0
- package/templates/astro-lorem/supabase/migrations/20260926130000_smoodly_v2.sql +26 -0
- package/templates/astro-lorem/supabase/migrations/20260926140000_smoodly_v3.sql +38 -0
- package/templates/astro-lorem/supabase/migrations/20260926150000_smoodly_v4.sql +41 -0
- package/templates/astro-lorem/supabase/migrations/20260929120000_smoodly_v5.sql +56 -0
- package/templates/astro-lorem/supabase/migrations/20260929135523_smoodly_v6.sql +200 -0
- package/templates/astro-lorem/supabase/migrations/20260930040956_smoodly_v7.sql +84 -0
- package/templates/astro-lorem/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
- package/templates/astro-lorem/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
- package/templates/{lorem/supabase/migrations/20260930041056_smoodly_views.sql → astro-lorem/supabase/migrations/20261007200100_smoodly_views.sql} +1 -1
- package/templates/astro-lorem/tsconfig.json +17 -0
- package/templates/astro-lorem-intl/AGENTS.md +55 -0
- package/templates/astro-lorem-intl/CLAUDE.md +1 -0
- package/templates/astro-lorem-intl/README.md +62 -0
- package/templates/astro-lorem-intl/_gitignore +5 -0
- package/templates/astro-lorem-intl/astro.config.ts +17 -0
- package/templates/astro-lorem-intl/package.json +24 -0
- package/templates/astro-lorem-intl/public/images/about_main.jpg +0 -0
- package/templates/astro-lorem-intl/public/images/article_photo.jpg +0 -0
- package/templates/astro-lorem-intl/public/images/hero_image.jpg +0 -0
- package/templates/astro-lorem-intl/public/images/home_section_2.jpg +0 -0
- package/templates/astro-lorem-intl/scripts/seed.ts +405 -0
- package/templates/astro-lorem-intl/src/components/ArticleCard.astro +19 -0
- package/templates/astro-lorem-intl/src/components/articles.ts +42 -0
- package/templates/astro-lorem-intl/src/components/elements/Callout.schema.ts +24 -0
- package/templates/astro-lorem-intl/src/components/elements/Cta.schema.ts +21 -0
- package/templates/astro-lorem-intl/src/components/news.ts +13 -0
- package/templates/astro-lorem-intl/src/components/pages/Articles.schema.ts +20 -0
- package/templates/astro-lorem-intl/src/components/pages/Home.schema.ts +26 -0
- package/templates/astro-lorem-intl/src/components/pages/News.schema.ts +17 -0
- package/templates/astro-lorem-intl/src/components/pages/Page.schema.ts +24 -0
- package/templates/astro-lorem-intl/src/components/sections/FavouriteArticles.schema.ts +17 -0
- package/templates/astro-lorem-intl/src/components/sections/Footer.schema.ts +31 -0
- package/templates/astro-lorem-intl/src/components/sections/Header.schema.ts +21 -0
- package/templates/astro-lorem-intl/src/components/sections/Hero.schema.ts +24 -0
- package/templates/astro-lorem-intl/src/components/sections/ImageText.schema.ts +30 -0
- package/templates/astro-lorem-intl/src/components/sections/PageHero.schema.ts +21 -0
- package/templates/astro-lorem-intl/src/components/sections/People.schema.ts +15 -0
- package/templates/astro-lorem-intl/src/components/sections/Points.schema.ts +21 -0
- package/templates/astro-lorem-intl/src/components/sections/Quote.schema.ts +23 -0
- package/templates/astro-lorem-intl/src/elements/callout.astro +13 -0
- package/templates/astro-lorem-intl/src/elements/cta.astro +15 -0
- package/templates/astro-lorem-intl/src/entry-pages/articles.astro +71 -0
- package/templates/astro-lorem-intl/src/entry-pages/news.astro +29 -0
- package/templates/astro-lorem-intl/src/layouts/Layout.astro +39 -0
- package/templates/astro-lorem-intl/src/live.config.ts +20 -0
- package/templates/astro-lorem-intl/src/messages/en.json +7 -0
- package/templates/astro-lorem-intl/src/messages/fi.json +7 -0
- package/templates/astro-lorem-intl/src/page-types/articlesIndex.astro +24 -0
- package/templates/astro-lorem-intl/src/page-types/home.astro +14 -0
- package/templates/astro-lorem-intl/src/page-types/newsIndex.astro +28 -0
- package/templates/astro-lorem-intl/src/page-types/page.astro +27 -0
- package/templates/astro-lorem-intl/src/pages/404.astro +7 -0
- package/templates/astro-lorem-intl/src/sections/favouriteArticles.astro +26 -0
- package/templates/astro-lorem-intl/src/sections/footer.astro +37 -0
- package/templates/astro-lorem-intl/src/sections/header.astro +27 -0
- package/templates/astro-lorem-intl/src/sections/hero.astro +28 -0
- package/templates/astro-lorem-intl/src/sections/imageText.astro +22 -0
- package/templates/astro-lorem-intl/src/sections/pageHero.astro +20 -0
- package/templates/astro-lorem-intl/src/sections/peopleSection.astro +24 -0
- package/templates/astro-lorem-intl/src/sections/points.astro +33 -0
- package/templates/astro-lorem-intl/src/sections/quote.astro +16 -0
- package/templates/astro-lorem-intl/src/smoodly/collections.ts +63 -0
- package/templates/astro-lorem-intl/src/smoodly/config.ts +48 -0
- package/templates/astro-lorem-intl/src/smoodly/elements.ts +6 -0
- package/templates/astro-lorem-intl/src/smoodly/globals.ts +29 -0
- package/templates/astro-lorem-intl/src/smoodly/sections.ts +18 -0
- package/templates/astro-lorem-intl/src/smoodly/toolsets.ts +16 -0
- package/templates/astro-lorem-intl/src/strings.ts +17 -0
- package/templates/astro-lorem-intl/src/styles/global.css +228 -0
- package/templates/astro-lorem-intl/supabase/migrations/20260926120000_smoodly_v1.sql +535 -0
- package/templates/astro-lorem-intl/supabase/migrations/20260926130000_smoodly_v2.sql +26 -0
- package/templates/astro-lorem-intl/supabase/migrations/20260926140000_smoodly_v3.sql +38 -0
- package/templates/astro-lorem-intl/supabase/migrations/20260926150000_smoodly_v4.sql +41 -0
- package/templates/astro-lorem-intl/supabase/migrations/20260929120000_smoodly_v5.sql +56 -0
- package/templates/astro-lorem-intl/supabase/migrations/20260929135523_smoodly_v6.sql +200 -0
- package/templates/astro-lorem-intl/supabase/migrations/20260930040956_smoodly_v7.sql +84 -0
- package/templates/astro-lorem-intl/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
- package/templates/astro-lorem-intl/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
- package/templates/{lorem-intl/supabase/migrations/20260930041056_smoodly_views.sql → astro-lorem-intl/supabase/migrations/20261007200100_smoodly_views.sql} +1 -1
- package/templates/astro-lorem-intl/tsconfig.json +17 -0
- package/templates/astro-lorem-intl.tsconfig.json +24 -0
- package/templates/astro-lorem.tsconfig.json +24 -0
- package/templates/blank/AGENTS.md +23 -16
- package/templates/blank/README.md +20 -15
- package/templates/blank/app/(smoodly)/admin/[[...segments]]/route.ts +8 -0
- package/templates/blank/components/elements/Button.schema.ts +22 -0
- package/templates/blank/components/elements/Button.tsx +2 -20
- package/templates/blank/components/pages/Home.schema.ts +17 -0
- package/templates/blank/components/pages/Home.tsx +2 -16
- package/templates/blank/components/pages/Page.schema.ts +14 -0
- package/templates/blank/components/pages/Page.tsx +2 -14
- package/templates/blank/components/pages/Post.tsx +5 -4
- package/templates/blank/components/sections/Text.schema.ts +24 -0
- package/templates/blank/components/sections/Text.tsx +7 -27
- package/templates/blank/package.json +1 -1
- package/templates/blank/scripts/seed.ts +2 -2
- package/templates/blank/smoodly/config.ts +8 -7
- package/templates/blank/smoodly/elements.ts +4 -4
- package/templates/blank/smoodly/globals.ts +4 -2
- package/templates/blank/smoodly/richtext.tsx +4 -5
- package/templates/blank/smoodly/sections.ts +4 -4
- package/templates/blank/smoodly/server.ts +22 -44
- package/templates/blank/smoodly/toolsets.ts +2 -2
- package/templates/blank/smoodly/views.ts +15 -0
- package/templates/blank/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
- package/templates/blank/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
- package/templates/blank/supabase/migrations/20261007200100_smoodly_views.sql +20 -0
- package/templates/blank-intl/AGENTS.md +23 -16
- package/templates/blank-intl/README.md +20 -15
- package/templates/blank-intl/app/(smoodly)/admin/[[...segments]]/route.ts +8 -0
- package/templates/blank-intl/components/elements/Button.schema.ts +22 -0
- package/templates/blank-intl/components/elements/Button.tsx +2 -20
- package/templates/blank-intl/components/pages/Home.schema.ts +17 -0
- package/templates/blank-intl/components/pages/Home.tsx +2 -16
- package/templates/blank-intl/components/pages/Page.schema.ts +14 -0
- package/templates/blank-intl/components/pages/Page.tsx +2 -14
- package/templates/blank-intl/components/pages/Post.tsx +5 -4
- package/templates/blank-intl/components/sections/Text.schema.ts +24 -0
- package/templates/blank-intl/components/sections/Text.tsx +7 -27
- package/templates/blank-intl/package.json +1 -1
- package/templates/blank-intl/scripts/seed.ts +2 -2
- package/templates/blank-intl/smoodly/config.ts +8 -7
- package/templates/blank-intl/smoodly/elements.ts +4 -4
- package/templates/blank-intl/smoodly/globals.ts +4 -2
- package/templates/blank-intl/smoodly/richtext.tsx +4 -5
- package/templates/blank-intl/smoodly/sections.ts +4 -4
- package/templates/blank-intl/smoodly/server.ts +22 -44
- package/templates/blank-intl/smoodly/toolsets.ts +2 -2
- package/templates/blank-intl/smoodly/views.ts +15 -0
- package/templates/blank-intl/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
- package/templates/blank-intl/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
- package/templates/blank-intl/supabase/migrations/20261007200100_smoodly_views.sql +20 -0
- package/templates/lorem/AGENTS.md +23 -16
- package/templates/lorem/README.md +3 -3
- package/templates/lorem/app/(smoodly)/admin/[[...segments]]/route.ts +8 -0
- package/templates/lorem/components/elements/Callout.schema.ts +24 -0
- package/templates/lorem/components/elements/Callout.tsx +2 -24
- package/templates/lorem/components/elements/Cta.schema.ts +21 -0
- package/templates/lorem/components/elements/Cta.tsx +2 -21
- package/templates/lorem/components/pages/Article.tsx +1 -1
- package/templates/lorem/components/pages/Articles.schema.ts +20 -0
- package/templates/lorem/components/pages/Articles.tsx +2 -20
- package/templates/lorem/components/pages/Home.schema.ts +26 -0
- package/templates/lorem/components/pages/Home.tsx +2 -26
- package/templates/lorem/components/pages/News.schema.ts +17 -0
- package/templates/lorem/components/pages/News.tsx +2 -17
- package/templates/lorem/components/pages/NewsPost.tsx +1 -1
- package/templates/lorem/components/pages/Page.schema.ts +24 -0
- package/templates/lorem/components/pages/Page.tsx +2 -24
- package/templates/lorem/components/sections/FavouriteArticles.schema.ts +17 -0
- package/templates/lorem/components/sections/FavouriteArticles.tsx +2 -17
- package/templates/lorem/components/sections/Footer.schema.ts +31 -0
- package/templates/lorem/components/sections/Footer.tsx +4 -32
- package/templates/lorem/components/sections/Header.schema.ts +21 -0
- package/templates/lorem/components/sections/Header.tsx +2 -21
- package/templates/lorem/components/sections/Hero.schema.ts +24 -0
- package/templates/lorem/components/sections/Hero.tsx +2 -24
- package/templates/lorem/components/sections/ImageText.schema.ts +30 -0
- package/templates/lorem/components/sections/ImageText.tsx +2 -30
- package/templates/lorem/components/sections/PageHero.schema.ts +21 -0
- package/templates/lorem/components/sections/PageHero.tsx +2 -21
- package/templates/lorem/components/sections/People.schema.ts +15 -0
- package/templates/lorem/components/sections/People.tsx +2 -14
- package/templates/lorem/components/sections/Points.schema.ts +21 -0
- package/templates/lorem/components/sections/Points.tsx +2 -21
- package/templates/lorem/components/sections/Quote.schema.ts +23 -0
- package/templates/lorem/components/sections/Quote.tsx +2 -23
- package/templates/lorem/package.json +1 -1
- package/templates/lorem/scripts/seed.ts +18 -18
- package/templates/lorem/smoodly/collections.ts +2 -2
- package/templates/lorem/smoodly/config.ts +14 -15
- package/templates/lorem/smoodly/elements.ts +5 -5
- package/templates/lorem/smoodly/globals.ts +10 -7
- package/templates/lorem/smoodly/richtext.tsx +5 -5
- package/templates/lorem/smoodly/sections.ts +12 -13
- package/templates/lorem/smoodly/server.ts +22 -44
- package/templates/lorem/smoodly/toolsets.ts +3 -3
- package/templates/lorem/smoodly/views.ts +33 -0
- package/templates/lorem/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
- package/templates/lorem/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
- package/templates/lorem/supabase/migrations/20261007200100_smoodly_views.sql +58 -0
- package/templates/lorem-intl/AGENTS.md +23 -16
- package/templates/lorem-intl/README.md +3 -3
- package/templates/lorem-intl/app/(smoodly)/admin/[[...segments]]/route.ts +8 -0
- package/templates/lorem-intl/components/elements/Callout.schema.ts +24 -0
- package/templates/lorem-intl/components/elements/Callout.tsx +2 -24
- package/templates/lorem-intl/components/elements/Cta.schema.ts +21 -0
- package/templates/lorem-intl/components/elements/Cta.tsx +2 -21
- package/templates/lorem-intl/components/pages/Article.tsx +1 -1
- package/templates/lorem-intl/components/pages/Articles.schema.ts +20 -0
- package/templates/lorem-intl/components/pages/Articles.tsx +2 -20
- package/templates/lorem-intl/components/pages/Home.schema.ts +26 -0
- package/templates/lorem-intl/components/pages/Home.tsx +2 -26
- package/templates/lorem-intl/components/pages/News.schema.ts +17 -0
- package/templates/lorem-intl/components/pages/News.tsx +2 -17
- package/templates/lorem-intl/components/pages/NewsPost.tsx +1 -1
- package/templates/lorem-intl/components/pages/Page.schema.ts +24 -0
- package/templates/lorem-intl/components/pages/Page.tsx +2 -24
- package/templates/lorem-intl/components/sections/FavouriteArticles.schema.ts +17 -0
- package/templates/lorem-intl/components/sections/FavouriteArticles.tsx +2 -17
- package/templates/lorem-intl/components/sections/Footer.schema.ts +31 -0
- package/templates/lorem-intl/components/sections/Footer.tsx +4 -32
- package/templates/lorem-intl/components/sections/Header.schema.ts +21 -0
- package/templates/lorem-intl/components/sections/Header.tsx +2 -21
- package/templates/lorem-intl/components/sections/Hero.schema.ts +24 -0
- package/templates/lorem-intl/components/sections/Hero.tsx +2 -24
- package/templates/lorem-intl/components/sections/ImageText.schema.ts +30 -0
- package/templates/lorem-intl/components/sections/ImageText.tsx +2 -30
- package/templates/lorem-intl/components/sections/PageHero.schema.ts +21 -0
- package/templates/lorem-intl/components/sections/PageHero.tsx +2 -21
- package/templates/lorem-intl/components/sections/People.schema.ts +15 -0
- package/templates/lorem-intl/components/sections/People.tsx +2 -14
- package/templates/lorem-intl/components/sections/Points.schema.ts +21 -0
- package/templates/lorem-intl/components/sections/Points.tsx +2 -21
- package/templates/lorem-intl/components/sections/Quote.schema.ts +23 -0
- package/templates/lorem-intl/components/sections/Quote.tsx +2 -23
- package/templates/lorem-intl/package.json +1 -1
- package/templates/lorem-intl/scripts/seed.ts +18 -18
- package/templates/lorem-intl/smoodly/collections.ts +2 -2
- package/templates/lorem-intl/smoodly/config.ts +14 -15
- package/templates/lorem-intl/smoodly/elements.ts +5 -5
- package/templates/lorem-intl/smoodly/globals.ts +10 -7
- package/templates/lorem-intl/smoodly/richtext.tsx +5 -5
- package/templates/lorem-intl/smoodly/sections.ts +12 -13
- package/templates/lorem-intl/smoodly/server.ts +22 -44
- package/templates/lorem-intl/smoodly/toolsets.ts +3 -3
- package/templates/lorem-intl/smoodly/views.ts +33 -0
- package/templates/lorem-intl/supabase/migrations/20261007120000_smoodly_v8.sql +154 -0
- package/templates/lorem-intl/supabase/migrations/20261007200000_smoodly_v9.sql +30 -0
- package/templates/lorem-intl/supabase/migrations/20261007200100_smoodly_views.sql +58 -0
- package/templates/blank/app/(smoodly)/admin/[[...segments]]/page.tsx +0 -1
- package/templates/blank/app/(smoodly)/admin/layout.tsx +0 -15
- package/templates/blank/smoodly/admin.tsx +0 -6
- package/templates/blank/smoodly/ops.ts +0 -11
- package/templates/blank-intl/app/(smoodly)/admin/[[...segments]]/page.tsx +0 -1
- package/templates/blank-intl/app/(smoodly)/admin/layout.tsx +0 -15
- package/templates/blank-intl/smoodly/admin.tsx +0 -6
- package/templates/blank-intl/smoodly/ops.ts +0 -11
- package/templates/lorem/app/(smoodly)/admin/[[...segments]]/page.tsx +0 -1
- package/templates/lorem/app/(smoodly)/admin/layout.tsx +0 -15
- package/templates/lorem/smoodly/admin.tsx +0 -6
- package/templates/lorem/smoodly/ops.ts +0 -11
- package/templates/lorem-intl/app/(smoodly)/admin/[[...segments]]/page.tsx +0 -1
- package/templates/lorem-intl/app/(smoodly)/admin/layout.tsx +0 -15
- package/templates/lorem-intl/smoodly/admin.tsx +0 -6
- package/templates/lorem-intl/smoodly/ops.ts +0 -11
|
@@ -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 {
|
|
28
|
-
const {
|
|
29
|
-
const {
|
|
30
|
-
const {
|
|
31
|
-
const {
|
|
32
|
-
const {
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
352
|
-
fi: { zones: { hero: [node(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
394
|
-
body: [node(
|
|
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
|
|
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
|
-
//
|
|
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",
|
|
@@ -5,19 +5,17 @@ import { sections } from "./sections";
|
|
|
5
5
|
import { globals } from "./globals";
|
|
6
6
|
import { elements } from "./elements";
|
|
7
7
|
import { article } from "./toolsets";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { ArticlePage } from "@/components/pages/Article";
|
|
13
|
-
import { NewsPage } from "@/components/pages/News";
|
|
14
|
-
import { NewsPostPage } from "@/components/pages/NewsPost";
|
|
8
|
+
import { homeSchema } from "@/components/pages/Home.schema";
|
|
9
|
+
import { articlesSchema } from "@/components/pages/Articles.schema";
|
|
10
|
+
import { pageSchema } from "@/components/pages/Page.schema";
|
|
11
|
+
import { newsSchema } from "@/components/pages/News.schema";
|
|
15
12
|
|
|
16
13
|
export { collections, sections, globals, elements };
|
|
17
14
|
|
|
18
|
-
// The registry and the plain settings, one file.
|
|
19
|
-
//
|
|
20
|
-
//
|
|
15
|
+
// The registry of schemas and the plain settings, one file. It imports
|
|
16
|
+
// no component, no route file and no Next API, so a script, the CLI and
|
|
17
|
+
// (later) an MCP server can load it outside the app; smoodly/views.ts
|
|
18
|
+
// lists the components that render these schemas. The
|
|
21
19
|
// locale set comes from i18n/routing.ts (plain config, no Next inside) —
|
|
22
20
|
// the proxy runs in the edge runtime and could not import this file the
|
|
23
21
|
// other way round.
|
|
@@ -28,7 +26,8 @@ export const config = defineConfig({
|
|
|
28
26
|
elements,
|
|
29
27
|
collections,
|
|
30
28
|
globals,
|
|
31
|
-
pages
|
|
29
|
+
// Page types. The entry pages are views: smoodly/views.ts lists them.
|
|
30
|
+
pages: [homeSchema, articlesSchema, pageSchema, newsSchema],
|
|
32
31
|
},
|
|
33
32
|
locales: { default: routing.defaultLocale, supported: [...routing.locales] },
|
|
34
33
|
// Editors pick dates and times in this zone; the views format with it (an IANA name, never an offset).
|
|
@@ -38,7 +37,7 @@ export const config = defineConfig({
|
|
|
38
37
|
// Nesting on: an editor can put pages three deep.
|
|
39
38
|
pages: { tree: { depth: 3 } },
|
|
40
39
|
// Smoodly's styles set (spacing, width, align) renders inline from
|
|
41
|
-
// these CSS values;
|
|
40
|
+
// these CSS values; the site's stylesheet defines the variables per
|
|
42
41
|
// breakpoint. Default stores nothing — a section looks as written.
|
|
43
42
|
styles: {
|
|
44
43
|
spacing: { sm: "var(--space-sm)", md: "var(--space-md)", lg: "var(--space-lg)" },
|
|
@@ -48,7 +47,7 @@ export const config = defineConfig({
|
|
|
48
47
|
css: true,
|
|
49
48
|
// The custom section (spec 2026-09-14 §6): the editor's own rows of
|
|
50
49
|
// columns. The columns take the article toolset (headings, lists,
|
|
51
|
-
// images, Callout and Cta)
|
|
52
|
-
// body images go through next/image like everywhere else.
|
|
53
|
-
custom: { toolset: article
|
|
50
|
+
// images, Callout and Cta); smoodly/views.ts binds the RichText that
|
|
51
|
+
// renders them, so body images go through next/image like everywhere else.
|
|
52
|
+
custom: { toolset: article },
|
|
54
53
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// The
|
|
2
|
-
//
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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 = [
|
|
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 {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
2
|
-
//
|
|
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 {
|
|
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
|
|
2
|
-
//
|
|
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 {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
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 = [
|
|
18
|
+
export const sections = [heroSchema, pageHeroSchema, imageTextSchema, pointsSchema, favouriteArticlesSchema, peopleSchema, quoteSchema, headerSchema, footerSchema];
|
|
@@ -5,23 +5,23 @@
|
|
|
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
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
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,
|
|
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
|
|
17
|
-
//
|
|
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
|
|
19
|
+
import { createPageRenderer, createSmoodlyQueries } from "smoodly/next";
|
|
21
20
|
import { connection } from "next/server";
|
|
22
21
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
23
22
|
import { getPathname } from "@/i18n/navigation";
|
|
24
|
-
import { collections, config,
|
|
23
|
+
import { collections, config, globals } from "./config";
|
|
24
|
+
import { views } from "./views";
|
|
25
25
|
|
|
26
26
|
type Renderer = ReturnType<typeof createPageRenderer>;
|
|
27
27
|
type Queries = ReturnType<typeof createSmoodlyQueries<typeof collections, typeof globals>>;
|
|
@@ -35,49 +35,27 @@ function bound(): Bound {
|
|
|
35
35
|
if (cached) return cached;
|
|
36
36
|
const env = smoodlyEnv();
|
|
37
37
|
const db = createSmoodlyClient(env);
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
const paths = new SupabasePathIndex(db, config.anchors);
|
|
41
|
-
const locales = config.locales;
|
|
42
|
-
const entries = new SupabaseEntryStore(db, collections, { paths, locales, globals, elements });
|
|
43
|
-
const pages = new SupabasePageStore(db, {
|
|
44
|
-
sections, elements, entries, paths, locales,
|
|
45
|
-
// The custom section's columns toolset, so a column's images count as usage (spec 2026-09-14 §6).
|
|
46
|
-
custom: config.custom,
|
|
47
|
-
homePageSlug: config.homePageSlug,
|
|
48
|
-
// Code-owned addresses by owner: a fixed page's or a collection's path (spec 2026-09-29 nested paths §3).
|
|
49
|
-
addresses: config.addresses,
|
|
50
|
-
tree: config.pages?.tree,
|
|
51
|
-
});
|
|
52
|
-
// The media library: rows in `assets`, bytes in the public `media` bucket.
|
|
53
|
-
const assets = new SupabaseAssetStore(db);
|
|
54
|
-
// The admission table, read by the Members page (spec 2026-09-25 §4).
|
|
55
|
-
const members = new SupabaseMemberStore(db);
|
|
38
|
+
// The stores, read off the config: pages, entries, the media library and the admission table.
|
|
39
|
+
const { pages, entries, assets, members, published } = createSupabaseStores(db, config);
|
|
56
40
|
const auth = supabaseAdminAuth({ authUrl: env.authUrl, authKey: env.authKey, db });
|
|
57
|
-
// The site layer's own view of the stores; nothing outside this file reads them.
|
|
58
|
-
const stores = () => ({ pages, entries, assets });
|
|
59
41
|
// The site layer: (locale, path) → page or entry, and the content API
|
|
60
42
|
// `q` wraps below. Not exported — the app reads through `q`, which adds
|
|
61
43
|
// draft awareness and the cache.
|
|
62
|
-
const site = createSmoodlySite(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
sections,
|
|
66
|
-
elements,
|
|
67
|
-
pages: (config.registry.pages ?? []) as PageRegistration[],
|
|
68
|
-
href,
|
|
69
|
-
});
|
|
44
|
+
const site = createSmoodlySite(siteOptions(config, () => ({ pages, entries, assets, published })));
|
|
45
|
+
// The components, checked against the config's schemas here, on first use.
|
|
46
|
+
const renderer = createPageRenderer({ site, ...views(), href });
|
|
70
47
|
// The read API (spec 2026-09-11): typed by the registry, draft-aware, cached under tags the admin expires.
|
|
71
48
|
const q = createSmoodlyQueries({ site, collections, globals });
|
|
72
49
|
cached = { db, pages, entries, assets, members, auth, site, renderer, q };
|
|
73
50
|
return cached;
|
|
74
51
|
}
|
|
75
52
|
|
|
76
|
-
/** The admin's wiring, for
|
|
53
|
+
/** The admin's wiring, for the admin route only. Scripts write through `content()`. */
|
|
77
54
|
export function adminDeps() {
|
|
78
55
|
smoodlyEnv("admin"); // the admin signs in with the publishable key: a missing one is named here, not on a live page
|
|
79
|
-
const { pages, entries, assets, members, auth } = bound();
|
|
80
|
-
|
|
56
|
+
const { pages, entries, assets, members, auth, site } = bound();
|
|
57
|
+
// The projector: a publish writes the finished documents a live page reads.
|
|
58
|
+
return { pages, entries, assets, members, auth, href, projector: site.projector };
|
|
81
59
|
}
|
|
82
60
|
|
|
83
61
|
/** Write content from code — seeds, migrations, route handlers (spec 2026-09-30 tester findings §1).
|
|
@@ -85,8 +63,8 @@ export function adminDeps() {
|
|
|
85
63
|
* throws `SmoodlyContentError`. `content().pages.create(…)`, `.entries.create(…)`, `.globals.set(…)`,
|
|
86
64
|
* `.media.upload(…)`; build tree nodes with `node(Section, fields)`. */
|
|
87
65
|
export function content(): SmoodlyContent {
|
|
88
|
-
const { pages, entries, assets, members } = bound();
|
|
89
|
-
return createSmoodlyContent({ config, pages, entries, assets, members, href });
|
|
66
|
+
const { pages, entries, assets, members, site } = bound();
|
|
67
|
+
return createSmoodlyContent({ config, pages, entries, assets, members, href, projector: site.projector });
|
|
90
68
|
}
|
|
91
69
|
|
|
92
70
|
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 {
|
|
10
|
-
import {
|
|
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: [
|
|
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
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
-- Smoodly core schema, version 8 (docs/superpowers/specs/2026-10-07-delivery-model-design.md).
|
|
2
|
+
-- Shipped in the smoodly package; `npx smoodly migrate` copies it into supabase/migrations/.
|
|
3
|
+
-- Never edit a published file: the next change is the next file.
|
|
4
|
+
-- The delta over version 7: the delivery model's two derived tables,
|
|
5
|
+
-- published_pages and published_entries, with the space trigger and the
|
|
6
|
+
-- write-key-only policies every content table has (no row cap: they are
|
|
7
|
+
-- derived), smoodly_list_published over the raw published snapshot, and
|
|
8
|
+
-- the published_routes view, one lookup for any address.
|
|
9
|
+
|
|
10
|
+
set client_min_messages = warning;
|
|
11
|
+
|
|
12
|
+
-- The delivery model (spec 2026-10-07): Publish writes the finished document of a page, an entry
|
|
13
|
+
-- or a global here; a live read is one lookup. Derived and rebuildable from the editing tables.
|
|
14
|
+
create table if not exists "published_pages" (
|
|
15
|
+
"space_id" uuid not null default '00000000-0000-0000-0000-000000000000',
|
|
16
|
+
"page_id" uuid not null references "pages" ("id") on delete cascade,
|
|
17
|
+
"locale" text not null,
|
|
18
|
+
"parent_id" uuid,
|
|
19
|
+
"sort" numeric,
|
|
20
|
+
"path" text,
|
|
21
|
+
"title" text not null,
|
|
22
|
+
"has_page" boolean not null,
|
|
23
|
+
"link_fields" jsonb not null default '{}'::jsonb,
|
|
24
|
+
"document" jsonb,
|
|
25
|
+
"tags" text[] not null default '{}',
|
|
26
|
+
"model" text not null,
|
|
27
|
+
"stale" boolean not null default false,
|
|
28
|
+
"published_at" timestamptz not null default now(),
|
|
29
|
+
primary key ("page_id", "locale")
|
|
30
|
+
);
|
|
31
|
+
create unique index if not exists "published_pages_address_idx"
|
|
32
|
+
on "published_pages" ("space_id", "locale", "path") where "path" is not null;
|
|
33
|
+
create index if not exists "published_pages_tree_idx"
|
|
34
|
+
on "published_pages" ("space_id", "locale", "parent_id", "sort");
|
|
35
|
+
|
|
36
|
+
create table if not exists "published_entries" (
|
|
37
|
+
"space_id" uuid not null default '00000000-0000-0000-0000-000000000000',
|
|
38
|
+
"entry_id" uuid not null references "entries" ("id") on delete cascade,
|
|
39
|
+
"locale" text not null,
|
|
40
|
+
"collection" text not null,
|
|
41
|
+
"parent_id" uuid,
|
|
42
|
+
"sort" numeric,
|
|
43
|
+
"slug" text,
|
|
44
|
+
"path" text,
|
|
45
|
+
"created_at" timestamptz not null,
|
|
46
|
+
"updated_at" timestamptz not null,
|
|
47
|
+
"fields" jsonb not null,
|
|
48
|
+
"document" jsonb not null,
|
|
49
|
+
"tags" text[] not null default '{}',
|
|
50
|
+
"model" text not null,
|
|
51
|
+
"stale" boolean not null default false,
|
|
52
|
+
"published_at" timestamptz not null default now(),
|
|
53
|
+
primary key ("entry_id", "locale")
|
|
54
|
+
);
|
|
55
|
+
create index if not exists "published_entries_list_idx"
|
|
56
|
+
on "published_entries" ("space_id", "collection", "locale");
|
|
57
|
+
create unique index if not exists "published_entries_address_idx"
|
|
58
|
+
on "published_entries" ("space_id", "locale", "path") where "path" is not null;
|
|
59
|
+
create index if not exists "published_entries_fields_idx"
|
|
60
|
+
on "published_entries" using gin ("fields");
|
|
61
|
+
|
|
62
|
+
alter table "published_pages" enable row level security;
|
|
63
|
+
alter table "published_entries" enable row level security;
|
|
64
|
+
|
|
65
|
+
-- smoodly_list_entries without the draft branch, over the delivery table (spec 2026-10-07 §3):
|
|
66
|
+
-- `where` and `order` read the raw published snapshot, the row answers with its document.
|
|
67
|
+
-- Invoker rights, so RLS decides what a key sees.
|
|
68
|
+
create or replace function "smoodly_list_published"(
|
|
69
|
+
p_collection text, p_locale text, p_where jsonb, p_order jsonb,
|
|
70
|
+
p_limit integer, p_parent uuid, p_has_parent boolean, p_ids uuid[]
|
|
71
|
+
) returns table ("id" uuid, "document" jsonb, "model" text, "stale" boolean) language sql stable set search_path = public as $$
|
|
72
|
+
with shown as (
|
|
73
|
+
select p."entry_id" as "id", p."sort", p."created_at", p."updated_at", p."fields", p."document", p."model", p."stale"
|
|
74
|
+
from "published_entries" p
|
|
75
|
+
where p."collection" = p_collection and p."locale" = p_locale
|
|
76
|
+
and (not p_has_parent or p."parent_id" is not distinct from p_parent)
|
|
77
|
+
and (p_ids is null or p."entry_id" = any(p_ids))
|
|
78
|
+
)
|
|
79
|
+
select s."id", s."document", s."model", s."stale" from shown s
|
|
80
|
+
where not exists (
|
|
81
|
+
select 1 from jsonb_each(coalesce(p_where, '{}'::jsonb)) w
|
|
82
|
+
where not (case when w.value ? 'in'
|
|
83
|
+
then (s."fields" ->> w.key) = any (select jsonb_array_elements_text(w.value -> 'in'))
|
|
84
|
+
else s."fields" @> jsonb_build_object(w.key, w.value -> 'contains') end))
|
|
85
|
+
order by
|
|
86
|
+
case when p_order ->> 'by' = 'manual' then s."sort" end asc nulls last,
|
|
87
|
+
case when p_order ->> 'direction' = 'asc' then
|
|
88
|
+
case p_order ->> 'by' when 'createdAt' then to_jsonb(s."created_at") when 'updatedAt' then to_jsonb(s."updated_at")
|
|
89
|
+
when 'manual' then null else nullif(nullif(s."fields" -> (p_order ->> 'by'), 'null'::jsonb), '""'::jsonb) end end asc nulls last,
|
|
90
|
+
case when p_order ->> 'direction' = 'desc' then
|
|
91
|
+
case p_order ->> 'by' when 'createdAt' then to_jsonb(s."created_at") when 'updatedAt' then to_jsonb(s."updated_at")
|
|
92
|
+
when 'manual' then null else nullif(nullif(s."fields" -> (p_order ->> 'by'), 'null'::jsonb), '""'::jsonb) end end desc nulls last,
|
|
93
|
+
s."created_at" asc, s."id" asc
|
|
94
|
+
limit p_limit;
|
|
95
|
+
$$;
|
|
96
|
+
|
|
97
|
+
-- One lookup for any address (spec 2026-10-07 §3): a page or an entry, under the caller's own policies.
|
|
98
|
+
create or replace view "published_routes" with (security_invoker = true) as
|
|
99
|
+
select "space_id", "locale", "path", 'page' as "kind", "page_id" as "id", "document", "model", "stale", "tags", null::text as "collection"
|
|
100
|
+
from "published_pages" where "path" is not null and "has_page"
|
|
101
|
+
union all
|
|
102
|
+
select "space_id", "locale", "path", 'entry' as "kind", "entry_id" as "id", "document", "model", "stale", "tags", "collection"
|
|
103
|
+
from "published_entries" where "path" is not null;
|
|
104
|
+
|
|
105
|
+
-- Stamped with the caller's space on insert, as every content table.
|
|
106
|
+
drop trigger if exists "smoodly_a_set_space" on "published_pages";
|
|
107
|
+
create trigger "smoodly_a_set_space" before insert on "published_pages"
|
|
108
|
+
for each row execute function "smoodly_set_space"();
|
|
109
|
+
|
|
110
|
+
drop trigger if exists "smoodly_a_set_space" on "published_entries";
|
|
111
|
+
create trigger "smoodly_a_set_space" before insert on "published_entries"
|
|
112
|
+
for each row execute function "smoodly_set_space"();
|
|
113
|
+
|
|
114
|
+
-- A write key reads and writes its own space; no other key reads (spec 2026-09-29 content API contract §8).
|
|
115
|
+
drop policy if exists "smoodly_write" on "published_pages";
|
|
116
|
+
|
|
117
|
+
drop policy if exists "smoodly_insert" on "published_pages";
|
|
118
|
+
create policy "smoodly_insert" on "published_pages" for insert
|
|
119
|
+
with check ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
120
|
+
|
|
121
|
+
drop policy if exists "smoodly_update" on "published_pages";
|
|
122
|
+
create policy "smoodly_update" on "published_pages" for update
|
|
123
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write')
|
|
124
|
+
with check ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
125
|
+
|
|
126
|
+
drop policy if exists "smoodly_delete" on "published_pages";
|
|
127
|
+
create policy "smoodly_delete" on "published_pages" for delete
|
|
128
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
129
|
+
|
|
130
|
+
drop policy if exists "smoodly_read" on "published_pages";
|
|
131
|
+
create policy "smoodly_read" on "published_pages" for select
|
|
132
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
133
|
+
|
|
134
|
+
drop policy if exists "smoodly_write" on "published_entries";
|
|
135
|
+
|
|
136
|
+
drop policy if exists "smoodly_insert" on "published_entries";
|
|
137
|
+
create policy "smoodly_insert" on "published_entries" for insert
|
|
138
|
+
with check ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
139
|
+
|
|
140
|
+
drop policy if exists "smoodly_update" on "published_entries";
|
|
141
|
+
create policy "smoodly_update" on "published_entries" for update
|
|
142
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write')
|
|
143
|
+
with check ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
144
|
+
|
|
145
|
+
drop policy if exists "smoodly_delete" on "published_entries";
|
|
146
|
+
create policy "smoodly_delete" on "published_entries" for delete
|
|
147
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
148
|
+
|
|
149
|
+
drop policy if exists "smoodly_read" on "published_entries";
|
|
150
|
+
create policy "smoodly_read" on "published_entries" for select
|
|
151
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
152
|
+
|
|
153
|
+
insert into "smoodly_meta" ("key", "value") values ('schema_version', '8')
|
|
154
|
+
on conflict ("key") do update set "value" = excluded."value";
|