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.
- 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
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { f, smoodly } from "smoodly";
|
|
2
|
+
|
|
3
|
+
// An Element: a small registered block editors insert inside an article
|
|
4
|
+
// body (the `richtext` context). Its body is richtext too — marks only —
|
|
5
|
+
// rendered by the package's pure RichText (a schema file imports no view:
|
|
6
|
+
// the view imports this file, and an import back would cycle).
|
|
7
|
+
export const calloutSchema = smoodly.schema.element({
|
|
8
|
+
name: "callout",
|
|
9
|
+
title: "Callout",
|
|
10
|
+
icon: "!",
|
|
11
|
+
description: "A highlighted note inside the text.",
|
|
12
|
+
contexts: ["richtext"],
|
|
13
|
+
fields: {
|
|
14
|
+
title: f.text().max(80),
|
|
15
|
+
body: f.richtext({ toolset: smoodly.toolset({ marks: ["bold", "italic", "link"] }) }),
|
|
16
|
+
},
|
|
17
|
+
settings: {
|
|
18
|
+
tone: f.select([{ value: "info", label: "Info" }, { value: "success", label: "Success" }, { value: "warning", label: "Warning" }]).default("info"),
|
|
19
|
+
},
|
|
20
|
+
sample: {
|
|
21
|
+
title: "Good to know",
|
|
22
|
+
body: { type: "doc", content: [{ type: "paragraph", content: [{ type: "text", text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }] }] },
|
|
23
|
+
},
|
|
24
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { f, smoodly } from "smoodly";
|
|
2
|
+
|
|
3
|
+
// A call to action inside an article body: heading, a line of text and
|
|
4
|
+
// one button. `variant` is a style — never translated.
|
|
5
|
+
export const ctaSchema = smoodly.schema.element({
|
|
6
|
+
name: "cta",
|
|
7
|
+
title: "Call to action",
|
|
8
|
+
icon: "→",
|
|
9
|
+
description: "A heading, a line and a button.",
|
|
10
|
+
contexts: ["richtext"],
|
|
11
|
+
fields: {
|
|
12
|
+
heading: f.text().max(80),
|
|
13
|
+
text: f.text().max(200).optional(),
|
|
14
|
+
label: f.text().max(40),
|
|
15
|
+
href: f.link(),
|
|
16
|
+
},
|
|
17
|
+
settings: {
|
|
18
|
+
variant: f.select([{ value: "primary", label: "Primary" }, { value: "outline", label: "Outline" }]).default("primary"),
|
|
19
|
+
},
|
|
20
|
+
sample: { heading: "Ready to start?", text: "Sed ut perspiciatis unde omnis iste natus.", label: "Get in touch", href: "/company/about-us" },
|
|
21
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// The news index's URL, for the post page's back link, from the
|
|
2
|
+
// collection's own nested path (smoodly/collections.ts).
|
|
3
|
+
import { news } from "@/smoodly/collections";
|
|
4
|
+
|
|
5
|
+
/** The collection's address in a locale: its per-locale path, or the
|
|
6
|
+
* first declared one for a locale the map does not name. */
|
|
7
|
+
function address(locale: string): string {
|
|
8
|
+
const p = news.path;
|
|
9
|
+
if (typeof p === "string") return p;
|
|
10
|
+
return p?.[locale] ?? Object.values(p ?? {})[0] ?? "company/news";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const newsIndexPath = (locale: string) => `/${address(locale)}`;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { smoodly, z } from "smoodly";
|
|
2
|
+
import { pageHeroSchema } from "../sections/PageHero.schema";
|
|
3
|
+
|
|
4
|
+
// The Articles index: a fixed page whose slugs are the collection's own
|
|
5
|
+
// segments (smoodly/collections.ts), which makes it the collection's
|
|
6
|
+
// index page — the mount in the Pages list opens this page's editor. The
|
|
7
|
+
// editor owns the hero; the grid below is developer JSX that reads the
|
|
8
|
+
// articles through `q`, newest first (the collection's `order`), cached
|
|
9
|
+
// under the collection's tag. In the editor canvas the site runs in draft
|
|
10
|
+
// mode, so the grid reads the live rows too: an unpublished article shows
|
|
11
|
+
// there as it will (spec 2026-09-11 §2).
|
|
12
|
+
export const articlesSchema = smoodly.schema.page({
|
|
13
|
+
name: "articlesIndex",
|
|
14
|
+
title: "Articles",
|
|
15
|
+
slug: "posts",
|
|
16
|
+
zones: {
|
|
17
|
+
hero: z.locked(pageHeroSchema),
|
|
18
|
+
},
|
|
19
|
+
seo: true,
|
|
20
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { smoodly, z } from "smoodly";
|
|
2
|
+
import { heroSchema } from "../sections/Hero.schema";
|
|
3
|
+
import { imageTextSchema } from "../sections/ImageText.schema";
|
|
4
|
+
import { pointsSchema } from "../sections/Points.schema";
|
|
5
|
+
import { favouriteArticlesSchema } from "../sections/FavouriteArticles.schema";
|
|
6
|
+
import { peopleSchema } from "../sections/People.schema";
|
|
7
|
+
import { quoteSchema } from "../sections/Quote.schema";
|
|
8
|
+
|
|
9
|
+
// A page type: zones declared here, placed by the page type's view (DESIGN.md §3).
|
|
10
|
+
// `slug` makes it fixed — one record the editor can neither delete nor
|
|
11
|
+
// duplicate — and the config's homePageSlug maps that record to "/".
|
|
12
|
+
// The hero is locked: fields only, never added, moved or removed. The
|
|
13
|
+
// body is freeform over five sections. Quote is among them because the
|
|
14
|
+
// picker offers a global item only where the zone allows its section: an
|
|
15
|
+
// editor may drop a one-off quote, or place the global one from the
|
|
16
|
+
// picker's Global group.
|
|
17
|
+
export const homeSchema = smoodly.schema.page({
|
|
18
|
+
name: "home",
|
|
19
|
+
title: "Home",
|
|
20
|
+
slug: "home",
|
|
21
|
+
zones: {
|
|
22
|
+
hero: z.locked(heroSchema),
|
|
23
|
+
body: z.freeform({ sections: [imageTextSchema, pointsSchema, favouriteArticlesSchema, peopleSchema, quoteSchema], custom: true }),
|
|
24
|
+
},
|
|
25
|
+
seo: true,
|
|
26
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { smoodly, z } from "smoodly";
|
|
2
|
+
import { pageHeroSchema } from "../sections/PageHero.schema";
|
|
3
|
+
|
|
4
|
+
// The News index: a fixed page on the news collection's own nested
|
|
5
|
+
// address (smoodly/collections.ts), so it is the collection's index page.
|
|
6
|
+
// Code owns /company/news whole: the Company page above it is an
|
|
7
|
+
// editor's, and renaming it leaves the news where it is. The editor owns
|
|
8
|
+
// the hero; the list below reads the posts through `q`, newest first.
|
|
9
|
+
export const newsSchema = smoodly.schema.page({
|
|
10
|
+
name: "newsIndex",
|
|
11
|
+
title: "News",
|
|
12
|
+
slug: "company/news",
|
|
13
|
+
zones: {
|
|
14
|
+
hero: z.locked(pageHeroSchema),
|
|
15
|
+
},
|
|
16
|
+
seo: true,
|
|
17
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { f, smoodly, z } from "smoodly";
|
|
2
|
+
import { pageHeroSchema } from "../sections/PageHero.schema";
|
|
3
|
+
import { imageTextSchema } from "../sections/ImageText.schema";
|
|
4
|
+
import { pointsSchema } from "../sections/Points.schema";
|
|
5
|
+
import { favouriteArticlesSchema } from "../sections/FavouriteArticles.schema";
|
|
6
|
+
import { peopleSchema } from "../sections/People.schema";
|
|
7
|
+
import { quoteSchema } from "../sections/Quote.schema";
|
|
8
|
+
|
|
9
|
+
// Open registration: editors create as many of these as they like, at
|
|
10
|
+
// any depth the config allows. `page` is where this one sits in the tree.
|
|
11
|
+
// Its locked hero is the page hero, not the home one: each shape locks
|
|
12
|
+
// its own.
|
|
13
|
+
export const pageSchema = smoodly.schema.page({
|
|
14
|
+
name: "page",
|
|
15
|
+
title: "Page",
|
|
16
|
+
zones: {
|
|
17
|
+
hero: z.locked(pageHeroSchema),
|
|
18
|
+
body: z.freeform({ sections: [imageTextSchema, pointsSchema, favouriteArticlesSchema, peopleSchema, quoteSchema], custom: true }),
|
|
19
|
+
},
|
|
20
|
+
seo: true,
|
|
21
|
+
// A page field (spec 2026-09-10 page fields §7): the parent's view lists
|
|
22
|
+
// the children that keep this on. Edited on the Settings tab.
|
|
23
|
+
fields: { showInNavigation: f.boolean().default(true) },
|
|
24
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { f, smoodly } from "smoodly";
|
|
2
|
+
import { articles } from "@/smoodly/collections";
|
|
3
|
+
|
|
4
|
+
// Articles an editor picks by hand (refList), as cards. The resolve pass
|
|
5
|
+
// hydrates each ref before render, so the view gets article fields, not
|
|
6
|
+
// ids; an article unpublished after this page went live resolves to
|
|
7
|
+
// null and is skipped.
|
|
8
|
+
export const favouriteArticlesSchema = smoodly.schema.section({
|
|
9
|
+
name: "favouriteArticles",
|
|
10
|
+
title: "Favourite articles",
|
|
11
|
+
description: "Articles picked by hand, as cards.",
|
|
12
|
+
fields: {
|
|
13
|
+
heading: f.text(),
|
|
14
|
+
items: f.refList(() => articles).max(6),
|
|
15
|
+
},
|
|
16
|
+
sample: { heading: "From the journal", items: [] },
|
|
17
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { f, smoodly } from "smoodly";
|
|
2
|
+
|
|
3
|
+
// The site footer — a VISUAL global item (smoodly/globals.ts): one row,
|
|
4
|
+
// edited under Global content, rendered by the layout. Three link columns
|
|
5
|
+
// as top-level objects, each localized as a whole (an object holding a
|
|
6
|
+
// list — one level, which the list field allows; a list of columns each
|
|
7
|
+
// holding a list would be a nested list, which it refuses).
|
|
8
|
+
const column = () =>
|
|
9
|
+
f.object({ title: f.text(), links: f.list(f.object({ label: f.text(), href: f.link() })) }).localized();
|
|
10
|
+
|
|
11
|
+
export const footerSchema = smoodly.schema.section({
|
|
12
|
+
name: "footer",
|
|
13
|
+
title: "Footer",
|
|
14
|
+
description: "The site footer: tagline, three link columns, copyright.",
|
|
15
|
+
fields: {
|
|
16
|
+
tagline: f.text().localized(),
|
|
17
|
+
company: column(),
|
|
18
|
+
legal: column(),
|
|
19
|
+
social: column(),
|
|
20
|
+
copyright: f.text(),
|
|
21
|
+
},
|
|
22
|
+
sample: {
|
|
23
|
+
tagline: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
|
24
|
+
company: { title: "Company", links: [{ label: "About", href: "/company/about-us" }] },
|
|
25
|
+
legal: { title: "Legal", links: [{ label: "Privacy", href: "#" }] },
|
|
26
|
+
social: { title: "Social", links: [{ label: "Instagram", href: "#" }] },
|
|
27
|
+
copyright: "© 2026 Lorem Co. Built with Smoodly.",
|
|
28
|
+
},
|
|
29
|
+
// The layout's footer keeps the design's spacing: no Spacing & layout group.
|
|
30
|
+
styles: false,
|
|
31
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { f, smoodly } from "smoodly";
|
|
2
|
+
|
|
3
|
+
// The site header — a VISUAL global item (smoodly/globals.ts): one row,
|
|
4
|
+
// edited under Global content, rendered by the layout, never placed in a
|
|
5
|
+
// page. The brand is the same in every language; the nav is a list of
|
|
6
|
+
// links localized as a whole, so each language has its own labels and
|
|
7
|
+
// hrefs. The layout renders HeaderView directly to hand it the locale
|
|
8
|
+
// links (a paired component takes only its schema's props); the paired
|
|
9
|
+
// Header is what the registry and the admin know.
|
|
10
|
+
export const headerSchema = smoodly.schema.section({
|
|
11
|
+
name: "header",
|
|
12
|
+
title: "Header",
|
|
13
|
+
description: "The site header: brand and navigation.",
|
|
14
|
+
fields: {
|
|
15
|
+
brand: f.text(),
|
|
16
|
+
nav: f.list(f.object({ label: f.text(), href: f.link() })).localized(),
|
|
17
|
+
},
|
|
18
|
+
sample: { brand: "Lorem Co.", nav: [{ label: "Home", href: "/" }] },
|
|
19
|
+
// Nobody pads the header from the editor: no Spacing & layout group.
|
|
20
|
+
styles: false,
|
|
21
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { f, smoodly } from "smoodly";
|
|
2
|
+
|
|
3
|
+
// The home page opener: kicker, heading, text, up to two buttons and a
|
|
4
|
+
// portrait photo. Home locks it (`z.locked(heroSchema)`): one node an editor
|
|
5
|
+
// fills but cannot add, move or remove. `sample` is what the editor
|
|
6
|
+
// materializes into an empty locked zone, so it is a complete value.
|
|
7
|
+
export const heroSchema = smoodly.schema.section({
|
|
8
|
+
name: "hero",
|
|
9
|
+
title: "Hero",
|
|
10
|
+
description: "The home page opener: heading, text, buttons and a photo.",
|
|
11
|
+
fields: {
|
|
12
|
+
kicker: f.text().optional(),
|
|
13
|
+
heading: f.text(),
|
|
14
|
+
text: f.text(),
|
|
15
|
+
buttons: f.list(f.object({ label: f.text(), href: f.link() })).max(2),
|
|
16
|
+
image: f.image({ aspect: "4:5" }),
|
|
17
|
+
},
|
|
18
|
+
sample: {
|
|
19
|
+
kicker: "Lorem ipsum dolor",
|
|
20
|
+
heading: "Consectetur adipiscing elit sed do eiusmod",
|
|
21
|
+
text: "Tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip.",
|
|
22
|
+
buttons: [{ label: "About us", href: "/company/about-us" }],
|
|
23
|
+
},
|
|
24
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { f, smoodly } from "smoodly";
|
|
2
|
+
|
|
3
|
+
// A photo beside a heading and richtext, the photo on either side (a
|
|
4
|
+
// setting, not a field: settings are never translated). Without a photo the
|
|
5
|
+
// heading takes the left column and the text the right — the About
|
|
6
|
+
// page's text block. The richtext renders through the package's
|
|
7
|
+
// RichText: paragraphs, headings, lists, quotes.
|
|
8
|
+
export const imageTextSchema = smoodly.schema.section({
|
|
9
|
+
name: "imageText",
|
|
10
|
+
title: "Image and text",
|
|
11
|
+
description: "A photo beside a heading and text; text alone in two columns without one.",
|
|
12
|
+
fields: {
|
|
13
|
+
image: f.image({ aspect: "4:3" }).optional(),
|
|
14
|
+
heading: f.text(),
|
|
15
|
+
// Body copy beside a photo: emphasis and links, no headings — the block's
|
|
16
|
+
// own heading field owns that. Every other richtext field takes the default.
|
|
17
|
+
text: f.richtext({ toolset: smoodly.toolset({ marks: ["bold", "italic", "link"] }) }),
|
|
18
|
+
link: f.object({ label: f.text(), href: f.link() }).optional(),
|
|
19
|
+
},
|
|
20
|
+
settings: {
|
|
21
|
+
imageSide: f.radio([{ value: "left", label: "Image left" }, { value: "right", label: "Image right" }]).default("left"),
|
|
22
|
+
},
|
|
23
|
+
sample: {
|
|
24
|
+
heading: "Duis aute irure dolor in reprehenderit",
|
|
25
|
+
text: {
|
|
26
|
+
type: "doc",
|
|
27
|
+
content: [{ type: "paragraph", content: [{ type: "text", text: "In voluptate velit esse cillum dolore eu fugiat nulla pariatur." }] }],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { f, smoodly } from "smoodly";
|
|
2
|
+
|
|
3
|
+
// The opener of every page that is not the home page: kicker, heading,
|
|
4
|
+
// text and an optional wide photo. Page and Articles lock it — each page
|
|
5
|
+
// shape locks its own hero, which is the point: a locked zone is per
|
|
6
|
+
// shape. Without an image the copy stands alone (the Articles index).
|
|
7
|
+
export const pageHeroSchema = smoodly.schema.section({
|
|
8
|
+
name: "pageHero",
|
|
9
|
+
title: "Page hero",
|
|
10
|
+
description: "A page opener: kicker, heading, text and an optional wide photo.",
|
|
11
|
+
fields: {
|
|
12
|
+
kicker: f.text().optional(),
|
|
13
|
+
heading: f.text(),
|
|
14
|
+
text: f.text(),
|
|
15
|
+
image: f.image({ aspect: "21:9" }).optional(),
|
|
16
|
+
},
|
|
17
|
+
sample: {
|
|
18
|
+
heading: "About us",
|
|
19
|
+
text: "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { f, smoodly } from "smoodly";
|
|
2
|
+
import { people } from "@/smoodly/collections";
|
|
3
|
+
|
|
4
|
+
// People picked by hand (refList), four to a row: name and role, the
|
|
5
|
+
// role in the page's language because it is a localized field.
|
|
6
|
+
export const peopleSchema = smoodly.schema.section({
|
|
7
|
+
name: "peopleSection",
|
|
8
|
+
title: "People",
|
|
9
|
+
description: "A heading and a row of people.",
|
|
10
|
+
fields: {
|
|
11
|
+
heading: f.text(),
|
|
12
|
+
people: f.refList(() => people),
|
|
13
|
+
},
|
|
14
|
+
sample: { heading: "Our people", people: [] },
|
|
15
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { f, smoodly } 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
|
+
});
|
|
@@ -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
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
// examples/astro/src/elements/callout.astro — the view of the element named "callout", inside an article body
|
|
3
|
+
import { type Props as SmoodlyProps } from "smoodly";
|
|
4
|
+
import { RichText } from "smoodly/astro/components";
|
|
5
|
+
import { calloutSchema } from "@/components/elements/Callout.schema";
|
|
6
|
+
|
|
7
|
+
type Props = SmoodlyProps<typeof calloutSchema>;
|
|
8
|
+
const { title, body, settings } = Astro.props;
|
|
9
|
+
---
|
|
10
|
+
<aside class="callout" data-tone={settings.tone}>
|
|
11
|
+
<strong class="callout__title">{title}</strong>
|
|
12
|
+
<div class="callout__body"><RichText doc={body} /></div>
|
|
13
|
+
</aside>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
// examples/astro/src/elements/cta.astro — the view of the element named "cta"
|
|
3
|
+
import { safeHref, type Props as SmoodlyProps } from "smoodly";
|
|
4
|
+
import { ctaSchema } from "@/components/elements/Cta.schema";
|
|
5
|
+
|
|
6
|
+
type Props = SmoodlyProps<typeof ctaSchema>;
|
|
7
|
+
const { heading, text, label, href, settings } = Astro.props;
|
|
8
|
+
---
|
|
9
|
+
<div class="cta" data-variant={settings.variant}>
|
|
10
|
+
<div class="cta__copy">
|
|
11
|
+
<strong class="cta__heading">{heading}</strong>
|
|
12
|
+
{text && <p class="cta__text">{text}</p>}
|
|
13
|
+
</div>
|
|
14
|
+
<a class={settings.variant === "outline" ? "button button--outline" : "button"} href={safeHref(href)}>{label}</a>
|
|
15
|
+
</div>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
// examples/astro/src/entry-pages/articles.astro — the entry page of the collection "articles", served at the
|
|
3
|
+
// collection's path (/posts/<slug>, /fi/artikkelit/<slug>). Fields only; refs arrive resolved (author is a
|
|
4
|
+
// person). "Related" is the newest other published articles; "More from <author>" filters on the shared
|
|
5
|
+
// author field in the store. The render locale and the alternates ride on the entry (spec 2026-09-15).
|
|
6
|
+
import { getLiveCollection } from "astro:content";
|
|
7
|
+
import { Image, RichText } from "smoodly/astro/components";
|
|
8
|
+
import { href } from "smoodly/astro/runtime";
|
|
9
|
+
import { articlesIndexPath, formatDate, readingMinutes } from "@/components/articles";
|
|
10
|
+
import type { EntryFields, EntryItem } from "smoodly";
|
|
11
|
+
import type { PageHead } from "smoodly/astro/runtime";
|
|
12
|
+
import type { articles } from "@/smoodly/collections";
|
|
13
|
+
import Layout from "../layouts/Layout.astro";
|
|
14
|
+
import ArticleCard from "../components/ArticleCard.astro";
|
|
15
|
+
import { ui } from "../strings";
|
|
16
|
+
|
|
17
|
+
type Props = { entry: EntryItem<EntryFields<typeof articles>>; head: PageHead };
|
|
18
|
+
const { entry, head } = Astro.props;
|
|
19
|
+
const { locale, locales } = entry;
|
|
20
|
+
const { t } = ui(locale);
|
|
21
|
+
const a = entry.fields;
|
|
22
|
+
const url = (path: string) => href(path, locale);
|
|
23
|
+
// Four newest, minus this one, so three remain even when it is among them; the store applies the limit.
|
|
24
|
+
const { entries: newest = [] } = await getLiveCollection("articles", { locale, limit: 4 });
|
|
25
|
+
const related = newest.map((e) => e.data).filter((r) => r.id !== entry.id).slice(0, 3);
|
|
26
|
+
const authorId = a.author?.id;
|
|
27
|
+
const { entries: byAuthor = [] } = authorId ? await getLiveCollection("articles", { locale, where: { author: authorId } }) : { entries: [] };
|
|
28
|
+
const more = byAuthor.map((e) => e.data).filter((r) => r.id !== entry.id);
|
|
29
|
+
const index = url(articlesIndexPath(locale));
|
|
30
|
+
---
|
|
31
|
+
<Layout head={head} locale={locale} locales={locales}>
|
|
32
|
+
<article class="container article">
|
|
33
|
+
<a class="article__back" href={index}>← {t("allArticles")}</a>
|
|
34
|
+
<div class="article__head">
|
|
35
|
+
{a.tags && a.tags.length > 0 && (
|
|
36
|
+
<div class="article__tags">{a.tags.map((tag, i) => <span class={i === 0 ? "tag tag--accent" : "tag"}>{tag}</span>)}</div>
|
|
37
|
+
)}
|
|
38
|
+
<h1 class="article__title">{a.title}</h1>
|
|
39
|
+
<p class="article__byline">
|
|
40
|
+
<span class="article__avatar" aria-hidden="true"></span>
|
|
41
|
+
<span>
|
|
42
|
+
{a.author?.fields.name && <strong>{a.author.fields.name}</strong>}
|
|
43
|
+
{a.author?.fields.name && " · "}
|
|
44
|
+
{a.date && <>{formatDate(a.date, locale)} · </>}
|
|
45
|
+
{t("minRead", { minutes: readingMinutes(a.body) })}
|
|
46
|
+
</span>
|
|
47
|
+
</p>
|
|
48
|
+
</div>
|
|
49
|
+
{a.image && <Image image={a.image} aspect="21:9" class="article__image" sizes="(min-width: 900px) 800px, 100vw" priority />}
|
|
50
|
+
<div class="article__body prose prose--lead"><RichText doc={a.body} sizes="(min-width: 900px) 720px, 100vw" /></div>
|
|
51
|
+
</article>
|
|
52
|
+
{more.length > 0 && (
|
|
53
|
+
<section class="related" data-testid="more-by-author">
|
|
54
|
+
<div class="container">
|
|
55
|
+
<div class="related__head"><h2 class="h2">{t("moreFromAuthor", { name: a.author?.fields.name ?? "" })}</h2></div>
|
|
56
|
+
<div class="card-grid card-grid--3">{more.map((r) => <ArticleCard article={r.fields} url={url(r.path!)} locale={locale} compact />)}</div>
|
|
57
|
+
</div>
|
|
58
|
+
</section>
|
|
59
|
+
)}
|
|
60
|
+
{related.length > 0 && (
|
|
61
|
+
<section class="related">
|
|
62
|
+
<div class="container">
|
|
63
|
+
<div class="related__head">
|
|
64
|
+
<h2 class="h2">{t("relatedArticles")}</h2>
|
|
65
|
+
<a class="link-accent" href={index}>{t("allArticles")} →</a>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="card-grid card-grid--3">{related.map((r) => <ArticleCard article={r.fields} url={url(r.path!)} locale={locale} compact />)}</div>
|
|
68
|
+
</div>
|
|
69
|
+
</section>
|
|
70
|
+
)}
|
|
71
|
+
</Layout>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
// examples/astro/src/entry-pages/news.astro — the entry page of the collection "news", at
|
|
3
|
+
// /company/news/<slug> and /fi/yritys/uutiset/<slug>: the collection's nested path, then the slug.
|
|
4
|
+
import { RichText } from "smoodly/astro/components";
|
|
5
|
+
import { href } from "smoodly/astro/runtime";
|
|
6
|
+
import { formatDate } from "@/components/articles";
|
|
7
|
+
import { newsIndexPath } from "@/components/news";
|
|
8
|
+
import type { EntryFields, EntryItem } from "smoodly";
|
|
9
|
+
import type { PageHead } from "smoodly/astro/runtime";
|
|
10
|
+
import type { news } from "@/smoodly/collections";
|
|
11
|
+
import Layout from "../layouts/Layout.astro";
|
|
12
|
+
import { ui } from "../strings";
|
|
13
|
+
|
|
14
|
+
type Props = { entry: EntryItem<EntryFields<typeof news>>; head: PageHead };
|
|
15
|
+
const { entry, head } = Astro.props;
|
|
16
|
+
const { locale, locales } = entry;
|
|
17
|
+
const { t } = ui(locale);
|
|
18
|
+
const n = entry.fields;
|
|
19
|
+
---
|
|
20
|
+
<Layout head={head} locale={locale} locales={locales}>
|
|
21
|
+
<article class="container article">
|
|
22
|
+
<a class="article__back" href={href(newsIndexPath(locale), locale)}>← {t("allNews")}</a>
|
|
23
|
+
<div class="article__head">
|
|
24
|
+
<h1 class="article__title">{n.title}</h1>
|
|
25
|
+
{n.date && <p class="article__byline">{formatDate(n.date, locale)}</p>}
|
|
26
|
+
</div>
|
|
27
|
+
<div class="article__body prose prose--lead"><RichText doc={n.body} /></div>
|
|
28
|
+
</article>
|
|
29
|
+
</Layout>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
// examples/astro/src/layouts/Layout.astro
|
|
3
|
+
// The site's own document: every page type and entry page renders inside it. The header and the footer are
|
|
4
|
+
// global content, read as live entries per locale, null until published there; the language links come from
|
|
5
|
+
// the page's own `locales` map (spec 2026-09-15), so a layout here can know which page is on screen — Astro
|
|
6
|
+
// renders the page before its layout's slot is filled. Nothing of Smoodly's is written here but the head it
|
|
7
|
+
// knows; in a preview the integration adds what the editor needs to the response.
|
|
8
|
+
import { getLiveEntry } from "astro:content";
|
|
9
|
+
import { Head } from "smoodly/astro/components";
|
|
10
|
+
import { href, type PageHead } from "smoodly/astro/runtime";
|
|
11
|
+
import Header from "../sections/header.astro";
|
|
12
|
+
import Footer from "../sections/footer.astro";
|
|
13
|
+
import "../styles/global.css";
|
|
14
|
+
|
|
15
|
+
type Props = { head: PageHead; locale: string; locales?: Record<string, { path: string | null } | null> };
|
|
16
|
+
const { head, locale, locales = {} } = Astro.props;
|
|
17
|
+
const [{ entry: header }, { entry: footer }, { entry: contact }] = await Promise.all([
|
|
18
|
+
getLiveEntry("header", { locale }),
|
|
19
|
+
getLiveEntry("footer", { locale }),
|
|
20
|
+
getLiveEntry("contact", { locale }),
|
|
21
|
+
]);
|
|
22
|
+
const codes = Object.keys(locales);
|
|
23
|
+
const links = codes.length > 1
|
|
24
|
+
? codes.map((code) => ({ code, url: href(locales[code]?.path ?? "/", code), current: code === locale }))
|
|
25
|
+
: undefined;
|
|
26
|
+
---
|
|
27
|
+
<!doctype html>
|
|
28
|
+
<html lang={locale}>
|
|
29
|
+
<head>
|
|
30
|
+
<meta charset="utf-8" />
|
|
31
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
32
|
+
<Head of={head} fallback="Lorem Co." />
|
|
33
|
+
</head>
|
|
34
|
+
<body>
|
|
35
|
+
{header && <Header {...header.data.fields} settings={header.data.settings} styles={header.data.styles} home={href("/", locale)} locales={links} />}
|
|
36
|
+
<main><slot /></main>
|
|
37
|
+
{footer && <Footer {...footer.data.fields} settings={footer.data.settings} styles={footer.data.styles} contact={contact?.data.fields} />}
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// examples/astro/src/live.config.ts
|
|
2
|
+
// Smoodly's content as live collections (spec 2026-10-02 astro cloud fit §6): a loader per collection, global
|
|
3
|
+
// item and the pages, from the package; this file only names them. `getLiveCollection("articles", { locale })`
|
|
4
|
+
// in a view reads through the read layer, and the response is tagged by what it read.
|
|
5
|
+
import { defineLiveCollection } from "astro:content";
|
|
6
|
+
import { entriesLoader, globalLoader, pageLoader, pageTreeLoader } from "smoodly/astro/content";
|
|
7
|
+
import { articles, news, people } from "@/smoodly/collections";
|
|
8
|
+
import { contact, footer, header, quote } from "@/smoodly/globals";
|
|
9
|
+
|
|
10
|
+
export const collections = {
|
|
11
|
+
pages: defineLiveCollection({ loader: pageLoader() }),
|
|
12
|
+
pageTree: defineLiveCollection({ loader: pageTreeLoader() }),
|
|
13
|
+
articles: defineLiveCollection({ loader: entriesLoader(articles) }),
|
|
14
|
+
news: defineLiveCollection({ loader: entriesLoader(news) }),
|
|
15
|
+
people: defineLiveCollection({ loader: entriesLoader(people) }),
|
|
16
|
+
header: defineLiveCollection({ loader: globalLoader(header) }),
|
|
17
|
+
footer: defineLiveCollection({ loader: globalLoader(footer) }),
|
|
18
|
+
contact: defineLiveCollection({ loader: globalLoader(contact) }),
|
|
19
|
+
quote: defineLiveCollection({ loader: globalLoader(quote) }),
|
|
20
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
// examples/astro/src/page-types/articlesIndex.astro — the view of the page type named "articlesIndex": the
|
|
3
|
+
// editor owns the hero; the grid reads the published articles as a live collection, newest first (the
|
|
4
|
+
// collection's `order`), and in the canvas the drafts too (the request scope reads drafts in a preview).
|
|
5
|
+
import { getLiveCollection } from "astro:content";
|
|
6
|
+
import { Zone } from "smoodly/astro/components";
|
|
7
|
+
import { href } from "smoodly/astro/runtime";
|
|
8
|
+
import type { PageContext } from "smoodly";
|
|
9
|
+
import type { PageHead, ZoneContent } from "smoodly/astro/runtime";
|
|
10
|
+
import Layout from "../layouts/Layout.astro";
|
|
11
|
+
import ArticleCard from "../components/ArticleCard.astro";
|
|
12
|
+
|
|
13
|
+
type Props = { page: PageContext; zones: Record<string, ZoneContent>; head: PageHead };
|
|
14
|
+
const { page, zones, head } = Astro.props;
|
|
15
|
+
const { entries = [] } = await getLiveCollection("articles", { locale: page.locale });
|
|
16
|
+
---
|
|
17
|
+
<Layout head={head} locale={page.locale} locales={page.locales}>
|
|
18
|
+
<Zone of={zones.hero} />
|
|
19
|
+
<section class="container articles-index">
|
|
20
|
+
<div class="card-grid">
|
|
21
|
+
{entries.map(({ data: entry }) => <ArticleCard article={entry.fields} url={href(entry.path!, page.locale)} locale={page.locale} />)}
|
|
22
|
+
</div>
|
|
23
|
+
</section>
|
|
24
|
+
</Layout>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
// examples/astro/src/page-types/home.astro — the view of the page type named "home"
|
|
3
|
+
import { Zone } from "smoodly/astro/components";
|
|
4
|
+
import type { PageContext } from "smoodly";
|
|
5
|
+
import type { PageHead, ZoneContent } from "smoodly/astro/runtime";
|
|
6
|
+
import Layout from "../layouts/Layout.astro";
|
|
7
|
+
|
|
8
|
+
type Props = { page: PageContext; zones: Record<string, ZoneContent>; head: PageHead };
|
|
9
|
+
const { page, zones, head } = Astro.props;
|
|
10
|
+
---
|
|
11
|
+
<Layout head={head} locale={page.locale} locales={page.locales}>
|
|
12
|
+
<Zone of={zones.hero} />
|
|
13
|
+
<Zone of={zones.body} />
|
|
14
|
+
</Layout>
|