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

@main-layout/shadcn-admin-layout

v1.4.0

Published

Modern admin dashboard layout built with Next.js, TypeScript, and shadcn/ui

Readme

Shadcn Admin Layout

A modern, minimal admin dashboard layout for Next.js (App Router) with:

  • Dynamic server rendering for user-aware layouts
  • Cookie-based auth (dummy endpoints) with protected routes
  • Role-based sidebar and user header display
  • Optional auth UI (bring-your-own or use the provided forms)

Features

  • 🚀 Zero Configuration: Works out of the box with minimal setup
  • 🔐 Built-in Authentication: Cookie-based auth with dummy endpoints for quick prototyping
  • 👥 Role-based Access Control: Show/hide sidebar items based on user roles
  • 🎨 Shadcn/ui Compatible: Uses your existing shadcn/ui components
  • 📱 Responsive Design: Mobile-friendly sidebar and layout
  • Server Components: Full Next.js App Router support
  • 🛡️ Protected Routes: Automatic route protection with middleware

Installation

npm install shadcn-admin-layout
# or
yarn add shadcn-admin-layout
# or
pnpm add shadcn-admin-layout

Prerequisites

  • Next.js 13+ with App Router
  • React 18+
  • TypeScript (recommended)
  • Tailwind CSS
  • Shadcn/ui components (optional but recommended)

Quick Setup

  1. Install the package:

    npm install shadcn-admin-layout
  2. Copy the components to your project:

    # Copy the layout components
    cp -r node_modules/shadcn-admin-layout/components/layout ./components/
    cp -r node_modules/shadcn-admin-layout/components/auth ./components/
    cp -r node_modules/shadcn-admin-layout/components/ui ./components/
       
    # Copy the API routes
    cp -r node_modules/shadcn-admin-layout/app/api ./app/
       
    # Copy utility files
    cp node_modules/shadcn-admin-layout/lib/auth.ts ./lib/
    cp node_modules/shadcn-admin-layout/middleware.ts ./
  3. Update your layout to use the AdminLayout component

Usage

Basic Implementation

Create a new page or update your existing layout to use the AdminLayout:

// app/dashboard/layout.tsx
import { AdminLayout } from '@/components/layout/AdminLayout'
import type { SidebarItem } from '@/components/layout/AdminLayout'

const sidebar: SidebarItem[] = [
  { 
    label: 'Dashboard', 
    href: '/dashboard', 
    icon: 'Home',
    roles: ['admin', 'editor', 'viewer'] 
  },
  {
    label: 'Users',
    icon: 'Users',
    roles: ['admin'],
    children: [
      { label: 'All Users', href: '/dashboard/users' },
      { label: 'Invitations', href: '/dashboard/users/invitations' },
    ],
  },
  {
    label: 'Analytics',
    href: '/dashboard/analytics',
    icon: 'BarChart',
    roles: ['admin', 'editor']
  },
  {
    label: 'Settings',
    href: '/dashboard/settings',
    icon: 'Settings',
    roles: ['admin']
  }
]

export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <AdminLayout 
      sidebar={sidebar}
      header={[
        <span key="version" className="text-sm text-muted-foreground">v1.0</span>
      ]}
    >
      {children}
    </AdminLayout>
  )
}

With Authentication

To add authentication, pass a login component:

// app/dashboard/layout.tsx
import { AdminLayout } from '@/components/layout/AdminLayout'
import LoginForm from '@/components/auth/LoginForm'

export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <AdminLayout 
      sidebar={sidebar}
      login={<LoginForm />}
    >
      {children}
    </AdminLayout>
  )
}

Custom Login Component

You can create your own login component:

// components/auth/CustomLogin.tsx
'use client'

import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'

export default function CustomLogin() {
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()
    // Your login logic here
    const response = await fetch('/api/auth/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email, password })
    })
    
    if (response.ok) {
      window.location.reload()
    }
  }

  return (
    <div className="min-h-screen flex items-center justify-center">
      <form onSubmit={handleSubmit} className="space-y-4 w-full max-w-sm">
        <div>
          <Label htmlFor="email">Email</Label>
          <Input
            id="email"
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            required
          />
        </div>
        <div>
          <Label htmlFor="password">Password</Label>
          <Input
            id="password"
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            required
          />
        </div>
        <Button type="submit" className="w-full">
          Sign In
        </Button>
      </form>
    </div>
  )
}

Authentication

Built-in Auth Endpoints

The package includes dummy authentication endpoints for quick prototyping:

  • POST /api/auth/login → sets cookie with a dummy user
  • POST /api/auth/signup → creates a dummy user and sets cookie
  • POST /api/auth/logout → clears the cookie

User Data Structure

type AuthUser = {
  id: string
  name: string
  email: string
  role: 'admin' | 'editor' | 'viewer'
}

Role-based Access Control

Sidebar items can be filtered by user roles:

const sidebar: SidebarItem[] = [
  // Visible to all authenticated users
  { label: 'Dashboard', href: '/dashboard' },
  
  // Only visible to admins
  { label: 'Users', href: '/dashboard/users', roles: ['admin'] },
  
  // Visible to admins and editors
  { label: 'Analytics', href: '/dashboard/analytics', roles: ['admin', 'editor'] },
  
  // Nested items inherit parent role restrictions
  {
    label: 'Settings',
    roles: ['admin'],
    children: [
      { label: 'General', href: '/dashboard/settings' },
      { label: 'Security', href: '/dashboard/settings/security' }
    ]
  }
]

