npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

next-spinks-posts

v1.1.1

Published

Flexible and generic React & Next.js product grid component library supporting custom API mappers, pagination, and detail views.

Readme

next-spinks-posts

A powerful, high-performance, and ultra-flexible React & Next.js catalog component package designed to display product catalogs, posts, and publications from Spinks World JSON APIs with minimal required setup. Supports 7 display layouts, touch-enabled slider/carousel, sortable tables, vertical timeline views, masonry grids, category/tag filtering, dark mode, and customizable card styling.


Key Features

  • Minimal Setup: Simply pass catalogGroupId={13} and the component automatically constructs API endpoints, resolves asset base URLs (static.spinksworld.com), generates thumbnails, and handles PDF downloads!
  • 🎨 7 Display Layouts:
    1. Responsive Grid (layout="grid"): 2, 3, 4, or 5 columns.
    2. List / Row View (layout="list"): Horizontal cards for dense list views.
    3. Carousel / Slider View (layout="slider"): Touch/swipe enabled, infinite loop, autoplay, keyboard arrows, and pagination dots.
    4. Masonry / Pinterest (layout="masonry"): Multi-column layout for variable height cards.
    5. Compact View (layout="compact"): High-density catalog layout.
    6. Table View (layout="table"): Accessible table layout with click-to-sort columns (Title, Category, Date).
    7. Timeline View (layout="timeline"): Vertical timeline layout for blogs, release notes, or event sequences.
  • 🎛️ Interactive Layout Switcher: Enable end-user layout toggle buttons with allowLayoutSwitching.
  • 🔍 Filtering & Sorting: Multi-field search, category dropdowns/pills, tag filters, and title/date sorting.
  • 📄 3 Pagination Modes: Traditional page numbers, "Load More" button, and Infinite Scroll auto-loading.
  • 🌙 Dark Mode & Themeable: Built-in CSS variables and dark mode support (theme="dark" | "light" | "auto").
  • 📱 Interactive Detail Modal: Built-in product detail modal for extended product views.
  • 🛠️ TypeScript Powered: Fully typed with generic parameter support and backward compatibility.

Installation

npm install next-spinks-posts
# or
yarn add next-spinks-posts
# or
pnpm add next-spinks-posts

Include styles in your _app.tsx, layout.tsx, or global CSS:

import "next-spinks-posts/styles.css";

Quick Start (Minimal Zero-Config)

Simply pass your catalogGroupId:

import { ProductGrid } from "next-spinks-posts";
import "next-spinks-posts/styles.css";

export default function CatalogPage() {
  return (
    <ProductGrid catalogGroupId={13} showSearch />
  );
}

Usage Examples

1. Interactive Layout Switcher & Filtering

Allow users to switch between Grid, List, Slider, Masonry, Table, and Timeline views on the fly:

import { ProductGrid } from "next-spinks-posts";

export default function AdvancedCatalogPage() {
  return (
    <ProductGrid
      catalogGroupId={13}
      layout="grid"
      columns={3}
      allowLayoutSwitching
      availableLayouts={["grid", "list", "slider", "masonry", "table", "timeline"]}
      showSearch
      showCategoryFilter
      showTagFilter
      showSort
      paginationMode="infinite"
      theme="auto"
    />
  );
}

2. Carousel / Slider View

Touch-enabled responsive carousel slider:

import { ProductGrid } from "next-spinks-posts";

export default function FeaturedSlider() {
  return (
    <ProductGrid
      catalogGroupId={13}
      layout="slider"
      sliderConfig={{
        loop: true,
        autoplay: true,
        autoplayInterval: 3500,
        showArrows: true,
        showDots: true,
        slidesPerView: { sm: 1, md: 2, lg: 3 },
        swipeable: true,
        keyboardNav: true,
      }}
    />
  );
}

3. Sortable Table View

Accessible table view with sortable columns for product catalog listings:

import { ProductGrid } from "next-spinks-posts";

