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

@djangocfg/layouts

v2.1.194

Published

Simple, straightforward layout components for Next.js - import and use with props

Downloads

7,583

Readme

@djangocfg/layouts

Simple, straightforward layout components for Next.js - import and use with props.

Part of DjangoCFG — modern Django framework for production-ready SaaS applications.

Install

pnpm add @djangocfg/layouts

Core Components

BaseApp

Core providers wrapper - use when you need providers without layout routing:

import { BaseApp } from '@djangocfg/layouts';

// app/layout.tsx
export default function RootLayout({ children }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <BaseApp
          theme={{ defaultTheme: 'dark' }}
          analytics={{ googleTrackingId: 'G-XXXXXXXXXX' }}
          centrifugo={{ enabled: true, url: process.env.NEXT_PUBLIC_CENTRIFUGO_URL }}
          pwaInstall={{ enabled: true, showInstallHint: true }}
          mcpChat={{ enabled: true, autoDetectEnvironment: true }}
        >
          {children}
        </BaseApp>
      </body>
    </html>
  );
}

Included providers:

  • ThemeProvider - Light/dark/system theme management
  • TooltipProvider - Tooltip positioning context
  • SWRConfig - Data fetching configuration
  • AuthProvider - Authentication context (from @djangocfg/api)
  • AnalyticsProvider - Google Analytics (optional)
  • CentrifugoProvider - WebSocket real-time (optional)
  • PwaProvider - PWA installation (optional)
  • ErrorTrackingProvider - Error handling and tracking
  • ErrorBoundary - React error boundary
  • MCP Chat Widget - AI chat assistant (optional)

Global components:

  • PageProgress - NProgress bar for route changes
  • Toaster - Toast notifications container
  • A2HSHint - PWA install hint (if enabled)

Note: Auth functionality is provided by @djangocfg/api package. See @djangocfg/api documentation for auth usage.

AppLayout

Smart layout router built on BaseApp - automatically selects layout based on route:

import { AppLayout } from '@djangocfg/layouts';
import { PublicLayout } from './_layouts/PublicLayout';
import { PrivateLayout } from './_layouts/PrivateLayout';
import { AdminLayout } from './_layouts/AdminLayout';

// app/layout.tsx
export default function RootLayout({ children }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <AppLayout
          // Provider configs (passed to BaseApp)
          theme={{ defaultTheme: 'system' }}
          analytics={{ googleTrackingId: 'G-XXXXXXXXXX' }}
          pwaInstall={{ enabled: true }}

          // Layout components
          publicLayout={{
            component: PublicLayout,
            enabledPath: ['/', '/legal', '/contact']
          }}
          privateLayout={{
            component: PrivateLayout,
            enabledPath: ['/dashboard', '/profile']
          }}
          adminLayout={{
            component: AdminLayout,
            enabledPath: '/admin'
          }}

          // Skip layout for fullscreen pages (providers still applied)
          noLayoutPaths={['/private/terminal', '/embed']}
        >
          {children}
        </AppLayout>
      </body>
    </html>
  );
}

Layout priority: Admin → Private → Public → Fallback

noLayoutPaths: Paths that render without any layout wrapper. Useful for fullscreen pages (terminal, embed, print). Providers (auth, theme, centrifugo) are still applied.

Layouts

Simple, props-based layout components. No complex configs needed!

Available Layouts

import { PublicLayout, PrivateLayout, AuthLayout } from '@djangocfg/layouts';

// Public page
<PublicLayout
  logo="/logo.svg"
  siteName="My App"
  navigation={navItems}
>
  {children}
</PublicLayout>

// Private page
<PrivateLayout
  sidebar={{
    groups: [
      { label: 'Main', items: menuItems }
    ]
  }}
  header={{ title: 'Dashboard' }}
>
  {children}
</PrivateLayout>

// Auth page
<AuthLayout
  logo="/logo.svg"
  title="Sign In"
  subtitle="Welcome back"
>
  <LoginForm />
</AuthLayout>

| Layout | Description | |--------|-------------| | BaseApp | Core providers wrapper (Theme, Auth, SWR, ErrorTracking, Toaster) | | AppLayout | Smart layout router with route-based layout switching | | PublicLayout | Public pages (home, docs, contact, legal) | | PrivateLayout | Authenticated user pages (dashboard, profile) | | AuthLayout | Authentication pages (login, signup, password reset) | | AdminLayout | Admin panel layout | | ProfileLayout | User profile pages |

