BBcode color tags in a theme

Continuing the discussion from Discourse BBCode color

Can this be offered as a theme component? This would allow customers on managed instances to install it. I also feel like there should be a more intuitive way of selecting color for a text, such as a color picker.

I’ll let Sam elaborate, but believe it’s a plugin because:

  • the server needs to cook the raw post in the back-end, and this can only be done if the assets are loaded in the backend for V8 to process it (which requires a plugin)
  • the plugins can include specs to test the new rules

However, there’s another workaround, e.g.:

post, e.g.:

[wrap=colorme color=red]Hello there[/wrap]
[wrap=colorme color=blue]Hi there![/wrap]

CSS:


div.d-wrap[data-wrap="colorme"], span.d-wrap[data-wrap="colorme"] {

  &[data-color="red"] {
    color: red;
  }

  &[data-color="blue"] {
    color: blue;
  }

  &[data-color="yellow"] {
    color: yellow;
  }

  &[data-color="green"] {
    color: green;
  }
}

You only need to add the CSS, the behaviour above is native.

The result appears to be a little less flexible and bulletproof than BBCode, but it’s quite useable for many use cases. (in order to have multiple different colours in the same line, the first character must not be coloured I believe?).

Based on:

2 Likes

That’s cool, thanks for pointing it out. The only thing I see problemtic with this is that it is very limiting for the end-user and also for the team who want to use this functionality.

A better and more flexible implementation would be if it was done via CSS variables where the generated code would be looking like this:

[wrap=colorme color=blue]Hi there![/wrap]

to

<div class="d-wrap" data-wrap="colorme" data-color="blue" style="--custom-colorme: blue">
    Bla
</div>

Then the underlying CSS could look like this with one statement and leave the color freedom to the enduser instead of delcaring every possible color in the CSS. He could use all kinds of color formats e.g. hsl, rgba etc.

div.d-wrap[data-wrap="colorme"] {
  &[data-color] {
    color: var(--custom-colorme);
  }
}

It would leave total freedom to the developer.

Adding support for custom CSS like this would also be backward compatible and not break anything from what I see. It would also allow better interaction with JS (via color picker for example).

1 Like

Themes have improved a lot since this plugin was created. You can already do this with a post decorator if you’re OK with the non-standard BBCode.

common > header

<script type="text/discourse-plugin" version="0.8">
  const hasAlpha = /(.,){3}|\//;
  const MAX_LENGTH = 25;

  const getVariable = value => {
    const color = value.replace(/\s/g, "");
    return hasAlpha.test(color) || color.length > MAX_LENGTH ? "" : color;
  };

  api.decorateCookedElement(
    post => {
      post
        .querySelectorAll("[data-color]")
        .forEach(i =>
          i.style.setProperty("--color", getVariable(i.dataset.color))
        );

      post
        .querySelectorAll("[data-bgcolor]")
        .forEach(i =>
          i.style.setProperty("--bgcolor", getVariable(i.dataset.bgcolor))
        );
    },
    { id: "wrap-colors" }
  );
</script>

common > css

.cooked,
.d-editor-preview {
  [data-color] {
    color: var(--color);
  }

  [data-bgcolor] {
    background-color: var(--bgcolor);
  }
}

It will accept any valid CSS color (color name, hex, RGB, HSL). It won’t accept RGBA or HSLA colors if they set an alpha value.

In the composer, you add this

color only
[wrap=color color=yellow]Hi there![/wrap] Welcome!

background only
[wrap=color bgcolor=red]Hi there![/wrap] Welcome!

color and background
[wrap=color color=#ff0000 bgcolor=white]Hi there![/wrap] Welcome!

and change the color to whatever you want.

Note that if you want to use HSL or RGB, you have to wrap them in quotes like so

bgcolor="rgba(0,0,0)"

This is safe with regard to user input and XSS since Discourse already escapes [wrap] tags, plus there’s also CSP. However…

3 Likes

Thats pretty cool. Thanks.

I am thinking of simplifying this further by adding a new toolbar button which looks like a color block.
Clicking on it will open a simple layer with preselected colors:

image

Clicking a color there will then perform the regular wrapWith composer method that adds the

[wrap=colorme color=blue]Hi there![/wrap]

around the selected text. Then, your code up there with decorateCookedElement() kicks in and renders it accordingly.

That sounds like an intuitive approach to me where ppl don’t have to write cryptic code to get colors.
I think I can whip this together in a theme component.

5 Likes

I’d already built my response into a Theme Component, so I’ve gone ahead and added Johani’s improvements.

Find it here:

merefield/discourse-tc-coloured-text: A simpler Theme Component alternative to the official BBCode post colouring plugin (github.com)

PR for palette welcome @Sören_Geier (and add yourself to the authors).

7 Likes

I’ve added a bit of padding when a bgcolor is specified, to give the background a little space to provide contrast. IMPROVE: give background colours room · merefield/discourse-tc-coloured-text@438916c (github.com)

2 Likes

I think I have something cooked up based on the previous work of you guys.
Will post a PR this weekend. Still bugs and things to iron out.

qKJ3Qt2RpY

4 Likes

Hi Sören! Did you ever post that PR? I just tried Robert’s theme component and don’t see your nifty color palette!

2 Likes

5 months later, Jesus, time flies. No haven’t had added it yet. I have some local version work in progress thingy. Not there where I want it to be.

1 Like