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 🙏

© 2025 – Pkg Stats / Ryan Hefner

playbook-sdk

v1.0.3

Published

A lightweight, production-ready frontend SDK for creating beautiful galleries

Downloads

1,363

Readme

Playbook Gallery SDK

A lightweight frontend SDK for creating masonry grid galleries with search, board navigation, and modal views. Works for asset management, photo galleries, and media libraries.

Version License Size

SDK UI

Features

  • Fully responsive - adapts from 2 to 8 columns based on screen size
  • Search with AI toggle - regular and semantic search
  • Board navigation - organize assets into categories
  • Modal viewer - full-screen asset view with keyboard navigation
  • Download support - one-click downloads
  • Customizable - extensive configuration options
  • Framework agnostic - works with vanilla JS, React, Vue, Angular
  • Zero dependencies
  • TypeScript support
  • Accessible - ARIA labels and keyboard navigation
  • Lightweight - ~15KB minified

Installation

Option 1: CDN (Quickest)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Gallery</title>

    <!-- Optional: Include Tailwind CSS for styling -->
    <script src="https://cdn.tailwindcss.com"></script>
  </head>
  <body>
    <!-- Your gallery container -->
    <div id="my-gallery"></div>

    <!-- Include Playbook SDK -->
    <script src="https://unpkg.com/playbook-sdk@latest/dist/playbook-sdk.min.js"></script>

    <script>
      // Initialize your gallery
      const gallery = PlaybookSDK.init({
        containerId: "my-gallery",
        organizationSlug: "your-org-slug",
        authToken: "your-auth-token",
      });
    </script>
  </body>
</html>

Option 2: npm

npm install playbook-sdk
import PlaybookSDK from "playbook-sdk";

const gallery = PlaybookSDK.init({
  containerId: "my-gallery",
  organizationSlug: "your-org-slug",
  authToken: "your-auth-token",
});

Option 3: Download

Download playbook-sdk.min.js and include it in your project:

<script src="path/to/playbook-sdk.min.js"></script>

Quick Start

1. Get Your Playbook API Credentials

Request API access at dev.playbook.com or email [email protected]. You'll need:

  • Organization Slug (e.g., playbook-sdk)
  • Auth Token (OAuth2 bearer token)
  • Board ID (optional - to scope gallery to specific board)

2. Create HTML Container

<div id="gallery-container"></div>

3. Initialize SDK

const gallery = PlaybookSDK.init({
  containerId: "gallery-container",
  organizationSlug: "playbook-sdk", // Your organization/workspace slug
  authToken: "your-token-here", // Your API access token
  boardId: "", // Optional: Scope gallery to specific board
  enableSearch: true,
  enableBoards: true,
  enableModal: true,
});

4. Done

The SDK will fetch and display your assets from Playbook.

Configuration Options

PlaybookSDK.init({
  // ===== Required =====
  containerId: "my-gallery", // ID of the container element
  organizationSlug: "your-org-slug", // Your Playbook workspace slug
  authToken: "your-auth-token", // Your API bearer token

  // ===== Optional Scoping =====
  boardId: "", // Scope to specific board (empty = workspace-wide)
  // When boardId is set:
  // - "All Assets" shows only assets from this board + nested boards
  // - Board navigation shows only children of this board
  // - Users cannot navigate outside this board tree

  // ===== Features =====
  enableSearch: true, // Show search bar with AI toggle
  enableBoards: true, // Show board/collection navigation
  enableModal: true, // Enable full-screen asset viewer
  enableDownload: true, // Show download button in modal
  enableInfo: true, // Show info button in modal

  // ===== Responsive Columns =====
  columnBreakpoints: {
    default: 2, // Mobile (< 768px)
    768: 3, // Tablet
    1024: 4, // Desktop
    1280: 5, // Large desktop
    1536: 6, // XL screens
    1800: 7, // 2XL screens
    2000: 8, // Ultra-wide
  },

  // ===== Styling =====
  theme: "light", // 'light' or 'dark' (future)
  customStyles: {}, // Custom CSS overrides

  // ===== Callbacks =====
  onAssetClick: function (asset) {
    console.log("Asset clicked:", asset);
  },

  onSearch: function (query) {
    console.log("Search performed:", query);
  },

  onBoardChange: function (boardId, boardTitle) {
    console.log("Board changed:", boardTitle || boardId);
  },

  onModalOpen: function (asset) {
    console.log("Modal opened:", asset);
  },

  onModalClose: function () {
    console.log("Modal closed");
  },

  onDownload: function (asset) {
    console.log("Asset downloaded:", asset);
  },
});

Examples

Workspace-wide gallery:

PlaybookSDK.init({
  containerId: "gallery",
  organizationSlug: "acme-corp",
  authToken: "abc123...",
  boardId: "", // Empty = show all workspace assets
});

Board-scoped gallery:

PlaybookSDK.init({
  containerId: "gallery",
  organizationSlug: "acme-corp",
  authToken: "abc123...",
  boardId: "SddGjNcAFZThZb3yVTSvbGbe", // Only this board + children
});

