Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/JAQA20/Paradigmas-G3/llms.txt

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

La Comanda has three shared layout components used across all authenticated pages: Sidebar, Header, and Notification. Sidebar and Header form the chrome of every protected view — the sidebar is mounted once as a fixed element on the left, and the header is rendered as a sticky bar at the top of the scrollable main content area. Notification is a standalone alert overlay that any page or component can render on demand. The Sidebar is a fixed-position left panel (w-64, h-screen) that provides the primary navigation for the La Comanda admin terminal. It renders the app branding, all main navigation links, a prominent New Order button, secondary links for Settings and Support, and a Logout button. Hooks used:
  • useLocation() (react-router-dom) — derives the active route from location.pathname to apply the active highlight style.
  • useTranslation() (react-i18next) — resolves all visible labels through the sidebar.* translation keys.
  • useAuth() (@clerk/clerk-react) — provides signOut() for the Logout button.
Navigation items are defined as a static array inside the component and mapped to <Link> elements:
const navItems = [
  { id: 'dashboard', label: t('sidebar.dashboard'),       icon: 'dashboard',   path: '/dashboard' },
  { id: 'tables',    label: t('sidebar.table_view'),      icon: 'grid_view',   path: '/tables'    },
  { id: 'kitchen',   label: t('sidebar.kitchen_monitor'), icon: 'chef_hat',    path: '/kitchen'   },
  { id: 'inventory', label: t('sidebar.inventory'),       icon: 'inventory_2', path: '/inventory' },
  { id: 'staff',     label: t('sidebar.staff_control'),   icon: 'badge',       path: '/staff'     },
];
Icons are rendered via Google’s Material Symbols font (<span className="material-symbols-outlined">). The active item uses 'FILL' 1 via fontVariationSettings to switch to the filled icon variant; inactive items use 'FILL' 0. Bottom section (rendered below a border-t divider in the mt-auto footer area):
  • New Order — a full-width <button> with a gradient background (from-primary to-primary-container).
  • Settings<Link to="/settings"> with the same active-state logic as nav items.
  • Support<Link to="/support">.
  • Logout — a <button> styled in text-error that calls signOut() on click.
Full component source:
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { useAuth } from '@clerk/clerk-react';

export const Sidebar: React.FC = () => {
    const location = useLocation();
    const { t } = useTranslation();
    const { signOut } = useAuth();
    const active = location.pathname.substring(1) || 'dashboard';

    const navItems = [
        { id: 'dashboard', label: t('sidebar.dashboard'),       icon: 'dashboard',   path: '/dashboard' },
        { id: 'tables',    label: t('sidebar.table_view'),      icon: 'grid_view',   path: '/tables'    },
        { id: 'kitchen',   label: t('sidebar.kitchen_monitor'), icon: 'chef_hat',    path: '/kitchen'   },
        { id: 'inventory', label: t('sidebar.inventory'),       icon: 'inventory_2', path: '/inventory' },
        { id: 'staff',     label: t('sidebar.staff_control'),   icon: 'badge',       path: '/staff'     },
    ];

    return (
        <aside className="h-screen w-64 fixed left-0 top-0 bg-surface-container-low dark:bg-surface-container-lowest flex flex-col py-6 px-4 z-50">
            <div className="mb-8 px-2 flex items-center gap-3">
                <div className="w-10 h-10 rounded-full bg-primary flex items-center justify-center text-white">
                    <span className="material-symbols-outlined" style={{ fontVariationSettings: "'FILL' 1" }}>restaurant</span>
                </div>
                <div>
                    <h1 className="text-2xl font-headline font-bold text-primary">La Comanda</h1>
                    <p className="text-xs font-label text-on-surface-variant tracking-wider uppercase">{t('sidebar.admin_terminal')}</p>
                </div>
            </div>

            <nav className="flex-1 space-y-1">
                {navItems.map((item) => {
                    const isActive = active === item.id || (active === '' && item.id === 'dashboard');
                    return (
                        <Link
                            key={item.id}
                            to={item.path}
                            className={`flex items-center gap-3 px-4 py-3 rounded-xl transition-colors ${
                                isActive
                                ? 'bg-primary-container text-on-primary-container font-bold shadow-sm'
                                : 'text-on-surface-variant hover:bg-surface-container-high'
                            }`}
                        >
                            <span className="material-symbols-outlined" style={{ fontVariationSettings: isActive ? "'FILL' 1" : "'FILL' 0" }}>{item.icon}</span>
                            <span className={`font-label text-sm ${isActive ? '' : 'font-medium'}`}>{item.label}</span>
                        </Link>
                    );
                })}
            </nav>

            <div className="mt-auto pt-6 space-y-1 border-t border-outline-variant/15">
                <button className="w-full mb-4 py-3 px-4 bg-gradient-to-r from-primary to-primary-container text-white rounded-full font-label text-sm font-bold shadow-md hover:opacity-90 transition-all active:scale-95">
                    {t('sidebar.new_order')}
                </button>
                <Link to="/settings" className={`flex items-center gap-3 px-4 py-3 rounded-xl transition-colors ${active === 'settings' ? 'bg-primary-container text-on-primary-container font-bold shadow-sm' : 'text-on-surface-variant hover:bg-surface-container-high'}`}>
                    <span className="material-symbols-outlined text-xl" style={{ fontVariationSettings: active === 'settings' ? "'FILL' 1" : "'FILL' 0" }}>settings</span>
                    <span className={`font-label text-sm ${active === 'settings' ? '' : 'font-medium'}`}>{t('sidebar.settings')}</span>
                </Link>
                <Link to="/support" className={`flex items-center gap-3 px-4 py-3 rounded-xl transition-colors ${active === 'support' ? 'bg-primary-container text-on-primary-container font-bold shadow-sm' : 'text-on-surface-variant hover:bg-surface-container-high'}`}>
                    <span className="material-symbols-outlined text-xl" style={{ fontVariationSettings: active === 'support' ? "'FILL' 1" : "'FILL' 0" }}>help</span>
                    <span className={`font-label text-sm ${active === 'support' ? '' : 'font-medium'}`}>{t('sidebar.support')}</span>
                </Link>
                <button onClick={() => signOut()} className="flex w-full items-center gap-3 px-4 py-3 text-error hover:bg-error-container/20 transition-colors rounded-xl mt-2">
                    <span className="material-symbols-outlined text-xl">logout</span>
                    <span className="font-label text-sm font-medium">{t('sidebar.logout')}</span>
                </button>
            </div>
        </aside>
    );
};