i18n Support

Pass i18n config to AppLayout for locale switching in all layouts:

import { AppLayout } from '@djangocfg/layouts';
import { useLocaleSwitcher } from '@djangocfg/nextjs/i18n/client';

function RootLayout({ children }) {
  const { locale, locales, changeLocale } = useLocaleSwitcher();

  return (
    <AppLayout
      // ... other configs
      i18n={{
        locale,
        locales,
        onLocaleChange: changeLocale,
      }}
    >
      {children}
    </AppLayout>
  );
}

The LocaleSwitcher component will automatically appear in PublicLayout and PrivateLayout headers.

LocaleSwitcher Component

A presentational locale switcher component that can be used standalone:

import { LocaleSwitcher } from '@djangocfg/layouts';

// Basic usage (pass locale data via props)
<LocaleSwitcher
  locale="en"
  locales={['en', 'ru', 'ko']}
  onChange={(locale) => router.push(`/${locale}`)}
/>

// With custom labels and styling
<LocaleSwitcher
  locale={currentLocale}
  locales={['en', 'ru', 'ko']}
  onChange={handleLocaleChange}
  labels={{ en: 'English', ru: 'Русский', ko: '한국어' }}
  variant="outline"
  size="sm"
  showIcon={true}
/>

Props: | Prop | Type | Default | Description | |------|------|---------|-------------| | locale | string | - | Current locale code | | locales | string[] | - | Available locale codes | | onChange | (locale: string) => void | - | Callback when locale changes | | labels | Record<string, string> | Built-in | Custom labels for locales | | showCode | boolean | false | Show locale code with label | | variant | 'ghost' \| 'outline' \| 'default' | 'ghost' | Button variant | | size | 'sm' \| 'default' \| 'lg' \| 'icon' | 'sm' | Button size | | showIcon | boolean | true | Show globe icon | | className | string | - | Custom CSS class |

Smart version: For automatic locale detection with next-intl hooks, use @djangocfg/nextjs/i18n/components which wraps this component.

Extension Layouts: Additional layouts like SupportLayout and PaymentsLayout are available in extension packages:

  • @djangocfg/ext-support - Support ticket layouts
  • @djangocfg/ext-payments - Payment flow layouts

Analytics

Google Analytics integration via react-ga4. Auto-tracks pageviews and user sessions.

Setup

Add tracking ID to your config:

// appLayoutConfig.ts
export const appLayoutConfig: AppLayoutConfig = {
  // ...
  analytics: {
    googleTrackingId: 'G-XXXXXXXXXX',
  },
};

Analytics is automatically initialized by AppLayout. Works only in production (NODE_ENV === 'production').

Usage

import { useAnalytics, Analytics, AnalyticsEvent, AnalyticsCategory } from '@djangocfg/layouts';

// In React components - auto-tracks pageviews
const { event, isEnabled } = useAnalytics();

event(AnalyticsEvent.THEME_CHANGE, {
  category: AnalyticsCategory.ENGAGEMENT,
  label: 'dark',
});

// Outside React (utilities, handlers)
Analytics.event('button_click', { category: 'engagement', label: 'signup' });
Analytics.setUser('user-123');

Predefined Events

| Category | Events | |----------|--------| | Auth | AUTH_LOGIN_SUCCESS, AUTH_LOGOUT, AUTH_SESSION_EXPIRED, AUTH_TOKEN_REFRESH | | OAuth | AUTH_OAUTH_START, AUTH_OAUTH_SUCCESS, AUTH_OAUTH_FAIL | | Error | ERROR_BOUNDARY, ERROR_API, ERROR_VALIDATION, ERROR_NETWORK | | Navigation | NAV_ADMIN_ENTER, NAV_DASHBOARD_ENTER, NAV_PAGE_VIEW | | Engagement | THEME_CHANGE, SIDEBAR_TOGGLE, MOBILE_MENU_OPEN |

Auto-tracking

Built-in tracking for:

  • Page views - on every route change
  • User ID - automatically set when user is authenticated
  • Auth events - login, logout, session expiry (from @djangocfg/api)
  • OAuth events - GitHub OAuth start, success, failure
  • Errors - React ErrorBoundary errors

PWA Installation

Enable PWA installation prompts with pwaInstall config:

