[TikiWiki-commits] [Git][tikiwiki/tiki][master] [ENH][UX] Theme customizer: Improved support for custom generated CSS

"Alvin Bauma \(@alvinBM\) via TikiWiki-cvs" <[email protected]>
Newsgroups gmane.comp.cms.tiki.cvs
Message-ID <6a7b12582677e_3832f37646548d@gitlab-sidekiq-low-urgency-cpu-bound-v2-84dcc76b6c-jjwd4.mail>

Alvin Bauma pushed to branch master at Tiki Wiki CMS Groupware / Tiki


Commits:
26164ba6 by Alvin Bauma at 2026-08-11T14:15:05+02:00
[ENH][UX] Theme customizer: Improved support for custom generated CSS
---
* [ENH][UI] Update theme customizer paths for generated CSS and ensure directory creation

* [ENH][UI] Add reset functionality for custom generated CSS in theme customizer

* [REF] refactor(theme-customizer): store generated CSS in file instead of DB pref

* [FIX] Fix calendar day view time range
---
* [FIX] Fix calendar day view time range

See merge request tikiwiki/tiki!10543

See merge request tikiwiki/tiki!8745

- - - - -


7 changed files:

- .gitignore
- lib/core/Services/StyleGuide/Controller.php
- lib/jquery_tiki/theme-customizer.js
- lib/pdflib.php
- lib/setup/theme.php
- path_constants.php
- templates/styleguide/show.tpl


Changes:

=====================================
.gitignore
=====================================
@@ -129,6 +129,8 @@ templates/.htaccess
 
 themes/css/custom.css
 themes/js/custom.js
+public/storage/custom_css/
+public/storage/custom_js/
 #These cannot go in public/generated as it would break the current theme system.
 themes/**/*.css
 themes/**/*.css.map


=====================================
lib/core/Services/StyleGuide/Controller.php
=====================================
@@ -5,6 +5,7 @@
 // All Rights Reserved. See copyright.txt for details and a complete list of authors.
 // Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
 
+// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
 class Services_StyleGuide_Controller
 {
     public function setUp()
@@ -48,9 +49,49 @@ class Services_StyleGuide_Controller
             ->add_jsfile('lib/jquery_tiki/theme-customizer.js')
         ;
 
+        $generatedCss = is_readable(THEME_CUSTOMIZER_GENERATED_CSS_PATH)
+            ? file_get_contents(THEME_CUSTOMIZER_GENERATED_CSS_PATH)
+            : '';
+
         return [
             'title' => tr('Theme Customizer'),
             'sections' => $sections,
+            'generated_css' => $generatedCss,
         ];
     }
+
+    public function action_save_generated_css($input)
+    {
+        Services_Exception_Denied::checkGlobal('admin');
+        $customCss = $input->generated_css->text();
+
+        $dir = dirname(THEME_CUSTOMIZER_GENERATED_CSS_PATH);
+        if (! is_dir($dir)) {
+            mkdir($dir, 0755, true);
+        }
+
+        if (file_put_contents(THEME_CUSTOMIZER_GENERATED_CSS_PATH, $customCss) !== false) {
+            Feedback::success(tr('The custom generated CSS has been saved'));
+        } else {
+            Feedback::error(tr("Couldn't save the custom generated CSS file. Check that public/storage/custom_css/ is writable."));
+        }
+        return true;
+    }
+
+    public function action_reset_generated_css($input)
+    {
+        Services_Exception_Denied::checkGlobal('admin');
+
+        if (! file_exists(THEME_CUSTOMIZER_GENERATED_CSS_PATH)) {
+            Feedback::note(tr('No custom generated CSS file found.'));
+            return true;
+        }
+
+        if (file_put_contents(THEME_CUSTOMIZER_GENERATED_CSS_PATH, '') !== false) {
+            Feedback::success(tr('The custom generated CSS has been reset'));
+        } else {
+            Feedback::error(tr("Couldn't reset the custom generated CSS file. Check that public/storage/custom_css/ is writable."));
+        }
+        return true;
+    }
 }


=====================================
lib/jquery_tiki/theme-customizer.js
=====================================
@@ -842,6 +842,17 @@ function themeFix() {
     }
 }
 
+function normalizeCssString(s) {
+    return String(s)
+        .replace(/\r\n/g, '\n')
+        .replace(/[\u00A0\u200B\u200C\u200D\uFEFF]/g, ' ')
+        .split('\n')
+        .map(function(line) { return line.trim(); })
+        .join('\n')
+        .replace(/[ \t]+/g, ' ')
+        .trim();
+}
+
 
 
 (function($) {
@@ -879,7 +890,7 @@ function themeFix() {
         $('.keep-changes').prop('checked', true);
         loadCustomizerCSS();
         tc.toCSS(inputJSON);
-        $('textarea[name=header_custom_css]').val(tc.generateCSS([inputJSON]));
+        $('textarea[name=generated_css]').val(tc.generateCSS([inputJSON]));
     }
     defaultInputValues();
 
@@ -914,9 +925,10 @@ function themeFix() {
 
     // generate custom css when clicked
     $('.generate-custom-css').on("click", function() {
-        $('textarea[name=header_custom_css]').val(tc.generateCSS([inputJSON]));
+        $('textarea[name=generated_css]').val(tc.generateCSS([inputJSON]));
+        $('#apply-custom-generated-css').prop('disabled', false);
         $('html, body').animate({
-            scrollTop: $('textarea[name=header_custom_css]').offset().top
+            scrollTop: $('textarea[name=generated_css]').offset().top
         }, 200);
         return false;
     });
@@ -1000,4 +1012,24 @@ function themeFix() {
             }
         });
     });
