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

@titusjin/side-panel-module

v2.0.1

Published

An enhanced reusable React side panel component with mobile responsiveness, external URL support, and advanced navigation features for Next.js applications

Readme

🔧 Side Panel Module

A powerful, mobile-responsive React navigation sidebar for Next.js applications

npm version License: MIT

📖 Table of Contents

✨ Features

| Feature | Description | v1.x | v2.x | |---------|-------------|------|------| | � Mobile Responsive | Auto-hide/show on mobile devices | ❌ | ✅ | | 🌍 External URLs | Support for external links (AppSheet, etc.) | ❌ | ✅ | | ⚡ Custom Navigation | Override default navigation behavior | ❌ | ✅ | | 🎯 Controlled State | External control of active panel | ❌ | ✅ | | 🎨 Color-coded UI | 5 distinct sections with color themes | ✅ | ✅ | | 💙 TypeScript | Full TypeScript support | ✅ | ✅ | | 🔄 Backwards Compatible | v1.x code works without changes | - | ✅ |

🚀 Quick Start

1. Install the Package

npm install @titusjin/side-panel-module

2. Basic Implementation

import SidePannel from '@titusjin/side-panel-module';
import '@titusjin/side-panel-module/dist/styles.css';

function App() {
  return (
    <div style={{ display: 'flex' }}>
      <SidePannel />
      <main style={{ marginLeft: '15vw', padding: '20px' }}>
        {/* Your main content */}
      </main>
    </div>
  );
}

3. That's It! 🎉

Your sidebar is now working with all 21 navigation items and responsive behavior.

📚 Usage Examples

Example 1: Simple Sidebar (Minimal Setup)

import SidePannel from '@titusjin/side-panel-module';
import '@titusjin/side-panel-module/dist/styles.css';

function App() {
  return (
    <div>
      <SidePannel className="my-sidebar" />
    </div>
  );
}

Result: Fully functional sidebar with default behavior.


Example 2: Mobile-Responsive App

import React, { useState } from 'react';
import SidePannel from '@titusjin/side-panel-module';
import '@titusjin/side-panel-module/dist/styles.css';

function App() {
  const [isSidebarOpen, setIsSidebarOpen] = useState(false);

  return (
    <div>
      {/* Mobile menu button */}
      <button 
        onClick={() => setIsSidebarOpen(!isSidebarOpen)}
        style={{ 
          display: 'block',
          '@media (min-width: 1025px)': { display: 'none' }
        }}
      >
        ☰ Menu
      </button>

      <SidePannel
        isOpen={isSidebarOpen}
        onClose={() => setIsSidebarOpen(false)}
      />
    </div>
  );
}

Result: Mobile-friendly sidebar that toggles on/off.


Example 3: Custom Navigation with Next.js Router

import React, { useState } from 'react';
import { useRouter } from 'next/navigation';
import SidePannel from '@titusjin/side-panel-module';
import '@titusjin/side-panel-module/dist/styles.css';

function App() {
  const router = useRouter();
  const [currentPage, setCurrentPage] = useState('/dashboard');

  const handleNavigation = (path: string, externalUrl?: string) => {
    if (externalUrl) {
      // Open external links in new tab
      window.open(externalUrl, '_blank');
    } else {
      // Navigate internally
      router.push(path);
      setCurrentPage(path);
    }
  };

  return (
    <SidePannel
      activePath={currentPage}
      onNavigate={handleNavigation}
    />
  );
}

Result: Custom navigation with external URL support.


Example 4: Complete Mobile App Setup

