bootscore icon indicating copy to clipboard operation
bootscore copied to clipboard

Bootstrap color palette to Gutenberg block editor

Open iwasthesword opened this issue 3 years ago • 16 comments

I propose we add custom Bootstrap palette to be added to the block editor. Ref If you are using the block editor this is a feature that would help A LOT to keep consistency across your site.

Since we have pre-processing I'm guessing it could be done as in the reference, but since I'm not familiar with the process in here I'd like to hear your opnions before diving in. What are your opinions on this? How should I go about implementing it? Feel free to join in

iwasthesword avatar Dec 13 '21 15:12 iwasthesword

I think it's a good idea to add some basic support for the block editor. We're happy if you want to contribute. The process here is simple. Just fork the theme repo, do your changes and create a Pull request.

crftwrk avatar Dec 13 '21 16:12 crftwrk

I think that it wouldn't be that hard, plus it would do ground work for more theme customization. Since theme.json is available it would make it a lot easier to implement and not depend on the PHP add_theme_support way of doing it.

The only thing we would need to make is the for scss-compiler.php file to generate the theme.json in the root dir with all the colors as specified in here.

I'm not sure SCSS Compiler CAN compile to .json buit looking at the SCSS code and generated CSS file I'd say the first part of the _root.scss has everything we need to do this, list all the colors:

@each $color, $value in $colors {
    --#{$variable-prefix}#{$color}: #{$value};
}

Any idea how I would about doing this? I'm not familiar with SCSS compiler and I'm having a hard time figuring it out how to add just the colors to the .json

iwasthesword avatar Dec 14 '21 20:12 iwasthesword

Building support in the scss is quite easy, using the example you posted. Unfortunately, the json/PHP is a bit harder. The compiler can't just read the variables and write json for it. This would basically require all the scss variables to be declared in PHP in some way, so both the compiler and a file writer for json can both use them.

In understrap they use gulp to generate the code, unfortunately in the current system of bootScore this won't fit, as we mainly focus on not needing additional tools. I'll take a closer look at the code on understrap soon, to see if I can get some inspiration.

The only way I can imagine this working the best if we give people instructions on how to edit the theme.json.

justinkruit avatar Dec 15 '21 07:12 justinkruit

I've did a bit of research and got a working prototype:

  • It uses an external tool https://github.com/sabberworm/PHP-CSS-Parser composer require sabberworm/php-css-parser to add the library
  • After the SCSS Compiler does all the work, it will load the bootstrap.min.css and parse the variables. You need to add the bootscore_compile_json() function after this line in functions.php for it to work
  • It will get all the whitelisted variables and structure the data in a array
  • Convert it to JSON and update theme.json

The function:

function bootscore_compile_json()
{
  require __DIR__ . '/../vendor/autoload.php';
  $parser = new \Sabberworm\CSS\Parser(file_get_contents(get_stylesheet_directory() . '/css/lib/bootstrap.min.css'));
  $cssDocument = $parser->parse();
  $vars_whitelist = array("--bs-primary","--bs-secondary","--bs-blue", "--bs-indigo", "--bs-purple", "--bs-pink", "--bs-red", "--bs-orange", "--bs-yellow", "--bs-green", "--bs-teal", "--bs-cyan", "--bs-white", "--bs-gray", "--bs-gray-dark");
  $rulesets = $cssDocument->getAllRuleSets();
  $custom_palette = array();

  foreach ($rulesets as $val)
  {
    $tmp = $val->getRules();
    foreach ($tmp as $rule)
    {
      $ruleV = (string) $rule->getValue();
      $ruleR = $rule->getRule();
      if (in_array($ruleR, $vars_whitelist))
      {
        $_name = str_replace("--bs-", "", $ruleR);
        $_color = array(
          "name" => ucfirst($_name),
          "slug" => $_name,
          "color" => $ruleV
        );
        $custom_palette[] = $_color;
      }
    }
  }
  $json_stru = array(
    "version" => 1,
    "settings" => array(
      "color" => array(
        "palette" => $custom_palette
      )
    )
  );
  $fp = fopen(get_stylesheet_directory() . '/theme.json', 'w');
  fwrite($fp, json_encode($json_stru));
  fclose($fp);
}

What do you think? Is the external lib a no-go? Maybe we could we make this optional?

iwasthesword avatar Dec 16 '21 20:12 iwasthesword

Loading in another external library will make the theme more heavy, and recompiling slower, which is a thing to consider. Although I must say, I totally didn't consider that there would even be a library that can read css like that. Testing would be required how hard this can hit performance.

Also, I played around with the theme.json, and even though it's nice, I personally wouldn't use it. It also overrides things like font families in Gutenberg, and if you don't set them they will also be empty in Gutenberg. I would go for the approach of the editor-color-palette and loading a colors.json in there.

justinkruit avatar Dec 16 '21 21:12 justinkruit

