VibeCoderzVibeCoderz
Telegram
All Prompts
Role-Based Side Drawer Navigation UI Preview
mobile appnavigationlayout

Role-Based Side Drawer Navigation

Контекстная боковая панель навигации. Динамически адаптирует пункты меню под роль пользователя, сохраняя структуру. Идеально для CRM и enterprise-приложений.

by Shirley LouLive Preview

Prompt

# Role-Based Side Drawer Navigation

Here is a reference implementation:

~~~html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Role-Based Navigation Drawer</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&display=swap" rel="stylesheet">
  <script src="https://code.iconify.design/iconify-icon/1.0.7/iconify-icon.min.js"></script>
  <style>
    body {
      font-family: 'Manrope', sans-serif;
      margin: 0;
      padding: 0;
      background-color: #F3F4F6;
    }
    /* Custom scrollbar for clean look */
    .hide-scrollbar::-webkit-scrollbar {
      display: none;
    }
    .hide-scrollbar {
      -ms-overflow-style: none;
      scrollbar-width: none;
    }
    /* Smooth fade in for drawer content */
    @keyframes slideIn {
      from { transform: translateX(-100%); }
      to { transform: translateX(0); }
    }
    @keyframes fadeIn {
      from { opacity: 0; }
      to { opacity: 1; }
    }
    .drawer-animate {
      animation: slideIn 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
    }
    .backdrop-animate {
      animation: fadeIn 0.4s ease-out forwards;
    }
  </style>
