Merge branch 'ui-navigation' into develop-unstable

pull/72/head
mokaddem 2021-09-17 17:12:33 +02:00
commit 0d8841a3bf
109 changed files with 100863 additions and 8596 deletions

View File

@ -18,18 +18,18 @@ $footerButtons = [
$tools = sprintf(
'<div class="mx-auto mb-3 mw-75 d-flex align-items-center">
<span class="flex-grow-1 text-right" style="font-size: large;">%s</span>
<span class="flex-grow-1 text-end" style="font-size: large;">%s</span>
<span class="mx-3">%s</span>
<span class="flex-grow-1 text-left" style="font-size: large;">%s</span>
<span class="flex-grow-1 text-start" style="font-size: large;">%s</span>
</div>',
sprintf('<span class="mr-2 d-inline-flex flex-column"><a href="%s" target="_blank" title="%s">%s</a><i style="font-size: medium;" class="text-center">%s</i></span>',
sprintf('<span class="me-2 d-inline-flex flex-column"><a href="%s" target="_blank" title="%s">%s</a><i style="font-size: medium;" class="text-center">%s</i></span>',
sprintf('/localTools/view/%s', h($request['localTool']->id)),
h($request['localTool']->description),
h($request['localTool']->name),
__('(local tool)')
),
sprintf('<i class="%s fa-lg"></i>', $this->FontAwesome->getClass('long-arrow-alt-right')),
sprintf('<span class="ml-2 d-inline-flex flex-column"><a href="%s" target="_blank" title="%s">%s</a><i style="font-size: medium;" class="text-center">%s</i></span>',
sprintf('<span class="ms-2 d-inline-flex flex-column"><a href="%s" target="_blank" title="%s">%s</a><i style="font-size: medium;" class="text-center">%s</i></span>',
sprintf('/localTools/broodTools/%s', h($request['data']['remote_tool']['id'])),
h($request['data']['remote_tool']['description'] ?? ''),
h($request['data']['remote_tool']['name']),
@ -77,9 +77,9 @@ $requestData = $this->Bootstrap->collapse([
sprintf('<pre class="p-2 rounded mb-0" style="background: #eeeeee55;"><code>%s</code></pre>', json_encode($request['data']['sent'], JSON_PRETTY_PRINT))
);
$rows = sprintf('<tr><td class="font-weight-bold">%s</td><td>%s</td></tr>', __('URL'), h($request['data']['url']));
$rows .= sprintf('<tr><td class="font-weight-bold">%s</td><td>%s</td></tr>', __('Reason'), h($request['data']['reason']['message']) ?? '');
$rows .= sprintf('<tr><td class="font-weight-bold">%s</td><td>%s</td></tr>', __('Errors'), h(json_encode($request['data']['reason']['errors'])) ?? '');
$rows = sprintf('<tr><td class="fw-bold">%s</td><td>%s</td></tr>', __('URL'), h($request['data']['url']));
$rows .= sprintf('<tr><td class="fw-bold">%s</td><td>%s</td></tr>', __('Reason'), h($request['data']['reason']['message']) ?? '');
$rows .= sprintf('<tr><td class="fw-bold">%s</td><td>%s</td></tr>', __('Errors'), h(json_encode($request['data']['reason']['errors'])) ?? '');
$table2 = sprintf('<table class="table table-sm table-borderless"><tbody>%s</tbody></table>', $rows);
$form = $this->element('genericElements/Form/genericForm', [

View File

@ -40,6 +40,7 @@ class AppController extends Controller
public $isRest = null;
public $restResponsePayload = null;
public $user = null;
public $breadcrumb = [];
/**
* Initialization hook method.
@ -75,6 +76,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);
@ -123,10 +127,12 @@ 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')['ui.dark']));
$this->set('baseurl', Configure::read('App.fullBaseUrl'));
Configure::write('app.bsTheme', 'default');
$this->set('bsTheme',Configure::read('app.bsTheme'));
if ($this->modelClass == 'Tags.Tags') {
$this->set('metaGroup', !empty($this->isAdmin) ? 'Administration' : 'Cerebrate');

View File

@ -14,12 +14,16 @@ use Cake\Error\Debugger;
class AuthKeysController extends AppController
{
public $filterFields = ['Users.username', 'authkey', 'comment', 'Users.id'];
public $quickFilterFields = ['authkey', ['comment' => true]];
public $containFields = ['Users'];
public function index()
{
$this->CRUD->index([
'filters' => ['Users.username', 'authkey', 'comment', 'Users.id'],
'quickFilters' => ['authkey', 'comment'],
'contain' => ['Users'],
'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields,
'contain' => $this->containFields,
'exclude_fields' => ['authkey']
]);
$responsePayload = $this->CRUD->getResponsePayload();

View File

@ -10,17 +10,21 @@ use Cake\ORM\TableRegistry;
class BroodsController extends AppController
{
public $filterFields = ['Broods.name', 'Broods.uuid', 'Broods.url', 'Broods.description', 'Organisations.id', 'Broods.trusted', 'pull', 'authkey'];
public $quickFilterFields = [['Broods.name' => true], 'Broods.uuid', ['Broods.description' => true]];
public $containFields = ['Organisations'];
public function index()
{
$this->CRUD->index([
'filters' => ['Broods.name', 'Broods.uuid', 'Broods.url', 'Broods.description', 'Organisations.id', 'Broods.trusted', 'pull', 'authkey'],
'quickFilters' => [['Broods.name' => true], 'Broods.uuid', ['Broods.description' => true]],
'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields,
'contextFilters' => [
'fields' => [
'pull',
]
],
'contain' => ['Organisations']
'contain' => $this->containFields
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {

View File

@ -11,11 +11,13 @@ use Cake\ORM\TableRegistry;
use Cake\Core\Configure;
use Cake\Core\Configure\Engine\PhpConfig;
use Cake\Utility\Inflector;
use Cake\Routing\Router;
class ACLComponent extends Component
{
private $user = null;
protected $components = ['Navigation'];
public function initialize(array $config): void
{
@ -453,475 +455,7 @@ class ACLComponent extends Component
public function getMenu()
{
$open = Configure::read('Cerebrate.open');
$menu = [
'ContactDB' => [
'Individuals' => [
'label' => __('Individuals'),
'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'),
'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'),
'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'),
'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'),
'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'),
'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'),
'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'),
'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'),
'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
]
],
'skipTopMenu' => true,
],
'Tags' => [
'label' => __('Tags'),
'url' => '/tags/index',
'children' => [
'index' => [
'url' => '/tags/index',
'label' => __('List Tags'),
],
'view' => [
'url' => '/tags/view/{{id}}',
'label' => __('View Tags'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => true,
],
'delete' => [
'url' => '/tags/delete/{{id}}',
'label' => __('Delete Tag'),
'actions' => ['delete', 'edit', 'view'],
'skipTopMenu' => true,
'popup' => 1
],
]
],
'MetaTemplates' => [
'label' => __('Meta Field Templates'),
'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'),
'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',
'children' => [
'settings' => [
'url' => '/instance/settings',
'label' => __('Settings')
],
'migration' => [
'url' => '/instance/migrationIndex',
'label' => __('Database migration')
]
]
],
],
'Cerebrate' => [
'Roles' => [
'label' => __('Roles'),
'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',
'children' => [
'home' => [
'url' => '/instance/home',
'label' => __('Home')
],
]
],
'Users' => [
__('My Profile'),
'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'),
'url' => '/open/organisations/index',
'children' => [
'index' => [
'url' => '/open/organisations/index',
'label' => __('List organisations')
],
],
'open' => in_array('organisations', Configure::read('Cerebrate.open'))
],
'Individuals' => [
'label' => __('Individuals'),
'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

@ -656,7 +656,7 @@ class CRUDComponent extends Component
return $massagedFilters;
}
protected function setQuickFilters(array $params, \Cake\ORM\Query $query, array $quickFilterFields): \Cake\ORM\Query
public function setQuickFilters(array $params, \Cake\ORM\Query $query, array $quickFilterFields): \Cake\ORM\Query
{
$queryConditions = [];
$this->Controller->set('quickFilter', empty($quickFilterFields) ? [] : $quickFilterFields);

View File

@ -0,0 +1,411 @@
<?php
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Core\Configure;
use Cake\Utility\Inflector;
use Cake\Utility\Hash;
use Cake\Routing\Router;
use Cake\ORM\TableRegistry;
class NavigationComponent extends Component
{
private $user = null;
public $breadcrumb = null;
public $iconToTableMapping = [
'Individuals' => 'address-book',
'Organisations' => 'building',
'EncryptionKeys' => 'key',
'SharingGroups' => 'user-friends',
'Broods' => 'network-wired',
'Roles' => 'id-badge',
'Users' => 'users',
'Inbox' => 'inbox',
'Outbox' => 'inbox',
'MetaTemplates' => 'object-group',
'LocalTools' => 'tools',
'Instance' => 'server',
];
public function initialize(array $config): void
{
$this->request = $config['request'];
}
public function beforeFilter($event)
{
$this->fullBreadcrumb = $this->genBreadcrumb();
$this->breadcrumb = $this->getBreadcrumb();
}
public function getSideMenu(): array
{
return [
'ContactDB' => [
'Individuals' => [
'label' => __('Individuals'),
'icon' => $this->iconToTableMapping['Individuals'],
'url' => '/individuals/index',
],
'Organisations' => [
'label' => __('Organisations'),
'icon' => $this->iconToTableMapping['Organisations'],
'url' => '/organisations/index',
],
'EncryptionKeys' => [
'label' => __('Encryption keys'),
'icon' => $this->iconToTableMapping['EncryptionKeys'],
'url' => '/encryptionKeys/index',
]
],
'Trust Circles' => [
'SharingGroups' => [
'label' => __('Sharing Groups'),
'icon' => $this->iconToTableMapping['SharingGroups'],
'url' => '/sharingGroups/index',
]
],
'Sync' => [
'Broods' => [
'label' => __('Broods'),
'icon' => $this->iconToTableMapping['Broods'],
'url' => '/broods/index',
]
],
'Administration' => [
'Roles' => [
'label' => __('Roles'),
'icon' => $this->iconToTableMapping['Roles'],
'url' => '/roles/index',
],
'Users' => [
'label' => __('Users'),
'icon' => $this->iconToTableMapping['Users'],
'url' => '/users/index',
],
'Messages' => [
'label' => __('Messages'),
'icon' => $this->iconToTableMapping['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' => $this->iconToTableMapping['MetaTemplates'],
'url' => '/metaTemplates/index',
],
'LocalTools.index' => [
'label' => __('Local Tools'),
'icon' => $this->iconToTableMapping['LocalTools'],
'url' => '/localTools/index',
]
]
],
'LocalTools' => [
'label' => __('Instance'),
'icon' => $this->iconToTableMapping['LocalTools'],
'children' => [
'Database' => [
'label' => __('Database'),
'url' => '/instance/migrationIndex',
'icon' => 'database',
]
]
],
],
'Open' => [
'Organisations' => [
'label' => __('Organisations'),
'icon' => $this->iconToTableMapping['Organisations'],
'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' => $this->iconToTableMapping['Individuals'],
'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 = $this->request->getParam('controller');
$action = $this->request->getParam('action');
if (empty($this->fullBreadcrumb[$controller]['routes']["{$controller}:{$action}"])) {
return [[
'label' => $controller,
'url' => Router::url(['controller' => $controller, 'action' => $action]),
]]; // 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 getDefaultCRUDConfig(string $controller, array $overrides=[], array $merges=[]): array
{
$table = TableRegistry::getTableLocator()->get($controller);
$default = [
'defaults' => [
'depth-1' => [
'after' => "{$controller}:index",
'textGetter' => !empty($table->getDisplayField()) ? $table->getDisplayField() : 'id',
'links' => [
"{$controller}:view",
"{$controller}:edit",
],
'actions' => [
"{$controller}:delete",
],
]
],
'routes' => [
"{$controller}:index" => [
'label' => Inflector::humanize($controller),
'url' => "/{$controller}/index",
'icon' => $this->iconToTableMapping[$controller]
],
"{$controller}:view" => [
'label' => __('View'),
'icon' => 'eye',
'inherit' => 'depth-1',
'url' => "/{$controller}/view/{{id}}",
'url_vars' => ['id' => 'id'],
],
"{$controller}:edit" => [
'label' => __('Edit'),
'icon' => 'edit',
'inherit' => 'depth-1',
'url' => "/{$controller}/edit/{{id}}",
'url_vars' => ['id' => 'id'],
],
"{$controller}:delete" => [
'label' => __('Delete'),
'icon' => 'trash',
'inherit' => 'depth-1',
'url' => "/{$controller}/delete/{{id}}",
'url_vars' => ['id' => 'id'],
],
]
];
$merged = array_merge_recursive($default, $merges);
$overridden = array_replace_recursive($merged, $overrides);
return $overridden;
}
public function genBreadcrumb(): array
{
$fullConfig = [
'Individuals' => $this->getDefaultCRUDConfig('Individuals'),
'Organisations' => $this->getDefaultCRUDConfig('Organisations'),
'EncryptionKeys' => $this->getDefaultCRUDConfig('EncryptionKeys'),
'SharingGroups' => $this->getDefaultCRUDConfig('SharingGroups'),
'Broods' => $this->getDefaultCRUDConfig('Broods', [], [
'defaults' => ['depth-1' => ['links' => 'LocalTools:brood_tools']]
]),
'Roles' => $this->getDefaultCRUDConfig('Roles'),
'Users' => $this->getDefaultCRUDConfig('Users'),
'Inbox' => $this->getDefaultCRUDConfig('Inbox', [
'defaults' => ['depth-1' => [
'links' => ['Inbox:view', 'Inbox:process'],
'actions' => ['Inbox:process', 'Inbox:delete'],
]]
], [
'routes' => [
'Inbox:discard' => [
'label' => __('Discard request'),
'inherit' => 'depth-1',
'url' => '/inbox/discard/{{id}}',
'url_vars' => ['id' => 'id'],
],
'Inbox:process' => [
'label' => __('Process request'),
'inherit' => 'depth-1',
'url' => '/inbox/process/{{id}}',
'url_vars' => ['id' => 'id'],
],
]
]),
'Outbox' => $this->getDefaultCRUDConfig('Outbox', [
'defaults' => ['depth-1' => [
'links' => ['Outbox:view', 'Outbox:process'],
'actions' => ['Outbox:process', 'Outbox:delete'],
]]
], [
'routes' => [
'Outbox:discard' => [
'label' => __('Discard request'),
'inherit' => 'depth-1',
'url' => '/outbox/discard/{{id}}',
'url_vars' => ['id' => 'id'],
],
'Outbox:process' => [
'label' => __('Process request'),
'inherit' => 'depth-1',
'url' => '/outbox/process/{{id}}',
'url_vars' => ['id' => 'id'],
],
]
]),
'MetaTemplates' => $this->getDefaultCRUDConfig('MetaTemplates', [
'defaults' => ['depth-1' => [
'links' => ['MetaTemplates:view', ''], // '' to remove leftovers. Related to https://www.php.net/manual/en/function.array-replace-recursive.php#124705
'actions' => ['MetaTemplates:toggle'],
]]
], [
'routes' => [
'MetaTemplates:toggle' => [
'label' => __('Toggle Meta-template'),
'inherit' => 'depth-1',
'url' => '/MetaTemplates/toggle/{{id}}',
'url_vars' => ['id' => 'id'],
],
]
]),
'LocalTools' => [
'routes' => [
'LocalTools:index' => [
'label' => __('Local Tools'),
'url' => '/localTools/index',
'icon' => $this->iconToTableMapping['LocalTools'],
],
'LocalTools:viewConnector' => [
'label' => __('View'),
'textGetter' => 'name',
'url' => '/localTools/viewConnector/{{connector}}',
'url_vars' => ['connector' => 'connector'],
'after' => 'LocalTools:index',
],
'LocalTools:broodTools' => [
'label' => __('Brood Tools'),
'url' => '/localTools/broodTools/{{id}}',
'url_vars' => ['id' => 'id'],
],
]
],
'Instance' => [
'routes' => [
'Instance:home' => [
'label' => __('Home'),
'url' => '/',
'icon' => 'home'
],
'Instance:migrationIndex' => [
'label' => __('Database Migration'),
'url' => '/instance/migrationIndex',
'icon' => 'database'
],
]
]
];
foreach ($fullConfig as $controller => $config) {
$fullConfig[$controller] = $this->insertInheritance($config, $fullConfig);
}
foreach ($fullConfig as $controller => $config) {
$fullConfig[$controller] = $this->insertRelated($config, $fullConfig);
}
return $fullConfig;
}
}

View File

@ -14,17 +14,21 @@ use Cake\Error\Debugger;
class EncryptionKeysController extends AppController
{
public $filterFields = ['owner_model', 'organisation_id', 'individual_id', 'encryption_key'];
public $quickFilterFields = ['encryption_key'];
public $containFields = ['Individuals', 'Organisations'];
public function index()
{
$this->CRUD->index([
'quickFilters' => ['encryption_key'],
'filters' => ['owner_model', 'organisation_id', 'individual_id', 'encryption_key'],
'quickFilters' => $this->quickFilterFields,
'filters' => $this->filterFields,
'contextFilters' => [
'fields' => [
'type'
]
],
'contain' => ['Individuals', 'Organisations']
'contain' => $this->containFields
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {

View File

@ -16,7 +16,9 @@ use Cake\Http\Exception\ForbiddenException;
class InboxController extends AppController
{
public $filters = ['scope', 'action', 'title', 'origin', 'comment'];
public $filterFields = ['scope', 'action', 'title', 'origin', 'comment'];
public $quickFilterFields = ['scope', 'action', ['title' => true], ['comment' => true]];
public $containFields = ['Users'];
public function beforeFilter(EventInterface $event)
{
@ -28,14 +30,14 @@ class InboxController extends AppController
public function index()
{
$this->CRUD->index([
'filters' => $this->filters,
'quickFilters' => ['scope', 'action', ['title' => true], ['comment' => true]],
'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields,
'contextFilters' => [
'fields' => [
'scope',
]
],
'contain' => ['Users']
'contain' => $this->containFields
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {

View File

@ -13,19 +13,21 @@ use Cake\ORM\TableRegistry;
class IndividualsController extends AppController
{
public $filters = ['uuid', 'email', 'first_name', 'last_name', 'position', 'Organisations.id', 'Alignments.type'];
public $quickFilterFields = ['uuid', ['email' => true], ['first_name' => true], ['last_name' => true], 'position'];
public $filterFields = ['uuid', 'email', 'first_name', 'last_name', 'position', 'Organisations.id', 'Alignments.type'];
public $containFields = ['Alignments' => 'Organisations'];
public function index()
{
$this->CRUD->index([
'filters' => $this->filters,
'quickFilters' => ['uuid', 'email', 'first_name', 'last_name', 'position'],
'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields,
'contextFilters' => [
'fields' => [
'Alignments.type'
]
],
'contain' => ['Alignments' => 'Organisations']
'contain' => $this->containFields
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {

View File

@ -6,6 +6,7 @@ use App\Controller\AppController;
use Cake\Utility\Hash;
use Cake\Utility\Text;
use \Cake\Database\Expression\QueryExpression;
use Cake\ORM\TableRegistry;
use Cake\Event\EventInterface;
use Cake\Core\Configure;
@ -32,6 +33,24 @@ class InstanceController extends AppController
return $this->RestResponse->viewData($data, 'json');
}
public function searchAll()
{
$searchValue = $this->request->getQuery('search');
$model = $this->request->getQuery('model', null);
$limit = $this->request->getQuery('limit', 5);
if (!empty($this->request->getQuery('show_all', false))) {
$limit = null;
}
$data = [];
if (!empty($searchValue)) {
$data = $this->Instance->searchAll($searchValue, $limit, $model);
}
if ($this->ParamHandler->isRest()) {
return $this->RestResponse->viewData($data, 'json');
}
$this->set('data', $data);
}
public function migrationIndex()
{
$migrationStatus = $this->Instance->getMigrationStatus();

View File

@ -9,11 +9,15 @@ use \Cake\Database\Expression\QueryExpression;
class MetaTemplateFieldsController extends AppController
{
public $quickFilterFields = ['field', 'type'];
public $filterFields = ['field', 'type', 'meta_template_id'];
public $containFields = [];
public function index()
{
$this->CRUD->index([
'filters' => ['field', 'type', 'meta_template_id'],
'quickFilters' => ['field', 'type']
'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {

View File

@ -9,6 +9,9 @@ use \Cake\Database\Expression\QueryExpression;
class MetaTemplatesController extends AppController
{
public $quickFilterFields = ['name', 'uuid', 'scope'];
public $filterFields = ['name', 'uuid', 'scope', 'namespace'];
public $containFields = ['MetaTemplateFields'];
public function update()
{
@ -34,8 +37,8 @@ class MetaTemplatesController extends AppController
public function index()
{
$this->CRUD->index([
'filters' => ['name', 'uuid', 'scope', 'namespace'],
'quickFilters' => ['name', 'uuid', 'scope'],
'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields,
'contextFilters' => [
'fields' => ['scope'],
'custom' => [
@ -49,7 +52,7 @@ class MetaTemplatesController extends AppController
],
]
],
'contain' => ['MetaTemplateFields']
'contain' => $this->containFields
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {

View File

@ -13,13 +13,15 @@ use Cake\Http\Exception\ForbiddenException;
class OrganisationsController extends AppController
{
public $filters = ['name', 'uuid', 'nationality', 'sector', 'type', 'url', 'Alignments.id', 'MetaFields.field', 'MetaFields.value', 'MetaFields.MetaTemplates.name'];
public $quickFilterFields = [['name' => true], 'uuid', 'nationality', 'sector', 'type', 'url'];
public $filterFields = ['name', 'uuid', 'nationality', 'sector', 'type', 'url', 'Alignments.id', 'MetaFields.field', 'MetaFields.value', 'MetaFields.MetaTemplates.name'];
public $containFields = ['Alignments' => 'Individuals'];
public function index()
{
$this->CRUD->index([
'filters' => $this->filters,
'quickFilters' => [['name' => true], 'uuid', 'nationality', 'sector', 'type', 'url'],
'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields,
'contextFilters' => [
'custom' => [
[
@ -57,7 +59,7 @@ class OrganisationsController extends AppController
]
],
],
'contain' => ['Alignments' => 'Individuals']
'contain' => $this->containFields
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {

View File

@ -16,7 +16,9 @@ use Cake\Http\Exception\ForbiddenException;
class OutboxController extends AppController
{
public $filters = ['scope', 'action', 'title', 'comment'];
public $filterFields = ['scope', 'action', 'title', 'comment'];
public $quickFilterFields = ['scope', 'action', ['title' => true], ['comment' => true]];
public $containFields = ['Users'];
public function beforeFilter(EventInterface $event)
{
@ -28,14 +30,14 @@ class OutboxController extends AppController
public function index()
{
$this->CRUD->index([
'filters' => $this->filters,
'quickFilters' => ['scope', 'action', ['title' => true], ['comment' => true]],
'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields,
'contextFilters' => [
'fields' => [
'scope',
]
],
'contain' => ['Users']
'contain' => $this->containFields
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {

View File

@ -12,11 +12,15 @@ use Cake\Http\Exception\ForbiddenException;
class RolesController extends AppController
{
public $filterFields = ['name', 'uuid', 'perm_admin', 'Users.id'];
public $quickFilterFields = ['name'];
public $containFields = [];
public function index()
{
$this->CRUD->index([
'filters' => ['name', 'uuid', 'perm_admin', 'Users.id'],
'quickFilters' => ['name']
'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {

View File

@ -10,11 +10,16 @@ use Cake\Error\Debugger;
class SharingGroupsController extends AppController
{
public $filterFields = ['SharingGroups.uuid', 'SharingGroups.name', 'description', 'releasability', 'Organisations.name', 'Organisations.uuid'];
public $quickFilterFields = ['SharingGroups.uuid', ['SharingGroups.name' => true], ['description' => true], ['releasability' => true]];
public $containFields = ['SharingGroupOrgs', 'Organisations', 'Users' => ['fields' => ['id', 'username']]];
public function index()
{
$this->CRUD->index([
'contain' => ['SharingGroupOrgs', 'Organisations', 'Users' => ['fields' => ['id', 'username']]],
'filters' => ['uuid', 'description', 'releasability', 'Organisations.name', 'Organisations.uuid']
'contain' => $this->containFields,
'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {

View File

@ -9,12 +9,16 @@ use \Cake\Database\Expression\QueryExpression;
class UsersController extends AppController
{
public $filterFields = ['Individuals.uuid', 'username', 'Individuals.email', 'Individuals.first_name', 'Individuals.last_name'];
public $quickFilterFields = ['Individuals.uuid', ['username' => true], ['Individuals.first_name' => true], ['Individuals.last_name' => true], 'Individuals.email'];
public $containFields = ['Individuals', 'Roles'];
public function index()
{
$this->CRUD->index([
'contain' => ['Individuals', 'Roles'],
'filters' => ['Users.email', 'uuid'],
'quickFilters' => ['uuid', ['username' => true], ['Individuals.first_name' => true], ['Individuals.last_name' => true], 'Individuals.email'],
'contain' => $this->containFields,
'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields,
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {

View File

@ -7,11 +7,13 @@ use Cake\ORM\Table;
use Cake\ORM\TableRegistry;
use Cake\Validation\Validator;
use Migrations\Migrations;
use Cake\Http\Exception\MethodNotAllowedException;
class InstanceTable extends AppTable
{
protected $activePlugins = ['Tags'];
public $seachAllTables = ['Broods', 'Individuals', 'Organisations', 'SharingGroups', 'Users', 'EncryptionKeys', ];
public function initialize(array $config): void
{
parent::initialize($config);
@ -39,9 +41,9 @@ class InstanceTable extends AppTable
->order(['date']);
$data = $query->toArray();
$interval = new \DateInterval('P1D');
$period = new \DatePeriod(new \DateTime("-{$days} days"), $interval ,new \DateTime());
$period = new \DatePeriod(new \DateTime("-{$days} days"), $interval, new \DateTime());
$timeline = [];
foreach($period as $date){
foreach ($period as $date) {
$timeline[$date->format("Y-m-d")] = [
'time' => $date->format("Y-m-d"),
'count' => 0
@ -63,6 +65,60 @@ class InstanceTable extends AppTable
return $statistics;
}
public function searchAll($value, $limit=5, $model=null)
{
$results = [];
$models = $this->seachAllTables;
if (!is_null($model)) {
if (in_array($model, $this->seachAllTables)) {
$models = [$model];
} else {
return $results; // Cannot search in this model
}
}
foreach ($models as $tableName) {
$controller = $this->getController($tableName);
$table = TableRegistry::get($tableName);
$query = $table->find();
$quickFilterOptions = $this->getQuickFiltersFieldsFromController($controller);
$containFields = $this->getContainFieldsFromController($controller);
if (empty($quickFilterOptions)) {
continue; // make sure we are filtering on something
}
$params = ['quickFilter' => $value];
$query = $controller->CRUD->setQuickFilters($params, $query, $quickFilterOptions);
if (!empty($containFields)) {
$query->contain($containFields);
}
$results[$tableName]['amount'] = $query->count();
$result = $query->limit($limit)->all()->toList();
if (!empty($result)) {
$results[$tableName]['entries'] = $result;
}
}
return $results;
}
public function getController($name)
{
$controllerName = "\\App\\Controller\\{$name}Controller";
if (!class_exists($controllerName)) {
throw new MethodNotAllowedException(__('Model `{0}` does not exists', $model));
}
$controller = new $controllerName;
return $controller;
}
public function getQuickFiltersFieldsFromController($controller)
{
return !empty($controller->quickFilterFields) ? $controller->quickFilterFields : [];
}
public function getContainFieldsFromController($controller)
{
return !empty($controller->containFields) ? $controller->containFields : [];
}
public function getMigrationStatus()
{
$migrations = new Migrations();

View File

@ -19,7 +19,7 @@ class MetaTemplatesTable extends AppTable
'foreignKey' => 'meta_template_id'
]
);
$this->setDisplayField('field');
$this->setDisplayField('name');
}
public function validationDefault(Validator $validator): Validator

View File

@ -133,6 +133,12 @@ class BootstrapHelper extends Helper
{
return BootstrapGeneric::genNode($node, $params, $content);
}
public function switch($options)
{
$bsSwitch = new BoostrapSwitch($options, $this);
return $bsSwitch->switch();
}
}
class BootstrapGeneric
@ -201,12 +207,10 @@ class BootstrapGeneric
{
return BootstrapGeneric::genNode('button', [
'type' => 'button',
'class' => 'close',
'data-dismiss' => $dismissTarget,
'class' => 'btn-close',
'data-bs-dismiss' => $dismissTarget,
'arial-label' => __('Close')
], BootstrapGeneric::genNode('span', [
'arial-hidden' => 'true'
], '&times;'));
]);
}
protected static function getTextClassForVariant($variant)
@ -377,7 +381,7 @@ class BootstrapTabs extends BootstrapGeneric
$html .= $this->openNode('div', ['class' => array_merge(
[
($this->options['vertical-size'] != 'auto' ? 'col-' . $this->options['vertical-size'] : ''),
($this->options['card'] ? 'card-header border-right' : '')
($this->options['card'] ? 'card-header border-end' : '')
],
[
"bg-{$this->options['header-variant']}",
@ -426,7 +430,7 @@ class BootstrapTabs extends BootstrapGeneric
[!empty($navItem['active']) ? 'active' : ''],
[!empty($navItem['disabled']) ? 'disabled' : '']
),
'data-toggle' => $this->options['pills'] ? 'pill' : 'tab',
'data-bs-toggle' => $this->options['pills'] ? 'pill' : 'tab',
'id' => $navItem['id'] . '-tab',
'href' => '#' . $navItem['id'],
'aria-controls' => $navItem['id'],
@ -829,7 +833,6 @@ class BoostrapButton extends BootstrapGeneric {
'variant' => 'primary',
'outline' => false,
'size' => '',
'block' => false,
'icon' => null,
'class' => [],
'type' => 'button',
@ -868,9 +871,6 @@ class BoostrapButton extends BootstrapGeneric {
if (!empty($this->options['size'])) {
$this->bsClasses[] = "btn-{$this->options['size']}";
}
if ($this->options['block']) {
$this->bsClasses[] = 'btn-block';
}
if ($this->options['variant'] == 'text') {
$this->bsClasses[] = 'p-0';
$this->bsClasses[] = 'lh-1';
@ -904,7 +904,7 @@ class BoostrapButton extends BootstrapGeneric {
private function genIcon()
{
$bsIcon = new BoostrapIcon($this->options['icon'], [
'class' => ['mr-1']
'class' => ['me-1']
]);
return $bsIcon->icon();
}
@ -947,8 +947,8 @@ class BoostrapBadge extends BootstrapGeneric {
$html = $this->genNode('span', [
'class' => array_merge($this->options['class'], [
'badge',
"badge-{$this->options['variant']}",
$this->options['pill'] ? 'badge-pill' : '',
"bg-{$this->options['variant']}",
$this->options['pill'] ? 'rounded-pill' : '',
]),
'title' => $this->options['title']
], h($this->options['text']));
@ -1115,7 +1115,7 @@ class BoostrapModal extends BootstrapGeneric {
'variant' => 'primary',
'text' => __('Ok'),
'params' => [
'data-dismiss' => $this->options['confirmFunction'] ? '' : 'modal',
'data-bs-dismiss' => $this->options['confirmFunction'] ? '' : 'modal',
'onclick' => $this->options['confirmFunction']
]
]))->button();
@ -1132,7 +1132,7 @@ class BoostrapModal extends BootstrapGeneric {
'variant' => 'secondary',
'text' => h($this->options['cancelText']),
'params' => [
'data-dismiss' => 'modal',
'data-bs-dismiss' => 'modal',
'onclick' => $this->options['cancelFunction']
]
]))->button();
@ -1142,7 +1142,7 @@ class BoostrapModal extends BootstrapGeneric {
'text' => h($this->options['confirmText']),
'class' => 'modal-confirm-button',
'params' => [
// 'data-dismiss' => $this->options['confirmFunction'] ? '' : 'modal',
// 'data-bs-dismiss' => $this->options['confirmFunction'] ? '' : 'modal',
'data-confirmFunction' => sprintf('%s', $this->options['confirmFunction'])
]
]))->button();
@ -1158,7 +1158,7 @@ class BoostrapModal extends BootstrapGeneric {
'text' => h($buttonConfig['text']),
'class' => 'modal-confirm-button',
'params' => [
'data-dismiss' => !empty($buttonConfig['clickFunction']) ? '' : 'modal',
'data-bs-dismiss' => !empty($buttonConfig['clickFunction']) ? '' : 'modal',
'data-clickFunction' => sprintf('%s', $buttonConfig['clickFunction'])
]
]))->button();
@ -1261,6 +1261,58 @@ class BoostrapCard extends BootstrapGeneric
}
}
class BoostrapSwitch extends BootstrapGeneric {
private $defaultOptions = [
'label' => '',
'variant' => 'primary',
'disabled' => false,
'checked' => false,
'title' => ''
];
function __construct($options) {
$this->allowedOptionValues = [
'variant' => BootstrapGeneric::$variants,
];
$this->processOptions($options);
}
private function processOptions($options)
{
$this->options = array_merge($this->defaultOptions, $options);
$this->checkOptionValidity();
}
public function switch()
{
return $this->genSwitch();
}
private function genSwitch()
{
$tmpId = 'tmp-' . mt_rand();
$html = $this->genNode('div', [
'class' => [
'form-check form-switch',
],
'title' => $this->options['title']
], implode('', [
$this->genNode('input', [
'type' => "checkbox",
'class' => 'orm-check-input',
'id' => $tmpId,
($this->options['disabled'] ? 'disabled' : '') => '',
($this->options['checked'] ? 'checked' : '') => $this->options['checked'] ? 'checked' : ''
]),
$this->genNode('label', [
'class' => 'orm-check-label',
'for' => $tmpId,
], h($this->options['label']))
]));
return $html;
}
}
class BoostrapProgress extends BootstrapGeneric {
private $defaultOptions = [
'value' => 0,
@ -1349,7 +1401,7 @@ class BoostrapCollapse extends BootstrapGeneric {
{
$html = $this->genNode('a', [
'class' => ['text-decoration-none'],
'data-toggle' => 'collapse',
'data-bs-toggle' => 'collapse',
'href' => '#collapseExample',
'role' => 'button',
'aria-expanded' => 'false',
@ -1459,7 +1511,7 @@ class BoostrapProgressTimeline extends BootstrapGeneric {
return $this->genNode('li', [
'class' => [
'text-center',
'font-weight-bold',
'fw-bold',
$isActive ? 'progress-active' : 'progress-inactive',
],
], h($step['text'] ?? ''));

View File

@ -49,10 +49,10 @@ 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;
$value = $options['highlight'] ? "<span class=\"fw-light\">${value}</span>" : $value;
$str = str_replace(
"{{{$i}}}",
$value,

View File

@ -5,9 +5,9 @@ echo $this->element('genericElements/genericModal', [
'<p>%s</p><p>%s</p><p>%s</p>',
__('Please make sure that you note down the authkey below, this is the only time the authkey is shown in plain text, so make sure you save it. If you lose the key, simply remove the entry and generate a new one.'),
__('Cerebrate will use the first and the last 4 digit for identification purposes.'),
sprintf('%s: <span class="font-weight-bold">%s</span>', __('Authkey'), h($entity->authkey_raw))
sprintf('%s: <span class="fw-bold">%s</span>', __('Authkey'), h($entity->authkey_raw))
),
'actionButton' => sprintf('<button" class="btn btn-primary" data-dismiss="modal">%s</button>', __('I have noted down my key, take me back now')),
'actionButton' => sprintf('<button" class="btn btn-primary" data-bs-dismiss="modal">%s</button>', __('I have noted down my key, take me back now')),
'noCancel' => true,
'staticBackdrop' => true,
]);

View File

@ -130,7 +130,7 @@ echo $this->element('genericElements/IndexTable/index_table', [
)
const $footer = $(modalObject.ajaxApi.statusNode).parent()
modalObject.ajaxApi.statusNode.remove()
const $cancelButton = $footer.find('button[data-dismiss="modal"]')
const $cancelButton = $footer.find('button[data-bs-dismiss="modal"]')
$cancelButton.text('<?= __('OK') ?>').removeClass('btn-secondary').addClass('btn-primary')
}
UI.submissionModal('/inbox/delete', successCallback, failCallback).then(([modalObject, ajaxApi]) => {

View File

@ -27,4 +27,4 @@
?>
</div>
<?php endforeach ?>
</div>
</div>

View File

@ -0,0 +1,68 @@
<?php
$sections = [];
foreach ($data as $tableName => $tableResult) {
if (empty($tableResult['amount'])) {
continue;
}
$section = '';
$table = Cake\ORM\TableRegistry::get($tableName);
$fieldPath = !empty($table->getDisplayField()) ? $table->getDisplayField() : 'id';
$section .= sprintf('<span class="d-flex text-nowrap px-2 search-container-model">
<span class="text-uppercase text-muted me-3 model-text">%s</span>
<span class="d-flex align-items-center search-container-divider">
<hr class="m-0"/>
</span>
<span class="fw-light text-muted ms-3 model-text">%s</span>
</span>', h($tableName), $tableResult['amount']);
foreach ($tableResult['entries'] as $entry) {
$section .= sprintf('<a class="dropdown-item" href="%s">%s</a>',
Cake\Routing\Router::URL([
'controller' => Cake\Utility\Inflector::pluralize($entry->getSource()),
'action' => 'view',
h($entry['id'])
]),
h($entry[$fieldPath])
);
}
$remaining = $tableResult['amount'] - count($tableResult['entries']);
if ($remaining > 0) {
$section .= sprintf('<a href="%s" class="dropdown-item total-found d-block pe-2">%s <strong class="total-found-number text-primary">%s</strong><span class="total-found-text d-inline ms-1" href="#">%s</span></a>',
Cake\Routing\Router::URL([
'controller' => 'instance',
'action' => 'search_all',
'?' => [
'model' => h($tableName),
'search' => h($this->request->getParam('?')['search'] ?? ''),
'show_all' => 1
]
]),
__('Load'),
$remaining,
__('more results')
);
}
$sections[] = $section;
}
if (!empty($ajax)) {
$sections[] = sprintf('<a class="dropdown-item border-top text-center text-muted p-2" href="%s"><i class="%s me-2"></i>%s</a>',
Cake\Routing\Router::URL([
'controller' => 'instance',
'action' => 'search_all',
'?' => [
'search' => h($this->request->getParam('?')['search'] ?? '')
]
]),
$this->FontAwesome->getClass('search-plus'),
__('View all results')
);
} else {
echo sprintf('<h2 class="fw-light mb-4">%s <span class="font-monospace">%s</span></h2>', __('Global search results for:'), h($this->request->getParam('?')['search'] ?? ''));
}
if (!empty($sections)) {
echo implode('', $sections);
} else {
echo sprintf('<span class="dropdown-item p-0 pb-1 text-center">%s</span>', __('- No result -'));
}

View File

@ -69,8 +69,8 @@ echo $this->element('genericElements/IndexTable/index_table', [
$conflictingTemplate = getConflictingTemplate($row, $data);
if (!empty($conflictingTemplate)) {
return sprintf(
"<span class=\"text-danger font-weight-bolder\">%s</span> %s.<br />
<ul><li><span class=\"font-weight-bolder\">%s</span> %s <span class=\"font-weight-bolder\">%s</span></li></ul>",
"<span class=\"text-danger fw-bolder\">%s</span> %s.<br />
<ul><li><span class=\"fw-bolder\">%s</span> %s <span class=\"fw-bolder\">%s</span></li></ul>",
__('Conflict with:'),
$this->Html->link(
h($conflictingTemplate->name),

View File

@ -1,10 +1,16 @@
<?php
echo $this->Html->image('logo-purple.png', ['alt' => 'CakePHP', 'class="form-signin"']);
echo '<div class="form-signin">';
$template = [
'inputContainer' => '<div class="form-floating input {{type}}{{required}}">{{content}}</div>',
'formGroup' => '{{input}}{{label}}',
'submitContainer' => '<div class="submit d-grid">{{content}}</div>',
];
$this->Form->setTemplates($template);
echo $this->Form->create(null, ['url' => ['controller' => 'users', 'action' => 'login']]);
echo $this->Form->control('username', ['label' => false, 'class' => 'form-control', 'placeholder' => __('Username')]);
echo $this->Form->control('password', ['type' => 'password', 'label' => false, 'class' => 'form-control', 'placeholder' => __('Password')]);
echo $this->Form->submit(__('Submit'), ['class' => 'btn btn-lg btn-primary btn-block']);
echo $this->Form->control('username', ['label' => 'Username', 'class' => 'form-control mb-2', 'placeholder' => __('Username')]);
echo $this->Form->control('password', ['type' => 'password', 'label' => 'Password', 'class' => 'form-control mb-3', 'placeholder' => __('Password')]);
echo $this->Form->control(__('Submit'), ['type' => 'submit', 'class' => 'btn btn-primary']);
echo $this->Form->end();
echo '</div>';
?>

View File

@ -14,7 +14,6 @@ if (!isset($params['escape']) || $params['escape'] !== false) {
?>
<div class="alert <?= h($class) ?> alert-dismissible fade show" role="alert">
<?= $message ?>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
</button>
</div>

View File

@ -10,7 +10,6 @@ if (!isset($params['escape']) || $params['escape'] !== false) {
?>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<?= $message ?>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
</button>
</div>

View File

@ -10,7 +10,6 @@ if (!isset($params['escape']) || $params['escape'] !== false) {
?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<?= $message ?>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
</button>
</div>

View File

@ -2,6 +2,6 @@
$controlParams = [
'options' => $fieldData['options'],
'empty' => $fieldData['empty'] ?? false,
'class' => ($fieldData['class'] ?? '') . ' formDropdown custom-select'
'class' => ($fieldData['class'] ?? '') . ' formDropdown form-select'
];
echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $fieldData);

View File

@ -9,11 +9,11 @@
$label = $fieldData['label'];
$formElement = $this->FormFieldMassage->prepareFormElement($this->Form, $params, $fieldData);
$temp = sprintf(
'<div class="form-group row ">
<div class="col-sm-2 col-form-label">%s</div>
'<div class="row mb-3">
<div class="col-sm-2 form-label">%s</div>
<div class="col-sm-10">
<div class="input-group">
%s<span class="input-group-append">%s</span>
%s<span>%s</span>
</div>
</div>
</div>',

View File

@ -17,7 +17,7 @@
}
}
echo sprintf(
'<span id = "%sInfoPopover" class="icon-info-sign" data-toggle="popover" data-trigger="hover"></span>',
'<span id = "%sInfoPopover" class="icon-info-sign" data-bs-toggle="popover" data-bs-trigger="hover"></span>',
h($field['field'])
);
?>

View File

@ -28,16 +28,16 @@
$formRandomValue = Cake\Utility\Security::randomString(8);
$formCreate = $this->Form->create($entity, ['id' => 'form-' . $formRandomValue]);
$default_template = [
'inputContainer' => '<div class="form-group row">{{content}}</div>',
'inputContainerError' => '<div class="form-group row has-error">{{content}}</div>',
'inputContainer' => '<div class="row mb-3">{{content}}</div>',
'inputContainerError' => '<div class="row mb-3 has-error">{{content}}</div>',
'label' => '{{text}}',
'input' => '<input type="{{type}}" name="{{name}}"{{attrs}} />',
'textarea' => '<textarea name="{{name}}" {{attrs}}>{{value}}</textarea>',
'select' => '<select name="{{name}}" {{attrs}}>{{content}}</select>',
'checkbox' => '<input type="checkbox" name="{{name}}" value="{{value}}"{{attrs}}>',
'checkboxFormGroup' => '{{label}}',
'formGroup' => '<div class="col-sm-2 col-form-label" {{attrs}}>{{label}}</div><div class="col-sm-10">{{input}}{{error}}</div>',
'nestingLabel' => '{{hidden}}<div class="col-sm-2 col-form-label">{{text}}</div><div class="col-sm-10">{{input}}</div>',
'formGroup' => '<div class="col-sm-2 form-label" {{attrs}}>{{label}}</div><div class="col-sm-10">{{input}}{{error}}</div>',
'nestingLabel' => '{{hidden}}<div class="col-sm-2 form-label">{{text}}</div><div class="col-sm-10">{{input}}</div>',
'option' => '<option value="{{value}}"{{attrs}}>{{text}}</option>',
'optgroup' => '<optgroup label="{{label}}"{{attrs}}>{{content}}</optgroup>',
'select' => '<select name="{{name}}"{{attrs}}>{{content}}</select>',
@ -98,7 +98,7 @@
'body' => sprintf(
'%s%s%s%s%s%s',
empty($data['description']) ? '' : sprintf(
'<div class="pb-2">%s</div>',
'<div class="pb-2 fw-light">%s</div>',
$data['description']
),
$ajaxFlashMessage,
@ -106,8 +106,12 @@
$fieldsString,
empty($metaTemplateString) ? '' : $this->element(
'genericElements/accordion_scaffold', [
'body' => $metaTemplateString,
'title' => 'Meta fields'
'children' => [
[
'body' => $metaTemplateString,
'title' => 'Meta fields'
]
]
]
),
$formEnd
@ -127,28 +131,36 @@
$fieldsString,
empty($metaTemplateString) ? '' : $this->element(
'genericElements/accordion_scaffold', [
'body' => $metaTemplateString,
'title' => 'Meta fields'
'children' => [
[
'body' => $metaTemplateString,
'title' => 'Meta fields'
]
]
]
),
$formEnd
);
} else {
echo sprintf(
'%s<h2>%s</h2>%s%s%s%s%s%s%s%s%s',
'%s<h2 class="fw-light">%s</h2>%s%s%s%s%s%s%s%s%s',
empty($ajax) ? '<div class="col-8">' : '',
empty($data['title']) ? sprintf('%s %s', $actionName, $modelName) : h($data['title']),
$formCreate,
$ajaxFlashMessage,
empty($data['description']) ? '' : sprintf(
'<div class="pb-3">%s</div>',
'<div class="pb-3 fw-light">%s</div>',
$data['description']
),
$fieldsString,
sprintf('<div class="panel">%s</div>', $fieldsString),
empty($metaTemplateString) ? '' : $this->element(
'genericElements/accordion_scaffold', [
'body' => $metaTemplateString,
'title' => 'Meta fields',
'children' => [
[
'body' => $metaTemplateString,
'title' => 'Meta fields',
]
],
'class' => 'mb-2'
]
),

View File

@ -17,7 +17,7 @@
* - function($row, $options): the lambda function. $row contain the row data
* - options: array of options. datapaths described in the datapath keyname will be extracted and replaced with the actual row value
*/
echo '<td class="action-links text-right text-nowrap">';
echo '<td class="action-links text-end text-nowrap">';
foreach ($actions as $action) {
if (isset($action['requirement']) && !$action['requirement']) {
continue;
@ -100,7 +100,7 @@
$action['onclick'] = sprintf('UI.submissionModalForIndex(\'%s\', \'%s\', \'%s\')', $modal_url, $reload_url, $tableRandomValue);
}
echo sprintf(
'<a href="%s" title="%s" aria-label="%s" %s %s class="link-unstyled"><i class="%s"></i></a> ',
'<a href="%s" title="%s" aria-label="%s" %s %s class="text-decoration-none text-reset table-link-action"><i class="%s"></i></a> ',
$url,
empty($action['title']) ? '' : h($action['title']),
empty($action['title']) ? '' : h($action['title']),

View File

@ -5,7 +5,7 @@ $canRemove = $this->request->getParam('prefix') !== 'Open';
if ($field['scope'] === 'individuals') {
foreach ($raw_alignments as $alignment) {
$alignments .= sprintf(
'<div><span class="font-weight-bold">%s</span> @ %s <a href="#" class="fas fa-trash .text-reset .text-decoration-none" onClick="%s"></a></div>',
'<div><span class="fw-bold">%s</span> @ %s <a href="#" class="fas fa-trash .text-reset .text-decoration-none" onClick="%s"></a></div>',
h($alignment['type']),
sprintf(
'<a href="%sorganisations/view/%s">%s</a>',
@ -25,7 +25,7 @@ if ($field['scope'] === 'individuals') {
} else if ($field['scope'] === 'organisations') {
foreach ($raw_alignments as $alignment) {
$alignments .= sprintf(
'<div>[<span class="font-weight-bold">%s</span>] %s <a href="#" class="fas fa-trash .text-reset .text-decoration-none" onClick="%s"></a></div>',
'<div>[<span class="fw-bold">%s</span>] %s <a href="#" class="fas fa-trash .text-reset .text-decoration-none" onClick="%s"></a></div>',
h($alignment['type']),
sprintf(
'<a href="%sindividuals/view/%s">%s</a>',

View File

@ -2,12 +2,12 @@
$start = $this->Hash->extract($row, 'authkey_start')[0];
$end = $this->Hash->extract($row, 'authkey_end')[0];
echo sprintf(
'<div>%s: <span class="font-weight-bold text-info">%s</span></div>',
'<div>%s: <span class="fw-bold text-info">%s</span></div>',
__('Starts with'),
h($start)
);
echo sprintf(
'<div>%s: <span class="font-weight-bold text-info">%s</span></div>',
'<div>%s: <span class="fw-bold text-info">%s</span></div>',
__('Ends with'),
h($end)
);

View File

@ -48,7 +48,7 @@
(!empty($this->Hash->extract($row, $field['data_path'])[0])) ? 'check' : 'times',
empty($rules_raw) ? '' :
sprintf(
' <span data-toggle="popover" title="%s" data-content="%s">(%s)</span>',
' <span data-bs-toggle="popover" title="%s" data-bs-content="%s">(%s)</span>',
__('Filter rules'),
$rules_raw,
__('Rules')

View File

@ -14,12 +14,12 @@
$data = h($data);
if (is_numeric($data)) {
if ($data == 0) {
$data = '<span class="text-primary font-weight-bold">' . __('Indefinite') . '</span>';
$data = '<span class="text-primary fw-bold">' . __('Indefinite') . '</span>';
} else {
if ($data <= time()) {
$data = '<span class="text-danger font-weight-bold">' . __('Expired') . '</span>';
$data = '<span class="text-danger fw-bold">' . __('Expired') . '</span>';
} else {
$data = '<span class="text-success font-weight-bold">' . date('Y-m-d H:i:s', $data) . '</span>';
$data = '<span class="text-success fw-bold">' . date('Y-m-d H:i:s', $data) . '</span>';
}
}
}

View File

@ -14,7 +14,7 @@
]
];
echo sprintf(
'<span class="font-weight-bold">%s</span>: %s',
'<span class="fw-bold">%s</span>: %s',
$types[$type]['name'],
$this->Html->link(
sprintf(

View File

@ -29,7 +29,7 @@
}
if ($actions) {
$headersHtml .= sprintf(
'<th class="actions text-right">%s</th>',
'<th class="actions text-end">%s</th>',
__('Actions')
);
}

View File

@ -19,14 +19,15 @@
$tableRandomValue = Cake\Utility\Security::randomString(8);
echo '<div id="table-container-' . h($tableRandomValue) . '">';
if (!empty($data['title'])) {
echo sprintf('<h2>%s</h2>', h($data['title']));
echo sprintf('<h2 class="fw-light">%s</h2>', h($data['title']));
}
if (!empty($data['description'])) {
echo sprintf(
'<div>%s</div>',
'<div class="fw-light">%s</div>',
empty($data['description']) ? '' : h($data['description'])
);
}
echo '<div class="panel">';
if (!empty($data['html'])) {
echo sprintf('<div>%s</div>', $data['html']);
}
@ -121,6 +122,7 @@
echo $this->element('/genericElements/IndexTable/pagination_links');
}
echo '</div>';
echo '</div>';
?>
<script type="text/javascript">
$(document).ready(function() {

View File

@ -18,7 +18,7 @@
}
}
echo sprintf(
'<a class="btn btn-small btn-dropdown-toggle %s %s" %s %s data-toggle="dropdown" href="#" %s>%s%s%s <span class="caret"></span></a><ul class="dropdown-menu">%s</ul>',
'<a class="btn btn-small btn-dropdown-toggle %s %s" %s %s data-bs-toggle="dropdown" href="#" %s>%s%s%s <span class="caret"></span></a><ul class="dropdown-menu">%s</ul>',
empty($data['class']) ? '' : h($data['class']),
empty($data['active']) ? 'btn-inverse' : 'btn-primary', // Change the default class for highlighted/active toggles here
empty($data['id']) ? '' : 'id="' . h($data['id']) . '"',

View File

@ -15,7 +15,7 @@
]);
}
echo sprintf(
'<div class="multi_select_actions btn-group mr-2 flex-wrap collapse" role="group" aria-label="button-group" data-table-random-value="%s">%s</div>',
'<div class="multi_select_actions btn-group me-2 flex-wrap collapse" role="group" aria-label="button-group" data-table-random-value="%s">%s</div>',
$tableRandomValue,
$buttons
);

View File

@ -36,7 +36,7 @@
$filteringButton = $this->Bootstrap->button($buttonConfig);
}
$button = empty($data['button']) && empty($data['fa-icon']) ? '' : sprintf(
'<div class="input-group-append"><button class="btn btn-primary" %s id="quickFilterButton-%s" %s>%s%s</button>%s</div>',
'<button class="btn btn-primary" %s id="quickFilterButton-%s" %s>%s%s</button>%s',
empty($data['data']) ? '' : h($data['data']),
h($tableRandomValue),
$filterEffective ? '' : 'disabled="disabled"',

View File

@ -5,7 +5,7 @@
$elements .= $this->element('/genericElements/ListTopBar/element_' . (empty($element['type']) ? 'simple' : h($element['type'])), array('data' => $element, 'tableRandomValue' => $tableRandomValue));
}
echo sprintf(
'<div %s class="btn-group btn-group-sm mr-2 flex-wrap" role="group" aria-label="button-group">%s</div>',
'<div %s class="btn-group btn-group-sm me-2 flex-wrap" role="group" aria-label="button-group">%s</div>',
(!empty($data['id'])) ? 'id="' . h($data['id']) . '"' : '',
$elements
);

View File

@ -11,7 +11,7 @@ if (!empty($field['path'])) {
if ($field['scope'] === 'individuals') {
foreach ($extracted['alignments'] as $alignment) {
$alignments .= sprintf(
'<div><span class="font-weight-bold">%s</span> @ %s <a href="#" class="fas fa-trash" onClick="%s"></a></div>',
'<div><span class="fw-bold">%s</span> @ %s <a href="#" class="fas fa-trash" onClick="%s"></a></div>',
h($alignment['type']),
sprintf(
'<a href="%sorganisations/view/%s">%s</a>',
@ -31,7 +31,7 @@ if ($field['scope'] === 'individuals') {
} else if ($field['scope'] === 'organisations') {
foreach ($extracted['alignments'] as $alignment) {
$alignments .= sprintf(
'<div>[<span class="font-weight-bold">%s</span>] %s <a href="#" class="fas fa-trash" onClick="%s"></a></div>',
'<div>[<span class="fw-bold">%s</span>] %s <a href="#" class="fas fa-trash" onClick="%s"></a></div>',
h($alignment['type']),
sprintf(
'<a href="%sindividuals/view/%s">%s</a>',

View File

@ -18,13 +18,13 @@
'<div class="card-header" id="heading-%s"><h5 class="mb0">%s</h5></div>',
$randomId,
sprintf(
'<button class="btn btn-link" data-toggle="collapse" data-target="#view-child-%s" aria-expanded="true" aria-controls="collapseOne">%s</button>',
'<button class="btn btn-link" data-bs-toggle="collapse" data-bs-target="#view-child-%s" aria-expanded="true" aria-controls="collapseOne">%s</button>',
$randomId,
h($child['title'])
)
),
sprintf(
'<div class="collapse %s" id="view-child-%s" data-parent="#accordion" labelledby="heading-%s"><div id="view-child-body-%s" class="card-body" data-content-url="%s" data-load-on="%s"></div></div>',
'<div class="collapse %s" id="view-child-%s" data-bs-parent="#accordion" labelledby="heading-%s"><div id="view-child-body-%s" class="card-body" data-content-url="%s" data-load-on="%s"></div></div>',
!empty($child['collapsed']) ? 'show' : 'collapsed',
$randomId,
$randomId,

View File

@ -79,7 +79,7 @@
$title;
echo sprintf(
"<div id=\"single-view-table-container-%s\">
<h2>%s</h2>
<h2 class=\"fw-light\">%s</h2>
%s%s
<div>%s</div>
<div id=\"metafieldsPanel\" class=\"col-lg-8 px-0\">%s</div>

View File

@ -1,13 +1,20 @@
<?php
$randomId = Cake\Utility\Security::randomString(8);
$accordionId = Cake\Utility\Security::randomString(8);
?>
<div id="accordion" class="<?= !empty($class) ? $class : '' ?>">
<div class="card">
<div class="card-header" id="heading-<?= $randomId ?>">
<h5 class="mb0"><a href="#" class="btn btn-link" data-toggle="collapse" data-target="#view-child-<?= $randomId ?>" aria-expanded="true" aria-controls="collapseOne"><?= h($title) ?></a></h5>
<div class="accordion <?= !empty($class) ? $class : '' ?>" id="accordion-<?= $accordionId ?>">
<?php foreach ($children as $child): ?>
<?php $childId = Cake\Utility\Security::randomString(8); ?>
<div class="accordion-item">
<h2 class="accordion-header" id="heading-<?= $childId ?>">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-<?= $childId ?>" aria-expanded="false" aria-controls="collapse-<?= $childId ?>">
<?= h($child['title']) ?>
</button>
</h2>
<div id="collapse-<?= $childId ?>" class="accordion-collapse collapse" aria-labelledby="heading-<?= $accordionId ?>" data-bs-parent="#accordion-<?= $accordionId ?>">
<div class="accordion-body">
<?= $child['body'] ?>
</div>
</div>
</div>
<div class="collapse collapsed" id="view-child-<?= $randomId ?>" data-parent="#accordion" labelledby="heading-<?= $randomId ?>">
<div id="view-child-body-<?= $randomId ?>" class="card-body" data-load-on="ready"><?= $body ?></div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>

View File

@ -1,9 +1,8 @@
<div class="modal-dialog <?= empty($class) ? '' : h($class) ?>" <?= !empty($staticBackdrop) ? 'data-backdrop="static"' : ''?> role="document">
<div class="modal-dialog <?= empty($class) ? '' : h($class) ?>" <?= !empty($staticBackdrop) ? 'data-bs-backdrop="static"' : ''?> role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?= h($title) ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
</button>
</div>
<div class="modal-body">
@ -11,7 +10,7 @@
</div>
<div class="modal-footer">
<?php if (empty($noCancel)): ?>
<button type="button" class="btn btn-secondary cancel-button" data-dismiss="modal"><?= __('Cancel') ?></button>
<button type="button" class="btn btn-secondary cancel-button" data-bs-dismiss="modal"><?= __('Cancel') ?></button>
<?php endif; ?>
<?= $actionButton ?>
</div>

View File

@ -41,7 +41,7 @@ foreach ($data['menu'] as $name => $menuElement) {
$navdata .= sprintf(
'<li class="nav-item dropdown">%s%s</li>',
sprintf(
'<a class="nav-link dropdown-toggle" href="#" id="%s" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">%s</a>',
'<a class="nav-link dropdown-toggle" href="#" id="%s" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">%s</a>',
'dropdown-label-' . h($i),
h($name)
),
@ -58,7 +58,7 @@ $logoutButton = sprintf(
__('Logout')
);
$navdata = sprintf(
'<div class="collapse navbar-collapse" id="navbarCollapse"><ul class="navbar-nav mr-auto">%s%s</ul></div>',
'<div class="collapse navbar-collapse" id="navbarCollapse"><ul class="navbar-nav me-auto">%s%s</ul></div>',
$navdata,
$logoutButton
);
@ -73,6 +73,6 @@ echo sprintf(
'<nav class="navbar navbar-expand-lg navbar-dark %s">%s%s%s</nav>',
$darkMode ? 'bg-primary' : 'bg-dark',
$homeButton,
'<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>',
'<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>',
$navdata
);

View File

@ -36,7 +36,7 @@ if (isset($menu[$metaGroup])) {
echo sprintf(
'<div class="dropdown show">%s%s</div>',
sprintf(
'<a class="btn btn-secondary dropdown-toggle" href="#" role="button" id="sideMenuDropdownLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">%s</a>',
'<a class="btn btn-secondary dropdown-toggle" href="#" role="button" id="sideMenuDropdownLink" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">%s</a>',
__('Navigation')
),
sprintf(

View File

@ -1,10 +1,11 @@
<?php
// return;
$children = '';
$backgroundColour = $darkMode ? 'bg-dark' : 'bg-light';
if (isset($menu[$metaGroup])) {
foreach ($menu[$metaGroup] as $scope => $scopeData) {
$children .= sprintf(
'<a href="%s" class="font-weight-bold list-group-item list-group-item-action %s %s pl-1 border-0">%s</a>',
'<a href="%s" class="fw-bold list-group-item list-group-item-action %s %s ps-1 border-0">%s</a>',
empty($scopeData['url']) ? '#' : $baseurl . '/' . h($scopeData['url']),
empty($scopeData['class']) ? '' : h($scopeData['class']),
$backgroundColour,
@ -35,9 +36,9 @@ if (isset($menu[$metaGroup])) {
}
$active = ($scope === $this->request->getParam('controller') && $action === $this->request->getParam('action'));
if (!empty($data['popup'])) {
$link_template = '<a href="#" onClick="UI.submissionModalAutoGuess(\'%s\')" class="list-group-item list-group-item-action %s %s pl-3 border-0 %s">%s</a>';
$link_template = '<a href="#" onClick="UI.submissionModalAutoGuess(\'%s\')" class="list-group-item list-group-item-action %s %s ps-3 border-0 %s">%s</a>';
} else {
$link_template = '<a href="%s" class="list-group-item list-group-item-action %s %s pl-3 border-0 %s">%s</a>';
$link_template = '<a href="%s" class="list-group-item list-group-item-action %s %s ps-3 border-0 %s">%s</a>';
}
$children .= sprintf(
$link_template,

View File

@ -0,0 +1,18 @@
<div class="container-fluid">
<div class="left-navbar">
<a class="navbar-brand d-sm-block d-none" href="<?= $baseurl ?>">
<div class="composed-app-icon-container">
<span class="app-icon w-100 h-100" title="<?= __('Cerebrate') ?>"></span>
</div>
</a>
<button class="navbar-toggler d-sm-none" type="button" data-bs-toggle="collapse" data-bs-target="#app-sidebar" aria-controls="app-sidebar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class="center-navbar">
<?= $this->element('layouts/header/header-breadcrumb'); ?>
</div>
<div class="right-navbar">
<?= $this->element('layouts/header/header-right'); ?>
</div>
</div>

View File

@ -0,0 +1,104 @@
<?php
use Cake\Core\Configure;
use Cake\Routing\Router;
$controller = $this->request->getParam('controller');
$action = $this->request->getParam('action');
$curentPath = "{$controller}{$action}";
$breadcrumbLinks = '';
$breadcrumbAction = '';
$this->Breadcrumbs->setTemplates([
'wrapper' => sprintf(
'<nav class="header-breadcrumb d-lg-block d-none"{{attrs}}><ol class="">{{content}}</ol></nav>'
),
'item' => '<li class="header-breadcrumb-item"{{attrs}}><i class="{{icon}} me-1"></i><a class="{{linkClass}}" href="{{url}}"{{innerAttrs}}>{{title}}</a></li>{{separator}}',
'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 $i => $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(h($entry['label']), Router::url($entry['url']), [
'title' => h($entry['label']),
'templateVars' => [
'linkClass' => $i == 0 ? 'fw-light' : '',
'icon' => ($i == 0 && !empty($entry['icon'])) ? $this->FontAwesome->getClass(h($entry['icon'])) : ''
]
]);
}
$lastCrumb = $breadcrumb[count($breadcrumb)-1];
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' : 'outline-secondary',
Router::url($linkEntry['url']),
h($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"><i class="me-1 %s"></i>%s</a>',
Router::url($actionEntry['url']),
!empty($entry['icon']) ? $this->FontAwesome->getClass(h($actionEntry['icon'])) : '',
h($actionEntry['label'])
);
}
}
}
?>
<?php
echo $this->Breadcrumbs->render(
[],
['separator' => '']
);
?>
<?php if (!empty($breadcrumbLinks) && !empty($breadcrumbAction)): ?>
<div class="breadcrumb-link-container position-absolute end-0 d-flex">
<?php endif; ?>
<?php if (!empty($breadcrumbLinks)): ?>
<div class="header-breadcrumb-children d-none d-md-flex btn-group">
<?= $breadcrumbLinks ?>
<a class="btn btn-primary btn-sm dropdown-toggle" href="#" role="button" id="dropdownMenuBreadcrumbAction" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<?= __('Actions') ?>
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownMenuBreadcrumbAction">
<?= $breadcrumbAction ?>
</div>
</div>
<?php endif; ?>
<?php if (!empty($breadcrumbAction) && false): ?>
<div class="header-breadcrumb-actions dropdown d-flex align-items-center">
<a class="btn btn-primary btn-sm dropdown-toggle" href="#" role="button" id="dropdownMenuBreadcrumbAction" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<?= __('Actions') ?>
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuBreadcrumbAction">
<?= $breadcrumbAction ?>
</div>
</div>
<?php endif; ?>
<?php if (!empty($breadcrumbLinks) && !empty($breadcrumbAction)): ?>
</div>
<?php endif; ?>

View File

@ -0,0 +1,13 @@
<?php
use Cake\Routing\Router;
?>
<div class="btn-group">
<a class="nav-link px-2 text-decoration-none profile-button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="#" data-bs-offset="10,20">
<i class="<?= $this->FontAwesome->getClass('bell') ?> fa-lg"></i>
</a>
<div class="dropdown-menu dropdown-menu-end">
<?php if (empty($notifications)): ?>
<h6 class="dropdown-header"><?= __('- No notification -') ?></h6>
<?php endif; ?>
</div>
</div>

View File

@ -0,0 +1,27 @@
<?php
use Cake\Routing\Router;
?>
<div class="btn-group">
<a class="nav-link px-2 text-decoration-none profile-button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="#" data-bs-offset="10,20">
<i class="<?= $this->FontAwesome->getClass('user-circle') ?> fa-lg"></i>
</a>
<div class="dropdown-menu dropdown-menu-end">
<h6 class="dropdown-header"><?= h($this->request->getAttribute('identity')['username']) ?></h6>
<a class="dropdown-item" href="<?= Router::url(['controller' => 'users', 'action' => 'view']) ?>">
<i class="me-1 <?= $this->FontAwesome->getClass('user-circle') ?>"></i>
<?= __('My Account') ?>
</a>
<a class="dropdown-item" href="<?= Router::url(['controller' => 'users', 'action' => 'userSettings']) ?>">
<i class="me-1 <?= $this->FontAwesome->getClass('user-cog') ?>"></i>
<?= __('Settings') ?>
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="<?= Router::url(['controller' => 'users', 'action' => 'logout']) ?>">
<i class="me-1 <?= $this->FontAwesome->getClass('sign-out-alt') ?>"></i>
<?= __('Logout') ?>
</a>
</div>
</div>
<style>
</style>

View File

@ -0,0 +1,15 @@
<div class="d-flex">
<div class="global-search-container d-md-block d-none">
<span class="search-input-container">
<input type="text" class="form-control d-inline-block" id="globalSearch" placeholder="<?= __('Search in Cerebrate...') ?>">
<i class="icon <?= $this->FontAwesome->getClass('search') ?>"></i>
</span>
<button type="button" class="dropdown-toggle d-none" id="dropdownMenuSearchAll" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"></button>
<div class="global-search-result-container dropdown-menu dropdown-menu-end p-0 pt-2" aria-labelledby="dropdownMenuSearchAll">
</div>
</div>
<div class="header-menu d-flex ms-1">
<?= $this->element('layouts/header/header-notifications') ?>
<?= $this->element('layouts/header/header-profile') ?>
</div>
</div>

View File

@ -0,0 +1,20 @@
<div class="sidebar-wrapper d-flex flex-column">
<div class="sidebar-scroll">
<div class="sidebar-content">
<ul class="sidebar-elements">
<?php foreach ($menu as $category => $categorized): ?>
<?= $this->element('layouts/sidebar/category', ['label' => $category]) ?>
<?php foreach ($categorized as $parentName => $parent): ?>
<?= $this->element('layouts/sidebar/entry', [
'parent' => $parent,
])
?>
<?php endforeach; ?>
<?php endforeach; ?>
</ul>
</div>
</div>
<span class="lock-sidebar align-self-center mt-auto w-100 d-none d-sm-block" onclick="$('.sidebar').toggleClass('expanded')">
<a type="button" class="btn btn-sm w-100"></a>
</span>
</div>

View File

@ -0,0 +1,4 @@
<li class="category text-muted">
<span class="category-label"><?= h($label) ?></span>
<span class="category-divider"><hr /></span>
</li>

View File

@ -0,0 +1,44 @@
<?php
$seed = 'sb-' . mt_rand();
$icon = $parent['icon'] ?? '';
$label = $parent['label'] ?? '';
$children = $parent['children'] ?? [];
$active = false;
if (!empty($children)) {
$url = "#{$seed}";
} else {
$url = $parent['url'] ?? '#';
}
$controller = \Cake\Utility\Inflector::variable($this->request->getParam('controller'));
$action = \Cake\Utility\Inflector::variable($this->request->getParam('action'));
$currentURL = "/{$controller}/{$action}";
if ($url == $currentURL) {
$active = true;
}
$hasActiveChild = false;
if (!empty($children)) {
$flattened = Cake\Utility\Hash::flatten($children);
$flattenedValues = array_values($flattened);
if (in_array($currentURL, $flattenedValues)) {
$hasActiveChild = true;
}
}
?>
<li class="<?= !empty($children) ? 'parent collapsed' : '' ?>">
<a class="sidebar-link <?= !empty($children) ? 'collapsed' : '' ?> <?= $active ? 'active' : '' ?> <?= $hasActiveChild ? 'have-active-child' : '' ?>" href="<?= h($url) ?>" <?= !empty($children) ? 'data-bs-toggle="collapse"' : '' ?> <?= $hasActiveChild ? 'aria-expanded="true"' : '' ?>>
<i class="sidebar-icon <?= $this->FontAwesome->getClass($icon) ?>"></i>
<span class="text"><?= h($label) ?></span>
</a>
<?php if (!empty($children)): ?>
<?= $this->element('layouts/sidebar/sub-menu', [
'seed' => $seed,
'children' => $children,
'open' => $hasActiveChild
]);
?>
<?php endif; ?>
</li>

View File

@ -0,0 +1,12 @@
<?php
$seed = $seed ?? 'sd-' . mt_rand();
?>
<ul id="<?= $seed ?>" class="sub-menu collapse <?= !empty($open) ? 'show' : '' ?>">
<?php foreach ($children as $child): ?>
<?= $this->element('layouts/sidebar/entry', [
'parent' => $child,
])
?>
<?php endforeach; ?>
</ul>

View File

@ -2,8 +2,7 @@
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?= h($title) ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
</button>
</div>
<div class="modal-body">
@ -16,7 +15,7 @@
['class' => 'btn btn-primary button-execute', 'id' => 'submitButton']
)
?>
<button type="button" class="btn btn-secondary cancel-button" data-dismiss="modal"><?= __('Cancel') ?></button>
<button type="button" class="btn btn-secondary cancel-button" data-bs-dismiss="modal"><?= __('Cancel') ?></button>
</div>
</div>
</div>

View File

@ -119,11 +119,11 @@ echo $this->Bootstrap->modal([
function addControlRow($filteringTable) {
const availableFilters = <?= json_encode($filters) ?>;
const $selectField = $('<select/>').addClass('fieldSelect custom-select custom-select-sm')
const $selectField = $('<select/>').addClass('fieldSelect form-select form-select-sm')
availableFilters.forEach(filter => {
$selectField.append($('<option/>').text(filter))
});
const $selectOperator = $('<select/>').addClass('fieldOperator custom-select custom-select-sm')
const $selectOperator = $('<select/>').addClass('fieldOperator form-select form-select-sm')
.append([
$('<option/>').text('=').val('='),
$('<option/>').text('!=').val('!='),
@ -145,7 +145,7 @@ echo $this->Bootstrap->modal([
}
function addFilteringRow($filteringTable, field, value, operator) {
const $selectOperator = $('<select/>').addClass('fieldOperator custom-select custom-select-sm')
const $selectOperator = $('<select/>').addClass('fieldOperator form-select form-select-sm')
.append([
$('<option/>').text('=').val('='),
$('<option/>').text('!=').val('!='),

View File

@ -13,6 +13,7 @@
* @license https://opensource.org/licenses/mit-license.php MIT License
* @var \App\View\AppView $this
*/
use Cake\Core\Configure;
$cakeDescription = 'Cerebrate';
?>
@ -27,18 +28,16 @@ $cakeDescription = 'Cerebrate';
</title>
<?= $this->Html->meta('icon') ?>
<?php
if (empty($darkMode)) {
echo $this->Html->css('bootstrap.css');
} else {
echo $this->Html->css('darkly-bootstrap.css');
}
echo $this->Html->css('themes/bootstrap-' . $bsTheme);
echo $this->Html->css('themes/theme-' . $bsTheme);
?>
<?= $this->Html->css('main.css') ?>
<?= $this->Html->css('font-awesome') ?>
<?= $this->Html->css('layout.css') ?>
<?= $this->Html->script('jquery-3.5.1.min.js') ?>
<?= $this->Html->script('popper.min.js') ?>
<?= $this->Html->script('bootstrap.bundle.js') ?>
<?= $this->Html->script('main.js') ?>
<?= $this->Html->script('utils.js') ?>
<?= $this->Html->script('bootstrap-helper.js') ?>
<?= $this->Html->script('api-helper.js') ?>
<?= $this->Html->script('select2.min.js') ?>
@ -70,28 +69,26 @@ $cakeDescription = 'Cerebrate';
<?= $this->Html->meta('favicon.ico', '/img/favicon.ico', ['type' => 'icon']); ?>
</head>
<body>
<header>
<?= $this->element('header') ?>
</header>
<main role="main">
<div class="container-fluid">
<div class="row">
<div class="col-1 d-none d-xl-block sidebar p-0">
<?= $this->element('side_menu') ?>
</div>
<div role="main" class="col-xl-11 col-lg-12 ml-sm-auto pt-3 px-4">
<div class="col-12 d-xl-none px-0"><?= $this->element('side_menu', ['minimal' => 1]) ?></div>
<?= $this->Flash->render() ?>
<?= $this->fetch('content') ?>
</div>
<div class="main-wrapper">
<header class="navbar top-navbar navbar-dark">
<?= $this->element('layouts/header') ?>
</header>
<nav id="app-sidebar" class="collapse d-sm-block sidebar">
<?= $this->element('layouts/sidebar') ?>
</nav>
<main role="main" class="content">
<div class="container-fluid mt-1">
<?= $this->Flash->render() ?>
<?= $this->fetch('content') ?>
</div>
</div>
</main>
</main>
</div>
<div id="mainModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mediumModalLabel" aria-hidden="true"></div>
<div id="mainToastContainer" style="position: absolute; top: 15px; right: 15px; z-index: 1080"></div>
<div id="mainModalContainer"></div>
</body>
<script>
const darkMode = (<?= empty($darkMode) ? 'false' : 'true' ?>)
const bsTheme = '<?= h($bsTheme); ?>'
</script>
</html>

View File

@ -8,7 +8,7 @@
<?= $this->fetch('title') ?>
</title>
<?= $this->Html->meta('icon') ?>
<?= $this->Html->css('bootstrap.css') ?>
<?= $this->Html->css('bootstrap-5.1.1.css') ?>
<?= $this->Html->css('login.css') ?>
<?= $this->Html->css('main.css') ?>
<?= $this->Html->css('font-awesome') ?>

View File

@ -0,0 +1,139 @@
/* body.light-mode {
background-color: #f1f2f4;
}
body.light-mode .sub-container {
background-color: white;
box-shadow: 0 0 35px 0 rgb(154 161 171 / 15%);
}
body.dark-mode .sub-container {
background-color: #363636;
border: 1px solid #454545;
} */
.sidebar {
box-shadow: 0 2px 2px 0 rgb(0 0 0 / 16%), 0 2px 6px 0 rgb(0 0 0 / 12%);
}
.sidebar ~ main.content:after {
background:#000;
}
.top-navbar {
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 2px 6px 0 rgba(0,0,0,0.12);
}
.light-mode .sidebar-wrapper {
border-right: 1px solid #ddd;
}
.light-mode .sidebar-wrapper {
border-right: 1px solid rgba(0, 0, 0, 0.125);
}
.light-mode ul.sidebar-elements li > a.sidebar-link.active {
background-color: #ebebeb;
}
.dark-mode ul.sidebar-elements li > a.sidebar-link.active {
background-color: #375a7f;
}
ul.sidebar-elements li > a.sidebar-link.active::after {
background-color: var(--cerebrate-color);
}
.light-mode .sidebar ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: #ebebeb;
}
.dark-mode .sidebar ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: #375a7f;
}
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: unset;
}
.sidebar ul.sidebar-elements li > a.sidebar-link.have-active-child::after {
background-color: var(--cerebrate-color);
}
ul.sidebar-elements li > a.sidebar-link {
color: unset;
}
.light-mode ul.sidebar-elements > li > a.sidebar-link:hover {
background-color: #f0f0f0;
}
.dark-mode ul.sidebar-elements > li > a.sidebar-link:hover {
background-color: #375a7f;
}
/* sidebar sub-menu */
ul.sidebar-elements li.parent > a.sidebar-link::before {
color: #bbb;
}
ul.sidebar-elements > li ul li > a.sidebar-link:hover {
background-color: #e0e0e0;
}
/*
Header
*/
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 .header-menu > a:hover,
header.navbar-light.top-navbar .header-breadcrumb .header-breadcrumb-item > a:hover {
color: #6c757d !important;
}
.center-navbar nav.header-breadcrumb {
color: white;
}
.navbar-dark .center-navbar nav.header-breadcrumb li.header-breadcrumb-item a{
color: white;
}
.navbar-light .center-navbar nav.header-breadcrumb li.header-breadcrumb-item a {
color: black;
}
.header-breadcrumb-children {
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);
}
.navbar-dark .right-navbar .header-menu a.nav-link {
color: white;
}
.navbar-light .right-navbar .header-menu a {
color: black;
}
.navbar-dark .left-navbar .navbar-brand img {
filter: invert(1);
}
.navbar-light .left-navbar .navbar-brand img {
filter: invert(0);
}
.navbar-dark .left-navbar .navbar-brand:hover img {
filter: invert(1) drop-shadow(0px 0px 3px #fff);
}
.navbar-light .left-navbar .navbar-brand:hover img {
filter: invert(0) drop-shadow(0px 0px 3px #000);
}
.navbar-light .composed-app-icon-container > .app-icon {
background-color: black;
}
.navbar-dark .composed-app-icon-container > .app-icon {
background-color: white;
}

492
webroot/css/layout.css Normal file
View File

@ -0,0 +1,492 @@
/* layout */
:root {
--navbar-height: 60px;
/* --navbar-height: 40px; */
--sidebar-width-expanded: 230px;
--sidebar-width-collapsed: 65px;
/* --sidebar-width-collapsed: 40px; */
}
body {
padding-top: var(--navbar-height);
margin-left: var(--sidebar-width-collapsed);
}
.panel {
padding: 0.75rem;
border-radius: 0.25rem;
margin-top: 0.75rem;
margin-bottom: 1rem;
}
/* navbar-toggler breakpoint */
@media (max-width: 576px) {
body {
margin-left: 0;
padding-top: 0;
display: flex;
}
header.top-navbar {
position: relative;
}
.sidebar {
width: 100% !important;
position: relative !important;
margin-top: 0 !important;
}
ul.sidebar-elements > li > a.sidebar-link > span.text {
visibility: visible !important;
}
ul.sidebar-elements > li.category > span.category-label {
display: block !important;
}
.sidebar:hover:not(.expanded) ~ main.content:after {
bottom: unset !important;
right: unset !important;
opacity: 0;
}
.sidebar.expanded ~ main.content {
margin-left: 0 !important;
}
.sidebar ul.sidebar-elements > li.category > span.category-label {
opacity: 1;
position: relative;
height: auto;
width: auto;
}
}
@media (max-width: 768px) {
.header-breadcrumb-actions > a {
border-top-left-radius: 0.25rem !important;
border-bottom-left-radius: 0.25rem !important;
}
}
.main-wrapper {
min-height: 100%;
/* padding-top: var(--navbar-height); */
}
.top-navbar {
min-height: var(--navbar-height);
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 0;
margin-bottom: 0;
z-index: 1020;
}
main.content {
position: relative;
left: 0;
min-height: 100%;
}
.sidebar {
margin-top: var(--navbar-height);
overflow: hidden;
position: fixed;
top: 0;
bottom: 0;
width: var(--sidebar-width-collapsed);
left: 0;
transform:translateZ(0) scale(1,1);
z-index:1039;
}
.sidebar.expanded, .sidebar:hover {
width: var(--sidebar-width-expanded);
}
.sidebar.expanded ~ main.content {
margin-left: calc(var(--sidebar-width-expanded) - var(--sidebar-width-collapsed));
}
.sidebar ~ main.content:after {
z-index: 1038;
content: ' ';
transition: opacity 0.5s;
position: fixed;
top:0;
left:0;
opacity: 0;
}
.sidebar:hover:not(.expanded) ~ main.content:after {
bottom: 0;
right:0;
opacity: 0.5;
}
.left-navbar {
min-width: 70px;
}
.center-navbar {
display: flex;
flex: 1 1 auto;
padding: 0 20px;
}
.right-navbar {
display: flex;
justify-content: end;
flex: 1 0 auto;
height: var(--navbar-height);
}
.right-navbar div.global-search-container {
margin: auto 0;
}
.global-search-result-container {
min-width: 280px;
}
.global-search-result-container .total-found {
font-size: 0.75rem;
padding-top: 0rem;
text-align: end;
}
.global-search-result-container .total-found .total-found-number {
font-size: 0.9rem;
}
.global-search-result-container .search-container-model .model-text {
font-size: 0.75rem;
font-weight: 600;
}
.global-search-result-container .search-container-model .search-container-divider {
flex: 1 0 0;
min-height: 20px;
}
.global-search-result-container .search-container-model .search-container-divider > hr {
height: 1px;
flex: 1 0 auto
}
.top-navbar .global-search-container {
position: relative;
}
.global-search-container #globalSearch {
padding-right: 26px;
}
.top-navbar .global-search-container .search-input-container > i.icon {
position: absolute;
right: 8px;
line-height: 38px;
}
.right-navbar div.header-menu a.nav-link {
margin: auto 0;
}
.right-navbar .header-menu .dropdown-menu a.dropdown-item > i {
min-width: 25px;
}
/* sidebar */
.sidebar-wrapper {
width: 100%;
height: 100%;
}
.sidebar-scroll {
position: relative;
width: 100%;
}
.sidebar-content {
padding-top: 0.25em;
}
ul.sidebar-elements {
margin: 0;
padding: 0;
}
.sidebar .lock-sidebar > a::before {
content: "\f101";
font-family: 'Font Awesome 5 Free';
font-weight: 900;
}
.sidebar.expanded .lock-sidebar > a::before {
content: "\f100";
}
/* sidebar entry */
ul.sidebar-elements > li {
list-style: none;
}
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link {
text-overflow: ellipsis;
}
ul.sidebar-elements li > a.sidebar-link {
position: relative;
display: block;
padding: 0 calc((var(--sidebar-width-collapsed) - 25px) / 2);
line-height: 35px;
overflow: hidden;
white-space: nowrap;
text-decoration: none;
}
ul.sidebar-elements li > a.sidebar-link.active::after {
content: ' ';
width: 3px;
top: 0;
right: 0;
bottom: 0;
position: absolute;
}
.sidebar ul.sidebar-elements li > a.sidebar-link.have-active-child::after {
content: ' ';
width: 3px;
top: 0;
right: 0;
bottom: 0;
position: absolute;
}
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child::after,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child::after {
content: unset;
}
ul.sidebar-elements > li > a.sidebar-link > * {
text-align: center;
vertical-align: middle;
}
ul.sidebar-elements > li > a.sidebar-link > i.sidebar-icon {
margin-right: 10px;
font-size: 19px;
min-width: 25px;
line-height: 19px;
}
.sidebar.expanded ul.sidebar-elements > li > a.sidebar-link > span.text,
.sidebar:hover ul.sidebar-elements > li > a.sidebar-link > span.text {
visibility: visible;
}
ul.sidebar-elements > li > a.sidebar-link > span.text {
visibility: hidden;
line-height: 40px;
white-space: nowrap;
}
/* sidebar sub-menu */
ul.sidebar-elements li.parent > a.sidebar-link::before {
visibility: hidden;
content: "\f0d7";
float: right;
font-family: 'Font Awesome 5 Free';
font-weight: 900;
font-size: 1rem;
}
ul.sidebar-elements li.parent > a.sidebar-link:not(.collapsed)::before {
content: "\f0d8";
}
.sidebar.expanded ul.sidebar-elements li.parent > a.sidebar-link::before,
.sidebar:hover ul.sidebar-elements li.parent > a.sidebar-link::before {
visibility: visible;
}
.sidebar.expanded ul.sidebar-elements li ul.show,
.sidebar.expanded ul.sidebar-elements li ul.collapsing,
.sidebar.expanded ul.sidebar-elements li ul.in,
.sidebar:hover ul.sidebar-elements li ul.show,
.sidebar:hover ul.sidebar-elements li ul.collapsing,
.sidebar:hover ul.sidebar-elements li ul.in {
display: block;
}
ul.sidebar-elements > li ul {
display: none;
padding: 10px 0;
list-style: none;
line-height: 20px;
}
ul.sidebar-elements > li ul li > a.sidebar-link {
font-size: 0.9rem;
padding-left: 35px;
padding-right: 17px;
}
ul.sidebar-elements > li ul li > ul > li > a.sidebar-link {
font-size: 0.85rem;
padding-left: 50px;
padding-right: 14px;
}
ul.sidebar-elements > li ul li > ul > li > ul > li > a.sidebar-link {
font-size: 0.8rem;
padding-left: 65px;
padding-right: 11px;
}
ul.sidebar-elements > li ul li > ul > li > ul > li > ul > li > a.sidebar-link {
font-size: 0.78rem;
padding-left: 80px;
padding-right: 8px;
}
/* sidebar category */
ul.sidebar-elements > li.category {
white-space: nowrap;
display: flex;
padding: 15px calc((var(--sidebar-width-collapsed) - 25px) / 2) 0;
line-height: 30px;
}
.sidebar.expanded ul.sidebar-elements > li.category > span.category-label,
.sidebar:hover ul.sidebar-elements > li.category > span.category-label {
opacity: 1;
position: relative;
height: auto;
width: auto;
}
ul.sidebar-elements > li.category > span.category-label {
display: flex;
position: absolute;
height: 0;
width: 0;
overflow: hidden;
text-transform: uppercase;
font-size: 0.75rem;
font-weight: 600;
margin-right: 15px;
opacity: 0;
transition: opacity 0.2s linear;
}
ul.sidebar-elements > li.category > span.category-divider {
min-height: 30px;
flex: 1 0 0%;
display: flex;
align-items: center;
}
ul.sidebar-elements > li.category > span.category-divider > hr {
margin: 0;
height: 1px;
flex: 1 0 auto;
}
/*
Header
*/
.center-navbar nav.header-breadcrumb {
padding: 0.5rem 0.75rem;
}
.center-navbar nav.header-breadcrumb > ol {
display: flex;
list-style: none;
padding-left: 0;
margin-bottom: 0;
}
.center-navbar nav.header-breadcrumb li {
line-height: 1.5;
}
.center-navbar nav.header-breadcrumb li.header-breadcrumb-item {
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.center-navbar nav.header-breadcrumb li.header-breadcrumb-separator {
padding: 0 0.75rem;
}
.navbar-dark .center-navbar nav.header-breadcrumb li.header-breadcrumb-separator {
/* color: black; */
}
.navbar-light .center-navbar nav.header-breadcrumb li.header-breadcrumb-separator {
/* color: white; */
}
.center-navbar nav.header-breadcrumb li.header-breadcrumb-item a {
text-decoration: none;
}
.header-breadcrumb-children {
border-radius: 0.25rem;
padding: 0 0.25rem;
display: flex;
align-items: center;
}
.header-breadcrumb-children > a:not(:last-child) {
}
.header-breadcrumb-actions > a {
}
.breadcrumb-link-container {
top: var(--navbar-height);
padding: 2px;
border-radius: 0 0 0 5px;
}
.header-breadcrumb-children .dropdown-menu .dropdown-item > i {
min-width: 25px;
}
.composed-app-icon-container {
height: calc(var(--navbar-height) - 10px);
width: calc(var(--navbar-height) - 10px);
position: relative;
display: block;
}
.composed-app-icon-container > .app-icon {
display: inline-block;
mask-image: url(/img/icon-composition/sheet-all.svg), url(/img/icon-composition/z.svg);
mask-position: 0 0, 2.4px calc((var(--navbar-height) - 10px) / 2);
mask-repeat: no-repeat;
mask-size: contain, cover;
mask-composite: source-out;
-webkit-mask-image: url(/img/icon-composition/sheet-all.svg), url(/img/icon-composition/z.svg);
-webkit-mask-position: 0 0, 2.4px calc((var(--navbar-height) - 10px) / 2);
-webkit-mask-repeat: no-repeat;
-webkit-mask-size: contain, cover;
-webkit-mask-composite: source-out;
transition-timing-function: ease-out;
transition-duration: 0.2s;
transition-property: -webkit-mask-position;
}
.composed-app-icon-container > .app-icon:hover {
mask-position: 0 0, 2.4px calc(0.75 * (var(--navbar-height) - 10px) / 2);
-webkit-mask-position: 0 0, 2.4px calc(0.75 * (var(--navbar-height) - 10px) / 2);
}

View File

@ -1,28 +1,7 @@
/* based on the example from https://getbootstrap.com/docs/4.0/examples/sign-in/*/
/* based on the example from https://getbootstrap.com/docs/4.0/examples/sign-in/ */
.form-signin {
width: 100%;
max-width: 330px;
padding: 15px;
margin: 0 auto;
}
.form-signin .form-control {
position: relative;
box-sizing: border-box;
height: auto;
padding: 10px;
font-size: 16px;
}
.form-signin .form-control:focus {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}

View File

@ -1,5 +1,5 @@
:root {
--cerebrate: #924da6;
--cerebrate-color: #924da6;
}
.pagination li.page-item > a.page-link > .ellipsis {
@ -21,7 +21,7 @@
color:black;
}
.sidebar {}
/* .sidebar {}
.side-bar-ul {
top: 70px;
@ -91,7 +91,7 @@
.side-bar-ul>.sidebar-brand a:hover {
color: #fff;
background: none;
}
} */
@media(min-width:768px) {
#wrapper {
@ -131,6 +131,14 @@
text-decoration: inherit;
}
.table-link-action {
filter: invert(0.4);
}
.table-link-action:hover {
filter: unset;
}
.btn-group > .btn:last-of-type:not(.dropdown-toggle), .btn-group > .btn-group:not(:last-of-type) > .btn {
border-top-right-radius: 0.2rem;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
/* Body */
.panel {
background-color: #363636;
border: 1px solid #454545;
box-shadow: none; }
/* Top navbar */
.top-navbar {
background-color: #375a7f; }
.center-navbar nav.header-breadcrumb {
color: #fff; }
header.top-navbar .header-menu > a:hover,
header.top-navbar .header-breadcrumb .header-breadcrumb-item > a:hover {
color: #d6d6d6 !important; }
.top-navbar .center-navbar nav.header-breadcrumb li.header-breadcrumb-item a {
color: #fff; }
.top-navbar .right-navbar .header-menu a.nav-link {
color: #fff; }
.top-navbar .left-navbar .navbar-brand img {
filter: invert(1); }
.top-navbar .left-navbar .navbar-brand:hover img {
filter: invert(1) drop-shadow(0px 0px 3px #fff); }
.top-navbar .composed-app-icon-container > .app-icon {
background-color: #fff; }
.breadcrumb-link-container {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 2px 6px 0 rgba(0, 0, 0, 0.12);
background-color: #adb5bd; }
/* Sidebar */
.sidebar {
transition: width .08s linear;
box-shadow: none;
background-color: #444; }
.sidebar ~ main.content:after {
background: #000; }
.sidebar .sidebar-wrapper {
border-right: 1px solid none; }
.sidebar .sidebar-wrapper {
border-right: 1px solid rgba(0, 0, 0, 0.125); }
.sidebar ul.sidebar-elements li > a.sidebar-link {
color: #fff; }
.sidebar ul.sidebar-elements li > a.sidebar-link.active {
background-color: #595f64;
color: #fff; }
.sidebar ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: #595f64;
color: #fff; }
.sidebar ul.sidebar-elements li > a.sidebar-link:hover {
background-color: #60676c;
color: #fff; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: unset; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child:hover,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child:hover {
background-color: #60676c; }
ul.sidebar-elements li > a.sidebar-link.active::after {
background-color: var(--cerebrate-color); }
.lock-sidebar > a.btn {
background-color: unset; }

View File

@ -0,0 +1,79 @@
/* Body */
.panel {
background-color: #fff;
border: none;
box-shadow: 0 0 35px 0 rgba(154, 161, 171, 0.25); }
/* Top navbar */
.top-navbar {
background-color: #343a40; }
.center-navbar nav.header-breadcrumb {
color: #fff; }
header.top-navbar .header-menu > a:hover,
header.top-navbar .header-breadcrumb .header-breadcrumb-item > a:hover {
color: #d6d6d6 !important; }
.top-navbar .center-navbar nav.header-breadcrumb li.header-breadcrumb-item a {
color: #fff; }
.top-navbar .right-navbar .header-menu a.nav-link {
color: #fff; }
.top-navbar .left-navbar .navbar-brand img {
filter: invert(1); }
.top-navbar .left-navbar .navbar-brand:hover img {
filter: invert(1) drop-shadow(0px 0px 3px #fff); }
.top-navbar .composed-app-icon-container > .app-icon {
background-color: #fff; }
.breadcrumb-link-container {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 2px 6px 0 rgba(0, 0, 0, 0.12);
background-color: #f8f9fa; }
/* Sidebar */
.sidebar {
transition: width .08s linear;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 2px 6px 0 rgba(0, 0, 0, 0.12);
background-color: #f8f9fa; }
.sidebar ~ main.content:after {
background: #000; }
.sidebar .sidebar-wrapper {
border-right: 1px solid #ddd; }
.sidebar .sidebar-wrapper {
border-right: 1px solid rgba(0, 0, 0, 0.125); }
.sidebar ul.sidebar-elements li > a.sidebar-link {
color: #000; }
.sidebar ul.sidebar-elements li > a.sidebar-link.active {
background-color: #dbdbdb;
color: #000; }
.sidebar ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: #dbdbdb;
color: #000; }
.sidebar ul.sidebar-elements li > a.sidebar-link:hover {
background-color: #ebebeb;
color: #000; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: unset; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child:hover,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child:hover {
background-color: #ebebeb; }
ul.sidebar-elements li > a.sidebar-link.active::after {
background-color: var(--cerebrate-color); }
.lock-sidebar > a.btn {
background-color: #f8f9fa; }

View File

@ -0,0 +1,79 @@
/* Body */
.panel {
background-color: #fff;
border: none;
box-shadow: 0 0 35px 0 rgba(154, 161, 171, 0.25); }
/* Top navbar */
.top-navbar {
background-color: #2c3e50; }
.center-navbar nav.header-breadcrumb {
color: #fff; }
header.top-navbar .header-menu > a:hover,
header.top-navbar .header-breadcrumb .header-breadcrumb-item > a:hover {
color: #d6d6d6 !important; }
.top-navbar .center-navbar nav.header-breadcrumb li.header-breadcrumb-item a {
color: #fff; }
.top-navbar .right-navbar .header-menu a.nav-link {
color: #fff; }
.top-navbar .left-navbar .navbar-brand img {
filter: invert(1); }
.top-navbar .left-navbar .navbar-brand:hover img {
filter: invert(1) drop-shadow(0px 0px 3px #fff); }
.top-navbar .composed-app-icon-container > .app-icon {
background-color: #fff; }
.breadcrumb-link-container {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 2px 6px 0 rgba(0, 0, 0, 0.12);
background-color: #ecf0f1; }
/* Sidebar */
.sidebar {
transition: width .08s linear;
box-shadow: none;
background-color: #ecf0f1; }
.sidebar ~ main.content:after {
background: #000; }
.sidebar .sidebar-wrapper {
border-right: 1px solid none; }
.sidebar .sidebar-wrapper {
border-right: 1px solid rgba(0, 0, 0, 0.125); }
.sidebar ul.sidebar-elements li > a.sidebar-link {
color: #000; }
.sidebar ul.sidebar-elements li > a.sidebar-link.active {
background-color: #dbdbdb;
color: #18bc9c; }
.sidebar ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: #dbdbdb;
color: #18bc9c; }
.sidebar ul.sidebar-elements li > a.sidebar-link:hover {
background-color: #ebebeb;
color: #18bc9c; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: unset; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child:hover,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child:hover {
background-color: #ebebeb; }
ul.sidebar-elements li > a.sidebar-link.active::after {
background-color: #18bc9c; }
.lock-sidebar > a.btn {
background-color: unset; }

View File

@ -0,0 +1,79 @@
/* Body */
.panel {
background-color: #fff;
border: none;
box-shadow: 0 0 35px 0 rgba(154, 161, 171, 0.25); }
/* Top navbar */
.top-navbar {
background-color: #2c3e50; }
.center-navbar nav.header-breadcrumb {
color: #fff; }
header.top-navbar .header-menu > a:hover,
header.top-navbar .header-breadcrumb .header-breadcrumb-item > a:hover {
color: #d6d6d6 !important; }
.top-navbar .center-navbar nav.header-breadcrumb li.header-breadcrumb-item a {
color: #fff; }
.top-navbar .right-navbar .header-menu a.nav-link {
color: #fff; }
.top-navbar .left-navbar .navbar-brand img {
filter: invert(1); }
.top-navbar .left-navbar .navbar-brand:hover img {
filter: invert(1) drop-shadow(0px 0px 3px #fff); }
.top-navbar .composed-app-icon-container > .app-icon {
background-color: #fff; }
.breadcrumb-link-container {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 2px 6px 0 rgba(0, 0, 0, 0.12);
background-color: #ecf0f1; }
/* Sidebar */
.sidebar {
transition: width .08s linear;
box-shadow: none;
background-color: #ecf0f1; }
.sidebar ~ main.content:after {
background: #000; }
.sidebar .sidebar-wrapper {
border-right: 1px solid none; }
.sidebar .sidebar-wrapper {
border-right: 1px solid rgba(0, 0, 0, 0.125); }
.sidebar ul.sidebar-elements li > a.sidebar-link {
color: #343a40; }
.sidebar ul.sidebar-elements li > a.sidebar-link.active {
background-color: #dbdbdb;
color: #18bc9c; }
.sidebar ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: #dbdbdb;
color: #18bc9c; }
.sidebar ul.sidebar-elements li > a.sidebar-link:hover {
background-color: #ebebeb;
color: #18bc9c; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: unset; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child:hover,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child:hover {
background-color: #ebebeb; }
ul.sidebar-elements li > a.sidebar-link.active::after {
background-color: #18bc9c; }
.lock-sidebar > a.btn {
background-color: unset; }

View File

@ -0,0 +1,523 @@
/* Body */
.panel {
background-color: transparent;
border: none;
box-shadow: 0 0 35px 0 rgba(154, 161, 171, 0.25); }
/* Top navbar */
.top-navbar {
background-color: #e83283; }
.center-navbar nav.header-breadcrumb {
color: #fff; }
header.top-navbar .header-menu > a:hover,
header.top-navbar .header-breadcrumb .header-breadcrumb-item > a:hover {
color: #d6d6d6 !important; }
.top-navbar .center-navbar nav.header-breadcrumb li.header-breadcrumb-item a {
color: #fff; }
.top-navbar .right-navbar .header-menu a.nav-link {
color: #fff; }
.top-navbar .left-navbar .navbar-brand img {
filter: invert(1); }
.top-navbar .left-navbar .navbar-brand:hover img {
filter: invert(1) drop-shadow(0px 0px 3px #fff); }
.top-navbar .composed-app-icon-container > .app-icon {
background-color: #fff; }
.breadcrumb-link-container {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 2px 6px 0 rgba(0, 0, 0, 0.12);
background-color: rgba(255, 255, 255, 0.4); }
/* Sidebar */
.sidebar {
transition: width .08s linear;
box-shadow: none;
background-color: rgba(255, 255, 255, 0.4); }
.sidebar ~ main.content:after {
background: #000; }
.sidebar .sidebar-wrapper {
border-right: 1px solid none; }
.sidebar .sidebar-wrapper {
border-right: 1px solid rgba(0, 0, 0, 0.125); }
.sidebar ul.sidebar-elements li > a.sidebar-link {
color: #fff; }
.sidebar ul.sidebar-elements li > a.sidebar-link.active {
background-color: #fff;
color: #343a40; }
.sidebar ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: #fff;
color: #343a40; }
.sidebar ul.sidebar-elements li > a.sidebar-link:hover {
background-color: #fff;
color: #343a40; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: unset; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child:hover,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child:hover {
background-color: #fff; }
ul.sidebar-elements li > a.sidebar-link.active::after {
background-color: #e83283; }
.lock-sidebar > a.btn {
background-color: rgba(255, 255, 255, 0.4); }
.btn {
display: inline-block;
font-weight: 400;
color: #fff;
text-align: center;
vertical-align: middle;
user-select: none;
background-color: transparent;
border: 1px solid transparent;
padding: 0.75rem 1.5rem;
font-size: 1rem;
line-height: 1.5;
border-radius: 0.5rem;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; }
@media (prefers-reduced-motion: reduce) {
.btn {
transition: none; } }
.btn:hover {
color: #fff;
text-decoration: none; }
.btn:focus, .btn.focus {
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(232, 50, 131, 0.25); }
.btn.disabled, .btn:disabled {
opacity: 0.65; }
.btn:not(:disabled):not(.disabled) {
cursor: pointer; }
a.btn.disabled,
fieldset:disabled a.btn {
pointer-events: none; }
.btn-primary {
color: #fff;
background-color: #e83283;
border-color: #e83283; }
.btn-primary:hover {
color: #fff;
background-color: #db196f;
border-color: #d01769; }
.btn-primary:focus, .btn-primary.focus {
color: #fff;
background-color: #db196f;
border-color: #d01769;
box-shadow: 0 0 0 0.2rem rgba(235, 81, 150, 0.5); }
.btn-primary.disabled, .btn-primary:disabled {
color: #fff;
background-color: #e83283;
border-color: #e83283; }
.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active,
.show > .btn-primary.dropdown-toggle {
color: #fff;
background-color: #d01769;
border-color: #c41664; }
.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus,
.show > .btn-primary.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(235, 81, 150, 0.5); }
.btn-secondary {
color: #212529;
background-color: rgba(255, 255, 255, 0.4);
border-color: rgba(255, 255, 255, 0.4); }
.btn-secondary:hover {
color: #212529;
background-color: rgba(236, 236, 236, 0.4);
border-color: rgba(230, 230, 230, 0.4); }
.btn-secondary:focus, .btn-secondary.focus {
color: #212529;
background-color: rgba(236, 236, 236, 0.4);
border-color: rgba(230, 230, 230, 0.4);
box-shadow: 0 0 0 0.2rem rgba(163, 165, 166, 0.5); }
.btn-secondary.disabled, .btn-secondary:disabled {
color: #212529;
background-color: rgba(255, 255, 255, 0.4);
border-color: rgba(255, 255, 255, 0.4); }
.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active,
.show > .btn-secondary.dropdown-toggle {
color: #212529;
background-color: rgba(230, 230, 230, 0.4);
border-color: rgba(223, 223, 223, 0.4); }
.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus,
.show > .btn-secondary.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(163, 165, 166, 0.5); }
.btn-success {
color: #212529;
background-color: #41d7a7;
border-color: #41d7a7; }
.btn-success:hover {
color: #fff;
background-color: #2ac895;
border-color: #28bd8d; }
.btn-success:focus, .btn-success.focus {
color: #fff;
background-color: #2ac895;
border-color: #28bd8d;
box-shadow: 0 0 0 0.2rem rgba(60, 188, 148, 0.5); }
.btn-success.disabled, .btn-success:disabled {
color: #212529;
background-color: #41d7a7;
border-color: #41d7a7; }
.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active,
.show > .btn-success.dropdown-toggle {
color: #fff;
background-color: #28bd8d;
border-color: #26b386; }
.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus,
.show > .btn-success.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(60, 188, 148, 0.5); }
.btn-info {
color: #212529;
background-color: #39cbfb;
border-color: #39cbfb; }
.btn-info:hover {
color: #fff;
background-color: #14c1fa;
border-color: #07befa; }
.btn-info:focus, .btn-info.focus {
color: #fff;
background-color: #14c1fa;
border-color: #07befa;
box-shadow: 0 0 0 0.2rem rgba(53, 178, 220, 0.5); }
.btn-info.disabled, .btn-info:disabled {
color: #212529;
background-color: #39cbfb;
border-color: #39cbfb; }
.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active,
.show > .btn-info.dropdown-toggle {
color: #fff;
background-color: #07befa;
border-color: #05b5ef; }
.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus,
.show > .btn-info.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(53, 178, 220, 0.5); }
.btn-warning {
color: #212529;
background-color: #ffc107;
border-color: #ffc107; }
.btn-warning:hover {
color: #212529;
background-color: #e0a800;
border-color: #d39e00; }
.btn-warning:focus, .btn-warning.focus {
color: #212529;
background-color: #e0a800;
border-color: #d39e00;
box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); }
.btn-warning.disabled, .btn-warning:disabled {
color: #212529;
background-color: #ffc107;
border-color: #ffc107; }
.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active,
.show > .btn-warning.dropdown-toggle {
color: #212529;
background-color: #d39e00;
border-color: #c69500; }
.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus,
.show > .btn-warning.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5); }
.btn-danger {
color: #212529;
background-color: #fd7e14;
border-color: #fd7e14; }
.btn-danger:hover {
color: #fff;
background-color: #e96b02;
border-color: #dc6502; }
.btn-danger:focus, .btn-danger.focus {
color: #fff;
background-color: #e96b02;
border-color: #dc6502;
box-shadow: 0 0 0 0.2rem rgba(220, 113, 23, 0.5); }
.btn-danger.disabled, .btn-danger:disabled {
color: #212529;
background-color: #fd7e14;
border-color: #fd7e14; }
.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active,
.show > .btn-danger.dropdown-toggle {
color: #fff;
background-color: #dc6502;
border-color: #cf5f02; }
.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus,
.show > .btn-danger.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(220, 113, 23, 0.5); }
.btn-light {
color: #212529;
background-color: #e9e9e8;
border-color: #e9e9e8; }
.btn-light:hover {
color: #212529;
background-color: #d6d6d4;
border-color: #d0d0ce; }
.btn-light:focus, .btn-light.focus {
color: #212529;
background-color: #d6d6d4;
border-color: #d0d0ce;
box-shadow: 0 0 0 0.2rem rgba(203, 204, 203, 0.5); }
.btn-light.disabled, .btn-light:disabled {
color: #212529;
background-color: #e9e9e8;
border-color: #e9e9e8; }
.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active,
.show > .btn-light.dropdown-toggle {
color: #212529;
background-color: #d0d0ce;
border-color: #cacac7; }
.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus,
.show > .btn-light.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(203, 204, 203, 0.5); }
.btn-dark {
color: #fff;
background-color: #212529;
border-color: #212529; }
.btn-dark:hover {
color: #fff;
background-color: #101214;
border-color: #0a0c0d; }
.btn-dark:focus, .btn-dark.focus {
color: #fff;
background-color: #101214;
border-color: #0a0c0d;
box-shadow: 0 0 0 0.2rem rgba(66, 70, 73, 0.5); }
.btn-dark.disabled, .btn-dark:disabled {
color: #fff;
background-color: #212529;
border-color: #212529; }
.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active,
.show > .btn-dark.dropdown-toggle {
color: #fff;
background-color: #0a0c0d;
border-color: #050506; }
.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus,
.show > .btn-dark.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(66, 70, 73, 0.5); }
.btn-outline-primary {
color: #e83283;
border-color: #e83283; }
.btn-outline-primary:hover {
color: #fff;
background-color: #e83283;
border-color: #e83283; }
.btn-outline-primary:focus, .btn-outline-primary.focus {
box-shadow: 0 0 0 0.2rem rgba(232, 50, 131, 0.5); }
.btn-outline-primary.disabled, .btn-outline-primary:disabled {
color: #e83283;
background-color: transparent; }
.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active,
.show > .btn-outline-primary.dropdown-toggle {
color: #fff;
background-color: #e83283;
border-color: #e83283; }
.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-primary.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(232, 50, 131, 0.5); }
.btn-outline-secondary {
color: rgba(255, 255, 255, 0.4);
border-color: rgba(255, 255, 255, 0.4); }
.btn-outline-secondary:hover {
color: #212529;
background-color: rgba(255, 255, 255, 0.4);
border-color: rgba(255, 255, 255, 0.4); }
.btn-outline-secondary:focus, .btn-outline-secondary.focus {
box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.5); }
.btn-outline-secondary.disabled, .btn-outline-secondary:disabled {
color: rgba(255, 255, 255, 0.4);
background-color: transparent; }
.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active,
.show > .btn-outline-secondary.dropdown-toggle {
color: #212529;
background-color: rgba(255, 255, 255, 0.4);
border-color: rgba(255, 255, 255, 0.4); }
.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-secondary.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.5); }
.btn-outline-success {
color: #41d7a7;
border-color: #41d7a7; }
.btn-outline-success:hover {
color: #212529;
background-color: #41d7a7;
border-color: #41d7a7; }
.btn-outline-success:focus, .btn-outline-success.focus {
box-shadow: 0 0 0 0.2rem rgba(65, 215, 167, 0.5); }
.btn-outline-success.disabled, .btn-outline-success:disabled {
color: #41d7a7;
background-color: transparent; }
.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active,
.show > .btn-outline-success.dropdown-toggle {
color: #212529;
background-color: #41d7a7;
border-color: #41d7a7; }
.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-success.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(65, 215, 167, 0.5); }
.btn-outline-info {
color: #39cbfb;
border-color: #39cbfb; }
.btn-outline-info:hover {
color: #212529;
background-color: #39cbfb;
border-color: #39cbfb; }
.btn-outline-info:focus, .btn-outline-info.focus {
box-shadow: 0 0 0 0.2rem rgba(57, 203, 251, 0.5); }
.btn-outline-info.disabled, .btn-outline-info:disabled {
color: #39cbfb;
background-color: transparent; }
.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active,
.show > .btn-outline-info.dropdown-toggle {
color: #212529;
background-color: #39cbfb;
border-color: #39cbfb; }
.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-info.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(57, 203, 251, 0.5); }
.btn-outline-warning {
color: #ffc107;
border-color: #ffc107; }
.btn-outline-warning:hover {
color: #212529;
background-color: #ffc107;
border-color: #ffc107; }
.btn-outline-warning:focus, .btn-outline-warning.focus {
box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); }
.btn-outline-warning.disabled, .btn-outline-warning:disabled {
color: #ffc107;
background-color: transparent; }
.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active,
.show > .btn-outline-warning.dropdown-toggle {
color: #212529;
background-color: #ffc107;
border-color: #ffc107; }
.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-warning.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); }
.btn-outline-danger {
color: #fd7e14;
border-color: #fd7e14; }
.btn-outline-danger:hover {
color: #212529;
background-color: #fd7e14;
border-color: #fd7e14; }
.btn-outline-danger:focus, .btn-outline-danger.focus {
box-shadow: 0 0 0 0.2rem rgba(253, 126, 20, 0.5); }
.btn-outline-danger.disabled, .btn-outline-danger:disabled {
color: #fd7e14;
background-color: transparent; }
.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active,
.show > .btn-outline-danger.dropdown-toggle {
color: #212529;
background-color: #fd7e14;
border-color: #fd7e14; }
.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-danger.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(253, 126, 20, 0.5); }
.btn-outline-light {
color: #e9e9e8;
border-color: #e9e9e8; }
.btn-outline-light:hover {
color: #212529;
background-color: #e9e9e8;
border-color: #e9e9e8; }
.btn-outline-light:focus, .btn-outline-light.focus {
box-shadow: 0 0 0 0.2rem rgba(233, 233, 232, 0.5); }
.btn-outline-light.disabled, .btn-outline-light:disabled {
color: #e9e9e8;
background-color: transparent; }
.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active,
.show > .btn-outline-light.dropdown-toggle {
color: #212529;
background-color: #e9e9e8;
border-color: #e9e9e8; }
.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-light.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(233, 233, 232, 0.5); }
.btn-outline-dark {
color: #212529;
border-color: #212529; }
.btn-outline-dark:hover {
color: #fff;
background-color: #212529;
border-color: #212529; }
.btn-outline-dark:focus, .btn-outline-dark.focus {
box-shadow: 0 0 0 0.2rem rgba(33, 37, 41, 0.5); }
.btn-outline-dark.disabled, .btn-outline-dark:disabled {
color: #212529;
background-color: transparent; }
.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active,
.show > .btn-outline-dark.dropdown-toggle {
color: #fff;
background-color: #212529;
border-color: #212529; }
.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-dark.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(33, 37, 41, 0.5); }
.btn-link {
font-weight: 400;
color: #fff;
text-decoration: none; }
.btn-link:hover {
color: #d9d9d9;
text-decoration: underline; }
.btn-link:focus, .btn-link.focus {
text-decoration: underline; }
.btn-link:disabled, .btn-link.disabled {
color: #6c757d;
pointer-events: none; }
.btn-lg {
padding: 0.5rem 1rem;
font-size: 1.25rem;
line-height: 1.5;
border-radius: 0.7rem; }
.btn-sm {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
line-height: 1.5;
border-radius: 0.6rem; }
.btn-block {
display: block;
width: 100%; }
.btn-block + .btn-block {
margin-top: 0.5rem; }
input[type="submit"].btn-block,
input[type="reset"].btn-block,
input[type="button"].btn-block {
width: 100%; }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
/* Body */
.panel {
background-color: #363636;
border: 1px solid #454545;
box-shadow: none; }
/* Top navbar */
.top-navbar {
background-color: #6f42c1; }
.center-navbar nav.header-breadcrumb {
color: #fff; }
header.top-navbar .header-menu > a:hover,
header.top-navbar .header-breadcrumb .header-breadcrumb-item > a:hover {
color: #d6d6d6 !important; }
.top-navbar .center-navbar nav.header-breadcrumb li.header-breadcrumb-item a {
color: #fff; }
.top-navbar .right-navbar .header-menu a.nav-link {
color: #fff; }
.top-navbar .left-navbar .navbar-brand img {
filter: invert(1); }
.top-navbar .left-navbar .navbar-brand:hover img {
filter: invert(1) drop-shadow(0px 0px 3px #fff); }
.top-navbar .composed-app-icon-container > .app-icon {
background-color: #fff; }
.breadcrumb-link-container {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 2px 6px 0 rgba(0, 0, 0, 0.12);
background-color: #44d9e8; }
/* Sidebar */
.sidebar {
transition: width .08s linear;
box-shadow: none;
background-color: #170229; }
.sidebar ~ main.content:after {
background: #000; }
.sidebar .sidebar-wrapper {
border-right: 1px solid none; }
.sidebar .sidebar-wrapper {
border-right: 1px solid rgba(0, 0, 0, 0.125); }
.sidebar ul.sidebar-elements li > a.sidebar-link {
color: #fff; }
.sidebar ul.sidebar-elements li > a.sidebar-link.active {
background-color: #343a40;
color: #3cf281; }
.sidebar ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: #343a40;
color: #3cf281; }
.sidebar ul.sidebar-elements li > a.sidebar-link:hover {
background-color: #495057;
color: #3cf281; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child {
background-color: unset; }
.sidebar.expanded ul.sidebar-elements li > a.sidebar-link.have-active-child:hover,
.sidebar:hover ul.sidebar-elements li > a.sidebar-link.have-active-child:hover {
background-color: #495057; }
ul.sidebar-elements li > a.sidebar-link.active::after {
background-color: #6f42c1; }
.lock-sidebar > a.btn {
background-color: unset; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 118 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 127 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 145 KiB

View File

@ -369,7 +369,7 @@ class Toaster {
$toastHeader.append($toastHeaderMuted)
}
if (options.closeButton) {
var $closeButton = $('<button type="button" class="ml-2 mb-1 close" aria-label="Close"><span aria-hidden="true">&times;</span></button>')
var $closeButton = $('<button type="button" class="ml-2 mb-1 close" data-bs-dismiss="toast" aria-label="Close"></button>')
.click(function() {
$(this).closest('.toast').data('toastObject').removeToast()
})
@ -531,13 +531,14 @@ class ModalFactory {
'confirm-danger',
]
static closeButtonHtml = '<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>'
static closeButtonHtml = '<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close"></button>'
/** Create the HTML of the modal and inject it into the DOM */
makeModal() {
if (this.isValid()) {
this.$modal = this.buildModal()
$('#mainModalContainer').append(this.$modal)
this.modalInstance = new bootstrap.Modal(this.$modal[0], this.bsModalOptions)
} else {
console.log('Modal not valid')
}
@ -547,7 +548,8 @@ class ModalFactory {
show() {
if (this.isValid()) {
var that = this
this.$modal.modal(this.bsModalOptions)
this.modalInstance.show()
this.$modal
.on('hidden.bs.modal', function () {
that.removeModal()
that.options.hiddenCallback(that)
@ -558,6 +560,17 @@ class ModalFactory {
that.findSubmitButtonAndAddListener()
}
})
// this.$modal.modal(this.bsModalOptions)
// .on('hidden.bs.modal', function () {
// that.removeModal()
// that.options.hiddenCallback(that)
// })
// .on('shown.bs.modal', function () {
// that.options.shownCallback(that)
// if (that.attachSubmitButtonListener) {
// that.findSubmitButtonAndAddListener()
// }
// })
} else {
console.log('Modal not valid')
}
@ -565,7 +578,8 @@ class ModalFactory {
/** Hide the modal using the bootstrap modal's hide command */
hide() {
this.$modal.modal('hide')
// this.$modal.modal('hide')
this.modalInstance.hide()
}
/** Remove the modal from the DOM */
@ -588,7 +602,7 @@ class ModalFactory {
* @return {jQuery} The modal jQuery object
*/
buildModal() {
const $modal = $('<div class="modal fade" tabindex="-1" aria-hidden="true"/>')
const $modal = $('<div class="modal fade" tabindex="-1"/>')
if (this.options.id !== false) {
$modal.attr('id', this.options.id)
$modal.attr('aria-labelledby', this.options.id)
@ -663,7 +677,7 @@ class ModalFactory {
getFooterOkOnly() {
return [
$('<button type="button" class="btn btn-primary">OK</button>')
.attr('data-dismiss', 'modal'),
.attr('data-bs-dismiss', 'modal'),
]
}
@ -671,19 +685,19 @@ class ModalFactory {
getFooterConfirm() {
let variant = this.options.type.split('-')[1]
variant = variant !== undefined ? variant : 'primary'
const $buttonCancel = $('<button type="button" class="btn btn-secondary" data-dismiss="modal"></button>')
const $buttonCancel = $('<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"></button>')
.text(this.options.cancelText)
.click(
(evt) => {
this.options.cancel(() => { this.hide() }, this, evt)
}
)
.attr('data-dismiss', (this.options.closeManually || !this.options.closeOnSuccess) ? '' : 'modal')
.attr('data-bs-dismiss', (this.options.closeManually || !this.options.closeOnSuccess) ? '' : 'modal')
const $buttonConfirm = $('<button type="button" class="btn"></button>')
.addClass('btn-' + variant)
.text(this.options.confirmText)
.attr('data-dismiss', (this.options.closeManually || this.options.closeOnSuccess) ? '' : 'modal')
.attr('data-bs-dismiss', (this.options.closeManually || this.options.closeOnSuccess) ? '' : 'modal')
$buttonConfirm.click(this.getConfirmationHandlerFunction($buttonConfirm))
return [$buttonCancel, $buttonConfirm]
}
@ -834,11 +848,7 @@ class OverlayFactory {
constructor(node, options={}) {
this.node = node
this.$node = $(this.node)
if (darkMode) {
this.options = Object.assign({}, OverlayFactory.defaultOptionsDarkTheme, options)
} else {
this.options = Object.assign({}, OverlayFactory.defaultOptions, options)
}
this.options = Object.assign({}, OverlayFactory.defaultOptions, options)
this.options.auto = options.auto ? this.options.auto : !(options.variant || options.spinnerVariant)
if (this.options.auto) {
this.adjustOptionsBasedOnNode()
@ -856,18 +866,6 @@ class OverlayFactory {
* @property {boolean} spinnerSmall - If the spinner inside the overlay should be small
* @property {string=('border'|'grow')} spinnerSmall - If the spinner inside the overlay should be small
*/
static defaultOptionsDarkTheme = {
text: '',
variant: 'light',
opacity: 0.25,
blur: '2px',
rounded: false,
auto: true,
spinnerVariant: '',
spinnerSmall: false,
spinnerType: 'border',
fallbackBoostrapVariant: 'light'
}
static defaultOptions = {
text: '',
variant: 'light',
@ -884,7 +882,7 @@ class OverlayFactory {
static overlayWrapper = '<div aria-busy="true" class="position-relative"/>'
static overlayContainer = '<div class="position-absolute text-nowrap" style="inset: 0px; z-index: 10;"/>'
static overlayBg = '<div class="position-absolute" style="inset: 0px;"/>'
static overlayBg = '<div class="position-absolute loading-overlay" style="inset: 0px;"/>'
static overlaySpinner = '<div class="position-absolute" style="top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%);"><span aria-hidden="true" class=""><!----></span></div></div>'
static overlayText = '<span class="ml-1 align-text-top"></span>'

File diff suppressed because it is too large Load Diff

View File

@ -115,9 +115,51 @@ function getTextColour(hex) {
}
}
function performGlobalSearch(evt) {
const $input = $('#globalSearch')
const $resultContainer = $('.global-search-result-container')
const value = $input.val()
const leftKey = 37,
upKey = 38,
rightKey = 39,
downKey = 40,
ingoredKeys = [leftKey, upKey, rightKey, downKey]
if (ingoredKeys.indexOf(evt.keyCode) != -1) {
return;
}
if (value.length < 3 && evt.keyCode != 13) {
$('#dropdownMenuSearchAll').dropdown('hide')
return;
}
const endpoint = '/instance/searchAll'
const searchParams = new URLSearchParams({search: value});
const url = endpoint + '?' + searchParams
const options = {
statusNode: $resultContainer
}
$('#dropdownMenuSearchAll').dropdown('show')
AJAXApi.quickFetchURL(url, options).then((theHTML) => {
$resultContainer.html(theHTML)
})
}
function focusSearchResults(evt) {
const upKey = 38,
downKey = 40
if ([upKey, downKey].indexOf(evt.keyCode) != -1) {
$('.global-search-result-container').find('.dropdown-item').first().focus()
}
}
var UI
$(document).ready(() => {
if (typeof UIFactory !== "undefined") {
UI = new UIFactory()
}
const debouncedGlobalSearch = debounce(performGlobalSearch, 400)
$('#globalSearch')
.keydown(debouncedGlobalSearch)
.keydown(focusSearchResults);
})

148
webroot/js/utils.js Normal file
View File

@ -0,0 +1,148 @@
// https://github.com/lodash/lodash/blob/master/debounce.js
function debounce(func, wait, options) {
let lastArgs,
lastThis,
maxWait,
result,
timerId,
lastCallTime
let lastInvokeTime = 0
let leading = false
let maxing = false
let trailing = true
// Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
const useRAF = (!wait && wait !== 0 && typeof root.requestAnimationFrame === 'function')
if (typeof func !== 'function') {
throw new TypeError('Expected a function')
}
wait = +wait || 0
if (typeof options === 'objects') {
leading = !!options.leading
maxing = 'maxWait' in options
maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait
trailing = 'trailing' in options ? !!options.trailing : trailing
}
function invokeFunc(time) {
const args = lastArgs
const thisArg = lastThis
lastArgs = lastThis = undefined
lastInvokeTime = time
result = func.apply(thisArg, args)
return result
}
function startTimer(pendingFunc, wait) {
if (useRAF) {
root.cancelAnimationFrame(timerId)
return root.requestAnimationFrame(pendingFunc)
}
return setTimeout(pendingFunc, wait)
}
function cancelTimer(id) {
if (useRAF) {
return root.cancelAnimationFrame(id)
}
clearTimeout(id)
}
function leadingEdge(time) {
// Reset any `maxWait` timer.
lastInvokeTime = time
// Start the timer for the trailing edge.
timerId = startTimer(timerExpired, wait)
// Invoke the leading edge.
return leading ? invokeFunc(time) : result
}
function remainingWait(time) {
const timeSinceLastCall = time - lastCallTime
const timeSinceLastInvoke = time - lastInvokeTime
const timeWaiting = wait - timeSinceLastCall
return maxing
? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
: timeWaiting
}
function shouldInvoke(time) {
const timeSinceLastCall = time - lastCallTime
const timeSinceLastInvoke = time - lastInvokeTime
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
(timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait))
}
function timerExpired() {
const time = Date.now()
if (shouldInvoke(time)) {
return trailingEdge(time)
}
// Restart the timer.
timerId = startTimer(timerExpired, remainingWait(time))
}
function trailingEdge(time) {
timerId = undefined
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if (trailing && lastArgs) {
return invokeFunc(time)
}
lastArgs = lastThis = undefined
return result
}
function cancel() {
if (timerId !== undefined) {
cancelTimer(timerId)
}
lastInvokeTime = 0
lastArgs = lastCallTime = lastThis = timerId = undefined
}
function flush() {
return timerId === undefined ? result : trailingEdge(Date.now())
}
function pending() {
return timerId !== undefined
}
function debounced(...args) {
const time = Date.now()
const isInvoking = shouldInvoke(time)
lastArgs = args
lastThis = this
lastCallTime = time
if (isInvoking) {
if (timerId === undefined) {
return leadingEdge(lastCallTime)
}
if (maxing) {
// Handle invocations in a tight loop.
timerId = startTimer(timerExpired, wait)
return invokeFunc(lastCallTime)
}
}
if (timerId === undefined) {
timerId = startTimer(timerExpired, wait)
}
return result
}
debounced.cancel = cancel
debounced.flush = flush
debounced.pending = pending
return debounced
}

View File

@ -0,0 +1,17 @@
{
"name": "theme",
"version": "1.0.0",
"description": "Create theme for the application",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"autobuild": "node-sass --watch scss -o ../css/themes",
"build": "node-sass scss -o ../css/themes"
},
"author": "",
"license": "ISC",
"dependencies": {
"bootstrap": "4.6",
"node-sass": "^6.0.1"
}
}

View File

@ -0,0 +1,173 @@
// Darkly 5.1.1
// Bootswatch
$theme: "darkly" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #ebebeb !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #888 !default;
$gray-700: #444 !default;
$gray-800: #303030 !default;
$gray-900: #222 !default;
$black: #000 !default;
$blue: #375a7f !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #e74c3c !default;
$orange: #fd7e14 !default;
$yellow: #f39c12 !default;
$green: #00bc8c !default;
$teal: #20c997 !default;
$cyan: #3498db !default;
$primary: $blue !default;
$secondary: $gray-700 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-500 !default;
$dark: $gray-800 !default;
$min-contrast-ratio: 1.9 !default;
// Body
$body-bg: $gray-900 !default;
$body-color: $white !default;
// Links
$link-color: $success !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: Lato, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
$h1-font-size: 3rem !default;
$h2-font-size: 2.5rem !default;
$h3-font-size: 2rem !default;
$text-muted: $gray-600 !default;
// Tables
$table-border-color: $gray-700 !default;
$table-bg-scale: 0 !default;
// Forms
$input-bg: $white !default;
$input-color: $gray-800 !default;
$input-border-color: $body-bg !default;
$input-group-addon-color: $gray-500 !default;
$input-group-addon-bg: $gray-700 !default;
$form-check-input-bg: $white !default;
$form-check-input-border: none !default;
$form-file-button-color: $white !default;
// Dropdowns
$dropdown-bg: $gray-900 !default;
$dropdown-border-color: $gray-700 !default;
$dropdown-divider-bg: $gray-700 !default;
$dropdown-link-color: $white !default;
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: $primary !default;
// Navs
$nav-link-padding-x: 2rem !default;
$nav-link-disabled-color: $gray-500 !default;
$nav-tabs-border-color: $gray-700 !default;
$nav-tabs-link-hover-border-color: $nav-tabs-border-color $nav-tabs-border-color transparent !default;
$nav-tabs-link-active-color: $white !default;
$nav-tabs-link-active-border-color: $nav-tabs-border-color $nav-tabs-border-color transparent !default;
// Navbar
$navbar-padding-y: 1rem !default;
$navbar-dark-color: rgba($white, .6) !default;
$navbar-dark-hover-color: $white !default;
$navbar-light-color: rgba($gray-900, .7) !default;
$navbar-light-hover-color: $gray-900 !default;
$navbar-light-active-color: $gray-900 !default;
$navbar-light-toggler-border-color: rgba($gray-900, .1) !default;
// Pagination
$pagination-color: $white !default;
$pagination-bg: $success !default;
$pagination-border-width: 0 !default;
$pagination-border-color: transparent !default;
$pagination-hover-color: $white !default;
$pagination-hover-bg: lighten($success, 10%) !default;
$pagination-hover-border-color: transparent !default;
$pagination-active-bg: $pagination-hover-bg !default;
$pagination-active-border-color: transparent !default;
$pagination-disabled-color: $white !default;
$pagination-disabled-bg: darken($success, 15%) !default;
$pagination-disabled-border-color: transparent !default;
// Cards
$card-cap-bg: $gray-700 !default;
$card-bg: $gray-800 !default;
// Popovers
$popover-bg: $gray-800 !default;
$popover-header-bg: $gray-700 !default;
// Toasts
$toast-background-color: $gray-700 !default;
$toast-header-background-color: $gray-800 !default;
// Modals
$modal-content-bg: $gray-800 !default;
$modal-content-border-color: $gray-700 !default;
$modal-header-border-color: $gray-700 !default;
// Progress bars
$progress-bg: $gray-700 !default;
// List group
$list-group-color: $body-color !default;
$list-group-bg: $gray-800 !default;
$list-group-border-color: $gray-700 !default;
$list-group-hover-bg: $gray-700 !default;
$list-group-action-hover-color: $list-group-color !default;
$list-group-action-active-bg: $gray-900 !default;
// Breadcrumbs
$breadcrumb-padding-y: .375rem !default;
$breadcrumb-padding-x: .75rem !default;
$breadcrumb-bg: $gray-700 !default;
$breadcrumb-border-radius: .25rem !default;
// Close
$btn-close-color: $white !default;
$btn-close-opacity: .4 !default;
$btn-close-hover-opacity: 1 !default;
// Code
$pre-color: inherit !default;

View File

@ -0,0 +1,113 @@
// Flatly 5.1.1
// Bootswatch
$theme: "flatly" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #ecf0f1 !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #b4bcc2 !default;
$gray-600: #95a5a6 !default;
$gray-700: #7b8a8b !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$black: #000 !default;
$blue: #2c3e50 !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #e74c3c !default;
$orange: #fd7e14 !default;
$yellow: #f39c12 !default;
$green: #18bc9c !default;
$teal: #20c997 !default;
$cyan: #3498db !default;
$primary: $blue !default;
$secondary: $gray-600 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-200 !default;
$dark: $gray-700 !default;
$min-contrast-ratio: 2.05 !default;
// Links
$link-color: $success !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: Lato, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
$h1-font-size: 3rem !default;
$h2-font-size: 2.5rem !default;
$h3-font-size: 2rem !default;
// Tables
$table-bg-scale: 0 !default;
// Dropdowns
$dropdown-link-color: $gray-700 !default;
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: $primary !default;
// Navs
$nav-link-padding-y: .5rem !default !default;
$nav-link-padding-x: 2rem !default;
$nav-link-disabled-color: $gray-600 !default !default;
$nav-tabs-border-color: $gray-200 !default;
// Navbar
$navbar-padding-y: 1rem !default;
$navbar-dark-color: $white !default;
$navbar-dark-hover-color: $primary !default;
$navbar-dark-active-color: $primary !default;
$navbar-dark-brand-color: $white !default;
$navbar-dark-brand-hover-color: $navbar-dark-brand-color !default;
// Pagination
$pagination-color: $white !default;
$pagination-bg: $success !default;
$pagination-border-width: 0 !default;
$pagination-border-color: transparent !default;
$pagination-hover-color: $white !default;
$pagination-hover-bg: darken($success, 15%) !default;
$pagination-hover-border-color: transparent !default;
$pagination-active-bg: $pagination-hover-bg !default;
$pagination-active-border-color: transparent !default;
$pagination-disabled-color: $gray-200 !default;
$pagination-disabled-bg: lighten($success, 15%) !default;
$pagination-disabled-border-color: transparent !default;
// List group
$list-group-hover-bg: $gray-200 !default;
$list-group-disabled-bg: $gray-200 !default;
// Breadcrumbs
$breadcrumb-padding-y: .375rem !default;
$breadcrumb-padding-x: .75rem !default;
$breadcrumb-border-radius: .25rem !default;
// Close
$btn-close-color: $white !default;
$btn-close-opacity: .4 !default;
$btn-close-hover-opacity: 1 !default;

View File

@ -0,0 +1,106 @@
// Minty 5.1.1
// Bootswatch
$theme: "minty" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #f7f7f9 !default;
$gray-300: #eceeef !default;
$gray-400: #ced4da !default;
$gray-500: #aaa !default;
$gray-600: #888 !default;
$gray-700: #5a5a5a !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$black: #000 !default;
$blue: #007bff !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #ff7851 !default;
$orange: #fd7e14 !default;
$yellow: #ffce67 !default;
$green: #56cc9d !default;
$teal: #20c997 !default;
$cyan: #6cc3d5 !default;
$primary: #78c2ad !default;
$secondary: #f3969a !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$dark: $gray-800 !default;
$min-contrast-ratio: 1.45 !default;
// Body
$body-color: $gray-600 !default;
// Components
$border-radius: .4rem !default;
$border-radius-lg: .6rem !default;
$border-radius-sm: .3rem !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$headings-font-family: Montserrat, -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !default;
$headings-color: $gray-700 !default;
// Tables
$table-border-color: rgba(0, 0, 0, .05) !default;
$table-bg-scale: 0 !default;
// Dropdowns
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: $secondary !default;
// Navbar
$navbar-dark-color: rgba($white, .6) !default;
$navbar-dark-hover-color: $white !default;
$navbar-light-color: rgba($black, .3) !default;
$navbar-light-hover-color: $gray-700 !default;
$navbar-light-active-color: $gray-700 !default;
$navbar-light-disabled-color: rgba($black, .1) !default;
// Pagination
$pagination-color: $white !default;
$pagination-bg: $primary !default;
$pagination-border-color: $primary !default;
$pagination-hover-color: $white !default;
$pagination-hover-bg: $secondary !default;
$pagination-hover-border-color: $pagination-hover-bg !default;
$pagination-active-bg: $secondary !default;
$pagination-active-border-color: $pagination-active-bg !default;
$pagination-disabled-color: $white !default;
$pagination-disabled-bg: #cce8e0 !default;
$pagination-disabled-border-color: $pagination-disabled-bg !default;
// Alerts
$alert-color-scale: 0% !default;
$alert-bg-scale: 0 !default;
// Breadcrumbs
$breadcrumb-padding-y: .375rem !default;
$breadcrumb-padding-x: .75rem !default;
$breadcrumb-bg: $primary !default;
$breadcrumb-divider-color: $white !default;
$breadcrumb-active-color: $breadcrumb-divider-color !default;
$breadcrumb-border-radius: .25rem !default;

View File

@ -0,0 +1,229 @@
// Quartz 5.1.1
// Bootswatch
$theme: "quartz" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #e9e9e8 !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #6c757d !default;
$gray-700: #495057 !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$black: #000 !default;
$blue: #3a8fd9 !default;
$indigo: #6610f2 !default;
$purple: #686dc3 !default;
$pink: #e83283 !default;
$red: #fc346f !default;
$orange: #fd7e14 !default;
$yellow: #ffc107 !default;
$green: #41d7a7 !default;
$teal: #528fb3 !default;
$cyan: #39cbfb !default;
$primary: $pink !default;
$secondary: rgba($white, .4) !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $orange !default;
$light: $gray-200 !default;
$dark: $gray-900 !default;
$min-contrast-ratio: 1.5 !default;
// Spacing
$spacer: 2rem !default;
// Body
$body-bg: $purple !default;
$body-color: $white !default;
// Links
$link-color: $white !default;
// Components
$border-color: rgba($white, .2) !default;
$border-radius: .5rem !default;
$border-radius-sm: .6rem !default;
$border-radius-lg: .7rem !default;
$border-radius-pill: 50rem !default;
$box-shadow: 1px 3px 24px -1px rgba($black, .15) !default;
$box-shadow-sm: 0 1px 1px rgba($black, .1) !default;
// Fonts
$headings-font-weight: 700 !default;
$text-muted: rgba($white, .7) !default;
$blockquote-footer-color: $text-muted !default;
// Tables
$table-dark-bg: $dark !default;
$table-dark-border-color: darken($dark, 5%) !default;
$table-bg-scale: 0 !default;
// Buttons + Forms
$input-btn-padding-y: .75rem !default;
$input-btn-padding-x: 1.5rem !default;
// Buttons
$btn-box-shadow: $box-shadow !default;
// Forms
$input-bg: transparent !default;
$input-disabled-bg: rgba($white, .1) !default;
$input-border-color: rgba($white, .4) !default;
$input-border-width: 1px !default;
$input-focus-border-color: $input-border-color !default;
$input-focus-box-shadow: none !default;
$input-placeholder-color: $text-muted !default;
$form-switch-color: $white !default;
$form-switch-focus-color: $form-switch-color !default;
$input-group-addon-bg: transparent !default;
$form-check-input-bg: rgba($white, .3) !default;
$form-check-input-border: 1px solid $border-color !default;
$form-select-indicator-color: $white !default;
$form-select-focus-box-shadow: none !default;
$form-range-track-bg: rgba($black, .2) !default;
$form-range-thumb-disabled-bg: $gray-500 !default;
// Navs
$nav-link-disabled-color: $text-muted !default;
$nav-tabs-border-width: 0 !default;
$nav-tabs-border-radius: 0 !default;
$nav-tabs-link-active-color: $gray-800 !default;
$nav-tabs-link-active-bg: $white !default;
$nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default;
$nav-pills-border-radius: $border-radius-pill !default;
$nav-pills-link-active-color: $white !default;
$nav-pills-link-active-bg: $primary !default;
// Navbars
$navbar-dark-color: rgba($white, .8) !default;
$navbar-dark-hover-color: $white !default;
$navbar-light-color: rgba($gray-800, .8) !default;
$navbar-light-hover-color: $gray-800 !default;
$navbar-light-active-color: $gray-800 !default;
$navbar-light-disabled-color: rgba($gray-800, .3) !default;
// Dropdowns
$dropdown-border-color: $border-color !default;
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: rgba($white, .4) !default;
// Pagination
$pagination-bg: rgba($white, .3) !default;
$pagination-border-width: 0 !default;
$pagination-focus-color: $white !default;
$pagination-focus-bg: $dropdown-link-hover-bg !default;
$pagination-focus-box-shadow: none !default;
$pagination-hover-color: $white !default;
$pagination-hover-bg: $dropdown-link-hover-bg !default;
$pagination-disabled-color: $text-muted !default;
$pagination-disabled-bg: $pagination-bg !default;
// Cards
$card-spacer-y: 1.75rem !default;
$card-spacer-x: 2rem !default;
$card-border-color: $border-color !default;
$card-cap-bg: transparent !default;
$card-cap-color: $white !default;
$card-color: $white !default;
$card-bg: transparent !default;
// Accordion
$accordion-button-bg: $secondary !default;
$accordion-button-active-bg: $primary !default;
$accordion-button-active-color: $white !default;
// Tooltips
$tooltip-opacity: .7 !default;
// Popovers
$popover-header-bg: $card-cap-bg !default;
$popover-body-color: $card-color !default;
$popover-body-padding-y: $spacer / 2 !default;
$popover-arrow-color: $border-color !default;
$popover-arrow-outer-color: transparent !default;
// Toasts
$toast-header-color: $card-color !default;
$toast-header-background-color: $card-cap-bg !default;
$toast-header-border-color: $border-color !default;
// Progress bars
$progress-bg: rgba($black, .2) !default;
// List group
$list-group-color: $white !default;
$list-group-bg: transparent !default;
$list-group-border-color: $border-color !default;
$list-group-border-width: 0 !default;
$list-group-hover-bg: $dropdown-link-hover-bg !default;
$list-group-disabled-color: $text-muted !default;
$list-group-action-color: $white !default;
$list-group-action-hover-color: $white !default;
// Breadcrumbs
$breadcrumb-divider-color: $white !default;
$breadcrumb-active-color: $white !default;
// Close
$btn-close-color: $white !default;

Some files were not shown because too many files have changed in this diff Show More