Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
13b00bc
Remove PHPDocs from constructor
emmadesilva Mar 26, 2024
f847691
Remove outdated class documentation
emmadesilva Mar 26, 2024
4a36e29
Sort property constructors
emmadesilva Mar 26, 2024
3bcafeb
Extract helper method
emmadesilva Mar 26, 2024
1b35793
Update constructor to use the same logic as the static create method
emmadesilva Mar 26, 2024
b3c87c2
Update and normalize class documentation and constructors
emmadesilva Mar 26, 2024
78ff7d2
Annotate array return generics
emmadesilva Mar 26, 2024
26cd0bf
Use fully qualified class name in type annotation
emmadesilva Mar 26, 2024
15b8b65
Test construct with null label
emmadesilva Mar 26, 2024
377a2ba
Create new documentation for simplified API
emmadesilva Mar 26, 2024
2c11b05
Swap order of examples
emmadesilva Mar 26, 2024
26baea1
Revert "Swap order of examples"
emmadesilva Mar 26, 2024
39ea38d
Clean up examples
emmadesilva Mar 26, 2024
4df7c70
Fix typo in code comment
emmadesilva Mar 26, 2024
0c29b9a
Document using external URLs
emmadesilva Mar 26, 2024
aea7e3a
Document examples more
emmadesilva Mar 26, 2024
80b2b97
Test item sorting
emmadesilva Mar 26, 2024
b542d4b
Style array key order
emmadesilva Mar 26, 2024
790c975
Clean up examples
emmadesilva Mar 26, 2024
894425b
Style examples
emmadesilva Mar 26, 2024
57e6608
Format Markdown
emmadesilva Mar 26, 2024
49f5b1f
Normalize Markdown
emmadesilva Mar 26, 2024
36eba07
Add quick references
emmadesilva Mar 26, 2024
a5b3e86
Add example context
emmadesilva Mar 26, 2024
7204ba9
Format method documentation
emmadesilva Mar 26, 2024
c9824a9
Add method documentation
emmadesilva Mar 27, 2024
cbd5849
Add commented Copilot idea
emmadesilva Mar 27, 2024
44cb271
Formatting
emmadesilva Mar 27, 2024
0191d44
Document alternate syntax
emmadesilva Mar 27, 2024
7149976
Document import
emmadesilva Mar 27, 2024
892b890
Document setup
emmadesilva Mar 27, 2024
3948eb8
Add initial menu documentation
emmadesilva Mar 27, 2024
a822c42
Revert "Document setup"
emmadesilva Mar 27, 2024
13cb289
Clean up documentation
emmadesilva Mar 27, 2024
8a5ceb3
Remove redundant example
emmadesilva Mar 27, 2024
f46b2de
Split out examples
emmadesilva Mar 27, 2024
619d7ee
Merge lines
emmadesilva Mar 27, 2024
d696a1b
Clean up heading levels
emmadesilva Mar 27, 2024
6021f7b
Fix typo
emmadesilva Mar 27, 2024
83b1fbc
Format class names
emmadesilva Mar 27, 2024
7d61603
Begin new section
emmadesilva Mar 27, 2024
41fb7cc
Change internal group items to be collection
emmadesilva Mar 27, 2024
bfa64bf
Return the items as the collection
emmadesilva Mar 27, 2024
8b2daf0
Support nesting navigation groups
emmadesilva Mar 28, 2024
62d6930
Sort grouped navigation items on retrieval
emmadesilva Mar 28, 2024
fa70254
Create HasNavigationItems.php
emmadesilva Mar 28, 2024
6b7cc4a
Use HasNavigationItems
emmadesilva Mar 28, 2024
e91503b
Document trait abstract
emmadesilva Mar 28, 2024
bccde3d
Move shared logic to trait
emmadesilva Mar 28, 2024
f80795f
Merge pull request #1630 from hydephp/restructure-navigation-item-oop…
emmadesilva Mar 28, 2024
dbc2379
Revert "Use HasNavigationItems"
emmadesilva Mar 28, 2024
cfe9784
Merge trait back into menu class
emmadesilva Mar 28, 2024
841d1bf
Revert "Create HasNavigationItems.php"
emmadesilva Mar 28, 2024
b412f34
Update navigation group to extend menu class
emmadesilva Mar 28, 2024
8461e60
Move up parent constructor call
emmadesilva Mar 28, 2024
cc803ba
Remove unused import
StyleCIBot Mar 28, 2024
544769a
Merge pull request #1645 from hydephp/restructure-navigation-item-oop…
emmadesilva Mar 28, 2024
b1f5867
Document the navigation group class
emmadesilva Mar 29, 2024
6042642
Unwrap collect calls for already collected items
emmadesilva Mar 29, 2024
89c4890
Fix formatting
emmadesilva Mar 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
264 changes: 211 additions & 53 deletions docs/advanced-features/navigation-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ navigation:

>warning This article covers advanced information that is only relevant if you want to create custom navigation menus. Instead, you may want to read the [Navigation](navigation) article for a general overview.


## Abstract

This article describes the Navigation API introduced in HydePHP v2. Both the main navigation menu and the documentation sidebar bundled with HydePHP are built with this API.
Expand All @@ -16,6 +17,7 @@ This article is intended for advanced users, as most users will not need to crea
For this reason, the documentation is very code-driven due to the technical nature of the API.
We'll also be mixing in some practical examples of Blade and PHP code to illustrate how you can use the API in your own projects.


## Overview

The Navigation API consists of a set of classes within the `Hyde\Framework\Features\Navigation` namespace.
Expand Down Expand Up @@ -70,7 +72,8 @@ $menu = MainNavigationMenu::get();
$sidebar = DocumentationSidebar::get();
```

>info Developer tip: The menus are only generated *after* the Hyde Kernel is booted. If you are getting BindingResolutionExceptions, ensure that you are not trying to access the menus too early in the application lifecycle. (Consider using the `booted` event.)
>info Developer tip: The menus are only generated *after* the Hyde Kernel is booted. If you are getting BindingResolutionExceptions, ensure that you are not trying to access the menus too early in the application lifecycle. (Consider using the `booted` event.)


## Creating Custom Menus

Expand Down Expand Up @@ -141,135 +144,290 @@ The object-oriented nature of the API also makes this perfect for package develo

Here are some general tips to keep in mind when working with the Navigation API:
- You can use the `add` method to add single items or arrays of items. You can also pass an array of items directly to the menu constructor.
- The navigation menu items is stored in a Laravel Collection, and is type safe to support both `NavigationItem` and `NavigationGroup` instances.
- The navigation menu items is stored in a Laravel Collection, and is type safe to support both `NavigationItem` and `NavigationGroup` instances.
- You can also construct NavigationItem instances directly, but the `create` method is a convenient shorthand, and can fill in data from routes, if you use them.
- It's also possible to set an item's priority as the third parameter, but here we don't need it, as they default to the order they are added.


## Class Reference

Below is a reference of the classes and methods available in the Navigation API.


## NavigationMenu

The `NavigationMenu` class represents a navigation menu. It contains a collection of items, which can be either `NavigationItem` or `NavigationGroup` instances.

## NavigationItem

The `NavigationItem` class represents a single item in a navigation menu. It contains information such as the destination link or route, a label, and priority for ordering in the menu.
### Quick Reference

Here is the constructor signature and a quick reference of the methods available on the `NavigationItem` class, and their types. Keep on reading to see more detailed examples and explanations.
Here is a quick reference of the methods available on the NavigationMenu class:

```php
use Hyde\Framework\Features\Navigation\NavigationItem;
use Hyde\Framework\Features\Navigation\NavigationMenu;

$item = new NavigationItem(Route|string $destination, string $label, int $priority = 500);
// Create a new NavigationMenu instance, optionally providing an array of items.
$menu = new NavigationMenu($items = []);

$item->getLink(): string; // Returns the resolved link route or destination URL.
$item->getLabel(): string; // Returns the label of the item.
$item->isActive(): bool; // Returns true if the item is the page being rendered.
$item->getPriority(): int; // Returns the priority of the item.
$item->getPage(): ?HydePage; // Returns the underlying Page instance, if there is one.
// Add a single item or an array of items to the menu.
$menu->add(new NavigationItem());
$menu->add([new NavigationItem()]);

// Get all items in the menu as a sorted Collection.
$menu->getItems(): Collection<NavigationItem|NavigationGroup>
```

### Creating Navigation Items
### Creating Navigation Menus

There are several ways to create navigation items using the `NavigationItem` class.
You can create a new NavigationMenu instance by simply calling the constructor, optionally providing an array of items.

#### Direct instantiation
```php
use Hyde\Framework\Features\Navigation\NavigationMenu;