</head>
<body>
  <!-- Root Container (Mobile Viewport) -->
  <div class="w-full h-screen relative bg-white overflow-hidden flex flex-col">
    
    <!-- BACKGROUND APP CONTENT (Context Layer) -->
    <!-- This represents the app behind the drawer, blurred and dimmed -->
    <main class="flex-1 bg-gray-50 flex flex-col w-full h-full relative">
      <header class="pt-14 px-5 pb-4 flex justify-between items-center bg-white border-b border-gray-100">
        <button id="drawer-open-btn" class="w-10 h-10 flex items-center justify-center rounded-lg hover:bg-gray-100 transition-colors" aria-label="Open menu">
          <iconify-icon icon="lucide:menu" class="text-2xl text-gray-900"></iconify-icon>
        </button>
        <div class="w-8 h-8 rounded-full bg-gray-200"></div>
      </header>
      <div class="p-5 space-y-4">
        <div class="h-40 w-full bg-white rounded-xl border border-gray-200 shadow-sm"></div>
        <div class="h-24 w-full bg-white rounded-xl border border-gray-200 shadow-sm"></div>
        <div class="h-56 w-full bg-white rounded-xl border border-gray-200 shadow-sm"></div>
      </div>
    </main>

    <!-- DRAWER OVERLAY SYSTEM -->
    
    <!-- Backdrop -->
    <div id="drawer-backdrop" class="absolute inset-0 bg-gray-900/40 backdrop-blur-[2px] z-40 opacity-0 pointer-events-none transition-opacity duration-300"></div>

    <!-- Side Drawer Panel -->
    <nav id="side-drawer" class="absolute top-0 left-0 bottom-0 w-[320px] bg-white z-50 shadow-2xl flex flex-col -translate-x-full transition-transform duration-300 ease-in-out border-r border-gray-100">
      
      <!-- 1. USER CONTEXT AREA -->
      <div class="pt-14 pb-6 px-6 border-b border-gray-100 flex items-center gap-4 bg-white">
        <div class="relative">
          <div class="w-12 h-12 rounded-full bg-gray-100 flex items-center justify-center border border-gray-200">
            <!-- Placeholder Avatar Icon -->
            <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" class="text-gray-400" stroke-width="1.5">
              <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
              <circle cx="12" cy="7" r="4"></circle>
            </svg>
          </div>
          <!-- Online Status Dot -->
          <div class="absolute bottom-0 right-0 w-3 h-3 bg-emerald-500 border-2 border-white rounded-full"></div>
        </div>
        
        <div class="flex-1 min-w-0">
          <h2 class="text-gray-900 font-bold text-base truncate">Alex Morgan</h2>
          <div class="flex items-center gap-2 mt-0.5">
            <span class="bg-black text-white text-[10px] font-bold px-2 py-0.5 rounded-full uppercase tracking-wider">Editor</span>
            <span class="text-xs text-gray-500">@design_lead</span>
          </div>
        </div>
      </div>

      <!-- SCROLLABLE NAVIGATION CONTENT -->
      <div class="flex-1 overflow-y-auto hide-scrollbar py-6 px-4 space-y-8">

        <!-- 2. SECTION: DISCOVER -->
        <div class="space-y-1">
          <h3 class="px-3 text-xs font-bold text-gray-400 uppercase tracking-widest mb-3">Discover</h3>
          
          <!-- Nav Item: Active State -->
          <a href="#" class="flex items-center gap-3 px-3 py-3 bg-gray-50 rounded-lg text-gray-900 group transition-colors">
            <div class="w-5 h-5 flex items-center justify-center">
               <svg class="w-5 h-5 text-gray-900" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                 <rect x="3" y="3" width="7" height="7" rx="1"></rect>
                 <rect x="14" y="3" width="7" height="7" rx="1"></rect>
                 <rect x="14" y="14" width="7" height="7" rx="1"></rect>
                 <rect x="3" y="14" width="7" height="7" rx="1"></rect>
               </svg>
            </div>
            <span class="font-semibold text-sm">Dashboard</span>
          </a>

          <!-- Nav Item: Default -->
          <a href="#" class="flex items-center gap-3 px-3 py-3 text-gray-600 hover:bg-gray-50 hover:text-gray-900 rounded-lg transition-colors">
            <div class="w-5 h-5 flex items-center justify-center">
               <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                 <circle cx="12" cy="12" r="10"></circle>
                 <line x1="12" y1="8" x2="12" y2="12"></line>
                 <line x1="12" y1="16" x2="12.01" y2="16"></line>
               </svg>
            </div>
            <span class="font-medium text-sm">Updates</span>
            <span class="ml-auto bg-gray-100 text-gray-600 text-[10px] font-bold px-1.5 py-0.5 rounded">4</span>
          </a>

          <a href="#" class="flex items-center gap-3 px-3 py-3 text-gray-600 hover:bg-gray-50 hover:text-gray-900 rounded-lg transition-colors">
             <div class="w-5 h-5 flex items-center justify-center">
                <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                  <path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
                </svg>
             </div>
             <span class="font-medium text-sm">Messages</span>
          </a>
        </div>

        <!-- 3. SECTION: WORKSPACE (Expandable Groups) -->
        <div class="space-y-1">
          <h3 class="px-3 text-xs font-bold text-gray-400 uppercase tracking-widest mb-3">Workspace</h3>

          <!-- Expandable Group: OPEN -->
          <div class="space-y-1">
            <button id="toggle-design-system" class="w-full flex items-center gap-3 px-3 py-3 text-gray-900 rounded-lg hover:bg-gray-50 transition-colors">
              <div class="w-5 h-5 flex items-center justify-center">
                <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                  <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path>
                </svg>
              </div>
              <span class="font-semibold text-sm flex-1 text-left">Design System</span>
              <svg class="w-4 h-4 text-gray-400 transform rotate-180 transition-transform" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                <polyline points="6 9 12 15 18 9"></polyline>
              </svg>
            </button>
            
            <!-- Nested Items (Indented) -->
            <div id="content-design-system" class="pl-11 pr-2 space-y-1 overflow-hidden transition-all duration-300">
              <a href="#" class="block py-2 text-sm text-gray-500 hover:text-gray-900 font-medium">Components</a>
              <a href="#" class="block py-2 text-sm text-gray-900 font-semibold border-l-2 border-black pl-3 -ml-3">Typography</a>
              <a href="#" class="block py-2 text-sm text-gray-500 hover:text-gray-900 font-medium">Color Palette</a>
            </div>
          </div>

          <!-- Expandable Group: COLLAPSED -->
          <div>
            <button id="toggle-documentation" class="w-full flex items-center gap-3 px-3 py-3 text-gray-600 rounded-lg hover:bg-gray-50 transition-colors">
              <div class="w-5 h-5 flex items-center justify-center">
                <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                  <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
                  <polyline points="14 2 14 8 20 8"></polyline>
                  <line x1="16" y1="13" x2="8" y2="13"></line>
                  <line x1="16" y1="17" x2="8" y2="17"></line>
                  <polyline points="10 9 9 9 8 9"></polyline>
                </svg>
              </div>
              <span class="font-medium text-sm flex-1 text-left">Documentation</span>
              <svg class="w-4 h-4 text-gray-400 transition-transform" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                <polyline points="6 9 12 15 18 9"></polyline>
              </svg>
            </button>
            <div id="content-documentation" class="pl-11 pr-2 space-y-1 overflow-hidden h-0 transition-all duration-300 opacity-0">
              <a href="#" id="doc-api-link" class="block py-2 text-sm text-gray-500 hover:text-gray-900 font-medium">API Reference</a>
              <a href="#" id="doc-guides-link" class="block py-2 text-sm text-gray-500 hover:text-gray-900 font-medium">User Guides</a>
            </div>
          </div>
        </div>

        <!-- 4. SECTION: ADMIN (Permission Gated) -->
        <div class="space-y-1">
          <div class="flex items-center justify-between px-3 mb-3">
            <h3 class="text-xs font-bold text-gray-400 uppercase tracking-widest">Admin</h3>
            <!-- Role Indicator -->
            <span class="text-[10px] text-gray-400 font-medium flex items-center gap-1">
              <svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                <rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
                <path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
              </svg>
              Restricted
            </span>
          </div>

          <!-- Permitted Item -->
          <a href="#" class="flex items-center gap-3 px-3 py-3 text-gray-600 hover:bg-gray-50 hover:text-gray-900 rounded-lg transition-colors">
            <div class="w-5 h-5 flex items-center justify-center">
              <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
                <circle cx="9" cy="7" r="4"></circle>
                <path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
                <path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
              </svg>
            </div>
            <span class="font-medium text-sm">Team Members</span>
          </a>

          <!-- Locked/Restricted Item (Visual permission handling) -->
          <div class="group relative flex items-center gap-3 px-3 py-3 rounded-lg opacity-50 cursor-not-allowed">
            <div class="w-5 h-5 flex items-center justify-center">
              <svg class="w-5 h-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                <rect x="2" y="5" width="20" height="14" rx="2"></rect>
                <line x1="2" y1="10" x2="22" y2="10"></line>
              </svg>
            </div>
            <span class="font-medium text-sm text-gray-400">Billing & Plans</span>
            <div class="ml-auto">
              <svg class="w-3.5 h-3.5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
                <rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
                <path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
              </svg>
            </div>
          </div>

          <!-- Hidden Item Placeholder (Shows logic of conditional rendering) -->
          <!-- <div class="hidden">Audit Logs</div> -->
        </div>

      </div>

      <!-- DRAWER FOOTER (Bottom Safe Area) -->
      <div class="pb-[34px] bg-white">
        <div class="px-6 py-4 border-t border-gray-100">
          <a href="#" class="flex items-center gap-3 text-gray-500 hover:text-gray-900 transition-colors">
            <div class="w-5 h-5 flex items-center justify-center">
              <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                <path d="M18.36 6.64a9 9 0 1 1-12.73 0"></path>
                <line x1="12" y1="2" x2="12" y2="12"></line>
              </svg>
            </div>
            <span class="font-medium text-sm">Log Out</span>
          </a>
        </div>
      </div>
    </nav>

  </div>
