chg: [app:naviation] Support of breadcrumbs for navigation - WiP

pull/72/head
mokaddem 2021-09-09 11:05:00 +02:00
parent 09996ea2ff
commit 866f73af88
9 changed files with 431 additions and 477 deletions

View File

@ -40,6 +40,7 @@ class AppController extends Controller
public $isRest = null;
public $restResponsePayload = null;
public $user = null;
public $breadcrumb = [];
/**
* Initialization hook method.
@ -74,6 +75,9 @@ class AppController extends Controller
'request' => $this->request,
'Authentication' => $this->Authentication
]);
$this->loadComponent('Navigation', [
'request' => $this->request,
]);
if (Configure::read('debug')) {
Configure::write('DebugKit.panels', ['DebugKit.Packages' => true]);
Configure::write('DebugKit.forceEnable', true);
@ -122,6 +126,7 @@ class AppController extends Controller
$this->ACL->checkAccess();
$this->set('menu', $this->ACL->getMenu());
$this->set('breadcrumb', $this->Navigation->getBreadcrumb());
$this->set('ajax', $this->request->is('ajax'));
$this->request->getParam('prefix');
$this->set('darkMode', !empty(Configure::read('Cerebrate.dark')));

View File

@ -17,6 +17,7 @@ class ACLComponent extends Component
{
private $user = null;
protected $components = ['Navigation'];
public function initialize(array $config): void
{
@ -454,464 +455,7 @@ class ACLComponent extends Component
public function getMenu()
{
$open = Configure::read('Cerebrate.open');
$menu = [
'ContactDB' => [
'Individuals' => [
'label' => __('Individuals'),
'icon' => 'address-book',
'url' => '/individuals/index',
'children' => [
'index' => [
'url' => '/individuals/index',
'label' => __('List individuals')
],
'add' => [
'url' => '/individuals/add',
'label' => __('Add individual'),
'popup' => 1
],
'view' => [
'url' => '/individuals/view/{{id}}',
'label' => __('View individual'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1
],
'edit' => [
'url' => '/individuals/edit/{{id}}',
'label' => __('Edit individual'),
'actions' => ['edit', 'delete', 'view'],
'skipTopMenu' => 1,
'popup' => 1
],
'delete' => [
'url' => '/individuals/delete/{{id}}',
'label' => __('Delete individual'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
]
]
],
'Organisations' => [
'label' => __('Organisations'),
'icon' => 'building',
'url' => '/organisations/index',
'children' => [
'index' => [
'url' => '/organisations/index',
'label' => __('List organisations')
],
'add' => [
'url' => '/organisations/add',
'label' => __('Add organisation'),
'popup' => 1
],
'view' => [
'url' => '/organisations/view/{{id}}',
'label' => __('View organisation'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1
],
'edit' => [
'url' => '/organisations/edit/{{id}}',
'label' => __('Edit organisation'),
'actions' => ['edit', 'delete', 'view'],
'skipTopMenu' => 1,
'popup' => 1
],
'delete' => [
'url' => '/organisations/delete/{{id}}',
'label' => __('Delete organisation'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
]
]
],
'EncryptionKeys' => [
'label' => __('Encryption keys'),
'icon' => 'key',
'url' => '/encryptionKeys/index',
'children' => [
'index' => [
'url' => '/encryptionKeys/index',
'label' => __('List encryption keys')
],
'add' => [
'url' => '/encryptionKeys/add',
'label' => __('Add encryption key'),
'popup' => 1
],
'edit' => [
'url' => '/encryptionKeys/edit/{{id}}',
'label' => __('Edit organisation'),
'actions' => ['edit'],
'skipTopMenu' => 1,
'popup' => 1
]
]
]
],
'Trust Circles' => [
'SharingGroups' => [
'label' => __('Sharing Groups'),
'icon' => 'user-friends',
'url' => '/sharingGroups/index',
'children' => [
'index' => [
'url' => '/sharingGroups/index',
'label' => __('List sharing groups')
],
'add' => [
'url' => '/SharingGroups/add',
'label' => __('Add sharing group'),
'popup' => 1
],
'edit' => [
'url' => '/SharingGroups/edit/{{id}}',
'label' => __('Edit sharing group'),
'actions' => ['edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
],
'delete' => [
'url' => '/SharingGroups/delete/{{id}}',
'label' => __('Delete sharing group'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
]
]
]
],
'Sync' => [
'Broods' => [
'label' => __('Broods'),
'icon' => 'network-wired',
'url' => '/broods/index',
'children' => [
'index' => [
'url' => '/broods/index',
'label' => __('List broods')
],
'add' => [
'url' => '/broods/add',
'label' => __('Add brood'),
'popup' => 1
],
'view' => [
'url' => '/broods/view/{{id}}',
'label' => __('View brood'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1
],
'edit' => [
'url' => '/broods/edit/{{id}}',
'label' => __('Edit brood'),
'actions' => ['edit', 'delete', 'view'],
'skipTopMenu' => 1,
'popup' => 1
],
'delete' => [
'url' => '/broods/delete/{{id}}',
'label' => __('Delete brood'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
]
]
]
],
'Administration' => [
'Roles' => [
'label' => __('Roles'),
'icon' => 'id-badge',
'url' => '/roles/index',
'children' => [
'index' => [
'url' => '/roles/index',
'label' => __('List roles')
],
'add' => [
'url' => '/roles/add',
'label' => __('Add role'),
'popup' => 1
],
'view' => [
'url' => '/roles/view/{{id}}',
'label' => __('View role'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1
],
'edit' => [
'url' => '/roles/edit/{{id}}',
'label' => __('Edit role'),
'actions' => ['edit', 'delete', 'view'],
'skipTopMenu' => 1,
'popup' => 1
],
'delete' => [
'url' => '/roles/delete/{{id}}',
'label' => __('Delete role'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
]
]
],
'Users' => [
'label' => __('Users'),
'icon' => 'users',
'url' => '/users/index',
'children' => [
'index' => [
'url' => '/users/index',
'label' => __('List users')
],
'add' => [
'url' => '/users/add',
'label' => __('Add user'),
'popup' => 1
],
'view' => [
'url' => '/users/view/{{id}}',
'label' => __('View user'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1
],
'edit' => [
'url' => '/users/edit/{{id}}',
'label' => __('Edit user'),
'actions' => ['edit', 'delete', 'view'],
'skipTopMenu' => 1,
'popup' => 1
],
'delete' => [
'url' => '/users/delete/{{id}}',
'label' => __('Delete user'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
]
]
],
'Inbox' => [
'label' => __('Inbox'),
'icon' => 'inbox',
'url' => '/inbox/index',
'children' => [
'index' => [
'url' => '/inbox/index',
'label' => __('Inbox')
],
'outbox' => [
'url' => '/outbox/index',
'label' => __('Outbox')
],
'view' => [
'url' => '/inbox/view/{{id}}',
'label' => __('View Message'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1
],
'delete' => [
'url' => '/inbox/delete/{{id}}',
'label' => __('Delete Message'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
],
'listProcessors' => [
'url' => '/inbox/listProcessors',
'label' => __('List Inbox Processors'),
'skipTopMenu' => 1
]
]
],
'Outbox' => [
'label' => __('Outbox'),
'icon' => 'inbox',
'url' => '/outbox/index',
'children' => [
'index' => [
'url' => '/outbox/index',
'label' => __('Outbox'),
'skipTopMenu' => 1
],
'view' => [
'url' => '/outbox/view/{{id}}',
'label' => __('View Message'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1
],
'delete' => [
'url' => '/outbox/delete/{{id}}',
'label' => __('Delete Message'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
],
'listProcessors' => [
'url' => '/outbox/listProcessors',
'label' => __('List Outbox Processors'),
'skipTopMenu' => 1
]
]
],
'MetaTemplates' => [
'label' => __('Meta Field Templates'),
'icon' => 'object-group',
'url' => '/metaTemplates/index',
'children' => [
'index' => [
'url' => '/metaTemplates/index',
'label' => __('List Meta Templates')
],
'view' => [
'url' => '/metaTemplates/view/{{id}}',
'label' => __('View Meta Template'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1
],
'delete' => [
'url' => '/metaTemplates/delete/{{id}}',
'label' => __('Delete Meta Template'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
],
'update' => [
'url' => '/metaTemplates/update',
'label' => __('Update Meta Templates'),
'actions' => ['index', 'view'],
'skipTopMenu' => 1,
'popup' => 1
]
]
],
'LocalTools' => [
'label' => __('Local Tools'),
'icon' => 'tools',
'url' => '/localTools/index',
'children' => [
'index' => [
'url' => '/localTools/index',
'label' => __('List Connectors')
],
'viewConnector' => [
'url' => '/localTools/viewConnector/{{connector}}',
'label' => __('View Connector'),
'actions' => ['view'],
'skipTopMenu' => 1
],
'add' => [
'url' => '/localTools/add/{{connector}}',
'label' => __('Add connection'),
'actions' => ['viewConnector'],
'skipTopMenu' => 1
],
'view' => [
'url' => '/localTools/view/{{id}}',
'label' => __('View Connection'),
'actions' => ['view'],
'skipTopMenu' => 1
]
]
],
'Instance' => [
__('Instance'),
'url' => '/instance/home',
'icon' => 'database',
'children' => [
'migration' => [
'url' => '/instance/migrationIndex',
'label' => __('Database migration')
]
]
],
],
'Cerebrate' => [
'Roles' => [
'label' => __('Roles'),
'icon' => 'id-badge',
'url' => '/roles/index',
'children' => [
'index' => [
'url' => '/roles/index',
'label' => __('List roles')
],
'view' => [
'url' => '/roles/view/{{id}}',
'label' => __('View role'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1
],
'delete' => [
'url' => '/roles/delete/{{id}}',
'label' => __('Delete Role'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
]
]
],
'Instance' => [
__('Instance'),
'url' => '/instance/home',
'icon' => 'home',
'children' => [
'home' => [
'url' => '/instance/home',
'label' => __('Home')
],
]
],
'Users' => [
__('My Profile'),
'icon' => 'user-circle',
'children' => [
'View My Profile' => [
'url' => '/users/view',
'label' => __('View My Profile')
],
'Edit My Profile' => [
'url' => '/users/edit',
'label' => __('Edit My Profile'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => 1,
'popup' => 1
]
]
]
],
'Open' => [
'Organisations' => [
'label' => __('Organisations'),
'icon' => 'buildings',
'url' => '/open/organisations/index',
'children' => [
'index' => [
'url' => '/open/organisations/index',
'label' => __('List organisations')
],
],
'open' => in_array('organisations', Configure::read('Cerebrate.open'))
],
'Individuals' => [
'label' => __('Individuals'),
'icon' => 'address-book',
'url' => '/open/individuals/index',
'children' => [
'index' => [
'url' => '/open/individuals/index',
'label' => __('List individuals')
],
],
'open' => in_array('individuals', Configure::read('Cerebrate.open'))
]
]
];
$menu = $this->Navigation->getSideMenu();
foreach ($menu as $group => $subMenu) {
foreach ($subMenu as $subMenuElementName => $subMenuElement) {
if (!empty($subMenuElement['url']) && !$this->checkAccessUrl($subMenuElement['url'], true) === true) {

View File

@ -0,0 +1,324 @@
<?php
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Core\Configure;
use Cake\Utility\Inflector;
use Cake\Routing\Router;
class NavigationComponent extends Component
{
private $user = null;
public $breadcrumb = null;
public function initialize(array $config): void
{
$this->request = $config['request'];
$this->fullBreadcrumb = $this->genBreadcrumb();
$this->breadcrumb = $this->getBreadcrumb();
}
public function getSideMenu(): array
{
return [
'ContactDB' => [
'Individuals' => [
'label' => __('Individuals'),
'icon' => 'address-book',
'url' => '/individuals/index',
],
'Organisations' => [
'label' => __('Organisations'),
'icon' => 'building',
'url' => '/organisations/index',
],
'EncryptionKeys' => [
'label' => __('Encryption keys'),
'icon' => 'key',
'url' => '/encryptionKeys/index',
]
],
'Trust Circles' => [
'SharingGroups' => [
'label' => __('Sharing Groups'),
'icon' => 'user-friends',
'url' => '/sharingGroups/index',
]
],
'Sync' => [
'Broods' => [
'label' => __('Broods'),
'icon' => 'network-wired',
'url' => '/broods/index',
]
],
'Administration' => [
'Roles' => [
'label' => __('Roles'),
'icon' => 'id-badge',
'url' => '/roles/index',
],
'Users' => [
'label' => __('Users'),
'icon' => 'users',
'url' => '/users/index',
],
'Messages' => [
'label' => __('Messages'),
'icon' => 'inbox',
'url' => '/inbox/index',
'children' => [
'index' => [
'url' => '/inbox/index',
'label' => __('Inbox')
],
'outbox' => [
'url' => '/outbox/index',
'label' => __('Outbox')
],
]
],
'Add-ons' => [
'label' => __('Add-ons'),
'icon' => 'puzzle-piece',
'children' => [
'MetaTemplates.index' => [
'label' => __('Meta Field Templates'),
'icon' => 'object-group',
'url' => '/metaTemplates/index',
],
'LocalTools.index' => [
'label' => __('Local Tools'),
'icon' => 'tools',
'url' => '/localTools/index',
]
]
],
'Instance' => [
'label' => __('Instance'),
'icon' => 'server',
'children' => [
'Database' => [
'label' => __('Database'),
'url' => '/instance/migrationIndex',
'icon' => 'database',
]
]
],
],
'Open' => [
'Organisations' => [
'label' => __('Organisations'),
'icon' => 'buildings',
'url' => '/open/organisations/index',
'children' => [
'index' => [
'url' => '/open/organisations/index',
'label' => __('List organisations')
],
],
'open' => in_array('organisations', Configure::read('Cerebrate.open'))
],
'Individuals' => [
'label' => __('Individuals'),
'icon' => 'address-book',
'url' => '/open/individuals/index',
'children' => [
'index' => [
'url' => '/open/individuals/index',
'label' => __('List individuals')
],
],
'open' => in_array('individuals', Configure::read('Cerebrate.open'))
]
]
];
}
public function getBreadcrumb(): array
{
$controller = Inflector::underscore($this->request->getParam('controller'));
$action = Inflector::underscore($this->request->getParam('action'));
if (empty($this->fullBreadcrumb[$controller]['routes']["{$controller}:{$action}"])) {
return []; // no breadcrumb defined for this endpoint
}
$currentRoute = $this->fullBreadcrumb[$controller]['routes']["{$controller}:{$action}"];
$breadcrumbPath = $this->getBreadcrumbPath("{$controller}:{$action}", $currentRoute);
return $breadcrumbPath['objects'];
}
public function getBreadcrumbPath(string $startRoute, array $currentRoute): array
{
$route = $startRoute;
$path = [
'routes' => [],
'objects' => [],
];
$visited = [];
while (empty($visited[$route])) {
$visited[$route] = true;
$path['routes'][] = $route;
$path['objects'][] = $currentRoute;
if (!empty($currentRoute['after'])) {
$route = $currentRoute['after'];
$split = explode(':', $currentRoute['after']);
$currentRoute = $this->fullBreadcrumb[$split[0]]['routes'][$currentRoute['after']];
}
}
$path['routes'] = array_reverse($path['routes']);
$path['objects'] = array_reverse($path['objects']);
return $path;
}
private function insertInheritance(array $config, array $fullConfig): array
{
if (!empty($config['routes'])) {
foreach ($config['routes'] as $routeName => $value) {
$config['routes'][$routeName]['route_path'] = $routeName;
if (!empty($value['inherit'])) {
$default = $config['defaults'][$value['inherit']] ?? [];
$config['routes'][$routeName] = array_merge($config['routes'][$routeName], $default);
unset($config['routes'][$routeName]['inherit']);
}
}
}
return $config;
}
private function insertRelated(array $config, array $fullConfig): array
{
if (!empty($config['routes'])) {
foreach ($config['routes'] as $routeName => $value) {
if (!empty($value['links'])) {
foreach ($value['links'] as $i => $linkedRoute) {
$split = explode(':', $linkedRoute);
if (!empty($fullConfig[$split[0]]['routes'][$linkedRoute])) {
$linkedRouteObject = $fullConfig[$split[0]]['routes'][$linkedRoute];
if (!empty($linkedRouteObject)) {
$config['routes'][$routeName]['links'][$i] = $linkedRouteObject;
continue;
}
}
unset($config['routes'][$routeName]['links'][$i]);
}
}
if (!empty($value['actions'])) {
foreach ($value['actions'] as $i => $linkedRoute) {
$split = explode(':', $linkedRoute);
if (!empty($fullConfig[$split[0]]['routes'][$linkedRoute])) {
$linkedRouteObject = $fullConfig[$split[0]]['routes'][$linkedRoute];
if (!empty($linkedRouteObject)) {
$config['routes'][$routeName]['actions'][$i] = $linkedRouteObject;
continue;
}
}
unset($config['routes'][$routeName]['actions'][$i]);
}
}
}
}
return $config;
}
public function genBreadcrumb(): array
{
$fullConfig = [
'broods' => [
'defaults' => [
'depth-1' => [
'after' => 'broods:index',
'textGetter' => 'name',
'links' => [
'broods:view',
'broods:edit',
'local_tools:brood_tools',
],
'actions' => [
'broods:delete',
],
]
],
'routes' => [
'broods:index' => [
'label' => __('Broods'),
'icon' => 'network-wired',
'url' => '/broods/index',
],
'broods:view' => [
'label' => __('View'),
'inherit' => 'depth-1',
'url' => '/broods/view/{{id}}',
'url_vars' => ['id' => 'id'],
],
'broods:edit' => [
'label' => __('Edit'),
'inherit' => 'depth-1',
'url' => '/broods/edit/{{id}}',
'url_vars' => ['id' => 'id'],
],
'broods:delete' => [
'label' => __('Delete'),
'inherit' => 'depth-1',
'url' => '/broods/delete/{{id}}',
'url_vars' => ['id' => 'id'],
],
]
],
'local_tools' => [
'routes' => [
'local_tools:brood_tools' => [
'label' => __('Brood Tools'),
'icon' => 'tools',
'url' => '/localTools/broodTools/{{id}}',
'url_vars' => ['id' => 'id'],
]
]
]
];
foreach ($fullConfig as $controller => $config) {
$fullConfig[$controller] = $this->insertInheritance($config, $fullConfig);
}
foreach ($fullConfig as $controller => $config) {
$fullConfig[$controller] = $this->insertRelated($config, $fullConfig);
}
return $fullConfig;
// return [
// 'Broods' => [
// 'index' => [
// 'label' => 'Broods',
// 'icon' => 'network-wired',
// 'url' => ['controller' => 'Broods', 'action' => 'index'],
// 'children' => [
// 'view' => [
// 'textGetter' => 'name',
// 'url' => ['controller' => 'Broods', 'action' => 'view', 'argsGetter' => ['id']],
// 'links' => [
// 'view' => [
// 'label' => __('View'),
// 'url' => ['controller' => 'Broods', 'action' => 'view', 'argsGetter' => ['id']],
// ],
// 'local_tools' => [
// 'textGetter' => 'name',
// 'url' => ['controller' => 'Broods', 'action' => 'delete', 'argsGetter' => ['id']],
// ],
// ],
// 'actions' => [
// 'edit' => [
// 'label' => __('Edit'),
// 'url' => ['controller' => 'Broods', 'action' => 'edit', 'argsGetter' => ['id']],
// ],
// 'delete' => [
// 'label' => __('Delete'),
// 'url' => ['controller' => 'Broods', 'action' => 'delete', 'argsGetter' => ['id']],
// ],
// ],
// ],
// ],
// ],
// ],
// ];
}
}

View File

@ -49,7 +49,7 @@ class DataFromPathHelper extends Helper
if (empty($strArg['function'])) {
$varValue = $options['sanitize'] ? h($varValue) : $varValue;
}
$extractedVars[] = $varValue;
$extractedVars[$i] = $varValue;
}
foreach ($extractedVars as $i => $value) {
$value = $options['highlight'] ? "<span class=\"font-weight-light\">${value}</span>" : $value;

View File

@ -1,6 +1,8 @@
<div class="container-fluid">
<div class="left-navbar">
<span class="navbar-brand">Logo</span>
<a class="navbar-brand" href="<?= $baseurl ?>">
<?= $this->Html->image('cerebrate-icon.svg', ['alt' => 'Cerebrate', 'height' => 50]) ?>
</a>
</div>
<div class="center-navbar">
<?= $this->element('layouts/header/header-center'); ?>

View File

@ -1,9 +1,15 @@
<?php
$this->Breadcrumbs->add([
['title' => 'Broods', 'url' => ['controller' => 'Broods', 'action' => 'index']],
['title' => 'Self', 'url' => ['controller' => 'Broods', 'action' => 'view', 4]],
[]
]);
use Cake\Core\Configure;
$controller = $this->request->getParam('controller');
$action = $this->request->getParam('action');
$curentPath = "{$controller}{$action}";
$navbarVariant = Configure::read('navbarVariant');
$navbarIsDark = Configure::read('navbarIsDark');
// $pass = $this->request->getParam('pass');
$breadcrumbLinks = '';
$breadcrumbAction = '';
$this->Breadcrumbs->setTemplates([
'wrapper' => sprintf(
'<nav class="header-breadcrumb"{{attrs}}><ol class="">{{content}}</ol></nav>'
@ -15,12 +21,67 @@
'itemWithoutLink' => '<li class="header-breadcrumb-item"{{attrs}}><span{{innerAttrs}}>{{title}}</span></li>{{separator}}',
'separator' => '<li class="header-breadcrumb-separator"{{attrs}}><span{{innerAttrs}}><i class="fa fa-sm fa-angle-right"></i></span></li>'
]);
if (!empty($breadcrumb)) {
foreach ($breadcrumb as $entry) {
if (!empty($entry['textGetter'])) {
$entry['label'] = Cake\Utility\Hash::get($entity, $entry['textGetter']);
}
if (!empty($entry['url_vars'])) {
$entry['url'] = $this->DataFromPath->buildStringFromDataPath($entry['url'], $entity, $entry['url_vars']);
}
$this->Breadcrumbs->add($entry['label'], $entry['url']);
}
$lastCrumb = $breadcrumb[count($breadcrumb)-1];
if (!empty($lastCrumb['links']) || !empty($lastCrumb['actions'])) {
$this->Breadcrumbs->add([[]]); // add last separetor
}
if (!empty($lastCrumb['links'])) {
foreach ($lastCrumb['links'] as $i => $linkEntry) {
$active = $linkEntry['route_path'] == $lastCrumb['route_path'];
if (!empty($linkEntry['url_vars'])) {
$linkEntry['url'] = $this->DataFromPath->buildStringFromDataPath($linkEntry['url'], $entity, $linkEntry['url_vars']);
}
$breadcrumbLinks .= sprintf('<a class="btn btn-%s btn-sm text-nowrap" role="button" href="%s">%s</a>',
$active ? 'secondary' : $navbarVariant,
$linkEntry['url'],
$linkEntry['label']
);
}
}
if (!empty($lastCrumb['actions'])) {
foreach ($lastCrumb['actions'] as $i => $actionEntry) {
if (!empty($actionEntry['url_vars'])) {
$actionEntry['url'] = $this->DataFromPath->buildStringFromDataPath($actionEntry['url'], $entity, $actionEntry['url_vars']);
}
$breadcrumbAction .= sprintf('<a class="dropdown-item" href="%s">%s</a>', $actionEntry['url'], $actionEntry['label']);
}
}
}
?>
<?php
echo $this->Breadcrumbs->render(
[],
['separator' => '']
);
?>
<div class="header-breadcrumb-children">
<a class="btn btn-secondary btn-sm" role="button" href="#">View</a>
<a class="btn btn-primary btn-sm" role="button" href="#">Local tools</a>
</div>
<?php if (!empty($breadcrumbLinks)): ?>
<div class="header-breadcrumb-children">
<?= $breadcrumbLinks ?>
</div>
<?php endif; ?>
<?php if (!empty($breadcrumbAction)): ?>
<div class="dropdown ml-3 d-flex align-items-center">
<a class="btn btn-primary dropdown-toggle" href="#" role="button" id="dropdownMenuBreadcrumbAction" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<?= __('Actions') ?>
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuBreadcrumbAction">
<?= $breadcrumbAction ?>
</div>
</div>
<?php endif; ?>

View File

@ -13,8 +13,15 @@
* @license https://opensource.org/licenses/mit-license.php MIT License
* @var \App\View\AppView $this
*/
use Cake\Core\Configure;
$cakeDescription = 'Cerebrate';
$navbarVariant = !empty($darkMode) ? 'primary' : 'dark';
$navbarIsDark = false;
$sidebarVariant = !empty($darkMode) ? 'dark' : 'dark';
Configure::write('navbarVariant', $navbarVariant);
Configure::write('navbarIsDark', $navbarIsDark);
Configure::write('sidebarVariant', $sidebarVariant);
?>
<!DOCTYPE html>
<html>
@ -50,14 +57,14 @@ $cakeDescription = 'Cerebrate';
</head>
<body>
<div class="main-wrapper">
<header class="navbar top-navbar <?= empty($darkMode) ? 'bg-dark navbar-dark' : 'bg-light navbar-light' ?>">
<header class="navbar top-navbar <?= sprintf('bg-%s navbar-%s', $navbarVariant, $navbarIsDark ? 'light' : 'dark') ?>">
<?= $this->element('layouts/header') ?>
</header>
<div class="sidebar <?= empty($darkMode) ? 'bg-light' : 'bg-dark' ?>">
<?= $this->element('layouts/sidebar') ?>
</div>
<main role="main" class="content">
<div class="container-fluid">
<div class="container-fluid mt-1">
<?= $this->Flash->render() ?>
<?= $this->fetch('content') ?>
</div>

View File

@ -7,7 +7,7 @@
}
body {
background-color: #eee;
/* background-color: #eee; */
}
.main-wrapper {
@ -23,6 +23,8 @@ body {
right: 0;
padding: 0;
margin-bottom: 0;
z-index: 1200;
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 2px 6px 0 rgba(0,0,0,0.12);
}
main.content {
@ -30,7 +32,6 @@ main.content {
left: 0;
margin-left: var(--sidebar-width-collapsed);
min-height: 100%;
background: red;
}
.sidebar {
@ -95,6 +96,7 @@ main.content {
.sidebar-wrapper {
width: 100%;
height: 100%;
border-right: 1px solid #ddd;
}
.sidebar-scroll {
@ -274,10 +276,12 @@ ul.sidebar-elements > li.category > span.category-divider > hr {
/*
Header
*/
header.navbar-dark.top-navbar a:hover {
header.navbar-dark.top-navbar .header-menu > a:hover,
header.navbar-dark.top-navbar .header-breadcrumb .header-breadcrumb-item > a:hover {
color: #d6d6d6 !important;
}
header.navbar-light.top-navbar a:hover {
header.navbar-light.top-navbar .header-menu > a:hover,
header.navbar-light.top-navbar .header-breadcrumb .header-breadcrumb-item > a:hover {
color: #6c757d !important;
}
@ -312,7 +316,7 @@ header.navbar-light.top-navbar a:hover {
}
.center-navbar nav.header-breadcrumb li.header-breadcrumb-item a {
text-decoration: none;
/* text-decoration: none; */
}
.navbar-dark .center-navbar nav.header-breadcrumb li.header-breadcrumb-item a{
@ -323,7 +327,10 @@ header.navbar-light.top-navbar a:hover {
}
.header-breadcrumb-children {
background-color: #eeeeee;
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.07),
inset 0 -1px 2px rgba(0, 0, 0, 0.5),
inset 0 3px 5px rgba(0, 0, 0, 0.6);
border-radius: 0.25rem;
padding: 0 0.5rem;
display: flex;

View File

@ -1,3 +1,7 @@
:root {
--cerebrate-color: #924da6;
}
.pagination li.page-item > a.page-link > .ellipsis {
line-height: 12px;
vertical-align: top;