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

@mounaji_npm/forum-landing

v0.1.0

Published

Landing page template for community forums — hero, features, post preview, and CTA sections

Readme

@mounaji_npm/forum-landing

Landing page template for community forums. Drop-in hero section, features grid, stats strip, recent posts preview, and sign-up CTA — all token-driven, no external dependencies.

Pair with @mounaji_npm/forum for a complete community platform.


Install

npm install @mounaji_npm/tokens @mounaji_npm/forum-landing

What's included

| Export | Description | |---|---| | ForumLandingPage | Full landing page (hero + features + stats + posts + CTA) | | HeroSection | Gradient headline + two CTA buttons + background glow | | FeaturesGrid | Responsive grid of feature cards | | StatsRow | Full-width stats strip (3–4 numbers) | | PostsPreview | Recent discussions list | | CTASection | Final gradient call-to-action block |

All sections are individually exported so you can compose a custom layout.


Quick Start

Drop-in full page

import { ForumLandingPage } from '@mounaji_npm/forum-landing';

export default function HomePage() {
  return (
    <ForumLandingPage
      name="DevHub Community"
      tagline="Where developers ask questions, share knowledge, and build together."
      primaryCTA={{ label: 'Join the Community', onClick: () => router.push('/signup') }}
      secondaryCTA={{ label: 'Browse Discussions', onClick: () => router.push('/forum') }}
      ctaAction={{ label: 'Get Started Free', onClick: () => router.push('/signup') }}
    />
  );
}

Next.js App Router

// app/page.js
'use client';
import { useRouter } from 'next/navigation';
import { ForumLandingPage } from '@mounaji_npm/forum-landing';

export default function HomePage() {
  const router = useRouter();

  return (
    <ForumLandingPage
      name="My Community"
      tagline="Ask questions. Share knowledge. Build together."
      primaryCTA={{ label: 'Join Free',           onClick: () => router.push('/signup') }}
      secondaryCTA={{ label: 'Browse Discussions', onClick: () => router.push('/forum') }}
      ctaAction={{ label: 'Get Started',           onClick: () => router.push('/signup') }}
    />
  );
}

Vite + React

import { useNavigate } from 'react-router-dom';
import { TokensProvider } from '@mounaji_npm/tokens';
import { ForumLandingPage } from '@mounaji_npm/forum-landing';

export default function HomeRoute() {
  const navigate = useNavigate();

  return (
    <TokensProvider>
      <ForumLandingPage
        name="My Community"
        tagline="Ask questions. Share knowledge. Build together."
        primaryCTA={{ label: 'Join Free',           onClick: () => navigate('/signup') }}
        secondaryCTA={{ label: 'Browse Discussions', onClick: () => navigate('/forum') }}
        ctaAction={{ label: 'Get Started',           onClick: () => navigate('/signup') }}
      />
    </TokensProvider>
  );
}

ForumLandingPage Props

| Prop | Type | Default | Description | |---|---|---|---| | name | string | 'Your Community' | Brand name — displayed as gradient headline | | tagline | string | built-in | One-liner below the headline | | description | string | — | Optional body text below tagline | | primaryCTA | { label, onClick } | { label: 'Join the Community' } | Primary hero button | | secondaryCTA | { label, onClick } | { label: 'Browse Discussions' } | Ghost hero button | | features | Feature[] | 6 built-in features | Feature cards in the grid | | stats | Stat[] | 3 built-in stats | Numbers in the stats strip | | previewPosts | Post[] | 4 demo posts | Posts shown in the preview section | | ctaTitle | string | built-in | CTA section headline | | ctaSubtitle | string | built-in | CTA section subtext | | ctaAction | { label, onClick } | built-in | CTA section button | | isDark | boolean | true | Dark / light theme | | style | CSSProperties | — | Root element style override |


Individual Sections

Import and compose sections independently:

import {
  HeroSection,
  FeaturesGrid,
  StatsRow,
  PostsPreview,
  CTASection,
} from '@mounaji_npm/forum-landing';

HeroSection

<HeroSection
  name="DevHub"
  tagline="Where developers connect."
  primaryCTA={{ label: 'Get Started', onClick: () => {} }}
  secondaryCTA={{ label: 'Learn More', onClick: () => {} }}
  isDark
