Colors for individual words or phrases

I find myself in need of coloring a few words red somewhat often, and blue or green a bit less so.

I got this working (see below), but I am curious if there is a more elegant or canonical way. I’ve been using SB barely a few weeks and I’d welcome some thoughts on this from the experts.

Colors ${Red("red")} and ${Green("green")} and ${Blue("blue!")}.

```space-lua
function Red(text)
  return widget.html(dom.span {
    style="color:red; font-weight: bold;",
    text
  })
end
function Green(text)
  return widget.html(dom.span {
    style="color:green; font-weight: bold;",
    text
  })
end
function Blue(text)
  return widget.html(dom.span {
    style="color:blue; font-weight: bold;",
    text
  })
end
```

I cannot find it right now but I think (not sure) I once proposed to extend our CommonMark in Silverbullet with {.class} (and {#html_tag} as well as {html_attr=ibut} or even {span .custom-class .another-class #some_id datatag='custom data'} would be splendid. What do you think @zef ?

Example:

This is red paragraph.
{.red}

- foo
- green bar {.green #with-id}
- quux

> My very special quote!
>
> I will styled by both CSS class and data-tag.
> And that's cool!
> {.myquote data-tag="cool"}

{.red}
Another red paragraph.

We, as we know, cannot have raw HTML in Markdown which makes sort of HTML/CSS trickery trickier without custom plugs. To use Space Lua is nice way but it’s not as elegant. The proposed syntax above would work for blocks only and the {...} can be appended or prepended to the block without any ambiguity (if it’s well defined, of course).

(The proposed above syntax already exists in some frameworks AFAIK.)

But I have no idea how to cope with inline spans. We will need some “closure” within which the {...} could apply or we can say that {html-tag} (without the =value as for the data tags) will insert the html-tag and we can see the end of it will be {/html-tag}, e.g.

Some {code .bash data-tag=something #reftag-1}while :; do :; done{/code} paragraph.

Result will be something like:

<p>Some <code class='bash' id='reftag-1' data-tag='something'>while :; do :; done</code> paragraph.

Looks good to me… :slight_smile:

I’ve created this solution at some point

@MrMugame I used this your CSS mastery extensively for my hashtags too.

But we still cannot assign custom datatags freely anywhere we would like to. The proposed syntax above allows for that, and it even works arround the lack of inline HTML support in Silverbullet, allows for https://domain.tld/Some/Page#exact-place referencing, custom CSS classes anywhere.

  • {.class} for divs (or {.class}...{/} for inlined spans),
  • {#id} (or {#id}...{/},
  • {some=datatag} (or {some=datatag}...{/}),
  • {html-element} (or {html-element}...{/}

    This is sort of problematic, because HTML also allows for example <span foo bar baz>...</span> too. To work this little ambiguity around we can say that a word is a HTML element if and only iff it is written right after the opening left brace { and if a space is placed between the { and the word then the HTML element is the default one (<span/> for inlined {...} and <div/> for block {...}, e.g. { not-element-name} with result <span not-element-name>,

  • combination of these at once like {em .red .bold #here excerpt='text'}text text text{/em}.

I really started to like it personally while thinking about it! :slight_smile: How difficult could it be to implement this (I can provide exact specification)?

Thank you for posting this! I was really wanting a way to add some color to my notes. I often quote a passage about a person I am researching in my genealogy notes, and had been putting the source citation in one color, and my comments on the passage in another color (via .css in Obsidian) Now I can do that in silverbullet via functions similar to what you posted above.

Kindness is rewarded: with the addition of new shortcuts, the operations for selected and unselected text now emulate the native Ctrl + B feature more faithfully.

local colors = {
  red    = "#E57373",
  green  = "#81C784",
  blue   = "#64B5F6",
  yellow = "#FFF176",
  purple = "#BAA7E5"
}

local function ColorText(text, color)
  return widget.html(dom.span {
    style = string.format("color:%s; font-weight: bold;", color),
    text
  })
end

function Red(text)    return ColorText(text, colors.red) end
function Green(text)  return ColorText(text, colors.green) end
function Blue(text)   return ColorText(text, colors.blue) end
function Yellow(text) return ColorText(text, colors.yellow) end
function Purple(text) return ColorText(text, colors.purple) end

function getSelectedText()
  local sel = editor.getSelection()
  if not sel or sel.from == sel.to then return nil end
  local text = editor.getText()
  return text:sub(sel.from + 1, sel.to)
end

function setSelectedText(newText)
  local sel = editor.getSelection()
  if not sel or sel.from == sel.to then return nil end
  editor.replaceRange(sel.from, sel.to, newText)
end

function moveToNewTextPos(suffixText)
  local pos = editor.getCursor()
  local newPos = pos - #suffixText
  editor.moveCursor(newPos, true)
end

local function wrapWithColor(fnName)
  local text = getSelectedText()
  if text and text ~= "" then
    local newText = string.format("${%s(\"%s\")}", fnName, text)
    setSelectedText(newText)
  else
    local insertText = string.format("${%s(\"\")}", fnName)
    editor.insertAtCursor(insertText, false)
    moveToNewTextPos("\")}")
  end
end

local colorNames = { "Red", "Green", "Blue", "Yellow", "Purple" }

for _, name in ipairs(colorNames) do
  local key = string.lower(string.sub(name, 1, 1))

  command.define {
    name = "Text: " .. name,
    category = "Style",
    key = "Alt-" .. key,
    description = string.format("将文本标记为柔和%s色", name),
    run = function()
      wrapWithColor(name)
    end
  }
end