import { BaseApp } from '@djangocfg/layouts';

<BaseApp
  pwaInstall={{
    enabled: true,
    showInstallHint: true,      // Show A2HS hint
    resetAfterDays: 3,           // Re-show after dismissal
    delayMs: 1000,               // Delay before showing
    logo: '/logo192.png',        // PWA logo
    resumeLastPage: true,        // Resume last page on PWA launch
  }}
>
  {children}
</BaseApp>

Features:

  • A2HSHint - Platform-specific install hints (iOS Safari/Chrome/Firefox, Android Chrome, Desktop)
  • Page Resume - Automatically navigate to last viewed page when PWA is launched
  • Auto-detection - Detects if running as PWA
  • Dismissal tracking - Respects user dismissal with localStorage
  • Custom timing - Configurable delay and reset periods

Page Resume: When resumeLastPage: true, the app saves the current pathname on every navigation and restores it when the PWA is launched. Pages like /auth, /login, /error are automatically excluded. Data expires after 24 hours.

Usage

import { usePwa } from '@djangocfg/layouts/snippets';

// PWA status
const { isPWA, isInstallable } = usePwa();

Snippets

Reusable UI components and hooks ready to use.

import {
  Breadcrumbs,
  AuthDialog,
  usePwa,
} from '@djangocfg/layouts/snippets';

| Snippet | Description | |---------|-------------| | Breadcrumbs | Navigation breadcrumbs with automatic path generation | | AuthDialog | Auth modal (login/register) with event-based triggers | | AnalyticsProvider | Analytics wrapper component | | usePwa | PWA status hook (isPWA, isInstallable, etc.) | | usePWAPageResume | Resume last page on PWA launch | | A2HSHint | Add to Home Screen hint component | | PWAPageResumeManager | Component for PWA page resume (use via BaseApp config) |

Extension Snippets: Additional components are available in extension packages:

  • @djangocfg/ext-leads - ContactForm, ContactPage, ContactInfo
  • @djangocfg/ext-knowbase - KnowledgeChat, ChatWidget, ChatUIProvider
  • @djangocfg/ext-newsletter - Hero (with newsletter subscription)

Breadcrumbs

import Breadcrumbs from '@djangocfg/layouts/snippets';

// Auto-generate from current path
<Breadcrumbs />

// Or provide custom items
<Breadcrumbs
  items={[
    { path: '/', label: 'Home', isActive: false },
    { path: '/products', label: 'Products', isActive: true },
  ]}
/>

AuthDialog

import { AuthDialog, openAuthDialog } from '@djangocfg/layouts/snippets';

// Add to layout
<AuthDialog authPath="/auth" />

// Trigger from anywhere
openAuthDialog({ message: 'Sign in to continue' });

Components

Utility components organized by category.

Core Components

import {
  JsonLd,
  LucideIcon,
  PageProgress,
  Suspense
} from '@djangocfg/layouts/components/core';

| Component | Description | |-----------|-------------| | JsonLd | JSON-LD structured data component | | LucideIcon | Lucide icon wrapper component | | PageProgress | Page loading progress indicator | | Suspense | Suspense wrapper component |

Error Components

import {
  ErrorBoundary,
  ErrorLayout,
  getErrorContent,
  ERROR_CODES
} from '@djangocfg/layouts/components/errors';

| Component | Description | |-----------|-------------| | ErrorBoundary | React error boundary component | | ErrorLayout | Reusable error page layout (404, 500, etc.) | | getErrorContent | Get error content by status code | | ERROR_CODES | Common HTTP error code constants |

ErrorLayout Usage:

// app/not-found.tsx
import { ErrorLayout } from '@djangocfg/layouts/components/errors';

export default function NotFound() {
  return <ErrorLayout code={404} supportEmail="[email protected]" />;
}

// app/error.tsx
'use client';
import { ErrorLayout } from '@djangocfg/layouts/components/errors';

export default function Error({ error, reset }) {
  return <ErrorLayout code={500} supportEmail="[email protected]" />;
}

Redirect Component

import { RedirectPage } from '@djangocfg/layouts/components/RedirectPage';

// app/page.tsx
export default function Page() {
  return (
    <RedirectPage
      authenticatedPath="/dashboard"
      unauthenticatedPath="/auth"
      loadingText="Loading..."
    />
  );
}

Error Tracking

