Skip to content

Commit

Permalink
Merge pull request #346 from mwehr/override_brand_colors
Browse files Browse the repository at this point in the history
#155 Allow overwriting of brand colors in flavours
  • Loading branch information
abias authored Dec 29, 2024
2 parents 630ac4d + d0515fe commit dc8fc19
Show file tree
Hide file tree
Showing 19 changed files with 1,127 additions and 164 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Changes

### Unreleased

* 2024-12-25 - Documentation: Explain the SCSS stack order in the README.
* 2024-12-25 - Bugfix: Fix the order in which all the pre SCSS assets are added to the SCSS stack, resolves #788.
* 2024-12-22 - Feature: Allow overwriting of brand colors and the usage of SCSS (instead of pure CSS) in flavours, resolves #155.
* 2024-12-15 - Feature: Add declaration of accessibility page and accessibility support page, resolves #567.

### v4.5-r4
Expand Down
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,63 @@ https://github.com/moodle-an-hochschulen/moodle-theme_boost_union_child
While Boost Union Child will surely help you to realize all your local Boost Union dreams, please do yourself and the whole community a favour and verify that your planned features are indeed not interesting as a pull request or feature request for the whole Boost Union community and could be contributed to Boost Union directly instead.


SCSS stack order
----------------

Within Boost Union, you have multiple possibilities to add your own SCSS code to the Moodle page. And many of the Boost Union settings add SCSS code as well to realize the particular setting's goal. However, as you know, in SCSS the order of the instructions is key.

The following list should give you an insight in which order all the SCSS code is added to the CSS stack which is shipped to the browser in the end.
To fully understand this list, you have to be aware of two terms in Moodle theming:

* _Pre SCSS_ or _Raw Initial SCSS_:\
This SCSS code is used only to initialize SCSS variables and not to write real SCSS code directly.
* _Post SCSS_ or _Raw SCSS_:\
This SCSS code is the real SCSS code which is compiled to CSS for the browser and which might consume the SCSS variables which have been set in the Pre SCSS.

Having said that, here's the order how all the SCSS code is added to the SCSS stack:

1. All plugins' `styles.css` files:\
Each Moodle plugin can ship with a `styles.css` file which contains CSS code (not SCSS code!) for the plugin. These files are added at the very beginning in the order of the plugin names and types.

2. `theme_boost` > `get_pre_scss()`:
* Adds the Boost Union Pre SCSS from the theme settings\
(which is set on `/admin/settings.php?section=theme_boost_union_look#theme_boost_union_look_scss`).\
Note: In fact, this function adds the _active theme's_ Pre SCSS which becomes important if you use a Boost Union Child theme.

3. `theme_boost_union` > `get_pre_scss()`:
* Adds the Boost Union Pre SCSS from disk\
(which is located on `/theme/boost_union/scss/boost_union/pre.scss` and which is empty currently)
* Sets several SCSS variables based on Boost Union or Boost Union flavour settings
* Adds the Boost Union external Pre SCSS\
(which is set on `/admin/settings.php?section=theme_boost_union_look#theme_boost_union_look_scss`)
* Adds the Boost Union flavour Pre SCSS\
(which is set within the active flavour on `/theme/boost_union/flavours/overview.php`)

4. `theme_boost_union` > `get_main_scss()`:
* Calls the `theme_boost` > `get_main_scss()` function
* Adds the Boost Core Preset\
(which is set on `/admin/settings.php?section=themesettingboost` and defaults to the `/theme/boost/scss/preset/default.scss` file).
With this preset, the FontAwesome library, the Bootstrap library and all the Moodle core stylings are added which means that this preset is the place where all the Moodle core style is added.
* Adds the Boost Union Post SCSS from disk\
(which is located on `/theme/boost_union/scss/boost_union/post.scss`)
This file holds all the Boost Union specific SCSS code which can be added to the stack without being dependent on specific configurations like configured colors or sizes.
* Add the Boost Union external SCSS\
(which is set on `/admin/settings.php?section=theme_boost_union_look#theme_boost_union_look_scss`)

5. `theme_boost` > `get_extra_scss()`:
* Adds the Boost Union Post SCSS from the theme settings\
(which is set on `/admin/settings.php?section=theme_boost_union_look#theme_boost_union_look_scss`).\
Note: In fact, this function adds the _active theme's_ Post SCSS which becomes important if you use a Boost Union Child theme.
* Adds the page background image and login page background image

