@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
Maintainers
Readme
🔧 Side Panel Module
A powerful, mobile-responsive React navigation sidebar for Next.js applications
📖 Table of Contents
- ✨ Features
- 🚀 Quick Start
- 📚 Usage Examples
- ⚙️ Props Reference
- 📱 Mobile Responsiveness
- 🎨 Navigation Structure
- 🔧 Customization
- 📦 Migration Guide
✨ 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-module2. 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 managementExternal 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
Install v2.x
npm install @titusjin/[email protected]Test existing functionality (should work unchanged)
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 fileLocal 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 devAvailable Scripts
npm run build # Build for production
npm run dev # Start development server
npm run clean # Clean build files
npm test # Run testsBuilding and Publishing
# Build the module
npm run build
# Publish to npm (requires npm login)
npm publish📄 License
MIT © Titus Jin
🤝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Contribution Guidelines
- Follow existing code style
- Add tests for new features
- Update documentation
- Ensure backwards compatibility
📞 Support
- 📚 Documentation: This README
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
- 📧 Email: [email protected]
🔗 Links
Made with ❤️ by Titus Jin
