149a243cbSGreg Roach<?php 23976b470SGreg Roach 349a243cbSGreg Roach/** 449a243cbSGreg Roach * webtrees: online genealogy 5d11be702SGreg Roach * Copyright (C) 2023 webtrees development team 649a243cbSGreg Roach * This program is free software: you can redistribute it and/or modify 749a243cbSGreg Roach * it under the terms of the GNU General Public License as published by 849a243cbSGreg Roach * the Free Software Foundation, either version 3 of the License, or 949a243cbSGreg Roach * (at your option) any later version. 1049a243cbSGreg Roach * This program is distributed in the hope that it will be useful, 1149a243cbSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 1249a243cbSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1349a243cbSGreg Roach * GNU General Public License for more details. 1449a243cbSGreg Roach * You should have received a copy of the GNU General Public License 1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 1649a243cbSGreg Roach */ 17fcfa147eSGreg Roach 1849a243cbSGreg Roachdeclare(strict_types=1); 1949a243cbSGreg Roach 2049a243cbSGreg Roachnamespace Fisharebest\Webtrees\Module; 2149a243cbSGreg Roach 22ade503dfSGreg Roachuse Fisharebest\Webtrees\Auth; 231fe542e9SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 24ade503dfSGreg Roachuse Fisharebest\Webtrees\Fact; 25ade503dfSGreg Roachuse Fisharebest\Webtrees\Gedcom; 26a49d0e3fSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\AccountEdit; 270c0910bfSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\ControlPanel; 28ea101122SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\HomePage; 2956f9a9c1SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\LoginPage; 3056f9a9c1SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\Logout; 316fd01894SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\ManageTrees; 3222e73debSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\PendingChanges; 337adfb8e5SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SelectLanguage; 347adfb8e5SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SelectTheme; 358e0e1b25SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\TreePage; 368e0e1b25SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\TreePageEdit; 378e0e1b25SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\UserPage; 388e0e1b25SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\UserPageEdit; 39ade503dfSGreg Roachuse Fisharebest\Webtrees\I18N; 40ade503dfSGreg Roachuse Fisharebest\Webtrees\Individual; 41ade503dfSGreg Roachuse Fisharebest\Webtrees\Menu; 42c72a9801SGreg Roachuse Fisharebest\Webtrees\Registry; 434ca7e03cSGreg Roachuse Fisharebest\Webtrees\Services\ModuleService; 44ade503dfSGreg Roachuse Fisharebest\Webtrees\Tree; 45b55cbc6bSGreg Roachuse Fisharebest\Webtrees\Validator; 466ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 473976b470SGreg Roach 4810e06497SGreg Roachuse function count; 4910e06497SGreg Roachuse function in_array; 507adfb8e5SGreg Roachuse function route; 51f78837dcSGreg Roachuse function view; 52ade503dfSGreg Roach 5349a243cbSGreg Roach/** 5449a243cbSGreg Roach * Trait ModuleThemeTrait - default implementation of ModuleThemeInterface 5549a243cbSGreg Roach */ 5649a243cbSGreg Roachtrait ModuleThemeTrait 5749a243cbSGreg Roach{ 58ade503dfSGreg Roach /** 59bfed30e4SGreg Roach * How should this module be identified in the control panel, etc.? 60bfed30e4SGreg Roach * 61bfed30e4SGreg Roach * @return string 62bfed30e4SGreg Roach */ 63bfed30e4SGreg Roach abstract public function title(): string; 64bfed30e4SGreg Roach 653d8b2a8eSGreg Roach public function description(): string 663d8b2a8eSGreg Roach { 673d8b2a8eSGreg Roach return I18N::translate('Theme') . ' — ' . $this->title(); 683d8b2a8eSGreg Roach } 693d8b2a8eSGreg Roach 703d8b2a8eSGreg Roach /** 71ade503dfSGreg Roach * Generate the facts, for display in charts. 72ade503dfSGreg Roach * 73ade503dfSGreg Roach * @param Individual $individual 74ade503dfSGreg Roach * 75ade503dfSGreg Roach * @return string 76ade503dfSGreg Roach */ 77ade503dfSGreg Roach public function individualBoxFacts(Individual $individual): string 78ade503dfSGreg Roach { 79ade503dfSGreg Roach $html = ''; 80ade503dfSGreg Roach 81ade503dfSGreg Roach $opt_tags = preg_split('/\W/', $individual->tree()->getPreference('CHART_BOX_TAGS'), 0, PREG_SPLIT_NO_EMPTY); 82ade503dfSGreg Roach // Show BIRT or equivalent event 83ade503dfSGreg Roach foreach (Gedcom::BIRTH_EVENTS as $birttag) { 8422d65e5aSGreg Roach if (!in_array($birttag, $opt_tags, true)) { 85820b62dfSGreg Roach $event = $individual->facts([$birttag])->first(); 86820b62dfSGreg Roach if ($event instanceof Fact) { 87ade503dfSGreg Roach $html .= $event->summary(); 88ade503dfSGreg Roach break; 89ade503dfSGreg Roach } 90ade503dfSGreg Roach } 91ade503dfSGreg Roach } 92ade503dfSGreg Roach // Show optional events (before death) 93ade503dfSGreg Roach foreach ($opt_tags as $key => $tag) { 9422d65e5aSGreg Roach if (!in_array($tag, Gedcom::DEATH_EVENTS, true)) { 95820b62dfSGreg Roach $event = $individual->facts([$tag])->first(); 96820b62dfSGreg Roach if ($event instanceof Fact) { 97ade503dfSGreg Roach $html .= $event->summary(); 98ade503dfSGreg Roach unset($opt_tags[$key]); 99ade503dfSGreg Roach } 100ade503dfSGreg Roach } 101ade503dfSGreg Roach } 102ade503dfSGreg Roach // Show DEAT or equivalent event 103ade503dfSGreg Roach foreach (Gedcom::DEATH_EVENTS as $deattag) { 104820b62dfSGreg Roach $event = $individual->facts([$deattag])->first(); 105820b62dfSGreg Roach if ($event instanceof Fact) { 106ade503dfSGreg Roach $html .= $event->summary(); 10722d65e5aSGreg Roach if (in_array($deattag, $opt_tags, true)) { 10822d65e5aSGreg Roach unset($opt_tags[array_search($deattag, $opt_tags, true)]); 109ade503dfSGreg Roach } 110ade503dfSGreg Roach break; 111ade503dfSGreg Roach } 112ade503dfSGreg Roach } 113ade503dfSGreg Roach // Show remaining optional events (after death) 114ade503dfSGreg Roach foreach ($opt_tags as $tag) { 115820b62dfSGreg Roach $event = $individual->facts([$tag])->first(); 116820b62dfSGreg Roach if ($event instanceof Fact) { 117ade503dfSGreg Roach $html .= $event->summary(); 118ade503dfSGreg Roach } 119ade503dfSGreg Roach } 120ade503dfSGreg Roach 121ade503dfSGreg Roach return $html; 122ade503dfSGreg Roach } 123ade503dfSGreg Roach 124ade503dfSGreg Roach /** 125ade503dfSGreg Roach * Links, to show in chart boxes; 126ade503dfSGreg Roach * 127ade503dfSGreg Roach * @param Individual $individual 128ade503dfSGreg Roach * 12909482a55SGreg Roach * @return array<Menu> 130ade503dfSGreg Roach */ 131ade503dfSGreg Roach public function individualBoxMenu(Individual $individual): array 132ade503dfSGreg Roach { 133aa6311c7SGreg Roach return array_merge( 134ade503dfSGreg Roach $this->individualBoxMenuCharts($individual), 135ade503dfSGreg Roach $this->individualBoxMenuFamilyLinks($individual) 136ade503dfSGreg Roach ); 137ade503dfSGreg Roach } 138ade503dfSGreg Roach 139ade503dfSGreg Roach /** 140ade503dfSGreg Roach * Chart links, to show in chart boxes; 141ade503dfSGreg Roach * 142ade503dfSGreg Roach * @param Individual $individual 143ade503dfSGreg Roach * 14409482a55SGreg Roach * @return array<Menu> 145ade503dfSGreg Roach */ 146ade503dfSGreg Roach public function individualBoxMenuCharts(Individual $individual): array 147ade503dfSGreg Roach { 148ade503dfSGreg Roach $menus = []; 149b55cbc6bSGreg Roach 150d35568b4SGreg Roach $module_service = Registry::container()->get(ModuleService::class); 151b55cbc6bSGreg Roach 152b55cbc6bSGreg Roach foreach ($module_service->findByComponent(ModuleChartInterface::class, $individual->tree(), Auth::user()) as $chart) { 153ade503dfSGreg Roach $menu = $chart->chartBoxMenu($individual); 154ade503dfSGreg Roach if ($menu) { 155ade503dfSGreg Roach $menus[] = $menu; 156ade503dfSGreg Roach } 157ade503dfSGreg Roach } 158ade503dfSGreg Roach 159f25fc0f9SGreg Roach usort($menus, static fn (Menu $x, Menu $y): int => I18N::comparator()($x->getLabel(), $y->getLabel())); 160ade503dfSGreg Roach 161ade503dfSGreg Roach return $menus; 162ade503dfSGreg Roach } 163ade503dfSGreg Roach 164ade503dfSGreg Roach /** 165ade503dfSGreg Roach * Family links, to show in chart boxes. 166ade503dfSGreg Roach * 167ade503dfSGreg Roach * @param Individual $individual 168ade503dfSGreg Roach * 16909482a55SGreg Roach * @return array<Menu> 170ade503dfSGreg Roach */ 171ade503dfSGreg Roach public function individualBoxMenuFamilyLinks(Individual $individual): array 172ade503dfSGreg Roach { 173ade503dfSGreg Roach $menus = []; 174ade503dfSGreg Roach 17539ca88baSGreg Roach foreach ($individual->spouseFamilies() as $family) { 176ade503dfSGreg Roach $menus[] = new Menu('<strong>' . I18N::translate('Family with spouse') . '</strong>', $family->url()); 17739ca88baSGreg Roach $spouse = $family->spouse($individual); 178ade503dfSGreg Roach if ($spouse && $spouse->canShowName()) { 17939ca88baSGreg Roach $menus[] = new Menu($spouse->fullName(), $spouse->url()); 180ade503dfSGreg Roach } 18139ca88baSGreg Roach foreach ($family->children() as $child) { 182ade503dfSGreg Roach if ($child->canShowName()) { 18339ca88baSGreg Roach $menus[] = new Menu($child->fullName(), $child->url()); 184ade503dfSGreg Roach } 185ade503dfSGreg Roach } 186ade503dfSGreg Roach } 187ade503dfSGreg Roach 188ade503dfSGreg Roach return $menus; 189ade503dfSGreg Roach } 190ade503dfSGreg Roach 191ade503dfSGreg Roach /** 192f567c3d8SGreg Roach * Generate a menu item to change the blocks on the current tree/user page. 193ade503dfSGreg Roach * 1940c8c69d4SGreg Roach * @param Tree $tree 1950c8c69d4SGreg Roach * 196ade503dfSGreg Roach * @return Menu|null 197ade503dfSGreg Roach */ 198*1ff45046SGreg Roach public function menuChangeBlocks(Tree $tree): Menu|null 199ade503dfSGreg Roach { 200d35568b4SGreg Roach $request = Registry::container()->get(ServerRequestInterface::class); 201b55cbc6bSGreg Roach $route = Validator::attributes($request)->route(); 202eb235819SGreg Roach 203de2aa325SGreg Roach if (Auth::check() && $route->name === UserPage::class) { 2048e0e1b25SGreg Roach return new Menu(I18N::translate('Customize this page'), route(UserPageEdit::class, ['tree' => $tree->name()]), 'menu-change-blocks'); 205ade503dfSGreg Roach } 206ade503dfSGreg Roach 207de2aa325SGreg Roach if (Auth::isManager($tree) && $route->name === TreePage::class) { 2088e0e1b25SGreg Roach return new Menu(I18N::translate('Customize this page'), route(TreePageEdit::class, ['tree' => $tree->name()]), 'menu-change-blocks'); 209ade503dfSGreg Roach } 210ade503dfSGreg Roach 211ade503dfSGreg Roach return null; 212ade503dfSGreg Roach } 213ade503dfSGreg Roach 214ade503dfSGreg Roach /** 215ade503dfSGreg Roach * Generate a menu item for the control panel. 216ade503dfSGreg Roach * 2170c8c69d4SGreg Roach * @param Tree $tree 2180c8c69d4SGreg Roach * 219ade503dfSGreg Roach * @return Menu|null 220ade503dfSGreg Roach */ 221*1ff45046SGreg Roach public function menuControlPanel(Tree $tree): Menu|null 222ade503dfSGreg Roach { 223ade503dfSGreg Roach if (Auth::isAdmin()) { 2240c0910bfSGreg Roach return new Menu(I18N::translate('Control panel'), route(ControlPanel::class), 'menu-admin'); 225ade503dfSGreg Roach } 226ade503dfSGreg Roach 2270c8c69d4SGreg Roach if (Auth::isManager($tree)) { 2286fd01894SGreg Roach return new Menu(I18N::translate('Control panel'), route(ManageTrees::class, ['tree' => $tree->name()]), 'menu-admin'); 229ade503dfSGreg Roach } 230ade503dfSGreg Roach 231ade503dfSGreg Roach return null; 232ade503dfSGreg Roach } 233ade503dfSGreg Roach 234ade503dfSGreg Roach /** 235ade503dfSGreg Roach * A menu to show a list of available languages. 236ade503dfSGreg Roach * 237ade503dfSGreg Roach * @return Menu|null 238ade503dfSGreg Roach */ 239*1ff45046SGreg Roach public function menuLanguages(): Menu|null 240ade503dfSGreg Roach { 241ade503dfSGreg Roach $menu = new Menu(I18N::translate('Language'), '#', 'menu-language'); 242ade503dfSGreg Roach 24390a2f718SGreg Roach foreach (I18N::activeLocales() as $active_locale) { 24490a2f718SGreg Roach $language_tag = $active_locale->languageTag(); 24565cf5706SGreg Roach $class = 'menu-language-' . $language_tag . (I18N::languageTag() === $language_tag ? ' active' : ''); 24690a2f718SGreg Roach $menu->addSubmenu(new Menu($active_locale->endonym(), '#', $class, [ 247d4786c66SGreg Roach 'data-wt-post-url' => route(SelectLanguage::class, ['language' => $language_tag]), 248ade503dfSGreg Roach ])); 249ade503dfSGreg Roach } 250ade503dfSGreg Roach 251ade503dfSGreg Roach if (count($menu->getSubmenus()) > 1) { 252ade503dfSGreg Roach return $menu; 253ade503dfSGreg Roach } 254ade503dfSGreg Roach 255ade503dfSGreg Roach return null; 256ade503dfSGreg Roach } 257ade503dfSGreg Roach 258ade503dfSGreg Roach /** 259ade503dfSGreg Roach * A login menu option (or null if we are already logged in). 260ade503dfSGreg Roach * 261ade503dfSGreg Roach * @return Menu|null 262ade503dfSGreg Roach */ 263*1ff45046SGreg Roach public function menuLogin(): Menu|null 264ade503dfSGreg Roach { 265ade503dfSGreg Roach if (Auth::check()) { 266ade503dfSGreg Roach return null; 267ade503dfSGreg Roach } 268ade503dfSGreg Roach 269d35568b4SGreg Roach $request = Registry::container()->get(ServerRequestInterface::class); 27086661454SGreg Roach 271ade503dfSGreg Roach // Return to this page after login... 2729f0bdfcdSGreg Roach $redirect = Validator::queryParams($request)->string('url', (string) $request->getUri()); 273b55cbc6bSGreg Roach $tree = Validator::attributes($request)->treeOptional(); 274b55cbc6bSGreg Roach $route = Validator::attributes($request)->route(); 275b45ccc4fSGreg Roach 276ade503dfSGreg Roach // ...but switch from the tree-page to the user-page 277de2aa325SGreg Roach if ($route->name === TreePage::class) { 27881bf3221SGreg Roach $redirect = route(UserPage::class, ['tree' => $tree?->name()]); 27991c514e5SGreg Roach } 280ade503dfSGreg Roach 28186661454SGreg Roach // Stay on the same tree page 28281bf3221SGreg Roach $url = route(LoginPage::class, ['tree' => $tree?->name(), 'url' => $redirect]); 28386661454SGreg Roach 28486661454SGreg Roach return new Menu(I18N::translate('Sign in'), $url, 'menu-login', ['rel' => 'nofollow']); 285ade503dfSGreg Roach } 286ade503dfSGreg Roach 287ade503dfSGreg Roach /** 288ade503dfSGreg Roach * A logout menu option (or null if we are already logged out). 289ade503dfSGreg Roach * 290ade503dfSGreg Roach * @return Menu|null 291ade503dfSGreg Roach */ 292*1ff45046SGreg Roach public function menuLogout(): Menu|null 293ade503dfSGreg Roach { 294ade503dfSGreg Roach if (Auth::check()) { 2959b541e4aSGreg Roach $parameters = [ 296d4786c66SGreg Roach 'data-wt-post-url' => route(Logout::class), 297d4786c66SGreg Roach 'data-wt-reload-url' => route(HomePage::class) 2989b541e4aSGreg Roach ]; 2999b541e4aSGreg Roach 3009b541e4aSGreg Roach return new Menu(I18N::translate('Sign out'), '#', 'menu-logout', $parameters); 301ade503dfSGreg Roach } 302ade503dfSGreg Roach 303ade503dfSGreg Roach return null; 304ade503dfSGreg Roach } 305ade503dfSGreg Roach 306ade503dfSGreg Roach /** 307ade503dfSGreg Roach * A link to allow users to edit their account settings. 308ade503dfSGreg Roach * 30965aec466SGreg Roach * @param Tree|null $tree 310a49d0e3fSGreg Roach * 311a49d0e3fSGreg Roach * @return Menu 312ade503dfSGreg Roach */ 313*1ff45046SGreg Roach public function menuMyAccount(Tree|null $tree): Menu 314ade503dfSGreg Roach { 31581bf3221SGreg Roach $url = route(AccountEdit::class, ['tree' => $tree?->name()]); 316ade503dfSGreg Roach 317df314983SGreg Roach return new Menu(I18N::translate('My account'), $url, 'menu-myaccount'); 318ade503dfSGreg Roach } 319ade503dfSGreg Roach 320ade503dfSGreg Roach /** 321ade503dfSGreg Roach * A link to the user's individual record (individual.php). 322ade503dfSGreg Roach * 3230c8c69d4SGreg Roach * @param Tree $tree 3240c8c69d4SGreg Roach * 325ade503dfSGreg Roach * @return Menu|null 326ade503dfSGreg Roach */ 327*1ff45046SGreg Roach public function menuMyIndividualRecord(Tree $tree): Menu|null 328ade503dfSGreg Roach { 3291fe542e9SGreg Roach $record = Registry::individualFactory()->make($tree->getUserPreference(Auth::user(), UserInterface::PREF_TREE_ACCOUNT_XREF), $tree); 330ade503dfSGreg Roach 331b6ec1ccfSGreg Roach if ($record instanceof Individual) { 332ade503dfSGreg Roach return new Menu(I18N::translate('My individual record'), $record->url(), 'menu-myrecord'); 333ade503dfSGreg Roach } 334ade503dfSGreg Roach 335ade503dfSGreg Roach return null; 336ade503dfSGreg Roach } 337ade503dfSGreg Roach 338ade503dfSGreg Roach /** 339ade503dfSGreg Roach * A link to the user's personal home page. 340ade503dfSGreg Roach * 3410c8c69d4SGreg Roach * @param Tree $tree 3420c8c69d4SGreg Roach * 343ade503dfSGreg Roach * @return Menu 344ade503dfSGreg Roach */ 3450c8c69d4SGreg Roach public function menuMyPage(Tree $tree): Menu 346ade503dfSGreg Roach { 3478e0e1b25SGreg Roach return new Menu(I18N::translate('My page'), route(UserPage::class, ['tree' => $tree->name()]), 'menu-mypage'); 348ade503dfSGreg Roach } 349ade503dfSGreg Roach 350ade503dfSGreg Roach /** 351ade503dfSGreg Roach * A menu for the user's personal pages. 352ade503dfSGreg Roach * 3530c8c69d4SGreg Roach * @param Tree|null $tree 3540c8c69d4SGreg Roach * 355ade503dfSGreg Roach * @return Menu|null 356ade503dfSGreg Roach */ 357*1ff45046SGreg Roach public function menuMyPages(Tree|null $tree): Menu|null 358ade503dfSGreg Roach { 359047fd705SGreg Roach if (Auth::check()) { 360a49d0e3fSGreg Roach if ($tree instanceof Tree) { 361ade503dfSGreg Roach return new Menu(I18N::translate('My pages'), '#', 'menu-mymenu', [], array_filter([ 3620c8c69d4SGreg Roach $this->menuMyPage($tree), 3630c8c69d4SGreg Roach $this->menuMyIndividualRecord($tree), 3640c8c69d4SGreg Roach $this->menuMyPedigree($tree), 365a49d0e3fSGreg Roach $this->menuMyAccount($tree), 3660c8c69d4SGreg Roach $this->menuControlPanel($tree), 3670c8c69d4SGreg Roach $this->menuChangeBlocks($tree), 368ade503dfSGreg Roach ])); 369ade503dfSGreg Roach } 370ade503dfSGreg Roach 371a49d0e3fSGreg Roach return $this->menuMyAccount($tree); 372a49d0e3fSGreg Roach } 373a49d0e3fSGreg Roach 374ade503dfSGreg Roach return null; 375ade503dfSGreg Roach } 376ade503dfSGreg Roach 377ade503dfSGreg Roach /** 378ade503dfSGreg Roach * A link to the user's individual record. 379ade503dfSGreg Roach * 3800c8c69d4SGreg Roach * @param Tree $tree 3810c8c69d4SGreg Roach * 382ade503dfSGreg Roach * @return Menu|null 383ade503dfSGreg Roach */ 384*1ff45046SGreg Roach public function menuMyPedigree(Tree $tree): Menu|null 385ade503dfSGreg Roach { 386c72a9801SGreg Roach $my_xref = $tree->getUserPreference(Auth::user(), UserInterface::PREF_TREE_ACCOUNT_XREF); 387ade503dfSGreg Roach 388d35568b4SGreg Roach $module_service = Registry::container()->get(ModuleService::class); 389b55cbc6bSGreg Roach $pedigree_chart = $module_service 390b55cbc6bSGreg Roach ->findByComponent(ModuleChartInterface::class, $tree, Auth::user()) 391b55cbc6bSGreg Roach ->first(static fn (ModuleInterface $module): bool => $module instanceof PedigreeChartModule); 392ade503dfSGreg Roach 393c72a9801SGreg Roach if ($my_xref !== '' && $pedigree_chart instanceof PedigreeChartModule) { 394c72a9801SGreg Roach $individual = Registry::individualFactory()->make($my_xref, $tree); 395c72a9801SGreg Roach 396c72a9801SGreg Roach if ($individual instanceof Individual) { 397ade503dfSGreg Roach return new Menu( 398ade503dfSGreg Roach I18N::translate('My pedigree'), 399c72a9801SGreg Roach $pedigree_chart->chartUrl($individual), 400ade503dfSGreg Roach 'menu-mypedigree' 401ade503dfSGreg Roach ); 402ade503dfSGreg Roach } 403c72a9801SGreg Roach } 404ade503dfSGreg Roach 405ade503dfSGreg Roach return null; 406ade503dfSGreg Roach } 407ade503dfSGreg Roach 408ade503dfSGreg Roach /** 409ade503dfSGreg Roach * Create a pending changes menu. 410ade503dfSGreg Roach * 4110c8c69d4SGreg Roach * @param Tree|null $tree 4120c8c69d4SGreg Roach * 413ade503dfSGreg Roach * @return Menu|null 414ade503dfSGreg Roach */ 415*1ff45046SGreg Roach public function menuPendingChanges(Tree|null $tree): Menu|null 416ade503dfSGreg Roach { 4170c8c69d4SGreg Roach if ($tree instanceof Tree && $tree->hasPendingEdit() && Auth::isModerator($tree)) { 418d35568b4SGreg Roach $request = Registry::container()->get(ServerRequestInterface::class); 419b55cbc6bSGreg Roach 42022e73debSGreg Roach $url = route(PendingChanges::class, [ 4219022ab66SGreg Roach 'tree' => $tree->name(), 422b55cbc6bSGreg Roach 'url' => (string) $request->getUri(), 423ade503dfSGreg Roach ]); 424ade503dfSGreg Roach 425ade503dfSGreg Roach return new Menu(I18N::translate('Pending changes'), $url, 'menu-pending'); 426ade503dfSGreg Roach } 427ade503dfSGreg Roach 428ade503dfSGreg Roach return null; 429ade503dfSGreg Roach } 430ade503dfSGreg Roach 431ade503dfSGreg Roach /** 432ade503dfSGreg Roach * Themes menu. 433ade503dfSGreg Roach * 434ade503dfSGreg Roach * @return Menu|null 435ade503dfSGreg Roach */ 436*1ff45046SGreg Roach public function menuThemes(): Menu|null 437ade503dfSGreg Roach { 438d35568b4SGreg Roach $module_service = Registry::container()->get(ModuleService::class); 439b55cbc6bSGreg Roach $themes = $module_service->findByInterface(ModuleThemeInterface::class, false, true); 440d35568b4SGreg Roach $current_theme = Registry::container()->get(ModuleThemeInterface::class); 4418136679eSGreg Roach 4428136679eSGreg Roach if ($themes->count() > 1) { 4430b5fd0a6SGreg Roach $submenus = $themes->map(static function (ModuleThemeInterface $theme) use ($current_theme): Menu { 4448136679eSGreg Roach $active = $theme->name() === $current_theme->name(); 4458136679eSGreg Roach $class = 'menu-theme-' . $theme->name() . ($active ? ' active' : ''); 4468136679eSGreg Roach 4478136679eSGreg Roach return new Menu($theme->title(), '#', $class, [ 448d4786c66SGreg Roach 'data-wt-post-url' => route(SelectTheme::class, ['theme' => $theme->name()]), 449ade503dfSGreg Roach ]); 450ade503dfSGreg Roach }); 451ade503dfSGreg Roach 4528136679eSGreg Roach return new Menu(I18N::translate('Theme'), '#', 'menu-theme', [], $submenus->all()); 453ade503dfSGreg Roach } 454ade503dfSGreg Roach 455ade503dfSGreg Roach return null; 456ade503dfSGreg Roach } 457ade503dfSGreg Roach 458ade503dfSGreg Roach /** 459ade503dfSGreg Roach * Generate a list of items for the main menu. 460ade503dfSGreg Roach * 4610c8c69d4SGreg Roach * @param Tree|null $tree 4620c8c69d4SGreg Roach * 46309482a55SGreg Roach * @return array<Menu> 464ade503dfSGreg Roach */ 465*1ff45046SGreg Roach public function genealogyMenu(Tree|null $tree): array 466ade503dfSGreg Roach { 4670c8c69d4SGreg Roach if ($tree === null) { 4680c8c69d4SGreg Roach return []; 4690c8c69d4SGreg Roach } 4700c8c69d4SGreg Roach 471d35568b4SGreg Roach $module_service = Registry::container()->get(ModuleService::class); 472b55cbc6bSGreg Roach 473b55cbc6bSGreg Roach return $module_service 474b55cbc6bSGreg Roach ->findByComponent(ModuleMenuInterface::class, $tree, Auth::user()) 475*1ff45046SGreg Roach ->map(static fn (ModuleMenuInterface $menu): Menu|null => $menu->getMenu($tree)) 476ade503dfSGreg Roach ->filter() 477ade503dfSGreg Roach ->all(); 478ade503dfSGreg Roach } 479ade503dfSGreg Roach 480ade503dfSGreg Roach /** 4810c8c69d4SGreg Roach * Create the genealogy menu. 482ade503dfSGreg Roach * 48309482a55SGreg Roach * @param array<Menu> $menus 484ade503dfSGreg Roach * 485ade503dfSGreg Roach * @return string 486ade503dfSGreg Roach */ 4870c8c69d4SGreg Roach public function genealogyMenuContent(array $menus): string 488ade503dfSGreg Roach { 489f25fc0f9SGreg Roach return implode('', array_map(static fn (Menu $menu): string => view('components/menu-item', ['menu' => $menu]), $menus)); 490ade503dfSGreg Roach } 491ade503dfSGreg Roach 492ade503dfSGreg Roach /** 493ade503dfSGreg Roach * Generate a list of items for the user menu. 494ade503dfSGreg Roach * 4950c8c69d4SGreg Roach * @param Tree|null $tree 4960c8c69d4SGreg Roach * 49709482a55SGreg Roach * @return array<Menu> 498ade503dfSGreg Roach */ 499*1ff45046SGreg Roach public function userMenu(Tree|null $tree): array 500ade503dfSGreg Roach { 501ade503dfSGreg Roach return array_filter([ 5020c8c69d4SGreg Roach $this->menuPendingChanges($tree), 5030c8c69d4SGreg Roach $this->menuMyPages($tree), 504ade503dfSGreg Roach $this->menuThemes(), 505ade503dfSGreg Roach $this->menuLanguages(), 506ade503dfSGreg Roach $this->menuLogin(), 507ade503dfSGreg Roach $this->menuLogout(), 508ade503dfSGreg Roach ]); 509ade503dfSGreg Roach } 510ade503dfSGreg Roach 511ade503dfSGreg Roach /** 512ade503dfSGreg Roach * A list of CSS files to include for this page. 513ade503dfSGreg Roach * 51424f2a3afSGreg Roach * @return array<string> 515ade503dfSGreg Roach */ 516ade503dfSGreg Roach public function stylesheets(): array 517ade503dfSGreg Roach { 518ade503dfSGreg Roach return []; 519ade503dfSGreg Roach } 52049a243cbSGreg Roach} 521