Skip to content

Commit 4e4aa21

Browse files
authored
Merge pull request #1578 from hydephp/refactor-main-navigation-menu
[2.x] Refactor navigation menu generators
2 parents ea3d13d + f14c7dd commit 4e4aa21

File tree

4 files changed

+160
-174
lines changed

4 files changed

+160
-174
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hyde\Framework\Features\Navigation;
6+
7+
use Hyde\Hyde;
8+
use Hyde\Facades\Config;
9+
use Illuminate\Support\Str;
10+
use Hyde\Support\Models\Route;
11+
use Hyde\Pages\DocumentationPage;
12+
use Illuminate\Support\Collection;
13+
use Hyde\Foundation\Facades\Routes;
14+
use Hyde\Foundation\Kernel\RouteCollection;
15+
16+
use function filled;
17+
use function strtolower;
18+
19+
/**
20+
* @experimental This class may change significantly before its release.
21+
*/
22+
abstract class BaseMenuGenerator
23+
{
24+
/** @var \Illuminate\Support\Collection<string, \Hyde\Framework\Features\Navigation\NavItem> */
25+
protected Collection $items;
26+
27+
/** @var \Hyde\Foundation\Kernel\RouteCollection<string, \Hyde\Support\Models\Route> */
28+
protected RouteCollection $routes;
29+
30+
protected bool $generatesSidebar;
31+
protected bool $usesGroups;
32+
33+
protected function __construct()
34+
{
35+
$this->items = new Collection();
36+
37+
$this->generatesSidebar = $this instanceof GeneratesDocumentationSidebarMenu;
38+
39+
$this->routes = $this->generatesSidebar
40+
? Routes::getRoutes(DocumentationPage::class)
41+
: Routes::all();
42+
43+
$this->usesGroups = $this->usesGroups();
44+
}
45+
46+
public static function handle(): NavigationMenu
47+
{
48+
$menu = new static();
49+
50+
$menu->generate();
51+
52+
return new NavigationMenu($menu->items);
53+
}
54+
55+
protected function generate(): void
56+
{
57+
$this->routes->each(function (Route $route): void {
58+
if ($this->canAddRoute($route)) {
59+
if ($this->canGroupRoute($route)) {
60+
$this->addRouteToGroup($route);
61+
} else {
62+
$this->items->put($route->getRouteKey(), NavItem::fromRoute($route));
63+
}
64+
}
65+
});
66+
}
67+
68+
protected function usesGroups(): bool
69+
{
70+
if ($this->generatesSidebar) {
71+
// In order to know if we should use groups in the sidebar, we need to loop through the pages and see if they have a group set.
72+
// This automatically enables the sidebar grouping for all pages if at least one group is set.
73+
74+
return $this->routes->first(fn (Route $route): bool => filled($route->getPage()->navigationMenuGroup())) !== null;
75+
} else {
76+
return Config::getString('hyde.navigation.subdirectories', 'hidden') === 'dropdown';
77+
}
78+
}
79+
80+
protected function canAddRoute(Route $route): bool
81+
{
82+
return $route->getPage()->showInNavigation();
83+
}
84+
85+
protected function canGroupRoute(Route $route): bool
86+
{
87+
return $this->usesGroups;
88+
}
89+
90+
protected function addRouteToGroup(Route $route): void
91+
{
92+
$item = NavItem::fromRoute($route);
93+
94+
$groupName = $this->generatesSidebar ? ($item->getGroup() ?? 'Other') : $item->getGroup();
95+
96+
$groupItem = $this->getOrCreateGroupItem($groupName);
97+
98+
$groupItem->addChild($item);
99+
100+
if (! $this->items->has($groupItem->getIdentifier())) {
101+
$this->items->put($groupItem->getIdentifier(), $groupItem);
102+
}
103+
}
104+
105+
protected function getOrCreateGroupItem(string $groupName): NavItem
106+
{
107+
$groupKey = Str::slug($groupName);
108+
$group = $this->items->get($groupKey);
109+
110+
return $group ?? $this->createGroupItem($groupKey, $groupName);
111+
}
112+
113+
protected function createGroupItem(string $groupKey, string $groupName): NavItem
114+
{
115+
$label = $this->searchForGroupLabelInConfig($groupKey) ?? $groupName;
116+
117+
$priority = $this->searchForGroupPriorityInConfig($groupKey);
118+
119+
return NavItem::dropdown($this->normalizeGroupLabel($label), [], $priority);
120+
}
121+
122+
protected function normalizeGroupLabel(string $label): string
123+
{
124+
// If there is no label, and the group is a slug, we can make a title from it
125+
if ($label === strtolower($label)) {
126+
return Hyde::makeTitle($label);
127+
}
128+
129+
return $label;
130+
}
131+
132+
protected function searchForGroupLabelInConfig(string $groupKey): ?string
133+
{
134+
$key = $this->generatesSidebar ? 'docs.sidebar_group_labels' : 'hyde.navigation.labels';
135+
136+
return Config::getArray($key, [])[$groupKey] ?? null;
137+
}
138+
139+
protected function searchForGroupPriorityInConfig(string $groupKey): ?int
140+
{
141+
$key = $this->generatesSidebar ? 'docs.sidebar_order' : 'hyde.navigation.order';
142+
143+
return Config::getArray($key, [])[$groupKey] ?? null;
144+
}
145+
}

packages/framework/src/Framework/Features/Navigation/GeneratesDocumentationSidebarMenu.php