You can create instances directly by passing either a URL or a Route instance to the constructor.
$menu = new NavigationMenu($items = []);
```

The first parameter is the destination, the second is the label, and the third optional parameter is the priority.
Here is how to provide an array or Collection of `NavigationItem` and/or `NavigationGroup` instances directly to the constructor.

```php
$item = new NavigationItem('index', 'Home');
$item = new NavigationItem(Routes::get('index'), 'Home');
$item = new NavigationItem('https://example.com', 'External Link');
use Hyde\Framework\Features\Navigation\NavigationMenu;
use Hyde\Framework\Features\Navigation\NavigationItem;
use Hyde\Framework\Features\Navigation\NavigationGroup;

$menu = new NavigationMenu([
new NavigationItem('index.html', 'Home'),
new NavigationItem('posts.html', 'Blog'),
new NavigationGroup('About', [
new NavigationItem('about.html', 'About Us'),
new NavigationItem('team.html', 'Our Team'),
]),
]);
```

### Adding Items to the Menu

You can also add items to the menu after it has been created by using the `add` method which can take a single item or an array of items, and can be fluently chained.

```php
$menu = (new NavigationMenu())
->add(new NavigationItem('contact.html', 'Contact Us'))
->add([
new NavigationItem('privacy.html', 'Privacy Policy'),
new NavigationItem('terms.html', 'Terms of Service'),
]);
```

#### Setting Priority
### Accessing Items in the Menu

You can set the priority of the item, which determines its position in the menu.
You can access all items in the menu by calling the `getItems` method, which will return a `Collection` of all items in the menu.

```php
$item = new NavigationItem(Routes::get('index'), 'Home', 25);
$items = $menu->getItems();
```

#### Static Creation Method
The items will automatically be sorted by their priority, with lower numbers coming first, defaulting to the order they were added if no priority is set.

You can use the static `create` method, which can automatically fill in the label and priority from a Route.
## NavigationItem

The `NavigationItem` class is an abstraction for a navigation menu item containing useful information like the destination, label, and priority.

### Quick Reference

Here is a quick reference of the methods available on the `NavigationItem` class:

```php
$item = NavigationItem::create(Routes::get('index'));
use Hyde\Framework\Features\Navigation\NavigationItem;

// Create a new NavigationItem instance.
$item = NavigationItem::create($destination, $label, $priority): NavigationItem;
$item = new NavigationItem($destination, $label, $priority); // Same as above.

// Get the link of the item.
$item->getLink(): string;

// Get the label of the item.
$item->getLabel(): string;

// Get the priority of the item.
$item->getPriority(): int;

// Check if the item is active. (Only works when the destination is a route)
$item->isActive(): bool;
```

### Blade Example

Here is an example of how you can put it all together in a Blade template:

```blade
<a href="{{ $item->getLink() }}" @class(['active' => $item->isActive()])>
{{ $item->getLabel() }}
</a>
```

You can also pass a custom label and priority to the `create` method to override the defaults.
This will output an anchor tag with the correct link and label, and if the item is active, it will add an `active` class to the tag.

### Creating Navigation Items

There are two syntaxes for creating `NavigationItem` instances, you can use a standard constructor or the static create method.
Both options provide the exact same signature and functionality, so it's just a matter of preference which one you use.

The constructors take three parameters: the destination, the label, and the optional priority.
The destination can be a `Route` instance, a route key string, or an external URL.

```php
$item = NavigationItem::create(Routes::get('index'), 'Custom Label', 50);
use Hyde\Framework\Features\Navigation\NavigationItem;

$item = new NavigationItem($destination, $label, $priority);
$item = NavigationItem::create($destination, $label, $priority);
```

#### Using Route Keys and URLs
#### Using Routes

The `create` method works with route keys and URLs.
Using the HydePHP routing system is the recommended way to create navigation items leading to pages within your project,
as they will automatically have links resolved to the correct URL, and Hyde can check if the items are active.
Additionally, Hyde will use the page data as the label and priority defaults unless you override them.

You can create routed navigation items by providing either a `Route` instance or a route key string as the destination.

```php
$item = NavigationItem::create('index');
$item = NavigationItem::create('https://example.com');
// Using a route key string.
new NavigationItem('index');

// Using the Routes facade to get a Route instance.
new NavigationItem(Routes::get('index'));

// Setting the label and/or priorities will override inferred data.
new NavigationItem(Routes::get('index'), 'Custom Label', 25);
```

Unless you pass a custom label to URL items, the label will be the URL itself.
Using a route key is more concise, but will not provide type safety as it will be treated as a link if the route does not exist,
whereas providing an invalid route key to the `Routes` facade will throw an exception. It's up to you which one you prefer.

#### Using External URLs

You can also create navigation items that link to external URLs by providing a full URL as the destination.

If you do not set a label for links, the label will default to the URL, and if you do not set a priority, it will default to `500`.

```php
$item = NavigationItem::create('https://example.com');
// This will lead directly to the link, and use it as the label with a priority of 500.
new NavigationItem('https://example.com');