6. `theme_boost_union` > `get_extra_scss()`:
* Overrides / enhances the background images which have been set before
* Adds the Boost Union flavour Post SCSS\
(which is set within the active flavour on `/theme/boost_union/flavours/overview.php`)
* Adds the Boost Union features' SCSS.
This is the Boost Union specific SCSS code which has to be added to the stack based on specific configurations, for example for changing the activity icon purposes or for changing the login form order.


Plugin repositories
-------------------

Expand Down Expand Up @@ -855,6 +912,7 @@ Moodle an Hochschulen e.V. would like to thank these main contributors (in alpha
* lern.link GmbH, Alexander Bias: Code, Peer Review, Ideating, Funding
* lern.link GmbH, Lukas MuLu Müller: Code
* lern.link GmbH, Beata Waloszczyk: Code
* Lutheran University of Applied Sciences Nuremberg: Funding
* Moodle.NRW / Ruhr University Bochum, Annika Lambert: Code
* Moodle.NRW / Ruhr University Bochum, Matthias Buttgereit: Code, Ideating
* Moodle.NRW / Ruhr University Bochum, Tim Trappen: Code, Ideating
Expand Down
200 changes: 193 additions & 7 deletions classes/form/flavour_edit_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,29 @@ class flavour_edit_form extends \moodleform {
* @throws \coding_exception
*/
public function definition() {
global $CFG, $OUTPUT;

// Get an easier handler for the form.
$mform = $this->_form;

// Prepare yes-no option for multiple usage.
$yesnooption = [false => get_string('no'), true => get_string('yes')];

// Require and register the QuickForm colorpicker element.
require_once($CFG->dirroot.'/theme/boost_union/classes/formelement/colorpicker.php');
\MoodleQuickForm::registerElementType(
'theme_boost_union_colorpicker',
$CFG->dirroot.'/theme/boost_union/classes/formelement/colorpicker.php',
'\theme_boost_union\formelement\colorpicker'
);
// Register validation rule for the QuickForm colorpicker element.
\MoodleQuickForm::registerRule(
'theme_boost_union_colorpicker_rule',
null,
'\theme_boost_union\formelement\colorpicker_rule',
$CFG->dirroot.'/theme/boost_union/classes/formelement/colorpicker_rule.php'
);

// Add the flavour ID as hidden element.
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
Expand All @@ -80,6 +97,17 @@ public function definition() {
$mform->addElement('header', 'looksettingsheader', get_string('configtitlelook', 'theme_boost_union'));
$mform->setExpanded('looksettingsheader');

// Add logos heading.
$context = new \stdClass();
$context->title = get_string('logosheading', 'theme_boost_union', null, true);
$mform->addElement(
'html',
// Wrapping the setting headings with a div with the ID "adminsettings" is not really correct as we will have
// duplicate IDs on the page. But it is the only way to re-use the correct styling for the setting heading.
// (And no, applying the ID to the form does not work either as we would trigger other unwanted stylings).
'<div id="adminsettings">'.$OUTPUT->render_from_template('core_admin/setting_heading', $context).'</div>'
);

// Add logo as filemanager element.
$mform->addElement('filemanager', 'flavours_look_logo',
get_string('logo', 'admin'), null, [
Expand All @@ -100,6 +128,14 @@ public function definition() {
]);
$mform->addHelpButton('flavours_look_logocompact', 'flavourslogocompact', 'theme_boost_union');

// Add favicon heading.
$context = new \stdClass();
$context->title = get_string('faviconheading', 'theme_boost_union', null, true);
$mform->addElement(
'html',
'<div id="adminsettings">'.$OUTPUT->render_from_template('core_admin/setting_heading', $context).'</div>'
);

// Add favicon as filemanager element.
$mform->addElement('filemanager', 'flavours_look_favicon',
get_string('faviconsetting', 'theme_boost_union'), null, [
Expand All @@ -110,6 +146,14 @@ public function definition() {
]);
$mform->addHelpButton('flavours_look_favicon', 'flavoursfavicon', 'theme_boost_union');

// Add backgroundimages heading.
$context = new \stdClass();
$context->title = get_string('backgroundimagesheading', 'theme_boost_union', null, true);
$mform->addElement(
'html',
'<div id="adminsettings">'.$OUTPUT->render_from_template('core_admin/setting_heading', $context).'</div>'
);

// Add backgroundimage as filemanager element.
$mform->addElement('filemanager', 'flavours_look_backgroundimage',
get_string('backgroundimagesetting', 'theme_boost_union'), null, [
Expand All @@ -120,14 +164,94 @@ public function definition() {
]);
$mform->addHelpButton('flavours_look_backgroundimage', 'flavoursbackgroundimage', 'theme_boost_union');

// Add custom css as textarea element.
// Note: In the current state of implementation, this setting only allows the usage of custom CSS, not SCSS.
// It will be appended to the stack of CSS code which is shipped to the browser.
// There is a follow-up issue on Github to add SCSS support.
// When this is realized, the widget's title string should be changed to 'theme_boost/rawscss'.
$mform->addElement('textarea', 'look_rawscss', get_string('flavourscustomcss', 'theme_boost_union'), ['rows' => 15]);
// Add brand colors heading.
$context = new \stdClass();
$context->title = get_string('brandcolorsheading', 'theme_boost_union', null, true);
$mform->addElement(
'html',
'<div id="adminsettings">'.$OUTPUT->render_from_template('core_admin/setting_heading', $context).'</div>'
);

// Add brandcolor as colorpicker element.
$this->check_slasharguments_warning($mform);
$mform->addElement(
'theme_boost_union_colorpicker',
'look_brandcolor',
get_string('flavoursbrandcolor', 'theme_boost_union'),
['id' => 'colourpicker_brandcolour']);
$mform->setType('look_brandcolor', PARAM_TEXT);
$mform->addRule('look_brandcolor', get_string('validateerror', 'admin'), 'theme_boost_union_colorpicker_rule');
$mform->addHelpButton('look_brandcolor', 'flavoursbrandcolor', 'theme_boost_union');

// Add Bootstrap colors heading.
$context = new \stdClass();
$context->title = get_string('bootstrapcolorsheading', 'theme_boost_union', null, true);
$mform->addElement(
'html',
'<div id="adminsettings">'.$OUTPUT->render_from_template('core_admin/setting_heading', $context).'</div>'
);

// Add Bootstrap color for 'success' as colorpicker element.
$this->check_slasharguments_warning($mform);
$mform->addElement(
'theme_boost_union_colorpicker',
'look_bootstrapcolorsuccess',
get_string('flavoursbootstrapcolorsuccess', 'theme_boost_union'),
['id' => 'colourpicker_bootstrapcolorsuccess']);
$mform->setType('look_bootstrapcolorsuccess', PARAM_TEXT);
$mform->addRule('look_bootstrapcolorsuccess', get_string('validateerror', 'admin'), 'theme_boost_union_colorpicker_rule');
$mform->addHelpButton('look_bootstrapcolorsuccess', 'flavoursbootstrapcolorsuccess', 'theme_boost_union');

// Add Bootstrap color for 'info' as colorpicker element.
$this->check_slasharguments_warning($mform);
$mform->addElement(
'theme_boost_union_colorpicker',
'look_bootstrapcolorinfo',
get_string('flavoursbootstrapcolorinfo', 'theme_boost_union'),
['id' => 'colourpicker_bootstrapcolorinfo']);
$mform->setType('look_bootstrapcolorinfo', PARAM_TEXT);
$mform->addRule('look_bootstrapcolorinfo', get_string('validateerror', 'admin'), 'theme_boost_union_colorpicker_rule');
$mform->addHelpButton('look_bootstrapcolorinfo', 'flavoursbootstrapcolorinfo', 'theme_boost_union');

// Add Bootstrap color for 'warning' as colorpicker element.
$this->check_slasharguments_warning($mform);
$mform->addElement(
'theme_boost_union_colorpicker',
'look_bootstrapcolorwarning',
get_string('flavoursbootstrapcolorwarning', 'theme_boost_union'),
['id' => 'colourpicker-bootstrapcolorwarning']);
$mform->setType('look_bootstrapcolorwarning', PARAM_TEXT);
$mform->addRule('look_bootstrapcolorwarning', get_string('validateerror', 'admin'), 'theme_boost_union_colorpicker_rule');
$mform->addHelpButton('look_bootstrapcolorwarning', 'flavoursbootstrapcolorwarning', 'theme_boost_union');

// Add Bootstrap color for 'danger' as colorpicker element.
$this->check_slasharguments_warning($mform);
$mform->addElement(
'theme_boost_union_colorpicker',
'look_bootstrapcolordanger',
get_string('flavoursbootstrapcolordanger', 'theme_boost_union'),
['id' => 'colourpicker-bbootstrapcolordanger']);
$mform->setType('look_bootstrapcolordanger', PARAM_TEXT);
$mform->addRule('look_bootstrapcolordanger', get_string('validateerror', 'admin'), 'theme_boost_union_colorpicker_rule');
$mform->addHelpButton('look_bootstrapcolordanger', 'flavoursbootstrapcolordanger', 'theme_boost_union');

// Add SCSS heading.
$context = new \stdClass();
$context->title = get_string('scssheading', 'theme_boost_union', null, true);
$mform->addElement(
'html',
'<div id="adminsettings">'.$OUTPUT->render_from_template('core_admin/setting_heading', $context).'</div>'
);

// Add custom initial SCSS as textarea element.
$mform->addElement('textarea', 'look_rawscsspre', get_string('flavourscustomscsspre', 'theme_boost_union'), ['rows' => 8]);
$mform->setType('title', PARAM_TEXT);
$mform->addHelpButton('look_rawscsspre', 'flavourscustomscsspre', 'theme_boost_union');

// Add custom SCSS as textarea element.
$mform->addElement('textarea', 'look_rawscss', get_string('flavourscustomscss', 'theme_boost_union'), ['rows' => 8]);
$mform->setType('title', PARAM_TEXT);
$mform->addHelpButton('look_rawscss', 'flavourscustomcss', 'theme_boost_union');
$mform->addHelpButton('look_rawscss', 'flavourscustomscss', 'theme_boost_union');

// Add apply-to-cohort as header element.
$mform->addElement('header', 'applytocohortheader', get_string('flavoursapplytocohorts', 'theme_boost_union'));
Expand Down Expand Up @@ -184,4 +308,66 @@ public function definition() {
// Add the action buttons.
$this->add_action_buttons();
}

/**
* Theme Boost Union - Flavours edit form validation
*
* The routine to check the SCSS code is copied and modified from admin_setting_scsscode in /lib/adminlib.php.
*
* @param array $data array of ("fieldname"=>value) of submitted data
* @param array $files array of uploaded files "element_name"=>tmp_file_path
* @return array of "element_name"=>"error_description" if there are errors,
* or an empty array if everything is OK (true allowed for backwards compatibility too).
*/
public function validation($data, $files) {
global $PAGE;

$errors = [];

// If we have any data.
if (!empty($data)) {
// Iterate over the SCSS fields.
foreach (['look_rawscss', 'look_rawscsspre'] as $field) {
// Check if the SCSS code can be compiled.
if (!empty($data[$field])) {
$compiler = new \core_scss();
try {
if ($scssproperties = $PAGE->theme->get_scss_property()) {
$compiler->setImportPaths($scssproperties[0]);
}
$compiler->compile($data[$field]);
} catch (\ScssPhp\ScssPhp\Exception\ParserException $e) {
$errors[$field] = get_string('scssinvalid', 'admin', $e->getMessage());
// phpcs:disable Generic.CodeAnalysis.EmptyStatement.DetectedCatch
} catch (\ScssPhp\ScssPhp\Exception\CompilerException $e) {
// Silently ignore this - it could be a SCSS variable defined from somewhere
// else which we are not examining here.
}
}
}
}

return $errors;
}

/**
* Helper function which adds a warning notification to the form if slasharguments is disabled.
*
* @param \MoodleQuickForm $mform The form object.
* @return void
*/
private function check_slasharguments_warning($mform) {
global $CFG, $OUTPUT;

// If slasharguments is disabled.
if (empty($CFG->slasharguments)) {
// Add a warning notification to the form.
$slashargumentsurl = new \core\url('/admin/search.php', ['query' => 'slasharguments']);
$notification = new \core\output\notification(
get_string('warningslashargumentsdisabled', 'theme_boost_union', ['url' => $slashargumentsurl]),
\core\output\notification::NOTIFY_WARNING);
$notification->set_show_closebutton(false);
$mform->addElement('html', $OUTPUT->render($notification));
}
}
}
Loading

0 comments on commit dc8fc19

Please sign in to comment.