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

@cyguin/docs

v0.1.6

Published

Drop-in docs widget and admin API for self-hosted Next.js apps

Readme

@cyguin/docs

Embeddable help and documentation widget for Next.js. Searchable, markdown-backed docs in a modal or sidebar — no external service needed.

Quickstart

npm install @cyguin/docs

1. Add the widget to your app

// app/layout.tsx (or any page)
import { DocsWidget } from '@cyguin/docs';
import '@cyguin/docs/styles.css';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        {children}
        <DocsWidget apiUrl="/api/docs" mode="modal" triggerLabel="Help" />
      </body>
    </html>
  );
}

2. Wire up the API route

// app/api/docs/[...cyguin]/route.ts
import { createDocsHandler } from '@cyguin/docs/next';
import { createSQLiteAdapter } from '@cyguin/docs/adapters/sqlite';

const adapter = createSQLiteAdapter({ path: './docs.db' });
export const GET = createDocsHandler({ adapter });

3. Wire up the admin route

// app/api/admin/docs/[...route]/route.ts
import { createAdminHandler } from '@cyguin/docs/next';
import { createSQLiteAdapter } from '@cyguin/docs/adapters/sqlite';

const adapter = createSQLiteAdapter({ path: './docs.db' });
const handler = createAdminHandler({
  adapter,
  secret: process.env.DOCS_ADMIN_SECRET,
});

export { handler as POST, handler as PUT, handler as PATCH, handler as DELETE };

DOCS_ADMIN_SECRET is required. Admin routes fail closed without it.

4. Seed some articles

import { createDocsHandler } from '@cyguin/docs/next';
import { createSQLiteAdapter } from '@cyguin/docs/adapters/sqlite';

const adapter = createSQLiteAdapter({ path: './docs.db' });
const handler = createDocsHandler({ adapter });

await handler.request(new Request('http://localhost/admin/docs', {
  method: 'POST',
  headers: { Authorization: 'Bearer your-secret', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    title: 'Getting Started',
    body_md: '# Getting Started\n\nWelcome to **My App**!',
    section: 'Introduction',
    article_order: 1,
  }),
}));

Modes

Modal (default)

Floating corner button opens a centered overlay. Click the backdrop or press Esc to close.

<DocsWidget mode="modal" triggerLabel="Help" />

Sidebar

Panel slides in from the right — good for persistent help panels.

<DocsWidget mode="sidebar" triggerLabel="Docs" />

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | apiUrl | string | "/api/docs" | Endpoint returning article list | | mode | "modal" \| "sidebar" | "modal" | Modal or sidebar | | triggerLabel | string | "Help" | Label on the floating trigger button | | defaultOpen | boolean | false | Open on mount | | className | string | "" | CSS class on root element |

API Contract

The apiUrl endpoint must return a JSON array of articles:

[
  {
    "id": "1",
    "title": "Getting Started",
    "body_md": "# Getting Started\n\nWelcome...",
    "section": "Introduction",
    "article_order": 1,
    "published_at": 1710000000
  }
]

GET /api/docs from @cyguin/docs/next returns this shape automatically.

Theming

The widget is dark by default. Override --cyguin-* variables on :root:

:root {
  --cyguin-bg: #0a0d17;
  --cyguin-bg-subtle: #101521;
  --cyguin-border: #252b3a;
  --cyguin-border-focus: #f5a800;
  --cyguin-fg: #f1f3f6;
  --cyguin-fg-muted: #888888;
  --cyguin-accent: #f5a800;
  --cyguin-accent-dark: #c47f00;
  --cyguin-accent-fg: #0a0a0a;
  --cyguin-radius: 6px;
  --cyguin-shadow: 0 1px 4px rgba(0,0,0,0.08);
}

Keyboard Navigation

| Key | Action | |-----|--------| | / | Focus search input | | Esc | Close widget | | / | Navigate article list | | Enter | Open selected article |

Exports

@cyguin/docs

| Export | Type | Description | |--------|------|-------------| | DocsWidget | Component | Searchable docs widget (modal/sidebar) | | DocsWidgetProps | Interface | Component props | | DocArticle | Interface | Article shape | | defaultCssVars | Object | Default CSS variable values |

@cyguin/docs/next

| Export | Type | Description | |--------|------|-------------| | createDocsHandler | Function | Factory for Next.js API route handler | | DocsAdapter | Interface | Storage adapter contract | | DocArticle | Interface | Article shape |