+
+    // Save generated CSS to file when clicking 'Apply Custom CSS' button
+    $('#apply-custom-generated-css').click(function(e) {
+        e.stopPropagation();
+        let generated_css = $('textarea[name=generated_css]').val();
+        $.post($.service('styleguide', 'save_generated_css'), {
+            generated_css,
+        }).always(function() {
+            location.href = location.href;
+        });
+    });
+
+    // Reset generated CSS file and localStorage when clicking 'Reset custom CSS' button
+    $('#reset-custom-generated-css').click(function(e) {
+        e.stopPropagation();
+        $.post($.service('styleguide', 'reset_generated_css')).always(function() {
+            deleteData();
+            location.href = location.href;
+        });
+    });
 })(jQuery);


=====================================
lib/pdflib.php
=====================================
@@ -606,6 +606,7 @@ HTML;
                 $basecss . $themecss . $printcss . $extcss .
                 $this->bootstrapReplace() .
                 $prefs["header_custom_css"] .
+                ($prefs['theme_customizer'] === 'y' && is_readable(THEME_CUSTOMIZER_GENERATED_CSS_PATH) ? file_get_contents(THEME_CUSTOMIZER_GENERATED_CSS_PATH) : '') .
             '</style>';
 
         $cssStyles = str_replace(


=====================================
lib/setup/theme.php
=====================================
@@ -160,6 +160,12 @@ Sections::onSectionChange(function ($section) {
     if (is_readable($custom_css)) {
         $addSectionThemeCssFile($custom_css, 53);
     }
+
+    //8) include optional Theme Customizer generated CSS if present
+    if ($prefs['theme_customizer'] === 'y' && is_readable(THEME_CUSTOMIZER_GENERATED_CSS_PATH)) {
+        $headerlib->add_cssfile(THEME_CUSTOMIZER_GENERATED_CSS_PATH . '?' . filemtime(THEME_CUSTOMIZER_GENERATED_CSS_PATH), 54);
+    }
+
     if (! isset($prefs['site_favicon_enable']) || $prefs['site_favicon_enable'] === 'y') {    // if favicons are disabled in preferences, skip the lot of it.
         $favicon_path = $themelib->get_theme_path($prefs['theme'], $prefs['theme_option'], 'favicon-16x16.png', 'favicons');
         if ($favicon_path) {  // if there is a 16x16 png favicon in the theme folder, then find and display others if they exist
@@ -202,7 +208,7 @@ Sections::onSectionChange(function ($section) {
         unset($favicon_path);  // no longer needed, so bye bye
     }
 
-    //8) produce $iconset to be used for generating icons
+    //9) produce $iconset to be used for generating icons
     $iconset = TikiLib::lib('iconset')->getIconsetForTheme($theme_active, $theme_option_active);
     // and add js support file
     $headerlib->add_jsfile('lib/jquery_tiki/iconsets.js');


=====================================
path_constants.php
=====================================
@@ -157,6 +157,8 @@ const THEMES_LEGACY_ALL_SITES_SHARED_TEMPLATES_PATH = 'themes/templates';
 const THEMES_BASE_FILES_FEATURE_CSS_PATH = 'themes/base_files/feature_css';
 /** Base themes source directory relative to project root */
 const BASE_THEMES_SRC_PATH = 'themes';
+/** CSS file generated by the Theme Customizer tool. */
+const THEME_CUSTOMIZER_GENERATED_CSS_PATH = 'public/storage/custom_css/custom-generated.css';
 
 const WHELP_PATH = 'whelp';
 


=====================================
templates/styleguide/show.tpl
=====================================
@@ -21,8 +21,12 @@
     </div>
 
     <div class="col">
-        <label for="header_custom_css">{tr}Custom CSS{/tr}</label>
-        <textarea name="header_custom_css" class="form-control" rows="10"></textarea>
+        <label for="generated_css">{tr}Custom CSS{/tr}</label>
+        <textarea name="generated_css" class="form-control" rows="10">{$generated_css|escape}</textarea>
+        <span class="text-muted">{tr}By clicking 'Apply Custom CSS' the CSS code will be applied as default custom CSS for your Tiki site.{/tr}</span>
+        <br />
+        <input disabled class="btn btn-primary mt-3" type="submit" title="{tr}Apply custom CSS{/tr}" value="{tr}Apply custom CSS{/tr}" id="apply-custom-generated-css">
+        <button class="btn btn-danger mt-3 ms-2" id="reset-custom-generated-css" title="{tr}Reset custom CSS{/tr}">{tr}Reset custom CSS{/tr}</button>
     </div>
 
     <div class="tc-footer">



View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/26164ba6bdba6a0fc23cb816fa35f40e73bd047b

-- 
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/26164ba6bdba6a0fc23cb816fa35f40e73bd047b
You're receiving this email because of your account on gitlab.com. Manage all notifications: https://gitlab.com/-/profile/notifications | Help: https://gitlab.com/help

_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.