├── .gitignore ├── LICENSE ├── README.md ├── astro ├── .env.template ├── .gitignore ├── .nvmrc ├── .stackblitzrc ├── README.md ├── astro.config.mjs ├── netlify.toml ├── package-lock.json ├── package.json ├── public │ ├── assets │ │ ├── blog │ │ │ └── example-blog │ │ │ │ └── alex-bertha-7VAXeUIn3tI-unsplash.jpg │ │ └── logo.svg │ ├── favicon.svg │ └── robots.txt ├── sandbox.config.json ├── src │ ├── components │ │ ├── ArticleSchema.astro │ │ ├── BaseHead.astro │ │ ├── BlogPost.astro │ │ ├── BlogPostPreview.astro │ │ ├── CodeBlock │ │ │ ├── code-block-styles.ts │ │ │ └── code-block.ts │ │ ├── Container.astro │ │ └── SanityPortableText.astro │ ├── data │ │ └── settings.js │ ├── layouts │ │ ├── Base.astro │ │ ├── Page.astro │ │ └── Post.astro │ ├── lib │ │ ├── api.js │ │ └── sanityPortableText.js │ ├── pages │ │ ├── 404.astro │ │ ├── blog │ │ │ ├── [slug].astro │ │ │ ├── category │ │ │ │ └── [slug].astro │ │ │ └── index.astro │ │ └── index.astro │ ├── styles │ │ ├── global.css │ │ └── reset.css │ └── utils │ │ └── helpers.js └── tsconfig.json ├── package-lock.json ├── package.json └── sanity ├── .gitignore ├── .npmignore ├── README.md ├── config ├── .checksums └── @sanity │ ├── data-aspects.json │ ├── default-layout.json │ ├── default-login.json │ ├── form-builder.json │ └── vision.json ├── package.json ├── plugins └── .gitkeep ├── sanity.json ├── schemas ├── author.js ├── blockContent.js ├── category.js ├── post.js └── schema.js ├── static ├── .gitkeep └── favicon.ico └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac files 2 | .DS_Store 3 | 4 | # Dependency directories 5 | /node_modules 6 | 7 | # lerna files 8 | /lerna-debug.log 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 White Pine Studio, LLC 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Astro Sanity Minimal Starter 2 | 3 | ## [Demo Site](https://astro-sanity-minimal-starter.netlify.app/) 4 | 5 | If you haven't heard about [Astro](https://astro.build) yet you're missing out. This starter repo gives you a blog website with a headless CMS setup using [Sanity.io](https://sanity.io). 6 | 7 | Don't be fooled by the simplicity of this starter either. With excellent SEO built in, Astro's excellent developer environment, and performance best practices you're getting one of the best foundations for a personal blog with posts written in markdown. The reason for making such a bare bones starter in terms of styles is that it has what you need out of the box for SEO and site structure but it makes no assumptions about how you want it look and behave. 8 | 9 | Sometimes starters can feel like they are giving us way too much and you'll spend a day picking apart half of the code to get to the setup you actually wanted. Want to use vanilla CSS instead of Tailwind or Scss? No problem! 10 | 11 | ## Features 12 | 13 | - A customizable headless CMS with [Sanity.io](https://sanity.io) 14 | - Excellent SEO Built In 15 | - Open Graph Tags (Twitter, Facebook, etc.) 16 | - User Declared Canonical URLs 17 | - RSS Feed 18 | - XML Sitemap 19 | - Robots.txt 20 | - JSON LD Schema 21 | - Extremely minimal styles 22 | - Performant Google Fonts Setup 23 | 24 | ## Get Started 25 | 26 | Watch my [step-by-step tutorial on YouTube](https://youtu.be/-jAWLTfsSQw) 27 | 28 | **Or** 29 | 30 | 31 | Follow the manual steps below: 32 | 33 | ### Initial Sanity Setup 34 | 35 | 1. [Create a repo from this template](https://github.com/jaydanurwin/astro-sanity-minimal-starter/generate) 36 | 2. If you don't have the Sanity CLI already run `npm install -g @sanity/cli` 37 | 3. Open a terminal from root folder of the project 38 | 4. `cd sanity` 39 | 5. `sanity install` 40 | 6. `sanity init` and follow the prompts (you will need to create a Sanity account if you haven't already) 41 | 8. Navigate to the astro folder 42 | 7. Rename `.env.template` to `.env` and 43 | 8. Replace the PUBLIC_SANITY_PROJECT_ID value with your token ID 44 | 45 | **Note:** You will want to add http://localhost:3000 to your allowed CORS orgins in your Sanity project settings at [https://manage.sanity.io](https://manage.sanity.io) 46 | 47 | ### To run your Sanity Studio 48 | 49 | 1. Open a terminal located at the sanity folder 50 | 2. `sanity install` 51 | 3. `sanity start` 52 | 4. Your studio should be running on [http://localhost:3333](http://localhost:3333) 53 | 5. Open [http://localhost:3333](http://localhost:3333) and copy the project ID from the Project info section 54 | 55 | ### To run your Astro site 56 | 57 | 1. Open a terminal located at the astro folder 58 | 2. `npm install` 59 | 3. `npm start` 60 | 4. Your Astro site should be running on [http://localhost:3000](http://localhost:3000) 61 | 5. `npm run build` to build to production locally 62 | -------------------------------------------------------------------------------- /astro/.env.template: -------------------------------------------------------------------------------- 1 | PUBLIC_SANITY_PROJECT_ID="8hj1t7km" 2 | PUBLIC_SANITY_DATASET="production" 3 | PUBLIC_SANITY_API_VERSION="v2021-03-25" 4 | PUBLIC_SANITY_READ_TOKEN="" 5 | PUBLIC_SANITY_GRAPHQL_URL="https://8hj1t7km.api.sanity.io/v1/graphql/production/default" -------------------------------------------------------------------------------- /astro/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist 3 | 4 | # dependencies 5 | node_modules/ 6 | .snowpack/ 7 | 8 | # logs 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # environment variables 14 | .env 15 | .env.production 16 | 17 | # macOS-specific files 18 | .DS_Store 19 | -------------------------------------------------------------------------------- /astro/.nvmrc: -------------------------------------------------------------------------------- 1 | v14.15.1 -------------------------------------------------------------------------------- /astro/.stackblitzrc: -------------------------------------------------------------------------------- 1 | { 2 | "startCommand": "npm start", 3 | "env": { 4 | "ENABLE_CJS_IMPORTS": true 5 | } 6 | } -------------------------------------------------------------------------------- /astro/README.md: -------------------------------------------------------------------------------- 1 | [![Netlify Status](https://api.netlify.com/api/v1/badges/6aa49dbb-2dc9-4ee1-baab-5d80d4136677/deploy-status)](https://app.netlify.com/sites/astro-minimal-starter/deploys) 2 | 3 | # astro-minimal-starter 4 | 5 | ## [Demo Site](https://astro-minimal-starter.netlify.app/) 6 | 7 | If you haven't heard about [Astro](https://astro.build) yet you're missing out. This starter repo gives you a blog website with posts written in Markdown, all powered by Astro. 8 | 9 | Don't be fooled by the simplicity of this starter either. With excellent SEO built in, Astro's excellent developer environment, and performance best practices you're getting one of the best foundations for a personal blog with posts written in markdown. The reason for making such a bare bones starter in terms of styles is that it has what you need out of the box for SEO and site structure but it makes no assumptions about how you want it look and behave. 10 | 11 | Sometimes starters can feel like they are giving us way too much and you'll spend a day picking apart half of the code to get to the setup you actually wanted. Want to vanilla CSS instead of Tailwind or Scss? No problem! 12 | 13 | ## Features 14 | 15 | - Excellent SEO Built In 16 | - Open Graph Tags (Twitter, Facebook, etc.) 17 | - User Declared Canonical URLs 18 | - RSS Feed 19 | - XML Sitemap 20 | - Robots.txt 21 | - JSON LD Schema 22 | - Markdown based blog posts with featured images 23 | - Extremely minimal styles 24 | - Performant Google Fonts Setup 25 | 26 | ## Get Started 27 | 28 | ``` 29 | # Install Dependencies 30 | 31 | npm i 32 | 33 | # Run Site locally 34 | 35 | npm start 36 | 37 | # Build Site 38 | 39 | npm run build 40 | ``` 41 | 42 | Navigate to `src/data/site.js` and edit to match your site's information. 43 | 44 | Start writing new blog posts in Markdown at `src/pages/blog/` 45 | -------------------------------------------------------------------------------- /astro/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'astro/config'; 2 | import sitemap from '@astrojs/sitemap'; 3 | 4 | import sanity from 'astro-sanity'; 5 | 6 | // https://astro.build/config 7 | export default defineConfig({ 8 | site: 'https://astro-sanity-minimal-starter.netlify.app/', 9 | // Your public domain, e.g.: https://my-site.dev/ 10 | integrations: [ 11 | sitemap(), 12 | sanity({ 13 | projectId: '8hj1t7km', 14 | dataset: 'production', 15 | apiVersion: 'v2021-03-25', 16 | useCdn: true, 17 | }), 18 | ], 19 | }); 20 | -------------------------------------------------------------------------------- /astro/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "npm run build" 3 | publish = "dist" -------------------------------------------------------------------------------- /astro/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "astro-sanity-minimal-starter", 3 | "version": "v3.2.0", 4 | "private": false, 5 | "scripts": { 6 | "dev": "astro dev", 7 | "start": "astro dev", 8 | "build": "astro build" 9 | }, 10 | "devDependencies": { 11 | "@astrojs/sitemap": "^0.1.0", 12 | "astro": "^1.2.4", 13 | "astro-sanity": "^1.0.0", 14 | "date-fns": "^2.23.0", 15 | "dotenv": "^10.0.0", 16 | "lit": "^2.3.1", 17 | "prismjs": "^1.25.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /astro/public/assets/blog/example-blog/alex-bertha-7VAXeUIn3tI-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/astro-sanity-minimal-starter/1e89323443682f6a6d571f37f8fc50a5c901f92c/astro/public/assets/blog/example-blog/alex-bertha-7VAXeUIn3tI-unsplash.jpg -------------------------------------------------------------------------------- /astro/public/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /astro/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /astro/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | -------------------------------------------------------------------------------- /astro/sandbox.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "infiniteLoopProtection": true, 3 | "hardReloadOnChange": false, 4 | "view": "browser", 5 | "template": "node", 6 | "container": { 7 | "port": 3000, 8 | "startScript": "start", 9 | "node": "14" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /astro/src/components/ArticleSchema.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import settings from '../data/settings.js'; 3 | 4 | const { title, permalink, publishDate, ogImageUrl, description } = Astro.props; 5 | 6 | const ldData = { 7 | "@context": "https://schema.org", 8 | "@type": "Article", 9 | "publisher": { 10 | "@type": "Organization", 11 | "name": `${settings.name} Blog`, 12 | "url": `${settings.url}/blog/`, 13 | }, 14 | "author": { 15 | "@type": "Person", 16 | "name": `${settings.name}`, 17 | "image": { 18 | "@type": "ImageObject", 19 | "url": `${settings.url}/assets/img/favicon.png`, 20 | "width": 512, 21 | "height": 512 22 | }, 23 | "url": "https://example.com/about/", 24 | "sameAs": [ 25 | `${settings.url}`, 26 | `${settings.facebookURL}`, 27 | `${settings.twitterURL}`, 28 | `${settings.instagramURL}` 29 | ] 30 | }, 31 | "headline": `${title}`, 32 | "url": `${permalink}`, 33 | "datePublished": `${publishDate}`, 34 | "image": { 35 | "@type": "ImageObject", 36 | "url": `${ogImageUrl}`, 37 | "width": 1200, 38 | }, 39 | "description": `${description}`, 40 | "mainEntityOfPage": { 41 | "@type": "WebPage", 42 | "@id": `${settings.url}/blog/` 43 | } 44 | } 45 | --- 46 | 47 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /astro/src/lib/api.js: -------------------------------------------------------------------------------- 1 | import { useSanityClient } from "astro-sanity"; 2 | 3 | export async function getAllPosts() { 4 | const query = `*[_type == 'post']{"categoryData": categories[]->{slug, title},author -> {name}, ...} | order(publishedAt desc)`; 5 | const data = await useSanityClient().fetch(query); 6 | return data; 7 | } 8 | 9 | export async function getAllCategoriesWithPosts() { 10 | const query = `*[_type == 'category']{"posts": *[_type == "post" && references(^._id)] | order(publishedAt desc), ...}`; 11 | const data = await useSanityClient().fetch(query); 12 | return data; 13 | } -------------------------------------------------------------------------------- /astro/src/lib/sanityPortableText.js: -------------------------------------------------------------------------------- 1 | import { portableTextToHtml } from 'astro-sanity'; 2 | import { getSanityImageURL } from '../utils/helpers.js'; 3 | 4 | const customComponents = { 5 | types: { 6 | mainImage: ({ value }) => { 7 | return ` 8 | 9 | 13 | ${value.alt} 18 | 19 | `; 20 | }, 21 | image: ({ value }) => { 22 | return ` 23 | 24 | 28 | ${value.alt} 33 | 34 | `; 35 | }, 36 | code: ({ value }) => { 37 | return ``; 38 | }, 39 | }, 40 | }; 41 | 42 | export function sanityPortableText(portabletext) { 43 | return portableTextToHtml(portabletext, customComponents); 44 | } -------------------------------------------------------------------------------- /astro/src/pages/404.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../layouts/Page.astro'; 3 | import Container from '../components/Container.astro'; 4 | 5 | const seo = { 6 | title: 'Uh Oh! Page Not Found', 7 | description: 'This is a starter repo for an blog built with Astro including open graph tags, canonical urls, RSS, sitemap support.', 8 | } 9 | 10 | --- 11 | 12 | 13 | 14 |