<script>
    const drawer = document.getElementById('side-drawer');
    const backdrop = document.getElementById('drawer-backdrop');
    const openBtn = document.getElementById('drawer-open-btn');
    const closeBtn = document.getElementById('drawer-open-btn'); // Reuse or specific logout/close if added

    const toggleDrawer = (isOpen) => {
      if (isOpen) {
        drawer.classList.remove('-translate-x-full');
        backdrop.classList.remove('opacity-0', 'pointer-events-none');
        backdrop.classList.add('opacity-100');
      } else {
        drawer.classList.add('-translate-x-full');
        backdrop.classList.remove('opacity-100');
        backdrop.classList.add('opacity-0', 'pointer-events-none');
      }
    };

    openBtn.addEventListener('click', () => toggleDrawer(true));
    backdrop.addEventListener('click', () => toggleDrawer(false));

    const setupToggle = (btnId, contentId) => {
      const btn = document.getElementById(btnId);
      const content = document.getElementById(contentId);
      const arrow = btn.querySelector('svg:last-child');

      btn.addEventListener('click', () => {
        const isExpanded = content.style.height !== '0px' && content.style.height !== '';
        if (isExpanded) {
          content.style.height = '0px';
          content.style.opacity = '0';
          arrow.style.transform = 'rotate(0deg)';
          btn.classList.replace('text-gray-900', 'text-gray-600');
          btn.classList.remove('font-semibold');
        } else {
          content.style.height = content.scrollHeight + 'px';
          content.style.opacity = '1';
          arrow.style.transform = 'rotate(180deg)';
          btn.classList.replace('text-gray-600', 'text-gray-900');
          btn.classList.add('font-semibold');
        }
      });
    };

    setupToggle('toggle-design-system', 'content-design-system');
    setupToggle('toggle-documentation', 'content-documentation');

    // Initial state for Documentation (it was closed by default in prompt)
    document.getElementById('content-documentation').style.height = '0px';
  </script>
</body>
</html>
~~~
All Prompts