Lines changed: 5 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,18 @@
44

55
namespace Hyde\Framework\Features\Navigation;
66

7-
use Hyde\Hyde;
8-
use Hyde\Facades\Config;
9-
use Illuminate\Support\Str;
107
use Hyde\Support\Models\Route;
118
use Hyde\Pages\DocumentationPage;
12-
use Illuminate\Support\Collection;
13-
use Hyde\Foundation\Facades\Routes;
14-
use Hyde\Foundation\Kernel\RouteCollection;
159

16-
use function filled;
1710
use function collect;
18-
use function strtolower;
1911

2012
/**
2113
* @experimental This class may change significantly before its release.
2214
*
23-
* @todo Consider making into a service which can create the sidebar as well.
24-
*
2515
* @see \Hyde\Framework\Features\Navigation\GeneratesMainNavigationMenu
2616
*/
27-
class GeneratesDocumentationSidebarMenu
17+
class GeneratesDocumentationSidebarMenu extends BaseMenuGenerator
2818
{
29-
/** @var \Illuminate\Support\Collection<string, \Hyde\Framework\Features\Navigation\NavItem> */
30-
protected Collection $items;
31-
32-
/** @var \Hyde\Foundation\Kernel\RouteCollection<string, \Hyde\Support\Models\Route> */
33-
protected RouteCollection $routes;
34-
35-
protected function __construct()
36-
{
37-
$this->items = new Collection();
38-
$this->routes = Routes::getRoutes(DocumentationPage::class);
39-
}
40-
4119
public static function handle(): DocumentationSidebar
4220
{
4321
$menu = new static();
@@ -50,39 +28,19 @@ public static function handle(): DocumentationSidebar
5028

5129
protected function generate(): void
5230
{
53-
$useGroups = $this->usesSidebarGroups();
54-
55-
$this->routes->each(function (Route $route) use ($useGroups): void {
56-
if ($this->canAddRoute($route)) {
57-
$item = NavItem::fromRoute($route);
58-
59-
if ($useGroups) {
60-
$this->addItemToGroup($item);
61-
} else {
62-
$this->items->put($route->getRouteKey(), $item);
63-
}
64-
}
65-
});
31+
parent::generate();
6632

6733
// If there are no pages other than the index page, we add it to the sidebar so that it's not empty
6834
if ($this->items->count() === 0 && DocumentationPage::home() !== null) {
6935
$this->items->push(NavItem::fromRoute(DocumentationPage::home()));
7036
}
7137
}
7238

73-
protected function usesSidebarGroups(): bool
74-
{
75-
// In order to know if we should use groups in the sidebar,
76-
// we need to loop through the pages and see if they have a group set
77-
78-
return $this->routes->first(function (Route $route): bool {
79-
return filled($route->getPage()->navigationMenuGroup());
80-
}) !== null;
81-
}
82-
8339
protected function canAddRoute(Route $route): bool
8440
{
85-
return $route->getPage()->showInNavigation() && ! $route->is(DocumentationPage::homeRouteName());
41+
return parent::canAddRoute($route)
42+
// Since the index page is linked in the header, we don't want it in the sidebar
43+
&& ! $route->is(DocumentationPage::homeRouteName());
8644
}
8745

8846
protected function sortByPriority(): void
@@ -97,57 +55,8 @@ protected function sortByPriority(): void
9755
})->values();
9856
}
9957

100-
protected function addItemToGroup(NavItem $item): void
101-
{
102-
$groupItem = $this->getOrCreateGroupItem($item->getGroup() ?? 'Other');
103-
104-
$groupItem->addChild($item);
105-
106-
if (! $this->items->has($groupItem->getIdentifier())) {
107-
$this->items->put($groupItem->getIdentifier(), $groupItem);
108-
}
109-
}
110-
11158
protected function getLowestPriorityInGroup(NavItem $item): int
11259
{
11360
return collect($item->getChildren())->min(fn (NavItem $child): int => $child->getPriority());
11461
}
115-
116-
protected function getOrCreateGroupItem(string $groupName): NavItem
117-
{
118-
$identifier = Str::slug($groupName);
119-
$group = $this->items->get($identifier);
120-
121-
return $group ?? $this->createGroupItem($identifier, $groupName);
122-
}
123-
124-
protected function createGroupItem(string $identifier, string $groupName): NavItem
125-
{
126-
$label = $this->searchForGroupLabelInConfig($identifier) ?? $groupName;
127-
$priority = $this->searchForGroupPriorityInConfig($identifier);
128-
129-
return NavItem::dropdown(static::normalizeGroupLabel($label), [], $priority);
130-
}
131-
132-
protected function searchForGroupLabelInConfig(string $identifier): ?string
133-
{
134-
return Config::getArray('docs.sidebar_group_labels', [])[$identifier] ?? null;
135-
}
136-
137-
/** Todo: Move into shared class */
138-
protected static function normalizeGroupLabel(string $label): string
139-
{
140-
// If there is no label, and the group is a slug, we can make a title from it
141-
if ($label === strtolower($label)) {
142-
return Hyde::makeTitle($label);
143-
}
144-
145-
return $label;
146-
}
147-
148-
/** Todo: Move into shared class */
149-
protected static function searchForGroupPriorityInConfig(string $groupKey): ?int
150-
{
151-
return Config::getArray('docs.sidebar_order', [])[$groupKey] ?? null;
152-
}
15362
}

0 commit comments

Comments
 (0)