Custom Authentication

Replace the dummy endpoints with your production auth:

// lib/auth.ts
import { cookies } from 'next/headers'

export async function getUser() {
  const cookieStore = await cookies()
  const userCookie = cookieStore.get('user')
  
  if (!userCookie) return null
  
  try {
    return JSON.parse(userCookie.value) as AuthUser
  } catch {
    return null
  }
}

export async function setUser(user: AuthUser) {
  const cookieStore = await cookies()
  cookieStore.set('user', JSON.stringify(user), {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    maxAge: 60 * 60 * 24 * 7 // 7 days
  })
}

Demo Forms

Use the bundled forms with pre-filled defaults for quick demos:

import LoginForm from '@/components/auth/LoginForm'
import SignupForm from '@/components/auth/SignupForm'

export function DemoLogin() {
  return <LoginForm defaultEmail="[email protected]" defaultPassword="password" />
}

export function DemoSignup() {
  return (
    <SignupForm
      defaultName="Jane Admin"
      defaultEmail="[email protected]"
      defaultPassword="password"
    />
  )
}

// Use with AdminLayout
export default function Page() {
  return (
    <AdminLayout login={<DemoLogin />}>
      <h1>Dashboard Content</h1>
    </AdminLayout>
  )
}

Configuration

Sidebar Configuration

The sidebar supports various configuration options:

interface SidebarItem {
  label: string
  href?: string
  icon?: string
  roles?: string[]
  children?: SidebarItem[]
  badge?: string | number
  disabled?: boolean
}

const sidebar: SidebarItem[] = [
  {
    label: 'Dashboard',
    href: '/dashboard',
    icon: 'Home',
    roles: ['admin', 'editor', 'viewer']
  },
  {
    label: 'Users',
    icon: 'Users',
    roles: ['admin'],
    badge: '12', // Shows a badge
    children: [
      { label: 'All Users', href: '/dashboard/users' },
      { label: 'Invitations', href: '/dashboard/users/invitations', badge: '3' }
    ]
  },
  {
    label: 'Maintenance',
    href: '/dashboard/maintenance',
    icon: 'Settings',
    roles: ['admin'],
    disabled: true // Disabled state
  }
]

Header Configuration

Customize the header with additional elements:

export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return (
    <AdminLayout 
      sidebar={sidebar}
      header={[
        <ThemeToggle key="theme" />,
        <span key="version" className="text-sm text-muted-foreground">v1.0</span>
      ]}
    >
      {children}
    </AdminLayout>
  )
}

API Reference

AdminLayout Props

interface AdminLayoutProps {
  children: React.ReactNode
  sidebar?: SidebarItem[]
  header?: React.ReactNode[]
  login?: React.ReactNode
  className?: string
}

Auth Utilities

// lib/auth.ts
export async function getUser(): Promise<AuthUser | null>
export async function setUser(user: AuthUser): Promise<void>
export async function clearUser(): Promise<void>
export function userHasRole(user: AuthUser, role: string): boolean

Middleware

The included middleware automatically protects routes:

// middleware.ts
export function middleware(request: NextRequest) {
  // Protects all /dashboard/** routes
  // Redirects to login if user is not authenticated
}

Examples

Complete Dashboard Setup

// app/dashboard/layout.tsx
import { AdminLayout } from '@/components/layout/AdminLayout'
import LoginForm from '@/components/auth/LoginForm'
import { ThemeToggle } from '@/components/theme/ThemeToggle'

const sidebar = [
  { label: 'Overview', href: '/dashboard', icon: 'Home' },
  { label: 'Analytics', href: '/dashboard/analytics', icon: 'BarChart' },
  { label: 'Users', href: '/dashboard/users', icon: 'Users', roles: ['admin'] },
  { label: 'Settings', href: '/dashboard/settings', icon: 'Settings', roles: ['admin'] }
]

export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return (
    <AdminLayout 
      sidebar={sidebar}
      header={[<ThemeToggle key="theme" />]}
      login={<LoginForm />}
    >
      {children}
    </AdminLayout>
  )
}

Standalone Login Page

// app/login/page.tsx
import LoginForm from '@/components/auth/LoginForm'

export default function LoginPage() {
  return (
    <div className="min-h-screen flex items-center justify-center">
      <div className="w-full max-w-md">
        <h1 className="text-2xl font-bold text-center mb-6">Sign In</h1>
        <LoginForm />
      </div>
    </div>
  )
}

Troubleshooting

Common Issues

1. "Module not found" errors

# Make sure you've copied all required files
cp -r node_modules/shadcn-admin-layout/components ./components/
cp -r node_modules/shadcn-admin-layout/app/api ./app/
cp node_modules/shadcn-admin-layout/lib/auth.ts ./lib/
cp node_modules/shadcn-admin-layout/middleware.ts ./

2. Authentication not working

  • Check that your middleware is properly configured
  • Verify cookie settings in your auth functions
  • Ensure API routes are accessible

3. Sidebar items not showing

  • Check user roles match the roles array in sidebar items
  • Verify user is properly authenticated
  • Check console for any JavaScript errors

4. Styling issues

  • Ensure Tailwind CSS is properly configured
  • Check that shadcn/ui components are installed
  • Verify CSS imports in your layout

Development Tips

  • Use the browser dev tools to inspect the user cookie
  • Check the Network tab for API calls to auth endpoints
  • Use React DevTools to inspect component props
  • Test with different user roles to verify access control

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Support

License

MIT License - see LICENSE file for details.