import {
  ErrorTrackingProvider,
  useErrors,
  useErrorEmitter,
  emitRuntimeError,
} from '@djangocfg/layouts';

// Wrap your app
<ErrorTrackingProvider>
  <YourApp />
</ErrorTrackingProvider>

// In React components - use hook
function MyComponent() {
  const { emitError } = useErrorEmitter('MyComponent');

  try {
    doSomething();
  } catch (error) {
    emitError('Something failed', error);
  }
}

// Outside React (utilities, libraries) - use standalone function
import { emitRuntimeError } from '@djangocfg/layouts';

try {
  doSomething();
} catch (error) {
  emitRuntimeError('MyUtility', 'Something failed', error);
}

// Access errors
const { errors, clearErrors } = useErrors();

Update Notifier

import { UpdateNotifier } from '@djangocfg/layouts/components/UpdateNotifier';

<UpdateNotifier />

Pages

Ready-to-use page components.

Legal Pages

Pre-built legal page components with default configurations.

import {
  PrivacyPage,
  TermsPage,
  CookiesPage,
  SecurityPage
} from '@djangocfg/layouts/pages/legal';

// app/legal/privacy/page.tsx
export default PrivacyPage;

// Or customize
import { PrivacyPage, privacyConfig } from '@djangocfg/layouts/pages/legal';

export default function CustomPrivacy() {
  return <PrivacyPage config={{
    ...privacyConfig,
    lastUpdated: '2024-01-01',
  }} />;
}

| Page | Description | |------|-------------| | PrivacyPage | Privacy policy page | | TermsPage | Terms of service page | | CookiesPage | Cookie policy page | | SecurityPage | Security policy page |

Utils

Utility functions and helpers.

import {
  generateOgImageUrl,
  getAbsoluteOgImageUrl,
  createOgImageUrlBuilder
} from '@djangocfg/layouts/utils/og-image';

// Generate OG image URL
const ogUrl = generateOgImageUrl('/api/og', {
  title: 'My Page',
  description: 'Page description',
  siteName: 'My Site',
});

| Utility | Description | |---------|-------------| | generateOgImageUrl | Generate OG image URL with base64 encoding | | getAbsoluteOgImageUrl | Get absolute OG image URL | | createOgImageUrlBuilder | Create OG image URL builder with defaults |

Exports

| Path | Content | |------|---------| | @djangocfg/layouts | Main exports (all modules) | | @djangocfg/layouts/layouts | Layout components | | @djangocfg/layouts/snippets | Reusable components + Analytics | | @djangocfg/layouts/components | All utility components | | @djangocfg/layouts/pages | Page components (legal pages) | | @djangocfg/layouts/pages/legal | Legal page components | | @djangocfg/layouts/utils | Utilities (og-image, logger) | | @djangocfg/layouts/styles | CSS | | @djangocfg/layouts/styles/dashboard | Dashboard-specific CSS |

Auth Exports: For authentication, use @djangocfg/api/auth - See @djangocfg/api documentation

Extension Packages

Additional functionality is available in extension packages:

| Extension | Package | Description | |-----------|---------|-------------| | Newsletter | @djangocfg/ext-newsletter | Newsletter subscription and campaigns | | Knowledge Base | @djangocfg/ext-knowbase | Documentation, chat, RAG-powered AI | | Leads | @djangocfg/ext-leads | Lead capture and contact forms | | Payments | @djangocfg/ext-payments | Payment processing and subscriptions | | Support | @djangocfg/ext-support | Support tickets and helpdesk |

Each extension has its own layouts, contexts, and components. See individual extension documentation for details.

Requirements

  • Next.js >= 15
  • React >= 19
  • Tailwind CSS >= 4
  • react-ga4 (bundled)
  • @djangocfg/ui-nextjs (peer dependency)
  • @djangocfg/api (peer dependency)

Philosophy

This package follows a simple, props-based approach:

  • No complex configs - just pass props
  • Type-safe - full TypeScript support
  • Flexible - compose layouts as needed
  • Production-ready - built for real apps
  • Modular - core layouts in one package, extensions separate

Examples

Complete App Setup

// app/layout.tsx
import { AppLayout } from '@djangocfg/layouts';
import { appLayoutConfig } from './_config/appLayoutConfig';

export default function RootLayout({ children }) {
  return (
    <AppLayout config={appLayoutConfig}>
      {children}
    </AppLayout>
  );
}