export default function CatalogTablePage() {
  return (
    <ProductGrid
      catalogGroupId={13}
      layout="table"
      showSearch
      showSort
      pageSize={20}
    />
  );
}

4. Vertical Timeline View

Great for release notes, publication archives, or event sequences:

import { ProductGrid } from "next-spinks-posts";

export default function PublicationTimeline() {
  return (
    <ProductGrid
      catalogGroupId={13}
      layout="timeline"
      showSort
    />
  );
}

5. Server Components (Next.js App Router async/await)

Fetch products directly inside Server Components using getProducts(13):

import { getProducts, ProductGrid } from "next-spinks-posts";

export default async function ServerPage() {
  // Automatically fetches from https://www.spinksworld.com/cgroup/json/13
  const products = await getProducts(13);

  return <ProductGrid products={products} layout="masonry" columns={4} />;
}

6. Custom Client Hook (useProducts)

Build a custom UI layout using the headless useProducts hook:

"use client";

import { useProducts, ProductCard } from "next-spinks-posts";

export function CustomProductList() {
  const { paginatedProducts, loading, searchQuery, setSearchQuery } = useProducts({
    catalogGroupId: 13,
    pageSize: 8,
  });

  if (loading) return <div>Loading catalog items...</div>;

  return (
    <div>
      <input
        type="text"
        value={searchQuery}
        onChange={(e) => setSearchQuery(e.target.value)}
        placeholder="Filter..."
      />
      <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: "16px" }}>
        {paginatedProducts.map((p) => (
          <ProductCard key={p.id} product={p} />
        ))}
      </div>
    </div>
  );
}

API Reference

<ProductGrid /> Props

| Prop | Type | Default | Description | |---|---|---|---| | catalogGroupId | number \| string | undefined | Catalog Category Group ID (e.g., 13). API endpoint is constructed internally automatically. | | layout | "grid" \| "list" \| "slider" \| "masonry" \| "compact" \| "table" \| "timeline" | "grid" | Initial display layout mode. | | columns | 2 \| 3 \| 4 \| 5 \| Object | 3 | Grid column counts for responsive layouts. | | allowLayoutSwitching | boolean | false | Enables view switcher toolbar buttons. | | availableLayouts | ProductLayout[] | all | Array of layouts available in view switcher. | | cardSize | "sm" \| "md" \| "lg" | "md" | Card sizing padding and font dimensions. | | aspectRatio | "1:1" \| "4:3" \| "16:9" \| "auto" | "4:3" | Card image aspect ratio. | | hoverAnimation | "zoom" \| "lift" \| "glow" \| "float" \| "none" | "lift" | Hover effect animation style. | | showSearch | boolean | false | Enables search bar input. | | showCategoryFilter | boolean | false | Enables category dropdown filter. | | showTagFilter | boolean | false | Enables tag filter pills. | | showSort | boolean | false | Enables sorting dropdown. | | paginationMode | "traditional" \| "loadMore" \| "infinite" | "traditional" | Pagination strategy. | | loadMoreText | string | "Load More Products" | Custom text for Load More button. | | sliderConfig | SliderConfig | {} | Carousel slider configuration options. | | theme | "light" \| "dark" \| "auto" | "light" | Component theme. | | renderCard | (product, idx) => ReactNode | undefined | Custom card render override. | | renderEmpty | ReactNode | undefined | Custom empty state element. |


CSS Variables Customization

Customize theme colors and typography by overriding CSS variables in your stylesheet:

:root {
  --sp-primary: #2563eb;
  --sp-primary-hover: #1d4ed8;
  --sp-primary-light: #eff6ff;
  --sp-text: #1e293b;
  --sp-text-muted: #64748b;
  --sp-bg: #f8fafc;
  --sp-card-bg: #ffffff;
  --sp-border: #e2e8f0;
  --sp-radius: 12px;
}

[data-theme="dark"] {
  --sp-bg: #0f172a;
  --sp-card-bg: #1e293b;
  --sp-text: #f1f5f9;
  --sp-border: #334155;
}

License

MIT © Next Spinks Posts