Skip to content

bhargav-bkpatel/astro-toc-generator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Alt Text

⚑Astro TOC Generator for Sanity

npm version npm downloads TypeScript Built with Astro

A table of contents generator for Astro.js that works specifically with Sanity CMS blog content. This component automatically generates a table of contents from your Sanity portable text content, with support for custom styling and smooth scrolling.

πŸ’‘ Features

  • 🎯 Specifically designed for Sanity CMS content
  • 🎨 Fully customizable styling with CSS variables
  • πŸ”„ Active section highlighting with parent-child relationships
  • πŸ”— Smooth scrolling support
  • πŸ“š Support for all heading levels (h1-h6)
  • 🌳 Hierarchical structure support
  • 🎨 Different styling per heading level
  • 🎯 Accurate scroll position tracking

πŸ“₯ Installation

npm install astro-toc-generator

πŸ’» Usage

  1. Import the component and styles in your Astro page:
---
import { TableOfContents, generateSlug } from 'astro-toc-generator';
import 'astro-toc-generator/styles'; // Import base styles

// Your Sanity portable text content
const content = [
  {
    _type: 'block',
    style: 'h1',
    children: [{ _type: 'span', text: 'Welcome to My Blog' }]
  },
  // ... more content blocks
];
---

<div class="layout">
  <aside>
    <TableOfContents
      content={body?.value}
      maxLevel={3}
      containerClass="toc-container"
      smoothScroll={true}
      activeClass="active"
      linkClass="toc-link"
      listClass="toc-list"
      listItemClass="toc-item"
      headingSelector="h1, h2, h3"
    />
  </aside>
  <article>
    <!-- Important: Add matching IDs to your headings using generateSlug -->
    <h1 id={generateSlug('Welcome to My Blog')}>Welcome to My Blog</h1>
    <h2 id={generateSlug('Introduction')}>Introduction</h2>
    <!-- ... more content -->
  </article>
</div>
  1. Add required CSS and customize the styling:
:root {
  /* Basic setup */
  scroll-behavior: smooth;

  /* Customize TOC appearance */
  --toc-bg: #f8f9fa;
  --toc-text-color: #666;
  --toc-border-color: #eaeaea;
  --toc-active-color: #0d6efd;
  --toc-active-bg: rgba(13, 110, 253, 0.05);
  --toc-hover-color: #000;
  --toc-hover-bg: rgba(0, 0, 0, 0.05);
  --toc-indent-size: 1rem;
  --toc-border-radius: 8px;
  --toc-transition: all 0.2s ease;
}

/* Layout setup */
.layout {
  display: grid;
  grid-template-columns: 3fr 1fr;
  gap: 2rem;
}

aside {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  overflow-y: auto;
  padding-top: 2rem;
}

/* Add scroll margin to headings */
h1,
h2,
h3,
h4,
h5,
h6 {
  scroll-margin-top: 2rem;
  padding-top: 2rem;
}