The Header is a sticky top bar (h-16, sticky top-0 z-40) rendered at the top of the main content area on all authenticated pages. It contains a search input on the left, and a notifications button, history button, and user profile card on the right. Props:
PropTypeDefaultDescription
titlestringundefinedOptional page title (accepted by the interface but not currently rendered in the bar itself).
searchPlaceholderstringt('header.search')Placeholder text for the search input. Falls back to the i18n value "Search settings or tools..." if omitted.
Hooks used:
  • useTranslation() — resolves header.search and header.manager labels.
Full component source:
import React from 'react';
import { useTranslation } from 'react-i18next';

interface HeaderProps {
    title?: string;
    searchPlaceholder?: string;
}

export const Header: React.FC<HeaderProps> = ({
    searchPlaceholder
}) => {
    const { t } = useTranslation();
    const finalSearchPlaceholder = searchPlaceholder || t('header.search');

    return (
        <header className="flex justify-between items-center h-16 px-8 sticky top-0 z-40 glass-header">
            <div className="flex items-center gap-4 flex-1">
                <div className="relative w-full max-w-md group">
                    <span className="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-on-surface-variant group-focus-within:text-primary transition-colors">search</span>
                    <input className="w-full bg-surface-container-low border-none rounded-full py-2 pl-10 pr-4 text-sm focus:ring-2 focus:ring-primary/20 transition-all font-body" placeholder={finalSearchPlaceholder} type="text" />
                </div>
            </div>
            <div className="flex items-center gap-6">
                <button className="relative text-on-surface-variant hover:text-primary transition-colors">
                    <span className="material-symbols-outlined">notifications</span>
                    <span className="absolute top-0 right-0 w-2 h-2 bg-error rounded-full"></span>
                </button>
                <button className="text-on-surface-variant hover:text-primary transition-colors">
                    <span className="material-symbols-outlined">history</span>
                </button>
                <div className="h-8 w-[1px] bg-outline-variant/30"></div>
                <div className="flex items-center gap-3">
                    <div className="text-right">
                        <p className="text-xs font-bold font-label">Andrés G.</p>
                        <p className="text-[10px] text-on-surface-variant">{t('header.manager')}</p>
                    </div>
                    <div className="w-10 h-10 rounded-full overflow-hidden bg-surface-container-high">
                        <img className="w-full h-full object-cover" alt="Profile" src="https://lh3.googleusercontent.com/aida-public/AB6AXuC-xSOnmii4s3POtelZ2398y7bB4F168sKb4kR516PXLViUzUDeO41WoAl06f6oYJZ7uAT4sPenHD9-r66AgZrHMWu0C5Qxk8suQRipE4xzKCUffGFvWpHUcoMOVy8lXhlM_nzmcH9TcQamu3Zc5m8kycqVqIZZe2n68juLU9EfcOsG0kiLXemiE-VBkzKBMn9evNX2W_kC340_qgv6b0duWxX3lAU_2jJg3uOQNzCbmSbyWzOuI9OnBQ" />
                    </div>
                </div>
            </div>
        </header>
    );
};
The glass-header class is defined in index.css as a custom utility. It applies a backdrop-filter: blur and a semi-transparent background to give the header its frosted-glass appearance over scrolling content.

