create-smoodly-app 0.0.45 → 0.0.47
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/astro-blank/supabase/migrations/20261008120000_smoodly_v10.sql +47 -0
- package/templates/{blank/supabase/migrations/20260930041056_smoodly_views.sql → astro-blank/supabase/migrations/20261008120100_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/astro-blank-intl/supabase/migrations/20261008120000_smoodly_v10.sql +47 -0
- package/templates/{blank-intl/supabase/migrations/20260930041056_smoodly_views.sql → astro-blank-intl/supabase/migrations/20261008120100_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 +32 -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/astro-lorem/supabase/migrations/20261008120000_smoodly_v10.sql +47 -0
- package/templates/{lorem/supabase/migrations/20260930041056_smoodly_views.sql → astro-lorem/supabase/migrations/20261008120100_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 +32 -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/astro-lorem-intl/supabase/migrations/20261008120000_smoodly_v10.sql +47 -0
- package/templates/{lorem-intl/supabase/migrations/20260930041056_smoodly_views.sql → astro-lorem-intl/supabase/migrations/20261008120100_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/20261008120000_smoodly_v10.sql +47 -0
- package/templates/blank/supabase/migrations/20261008120100_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/20261008120000_smoodly_v10.sql +47 -0
- package/templates/blank-intl/supabase/migrations/20261008120100_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/20261008120000_smoodly_v10.sql +47 -0
- package/templates/lorem/supabase/migrations/20261008120100_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/20261008120000_smoodly_v10.sql +47 -0
- package/templates/lorem-intl/supabase/migrations/20261008120100_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
package/README.md
CHANGED
|
@@ -2,18 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
npx create-smoodly-app my-site
|
|
4
4
|
|
|
5
|
-
A fresh Next.js
|
|
6
|
-
project holding the schema, `.env
|
|
7
|
-
sign in.
|
|
5
|
+
A fresh Astro or Next.js site with the Smoodly admin mounted at `/admin`, a
|
|
6
|
+
Supabase project holding the schema, `.env` (Astro) or `.env.local` (Next)
|
|
7
|
+
written, and a first editor who can sign in.
|
|
8
8
|
|
|
9
9
|
## What it asks
|
|
10
10
|
|
|
11
11
|
1. Project name (also the positional argument).
|
|
12
|
-
2. **
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
`
|
|
16
|
-
3.
|
|
12
|
+
2. **Framework**: Astro (the default, and what `--yes` takes) or Next.js.
|
|
13
|
+
Flag: `--framework astro|next`. The questions below apply to both; the
|
|
14
|
+
Astro site ships no React, and writes `.env` (its `npm start` reads it)
|
|
15
|
+
with `SITE_URL` on port 4321.
|
|
16
|
+
3. **Multilingual?** No (default) scaffolds one language. Yes asks for the
|
|
17
|
+
locales, comma-separated, the first being the default (`en, fi`). Next
|
|
18
|
+
gets the next-intl layout: the site under `app/[locale]/`, `i18n/`,
|
|
19
|
+
`proxy.ts`, translated URLs per locale; Astro gets its own i18n config
|
|
20
|
+
(`astro.config.ts` and `src/smoodly/config.ts`). Flag: `--locales en,fi`.
|
|
21
|
+
4. Where content lives: a **local Supabase stack** (`supabase init` +
|
|
17
22
|
`supabase start` inside the app, with the services Smoodly never uses
|
|
18
23
|
excluded — the image proxy, edge functions, analytics, the pooler —
|
|
19
24
|
so the stack stays small beside any other you run; needs
|
|
@@ -29,14 +34,14 @@ sign in.
|
|
|
29
34
|
project is Smoodly's own: its tables are created unprefixed in `public`,
|
|
30
35
|
so an app that keeps its own tables in Supabase gives them a project of
|
|
31
36
|
their own, or takes Smoodly Cloud for content (DESIGN.md §1).
|
|
32
|
-
|
|
37
|
+
5. The first editor: pick an existing Auth user or create one (email +
|
|
33
38
|
password). The `members` row is written with role `admin`, the email
|
|
34
39
|
beside the id.
|
|
35
40
|
If `@` does not appear when you type it (macOS, `@` on Option+2 with the
|
|
36
41
|
terminal's "Option as Meta" setting on), paste the address or pass
|
|
37
42
|
`--editor-email`.
|
|
38
43
|
|
|
39
|
-
Every prompt has a flag, so CI can run it: `--supabase local|hosted`, `--locales`,
|
|
44
|
+
Every prompt has a flag, so CI can run it: `--framework astro|next`, `--supabase local|hosted`, `--locales`,
|
|
40
45
|
`--url`, `--publishable-key`, `--secret-key`, `--editor-email` (password from
|
|
41
46
|
`SMOODLY_EDITOR_PASSWORD`), `--skip-link`, `--yes`. `--help` lists them.
|
|
42
47
|
A hidden `--smoodly-dep <spec>` overrides the `smoodly` dependency written into
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ function parseFlags(argv) {
|
|
|
32
32
|
"smoodly-dep": { type: "string" },
|
|
33
33
|
locales: { type: "string" },
|
|
34
34
|
starter: { type: "string" },
|
|
35
|
+
framework: { type: "string" },
|
|
35
36
|
"skip-link": { type: "boolean", default: false },
|
|
36
37
|
yes: { type: "boolean", short: "y", default: false },
|
|
37
38
|
help: { type: "boolean", short: "h", default: false }
|
|
@@ -46,6 +47,10 @@ function parseFlags(argv) {
|
|
|
46
47
|
if (starter !== void 0 && starter !== "lorem" && starter !== "blank") {
|
|
47
48
|
throw new Error(`--starter must be "lorem" or "blank", got "${starter}"`);
|
|
48
49
|
}
|
|
50
|
+
const framework = values.framework;
|
|
51
|
+
if (framework !== void 0 && framework !== "astro" && framework !== "next") {
|
|
52
|
+
throw new Error(`--framework must be "astro" or "next", got "${framework}"`);
|
|
53
|
+
}
|
|
49
54
|
return {
|
|
50
55
|
name: positionals[0],
|
|
51
56
|
supabase,
|
|
@@ -58,10 +63,11 @@ function parseFlags(argv) {
|
|
|
58
63
|
help: values.help ?? false,
|
|
59
64
|
smoodlyDep: values["smoodly-dep"],
|
|
60
65
|
locales: values.locales === void 0 ? void 0 : parseLocales(values.locales),
|
|
61
|
-
starter
|
|
66
|
+
starter,
|
|
67
|
+
framework
|
|
62
68
|
};
|
|
63
69
|
}
|
|
64
|
-
var HELP = `create-smoodly-app \u2014 a fresh Next.js site with Smoodly installed
|
|
70
|
+
var HELP = `create-smoodly-app \u2014 a fresh Astro or Next.js site with Smoodly installed
|
|
65
71
|
|
|
66
72
|
Usage: npx create-smoodly-app [folder] [options]
|
|
67
73
|
|
|
@@ -69,8 +75,9 @@ Usage: npx create-smoodly-app [folder] [options]
|
|
|
69
75
|
the package name: lowercase letters, digits, dots, dashes and underscores.
|
|
70
76
|
|
|
71
77
|
Options:
|
|
78
|
+
--framework astro|next The framework (asked when omitted; astro is the default)
|
|
72
79
|
--supabase local|hosted Where content lives (asked when omitted; local needs the Supabase CLI)
|
|
73
|
-
--locales <a,b,\u2026> Multilingual: the locales, first is the default (
|
|
80
|
+
--locales <a,b,\u2026> Multilingual: the locales, first is the default (Astro i18n or next-intl; omitted = one language)
|
|
74
81
|
--starter lorem|blank lorem: the Lorem Co. tour of every feature (default); blank: one of each, for building your own
|
|
75
82
|
--url <url> Hosted: the Supabase project URL
|
|
76
83
|
--publishable-key <key> Hosted: the anon / publishable key
|
|
@@ -145,15 +152,15 @@ async function hasCommand(cmd, run2, cwd) {
|
|
|
145
152
|
|
|
146
153
|
// src/ports-net.ts
|
|
147
154
|
import { createServer } from "node:net";
|
|
148
|
-
function canListen(
|
|
155
|
+
function canListen(port2, host) {
|
|
149
156
|
return new Promise((resolve3) => {
|
|
150
157
|
const server = createServer();
|
|
151
158
|
server.once("error", () => resolve3(false));
|
|
152
|
-
server.listen(
|
|
159
|
+
server.listen(port2, host, () => server.close(() => resolve3(true)));
|
|
153
160
|
});
|
|
154
161
|
}
|
|
155
|
-
async function isPortFree(
|
|
156
|
-
return await canListen(
|
|
162
|
+
async function isPortFree(port2) {
|
|
163
|
+
return await canListen(port2, "127.0.0.1") && await canListen(port2, "0.0.0.0");
|
|
157
164
|
}
|
|
158
165
|
|
|
159
166
|
// src/prompts.ts
|
|
@@ -161,7 +168,7 @@ import * as p from "@clack/prompts";
|
|
|
161
168
|
import { resolve as resolve2 } from "node:path";
|
|
162
169
|
|
|
163
170
|
// src/env.ts
|
|
164
|
-
function renderEnv(keys) {
|
|
171
|
+
function renderEnv(keys, siteUrl2 = "http://localhost:3000") {
|
|
165
172
|
return [
|
|
166
173
|
"# Smoodly, self-host: the content project's values. The live site reads",
|
|
167
174
|
"# with SMOODLY_URL and SMOODLY_SECRET_KEY; the admin also signs in with",
|
|
@@ -173,7 +180,7 @@ function renderEnv(keys) {
|
|
|
173
180
|
"",
|
|
174
181
|
"# The site's own address: absolute hreflang and social URLs. Set it to",
|
|
175
182
|
"# the production URL where you deploy.",
|
|
176
|
-
|
|
183
|
+
`SITE_URL=${siteUrl2}`,
|
|
177
184
|
""
|
|
178
185
|
].join("\n");
|
|
179
186
|
}
|
|
@@ -224,6 +231,8 @@ async function isEmptyOrMissing(dir) {
|
|
|
224
231
|
}
|
|
225
232
|
var ROUTING_LOCALES = ' locales: ["en", "fi"],';
|
|
226
233
|
var ROUTING_DEFAULT = ' defaultLocale: "en",';
|
|
234
|
+
var ASTRO_I18N_LINE = ' i18n: { locales: ["en", "fi"], defaultLocale: "en" },';
|
|
235
|
+
var ASTRO_CONFIG_LOCALES_LINE = ' locales: { default: "en", supported: ["en", "fi"] },';
|
|
227
236
|
var ARTICLES_PATH_LINE = ' path: { en: "posts", fi: "artikkelit" },';
|
|
228
237
|
var ARTICLES_SLUG_LINE = ' slug: { en: "posts", fi: "artikkelit" },';
|
|
229
238
|
var NEWS_PATH_LINE = ' path: { en: "company/news", fi: "yritys/uutiset" },';
|
|
@@ -244,7 +253,20 @@ async function scaffold(opts) {
|
|
|
244
253
|
pkg.name = opts.name;
|
|
245
254
|
if (opts.smoodlyDep) pkg.dependencies.smoodly = opts.smoodlyDep;
|
|
246
255
|
await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
247
|
-
|
|
256
|
+
const astro = opts.framework === "astro";
|
|
257
|
+
const root = astro ? "src/" : "";
|
|
258
|
+
if (opts.locales && astro) {
|
|
259
|
+
const rewriteLine = async (rel, line, next) => {
|
|
260
|
+
const path = join(opts.dir, rel);
|
|
261
|
+
const source = await readFile(path, "utf8");
|
|
262
|
+
if (!source.includes(line)) throw new Error(`${rel} in the template has drifted; expected the line
|
|
263
|
+
${line}`);
|
|
264
|
+
await writeFile(path, source.replace(line, next));
|
|
265
|
+
};
|
|
266
|
+
await rewriteLine("astro.config.ts", ASTRO_I18N_LINE, ` i18n: { locales: [${opts.locales.map((l) => JSON.stringify(l)).join(", ")}], defaultLocale: ${JSON.stringify(opts.locales[0])} },`);
|
|
267
|
+
await rewriteLine("src/smoodly/config.ts", ASTRO_CONFIG_LOCALES_LINE, ` locales: { default: ${JSON.stringify(opts.locales[0])}, supported: [${opts.locales.map((l) => JSON.stringify(l)).join(", ")}] },`);
|
|
268
|
+
}
|
|
269
|
+
if (opts.locales && !astro) {
|
|
248
270
|
const routingPath = join(opts.dir, "i18n/routing.ts");
|
|
249
271
|
const routing = await readFile(routingPath, "utf8");
|
|
250
272
|
if (!routing.includes(ROUTING_LOCALES) || !routing.includes(ROUTING_DEFAULT)) {
|
|
@@ -254,23 +276,25 @@ async function scaffold(opts) {
|
|
|
254
276
|
routingPath,
|
|
255
277
|
routing.replace(ROUTING_LOCALES, ` locales: [${opts.locales.map((l) => JSON.stringify(l)).join(", ")}],`).replace(ROUTING_DEFAULT, ` defaultLocale: ${JSON.stringify(opts.locales[0])},`)
|
|
256
278
|
);
|
|
257
|
-
|
|
279
|
+
}
|
|
280
|
+
if (opts.locales) {
|
|
281
|
+
const source = await readFile(join(opts.dir, `${root}messages`, "en.json"), "utf8").catch(() => null);
|
|
258
282
|
if (source !== null) {
|
|
259
283
|
for (const locale of opts.locales) {
|
|
260
|
-
const file = join(opts.dir,
|
|
284
|
+
const file = join(opts.dir, `${root}messages`, `${locale}.json`);
|
|
261
285
|
if (await readFile(file, "utf8").catch(() => null) === null) await writeFile(file, source);
|
|
262
286
|
}
|
|
263
287
|
}
|
|
264
288
|
if (opts.starter !== "blank") {
|
|
265
289
|
const rewrites = [
|
|
266
|
-
{ map: articlesSegments(opts.locales), from: '{ en: "posts", fi: "artikkelit" }', lines: [["smoodly/collections.ts", ARTICLES_PATH_LINE], ["components/pages/Articles.
|
|
267
|
-
{ map: newsSegments(opts.locales), from: '{ en: "company/news", fi: "yritys/uutiset" }', lines: [["smoodly/collections.ts", NEWS_PATH_LINE], ["components/pages/News.
|
|
290
|
+
{ map: articlesSegments(opts.locales), from: '{ en: "posts", fi: "artikkelit" }', lines: [["smoodly/collections.ts", ARTICLES_PATH_LINE], ["components/pages/Articles.schema.ts", ARTICLES_SLUG_LINE]] },
|
|
291
|
+
{ map: newsSegments(opts.locales), from: '{ en: "company/news", fi: "yritys/uutiset" }', lines: [["smoodly/collections.ts", NEWS_PATH_LINE], ["components/pages/News.schema.ts", NEWS_SLUG_LINE]] }
|
|
268
292
|
];
|
|
269
293
|
for (const { map, from, lines } of rewrites) {
|
|
270
294
|
for (const [rel, line] of lines) {
|
|
271
|
-
const path = join(opts.dir, rel);
|
|
295
|
+
const path = join(opts.dir, root + rel);
|
|
272
296
|
const source2 = await readFile(path, "utf8");
|
|
273
|
-
if (!source2.includes(line)) throw new Error(`${rel} in the template has drifted; expected the line
|
|
297
|
+
if (!source2.includes(line)) throw new Error(`${root}${rel} in the template has drifted; expected the line
|
|
274
298
|
${line}`);
|
|
275
299
|
await writeFile(path, source2.replace(line, line.replace(from, map)));
|
|
276
300
|
}
|
|
@@ -302,7 +326,16 @@ async function resolveAnswers(flags2, ctx, env = process.env) {
|
|
|
302
326
|
const invalid = validName(name);
|
|
303
327
|
if (invalid) bail(invalid);
|
|
304
328
|
if (!await isEmptyOrMissing(dir)) bail(`${dir} exists and is not empty.`);
|
|
305
|
-
const
|
|
329
|
+
const framework = flags2.framework ?? (flags2.yes ? "astro" : await answer(
|
|
330
|
+
p.select({
|
|
331
|
+
message: "Framework?",
|
|
332
|
+
options: [
|
|
333
|
+
{ value: "astro", label: "Astro", hint: "sections as .astro files, pages cached whole and expired by tag" },
|
|
334
|
+
{ value: "next", label: "Next.js", hint: "sections as React server components" }
|
|
335
|
+
]
|
|
336
|
+
})
|
|
337
|
+
));
|
|
338
|
+
const locales = flags2.locales ?? (flags2.yes ? void 0 : await answer(p.confirm({ message: `Multilingual site? (${framework === "astro" ? "Astro i18n" : "next-intl"}, translated URLs)`, initialValue: false })) ? await answer(
|
|
306
339
|
p.text({
|
|
307
340
|
message: "Locales, comma-separated, the first is the default",
|
|
308
341
|
placeholder: "en, fr",
|
|
@@ -336,7 +369,7 @@ async function resolveAnswers(flags2, ctx, env = process.env) {
|
|
|
336
369
|
if (supabase === "local") {
|
|
337
370
|
if (!ctx.hasSupabaseCli) bail("Local mode needs the Supabase CLI: https://supabase.com/docs/guides/cli (brew install supabase/tap/supabase)");
|
|
338
371
|
if (flags2.editorEmail && !env.SMOODLY_EDITOR_PASSWORD) throw new Error(`Set SMOODLY_EDITOR_PASSWORD to create ${flags2.editorEmail}.`);
|
|
339
|
-
return { name, dir, supabase, hasSupabaseCli: true, smoodlyDep: flags2.smoodlyDep, locales, starter };
|
|
372
|
+
return { name, dir, supabase, hasSupabaseCli: true, smoodlyDep: flags2.smoodlyDep, locales, starter, framework };
|
|
340
373
|
}
|
|
341
374
|
const badUrl = "Supabase project URL must be an http(s) URL, like https://abcd.supabase.co";
|
|
342
375
|
const typedUrl = flags2.url ?? await answer(
|
|
@@ -355,7 +388,7 @@ async function resolveAnswers(flags2, ctx, env = process.env) {
|
|
|
355
388
|
p.log.warn(`No project ref in ${url}; skipping supabase link. Run \`supabase link --project-ref <project-ref>\` and \`supabase db push\` yourself.`);
|
|
356
389
|
}
|
|
357
390
|
const linkAndPush = !ctx.hasSupabaseCli ? false : flags2.skipLink || !ref ? false : flags2.yes ? true : await answer(p.confirm({ message: `Link this app to the project and push the migration now? (supabase link --project-ref ${ref}, supabase db push)` }));
|
|
358
|
-
return { name, dir, supabase, hasSupabaseCli: ctx.hasSupabaseCli, hosted: { keys: { url, publishableKey, secretKey }, linkAndPush }, smoodlyDep: flags2.smoodlyDep, locales, starter };
|
|
391
|
+
return { name, dir, supabase, hasSupabaseCli: ctx.hasSupabaseCli, hosted: { keys: { url, publishableKey, secretKey }, linkAndPush }, smoodlyDep: flags2.smoodlyDep, locales, starter, framework };
|
|
359
392
|
}
|
|
360
393
|
function askEditorWith(flags2, env = process.env) {
|
|
361
394
|
return async (existing) => {
|
|
@@ -388,8 +421,9 @@ function askEditorWith(flags2, env = process.env) {
|
|
|
388
421
|
import { join as join2 } from "node:path";
|
|
389
422
|
|
|
390
423
|
// src/plan.ts
|
|
391
|
-
function templateName(starter, locales) {
|
|
392
|
-
|
|
424
|
+
function templateName(framework, starter, locales) {
|
|
425
|
+
const base = locales === "intl" ? `${starter}-intl` : starter;
|
|
426
|
+
return framework === "astro" ? `astro-${base}` : base;
|
|
393
427
|
}
|
|
394
428
|
function plan(a) {
|
|
395
429
|
if (a.supabase === "local" && !a.hasSupabaseCli) {
|
|
@@ -420,8 +454,8 @@ async function findFreeBlock(ports, isFree, bases = BASES) {
|
|
|
420
454
|
for (const base of bases) {
|
|
421
455
|
const shifted = ports.map((p3) => base + (p3 - DEFAULT_BASE));
|
|
422
456
|
let allFree = true;
|
|
423
|
-
for (const
|
|
424
|
-
if (!await isFree(
|
|
457
|
+
for (const port2 of shifted) {
|
|
458
|
+
if (!await isFree(port2)) {
|
|
425
459
|
allFree = false;
|
|
426
460
|
break;
|
|
427
461
|
}
|
|
@@ -465,12 +499,13 @@ async function run(answers2, deps) {
|
|
|
465
499
|
switch (step) {
|
|
466
500
|
case "copyTemplate":
|
|
467
501
|
await deps.fs.scaffold({
|
|
468
|
-
templateDir: deps.templateDirs[templateName(answers2.starter ?? "lorem", answers2.locales ? "intl" : "single")],
|
|
502
|
+
templateDir: deps.templateDirs[templateName(answers2.framework, answers2.starter ?? "lorem", answers2.locales ? "intl" : "single")],
|
|
469
503
|
dir: cwd,
|
|
470
504
|
name: answers2.name,
|
|
471
505
|
smoodlyDep: answers2.smoodlyDep,
|
|
472
506
|
locales: answers2.locales,
|
|
473
|
-
starter: answers2.starter
|
|
507
|
+
starter: answers2.starter,
|
|
508
|
+
framework: answers2.framework
|
|
474
509
|
});
|
|
475
510
|
break;
|
|
476
511
|
case "install":
|
|
@@ -478,7 +513,7 @@ async function run(answers2, deps) {
|
|
|
478
513
|
await sh("npm", ["install"]);
|
|
479
514
|
break;
|
|
480
515
|
case "gitInit":
|
|
481
|
-
await deps.agentFiles?.(cwd).catch(() => {
|
|
516
|
+
if (answers2.framework === "next") await deps.agentFiles?.(cwd).catch(() => {
|
|
482
517
|
});
|
|
483
518
|
await sh("git", ["init"], { capture: true });
|
|
484
519
|
await sh("git", ["add", "-A"], { capture: true });
|
|
@@ -520,7 +555,7 @@ async function run(answers2, deps) {
|
|
|
520
555
|
await sh("supabase", ["db", "push"]);
|
|
521
556
|
break;
|
|
522
557
|
case "writeEnv":
|
|
523
|
-
await deps.fs.writeFile(join2(cwd,
|
|
558
|
+
await deps.fs.writeFile(join2(cwd, envFile(answers2)), renderEnv(ctx.keys, siteUrl(answers2)));
|
|
524
559
|
break;
|
|
525
560
|
case "ensureEditor":
|
|
526
561
|
ctx.editor = await ensureEditor(deps.editorClient(ctx.keys), deps.askEditor);
|
|
@@ -548,10 +583,12 @@ async function run(answers2, deps) {
|
|
|
548
583
|
return { ok: true, keys: ctx.keys, editor: ctx.editor };
|
|
549
584
|
}
|
|
550
585
|
var withoutSeedSql = (toml) => toml.replace(/(\[db\.seed\]\n(?:#.*\n)*enabled = )true/, "$1false");
|
|
586
|
+
var envFile = (answers2) => answers2.framework === "astro" ? ".env" : ".env.local";
|
|
587
|
+
var siteUrl = (answers2) => answers2.framework === "astro" ? "http://localhost:4321" : "http://localhost:3000";
|
|
551
588
|
function fallbackFor(step, answers2, keys) {
|
|
552
|
-
const envLines = keys ? `Write ${answers2.dir}
|
|
589
|
+
const envLines = keys ? `Write ${answers2.dir}/${envFile(answers2)}:
|
|
553
590
|
|
|
554
|
-
${renderEnv(keys).split("\n").filter((l) => !l.startsWith("#")).join("\n").trimEnd()}` : `Write ${answers2.dir}
|
|
591
|
+
${renderEnv(keys, siteUrl(answers2)).split("\n").filter((l) => !l.startsWith("#")).join("\n").trimEnd()}` : `Write ${answers2.dir}/${envFile(answers2)} with SMOODLY_URL, SMOODLY_SECRET_KEY and SMOODLY_PUBLISHABLE_KEY (from \`supabase status\`), and SITE_URL=${siteUrl(answers2)}.`;
|
|
555
592
|
const editorLines = [
|
|
556
593
|
"Create the first editor, then the starter content:",
|
|
557
594
|
"",
|
|
@@ -597,7 +634,11 @@ var TEMPLATE_DIRS = {
|
|
|
597
634
|
lorem: fileURLToPath(new URL("../templates/lorem/", import.meta.url)),
|
|
598
635
|
"lorem-intl": fileURLToPath(new URL("../templates/lorem-intl/", import.meta.url)),
|
|
599
636
|
blank: fileURLToPath(new URL("../templates/blank/", import.meta.url)),
|
|
600
|
-
"blank-intl": fileURLToPath(new URL("../templates/blank-intl/", import.meta.url))
|
|
637
|
+
"blank-intl": fileURLToPath(new URL("../templates/blank-intl/", import.meta.url)),
|
|
638
|
+
"astro-lorem": fileURLToPath(new URL("../templates/astro-lorem/", import.meta.url)),
|
|
639
|
+
"astro-lorem-intl": fileURLToPath(new URL("../templates/astro-lorem-intl/", import.meta.url)),
|
|
640
|
+
"astro-blank": fileURLToPath(new URL("../templates/astro-blank/", import.meta.url)),
|
|
641
|
+
"astro-blank-intl": fileURLToPath(new URL("../templates/astro-blank-intl/", import.meta.url))
|
|
601
642
|
};
|
|
602
643
|
var flags;
|
|
603
644
|
try {
|
|
@@ -649,15 +690,16 @@ if (!outcome.ok) {
|
|
|
649
690
|
if (outcome.fallback) p2.note(outcome.fallback, "Finish by hand");
|
|
650
691
|
process.exit(1);
|
|
651
692
|
}
|
|
693
|
+
var port = answers.framework === "astro" ? 4321 : 3e3;
|
|
652
694
|
p2.note(
|
|
653
695
|
[
|
|
654
696
|
...relative(process.cwd(), answers.dir) ? [`cd ${relative(process.cwd(), answers.dir)}`] : [],
|
|
655
697
|
"npm run dev",
|
|
656
698
|
"",
|
|
657
|
-
answers.starter === "blank" ?
|
|
658
|
-
|
|
699
|
+
answers.starter === "blank" ? `Site: http://localhost:${port} (a blank site \u2014 build it in ${answers.framework === "astro" ? "src/sections/, src/components/" : "components/"} and at /admin)` : `Site: http://localhost:${port} (the Lorem Co. starter \u2014 edit it at /admin)`,
|
|
700
|
+
`Admin: http://localhost:${port}/admin`,
|
|
659
701
|
`Editor: ${outcome.editor.email ?? outcome.editor.id}`,
|
|
660
|
-
...answers.locales ? [`Locales: ${answers.locales.join(", ")} (i18n/routing.ts)`] : []
|
|
702
|
+
...answers.locales ? [`Locales: ${answers.locales.join(", ")} (${answers.framework === "astro" ? "astro.config.ts and src/smoodly/config.ts" : "i18n/routing.ts"})`] : []
|
|
661
703
|
].join("\n"),
|
|
662
704
|
"Ready"
|
|
663
705
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-smoodly-app",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.47",
|
|
4
4
|
"description": "Create a Smoodly site: a fresh Next.js app with the admin mounted, a Supabase schema, an env file and a first editor.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"prepublishOnly": "npm run build",
|
|
27
27
|
"test": "vitest run",
|
|
28
28
|
"typecheck": "tsc --noEmit && npm run typecheck:templates",
|
|
29
|
-
"typecheck:templates": "npm run build:template && tsc -p templates/lorem.tsconfig.json && tsc -p templates/lorem-intl.tsconfig.json && tsc -p templates/blank.tsconfig.json && tsc -p templates/blank-intl.tsconfig.json"
|
|
29
|
+
"typecheck:templates": "npm run build:template && tsc -p templates/lorem.tsconfig.json && tsc -p templates/lorem-intl.tsconfig.json && tsc -p templates/blank.tsconfig.json && tsc -p templates/blank-intl.tsconfig.json && tsc -p templates/astro-lorem.tsconfig.json && tsc -p templates/astro-lorem-intl.tsconfig.json && tsc -p templates/astro-blank.tsconfig.json && tsc -p templates/astro-blank-intl.tsconfig.json"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@clack/prompts": "^1.7.0",
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Working in this Smoodly site
|
|
2
|
+
|
|
3
|
+
This is an Astro site with Smoodly installed: content lives in Supabase, the admin is mounted at /admin by the `smoodly/astro` integration in `astro.config.ts`, and the site reads content through live collections (`src/live.config.ts`). Read README.md first: it says where things are.
|
|
4
|
+
|
|
5
|
+
## Rules
|
|
6
|
+
|
|
7
|
+
- **Register schemas in the config; views are files by name.** A section's view is
|
|
8
|
+
`src/sections/<name>.astro`, an element's `src/elements/<name>.astro`, a page
|
|
9
|
+
type's `src/page-types/<name>.astro`, an entry page's
|
|
10
|
+
`src/entry-pages/<collection>.astro`, where <name> is the schema's `name`.
|
|
11
|
+
The schema is listed in its barrel (`src/smoodly/sections.ts`, `elements.ts`,
|
|
12
|
+
the config's `pages`; collections and global items in `collections.ts`,
|
|
13
|
+
`globals.ts`) and `src/smoodly/config.ts` is the one registry. The server
|
|
14
|
+
names a schema with no file, and a file with no schema, at the first request.
|
|
15
|
+
- **A `.schema.ts` file imports no component.** Zones, toolsets, global items and
|
|
16
|
+
`node()` take schemas (`z.locked(heroSchema)`), never views.
|
|
17
|
+
- **After a new collection or a `smoodly` upgrade, run `npx smoodly migrate`**
|
|
18
|
+
and apply what it writes (`supabase db push` hosted, `supabase migration up`
|
|
19
|
+
local). It copies the core schema files the package ships and writes a
|
|
20
|
+
read view and order index per collection. Never edit a file it wrote.
|
|
21
|
+
The admin reads the base tables, so it lists a collection either way;
|
|
22
|
+
the view is for SQL and PostgREST readers, the index for `order`.
|
|
23
|
+
- **Content from code goes through `createContent(config)`** from `smoodly/astro`:
|
|
24
|
+
`scripts/seed.ts` is starter content written with it — the admin's own
|
|
25
|
+
operations, so validation and publish checks apply and a failure throws. Never
|
|
26
|
+
write rows or call the stores directly. The seed is idempotent; `npm run seed`.
|
|
27
|
+
- **Reads are live collections.** `src/live.config.ts` names one loader per
|
|
28
|
+
collection, global item, the pages and the page tree; a view reads with
|
|
29
|
+
`getLiveCollection("articles", { locale })` or `getLiveEntry("footer", { locale })`
|
|
30
|
+
from `astro:content`. Every read tags the response, and a publish expires it.
|
|
31
|
+
- **The admin, the preview address and the page shell are injected** by
|
|
32
|
+
`smoodly()` in `astro.config.ts`; the project has no route file for them. A page
|
|
33
|
+
file of your own under `src/pages` wins its address. `site` in `astro.config.ts`
|
|
34
|
+
is the site's own address (from `SITE_URL`).
|
|
35
|
+
- **A link an editor typed goes through `safeHref`** from "smoodly" in an `.astro`
|
|
36
|
+
view: `<a href={safeHref(link.href)}>`. Astro writes attributes as given, so a
|
|
37
|
+
`javascript:` URL would reach the page; the template build refuses a shipped
|
|
38
|
+
view that skips it.
|
|
39
|
+
- **Section styles are inline.** `<Section>` from `smoodly/astro/components` renders
|
|
40
|
+
the root element with Smoodly's styles set and the node id; marks
|
|
41
|
+
(`smoodly.marks(schema)`) tie rendered elements to fields.
|
|
42
|
+
- **Multilingual sites.** The locale set is `locales` in `src/smoodly/config.ts`
|
|
43
|
+
and `i18n` in `astro.config.ts`; the two must agree. UI strings of the site's
|
|
44
|
+
own go through `src/strings.ts` and `src/messages/<locale>.json`.
|
|
45
|
+
- **Fixed versus open pages.** A page type with a `slug` is fixed: one
|
|
46
|
+
record, created for you, never deleted. Without one it is open: editors
|
|
47
|
+
create as many as they like.
|
|
48
|
+
|
|
49
|
+
## Commands
|
|
50
|
+
|
|
51
|
+
npm run dev # http://localhost:4321, /admin is the editor
|
|
52
|
+
npm run build # checks the schema files (smoodly migrate --check), then astro build
|
|
53
|
+
npm run start # the built server (dist/server/entry.mjs)
|
|
54
|
+
npm run seed # starter content, idempotent
|
|
55
|
+
npm run typecheck # astro check
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Smoodly site
|
|
2
|
+
|
|
3
|
+
Created by `create-smoodly-app`. Content lives in Supabase; the admin is
|
|
4
|
+
mounted at `/admin` by the `smoodly/astro` integration. AGENTS.md holds the
|
|
5
|
+
rules for an agent (or a person) building the site.
|
|
6
|
+
|
|
7
|
+
npm run dev # http://localhost:4321 — /admin is the editor
|
|
8
|
+
|
|
9
|
+
## Where things are
|
|
10
|
+
|
|
11
|
+
- `astro.config.ts` — the `smoodly()` integration (it mounts the admin, the preview address and the page shell), the node adapter, the cache and `site` (from `SITE_URL`).
|
|
12
|
+
- `src/page-types/` — one view per page type: `home.astro` (fixed at /, one freeform zone) and `page.astro` (open, editors create many).
|
|
13
|
+
- `src/entry-pages/posts.astro` — the entry page of the posts collection, at /posts/<slug>.
|
|
14
|
+
- `src/sections/text.astro` and `src/components/sections/Text.schema.ts` — the one section: a title and a richtext body.
|
|
15
|
+
- `src/elements/button.astro` and `src/components/elements/Button.schema.ts` — the one element: a link styled as a button, embedded in richtext through `src/smoodly/toolsets.ts`.
|
|
16
|
+
- `src/components/LocaleNav.astro` — the language links every page view renders from its `locales` map; nothing with one locale.
|
|
17
|
+
- `src/layouts/Layout.astro` — the document every view renders: the head, the footer line from the `site` global item, `src/styles/global.css`.
|
|
18
|
+
- `src/smoodly/` — the wiring: `config.ts` (the registry of schemas and the settings), `collections.ts` (posts), `globals.ts` (the site item), `sections.ts` and `elements.ts` (the schemas the config registers), `toolsets.ts`.
|
|
19
|
+
- `src/live.config.ts` — the live collections the views read with `getLiveCollection` and `getLiveEntry`.
|
|
20
|
+
- `scripts/seed.ts` — the home page and the site item, written through `createContent(config)`. `npm run seed` is idempotent.
|
|
21
|
+
- `src/styles/global.css` — a reset, a container, the two tones. Replace it.
|
|
22
|
+
- `.env` — `SMOODLY_URL`, `SMOODLY_SECRET_KEY`, `SMOODLY_PUBLISHABLE_KEY`.
|
|
23
|
+
|
|
24
|
+
## Add a section
|
|
25
|
+
|
|
26
|
+
Copy `src/components/sections/Text.schema.ts`, give the schema a new
|
|
27
|
+
`name` and `title` and declare its fields. List it in `sections` in
|
|
28
|
+
`src/smoodly/sections.ts` and in the `sections` of every zone that may
|
|
29
|
+
hold it in `src/components/pages/*.schema.ts`. Then write its view,
|
|
30
|
+
`src/sections/<name>.astro`, by copying `text.astro`: render the fields
|
|
31
|
+
inside `<Section>` with marks on each. It appears in the editor's "+"
|
|
32
|
+
picker. A schema with no view, and a view with no schema, are named at
|
|
33
|
+
the first request.
|
|
34
|
+
|
|
35
|
+
## Add an element
|
|
36
|
+
|
|
37
|
+
Copy `src/components/elements/Button.schema.ts` (relative imports only).
|
|
38
|
+
Add the schema to `elements` in `src/smoodly/elements.ts` and to the
|
|
39
|
+
`elements` of the toolset in `src/smoodly/toolsets.ts` that may embed
|
|
40
|
+
it, and write `src/elements/<name>.astro`. A link an editor types goes
|
|
41
|
+
through `safeHref`, as in `button.astro`. It appears in the richtext
|
|
42
|
+
editor's "/" menu.
|
|
43
|
+
|
|
44
|
+
## Add a collection
|
|
45
|
+
|
|
46
|
+
Copy the `posts` block in `src/smoodly/collections.ts`, add the new
|
|
47
|
+
collection to `collections` and a loader for it in `src/live.config.ts`,
|
|
48
|
+
and write its entry page, `src/entry-pages/<collection>.astro`, by
|
|
49
|
+
copying `posts.astro`. Then write its read view and order index and
|
|
50
|
+
apply them:
|
|
51
|
+
|
|
52
|
+
npx smoodly migrate
|
|
53
|
+
supabase db push # hosted; `supabase migration up` for the local stack (keeps the content)
|
|
54
|
+
|
|
55
|
+
The same command brings the core schema forward after a `smoodly` upgrade.
|
|
56
|
+
|
|
57
|
+
## Add a global item
|
|
58
|
+
|
|
59
|
+
Copy the `site` block in `src/smoodly/globals.ts`, add it to `globals`
|
|
60
|
+
and give it a loader in `src/live.config.ts`. A view reads it with
|
|
61
|
+
`getLiveEntry("name", { locale })`. Edit it under Globals in the admin.
|
|
62
|
+
|
|
63
|
+
Reseed an empty database any time with `npm run seed`.
|
|
64
|
+
|
|
65
|
+
## Moving the admin
|
|
66
|
+
|
|
67
|
+
The admin is at `/admin`. To serve it somewhere else, say `/studio`:
|
|
68
|
+
|
|
69
|
+
1. set `smoodly({ adminPath: "/studio" })` in `astro.config.ts`,
|
|
70
|
+
2. set `admin: { path: "/studio" }` in `src/smoodly/config.ts`.
|
|
71
|
+
|
|
72
|
+
The two must agree; the admin says so when they do not.
|
|
73
|
+
|
|
74
|
+
## Editors
|
|
75
|
+
|
|
76
|
+
Anyone who may open `/admin` is a Supabase Auth user with a row in the
|
|
77
|
+
`editors` table. To add one: create the user in Supabase Studio
|
|
78
|
+
(Authentication → Users), then in the SQL editor:
|
|
79
|
+
|
|
80
|
+
insert into editors (user_id, role) values ('<the user id>', 'editor');
|
|
81
|
+
|
|
82
|
+
## Hosted Supabase
|
|
83
|
+
|
|
84
|
+
supabase init # if the CLI has not been set up here yet
|
|
85
|
+
supabase link # pick the project
|
|
86
|
+
supabase db push # applies supabase/migrations/
|
|
87
|
+
|
|
88
|
+
Then put the project's URL and keys in `.env`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig, memoryCache } from "astro/config";
|
|
2
|
+
import node from "@astrojs/node";
|
|
3
|
+
import smoodly from "smoodly/astro";
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
output: "server",
|
|
7
|
+
adapter: node({ mode: "standalone" }),
|
|
8
|
+
// Pages are cached whole and expire by tag when an editor publishes (one process, one cache).
|
|
9
|
+
cache: { provider: memoryCache() },
|
|
10
|
+
// The site's own address: canonical, hreflang and social links are absolute on it. Astro reads astro.config
|
|
11
|
+
// before .env, so this sees only a SITE_URL set in the shell; when it is unset, smoodly() sets `site` from
|
|
12
|
+
// SITE_URL in .env. Set SITE_URL where you deploy: `site` is fixed at `astro build`.
|
|
13
|
+
site: process.env.SITE_URL,
|
|
14
|
+
integrations: [smoodly({ config: "src/smoodly/config.ts" })],
|
|
15
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "smoodly-site",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "astro dev",
|
|
7
|
+
"build": "smoodly migrate --check && astro build",
|
|
8
|
+
"start": "node --env-file-if-exists=.env dist/server/entry.mjs",
|
|
9
|
+
"seed": "tsx scripts/seed.ts",
|
|
10
|
+
"typecheck": "astro check"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@astrojs/node": "^11.1.6",
|
|
14
|
+
"@supabase/supabase-js": "^2.113.0",
|
|
15
|
+
"astro": "^7.3.5",
|
|
16
|
+
"smoodly": "0.0.47"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@astrojs/check": "^0.9.10",
|
|
20
|
+
"@types/node": "^26.4.1",
|
|
21
|
+
"typescript": "^5",
|
|
22
|
+
"tsx": "^4"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// The starter's content, written through the content API (`createContent(config)`
|
|
2
|
+
// from smoodly/astro): the admin's own operations, so validation and
|
|
3
|
+
// the publish checks apply and a failure throws. It is also the example
|
|
4
|
+
// of writing content from code. Ships in the scaffold; create-smoodly-app
|
|
5
|
+
// runs `npm run seed` after the first editor. Idempotent: exits once the
|
|
6
|
+
// home page has content in the default locale. Writes the same copy into every configured locale, whatever
|
|
7
|
+
// their codes, so every locale's "/" resolves.
|
|
8
|
+
// Run: npm run seed (needs .env and a Supabase stack).
|
|
9
|
+
import type { PageTree, TreeNode } from "smoodly";
|
|
10
|
+
|
|
11
|
+
const { config } = await import("../src/smoodly/config");
|
|
12
|
+
const { node } = await import("smoodly");
|
|
13
|
+
const { createContent } = await import("smoodly/astro");
|
|
14
|
+
const { content } = createContent(config);
|
|
15
|
+
const { textSchema } = await import("../src/components/sections/Text.schema");
|
|
16
|
+
const c = content;
|
|
17
|
+
|
|
18
|
+
const DEFAULT = config.locales.default;
|
|
19
|
+
const OTHERS = config.locales.supported.filter((l) => l !== DEFAULT);
|
|
20
|
+
|
|
21
|
+
// The home page is code-owned: `find` returns its record, creating it when
|
|
22
|
+
// the database is new. It is seeded once somebody has given it sections.
|
|
23
|
+
const home = (await c.pages.find(DEFAULT, "/"))!;
|
|
24
|
+
if (Object.values((await c.pages.getTree(home.id, DEFAULT))?.zones ?? {}).some((nodes) => nodes.length > 0)) {
|
|
25
|
+
console.log(`Already seeded — the home page has content in "${DEFAULT}".`);
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Richtext is TipTap JSON, the stored format; RichText renders it.
|
|
30
|
+
type Node = Record<string, unknown>;
|
|
31
|
+
const p = (s: string): Node => ({ type: "paragraph", content: [{ type: "text", text: s }] });
|
|
32
|
+
const button = (label: string, href: string): Node => ({ type: "element", attrs: { name: "button", fields: { label, href }, settings: {} } });
|
|
33
|
+
const doc = (...content: Node[]) => ({ type: "doc", content });
|
|
34
|
+
|
|
35
|
+
// --- the site item: name and tagline, published in every locale ------
|
|
36
|
+
|
|
37
|
+
for (const locale of [DEFAULT, ...OTHERS]) {
|
|
38
|
+
await c.globals.set("site", locale, { name: "My site", tagline: "Built with Smoodly" });
|
|
39
|
+
await c.globals.publish("site", locale);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// --- the home page: one Text section and one custom section ----------
|
|
43
|
+
|
|
44
|
+
// The custom section is not a registered section, so it is a plain node object.
|
|
45
|
+
const custom: TreeNode = {
|
|
46
|
+
id: "node-custom",
|
|
47
|
+
type: "custom",
|
|
48
|
+
fields: { rows: [
|
|
49
|
+
{ spans: [6, 6], gap: "md", align: "top", reverse: false, columns: [
|
|
50
|
+
doc(p("A custom section holds rows of columns. Drag the width bar in the inspector to resize them.")),
|
|
51
|
+
doc(p("Each column is richtext. Columns stack on small screens; the developer's stylesheet needs nothing.")),
|
|
52
|
+
] },
|
|
53
|
+
] },
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const tree: PageTree = {
|
|
57
|
+
meta: { description: "A new site, built with Smoodly." },
|
|
58
|
+
zones: {
|
|
59
|
+
body: [
|
|
60
|
+
node(textSchema, {
|
|
61
|
+
title: "Hello",
|
|
62
|
+
body: doc(
|
|
63
|
+
p("This is your home page. Open the admin to edit this text, add sections, create pages and write posts."),
|
|
64
|
+
p("Everything you see is defined in components/ and registered in smoodly/. The README says where things are."),
|
|
65
|
+
button("Open the admin", "/admin"),
|
|
66
|
+
),
|
|
67
|
+
}, { id: "node-hello", settings: { background: "paper" } }),
|
|
68
|
+
// The custom section: the editor's own rows of columns, rendered by Smoodly.
|
|
69
|
+
custom,
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// The home page exists in every locale already (its registration says so): write the tree and publish.
|
|
75
|
+
for (const locale of [DEFAULT, ...OTHERS]) {
|
|
76
|
+
await c.pages.setTree(home.id, locale, tree);
|
|
77
|
+
await c.pages.publish(home.id, locale);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log(`Seeded the blank starter in "${[DEFAULT, ...OTHERS].join('", "')}": the home page and the site item, published.`);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
// src/components/LocaleNav.astro — the language links, rendered by every page view from its own `locales` map:
|
|
3
|
+
// the same page in the other language where it is published there, that language's home otherwise. Nothing
|
|
4
|
+
// with one locale, so the single-language scaffold shares the file.
|
|
5
|
+
import { href } from "smoodly/astro/runtime";
|
|
6
|
+
|
|
7
|
+
type Props = { locale: string; locales: Record<string, { path: string | null } | null> };
|
|
8
|
+
const { locale, locales } = Astro.props;
|
|
9
|
+
const codes = Object.keys(locales);
|
|
10
|
+
---
|
|
11
|
+
{codes.length > 1 && (
|
|
12
|
+
<nav class="container locales" aria-label="Language">
|
|
13
|
+
{codes.map((code) => <a href={href(locales[code]?.path ?? "/", code)} aria-current={code === locale ? "page" : undefined}>{code}</a>)}
|
|
14
|
+
</nav>
|
|
15
|
+
)}
|