404

15 |

Uh Oh! We couldn't find the page you were looking for

16 | Return Home 17 |
18 |
-------------------------------------------------------------------------------- /astro/src/pages/blog/[slug].astro: -------------------------------------------------------------------------------- 1 | --- 2 | // Component Imports 3 | import Layout from '../../layouts/Post.astro' 4 | import BlogPost from '../../components/BlogPost.astro' 5 | import { getSanityImageURL } from '../../utils/helpers.js'; 6 | import { getAllPosts } from '../../lib/api.js'; 7 | 8 | export async function getStaticPaths() { 9 | const allBlogPosts = await getAllPosts(); 10 | 11 | // rss({ 12 | // title: 'Example Blog', 13 | // description: 'An example blog on Astro', 14 | // customData: `en-us`, 15 | // items: allBlogPosts.map(item => ({ 16 | // title: item.title, 17 | // description: item.description, 18 | // link: `/blog/${item.slug.current}`, 19 | // pubDate: item.publishedAt, 20 | // })), 21 | // }); 22 | return allBlogPosts.map(post => ({ params: { slug: post.slug.current }, props: { post } })); 23 | } 24 | 25 | const { post } = Astro.props; 26 | 27 | const seo = { 28 | title: post.title, 29 | description: post.description, 30 | image: getSanityImageURL(post.mainImage).width(1200).url(), 31 | } 32 | --- 33 | 34 | 35 | {post.categoryData && } 40 | 41 | -------------------------------------------------------------------------------- /astro/src/pages/blog/category/[slug].astro: -------------------------------------------------------------------------------- 1 | --- 2 | // Component Imports 3 | import Layout from '../../../layouts/Page.astro' 4 | import BlogPostPreview from '../../../components/BlogPostPreview.astro' 5 | 6 | import { getAllCategoriesWithPosts } from '../../../lib/api.js'; 7 | 8 | export async function getStaticPaths() { 9 | const allCategoryData = await getAllCategoriesWithPosts(); 10 | 11 | return allCategoryData.map(category => ({params: { slug: category.slug.current }, props: {category}})); 12 | } 13 | 14 | const { category } = Astro.props; 15 | 16 | const seo = { 17 | title: category.title, 18 | } 19 | --- 20 | 21 | 22 |

