diff --git a/src/navigation.js b/src/navigation.js index 41dd73d..d9d2725 100644 --- a/src/navigation.js +++ b/src/navigation.js @@ -116,6 +116,116 @@ function generateVitePageComponent(page, config) { `; } +// Icon mapping for sidebar nav items (Lucide icon names) +const ICON_MAP = { + Home: 'Home', Dashboard: 'LayoutDashboard', Products: 'ShoppingBag', + Cart: 'ShoppingCart', Account: 'User', Wishlist: 'Heart', + Orders: 'Package', Categories: 'Grid3X3', Search: 'Search', + Support: 'HelpCircle', Students: 'Users', Courses: 'BookOpen', + Grades: 'Award', Attendance: 'ClipboardCheck', Schedule: 'Calendar', + Payments: 'CreditCard', Reports: 'BarChart3', Staff: 'Briefcase', + Analytics: 'TrendingUp', Users: 'Users', Billing: 'Receipt', + Settings: 'Settings', Integrations: 'Puzzle', Team: 'UserPlus', + Articles: 'FileText', Authors: 'Pen', Newsletter: 'Mail', + About: 'Info', Tags: 'Tag', Archive: 'Archive', Contact: 'MessageSquare', + Projects: 'FolderKanban', Skills: 'Zap', Blog: 'BookOpen', + Testimonials: 'Quote', Resume: 'FileUser', Services: 'Wrench', +}; + +// Templates that support sidebar +const SIDEBAR_TEMPLATES = ['ecommerce', 'school', 'saas', 'blog']; + +function generateSidebarComponent(selectedPages, config, isVite) { + const iconImports = selectedPages + .map((p) => ICON_MAP[p.label] || 'Circle') + .filter((v, i, a) => a.indexOf(v) === i); // deduplicate + // Always include Circle as the fallback icon + if (!iconImports.includes('Circle')) iconImports.push('Circle'); + + const linkComponent = isVite ? 'Link' : 'Link'; + const linkProp = isVite ? 'to' : 'href'; + const linkImport = isVite + ? "import { Link, useLocation } from 'react-router-dom';" + : "import Link from 'next/link';"; + const navImport = isVite + ? "import { navLinks } from '../lib/nav';" + : "import { navLinks } from '../lib/nav';"; + + const activeLogic = isVite + ? ` const location = useLocation(); + const isActive = (href: string) => location.pathname === href;` + : ` const isActive = (href: string) => false; // Replace with usePathname() for active state`; + + const iconEntries = selectedPages.map((p) => { + const icon = ICON_MAP[p.label] || 'Circle'; + return ` '${p.label}': ${icon},`; + }).join('\n'); + + return `'use client'; + +${linkImport} +import { ${iconImports.join(', ')} } from 'lucide-react'; +${navImport} + +const iconMap: Record> = { +${iconEntries} +}; + +export default function Sidebar() { +${activeLogic} + + return ( + + ); +} +`; +} + export function generateNavigation(projectPath, config) { const pool = PAGE_POOLS[config.template]; if (!pool) return; @@ -153,5 +263,17 @@ export function generateNavigation(projectPath, config) { } } + // 3. Generate Sidebar.tsx if template supports it and user selected sidebar + if (config.includeSidebar && SIDEBAR_TEMPLATES.includes(config.template)) { + const sidebarDir = isVite + ? path.join(projectPath, 'src', 'components') + : path.join(projectPath, 'components'); + + if (!fs.existsSync(sidebarDir)) fs.mkdirSync(sidebarDir, { recursive: true }); + + const sidebarPath = path.join(sidebarDir, 'Sidebar.tsx'); + fs.writeFileSync(sidebarPath, generateSidebarComponent(selectedPages, config, isVite)); + } + return selectedPages; }