Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ashcroft08/provesa-web/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The AdminSidebar component provides the main navigation sidebar for the PROVESA admin panel. It features a glass-morphism design, active tab highlighting, user profile display, and logout functionality.

Import

import AdminSidebar from '$lib/components/admin/AdminSidebar.svelte';

Props

navItems
array
required
Array of navigation item objects that define the sidebar menu.NavItem Structure:
{
  name: string;      // Display name and unique identifier
  icon: string;      // Material Icons icon name
  badge?: number;    // Optional notification badge count
}
activeTab
string
required
Currently active tab name. This prop is bindable, so changes in the sidebar will update the parent component.Example:
let activeTab = $state('Dashboard');
user
object
User information object for the profile section.User Structure:
{
  name?: string;     // User's full name
  email?: string;    // User's email (not displayed but may be used)
}
If not provided or if name is missing, defaults to “Administrador”.

Usage

Basic Usage

<script>
  import AdminSidebar from '$lib/components/admin/AdminSidebar.svelte';
  
  let activeTab = $state('Dashboard');
  
  const navItems = [
    { name: 'Dashboard', icon: 'dashboard' },
    { name: 'Productos', icon: 'inventory_2' },
    { name: 'Usuarios', icon: 'people', badge: 3 }
  ];
  
  const user = {
    name: 'Juan Pérez'
  };
</script>

<AdminSidebar {navItems} bind:activeTab {user} />

Complete Admin Panel Example

<script>
  import AdminSidebar from '$lib/components/admin/AdminSidebar.svelte';
  
  let { data } = $props();
  let activeTab = $state('Dashboard');
  
  const navItems = [
    { name: 'Dashboard', icon: 'dashboard' },
    { name: 'Sliders', icon: 'view_carousel' },
    { name: 'Productos', icon: 'inventory_2' },
    { name: 'Nosotros', icon: 'info' },
    { name: 'Footer', icon: 'web' },
    { name: 'Páginas Legales', icon: 'gavel' },
    { name: 'Concursos', icon: 'emoji_events' },
    { name: 'Postulaciones', icon: 'work', badge: 5 },
    { name: 'Sugerencias', icon: 'feedback', badge: 12 },
    { name: 'Configuración', icon: 'settings' }
  ];
</script>

<AdminSidebar {navItems} bind:activeTab user={data.user} />

