]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Merge pull request #1317 from ArthurHoaro/feature/default-colors
authorArthurHoaro <arthur@hoa.ro>
Sat, 20 Jul 2019 07:36:39 +0000 (09:36 +0200)
committerGitHub <noreply@github.com>
Sat, 20 Jul 2019 07:36:39 +0000 (09:36 +0200)
Plugin to override default template colors

13 files changed:
.dev/.sasslintrc
.gitignore
assets/default/scss/shaarli.scss
doc/md/Plugin-System.md
doc/md/Plugins.md
inc/languages/fr/LC_MESSAGES/shaarli.po
index.php
plugins/default_colors/default_colors.css.template [new file with mode: 0644]
plugins/default_colors/default_colors.meta [new file with mode: 0644]
plugins/default_colors/default_colors.php [new file with mode: 0644]
plugins/demo_plugin/demo_plugin.meta
plugins/demo_plugin/demo_plugin.php
tests/plugins/PluginDefaultColorsTest.php [new file with mode: 0644]

index ac406d7b0418b7eb1e8729168cea270f417c029c..47c3145de4ce6518dd36a9d09a8049dd0a48c13d 100644 (file)
@@ -2,9 +2,11 @@ options:
   max-warnings: 0
 rules:
   property-sort-order:
-    - 1
-    -
-      order: 'concentric'
+    - 0
+# Sort order rule does not work with CSS variables: https://github.com/sasstools/sass-lint/issues/1161
+#    - 1
+#    -
+#      order: 'concentric'
   no-important:
     - 0
   no-vendor-prefixes:
index c54d9b693d056a0e8abad358464e5625356753e1..b21d2118f857712e35854e25266ab8ffcfa5713b 100644 (file)
@@ -28,6 +28,7 @@ phpdoc.xml
 
 # User plugin configuration
 plugins/*/config.php
+plugins/default_colors/default_colors.css
 
 # HTML documentation
 doc/html/
index 9e5464a0c8362fb233a7c71128d99e31d2cfdca2..1d89f9983b48a2f70fe97ef203b1a9f8718c123e 100644 (file)
@@ -25,9 +25,15 @@ $warning-text: #97600d;
 $form-input-border: #d8d8d8;
 $form-input-background: #eee;
 
+:root {
+  --main-color: #{$main-green};
+  --background-color: #{$background-color};
+  --dark-main-color: #{$dark-green};
+}
+
 // General
 body {
-  background: $background-color;
+  background: var(--background-color);
 }
 
 .strong {
@@ -143,7 +149,7 @@ body,
 }
 
 .pure-alert-success {
-  background-color: $main-green;
+  background-color: var(--main-color);
 }
 
 .pure-alert-warning {
@@ -169,7 +175,7 @@ body,
   top: 0;
   transition: max-height .5s;
   z-index: 999;
-  background: $main-green;
+  background: var(--main-color);
   width: 100%;
   // Hack to transition with auto height: http://stackoverflow.com/a/8331169/1484919
   max-height: 45px;
@@ -322,7 +328,7 @@ body,
   button {
     border: 0;
     border-radius: 2px;
-    background-color: $main-green;
+    background-color: var(--main-color);
     padding: 4px 8px 6px;
     color: $almost-white;
   }
@@ -358,7 +364,7 @@ body,
 .search-tagcloud {
   button {
     &:hover {
-      color: $background-color;
+      color: var(--background-color);
     }
   }
 }
@@ -389,7 +395,7 @@ body,
   position: fixed;
   visibility: hidden;
   z-index: 999;
-  background: $main-green;
+  background: var(--main-color);
   padding: 5px 0;
   width: 100%;
   height: 30px;
@@ -411,7 +417,7 @@ body,
     margin: 0 0 5px;
     border: 1px solid $almost-white;
     border-radius: 2px;
-    background: $main-green;
+    background: var(--main-color);
     padding: 4px 0;
     width: 100px;
     height: 28px;
@@ -419,7 +425,7 @@ body,
 
     &:hover {
       background: $almost-white;
-      color: $main-green;
+      color: var(--main-color);
     }
   }
 
@@ -558,7 +564,7 @@ body,
   }
 
   .filter-on {
-    background: $main-green;
+    background: var(--main-color);
     color: $light-green;
   }
 
@@ -697,7 +703,7 @@ body,
 
       &:visited {
         .linklist-link {
-          color: $dark-green;
+          color: var(--dark-main-color);
         }
       }
 
@@ -708,7 +714,7 @@ body,
   }
 
   .linklist-link {
-    color: $main-green;
+    color: var(--main-color);
     font-size: 1.1em;
 
     &:hover {
@@ -783,14 +789,14 @@ body,
 
   a {
     text-decoration: none;
-    color: $main-green;
+    color: var(--main-color);
 
     &:hover {
       color: $dark-grey;
     }
 
     &:visited {
-      color: $dark-green;
+      color: var(--dark-main-color);
     }
   }
 }
@@ -888,7 +894,7 @@ body,
   &::before {
     display: block;
     margin: 10px auto;
-    background: linear-gradient(to right, $background-color, $dark-grey, $background-color);
+    background: linear-gradient(to right, var(--background-color), $dark-grey, var(--background-color));
     width: 80%;
     height: 1px;
     content: '';
@@ -917,7 +923,7 @@ body,
   margin: 15px 5px;
   border: 0;
   box-shadow: 1px 1px 1px $form-input-border, -1px -1px 6px $form-input-border, -1px 1px 2px $form-input-border, 1px -1px 2px $form-input-border;
-  background: $main-green;
+  background: var(--main-color);
   min-width: 150px;
   height: 35px;
   vertical-align: center;
@@ -941,7 +947,7 @@ body,
     padding: 10px 0;
     width: 100%;
     text-align: center;
-    color: $main-green;
+    color: var(--main-color);
   }
 
   .window-subtitle {
@@ -950,7 +956,7 @@ body,
 
   a {
     text-decoration: none;
-    color: $main-green;
+    color: var(--main-color);
     font-weight: bold;
 
     &.button {
@@ -1278,7 +1284,7 @@ form {
 
   .pure-button {
     &:hover {
-      background-color: $main-green;
+      background-color: var(--main-color);
       background-image: none;
       color: $almost-white;
     }
@@ -1362,7 +1368,7 @@ form {
   }
 
   .validate-rename-tag {
-    color: $main-green;
+    color: var(--main-color);
   }
 }
 
@@ -1458,7 +1464,7 @@ form {
     &::after {
       display: block;
       margin: 10px auto;
-      background: linear-gradient(to right, $background-color, $dark-grey, $background-color);
+      background: linear-gradient(to right, var(--background-color), $dark-grey, var(--background-color));
       width: 90%;
       height: 1px;
       content: '';
@@ -1508,14 +1514,14 @@ form {
 .daily-entry-description {
   a {
     text-decoration: none;
-    color: $main-green;
+    color: var(--main-color);
 
     &:hover {
       text-shadow: 1px 1px $background-linklist-info;
     }
 
     &:visited {
-      color: $dark-green;
+      color: var(--dark-main-color);
     }
   }
 }
@@ -1572,12 +1578,12 @@ form {
 }
 
 .pure-button-shaarli {
-  background-color: $main-green;
+  background-color: var(--main-color);
 }
 
 .progressbar {
   border-radius: 6px;
-  background-color: $main-green;
+  background-color: var(--main-color);
   padding: 1px;
 
   > div {
@@ -1586,8 +1592,8 @@ form {
       -45deg,
       $almost-white,
       $almost-white 6px,
-      $background-color 6px,
-      $background-color 12px
+      var(--background-color) 6px,
+      var(--background-color) 12px
     );
     width: 0%;
     height: 10px;
index cbec04c0fa0bf12ad87f2b33824c64f7c2700c0b..9b0d3a7db5acf08a6caeb0bf1cff1a4b9af759bd 100644 (file)
@@ -137,6 +137,7 @@ If it's still not working, please [open an issue](https://github.com/shaarli/Sha
 | [render_feed](#render_feed) | Allow to do add tags in RSS and ATOM feeds. |
 | [save_link](#save_link) | Allow to alter the link being saved in the datastore. |
 | [delete_link](#delete_link) | Allow to do an action before a link is deleted from the datastore. |
+| [save_plugin_parameters](#save_plugin_parameters) | Allow to manipulate plugin parameters before they're saved. |
 
 
 
@@ -471,6 +472,22 @@ Allow to execute any action before the link is actually removed from the datasto
 - created
 - updated
 
+
+#### save_plugin_parameters
+
+Triggered when the plugin parameters are saved from the plugin administration page.
+
+Plugins can perform an action every times their settings are updated.
+For example it is used to update the CSS file of the `default_colors` plugins.
+
+##### Data
+
+`$data` input contains the `$_POST` array.
+
+So if the plugin has a parameter called `MYPLUGIN_PARAMETER`,
+the array will contain an entry with `MYPLUGIN_PARAMETER` as a key.
+
+
 ## Guide for template designer
 
 ### Plugin administration
index 954442e2789db64355641a1a9d5a324342b41427..3e261815252ac38473dace088a6c40fa7574d573 100644 (file)
@@ -63,8 +63,12 @@ Usage of each plugin is documented in it's README file:
 
  * `addlink-toolbar`: Adds the addlink input on the linklist page
  * `archiveorg`: For each link, add an Archive.org icon
+ * `default_colors`: Override default theme colors.
+ * `isso`: Let visitor comment your shaares on permalinks with Isso.
  * [`markdown`](https://github.com/shaarli/Shaarli/blob/master/plugins/markdown/README.md): Render shaare description with Markdown syntax.
+ * `piwik`: A plugin that adds Piwik tracking code to Shaarli pages.
  * [`playvideos`](https://github.com/shaarli/Shaarli/blob/master/plugins/playvideos/README.md): Add a button in the toolbar allowing to watch all videos.
+ * `pubsubhubbub`: Enable PubSubHubbub feed publishing
  * `qrcode`: For each link, add a QRCode icon.
  * [`wallabag`](https://github.com/shaarli/Shaarli/blob/master/plugins/wallabag/README.md):  For each link, add a Wallabag icon to save it in your instance.
 
index 611296f1c30ba46bb44fa46fe5a2b64c7f3e51db..026d0101dadd9ce1c89dae7b8e5610ef48d8b55d 100644 (file)
@@ -1,8 +1,8 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: Shaarli\n"
-"POT-Creation-Date: 2019-07-06 12:14+0200\n"
-"PO-Revision-Date: 2019-07-06 12:17+0200\n"
+"POT-Creation-Date: 2019-07-13 10:45+0200\n"
+"PO-Revision-Date: 2019-07-13 10:49+0200\n"
 "Last-Translator: \n"
 "Language-Team: Shaarli\n"
 "Language: fr_FR\n"
@@ -403,7 +403,7 @@ msgstr "Note : "
 
 #: index.php:1424
 msgid "Invalid link ID provided"
-msgstr ""
+msgstr "ID du lien non valide"
 
 #: index.php:1444 tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65
 msgid "Export"
@@ -428,15 +428,15 @@ msgstr ""
 msgid "Plugin administration"
 msgstr "Administration des plugins"
 
-#: index.php:1615 tmp/thumbnails.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14
+#: index.php:1616 tmp/thumbnails.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14
 msgid "Thumbnails update"
 msgstr "Mise à jour des miniatures"
 
-#: index.php:1781
+#: index.php:1782
 msgid "Search: "
 msgstr "Recherche : "
 
-#: index.php:1824
+#: index.php:1825
 #, php-format
 msgid ""
 "<pre>Sessions do not seem to work correctly on your server.<br>Make sure the "
@@ -455,7 +455,7 @@ msgstr ""
 "des cookies. Nous vous recommandons d'accéder à votre serveur depuis son "
 "adresse IP ou un <em>Fully Qualified Domain Name</em>.<br>"
 
-#: index.php:1834
+#: index.php:1835
 msgid "Click to try again."
 msgstr "Cliquer ici pour réessayer."
 
@@ -480,7 +480,33 @@ msgstr "Voir sur archive.org"
 msgid "For each link, add an Archive.org icon."
 msgstr "Pour chaque lien, ajoute une icône pour Archive.org."
 
-#: plugins/demo_plugin/demo_plugin.php:465
+#: plugins/default_colors/default_colors.php:33
+msgid ""
+"Default colors plugin error: This plugin is active and no custom color is "
+"configured."
+msgstr ""
+"Erreur du plugin default colors : ce plugin est actif et aucune couleur "
+"n'est configurée."
+
+#: plugins/default_colors/default_colors.php:107
+msgid "Override default theme colors. Use any CSS valid color."
+msgstr ""
+"Remplacer les couleurs du thème par défaut. Utiliser n'importe quelle "
+"couleur CSS valide."
+
+#: plugins/default_colors/default_colors.php:108
+msgid "Main color (navbar green)"
+msgstr "Couleur principale (vert de la barre de navigation)"
+
+#: plugins/default_colors/default_colors.php:109
+msgid "Background color (light grey)"
+msgstr "Couleur de fond (gris léger)"
+
+#: plugins/default_colors/default_colors.php:110
+msgid "Dark main color (e.g. visited links)"
+msgstr "Couleur principale sombre (ex : les liens visités)"
+
+#: plugins/demo_plugin/demo_plugin.php:482
 msgid ""
 "A demo plugin covering all use cases for template designers and plugin "
 "developers."
@@ -488,6 +514,14 @@ msgstr ""
 "Une extension de démonstration couvrant tous les cas d'utilisation pour les "
 "designers de thèmes et les développeurs d'extensions."
 
+#: plugins/demo_plugin/demo_plugin.php:483
+msgid "This is a parameter dedicated to the demo plugin. It'll be suffixed."
+msgstr "Ceci est un paramètre dédié au plugin de démo. Il sera suffixé."
+
+#: plugins/demo_plugin/demo_plugin.php:484
+msgid "Other demo parameter"
+msgstr "Un autre paramètre de démo"
+
 #: plugins/isso/isso.php:22
 msgid ""
 "Isso plugin error: Please define the \"ISSO_SERVER\" setting in the plugin "
@@ -703,9 +737,8 @@ msgstr ""
 "miniatures."
 
 #: tmp/configure.90100d2eaf5d3705e14b9b4f78ecddc9.rtpl.php:162
-#| msgid "Enable thumbnails"
 msgid "Synchonize thumbnails"
-msgstr ""
+msgstr "Synchroniser les miniatures"
 
 #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29
 msgid "title"
index 957d8d9a4f428abbc0524b02f4e91bfd04e5b47e..f0f71dbb9b34ce9570ea966e23cef0fb5e82a733 100644 (file)
--- a/index.php
+++ b/index.php
@@ -1567,6 +1567,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
     if ($targetPage == Router::$PAGE_SAVE_PLUGINSADMIN) {
         try {
             if (isset($_POST['parameters_form'])) {
+                $pluginManager->executeHooks('save_plugin_parameters', $_POST);
                 unset($_POST['parameters_form']);
                 foreach ($_POST as $param => $value) {
                     $conf->set('plugins.'. $param, escape($value));
diff --git a/plugins/default_colors/default_colors.css.template b/plugins/default_colors/default_colors.css.template
new file mode 100644 (file)
index 0000000..87e22a0
--- /dev/null
@@ -0,0 +1,3 @@
+:root {
+%s
+}
diff --git a/plugins/default_colors/default_colors.meta b/plugins/default_colors/default_colors.meta
new file mode 100644 (file)
index 0000000..108962c
--- /dev/null
@@ -0,0 +1,5 @@
+description="Override default theme colors. Use any CSS valid color."
+parameters="DEFAULT_COLORS_MAIN;DEFAULT_COLORS_BACKGROUND;DEFAULT_COLORS_DARK_MAIN"
+parameter.DEFAULT_COLORS_MAIN="Main color (navbar green)"
+parameter.DEFAULT_COLORS_BACKGROUND="Background color (light grey)"
+parameter.DEFAULT_COLORS_DARK_MAIN="Dark main color (e.g. visited links)"
diff --git a/plugins/default_colors/default_colors.php b/plugins/default_colors/default_colors.php
new file mode 100644 (file)
index 0000000..1928cc9
--- /dev/null
@@ -0,0 +1,111 @@
+<?php
+
+/**
+ * Plugin default_colors.
+ *
+ * Allow users to easily overrides colors of the default theme.
+ */
+
+use Shaarli\Config\ConfigManager;
+use Shaarli\Plugin\PluginManager;
+
+const DEFAULT_COLORS_PLACEHOLDERS = [
+    'DEFAULT_COLORS_MAIN',
+    'DEFAULT_COLORS_BACKGROUND',
+    'DEFAULT_COLORS_DARK_MAIN',
+];
+
+/**
+ * Display an error if the plugin is active a no color is configured.
+ *
+ * @param $conf ConfigManager instance
+ *
+ * @return array|null The errors array or null of there is none.
+ */
+function default_colors_init($conf)
+{
+    $params = '';
+    foreach (DEFAULT_COLORS_PLACEHOLDERS as $placeholder) {
+        $params .= trim($conf->get('plugins.'. $placeholder, ''));
+    }
+
+    if (empty($params)) {
+        $error = t('Default colors plugin error: '.
+            'This plugin is active and no custom color is configured.');
+        return array($error);
+    }
+}
+
+/**
+ * When plugin parameters are saved, we regenerate the custom CSS file with provided settings.
+ *
+ * @param array $data $_POST array
+ *
+ * @return array Updated $_POST array
+ */
+function hook_default_colors_save_plugin_parameters($data)
+{
+    $file = PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css';
+    $template = file_get_contents(PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css.template');
+    $content = '';
+    foreach (DEFAULT_COLORS_PLACEHOLDERS as $rule) {
+        $content .= ! empty($data[$rule])
+            ? default_colors_format_css_rule($data, $rule) .';'. PHP_EOL
+            : '';
+    }
+
+    if (! empty($content)) {
+        file_put_contents($file, sprintf($template, $content));
+    }
+
+    return $data;
+}
+
+/**
+ * When linklist is displayed, include default_colors CSS file.
+ *
+ * @param array $data - header data.
+ *
+ * @return mixed - header data with default_colors CSS file added.
+ */
+function hook_default_colors_render_includes($data)
+{
+    $file = PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css';
+    if (file_exists($file )) {
+        $data['css_files'][] = $file ;
+    }
+
+    return $data;
+}
+
+/**
+ * Create a valid CSS rule from parameters settings and plugin parameter.
+ *
+ * @param array  $data      $_POST array
+ * @param string $parameter Plugin parameter name
+ *
+ * @return string CSS rules for the provided parameter and its matching value.
+ */
+function default_colors_format_css_rule($data, $parameter)
+{
+    if (empty($data[$parameter])) {
+        return '';
+    }
+
+    $key = str_replace('DEFAULT_COLORS_', '', $parameter);
+    $key = str_replace('_', '-', strtolower($key)) .'-color';
+    return '  --'. $key .': '. $data[$parameter];
+}
+
+
+/**
+ * This function is never called, but contains translation calls for GNU gettext extraction.
+ */
+function default_colors_translation()
+{
+    // meta
+    t('Override default theme colors. Use any CSS valid color.');
+    t('Main color (navbar green)');
+    t('Background color (light grey)');
+    t('Dark main color (e.g. visited links)');
+}
index b063ecb72380862380609b004711c27843eee4a0..cd616441c338c59cc93a963e1456af5dcea4110b 100644 (file)
@@ -1 +1,4 @@
 description="A demo plugin covering all use cases for template designers and plugin developers."
+parameters="DEMO_PLUGIN_PARAMETER;DEMO_PLUGIN_OTHER_PARAMETER"
+parameter.DEMO_PLUGIN_PARAMETER="This is a parameter dedicated to the demo plugin. It'll be suffixed."
+parameter.DEMO_PLUGIN_OTHER_PARAMETER="Other demo parameter"
index 95ea7fe2d029767f16c000d1672e9aa0bacf4cd4..71ba7495ce9695bd948b52f741dfe2bb5f53da18 100644 (file)
@@ -456,6 +456,23 @@ function hook_demo_plugin_render_feed($data)
     return $data;
 }
 