All Posts Tagged with "{category.title}"

23 | {category.posts.map((post) => ( 24 | 25 | ))} 26 |
-------------------------------------------------------------------------------- /astro/src/pages/blog/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | // Component Imports 3 | import Layout from '../../layouts/Page.astro' 4 | import BlogPostPreview from '../../components/BlogPostPreview.astro'; 5 | 6 | import { getAllPosts } from '../../lib/api.js'; 7 | import Container from '../../components/Container.astro'; 8 | 9 | 10 | const seo = { 11 | title: 'Example Blog', 12 | description: 'This is a starter repo for an blog built with Astro including open graph tags, canonical urls, RSS, sitemap support.' 13 | } 14 | 15 | const allPostData = await getAllPosts(); 16 | 17 | --- 18 | 19 | 20 | 21 |
22 |
23 | {allPostData.map((post) => 24 | )} 25 |
26 |
27 |
28 |
29 | 30 | -------------------------------------------------------------------------------- /astro/src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../layouts/Page.astro'; 3 | import Container from '../components/Container.astro'; 4 | 5 | 6 | const seo = { 7 | title: "Astro Minimal Starter", 8 | description: "This is a starter repo for an blog built with Astro including open graph tags, canonical urls, RSS, sitemap support." 9 | } 10 | --- 11 | 12 | 13 | 14 |

