Skip to content

multidots/sanity-blog

Repository files navigation

Sanity Blog Theme (Next.js + Sanity v3)

Modern, editor-friendly starter that pairs Next.js (App Router) with Sanity Studio v3. It ships with a flexible Page Builder, a blog, SEO fields, and a curated Studio experience (Desk structure, grouped fields, icons, and collapsible inputs).

Highlights

  • Page Builder with reusable blocks (Hero, CTA, Image & Text, Client Logos, Services, Testimonials, Team, Address)
  • Organized editor UX: field groups, collapsible sections, sensible defaults, previews
  • Sanity Studio embedded at /studio with a custom content structure
  • Blog with authors, categories, SEO, pagination-ready queries

Create a new project

The easiest way to get started is using the CLI:

npx @multidots/sanity-blog-theme my-blog-project
cd my-blog-project

Or using your preferred package manager:

# npm
npx @multidots/sanity-blog-theme my-blog-project

# yarn
yarn create @multidots/sanity-blog-theme my-blog-project

# pnpm
pnpm create @multidots/sanity-blog-theme my-blog-project

or Directly clone the repository:

git clone https://github.com/multidots/sanity-blog.git
cd sanity-blog-theme

This will:

  • Create a new directory with your project name
  • Copy all template files
  • Interactive Sanity setup - Configure your project with guided prompts
  • Auto-generate .env.local - No manual environment setup needed
  • Install dependencies automatically
  • Set up a proper .gitignore file
  • Update package.json with your project name

πŸš€ Interactive Setup Process

The CLI will guide you through:

  1. Sanity Project Configuration - Enter your project details:

    • Project ID
    • Dataset name (default: "production")
    • API version (auto-suggested with current date)
  2. Environment File Creation - Choose to:

    • Create .env.local with your actual project details
    • Or get an .env.example template for manual setup
  3. Ready to Go - Your project will be fully configured and ready to run!

Project structure

Folder Structure

sanity-blog-theme/
β”œβ”€β”€ public/                         # Static assets
β”‚   └── images/                    # Image assets
β”œβ”€β”€ src/                           # Source code
β”‚   β”œβ”€β”€ app/                       # Next.js App Router
β”‚   β”‚   β”œβ”€β”€ (frontend)/           # Frontend route group
β”‚   β”‚   β”‚   β”œβ”€β”€ [slug]/           # Dynamic page routes
β”‚   β”‚   β”‚   └── blog/             # Blog routes
β”‚   β”‚   β”‚       └── [slug]/       # Individual blog post routes
β”‚   β”‚   β”œβ”€β”€ api/                  # API routes
β”‚   β”‚   β”‚   └── submit-form/      # Form submission endpoint for contact form plugin integration
β”‚   β”‚   └── studio/               # Sanity Studio routes
β”‚   β”‚       └── [[...tool]]/      # Studio catch-all routes
β”‚   β”œβ”€β”€ components/               # React components
β”‚   β”‚   └── blocks/               # Page Builder block components
β”‚   └── sanity/                   # Sanity configuration and schemas
β”‚       β”œβ”€β”€ lib/                  # Sanity utilities
β”‚       └── schemaTypes/          # Content schemas
β”‚           └── blocks/           # Block schemas for Page Builder

Sanity Studio

  • Config: sanity.config.ts
  • Schemas: src/sanity/schemaTypes/
  • Custom Desk structure: src/sanity/structure.ts
  • Contact Form: @multidots/sanity-plugin-contact-form integration

Studio is mounted at /studio via the Next.js App Router integration.

Content model (schemas)

Documents

  • page: Title, Slug, Content (Page Builder), SEO
  • post: Title, Slug, Author, Main Image, Categories, Published At, Body, SEO
  • author: Name, Slug, Image, Bio
  • category: Title, Slug, Description
  • siteSettings (singleton): General, Header (Logo, Menu), Footer (menus, social), Blog settings, Home page reference

Objects and blocks

  • pageBuilder: Array composing these blocks:
    • hero: Headline/subtitle, background (image/color), alignment, colors
    • ctaBlock: Heading, Subheading, Button (text/link/new tab), background (image/color), text color
    • imageTextSection: Title, portable description, main image (+alt/size), image position, button
    • clientList: Title, logos (image + url/new tab)
    • services: Title, services (title, text, background color)
    • testimonialSlider: Title, testimonials (quote, author)
    • team: Title, team (name, role, image, bg color)
    • address: Title, address, phone, email
  • blockContent: Portable Text with basic marks, images, CTAs, etc.
  • seo: Title override, description, image, noindex