Usage Examples

Basic Implementation

<!DOCTYPE html>
<html>
  <head>
    <title>My Asset Gallery</title>
    <script src="https://cdn.tailwindcss.com"></script>
  </head>
  <body class="bg-gray-100 p-8">
    <div class="max-w-7xl mx-auto">
      <h1 class="text-4xl font-bold mb-8">Asset Library</h1>
      <div id="gallery"></div>
    </div>

    <script src="playbook-sdk.min.js"></script>
    <script>
      PlaybookSDK.init({
        containerId: "gallery",
        organizationSlug: "my-company",
        authToken: "your-token-here",
      });
    </script>
  </body>
</html>

With Callbacks

const gallery = PlaybookSDK.init({
  containerId: "gallery",
  organizationSlug: "my-company",
  authToken: "your-token",

  onAssetClick: function (asset) {
    // Track analytics
    gtag("event", "asset_view", {
      asset_id: asset.token,
      asset_name: asset.title,
    });
  },

  onSearch: function (query) {
    // Track search
    console.log("User searched for:", query);
  },

  onBoardChange: function (boardId, boardTitle) {
    // Track board navigation
    console.log("Navigated to:", boardTitle);
  },

  onDownload: function (asset) {
    // Track downloads
    gtag("event", "asset_download", {
      asset_id: asset.token,
    });
  },
});

Custom Column Configuration

PlaybookSDK.init({
  containerId: "gallery",
  organizationSlug: "my-company",
  authToken: "your-token",

  // Custom breakpoints for your design
  columnBreakpoints: {
    default: 1, // 1 column on mobile
    640: 2, // 2 columns on small tablets
    1024: 3, // 3 columns on desktop
    1440: 4, // 4 columns on large screens
  },
});

React Integration

import { useEffect, useRef } from "react";
import PlaybookSDK from "playbook-sdk";

function GalleryComponent() {
  const galleryRef = useRef(null);
  const sdkInstance = useRef(null);

  useEffect(() => {
    if (galleryRef.current && !sdkInstance.current) {
      sdkInstance.current = PlaybookSDK.init({
        containerId: "react-gallery",
        organizationSlug: "your-org-slug",
        authToken: "your-auth-token",

        onAssetClick: (asset) => {
          console.log("Asset clicked:", asset);
        },
      });
    }

    return () => {
      if (sdkInstance.current) {
        PlaybookSDK.destroy("react-gallery");
        sdkInstance.current = null;
      }
    };
  }, []);

  return <div id='react-gallery' ref={galleryRef} />;
}

export default GalleryComponent;

TypeScript Integration

TypeScript definitions included:

import PlaybookSDK, {
  PlaybookConfig,
  GalleryInstance,
  Asset,
  Board,
} from "playbook-sdk";
import { useEffect, useRef } from "react";

function TypeScriptGallery() {
  const sdkInstance = useRef<GalleryInstance | null>(null);

  useEffect(() => {
    const config: PlaybookConfig = {
      containerId: "ts-gallery",
      organizationSlug: "your-org-slug",
      authToken: "your-auth-token",
      enableSearch: true,
      enableBoards: true,

      onAssetClick: (asset: Asset) => {
        console.log("Asset clicked:", asset.title);
      },

      onBoardChange: (boardId: string, boardTitle: string) => {
        console.log("Board changed:", boardTitle);
      },
    };

    sdkInstance.current = PlaybookSDK.init(config);

    return () => {
      if (sdkInstance.current) {
        PlaybookSDK.destroy("ts-gallery");
      }
    };
  }, []);

  return <div id='ts-gallery' />;
}

Public API Methods

Interact with the gallery instance:

const gallery = PlaybookSDK.init({
  /* config */
});

// Refresh the gallery
gallery.refresh();

// Programmatically search
gallery.search("logo");

// Select a specific board
gallery.selectBoardById("brand-assets");

// Get current assets
const assets = gallery.getAssets();

// Destroy the gallery
gallery.destroy();

// Get gallery instance later
const instance = PlaybookSDK.getInstance("my-gallery");

Styling & Customization

CSS classes are prefixed with pb- to avoid conflicts:

/* Override styles in your CSS */
.pb-masonry-item img {
  border-radius: 12px !important;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2) !important;
}

.pb-board-btn.active {
  background-color: #your-brand-color !important;
}

.pb-modal-content {
  border-radius: 20px !important;
}

Keyboard Shortcuts

Modal controls:

  • Previous asset
  • Next asset
  • Esc Close modal

Browser Support

  • Chrome/Edge (latest)
  • Firefox (latest)
  • Safari (latest)
  • Mobile browsers (iOS Safari, Chrome Mobile)

Support

For issues and questions:

Roadmap

  • [ ] Dark theme support
  • [ ] Video preview in grid
  • [ ] Drag & drop upload
  • [ ] Batch download
  • [ ] Grid/List view toggle
  • [ ] Advanced filtering
  • [ ] Asset metadata display
  • [ ] Lazy loading optimization