/* Optional: Add box shadow to TOC */
.toc-container {
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* Optional: Override specific styles */
.toc-link.active {
  color: red; /* Change active color */
}

πŸ“Œ Important Notes

  1. Heading IDs: Add IDs to your headings using the generateSlug function
  2. CSS Variables: Customize appearance using CSS variables in :root
  3. Scroll Behavior: Add scroll-behavior: smooth to your root element
  4. Scroll Margins: Add scroll-margin-top to headings for proper positioning

πŸ“ Supported Props

Prop Type Default Description
content PortableTextBlock[] or any[] required Your Sanity portable text content
containerClass string 'toc-container' Class for the container element
listClass string 'toc-list' Class for the list element
listItemClass string 'toc-item' Class for list items
linkClass string 'toc-link' Class for links
activeClass string 'active' Class for active links
smoothScroll boolean true Enable/disable smooth scrolling
maxLevel number 6 Maximum heading level to include (1-6)
headingSelector string 'h1, h2, h3, h4, h5, h6' Selector for headings to track

πŸš€ Heading Level Mapping

The component automatically maps Sanity heading styles to their corresponding HTML levels:

Sanity Style HTML Level Description
h1 Level 1 Main title/chapter heading
h2 Level 2 Section heading
h3 Level 3 Subsection heading
h4 Level 4 Sub-subsection heading
h5 Level 5 Minor heading
h6 Level 6 Smallest heading

Level-based CSS Classes

Each TOC item receives classes based on its heading level for targeted styling:

/* Target specific heading levels */
.toc-item.level-1 {
  /* h1 headings */
}
.toc-item.level-2 {
  /* h2 headings */
}
.toc-item.level-3 {
  /* h3 headings */
}
.toc-item.level-4 {
  /* h4 headings */
}
.toc-item.level-5 {
  /* h5 headings */
}
.toc-item.level-6 {
  /* h6 headings */
}

/* Example: Style different levels differently */
.toc-item.level-1 .toc-link {
  font-weight: bold;
  font-size: 1.1em;
}

.toc-item.level-2 .toc-link {
  font-weight: 600;
}

.toc-item.level-3 .toc-link {
  font-weight: normal;
  opacity: 0.8;
}

Depth-based Classes

The component also provides depth classes for nested items:

/* Target by nesting depth */
.toc-item.depth-0 {
  /* Root level items */
}
.toc-item.depth-1 {
  /* First level nested items */
}
.toc-item.depth-2 {
  /* Second level nested items */
}

/* Example: Increase indentation per depth level */
.toc-item.depth-1 {
  padding-left: calc(var(--toc-indent-size) * 1);
}

.toc-item.depth-2 {
  padding-left: calc(var(--toc-indent-size) * 2);
}

πŸͺ„ CSS Variables

Variable Default Description
--toc-bg #f8f9fa Background color of the TOC
--toc-text-color #666 Default text color
--toc-border-color #eaeaea Border color
--toc-active-color #0d6efd Color for active items
--toc-active-bg rgba(13, 110, 253, 0.05) Background for active items
--toc-hover-color #000 Text color on hover
--toc-hover-bg rgba(0, 0, 0, 0.05) Background on hover
--toc-indent-size 1rem Indentation size for nested items
--toc-border-radius 8px Border radius of the container
--toc-transition all 0.2s ease Transition for hover/active states

πŸ› οΈ Utility Functions

import { generateSlug } from "astro-toc-generator";

// Generate URL-friendly slugs for heading IDs
const slug = generateSlug("Your Heading Text");

✏️ Customization Examples

  1. Style different heading levels:
/* Main headings (h1) - larger and bold */
.toc-item.level-1 .toc-link {
  font-size: 1.2em;
  font-weight: bold;
  color: #000;
}

/* Subheadings (h2) - medium weight */
.toc-item.level-2 .toc-link {
  font-size: 1.1em;
  font-weight: 600;
  color: #333;
}

/* Minor headings (h3+) - lighter */
.toc-item.level-3 .toc-link,
.toc-item.level-4 .toc-link,
.toc-item.level-5 .toc-link,
.toc-item.level-6 .toc-link {
  font-size: 1em;
  font-weight: normal;
  color: #666;
}
  1. Progressive indentation by level:
.toc-item.level-2 {
  padding-left: 1rem;
}
.toc-item.level-3 {
  padding-left: 2rem;
}
.toc-item.level-4 {
  padding-left: 3rem;
}
.toc-item.level-5 {
  padding-left: 4rem;
}
.toc-item.level-6 {
  padding-left: 5rem;
}
  1. Change active state colors:
:root {
  --toc-active-color: red;
  --toc-active-bg: rgba(255, 0, 0, 0.05);
}
  1. Modify indentation:
:root {
  --toc-indent-size: 1.5rem;
}
  1. Change container appearance:
:root {
  --toc-bg: #fff;
  --toc-border-radius: 12px;
}

.toc-container {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
  1. Custom hover effects:
:root {
  --toc-hover-color: #0d6efd;
  --toc-hover-bg: rgba(13, 110, 253, 0.1);
}

πŸ“š Example Content Structure

Here's how your Sanity content structure should look:

const content = [
  // Level 1 - h1
  {
    _type: "block",
    style: "h1",
    children: [{ _type: "span", text: "Main Title" }],
  },
  // Level 2 - h2
  {
    _type: "block",
    style: "h2",
    children: [{ _type: "span", text: "Section Title" }],
  },
  // Level 3 - h3
  {
    _type: "block",
    style: "h3",
    children: [{ _type: "span", text: "Subsection Title" }],
  },
];

πŸ“¦ Quick Start & Development

npm create astro@latest -- --template minimal

Open in StackBlitz Open with CodeSandbox Open in GitHub Codespaces

πŸ’Ό Explore my personal work and projects:

Visit my portfolio at Bhargav Patel to explore my work, projects, and what I’ve been building lately.

πŸͺͺ License

MIT

About

Dynamic Table of Contents Generator for Astro.js with Sanity Integration Automatically creates a Table of Contents (ToC) for your Astro.js pages based on Portable Text content from Sanity CMS. Integrates with Sanity's rich text structure to generate anchor links and enhance content navigation and SEO.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Contributors