Notification

The Notification component renders a fixed-position alert overlay in the top-right corner of the viewport (fixed top-20 right-8 z-50). It supports three visual types — urgent, success, and info — and can close itself automatically after a configurable delay. Props:
PropTypeDefaultDescription
titlestringSmall all-caps label shown above the heading (e.g. "URGENT", "LOW STOCK").
timestring"JUST NOW"Timestamp badge rendered in a monospace chip.
headingstringLarge bold headline text.
descriptionstringBody text with additional detail.
type'urgent' | 'success' | 'info''urgent'Controls background color and icon.
onClose() => voidundefinedCallback invoked when the notification is dismissed.
autoCloseMsnumberundefinedIf set, auto-dismisses the notification after this many milliseconds.
Type → style mapping:
TypeBackgroundIconAnimation
urgentbg-error text-on-errorpriority_highanimate-pulse
successbg-green-600 text-whitecheck_circleNone
infobg-primary text-whiteinfoNone
Full component source:
import React, { useState, useEffect } from 'react';

interface NotificationProps {
    title: string;
    time?: string;
    heading: string;
    description: string;
    type?: 'urgent' | 'success' | 'info';
    onClose?: () => void;
    autoCloseMs?: number;
}

export const Notification: React.FC<NotificationProps> = ({
    title,
    time = "JUST NOW",
    heading,
    description,
    type = 'urgent',
    onClose,
    autoCloseMs
}) => {
    const [isVisible, setIsVisible] = useState(true);

    useEffect(() => {
        if (autoCloseMs) {
            const timer = setTimeout(() => {
                handleClose();
            }, autoCloseMs);
            return () => clearTimeout(timer);
        }
    }, [autoCloseMs]);

    const handleClose = () => {
        setIsVisible(false);
        if (onClose) onClose();
    };

    if (!isVisible) return null;

    let containerClass = "bg-error text-on-error";
    let icon = "priority_high";

    if (type === 'success') {
        containerClass = "bg-green-600 text-white";
        icon = "check_circle";
    } else if (type === 'info') {
        containerClass = "bg-primary text-white";
        icon = "info";
    }

    return (
        <div className="fixed top-20 right-8 z-50 animate-in slide-in-from-right-8 duration-300">
            <div className={`${containerClass} p-4 rounded-xl shadow-xl border-2 border-white/20 flex items-center gap-4 min-w-[320px] ${type === 'urgent' ? 'animate-pulse' : ''}`}>
                <div className="w-12 h-12 bg-white/20 rounded-full flex items-center justify-center shrink-0">
                    <span className="material-symbols-outlined text-3xl">{icon}</span>
                </div>
                <div className="flex-grow">
                    <div className="flex justify-between items-start">
                        <p className="font-label text-xs uppercase tracking-widest opacity-90 font-bold">{title}</p>
                        <span className="text-[10px] font-mono bg-black/20 px-2 py-0.5 rounded">{time}</span>
                    </div>
                    <p className="text-xl font-bold font-headline leading-tight mt-1">{heading}</p>
                    <p className="text-sm font-body opacity-90 mt-1">{description}</p>
                </div>
                <button onClick={handleClose} className="p-1 hover:bg-white/10 rounded-full transition-colors flex shrink-0 self-start">
                    <span className="material-symbols-outlined">close</span>
                </button>
            </div>
        </div>
    );
};

Usage Example

Every authenticated page follows the same layout pattern: the Sidebar is rendered as a sibling to a <main> element that is offset with ml-72 to clear the fixed sidebar width, and the Header is the first child inside <main>.
import { Sidebar } from '../components/Sidebar';
import { Header } from '../components/Header';

export const Dashboard: React.FC = () => (
  <div className="bg-slate-50 min-h-screen">
    <Sidebar />
    <main className="ml-72 flex flex-col min-h-screen">
      <Header title="Analytics Dashboard" />
      {/* page content */}
    </main>
  </div>
);
To display an alert from any page, render <Notification> anywhere in the tree — it positions itself absolutely over the viewport:
import { Notification } from '../components/Notification';

<Notification
  title="Low Stock"
  heading="Vegetable supplies critical"
  description="4 items are below their reorder point."
  type="urgent"
  autoCloseMs={6000}
  onClose={() => setShowAlert(false)}
/>

Build docs developers (and LLMs) love