Icons

  • Blocks use icons from @sanity/icons for a clearer insert menu and arrays.
    • For example: hero (TextIcon), ctaBlock (BlockContentIcon), team (UsersIcon), address (PinIcon)
    • Change icons in each block schema under src/sanity/schemaTypes/blocks/*Type.ts.

Desk structure

Defined in src/sanity/structure.ts:

  • Site Settings singleton pinned at the top
  • Pages
  • Blog β†’ Posts, Categories, Authors
  • Any other types appear in a fallback list

Frontend implementation

Rendering content

  • Page Builder component: src/components/PageBuilder.tsx
    • Maps each _type in the pageBuilder array to a React component in src/components/blocks/*
    • Includes in-place editing data attributes via next-sanity for a smoother authoring workflow

Mobile Navigation

  • Responsive hamburger menu with smooth slide animations
  • Vertical mobile menu layout with professional styling
  • Touch-friendly interactions and accessibility features
  • Auto-close on navigation and click outside

Contact Form System

  • Plugin: @multidots/sanity-plugin-contact-form v1.0.5
  • Features: Dynamic forms, file upload, reCAPTCHA, email notifications
  • Documentation: Plugin Documentation

Queries

Queries live in src/sanity/lib/queries.ts and cover header/footer, sitemap, pages, posts, and settings.

  • PAGE_QUERY loads page content + SEO
  • POSTS_QUERY, POSTS_COUNT_QUERY, SINGLE_POST_QUERY power the blog
  • SITE_SETTINGS_QUERY, HEADER_QUERY, FOOTER_QUERY load global UI config
  • SITEMAP_QUERY returns URLs and update dates for pages and posts

Using the Page Builder

  1. Create a Page document in Studio
  2. Add blocks to the Content group
  3. Use the insert menu (grid view) to discover blocks; re-order via drag-and-drop
  4. Most blocks have grouped fields (Content, Style, etc.) and collapsible sub-objects for a clean editing experience

Contact Form Plugin

The project includes @multidots/sanity-plugin-contact-form for dynamic form creation and management. For detailed setup and usage instructions, visit the plugin documentation.

Blog

Content modeling

  • post documents reference author and category
  • seo embedded per post

Frontend

  • Blog listing and post page live under src/app/(frontend)/blog
  • Pagination logic can use POSTS_QUERY + POSTS_COUNT_QUERY
  • Posts per page driven by siteSettings.blogPostsPerPage

Global settings

Singleton: siteSettings (enforced via Desk structure and restricted actions in sanity.config.ts).

Key fields

  • General: siteTitle
  • Header: logo, menuItems (title, url, openInNewTab)
  • Footer: footerTitle, footerDescription, footermenuItems, copyrightText, socialLinks
  • Pages: homePage reference (used as the site’s homepage source)
  • Blog: blogPostsPerPage, blogPageCTA

SEO

Each page and post has an seo object. Queries coalesce page/post title/description when SEO fields are left empty. noIndex can be toggled per document.

Add a new block

  1. Create the schema
  • Add a new file under src/sanity/schemaTypes/blocks/YourBlockType.ts
  • Follow the pattern in existing blocks: groups, fields, preview, icon
  1. Register the type
  • Export it from src/sanity/schemaTypes/index.ts
  • Add it to the of list in src/sanity/schemaTypes/pageBuilderType.ts
  1. Build the React component
  • Create src/components/blocks/YourBlock.tsx
  • Match props to your schema fields
  1. Map it in the Page Builder
  • Update the switch in src/components/PageBuilder.tsx to render your component when _type === 'yourBlock'
  1. (Optional) Insert menu preview
  • Add /public/block-previews/yourBlock.png to visualize the block in the Studio insert grid

Current Available Blocks: hero, ctaBlock, imageTextSection, clientList, services, testimonialSlider, team, address

Development

Common commands

npm run dev      # Start Next.js app + Studio (mounted at /studio)
npm run build    # Production build
npm run start    # Start production server

Sanity configuration

  • Project/API vars are set via src/sanity/env.ts
  • Studio plugins: Structure tool, Vision, Color input, Contact Form plugin

Troubleshooting

  • Missing env var error
    • The app throws a helpful error if NEXT_PUBLIC_SANITY_PROJECT_ID or NEXT_PUBLIC_SANITY_DATASET is missing
  • Studio not showing a type
    • Ensure the type is exported in src/sanity/schemaTypes/index.ts

License

MIT β€” feel free to use, modify, and distribute. Attribution is appreciated.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •