From b4fdc625da4d8f797559b48659da0e796469d754 Mon Sep 17 00:00:00 2001 From: mokaddem Date: Sat, 18 Sep 2021 11:21:50 +0200 Subject: [PATCH] chg: [setting] Support of themes in settings --- config/cerebrate.php | 2 +- src/Controller/AppController.php | 3 +-- src/Model/Table/InstanceTable.php | 19 +++++++++++++++ src/Model/Table/SettingsProviderTable.php | 29 +++++++++++++++++------ src/View/Helper/BootstrapHelper.php | 18 ++++++++------ templates/element/Settings/field.php | 27 ++++++--------------- webroot/css/bootstrap-additional.css | 20 ++++++++-------- webroot/css/main.css | 3 ++- 8 files changed, 73 insertions(+), 48 deletions(-) diff --git a/config/cerebrate.php b/config/cerebrate.php index bfb2cf9..26ab086 100644 --- a/config/cerebrate.php +++ b/config/cerebrate.php @@ -4,6 +4,6 @@ return [ 'open' => [], 'app.baseurl' => 'http://localhost:8000/', 'app.uuid' => 'cc9b9358-7c4b-4464-9a2c-f0cb089ff974', - 'ui.dark' => 0, + 'ui.bsTheme' => 'default', ] ]; diff --git a/src/Controller/AppController.php b/src/Controller/AppController.php index 0b24df2..34ab727 100644 --- a/src/Controller/AppController.php +++ b/src/Controller/AppController.php @@ -131,8 +131,7 @@ class AppController extends Controller $this->set('ajax', $this->request->is('ajax')); $this->request->getParam('prefix'); $this->set('baseurl', Configure::read('App.fullBaseUrl')); - Configure::write('app.bsTheme', 'default'); - $this->set('bsTheme',Configure::read('app.bsTheme')); + $this->set('bsTheme', Configure::read('Cerebrate')['ui.bsTheme']); if ($this->modelClass == 'Tags.Tags') { $this->set('metaGroup', !empty($this->isAdmin) ? 'Administration' : 'Cerebrate'); diff --git a/src/Model/Table/InstanceTable.php b/src/Model/Table/InstanceTable.php index 1110597..c1870f4 100644 --- a/src/Model/Table/InstanceTable.php +++ b/src/Model/Table/InstanceTable.php @@ -7,6 +7,7 @@ use Cake\ORM\Table; use Cake\ORM\TableRegistry; use Cake\Validation\Validator; use Migrations\Migrations; +use Cake\Filesystem\Folder; use Cake\Http\Exception\MethodNotAllowedException; class InstanceTable extends AppTable @@ -167,4 +168,22 @@ class InstanceTable extends AppTable 'success' => true ]; } + + public function getAvailableThemes() + { + $themesPath = ROOT . '/webroot/css/themes'; + $dir = new Folder($themesPath); + $filesRegex = 'bootstrap-(?P\w+)\.css'; + $themeRegex = '/' . 'bootstrap-(?P\w+)\.css' . '/'; + $files = $dir->find($filesRegex); + $themes = []; + foreach ($files as $filename) { + $matches = []; + $themeName = preg_match($themeRegex, $filename, $matches); + if (!empty($matches['themename'])) { + $themes[] = $matches['themename']; + } + } + return $themes; + } } diff --git a/src/Model/Table/SettingsProviderTable.php b/src/Model/Table/SettingsProviderTable.php index d70b2d2..5483352 100644 --- a/src/Model/Table/SettingsProviderTable.php +++ b/src/Model/Table/SettingsProviderTable.php @@ -3,6 +3,7 @@ namespace App\Model\Table; use App\Model\Table\AppTable; use Cake\Validation\Validator; +use Cake\ORM\TableRegistry; class SettingsProviderTable extends AppTable { @@ -140,14 +141,17 @@ class SettingsProviderTable extends AppTable ], 'UI' => [ 'General' => [ - 'ui.dark' => [ - 'name' => __('Dark theme'), - 'type' => 'boolean', - 'description' => __('Enable the dark theme of the application'), - 'default' => false, - 'test' => function() { - return 'Fake error'; + 'ui.bsTheme' => [ + 'description' => 'The Bootstrap theme to use for the application', + 'default' => 'default', + 'name' => 'UI Theme', + 'options' => function($settingsProviders) { + $instanceTable = TableRegistry::getTableLocator()->get('Instance'); + $themes = $instanceTable->getAvailableThemes(); + return array_combine($themes, $themes); }, + 'severity' => 'info', + 'type' => 'select' ], ], ], @@ -174,6 +178,17 @@ class SettingsProviderTable extends AppTable ] ], 'Features' => [ + 'Demo Settings' => [ + 'demo.switch' => [ + 'name' => __('Switch'), + 'type' => 'boolean', + 'description' => __('A switch acting as a checkbox'), + 'default' => false, + 'test' => function() { + return 'Fake error'; + }, + ], + ] ], ]; } diff --git a/src/View/Helper/BootstrapHelper.php b/src/View/Helper/BootstrapHelper.php index 2ea7a69..7d949b5 100644 --- a/src/View/Helper/BootstrapHelper.php +++ b/src/View/Helper/BootstrapHelper.php @@ -190,7 +190,9 @@ class BootstrapGeneric { $html = ''; foreach ($params as $k => $v) { - $html .= BootstrapGeneric::genHTMLParam($k, $v) . ' '; + if (!empty($k) && !empty($v)) { + $html .= BootstrapGeneric::genHTMLParam($k, $v) . ' '; + } } return $html; } @@ -1269,7 +1271,9 @@ class BoostrapSwitch extends BootstrapGeneric { 'variant' => 'primary', 'disabled' => false, 'checked' => false, - 'title' => '' + 'title' => '', + 'class' => [], + 'attrs' => [], ]; function __construct($options) { @@ -1299,15 +1303,15 @@ class BoostrapSwitch extends BootstrapGeneric { ], 'title' => $this->options['title'] ], implode('', [ - $this->genNode('input', [ + $this->genNode('input', array_merge([ 'type' => "checkbox", - 'class' => 'orm-check-input', + 'class' => 'form-check-input', 'id' => $tmpId, ($this->options['disabled'] ? 'disabled' : '') => '', - ($this->options['checked'] ? 'checked' : '') => $this->options['checked'] ? 'checked' : '' - ]), + ($this->options['checked'] ? 'checked' : '') => $this->options['checked'] ? 'checked' : '', + ], $this->options['attrs'])), $this->genNode('label', [ - 'class' => 'orm-check-label', + 'class' => 'form-check-label', 'for' => $tmpId, ], h($this->options['label'])) ])); diff --git a/templates/element/Settings/field.php b/templates/element/Settings/field.php index 8fb33fb..00f24fe 100644 --- a/templates/element/Settings/field.php +++ b/templates/element/Settings/field.php @@ -25,31 +25,18 @@ } elseif ($setting['type'] == 'boolean') { $input = (function ($settingName, $setting, $appView) { $settingId = str_replace('.', '_', $settingName); - $switch = $appView->Bootstrap->genNode('input', [ + return $this->Bootstrap->switch([ + 'label' => h($setting['description']), + 'checked' => !empty($setting['value']), + 'id' => $settingId, 'class' => [ - 'custom-control-input', (!empty($setting['error']) ? 'is-invalid' : ''), (!empty($setting['error']) ? $appView->get('variantFromSeverity')[$setting['severity']] : ''), ], - 'type' => 'checkbox', - 'value' => !empty($setting['value']) ? 1 : 0, - (!empty($setting['value']) ? 'checked' : '') => !empty($setting['value']) ? 'checked' : '', - 'id' => $settingId, - 'data-setting-name' => $settingName, + 'attrs' => [ + 'data-setting-name' => $settingName + ] ]); - $label = $appView->Bootstrap->genNode('label', [ - 'class' => [ - 'custom-control-label' - ], - 'for' => $settingId, - ], h($setting['description'])); - $container = $appView->Bootstrap->genNode('div', [ - 'class' => [ - 'custom-control', - 'form-switch', - ], - ], implode('', [$switch, $label])); - return $container; })($settingName, $setting, $this); $description = ''; diff --git a/webroot/css/bootstrap-additional.css b/webroot/css/bootstrap-additional.css index 3805c7b..ef148bb 100644 --- a/webroot/css/bootstrap-additional.css +++ b/webroot/css/bootstrap-additional.css @@ -159,34 +159,34 @@ div.progress-timeline .progress-line.progress-inactive { background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right 0.75rem center/8px 10px, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%2317a2b8' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%2317a2b8' stroke='none'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } -.custom-control-input.is-invalid.warning ~ .custom-control-label { +.form-check-input.is-invalid.warning ~ .form-check-label { color: unset; } -.custom-control-input.is-invalid.warning ~ .custom-control-label::before { +.form-check-input.is-invalid.warning ~ .form-check-label::before { border-color: #ffc107; } -.custom-control-input.is-invalid.warning:checked ~ .custom-control-label::before { +.form-check-input.is-invalid.warning:checked ~ .form-check-label::before { background-color: #ffc107; } -.custom-control-input.is-invalid.warning:focus:not(:checked) ~ .custom-control-label::before { +.form-check-input.is-invalid.warning:focus:not(:checked) ~ .form-check-label::before { border-color: #ffc107; } -.custom-control-input.is-invalid.warning:focus ~ .custom-control-label::before { +.form-check-input.is-invalid.warning:focus ~ .form-check-label::before { box-shadow: 0 0 0 0.2rem #ffc10740; } -.custom-control-input.is-invalid.info ~ .custom-control-label { +.form-check-input.is-invalid.info ~ .form-check-label { color: unset; } -.custom-control-input.is-invalid.info ~ .custom-control-label::before { +.form-check-input.is-invalid.info ~ .form-check-label::before { border-color: #17a2b8; } -.custom-control-input.is-invalid.info:checked ~ .custom-control-label::before { +.form-check-input.is-invalid.info:checked ~ .form-check-label::before { background-color: #17a2b8; } -.custom-control-input.is-invalid.info:focus:not(:checked) ~ .custom-control-label::before { +.form-check-input.is-invalid.info:focus:not(:checked) ~ .form-check-label::before { border-color: #17a2b8; } -.custom-control-input.is-invalid.info:focus ~ .custom-control-label::before { +.form-check-input.is-invalid.info:focus ~ .form-check-label::before { box-shadow: 0 0 0 0.2rem #17a2b840; } diff --git a/webroot/css/main.css b/webroot/css/main.css index dc8376c..9eff40c 100644 --- a/webroot/css/main.css +++ b/webroot/css/main.css @@ -170,7 +170,8 @@ input[type="checkbox"]:disabled.change-cursor { } .select2-container { - z-index: 1060; + /* z-index: 1060; */ + z-index: 1038; } .grow-on-hover {