# HPVM-Menu Developer Documentation

## Overview

**HPVM-Menu** (Hyper Parametrizable Vanilla Menu) is a lightweight, flexible off-canvas menu library built with pure JavaScript. It provides a complete solution for web application navigation with support for nested menus, search functionality, themes, and extensive customization options.

- **Version**: 1.0.2
- **License**: CC-BY-NC-4.0
- **Size**: ~16Kb (minified)
- **Dependencies**: FontAwesome 6.x (optional, for icons)

## Table of Contents

- [Quick Start](#quick-start)
- [Architecture](#architecture)
- [Core Components](#core-components)
  - [Iconbar](#iconbar)
  - [Sidebar](#sidebar)
  - [Overlay](#overlay)
  - [Mixin](#mixin)
  - [Search](#search)
- [Configuration](#configuration)
- [API Reference](#api-reference)
- [Advanced Usage](#advanced-usage)
- [Styling & Themes](#styling--themes)
- [Examples](#examples)
- [Migration Guide](#migration-guide)

## Quick Start

### Installation

```bash
npm install hpvm-menu
```

### CDN

```html
<!-- CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.1.2/css/all.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hpvm-menu@1.0.2/dist/css/all.css">

<!-- JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/hpvm-menu@1.0.2/dist/js/all.min.js"></script>
```

### Basic HTML Structure

```html
<div class="icon-bar container">
  <div class="icon-bar-top"></div>
  <div class="icon-bar-bottom"></div>
</div>

<div id="overlay">
  <i class="fa-solid fa-sync fa-spin fa-5x is-loaded"></i>
</div>

<div class="sidebar">
  <div class="sidebar-widelogo">
    <img src="logo.png" alt="Logo" />
  </div>
  <div id="sidebarTitle" class="sidebar-title">Menu</div>
  <div class="search">
    <input class="searchInput" placeholder="Search..." onkeyup="HpvMenu.sidebar.filterFn(this, 'menuItems')" />
    <button class="btn"><i class="fas fa-search"></i></button>
  </div>
  <ul id="menuItems" class="nav"></ul>
  <div id="sideBarStatusText">
    <p>No items available</p>
  </div>
</div>

<div id="content" class="content">
  Your content here
</div>
```

### Basic JavaScript Setup

```javascript
document.addEventListener('DOMContentLoaded', function() {
  // Register iconbar entry
  HpvMenu.iconbar.registerEntry({
    'parentCls': 'icon-bar-top',
    'innerHtml': '<i class="fa fa-home"></i>',
    'tooltiptext': 'Home',
    'onClick': function(event) {
      HpvMenu.mixin.handleIconBarClick(event, 'home');
    }
  });

  // Register sidebar entry
  HpvMenu.sidebar.registerEntry({
    'id': 'home',
    'title': 'Home Menu',
    'overlay': true,
    'sortItens': true,
    'search': {
      'enabled': true,
      'mode': 'fuzzy',
      'fields': ['title']
    },
    'itens': [
      { 'type': 'entry', 'title': 'Dashboard' },
      { 'type': 'entry', 'title': 'Profile' }
    ],
    'onItemClick': function(event, entry, item) {
      console.log('Clicked:', item.title);
    }
  });
});
```

## Architecture

HPVM-Menu follows a modular architecture where each component can be used independently or combined using the Mixin utility.

```
HpvMenu
├── iconbar      # Vertical navigation bar
├── sidebar      # Sliding menu panel
├── overlay      # Semi-transparent overlay
├── mixin        # Component coordination
└── search       # Search functionality
```

## Core Components

### Iconbar

The iconbar provides a vertical navigation bar with icons, tooltips, and click handlers.

#### Methods

##### `HpvMenu.iconbar.registerEntry(entry)`

Registers a new iconbar entry.

**Parameters:**
- `entry.parentCls` (string): CSS class of parent container (`icon-bar-top` or `icon-bar-bottom`)
- `entry.innerHtml` (string): HTML content for the icon
- `entry.tooltiptext` (string, optional): Tooltip text
- `entry.classes` (array, optional): Additional CSS classes
- `entry.onClick` (function, optional): Click event handler

**Example:**
```javascript
HpvMenu.iconbar.registerEntry({
  'parentCls': 'icon-bar-top',
  'innerHtml': '<i class="fa fa-dashboard"></i>',
  'tooltiptext': 'Dashboard',
  'classes': ['custom-class'],
  'onClick': function(event) {
    HpvMenu.mixin.handleIconBarClick(event, 'dashboard');
  }
});
```

##### `HpvMenu.iconbar.setActive(element)`

Sets an iconbar entry as active.

##### `HpvMenu.iconbar.removeLastActive()`

Removes active state from all iconbar entries.

### Sidebar

The sidebar is the main menu component that slides in from the left side.

#### Entry Configuration

Each sidebar entry is configured with the following options:

```javascript
{
  'id': 'unique-identifier',           // Required: Unique identifier
  'title': 'Menu Title',               // Required: Display title
  'overlay': true,                     // Show overlay when open
  'sortItens': true,                   // Sort items alphabetically
  'search': {                          // Search configuration
    'enabled': true,
    'mode': 'fuzzy',                  // 'fuzzy', 'normal', or false
    'fields': ['title', 'tags']       // Fields to search in
  },
  'itens': [...],                      // Menu items array
  'loadItens': function() {...},       // Dynamic item loader
  'itemRenderer': function() {...},    // Custom item renderer
  'onItemClick': function() {...}      // Item click handler
}
```

#### Item Types

##### Entry Items

Basic menu items:

```javascript
{
  'type': 'entry',                    // Required
  'title': 'Item Title',              // Required
  'innerHtml': '<i class="fa fa-icon"></i>', // Icon HTML
  'href': 'https://example.com',      // Link URL
  'tags': ['tag1', 'tag2'],          // Search tags
  'order': 1,                         // Sort order (lower = first)
  // ... custom properties
}
```

##### Divide Items

Section dividers with child items:

```javascript
{
  'type': 'divide',
  'title': 'Section Name',
  'childs': [
    { 'type': 'entry', 'title': 'Child Item 1' },
    { 'type': 'entry', 'title': 'Child Item 2' }
  ]
}
```

##### Dropdown Items

Collapsible menu sections:

```javascript
{
  'type': 'dropdown',
  'title': 'Dropdown Menu',
  'childs': [
    { 'type': 'entry', 'title': 'Sub Item 1' },
    { 'type': 'entry', 'title': 'Sub Item 2' }
  ]
}
```

#### Methods

##### `HpvMenu.sidebar.registerEntry(entry)`

Registers a new sidebar entry.

##### `HpvMenu.sidebar.show(id)`

Displays the sidebar with the specified entry.

##### `HpvMenu.sidebar.close()`

Closes the sidebar.

##### `HpvMenu.sidebar.filterFn(element, targetId)`

Filters sidebar items based on search input.

### Overlay

The overlay provides a semi-transparent background when the sidebar is open.

#### Methods

##### `HpvMenu.overlay.show(usingIconBar, usingSidebar)`

Shows the overlay, adjusting position based on visible components.

##### `HpvMenu.overlay.hide()`

Hides the overlay.

##### `HpvMenu.overlay.showLoading(usingIconBar, usingSidebar)`

Shows overlay with loading spinner.

##### `HpvMenu.overlay.hideLoading()`

Hides overlay and loading spinner.

### Mixin

The mixin component provides helper functions to coordinate between components.

#### Methods

##### `HpvMenu.mixin.handleIconBarClick(event, sidebarId)`

Handles iconbar clicks - sets active state, opens sidebar, and shows overlay.

##### `HpvMenu.mixin.closeSideBar()`

Closes sidebar, hides overlay, and removes active states.

##### `HpvMenu.mixin.setIconBarActive(element)`

Sets iconbar entry as active, closing sidebar if already open.

### Search

HPVM-Menu supports both basic text search and fuzzy search using Fuse.js.

#### Search Modes

- **Normal**: Basic text matching in title and tags
- **Fuzzy**: Advanced search with Fuse.js (requires separate inclusion)
- **Disabled**: No search functionality

#### Implementation

```javascript
// Basic search
onkeyup="HpvMenu.sidebar.filterFn(this, 'menuItems')"

// Fuzzy search (requires Fuse.js)
HpvMenu.sidebar.filterFn = HpvMenu.sidebar.filterFnFuzzy;
```

## Configuration

### Global Configuration

```javascript
// Custom sort function
entry.sortFn = function(entry, items) {
  return items.sort((a, b) => a.customOrder - b.customOrder);
};

// Custom item renderer
entry.itemRenderer = function(target, entry, item, path) {
  let li = document.createElement('li');
  // Custom rendering logic
  return li;
};
```

### Dynamic Item Loading

```javascript
HpvMenu.sidebar.registerEntry({
  'id': 'dynamic-menu',
  'title': 'Dynamic Menu',
  'loadItens': function() {
    // Load items from API, localStorage, etc.
    return fetch('/api/menu-items')
      .then(response => response.json())
      .then(data => data.items);
  }
});
```

## API Reference

### HpvMenu.iconbar

| Method | Parameters | Description |
|--------|------------|-------------|
| `registerEntry` | `entry` | Register new iconbar entry |
| `setActive` | `element` | Set entry as active |
| `removeLastActive` | - | Remove all active states |

### HpvMenu.sidebar

| Method | Parameters | Description |
|--------|------------|-------------|
| `registerEntry` | `entry` | Register new sidebar entry |
| `show` | `id` | Display sidebar entry |
| `close` | - | Close sidebar |
| `filterFn` | `element`, `targetId` | Filter items |
| `handleStarClick` | `event`, `entry`, `item` | Handle favorite toggle |

### HpvMenu.overlay

| Method | Parameters | Description |
|--------|------------|-------------|
| `show` | `usingIconBar`, `usingSidebar` | Show overlay |
| `hide` | - | Hide overlay |
| `showLoading` | `usingIconBar`, `usingSidebar` | Show with loading |
| `hideLoading` | - | Hide loading overlay |

### HpvMenu.mixin

| Method | Parameters | Description |
|--------|------------|-------------|
| `handleIconBarClick` | `event`, `sidebarId` | Handle iconbar click |
| `closeSideBar` | - | Close all components |
| `setIconBarActive` | `element` | Set active state |

## Advanced Usage

### Custom Item Renderer

```javascript
'itemRenderer': function(target, entry, item, path) {
  let li = document.createElement('li');
  let anchor = document.createElement('a');

  // Custom structure
  anchor.innerHTML = `
    <div class="custom-item">
      <span class="title">${item.title}</span>
      <span class="subtitle">${item.subtitle || ''}</span>
    </div>
  `;

  li.appendChild(anchor);

  // Add click handler
  anchor.addEventListener('click', function(event) {
    entry.onItemClick(event, entry, item);
  });

  target.appendChild(li);
  return li;
}
```

### Working with Favorites

```javascript
// Access favorites
let favorites = HpvMenu.sidebar.fav;

// Add item to favorites programmatically
HpvMenu.sidebar.fav.push({
  'title': 'My Item',
  'savedPath': ['Menu', 'Submenu']
});
localStorage.setItem('favoritos', JSON.stringify(HpvMenu.sidebar.fav));

// Remove from favorites
let index = HpvMenu.sidebar.fav.findIndex(fav => fav.title === 'My Item');
if (index > -1) {
  HpvMenu.sidebar.fav.splice(index, 1);
  localStorage.setItem('favoritos', JSON.stringify(HpvMenu.sidebar.fav));
}
```

### Custom Search Implementation

```javascript
// Custom search function
HpvMenu.sidebar.filterFn = function(el, id) {
  let searchTerm = el.value.toLowerCase();
  let items = document.getElementById(id).getElementsByTagName('li');

  for (let item of items) {
    let text = item.textContent.toLowerCase();
    item.style.display = text.includes(searchTerm) ? '' : 'none';
  }
};
```

### Event Handling

```javascript
// Item click with custom logic
'onItemClick': function(event, entry, item) {
  event.preventDefault();

  // Custom navigation logic
  if (item.href) {
    window.location.href = item.href;
  } else {
    // Handle custom action
    handleCustomAction(item);
  }

  // Close sidebar after action
  HpvMenu.mixin.closeSideBar();
}
```

## Styling & Themes

### Default Theme

The library includes a default light theme with the following key styles:

```css
/* Sidebar */
.sidebar {
  background: #e0e0e0;
  width: 270px;
}

/* Iconbar */
.icon-bar {
  background-color: #555;
  width: 50px;
}

/* Active states */
.icon-bar .active {
  background: #e0e0e0;
  color: #3b3b3b;
}
```

### Dark Theme

To use the dark theme, include the theme CSS after the main CSS:

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hpvm-menu@1.0.2/dist/css/themes/dark-grey.css">
```

### Custom Styling

```css
/* Custom iconbar styling */
.icon-bar {
  background: linear-gradient(180deg, #667eea 0%, #764ba2 100%);
}

.icon-bar a:hover {
  background-color: rgba(255, 255, 255, 0.1);
}

/* Custom sidebar styling */
.sidebar {
  background: #2c3e50;
  color: #ecf0f1;
}

.sidebar .nav li a {
  color: #ecf0f1;
  border-bottom: 1px solid #34495e;
}

.sidebar .nav li a:hover {
  background: #34495e;
}
```

### Responsive Design

The library includes responsive breakpoints:

```css
/* Mobile adjustments */
@media screen and (max-height: 590px) {
  .icon-bar a {
    padding: 10px;
  }
}

/* Tablet adjustments */
@media screen and (min-height: 590px) and (max-height: 750px) {
  .icon-bar a {
    padding: 12px;
  }
}
```

## Examples

### Basic Menu

See `examples/all-in-one/index.html` for a complete implementation with multiple menu types.

### Iconbar-Only Navigation

```javascript
// Simple iconbar navigation
HpvMenu.iconbar.registerEntry({
  'parentCls': 'icon-bar-top',
  'innerHtml': '<i class="fa fa-home"></i>',
  'tooltiptext': 'Home',
  'onClick': () => window.location.href = '/home'
});
```

### Search-Only Interface

```javascript
// Sidebar with search only
HpvMenu.sidebar.registerEntry({
  'id': 'search-menu',
  'title': 'Search Results',
  'search': {
    'enabled': true,
    'mode': 'fuzzy',
    'fields': ['title', 'description', 'tags']
  },
  'itens': [], // Initially empty
  'loadItens': () => loadSearchData()
});
```

### Nested Menu Structure

```javascript
{
  'id': 'nested-menu',
  'title': 'Nested Menu',
  'itens': [
    {
      'type': 'divide',
      'title': 'User Management',
      'childs': [
        { 'type': 'entry', 'title': 'Users' },
        { 'type': 'entry', 'title': 'Roles' },
        {
          'type': 'dropdown',
          'title': 'Permissions',
          'childs': [
            { 'type': 'entry', 'title': 'Read' },
            { 'type': 'entry', 'title': 'Write' },
            { 'type': 'entry', 'title': 'Admin' }
          ]
        }
      ]
    }
  ]
}
```

## Migration Guide

### From v1.0.0 to v1.0.2

- Added fuzzy search support
- Improved item renderer API
- Enhanced theme support
- Better mobile responsiveness

### Breaking Changes

- `search` property now accepts an object instead of boolean
- `itemRenderer` function signature changed
- `loadItens` now supports async functions

### Migration Example

```javascript
// Old v1.0.0
{
  'search': true,
  'itemRenderer': function(item) { /* old signature */ }
}

// New v1.0.2
{
  'search': {
    'enabled': true,
    'mode': 'fuzzy',
    'fields': ['title']
  },
  'itemRenderer': function(target, entry, item, path) { /* new signature */ }
}
```

## Browser Support

- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+

## Performance Considerations

- The library is optimized for menus with up to 200 items
- Fuzzy search requires additional Fuse.js library (~9Kb)
- Use `loadItens` for large dynamic datasets
- Minimize DOM manipulations in custom renderers

## Troubleshooting

### Common Issues

1. **Sidebar not opening**
   - Check that HTML structure matches documentation
   - Ensure `id` matches between `registerEntry` and `handleIconBarClick`

2. **Search not working**
   - Verify search input has correct `onkeyup` handler
   - Check that `filterFn` is properly assigned

3. **Styling issues**
   - Include CSS files in correct order
   - Check for CSS conflicts with existing styles

### Debug Mode

Enable debug logging:

```javascript
HpvMenu.debug = true;
```

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. Submit a pull request

## License

This project is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License.

## Support

- **Issues**: [GitHub Issues](https://github.com/drecchia/hpvm-menu/issues)
- **Discussions**: [GitHub Discussions](https://github.com/drecchia/hpvm-menu/discussions)
- **Email**: Support inquiries welcome

---

**Author**: Danilo T Recchia
**Repository**: [https://github.com/drecchia/hpvm-menu](https://github.com/drecchia/hpvm-menu)