Now that theme.json evolved a bit I think it's a good time to revive this. After refactoring, instead of just the palette, it now also loads font families and set body text and bg colors, plus opens up for any exposed BS variable to be included in theme.json

I also tested the performance and it takes around 0.7 seconds to execute the function on my end. With a check for last modified like the bootscore_compile_scss() has it shouldn't be a problem, right?

Here's the new function:

function bootscore_compile_json()
{
  require __DIR__ . '/../vendor/autoload.php';
  $parser = new \Sabberworm\CSS\Parser(file_get_contents(get_stylesheet_directory() . '/css/lib/bootstrap.min.css'));
  $cssDocument = $parser->parse();
  $vars_fetch = array("--bs-primary", "--bs-secondary", "--bs-blue", "--bs-indigo", "--bs-purple", "--bs-pink", "--bs-red", "--bs-orange", "--bs-yellow", "--bs-green", "--bs-teal", "--bs-cyan", "--bs-white", "--bs-gray", "--bs-gray-dark", "--bs-body-font-family", "--bs-font-sans-serif", "--bs-font-monospace", "--bs-body-color", "--bs-body-bg");
  $rulesets = $cssDocument->getAllRuleSets();
  $custom_palette = array();

  foreach ($rulesets as $val)
  {
    $tmp = $val->getRules();
    foreach ($tmp as $rule)
    {
      $ruleV = (string) $rule->getValue();
      $ruleR = $rule->getRule();
      if (in_array($ruleR, $vars_fetch))
      {
        $custom_palette[$ruleR] = $ruleV;
      }
    }
  }

  $json_stru = array(
    "version" => 2,
    "styles" => array(
      "color" => array(
        "text" => $custom_palette["--bs-body-color"],
        "background" => $custom_palette["--bs-body-bg"]
      ),
      "typography" => array(
        "fontFamily" => "var(--wp--preset--font-family--default-font-family)",
      )
    ),
    "settings" => array(
      "typography" => array(
        "fontFamilies" => array(
          array(
            "fontFamily" => $custom_palette["--bs-body-font-family"],
            "slug" => "default-font-family",
            "name" => "Default Bootstrap Font"
          ),
          array(
            "fontFamily" => $custom_palette["--bs-font-sans-serif"],
            "slug" => "font-sans-serif",
            "name" => "Sans Serif"
          ),
          array(
            "fontFamily" => $custom_palette["--bs-font-monospace"],
            "slug" => "font-monospace",
            "name" => "Monospace"
          )
        )
      ),
      "color" => array(
        "palette" => array(
          array(
            "name" => "Primary",
            "slug" => "primary",
            "color" => $custom_palette["--bs-primary"]
          ),
          array(
            "name" => "Secondary",
            "slug" => "secondary",
            "color" => $custom_palette["--bs-secondary"]
          ),
          array(
            "name" => "Blue",
            "slug" => "blue",
            "color" => $custom_palette["--bs-blue"]
          ),
          array(
            "name" => "Indigo",
            "slug" => "indigo",
            "color" => $custom_palette["--bs-indigo"]
          ),
          array(
            "name" => "Purple",
            "slug" => "purple",
            "color" => $custom_palette["--bs-purple"]
          ),
          array(
            "name" => "Pink",
            "slug" => "pink",
            "color" => $custom_palette["--bs-pink"]
          ),
          array(
            "name" => "Red",
            "slug" => "red",
            "color" => $custom_palette["--bs-red"]
          ),
          array(
            "name" => "Orange",
            "slug" => "orange",
            "color" => $custom_palette["--bs-orange"]
          ),
          array(
            "name" => "Yellow",
            "slug" => "yellow",
            "color" => $custom_palette["--bs-yellow"]
          ),
          array(
            "name" => "Green",
            "slug" => "green",
            "color" => $custom_palette["--bs-green"]
          ),
          array(
            "name" => "Teal",
            "slug" => "teal",
            "color" => $custom_palette["--bs-teal"]
          ),
          array(
            "name" => "Cyan",
            "slug" => "cyan",
            "color" => $custom_palette["--bs-cyan"]
          ),
          array(
            "name" => "White",
            "slug" => "white",
            "color" => $custom_palette["--bs-white"]
          ),
          array(
            "name" => "Gray",
            "slug" => "gray",
            "color" => $custom_palette["--bs-gray"]
          ),
          array(
            "name" => "Gray Dark",
            "slug" => "gray-dark",
            "color" => $custom_palette["--bs-gray-dark"]
          )
        )
      )
    )
  );
  $fp = fopen(get_stylesheet_directory() . '/theme.json', 'w');
  fwrite($fp, json_encode($json_stru));
  fclose($fp);
}

iwasthesword avatar Mar 31 '22 20:03 iwasthesword

Can you fork the theme and create a working example to test?

Path to css has changed from /css/lib/bootstrap.min.css to /css/main.css.