<main class="lg:pl-72">
  {#if activeTab === 'Dashboard'}
    <DashboardTab />
  {:else if activeTab === 'Productos'}
    <ProductosTab />
  {/if}
  <!-- More tabs... -->
</main>

Component Structure

Logo Section

Displays the PROVESA logo at the top:
<div class="flex-shrink-0 px-8 pt-6 pb-4">
  <img src={logo} alt="Provesa" class="mx-auto h-12 w-auto object-contain" />
</div>
Scrollable navigation menu in the middle:
<nav class="sidebar-scroll flex-1 space-y-1 overflow-y-auto px-6 py-2">
  {#each navItems as item}
    <button
      onclick={() => (activeTab = item.name)}
      class="flex w-full items-center gap-4 rounded-2xl px-4 py-2.5
             {activeTab === item.name ? 'active-nav' : 'text-slate-500'}"
    >
      <span class="material-icons text-[20px]">{item.icon}</span>
      {item.name}
      {#if item.badge}
        <span class="bg-accent-red ml-auto rounded-full px-2 py-0.5 
                     text-[10px] text-white">
          {item.badge}
        </span>
      {/if}
    </button>
  {/each}
</nav>

User Profile Section

Fixed at the bottom with logout button:
<div class="flex-shrink-0 border-t border-slate-100 px-6 py-4">
  <div class="flex items-center gap-3 rounded-2xl bg-slate-50 p-3">
    <!-- Avatar with initials -->
    <div class="flex h-10 w-10 items-center justify-center rounded-full 
                bg-primary font-bold text-white uppercase">
      {initials}
    </div>
    
    <!-- User info -->
    <div class="min-w-0 flex-1">
      <p class="truncate text-xs font-bold">{user?.name || 'Administrador'}</p>
      <p class="truncate text-[10px] text-slate-400">Panel de Control</p>
    </div>
    
    <!-- Logout button -->
    <form action="?/logout" method="POST" use:enhance>
      <button class="hover:text-accent-red text-slate-400 transition-colors">
        <span class="material-icons text-lg">logout</span>
      </button>
    </form>
  </div>
</div>

User Initials

The avatar displays user initials derived from the name:
let initials = $derived(
  user?.name
    ? user.name
        .split(' ')
        .map((n) => n[0])
        .join('')
        .toUpperCase()
        .substring(0, 2)
    : 'AD'
);
Examples:
  • “Juan Pérez” → “JP”
  • “María” → “M”
  • “José Antonio López” → “JA”
  • No user → “AD”

Active Tab Styling

The active navigation item receives special styling:
.active-nav {
  background-color: var(--color-primary);
  color: white !important;
  box-shadow: 0 10px 15px -3px rgba(0, 82, 165, 0.3);
}
Inactive items:
text-slate-500 hover:bg-slate-50 hover:text-primary

Notification Badges

Optional red badges for items needing attention:
{#if item.badge}
  <span class="bg-accent-red ml-auto rounded-full px-2 py-0.5 
               text-[10px] text-white">
    {item.badge}
  </span>
{/if}
Example:
{ name: 'Postulaciones', icon: 'work', badge: 5 }

Glass-Morphism Design

The sidebar uses a glass effect:
.glass-sidebar {
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(12px);
  border-right: 1px solid rgba(226, 232, 240, 0.8);
}

Scrollable Navigation

The navigation area is scrollable with hidden scrollbar:
.sidebar-scroll {
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* IE/Edge */
}
.sidebar-scroll::-webkit-scrollbar {
  display: none; /* Chrome/Safari */
}
This allows for many navigation items without breaking the layout.

Logout Functionality

The logout button submits a form action:
<form action="?/logout" method="POST" use:enhance>
  <button title="Cerrar Sesión">
    <span class="material-icons text-lg">logout</span>
  </button>
</form>
The use:enhance directive provides progressive enhancement for the form submission.

Positioning

position: fixed;
inset-y-0;
left-0;
z-index: 50;
width: 18rem; /* 72 in Tailwind = 288px */
  • Fixed to the left side of the viewport
  • Full height
  • Hidden on screens < 1024px (mobile/tablet)
  • Visible on large screens (≥1024px)

Layout Compensation

When using the sidebar, add left padding to main content:
<AdminSidebar {navItems} bind:activeTab {user} />

<main class="lg:pl-72">
  <!-- Content here -->
</main>
The lg:pl-72 class adds left padding equal to the sidebar width on large screens.

Material Icons

Requires Material Icons font to be loaded. Common icons used:
Icon NameUsage
dashboardDashboard/Home
view_carouselSliders
inventory_2Products
infoAbout/Info
webFooter/Web
gavelLegal pages
emoji_eventsContests
workJob applications
feedbackSuggestions
settingsSettings
logoutLogout button

Accessibility

  • Uses semantic HTML with <aside> and <nav> elements
  • Button elements for interactive items
  • Proper ARIA support through semantic HTML
  • Logout button has descriptive title attribute
  • Logo has descriptive alt text
  • Truncated text for long user names

Responsive Behavior

  • Mobile/Tablet (< 1024px): Hidden completely
  • Desktop (≥ 1024px): Visible as fixed sidebar
For mobile navigation, you would typically implement a separate mobile menu or hamburger menu.

Dependencies

  • $app/forms - enhance for progressive enhancement
  • $lib/assets/images/provesa-logo.png - PROVESA logo
  • Material Icons font (must be loaded in app)
  • Admin tabs (DashboardTab, ProductosTab, etc.)
  • Navbar - Public site navigation

Build docs developers (and LLMs) love