// You can also set a custom label and priority to override the defaults.
new NavigationItem('https://example.com', 'External Link', 25);
```

### Navigation Item Methods
While it is discouraged to use external URLs for internal pages, as Hyde won't be able to resolve relative links or check active states,
they are excellent for any time you want an absolute link to an external site or resource.

### Getting Label and Link
Note that Hyde will not validate or modify the URL, so you are responsible for ensuring it's correct.

### Accessing the resolved links

The `getLink` method is designed to return a link that can be used in the `href` attribute of an anchor tag.

If the destination is a route, the link will be resolved to the correct URL, using relative paths if possible. It will also respect the pretty URL setting.

```php
$item = NavigationItem::create('index');
$item = new NavigationItem(Routes::get('index'));
$item->getLink(); // Outputs 'index.html'

// Get the label of the item.
$item->getLabel(); // Returns 'Home'
$item = new NavigationItem('https://example.com');
$item->getLink(); // Outputs 'https://example.com'
```

// Get the link of the item.
$item->getLink(); // Returns 'index.html'
**Tip:** The item instances automatically turns into the resolved link when cast to a string. Perfect for your Blade templates!

```blade
<a href="{{ $item }}">{{ $item->getLabel() }}</a>
```

You can also get the link by casting the item to a string.
### Accessing the label

The `getLabel` method returns the label of the item. This is the text that will be displayed in the navigation menu.

```php
(string) $item; // Returns 'index.html'
$item = new NavigationItem('index', 'Home');
$item->getLabel(); // Outputs 'Home'
```

### Getting Priority
### Accessing the priority

The `getPriority` method returns the priority of the item. This is a number that determines the order in which the items are displayed in the menu, where lower numbers come first.

```php
$item->getPriority(); // Returns 0
$item = new NavigationItem('index', 'Home', 25);
$item->getPriority(); // Outputs 25
```

### Getting Page Instance
### Checking if the item is active

You can get the underlying Page instance of the item, if it exists.
The `isActive` method checks if the item is active (by comparing it to the Hyde page being compiled at the moment). This is useful for highlighting the current page in the navigation menu.

```php
$item->getPage(); // Returns instance of BladePage or null
$item = new NavigationItem('index');
$item->isActive(); // Outputs true if the item is the current page, otherwise false.
```

### Checking Active State
<!--
Generated by Copilot, kinda cool, maybe something to implement?

### Advanced Usage

#### Customizing the Active State

You can check if the item is active (i.e., the current page being rendered).
By default, the `isActive` method will check if the item's destination matches the current page being compiled.

However, you can also provide a custom callback to the method to determine if the item is active.

```php
$item->isActive(); // Returns false
$item = new NavigationItem('index');
$item->isActive(fn($item) => $item->getLink() === 'index.html');
```

This concludes the documentation for the `NavigationItem` class.
This is useful if you want to check for a specific query parameter, or if you want to check if the item is active based on a more complex condition.
-->


## NavigationGroup

The `NavigationGroup` class represents a group of items in a navigation menu. It contains a label, priority, and a collection of navigation items.
This class is often used to create submenus or dropdowns in a navigation menu.

The `NavigationGroup` class extends the `NavigationMenu` class, and thus inherits the same base methods and functionality,
while also having shared methods with the `NavigationItem` class to render the groups in a Blade view.

### Quick Reference

Here is a quick reference of the methods available on the `NavigationGroup` class:

```php
use Hyde\Framework\Features\Navigation\NavigationGroup;

// Create a new NavigationGroup instance.
$group = new NavigationGroup($label, $items = [], $priority = 500);

// Add a single item or an array of items to the group.
$group->add(new NavigationItem());
$group->add([new NavigationItem()]);

// Get all items in the group as a Collection sorted by priority.
$group->getItems(): Collection<NavigationItem|NavigationGroup>

// Get the label of the group.
$group->getLabel(): string;

// Get the priority of the group.
$group->getPriority(): int;

// Get the group key, which is a normalized kebab-case version of the label.
$group->getGroupKey(): string;
```

As the `NavigationGroup` class extends the `NavigationMenu` class, please see the `NavigationMenu` section for detailed information of the methods available.

### Usage Scenarios

HydePHP uses the `NavigationGroup` class to create dropdowns in the main navigation menu and the category groups in the documentation sidebar.

In your own custom menus, you can use this class for the same types of functionality, and you can even nest groups within groups to create complex navigation structures.
Loading