/>

| Prop | Type | Description | |---|---|---| | name | string | Brand name (gradient text) | | tagline | string | Subtitle text | | description | string | Optional body paragraph | | primaryCTA | { label, onClick } | Gradient fill button | | secondaryCTA | { label, onClick } | Ghost outline button | | isDark | boolean | Theme |


FeaturesGrid

<FeaturesGrid
  features={[
    { icon: '💬', title: 'Threaded Discussions',  description: 'Organized replies keep conversations readable.' },
    { icon: '▲',  title: 'Community Voting',       description: 'Best answers rise to the top automatically.' },
    { icon: '🔍', title: 'Full-text Search',       description: 'Find any post or reply in seconds.' },
    { icon: '🏷', title: 'Tags & Categories',      description: 'Structured navigation for any topic.' },
  ]}
  isDark
/>

Each feature:

| Field | Type | Description | |---|---|---| | icon | string | Emoji icon | | title | string | Feature name | | description | string | One-sentence description |


StatsRow

<StatsRow
  stats={[
    { icon: '💬', value: '12,400+', label: 'Posts published' },
    { icon: '👥', value: '3,200+',  label: 'Community members' },
    { icon: '✓',  value: '89%',     label: 'Questions answered' },
  ]}
  isDark
/>

PostsPreview

Shows a compact list of recent discussions. Pass your live post data from an API:

import useSWR from 'swr';
import { PostsPreview } from '@mounaji_npm/forum-landing';

function RecentDiscussions() {
  const { data } = useSWR('/api/posts?limit=5', fetcher);

  return (
    <PostsPreview
      posts={(data ?? []).map(p => ({
        title:    p.title,
        category: p.category.label,
        icon:     p.category.icon,
        votes:    p.votes,
        replies:  p.replyCount,
        solved:   p.isSolved,
      }))}
      onViewAll={() => router.push('/forum')}
      isDark
    />
  );
}

Post shape for PostsPreview (simplified — no full Post object needed):

| Field | Type | Description | |---|---|---| | title | string | Post title | | category | string | Category label | | icon | string | Category emoji | | votes | number | Vote count | | replies | number | Reply count | | solved | boolean | Show "Solved" badge |


CTASection

<CTASection
  title="Ready to join the conversation?"
  subtitle="Ask questions, share knowledge, and connect with your community."
  action={{ label: 'Get Started Free', onClick: () => router.push('/signup') }}
  isDark
/>

Combining with @mounaji_npm/forum

The recommended full setup puts the landing page at / and the forum at /forum:

// Next.js: two separate page files
// app/page.js       → ForumLandingPage
// app/forum/page.js → ForumPage

// Vite: two routes
<Routes>
  <Route path="/"     element={<HomeRoute />} />
  <Route path="/forum" element={<ForumRoute />} />
</Routes>

Customizing content

Override any section's built-in copy:

<ForumLandingPage
  name="Acme Developers"
  tagline="Build faster. Ask smarter. Ship together."

  features={[
    { icon: '🚀', title: 'Fast Answers', description: 'Get replies from the community within minutes.' },
    { icon: '📚', title: 'Knowledge Base', description: 'Every solved thread becomes a searchable resource.' },
    { icon: '🔒', title: 'Private Channels', description: 'Create invite-only spaces for your team.' },
  ]}

  stats={[
    { icon: '💬', value: '500+',  label: 'Active discussions' },
    { icon: '👥', value: '200+',  label: 'Team members' },
    { icon: '⚡', value: '< 2h',  label: 'Avg. response time' },
  ]}

  ctaTitle="Your community is waiting."
  ctaSubtitle="Join 200+ engineers already on the platform."
  ctaAction={{ label: 'Request Access', onClick: handleSignup }}
/>

Theming

import { TokensProvider } from '@mounaji_npm/tokens';
import { ForumLandingPage } from '@mounaji_npm/forum-landing';

// Custom brand colors
<TokensProvider initialTokens={{
  colorPrimary: '#7C3AED',
  colorAccent:  '#06B6D4',
}}>
  <ForumLandingPage name="MyBrand" />
</TokensProvider>

// Light mode
<ForumLandingPage isDark={false} name="MyBrand" />