Public Page

// app/page.tsx
import { PublicLayout } from '@djangocfg/layouts';

export default function HomePage() {
  return (
    <PublicLayout
      logo="/logo.svg"
      siteName="My App"
      navigation={[
        { label: 'Home', href: '/' },
        { label: 'Docs', href: '/docs' },
        { label: 'Contact', href: '/contact' }
      ]}
    >
      <h1>Welcome</h1>
    </PublicLayout>
  );
}

Private Dashboard

// app/dashboard/page.tsx
import { PrivateLayout } from '@djangocfg/layouts';

export default function DashboardPage() {
  return (
    <PrivateLayout
      sidebar={{
        groups: [
          {
            label: 'Main',
            items: [
              { label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },
              { label: 'Settings', href: '/settings', icon: 'Settings' }
            ]
          }
        ],
        homeHref: '/dashboard'
      }}
      header={{ title: 'Dashboard' }}
    >
      <h1>Dashboard</h1>
    </PrivateLayout>
  );
}

Auth Page (OTP + 2FA Authentication)

// app/auth/page.tsx
'use client';

import { AuthLayout } from '@djangocfg/layouts';

export default function AuthPage() {
  return (
    <AuthLayout
      sourceUrl="https://example.com"
      supportUrl="/support"
      termsUrl="/terms"
      privacyUrl="/privacy"
      enablePhoneAuth={false}
      enableGithubAuth={true}
      logoUrl="/logo.svg"
      redirectUrl="/dashboard"
      onOTPSuccess={() => {
        console.log('Authentication successful');
      }}
      onOAuthSuccess={(user, isNewUser, provider) => {
        console.log('OAuth success:', { user, isNewUser, provider });
      }}
    >
      <div className="text-center mb-6">
        <h2 className="text-2xl font-bold">Welcome to My App</h2>
        <p className="text-muted-foreground mt-2">
          Sign in with your email or phone
        </p>
      </div>
    </AuthLayout>
  );
}

Authentication Flow:

  1. Identifier → Enter email/phone or click GitHub OAuth
  2. OTP → Enter 6-digit verification code
  3. 2FA → Enter TOTP code (if 2FA enabled for user)
  4. Success → Show logo animation, then redirect

AuthLayout Props: | Prop | Type | Description | |------|------|-------------| | sourceUrl | string | Application URL for OTP emails | | redirectUrl | string | URL to redirect after successful auth (default: /dashboard) | | logoUrl | string | Logo URL for success screen (SVG recommended) | | enablePhoneAuth | boolean | Enable phone number authentication | | enableGithubAuth | boolean | Enable GitHub OAuth | | enable2FASetup | boolean | Enable 2FA setup prompt after login (default: true). Set to false to skip 2FA setup prompt - users can then configure 2FA from ProfileLayout instead. | | termsUrl | string | Terms of service URL (shows checkbox if provided) | | privacyUrl | string | Privacy policy URL | | supportUrl | string | Support page URL | | onOTPSuccess | () => void | Callback after successful authentication | | onOAuthSuccess | (user, isNewUser, provider) => void | Callback after successful OAuth | | onError | (message: string) => void | Error callback |

Profile Page (with 2FA Management)

// app/profile/page.tsx
'use client';

import { ProfileLayout } from '@djangocfg/layouts';

export default function ProfilePage() {
  return (
    <ProfileLayout
      title="Profile Settings"
      description="Manage your account"
      enable2FA={true}  // Show 2FA management section
      showMemberSince={true}
      showLastLogin={true}
      onUnauthenticated={() => {
        // Redirect to login
      }}
    />
  );
}

ProfileLayout Props: | Prop | Type | Description | |------|------|-------------| | title | string | Page title (default: "Profile Settings") | | description | string | Page description | | enable2FA | boolean | Show 2FA management section (default: false). When enabled, users can enable/disable Two-Factor Authentication from their profile. | | showMemberSince | boolean | Show member since date (default: true) | | showLastLogin | boolean | Show last login date (default: true) | | onUnauthenticated | () => void | Callback when user is not authenticated |

2FA Configuration Strategy:

  • Use enable2FASetup={false} in AuthLayout to skip post-login 2FA setup prompt
  • Use enable2FA={true} in ProfileLayout to allow users to manage 2FA from settings
  • This gives users control over when to enable 2FA instead of forcing it during login

License

MIT

Links