README.md

# NavBuddy

[![Hex version badge](https://img.shields.io/hexpm/v/navbuddy.svg)](https://hex.pm/packages/navbuddy)
[![Hex docs badge](https://img.shields.io/badge/hex-docs-green.svg)](https://hexdocs.pm/navbuddy)
[![License badge](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/SangRJ/navbuddy/blob/main/LICENSE)

**Advanced Configurable Navigation Component for Phoenix LiveView**

NavBuddy provides comprehensive navigation components for Phoenix LiveView applications, featuring dropdowns, mega menus, mobile-responsive design, native DaisyUI integration, and full accessibility support.

## Features

- 🎯 **Advanced Menu System**: Single-layer dropdowns, multi-layer dropdowns, and mega menus
- 📱 **Mobile-Responsive**: Drawer, collapse, and overlay modes for mobile devices
- 🎨 **Native DaisyUI Integration**: True Tailwind CSS + DaisyUI support with theme compatibility
- 🎨 **Standalone DaisyUI**: Built-in compatibility with DaisyUI components and themes
- ♿ **Accessibility First**: WCAG 2.1 AA compliant with screen reader support
- ⌨️ **Keyboard Navigation**: Full arrow key navigation with focus management
- 🎨 **Modern Theming**: DaisyUI theme tokens with light/dark/auto theme support
- 🔧 **Highly Configurable**: Extensive configuration options
- 🚀 **Phoenix 1.8+ Ready**: Enhanced for Phoenix 1.8+ and LiveView 1.1+
- 📊 **Analytics Ready**: Built-in event tracking support

## Quick Start

Add to your `mix.exs`:

```elixir
def deps do
  [
    {:navbuddy, "~> 0.4.0"}
  ]
end
```

## Installation & Setup

Choose your integration approach:

### 🚀 Native DaisyUI Integration (Recommended for Phoenix 1.8+)

For projects with Tailwind CSS + DaisyUI already set up:

```elixir
# Add to mix.exs
{:navbuddy, "~> 0.4.0"}
```

Then use native components:

```heex
<NavBuddy.NativeComponent.native_nav
  items={@nav_items}
  brand={%{name: "MyApp", href: "/"}}
  theme="light"
/>
```

**📖 [Complete Native Setup Guide](NATIVE_DAISYUI_GUIDE.md)**

### With DaisyUI (Recommended)

If you're using DaisyUI in your Phoenix project, NavBuddy will automatically integrate with your existing themes and styling:

```html
<!-- NavBuddy CSS will work seamlessly with your DaisyUI setup -->
<link rel="stylesheet" href="/assets/navbuddy.css" />
<script src="/assets/navbuddy.js"></script>
```

### Standalone (Without DaisyUI)

Include the CSS and JavaScript in your layout:

```html
<link rel="stylesheet" href="/assets/navbuddy.css" />
<script src="/assets/navbuddy.js"></script>
```

Use in your LiveView:

```elixir
defmodule MyAppWeb.PageLive do
  use MyAppWeb, :live_view
  import NavBuddy.Component

  def mount(_params, _session, socket) do
    socket = assign(socket, :navigation_items, navigation_items())
    {:ok, socket}
  end

  def render(assigns) do
    ~H"""
    <.nav_menu items={@navigation_items} current_path={@current_path} />
    """
  end

  defp navigation_items do
    [
      %{id: "home", label: "Home", navigate: "/"},
      %{id: "about", label: "About", navigate: "/about"},
      %{
        id: "products",
        label: "Products",
        navigate: "/products",
        dropdown: [
          %{id: "web", label: "Web Apps", navigate: "/products/web"},
          %{id: "mobile", label: "Mobile Apps", navigate: "/products/mobile"}
        ]
      }
    ]
  end
end
```

## Navigation Structure

NavBuddy supports various navigation structures with comprehensive validation and helpful error messages.

### Required vs Optional Fields

**Required fields:**

- `id` (string) - Unique identifier for the navigation item
- `label` (string) - Display text for the navigation item

**Optional fields:**

- `navigate` (string) - Path to navigate to (required for clickable items)
- `icon` (string) - Icon class or identifier
- `dropdown` (list) - List of child navigation items
- `mega_menu` (map) - Mega menu configuration
- `active` (boolean) - Whether the item is currently active
- `disabled` (boolean) - Whether the item is disabled
- `permissions` (string | list) - Required permissions to see the item

### Convenience Functions

NavBuddy provides helper functions to create navigation items easily:

```elixir
# Simple navigation item
NavBuddy.nav_item("home", "Home", "/")
# => %{id: "home", label: "Home", navigate: "/"}

# With additional options
NavBuddy.nav_item("admin", "Admin", "/admin", permissions: "admin", icon: "admin-icon")
# => %{id: "admin", label: "Admin", navigate: "/admin", permissions: "admin", icon: "admin-icon"}

# Dropdown item
dropdown_items = [
  NavBuddy.nav_item("web", "Web Apps", "/products/web"),
  NavBuddy.nav_item("mobile", "Mobile Apps", "/products/mobile")
]
NavBuddy.dropdown_item("products", "Products", dropdown_items)

# Mega menu item
categories = %{
  "Frontend" => [NavBuddy.nav_item("react", "React", "/tools/react")],
  "Backend" => [NavBuddy.nav_item("elixir", "Elixir", "/tools/elixir")]
}
NavBuddy.mega_menu_item("tools", "Tools", categories)
```

### Validation and Error Handling

NavBuddy provides comprehensive validation with helpful error messages:

```elixir
# Invalid item - missing required fields
NavBuddy.validate_nav_item(%{label: "Home"})
# => {:error, "Navigation item missing required field 'id'. Required fields: id (string), label (string). Optional fields: navigate, icon, dropdown, mega_menu, active, disabled, permissions"}

# Invalid field type
NavBuddy.validate_nav_item(%{id: "home", label: "Home", active: "yes"})
# => {:error, "Field 'active' must be a boolean, got: \"yes\""}

# Conflicting navigation types
NavBuddy.validate_nav_item(%{id: "item", label: "Item", dropdown: [], mega_menu: %{}})
# => {:error, "Navigation item cannot have both 'dropdown' and 'mega_menu'. Choose one or the other."}
```

### Simple Links

```elixir
%{id: "home", label: "Home", navigate: "/", icon: "home"}
```

### Single-Layer Dropdowns

```elixir
%{
  id: "products",
  label: "Products",
  navigate: "/products",
  icon: "package",
  dropdown: [
    %{id: "web", label: "Web Development", navigate: "/products/web"},
    %{id: "mobile", label: "Mobile Apps", navigate: "/products/mobile"}
  ]
}
```

### Multi-Layer Dropdowns

```elixir
%{
  id: "services",
  label: "Services",
  dropdown: [
    %{
      id: "development",
      label: "Development",
      dropdown: [
        %{id: "frontend", label: "Frontend", navigate: "/services/frontend"},
        %{id: "backend", label: "Backend", navigate: "/services/backend"}
      ]
    }
  ]
}
```

### Mega Menus

```elixir
%{
  id: "solutions",
  label: "Solutions",
  mega_menu: %{
    title: "Our Solutions",
    description: "Comprehensive business solutions",
    sections: [
      %{
        title: "For Small Business",
        description: "Perfect for startups",
        items: [
          %{id: "starter", label: "Starter Package", navigate: "/solutions/starter"},
          %{id: "growth", label: "Growth Package", navigate: "/solutions/growth"}
        ]
      },
      %{
        title: "For Enterprise",
        description: "Scalable solutions",
        items: [
          %{id: "enterprise", label: "Enterprise Suite", navigate: "/solutions/enterprise"},
          %{id: "custom", label: "Custom Solutions", navigate: "/solutions/custom"}
        ]
      }
    ]
  }
}
```

## Permissions-Based Navigation

NavBuddy supports permissions-based filtering to control which navigation items are visible to users. Add a `permissions` key to any navigation item to require specific permissions.

### Basic Permissions

```elixir
navigation_items = [
  %{id: "home", label: "Home", navigate: "/"},
  %{id: "dashboard", label: "Dashboard", navigate: "/dashboard", permissions: "user"},
  %{id: "admin", label: "Admin Panel", navigate: "/admin", permissions: "admin"}
]
```

### Multiple Required Permissions

Use a list to require multiple permissions (user must have ALL permissions):

```elixir
navigation_items = [
  %{
    id: "sensitive",
    label: "Sensitive Data",
    navigate: "/sensitive",
    permissions: ["admin", "data_access"]  # Requires BOTH permissions
  }
]
```

### Nested Structure Permissions

Permissions work with dropdowns and mega-menus:

```elixir
navigation_items = [
  %{
    id: "reports",
    label: "Reports",
    dropdown: [
      %{id: "basic_reports", label: "Basic Reports", navigate: "/reports/basic"},
      %{id: "admin_reports", label: "Admin Reports", navigate: "/reports/admin", permissions: "admin"},
      %{id: "analytics", label: "Analytics", navigate: "/reports/analytics", permissions: ["analyst", "premium"]}
    ]
  }
]
```

### Using in LiveView

Pass user permissions to the component:

```elixir
# In your LiveView mount/3 or assign
def mount(_params, session, socket) do
  current_user = get_current_user(session)
  user_permissions = get_user_permissions(current_user)

  socket = assign(socket, user_permissions: user_permissions)
  {:ok, socket}
end

# In your template
<NavBuddy.Component.nav_menu
  items={@navigation_items}
  user_permissions={@user_permissions}
  config={@nav_config}
  current_path={@current_path} />
```

### Permission Examples

```elixir
# String permission - user needs "admin" permission
%{id: "admin", label: "Admin", navigate: "/admin", permissions: "admin"}

# List of permissions - user needs ALL listed permissions
%{id: "sensitive", label: "Sensitive", navigate: "/sensitive", permissions: ["admin", "security"]}

# No permissions - visible to everyone
%{id: "home", label: "Home", navigate: "/"}

# nil permissions - same as no permissions key
%{id: "public", label: "Public", navigate: "/public", permissions: nil}
```

The filtering automatically:

- Shows items with no `permissions` key to everyone
- Shows items with `permissions: nil` to everyone
- Requires exact string match for string permissions
- Requires ALL permissions in list for list permissions
- Recursively filters dropdown and mega-menu items
- Removes parent items if all children are filtered out

## Configuration

Create a configuration struct:

```elixir
config = %NavBuddy.Config{
  orientation: :horizontal,        # :horizontal | :vertical
  theme: :auto,                   # :light | :dark | :auto
  dropdown_trigger: :hover,       # :hover | :click
  mobile_behavior: :drawer,       # :drawer | :collapse | :overlay
  animations: true,               # boolean
  accessibility: true,            # boolean
  mobile_breakpoint: 768,         # pixels
  max_dropdown_depth: 5,          # levels
  auto_close_delay: 300,          # milliseconds
  touch_gestures: true,           # boolean
  analytics: false                # boolean
}
```

Use with your navigation:

```elixir
<.nav_menu items={@navigation_items} config={config} current_path={@current_path} />
```

## LiveView Integration

NavBuddy includes comprehensive LiveView helpers:

```elixir
defmodule MyAppWeb.PageLive do
  use MyAppWeb, :live_view
  use NavBuddy.LiveHelpers  # Adds event handlers

  def mount(_params, _session, socket) do
    socket =
      socket
      |> assign_navbuddy_state()
      |> assign(:navigation_items, navigation_items())

    {:ok, socket}
  end

  # Event handlers are automatically available:
  # handle_event("navbuddy:item_click", ...)
  # handle_event("navbuddy:dropdown_toggle", ...)
  # handle_event("navbuddy:mobile_toggle", ...)
end
```

## Mobile Optimization

### Drawer Mode (Default)

Slide-out navigation drawer on mobile:

```elixir
%NavBuddy.Config{mobile_behavior: :drawer}
```

### Collapse Mode

Collapsible menu sections:

```elixir
%NavBuddy.Config{mobile_behavior: :collapse}
```

### Overlay Mode

Full-screen navigation overlay:

```elixir
%NavBuddy.Config{mobile_behavior: :overlay}
```

## Theming

### Automatic Theme Detection

```elixir
%NavBuddy.Config{theme: :auto}  # Follows system preference
```

### Manual Theme Selection

```elixir
%NavBuddy.Config{theme: :light}  # or :dark
```

### Custom Themes

Override CSS custom properties:

```css
:root {
  --navbuddy-bg-primary: #your-color;
  --navbuddy-text-primary: #your-color;
  --navbuddy-accent-primary: #your-color;
}
```

## Accessibility Features

NavBuddy is built with accessibility in mind:

- **ARIA Support**: Proper ARIA labels, roles, and states
- **Keyboard Navigation**: Full keyboard support with arrow keys
- **Screen Readers**: Compatible with screen reader software
- **Focus Management**: Intelligent focus handling
- **High Contrast**: Support for high contrast themes
- **Reduced Motion**: Respects `prefers-reduced-motion`

### Keyboard Navigation

- **Arrow Keys**: Navigate between menu items
- **Enter/Space**: Activate menu items
- **Escape**: Close menus and return focus
- **Home/End**: Jump to first/last items
- **Tab**: Standard tab navigation

## Breadcrumbs

Automatic breadcrumb generation:

```elixir
<.nav_breadcrumbs
  items={@navigation_items}
  current_path={@current_path}
/>
```

## Advanced Features

### Smart Positioning

Automatically adjusts dropdown and mega menu positions to stay within viewport:

```elixir
%NavBuddy.Config{smart_positioning: true}
```

### Touch Gestures

Mobile-optimized touch interactions:

```elixir
%NavBuddy.Config{touch_gestures: true}
```

### Analytics Integration

Built-in event tracking:

```elixir
%NavBuddy.Config{analytics: true}

# Events emitted:
# navbuddy:item_click
# navbuddy:dropdown_open
# navbuddy:dropdown_close
# navbuddy:mobile_toggle
```

### Animation Control

Control animations:

```elixir
%NavBuddy.Config{animations: true, auto_close_delay: 300}
```

## CSS Classes

NavBuddy provides semantic CSS classes for customization:

- `.navbuddy-nav` - Main navigation container
- `.navbuddy-nav-item` - Navigation item wrapper
- `.navbuddy-nav-link` - Navigation links
- `.navbuddy-dropdown` - Dropdown menus
- `.navbuddy-mega-menu` - Mega menus
- `.navbuddy-mobile-toggle` - Mobile menu toggle
- `.navbuddy-breadcrumbs` - Breadcrumb navigation

## JavaScript API

Access the JavaScript API directly:

```javascript
// Initialize manually
const nav = new NavBuddy(document.querySelector(".navbuddy-nav"), {
  smartPositioning: true,
  keyboardNavigation: true,
  analytics: true,
});

// Methods
nav.openDropdown("products");
nav.closeMegaMenu("solutions");
nav.toggleMobileNav();
nav.closeAllMenus();

// Events
nav.trackEvent("custom_event", { custom: "data" });

// State
const state = nav.getState();
```

## Browser Support

- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+

## Examples

Check out the included example navigation structure:

```elixir
NavBuddy.example_navigation()
```

This returns a comprehensive navigation structure showcasing all features:

- Simple links with icons
- Single and multi-level dropdowns
- Mega menus with grid layouts
- Mixed navigation types

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## Changelog

### v0.1.0 (2025-01-25)

- Initial release
- Advanced dropdown and mega menu support
- Mobile-responsive design
- Full accessibility implementation
- Comprehensive theming system
- LiveView integration
- Touch gesture support
- Analytics integration

## License

MIT License - see [LICENSE](LICENSE) for details.

## Acknowledgments

- Phoenix LiveView team for the excellent framework
- Tailwind CSS for design inspiration
- Accessibility guidelines from WCAG 2.1

---

**Made with ❤️ for the Phoenix community**