Astro Sanity Minimal Starter

15 | 16 |

17 | If you haven't heard about Astro yet you're missing out. This starter repo gives you a blog website with a headless CMS setup using Sanity.io.

18 | 19 |

20 | Don't be fooled by the simplicity of this starter either. With excellent SEO built in, Astro's excellent developer environment, and performance best practices you're getting one of the best foundations for a personal blog with posts written in markdown. The reason for making such a bare bones starter in terms of styles is that it has what you need out of the box for SEO and site structure but it makes no assumptions about how you want it look and behave. 21 |

22 | 23 |

Sometimes starters can feel like they are giving us way too much and you'll spend a day picking apart half of the code to get to the setup you actually wanted. Want to use vanilla CSS instead of Tailwind or Scss? No problem!

24 | 25 |

Features

26 |
    27 |
  • A customizable headless CMS with Sanity.io
  • 28 |
  • Excellent SEO Built In
  • 29 |
  • Open Graph Tags (Twitter, Facebook, etc.)
  • 30 |
  • User Declared Canonical URLs
  • 31 |
  • RSS Feed
  • 32 |
  • XML Sitemap
  • 33 |
  • Robots.txt
  • 34 |
  • JSON LD Schema
  • 35 |
36 | 37 | Blog → 38 |
39 |
-------------------------------------------------------------------------------- /astro/src/styles/global.css: -------------------------------------------------------------------------------- 1 | @import url('./reset.css'); 2 | 3 | :root { 4 | --container-max-width: 1200px; 5 | --container-max-width-narrow: 960px; 6 | --container-padding: 0 1rem; 7 | } 8 | 9 | html, 10 | body { 11 | margin: 0; 12 | padding: 0; 13 | background: #fff; 14 | color: #000; 15 | font-family: 'Open Sans', Arial, Helvetica, sans-serif; 16 | } 17 | 18 | p { 19 | margin-bottom: 1rem; 20 | } 21 | -------------------------------------------------------------------------------- /astro/src/styles/reset.css: -------------------------------------------------------------------------------- 1 | /* Modern CSS Reset from https://piccalil.li/blog/a-modern-css-reset/ */ 2 | 3 | /* Box sizing rules */ 4 | *, 5 | *::before, 6 | *::after { 7 | box-sizing: border-box; 8 | } 9 | 10 | /* Remove default margin */ 11 | body, 12 | h1, 13 | h2, 14 | h3, 15 | h4, 16 | p, 17 | figure, 18 | blockquote, 19 | dl, 20 | dd { 21 | margin: 0; 22 | } 23 | 24 | /* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */ 25 | ul[role='list'], 26 | ol[role='list'] { 27 | list-style: none; 28 | } 29 | 30 | /* Set core root defaults */ 31 | html:focus-within { 32 | scroll-behavior: smooth; 33 | } 34 | 35 | /* Set core body defaults */ 36 | body { 37 | min-height: 100vh; 38 | text-rendering: optimizeSpeed; 39 | line-height: 1.5; 40 | } 41 | 42 | /* A elements that don't have a class get default styles */ 43 | a:not([class]) { 44 | text-decoration-skip-ink: auto; 45 | } 46 | 47 | /* Make images easier to work with */ 48 | img, 49 | picture { 50 | max-width: 100%; 51 | display: block; 52 | } 53 | 54 | /* Inherit fonts for inputs and buttons */ 55 | input, 56 | button, 57 | textarea, 58 | select { 59 | font: inherit; 60 | } 61 | 62 | /* Remove all animations, transitions and smooth scroll for people that prefer not to see them */ 63 | @media (prefers-reduced-motion: reduce) { 64 | html:focus-within { 65 | scroll-behavior: auto; 66 | } 67 | 68 | *, 69 | *::before, 70 | *::after { 71 | animation-duration: 0.01ms !important; 72 | animation-iteration-count: 1 !important; 73 | transition-duration: 0.01ms !important; 74 | scroll-behavior: auto !important; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /astro/src/utils/helpers.js: -------------------------------------------------------------------------------- 1 | import { parseISO, format } from 'date-fns'; 2 | import { useSanityClient, createImageBuilder} from 'astro-sanity'; 3 | 4 | const builder = createImageBuilder(useSanityClient()); 5 | 6 | export function formatBlogPostDate(date) { 7 | const dateString = parseISO(date, 'YYYY/MM/Do'); 8 | const formattedDateString = format(dateString, 'MMMM do, yyyy'); 9 | return `${formattedDateString}`; 10 | } 11 | 12 | export function getSanityImageURL(source) { 13 | return builder.image(source); 14 | } -------------------------------------------------------------------------------- /astro/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "experimentalDecorators": true, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "astro-sanity-minimal-starter", 3 | "version": "1.1.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "astro-sanity-minimal-starter", 9 | "version": "1.1.1" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": false, 3 | "name": "astro-sanity-minimal-starter", 4 | "version": "3.1.0", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /sanity/.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /node_modules 3 | 4 | yarn.lock -------------------------------------------------------------------------------- /sanity/.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | /logs 3 | *.log 4 | 5 | # Coverage directory used by tools like istanbul 6 | /coverage 7 | 8 | # Dependency directories 9 | node_modules 10 | 11 | # Compiled sanity studio 12 | /dist 13 | -------------------------------------------------------------------------------- /sanity/README.md: -------------------------------------------------------------------------------- 1 | # Sanity Blogging Content Studio 2 | 3 | Congratulations, you have now installed the Sanity Content Studio, an open source real-time content editing environment connected to the Sanity backend. 4 | 5 | Now you can do the following things: 6 | 7 | - [Read “getting started” in the docs](https://www.sanity.io/docs/introduction/getting-started?utm_source=readme) 8 | - Check out the example frontend: [React/Next.js](https://github.com/sanity-io/tutorial-sanity-blog-react-next) 9 | - [Read the blog post about this template](https://www.sanity.io/blog/build-your-own-blog-with-sanity-and-next-js?utm_source=readme) 10 | - [Join the community Slack](https://slack.sanity.io/?utm_source=readme) 11 | - [Extend and build plugins](https://www.sanity.io/docs/content-studio/extending?utm_source=readme) 12 | -------------------------------------------------------------------------------- /sanity/config/.checksums: -------------------------------------------------------------------------------- 1 | { 2 | "#": "Used by Sanity to keep track of configuration file checksums, do not delete or modify!", 3 | "@sanity/default-layout": "bb034f391ba508a6ca8cd971967cbedeb131c4d19b17b28a0895f32db5d568ea", 4 | "@sanity/default-login": "6fb6d3800aa71346e1b84d95bbcaa287879456f2922372bb0294e30b968cd37f", 5 | "@sanity/form-builder": "b38478227ba5e22c91981da4b53436df22e48ff25238a55a973ed620be5068aa", 6 | "@sanity/data-aspects": "d199e2c199b3e26cd28b68dc84d7fc01c9186bf5089580f2e2446994d36b3cb6", 7 | "@sanity/vision": "da5b6ed712703ecd04bf4df560570c668aa95252c6bc1c41d6df1bda9b8b8f60" 8 | } 9 | -------------------------------------------------------------------------------- /sanity/config/@sanity/data-aspects.json: -------------------------------------------------------------------------------- 1 | { 2 | "listOptions": {} 3 | } 4 | -------------------------------------------------------------------------------- /sanity/config/@sanity/default-layout.json: -------------------------------------------------------------------------------- 1 | { 2 | "toolSwitcher": { 3 | "order": [], 4 | "hidden": [] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /sanity/config/@sanity/default-login.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": { 3 | "mode": "append", 4 | "redirectOnSingle": false, 5 | "entries": [] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /sanity/config/@sanity/form-builder.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": { 3 | "directUploads": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /sanity/config/@sanity/vision.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultApiVersion": "2021-10-21" 3 | } 4 | -------------------------------------------------------------------------------- /sanity/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanityminimalstarter", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "package.json", 7 | "author": "Jaydan Urwin ", 8 | "license": "UNLICENSED", 9 | "scripts": { 10 | "start": "sanity start", 11 | "build": "sanity build", 12 | "graphql-deploy": "sanity graphql deploy --playground" 13 | }, 14 | "keywords": [ 15 | "sanity" 16 | ], 17 | "dependencies": { 18 | "@sanity/base": "^2.30.0", 19 | "@sanity/code-input": "^2.30.0", 20 | "@sanity/core": "^2.30.0", 21 | "@sanity/default-layout": "^2.30.0", 22 | "@sanity/default-login": "^2.30.0", 23 | "@sanity/desk-tool": "^2.30.0", 24 | "@sanity/vision": "^2.30.0", 25 | "prop-types": "^15.7", 26 | "react": "^17.0", 27 | "react-dom": "^17.0", 28 | "styled-components": "^5.2.0" 29 | }, 30 | "devDependencies": {} 31 | } 32 | -------------------------------------------------------------------------------- /sanity/plugins/.gitkeep: -------------------------------------------------------------------------------- 1 | User-specific packages can be placed here 2 | -------------------------------------------------------------------------------- /sanity/sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "project": { 4 | "name": "Sanity Minimal Starter" 5 | }, 6 | "api": { 7 | "projectId": "8hj1t7km", 8 | "dataset": "production" 9 | }, 10 | "plugins": [ 11 | "@sanity/base", 12 | "@sanity/default-layout", 13 | "@sanity/default-login", 14 | "@sanity/desk-tool", 15 | "@sanity/code-input" 16 | ], 17 | "env": { 18 | "development": { 19 | "plugins": [ 20 | "@sanity/vision" 21 | ] 22 | } 23 | }, 24 | "parts": [ 25 | { 26 | "name": "part:@sanity/base/schema", 27 | "path": "./schemas/schema" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /sanity/schemas/author.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'author', 3 | title: 'Author', 4 | type: 'document', 5 | fields: [ 6 | { 7 | name: 'name', 8 | title: 'Name', 9 | type: 'string', 10 | }, 11 | { 12 | name: 'slug', 13 | title: 'Slug', 14 | type: 'slug', 15 | options: { 16 | source: 'name', 17 | maxLength: 96, 18 | }, 19 | }, 20 | { 21 | name: 'image', 22 | title: 'Image', 23 | type: 'image', 24 | options: { 25 | hotspot: true, 26 | }, 27 | }, 28 | { 29 | name: 'bio', 30 | title: 'Bio', 31 | type: 'array', 32 | of: [ 33 | { 34 | title: 'Block', 35 | type: 'block', 36 | styles: [{title: 'Normal', value: 'normal'}], 37 | lists: [], 38 | }, 39 | ], 40 | }, 41 | ], 42 | preview: { 43 | select: { 44 | title: 'name', 45 | media: 'image', 46 | }, 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /sanity/schemas/blockContent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This is the schema definition for the rich text fields used for 3 | * for this blog studio. When you import it in schemas.js it can be 4 | * reused in other parts of the studio with: 5 | * { 6 | * name: 'someName', 7 | * title: 'Some title', 8 | * type: 'blockContent' 9 | * } 10 | */ 11 | export default { 12 | title: 'Block Content', 13 | name: 'blockContent', 14 | type: 'array', 15 | of: [ 16 | { 17 | title: 'Block', 18 | type: 'block', 19 | // Styles let you set what your user can mark up blocks with. These 20 | // correspond with HTML tags, but you can set any title or value 21 | // you want and decide how you want to deal with it where you want to 22 | // use your content. 23 | styles: [ 24 | {title: 'Normal', value: 'normal'}, 25 | {title: 'H1', value: 'h1'}, 26 | {title: 'H2', value: 'h2'}, 27 | {title: 'H3', value: 'h3'}, 28 | {title: 'H4', value: 'h4'}, 29 | {title: 'Quote', value: 'blockquote'}, 30 | ], 31 | lists: [{title: 'Bullet', value: 'bullet'}], 32 | // Marks let you mark up inline text in the block editor. 33 | marks: { 34 | // Decorators usually describe a single property – e.g. a typographic 35 | // preference or highlighting by editors. 36 | decorators: [ 37 | {title: 'Strong', value: 'strong'}, 38 | {title: 'Emphasis', value: 'em'}, 39 | ], 40 | // Annotations can be any object structure – e.g. a link or a footnote. 41 | annotations: [ 42 | { 43 | title: 'URL', 44 | name: 'link', 45 | type: 'object', 46 | fields: [ 47 | { 48 | title: 'URL', 49 | name: 'href', 50 | type: 'url', 51 | }, 52 | ], 53 | }, 54 | ], 55 | }, 56 | }, 57 | // You can add additional types here. Note that you can't use 58 | // primitive types such as 'string' and 'number' in the same array 59 | // as a block type. 60 | { 61 | type: 'image', 62 | options: {hotspot: true}, 63 | }, 64 | { 65 | type: 'code' 66 | } 67 | ], 68 | } 69 | -------------------------------------------------------------------------------- /sanity/schemas/category.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'category', 3 | title: 'Category', 4 | type: 'document', 5 | fields: [ 6 | { 7 | name: 'title', 8 | title: 'Title', 9 | type: 'string', 10 | }, 11 | { 12 | name: 'slug', 13 | title: 'Slug', 14 | type: 'slug', 15 | options: { 16 | source: 'title', 17 | maxLength: 96, 18 | }, 19 | }, 20 | { 21 | name: 'description', 22 | title: 'Description', 23 | type: 'text', 24 | }, 25 | ], 26 | } -------------------------------------------------------------------------------- /sanity/schemas/post.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'post', 3 | title: 'Post', 4 | type: 'document', 5 | fields: [ 6 | { 7 | name: 'title', 8 | title: 'Title', 9 | type: 'string', 10 | }, 11 | { 12 | name: 'slug', 13 | title: 'Slug', 14 | type: 'slug', 15 | options: { 16 | source: 'title', 17 | maxLength: 96, 18 | }, 19 | }, 20 | { 21 | name: 'author', 22 | title: 'Author', 23 | type: 'reference', 24 | to: {type: 'author'}, 25 | }, 26 | { 27 | name: 'mainImage', 28 | title: 'Main image', 29 | type: 'image', 30 | options: { 31 | hotspot: true, 32 | }, 33 | }, 34 | { 35 | name: 'categories', 36 | title: 'Categories', 37 | type: 'array', 38 | of: [{type: 'reference', to: {type: 'category'}}], 39 | }, 40 | { 41 | name: 'publishedAt', 42 | title: 'Published at', 43 | type: 'datetime', 44 | }, 45 | { 46 | name: 'excerpt', 47 | title: 'Excerpt', 48 | type: 'text', 49 | validation: Rule => Rule.max(200).warning('The description shouldn\'t be longer than 200 characters'), 50 | }, 51 | { 52 | name: 'body', 53 | title: 'Body', 54 | type: 'blockContent', 55 | }, 56 | ], 57 | 58 | preview: { 59 | select: { 60 | title: 'title', 61 | author: 'author.name', 62 | media: 'mainImage', 63 | }, 64 | prepare(selection) { 65 | const {author} = selection 66 | return Object.assign({}, selection, { 67 | subtitle: author && `by ${author}`, 68 | }) 69 | }, 70 | }, 71 | } 72 | -------------------------------------------------------------------------------- /sanity/schemas/schema.js: -------------------------------------------------------------------------------- 1 | // First, we must import the schema creator 2 | import createSchema from 'part:@sanity/base/schema-creator' 3 | 4 | // Then import schema types from any plugins that might expose them 5 | import schemaTypes from 'all:part:@sanity/base/schema-type' 6 | 7 | // We import object and document schemas 8 | import blockContent from './blockContent' 9 | import category from './category' 10 | import post from './post' 11 | import author from './author' 12 | 13 | // Then we give our schema to the builder and provide the result to Sanity 14 | export default createSchema({ 15 | // We name our schema 16 | name: 'default', 17 | // Then proceed to concatenate our document type 18 | // to the ones provided by any plugins that are installed 19 | types: schemaTypes.concat([ 20 | // The following are document types which will appear 21 | // in the studio. 22 | post, 23 | author, 24 | category, 25 | // When added to this list, object types can be used as 26 | // { type: 'typename' } in other document schemas 27 | blockContent, 28 | ]), 29 | }) 30 | -------------------------------------------------------------------------------- /sanity/static/.gitkeep: -------------------------------------------------------------------------------- 1 | Files placed here will be served by the Sanity server under the `/static`-prefix 2 | -------------------------------------------------------------------------------- /sanity/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/astro-sanity-minimal-starter/1e89323443682f6a6d571f37f8fc50a5c901f92c/sanity/static/favicon.ico -------------------------------------------------------------------------------- /sanity/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // Note: This config is only used to help editors like VS Code understand/resolve 3 | // parts, the actual transpilation is done by babel. Any compiler configuration in 4 | // here will be ignored. 5 | "include": ["./node_modules/@sanity/base/types/**/*.ts", "./**/*.ts", "./**/*.tsx"] 6 | } 7 | --------------------------------------------------------------------------------