import React, { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import SidePannel from '@titusjin/side-panel-module';
import '@titusjin/side-panel-module/dist/styles.css';

function Layout({ children }: { children: React.ReactNode }) {
  const router = useRouter();
  const [isMobile, setIsMobile] = useState(false);
  const [sidebarOpen, setSidebarOpen] = useState(false);
  const [activePage, setActivePage] = useState('/');

  // Check if mobile on mount and resize
  useEffect(() => {
    const checkMobile = () => setIsMobile(window.innerWidth <= 1024);
    checkMobile();
    window.addEventListener('resize', checkMobile);
    return () => window.removeEventListener('resize', checkMobile);
  }, []);

  const handleNavigation = (path: string, externalUrl?: string) => {
    setActivePage(path);
    
    if (externalUrl) {
      window.open(externalUrl, '_blank');
    } else {
      router.push(path);
    }
  };

  return (
    <div style={{ display: 'flex', minHeight: '100vh' }}>
      {/* Mobile Header */}
      {isMobile && (
        <header style={{
          position: 'fixed',
          top: 0,
          left: 0,
          right: 0,
          height: '60px',
          background: '#fff',
          borderBottom: '1px solid #ddd',
          display: 'flex',
          alignItems: 'center',
          padding: '0 20px',
          zIndex: 1000
        }}>
          <button onClick={() => setSidebarOpen(!sidebarOpen)}>
            ☰ Menu
          </button>
          <h1 style={{ marginLeft: '20px' }}>My App</h1>
        </header>
      )}

      {/* Sidebar */}
      <SidePannel
        isOpen={!isMobile || sidebarOpen}
        onClose={() => setSidebarOpen(false)}
        onNavigate={handleNavigation}
        activePath={activePage}
      />

      {/* Main Content */}
      <main style={{
        marginLeft: isMobile ? '0' : '15vw',
        marginTop: isMobile ? '60px' : '0',
        padding: '20px',
        flex: 1
      }}>
        {children}
      </main>
    </div>
  );
}

Result: Production-ready mobile app layout.

⚙️ Props Reference

interface SidePannelProps {
  className?: string;           // Additional CSS class
  isOpen?: boolean;             // Control sidebar visibility  
  onClose?: () => void;         // Handle mobile close events
  onNavigate?: (path: string, outsideUrl?: string) => void;  // Custom navigation
  activePath?: string;          // Current active panel
}

Detailed Props

| Prop | Type | Default | Required | Description | |------|------|---------|----------|-------------| | className | string | undefined | No | Additional CSS class name for custom styling | | isOpen | boolean | true | No | Controls sidebar visibility (useful for mobile) | | onClose | function | undefined | No | Called when sidebar should close (mobile behavior) | | onNavigate | function | undefined | No | Custom navigation handler. Receives (path, externalUrl?) | | activePath | string | undefined | No | Currently active panel. If not provided, component manages its own state |

Prop Examples

// Basic usage
<SidePannel />

// With custom class
<SidePannel className="my-custom-sidebar" />

// Mobile controlled
<SidePannel 
  isOpen={isMobileMenuOpen} 
  onClose={() => setIsMobileMenuOpen(false)} 
/>

// With custom navigation
<SidePannel 
  onNavigate={(path, externalUrl) => {
    if (externalUrl) {
      window.open(externalUrl, '_blank');
    } else {
      router.push(path);
    }
  }}
/>

// Externally controlled active state
<SidePannel activePath="/current-page" />

📱 Mobile Responsiveness

How It Works

| Screen Size | Behavior | Default State | |-------------|----------|---------------| | Desktop (> 1024px) | Always visible, fixed position | Always shown | | Tablet/Mobile (≤ 1024px) | Hidden by default, slides in/out | Hidden |

CSS Classes

The component automatically applies responsive classes:

.sidePannel {
  /* Desktop: Always visible */
  @media (min-width: 1025px) {
    transform: translateX(0);
  }
  
  /* Mobile: Hidden by default */
  @media (max-width: 1024px) {
    transform: translateX(-100%);
    transition: transform 0.3s ease-in-out;
  }
  
  /* Mobile: Shown when .open class is applied */
  &.open {
    @media (max-width: 1024px) {
      transform: translateX(0);
    }
  }
}

Mobile Implementation Tips

// 1. Add a mobile menu button
const [isMobile, setIsMobile] = useState(false);
const [menuOpen, setMenuOpen] = useState(false);

useEffect(() => {
  const checkMobile = () => setIsMobile(window.innerWidth <= 1024);
  window.addEventListener('resize', checkMobile);
  return () => window.removeEventListener('resize', checkMobile);
}, []);

// 2. Show menu button only on mobile
{isMobile && (
  <button onClick={() => setMenuOpen(!menuOpen)}>
    ☰ Menu
  </button>
)}

// 3. Control sidebar with mobile state
<SidePannel 
  isOpen={!isMobile || menuOpen}
  onClose={() => setMenuOpen(false)}
/>

🎨 Navigation Structure

The sidebar contains 21 navigation items organized in 5 color-coded sections:

🟢 Special Operations (Green Background)

// Core system functions
'/iam'           // Identity & Access Management
'/new-intake'    // New item intake process  
'/request'       // Request management
'/localoffice'   // Mail intake
'/destruction'   // Item destruction

🟣 Purple Section (Item Management)

// Item-related operations
'/reuse'             // Item reuse management
'/active-items'      // Currently active items
'/product/manageItem'// Item database
'/flag-item'         // Flagged items
'/messages'          // Message center

🟠 Orange Section (Commerce)

// Business operations
'/shipping'    // Shipping management
'/inventory'   // Inventory tracking
'/orders'      // Order management

⚫ Grey Section (Operations)

// Operational tools
'/logistics'   // Logistics coordination
'/track_item'  // External tracking (AppSheet) 🔗
'/pickups'     // Pickup scheduling
'/weights'     // Weight management  
'/sb-20'       // SB-20 operations

🔴 Red Section (System Admin)

// System administration
'/tickets'         // Issue tickets
'/app-setup'       // Application configuration
'/system/employee' // User management

External URL Example

Some navigation items support external URLs:

// Track Item opens external AppSheet application
{
  path: '/track_item',
  externalUrl: 'https://www.appsheet.com/start/7ad80c49-7615-474d-b4ee-79c84fe9f355',
  icon: 'barcode_reader',
  label: 'Track Item'
}

🔧 Customization

Custom Styling

/* Override default styles */
.my-custom-sidebar {
  width: 20vw;  /* Wider sidebar */
  background: linear-gradient(180deg, #667eea 0%, #764ba2 100%);
}

.my-custom-sidebar .card {
  border-radius: 8px;  /* Rounded cards */
  margin: 4px;
}

.my-custom-sidebar .active {
  background: #ff6b6b;  /* Custom active color */
}

Custom Icons

The component uses Material Icons. To customize:

/* Make sure Material Icons are loaded */
@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined');

/* Or use CDN in your HTML */
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet">

Layout Integration

// Method 1: Fixed sidebar with margin
<div style={{ display: 'flex' }}>
  <SidePannel />
  <main style={{ marginLeft: '15vw', padding: '20px' }}>
    Content
  </main>
</div>

// Method 2: Overlay sidebar (mobile-first)
<div style={{ position: 'relative' }}>
  <SidePannel isOpen={sidebarOpen} />
  <main style={{ padding: '20px' }}>
    Content
  </main>
</div>

📦 Migration Guide

From v1.x to v2.x

Good News: Your existing code will work without any changes!

// ✅ v1.x code - still works in v2.x
<SidePannel className="my-class" />

// ✅ v2.x enhanced features - optional
<SidePannel 
  className="my-class"
  isOpen={isOpen}
  onClose={handleClose}
  onNavigate={handleNavigation}
  activePath={activePath}
/>

Breaking Changes

None! v2.x is fully backwards compatible.

New Features Available

| Feature | v1.x | v2.x | Migration Required | |---------|------|------|-------------------| | Basic sidebar | ✅ | ✅ | None | | Mobile responsive | ❌ | ✅ | Optional props | | External URLs | ❌ | ✅ | Automatic | | Custom navigation | ❌ | ✅ | Optional callback | | Controlled state | ❌ | ✅ | Optional prop |

Recommended Upgrade Steps

  1. Install v2.x

    npm install @titusjin/[email protected]
  2. Test existing functionality (should work unchanged)

  3. Gradually add new features as needed:

    // Start with mobile support
    const [isOpen, setIsOpen] = useState(true);
    <SidePannel isOpen={isOpen} onClose={() => setIsOpen(false)} />
       
    // Then add custom navigation
    <SidePannel onNavigate={(path, externalUrl) => { /* custom logic */ }} />
       
    // Finally add controlled state
    <SidePannel activePath={currentPage} />

� Troubleshooting

Common Issues

1. Sidebar not visible on mobile

// ❌ Problem: isOpen not controlled
<SidePannel />

// ✅ Solution: Control isOpen state
const [isOpen, setIsOpen] = useState(false); // Start closed on mobile
<SidePannel isOpen={isOpen} />

2. Styles not loading

// ❌ Problem: CSS not imported
import SidePannel from '@titusjin/side-panel-module';

// ✅ Solution: Import CSS
import SidePannel from '@titusjin/side-panel-module';
import '@titusjin/side-panel-module/dist/styles.css';

3. Navigation not working

// ❌ Problem: No navigation handler
<SidePannel />

// ✅ Solution: Add navigation handler
<SidePannel onNavigate={(path) => router.push(path)} />

4. TypeScript errors

// ❌ Problem: No type imports
import SidePannel from '@titusjin/side-panel-module';

// ✅ Solution: Import types
import SidePannel, { SidePannelProps } from '@titusjin/side-panel-module';

Debug Mode

Add debug logging to understand behavior:

<SidePannel 
  onNavigate={(path, externalUrl) => {
    console.log('Navigation:', { path, externalUrl });
    // Your navigation logic
  }}
  onClose={() => {
    console.log('Sidebar closed');
    // Your close logic
  }}
/>

🛠️ Development & Contributing

Project Structure

module_sidePannel/
├── src/
│   ├── index.ts          # Main export file
│   ├── sidePannel.tsx    # Main component
│   ├── styles.module.scss# Component styles
│   └── types.d.ts        # Type definitions
├── dist/                 # Built files (generated)
├── example.tsx           # Usage examples
├── package.json          # Package configuration
├── rollup.config.js      # Build configuration
└── README.md            # This file

Local Development

# Clone repository
git clone https://github.com/titusjin/listingApplication.git
cd listingApplication/module_sidePannel

# Install dependencies
npm install

# Build the module
npm run build

# Test the example
npm run dev

Available Scripts

npm run build    # Build for production
npm run dev      # Start development server
npm run clean    # Clean build files
npm test         # Run tests

Building and Publishing

# Build the module
npm run build

# Publish to npm (requires npm login)
npm publish

📄 License

MIT © Titus Jin

🤝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Contribution Guidelines

  • Follow existing code style
  • Add tests for new features
  • Update documentation
  • Ensure backwards compatibility

📞 Support

🔗 Links


Made with ❤️ by Titus Jin