crftwrk avatar Apr 01 '22 10:04 crftwrk

Can you fork the theme and create a working example to test?

I forked it here and in this branch is the working prototype. I tested it with child theme and it seems to be working also. (Sorry, I accidentally messed up the formatting from inc/scss-compiler.php)

iwasthesword avatar Apr 05 '22 18:04 iwasthesword

Tested and works flawlessly. Think that's pretty smart and would love to add this feature to the theme.

  • @iwasthesword are you able to maintain this part in the long-therm?
  • @justinkruit what do you think?

If so, I'm in.

crftwrk avatar Apr 09 '22 09:04 crftwrk

  • @iwasthesword are you able to maintain this part in the long-therm?

Yes, I can maintain this in the long term.

iwasthesword avatar Apr 14 '22 17:04 iwasthesword

I'm in 👍.

If it's ok for you, I'd like to address this to v5.2.1.0 because v5.2.0.0 is closed to ship, has already many changes and I'm still struggling with some things.

crftwrk avatar Apr 19 '22 09:04 crftwrk

I think it's best too. I will soon start working on adding the 'last modified' check so it doesn't fire every load and polish the code bit and prepare for the next release.

iwasthesword avatar Apr 19 '22 17:04 iwasthesword

I've been testing with the theme.json today, but for some reason it still feels buggy. Spacing on blocks go missing, font families missing when you don't add them, etc. Next to that, adding this library will also render the theme.json on each page load when developing.

It's a nice system, but I honestly think it's for the best if users add the colors themselves, either with theme.json or via add_theme_support('editor-color-palette', array()).

justinkruit avatar Apr 20 '22 13:04 justinkruit

I've used the understrap build system (basically the package.json npm build script) and personally prefer it to bootscores SCSSphp compilation, but come back to bootscore as its woocommerce support and out-of-the-box menu system and other things are stronger.

The understrap system basically copies all the required SCSS files from the parent theme and compiles with NPM scripts. Understrap also has a browser watch compilation if you like that kind of thing, all are pretty straightforward.

What I like about it is you have more control over the SCSS, I comment some of Bootstrap SCSS imports that I don't use and comment out lots of fontawesome SCSS. Also dependencies like:

  • fontawesome
  • bootstrap5

are simply pulled down via NPM, at the moment the bootscores main theme is having to package these dependencies.

The NPM build command is straightforward and ubiquitous and wouldn't think it would scare people away from using the theme, themes like this are developer-centric. NPM build makes life easier and is powerful and configurable.

I disabled bootscores SCSSphp compilation and moved over to NPM script in the work I'm currently undertaking and run a NPM scripts that compiles the SCSS and copies it to the CSS directory. Like this

"scripts": {
        "css": "npm-run-all css-compile css-postcss css-minify",
        "css-compile": "sass --style expanded --source-map --embed-sources --no-error-css --quiet scss/main.scss:css/main.css",
        "css-minify": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output css/ --batch --batch-suffix \".min\" \"css/*.css\" \"!css/*.min.css\" \"!css/*rtl*.css\"",
        "css-postcss": "postcss --config src/build/postcss.config.js --replace \"css/*.css\" \"!css/*.rtl*.css\" \"!css/*.min.css\"",
        "copy-assets": "node src/build/copy-assets.js"
    },

I initially ran the copy-assets NPM script which just runs a piece of JS to copy the required asset files from the parent theme.

Understrap has scripts to compile and minify JS

"js": "npm-run-all js-compile js-minify",
    "js-compile": "rollup --config src/build/rollup.config.js --sourcemap",
    "js-minify": "terser js/child-theme.min.js --config-file src/build/terser.config.json --source-map \"content=js/child-theme.js.map,url=child-theme.min.js.map,filename=child-theme.min.js\" --output js/child-theme.min.js",

And browser-sync scripts to compile when SCSS is updated etc

 "watch": "npm-run-all --parallel watch-run-*",
    "watch-bs": "npm-run-all --parallel bs watch-run-*",
    "watch-run-css": "nodemon --watch src/sass/ --ext scss --exec \"npm-run-all css\"",
    "watch-run-js": "nodemon --watch src/js/ --ext js --exec \"npm-run-all js\"",

Not sure there is much appetite to explore this after your work last year to integrate a PHP SCSS compiler. But I'd be interested in using NPM with bootscore and could chip in.

hsankala avatar Feb 13 '23 17:02 hsankala

Thanks to https://github.com/bootscore/bootscore/pull/375 you can now disable scssphp with a single line in wp-config.php or functions.php and use a compiler of your choice instead. Release is this week after WooCommerce 7.4 update, but you can simply download main branch as well.

crftwrk avatar Feb 13 '23 17:02 crftwrk

@crftwrk sweet, thanks I'll use that when available.

hsankala avatar Feb 13 '23 17:02 hsankala