+/**
+ * When plugin parameters are saved.
+ *
+ * @param array $data $_POST array
+ *
+ * @return array Updated $_POST array
+ */
+function hook_demo_plugin_save_plugin_parameters($data)
+{
+    // Here we edit the provided value, but we can use this to generate config files, etc.
+    if (! empty($data['DEMO_PLUGIN_PARAMETER']) && ! endsWith($data['DEMO_PLUGIN_PARAMETER'], '_SUFFIX')) {
+        $data['DEMO_PLUGIN_PARAMETER'] .= '_SUFFIX';
+    }
+
+    return $data;
+}
+
 /**
  * This function is never called, but contains translation calls for GNU gettext extraction.
  */
@@ -463,4 +480,6 @@ function demo_dummy_translation()
 {
     // meta
     t('A demo plugin covering all use cases for template designers and plugin developers.');
+    t('This is a parameter dedicated to the demo plugin. It\'ll be suffixed.');
+    t('Other demo parameter');
 }
diff --git a/tests/plugins/PluginDefaultColorsTest.php b/tests/plugins/PluginDefaultColorsTest.php
new file mode 100644 (file)
index 0000000..b9951cc
--- /dev/null
@@ -0,0 +1,195 @@
+<?php
+
+namespace Shaarli\Plugin\DefaultColors;
+
+use DateTime;
+use PHPUnit\Framework\TestCase;
+use Shaarli\Bookmark\LinkDB;
+use Shaarli\Config\ConfigManager;
+use Shaarli\Plugin\PluginManager;
+
+require_once 'plugins/default_colors/default_colors.php';
+
+/**
+ * Class PluginDefaultColorsTest
+ *
+ * Test the DefaultColors plugin (allowing to override default template colors).
+ */
+class PluginDefaultColorsTest extends TestCase
+{
+    /**
+     * Reset plugin path
+     */
+    public function setUp()
+    {
+        PluginManager::$PLUGINS_PATH = 'sandbox';
+        mkdir(PluginManager::$PLUGINS_PATH . '/default_colors/');
+        copy(
+            'plugins/default_colors/default_colors.css.template',
+            PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css.template'
+        );
+    }
+
+    /**
+     * Remove sandbox files and folder
+     */
+    public function tearDown()
+    {
+        if (file_exists('sandbox/default_colors/default_colors.css.template')) {
+            unlink('sandbox/default_colors/default_colors.css.template');
+        }
+
+        if (file_exists('sandbox/default_colors/default_colors.css')) {
+            unlink('sandbox/default_colors/default_colors.css');
+        }
+
+        if (is_dir('sandbox/default_colors')) {
+            rmdir('sandbox/default_colors');
+        }
+    }
+
+    /**
+     * Test DefaultColors init without errors.
+     */
+    public function testDefaultColorsInitNoError()
+    {
+        $conf = new ConfigManager('');
+        $conf->set('plugins.DEFAULT_COLORS_BACKGROUND', 'value');
+        $errors = default_colors_init($conf);
+        $this->assertEmpty($errors);
+    }
+
+    /**
+     * Test DefaultColors init with errors.
+     */
+    public function testDefaultColorsInitError()
+    {
+        $conf = new ConfigManager('');
+        $errors = default_colors_init($conf);
+        $this->assertNotEmpty($errors);
+    }
+
+    /**
+     * Test the save plugin parameters hook with all colors specified.
+     */
+    public function testSavePluginParametersAll()
+    {
+        $post = [
+            'other1' => true,
+            'DEFAULT_COLORS_MAIN' => 'blue',
+            'DEFAULT_COLORS_BACKGROUND' => 'pink',
+            'other2' => ['yep'],
+            'DEFAULT_COLORS_DARK_MAIN' => 'green',
+        ];
+
+        hook_default_colors_save_plugin_parameters($post);
+        $this->assertFileExists($file = 'sandbox/default_colors/default_colors.css');
+        $content = file_get_contents($file);
+        $expected = ':root {
+  --main-color: blue;
+  --background-color: pink;
+  --dark-main-color: green;
+
+}
+';
+        $this->assertEquals($expected, $content);
+    }
+
+    /**
+     * Test the save plugin parameters hook with only one color specified.
+     */
+    public function testSavePluginParametersSingle()
+    {
+        $post = [
+            'other1' => true,
+            'DEFAULT_COLORS_BACKGROUND' => 'pink',
+            'other2' => ['yep'],
+            'DEFAULT_COLORS_DARK_MAIN' => '',
+        ];
+
+        hook_default_colors_save_plugin_parameters($post);
+        $this->assertFileExists($file = 'sandbox/default_colors/default_colors.css');
+        $content = file_get_contents($file);
+        $expected = ':root {
+  --background-color: pink;
+
+}
+';
+        $this->assertEquals($expected, $content);
+    }
+
+    /**
+     * Test the save plugin parameters hook with no color specified.
+     */
+    public function testSavePluginParametersNone()
+    {
+        hook_default_colors_save_plugin_parameters([]);
+        $this->assertFileNotExists($file = 'sandbox/default_colors/default_colors.css');
+    }
+
+    /**
+     * Make sure that the CSS is properly included by the include hook.
+     */
+    public function testIncludeWithFile()
+    {
+        $data = [
+            'css_files' => ['file1'],
+            'js_files' => ['file2'],
+        ];
+        touch($file = 'sandbox/default_colors/default_colors.css');
+        $processedData = hook_default_colors_render_includes($data);
+
+        $this->assertCount(2, $processedData['css_files']);
+        $this->assertEquals($file, $processedData['css_files'][1]);
+        $this->assertCount(1, $processedData['js_files']);
+    }
+
+    /**
+     * Make sure that the CSS is not included by the include hook if the CSS file does not exist.
+     */
+    public function testIncludeWithoutFile()
+    {
+        $data = [
+            'css_files' => ['file1'],
+            'js_files' => ['file2'],
+        ];
+        $processedData = hook_default_colors_render_includes($data);
+
+        $this->assertEquals($data, $processedData);
+    }
+
+    /**
+     * Test helper function which generates CSS rules with valid input.
+     */
+    public function testFormatCssRuleValid()
+    {
+        $data = [
+            'other1' => true,
+            'DEFAULT_COLORS_BLIP_BLOP' => 'shinyColor',
+            'other2' => ['yep'],
+        ];
+        $result = default_colors_format_css_rule($data, 'DEFAULT_COLORS_BLIP_BLOP');
+        $this->assertEquals('  --blip-blop-color: shinyColor', $result);
+
+        $data = ['unknown-parameter' => true];
+        $result = default_colors_format_css_rule($data, 'unknown-parameter');
+        $this->assertEquals('  --unknown-parameter-color: 1', $result);
+    }
+
+    /**
+     * Test helper function which generates CSS rules with invalid input.
+     */
+    public function testFormatCssRuleInvalid()
+    {
+        $result = default_colors_format_css_rule([], 'DEFAULT_COLORS_BLIP_BLOP');
+        $this->assertEmpty($result);
+
+        $data = [
+            'other1' => true,
+            'DEFAULT_COLORS_BLIP_BLOP' => 'shinyColor',
+            'other2' => ['yep'],
+        ];
+        $result = default_colors_format_css_rule($data, '');
+        $this->assertEmpty($result);
+    }
+}