Skip to content

Commit b3cea12

Browse files
committed
feat: enable colors for tag labels as an option
1 parent df9dd03 commit b3cea12

5 files changed

Lines changed: 81 additions & 30 deletions

File tree

common/common.scss

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,31 @@
77
vertical-align: middle;
88
}
99

10-
.discourse-tag--tag-icons-style {
11-
&.simple {
12-
color: var(--color1, --tag-text-color);
13-
}
14-
15-
&.bullet {
16-
color: var(--color1, --tag-text-color);
17-
}
10+
.hashtag-cooked .hashtag-tag-icon .d-icon {
11+
color: var(--color1, var(--primary));
12+
}
1813

19-
&.box {
20-
color: var(--color2, --tag-text-color);
21-
background: var(--color1, --primary-low);
22-
}
14+
.discourse-tag--tag-icons-style .tag-icon {
15+
color: var(--color1, var(--tag-text-color));
2316
}
2417

25-
.hashtag-cooked:has(.hashtag-tag-icon) {
26-
color: var(--color1, --d-sidebar-link-icon-color);
18+
@if $enable_colors_for_tag_labels == "true" {
19+
.discourse-tag--tag-icons-style {
20+
&.simple {
21+
color: var(--color1, var(--tag-text-color));
22+
}
23+
24+
&.bullet {
25+
color: var(--color1, var(--tag-text-color));
26+
}
27+
28+
&.box {
29+
color: var(--color2, var(--tag-text-color));
30+
background-color: var(--color1, var(--primary-low));
31+
32+
.tag-icon {
33+
color: inherit;
34+
}
35+
}
36+
}
2737
}

javascripts/discourse/initializers/tag-icons.js

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import TagHashtagType from "discourse/lib/hashtag-types/tag";
22
import { iconHTML } from "discourse/lib/icon-library";
33
import { withPluginApi } from "discourse/lib/plugin-api";
44
import { defaultRenderTag } from "discourse/lib/render-tag";
5+
import { contrastColor } from "../lib/colors";
56

67
function iconTagRenderer(tag, params) {
78
// Get the rendered default tag markup.
@@ -19,7 +20,7 @@ function iconTagRenderer(tag, params) {
1920

2021
// Update the tag markup with an SVG icon, and inline-styles for the colors.
2122
if (tagIconItem) {
22-
const [, iconName, color1, color2] = tagIconItem.split(",");
23+
const [, iconName, color] = tagIconItem.split(",");
2324

2425
const parser = new DOMParser();
2526
const tagElement = parser.parseFromString(renderedTag, "text/html").body
@@ -31,8 +32,8 @@ function iconTagRenderer(tag, params) {
3132

3233
tagElement.prepend(iconElement);
3334
tagElement.classList.add("discourse-tag--tag-icons-style");
34-
tagElement.style.setProperty("--color1", color1 ?? "inherit");
35-
tagElement.style.setProperty("--color2", color2 ?? "inherit");
35+
tagElement.style.setProperty("--color1", color ?? "");
36+
tagElement.style.setProperty("--color2", color ? contrastColor(color) : "");
3637

3738
return tagElement.outerHTML;
3839
}
@@ -56,7 +57,11 @@ class TagHashtagTypeWithIcon extends TagHashtagType {
5657
newIcon.classList.add("hashtag-tag-icon");
5758
newIcon.innerHTML = svgIcon;
5859
if (opt.color) {
59-
newIcon.style.color = opt.color;
60+
newIcon.style.setProperty("--color1", opt.color ?? "");
61+
newIcon.style.setProperty(
62+
"--color2",
63+
opt.color ? contrastColor(opt.color) : ""
64+
);
6065
}
6166
return newIcon.outerHTML;
6267
}
@@ -74,34 +79,30 @@ export default {
7479
withPluginApi((api) => {
7580
api.replaceTagRenderer(iconTagRenderer);
7681

77-
/** @type {Record<string, { icon: string; color?: string; backgroundColor?: string; }?>} */
82+
/** @type {Record<string, { icon: string, color?: string }>} */
7883
const tagsMap = {};
7984

8085
const tagIconList = settings.tag_icon_list.split("|");
8186

8287
tagIconList.forEach((tagIcon) => {
83-
const [tagName, icon, color, backgroundColor] = tagIcon.split(",");
88+
const [tagName, prefixValue, prefixColor] = tagIcon.split(",");
8489

85-
if (tagName && icon) {
86-
// Sidebar section links
90+
if (tagName && prefixValue) {
8791
if (api.registerCustomTagSectionLinkPrefixIcon) {
8892
api.registerCustomTagSectionLinkPrefixIcon({
8993
tagName,
90-
prefixValue: icon,
91-
prefixColor: color,
94+
prefixValue,
95+
prefixColor,
9296
});
9397
}
9498

95-
// Everywhere else;
9699
tagsMap[tagName] = {
97-
icon,
98-
color,
99-
backgroundColor,
100+
icon: prefixValue,
101+
color: prefixColor,
100102
};
101103
}
102104
});
103105

104-
// Mentions.
105106
if (api.registerHashtagType) {
106107
api.registerHashtagType(
107108
"tag",
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const hexToRgb = (hex) => {
2+
if (typeof hex !== "string") {
3+
throw new TypeError("Hex color must be a string");
4+
}
5+
6+
let value = hex.trim().replace(/^#/, "");
7+
8+
if (value.length === 3) {
9+
value = value
10+
.split("")
11+
.map((char) => char + char)
12+
.join("");
13+
}
14+
15+
if (!/^[0-9a-fA-F]{6}$/.test(value)) {
16+
throw new Error(`Invalid hex color: ${hex}`);
17+
}
18+
19+
const num = parseInt(value, 16);
20+
21+
// eslint-disable-next-line no-bitwise
22+
return [(num >> 16) & 255, (num >> 8) & 255, num & 255];
23+
};
24+
25+
const luminance = (rgb) => {
26+
const c = [rgb[0], rgb[1], rgb[2]].map((v) => {
27+
v /= 255;
28+
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
29+
});
30+
return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
31+
};
32+
33+
export const contrastColor = (hexColor) => {
34+
const rgb = hexToRgb(hexColor);
35+
return luminance(rgb) >= 0.45 ? "#000d" : "#fffd";
36+
};

locales/en.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
en:
22
theme_metadata:
33
settings:
4-
tag_icon_list: 'Enter comma-delimited configuration for tags, in the format "tag-slug,icon,color,backgroundColor". The colors are optional.'
4+
tag_icon_list: 'Enter comma-delimited configuration for tags, in the format "tag-slug,icon,iconColor". Icon color is optional.'
5+
enable_colors_for_tag_labels: "Use colors for both tag icon and the tag label based on the configuration set above."
56
svg_icons: "List of FontAwesome 6 icons used in this theme component"

settings.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
tag_icon_list:
22
default: "tag1,circle-question,#CC0000|"
33
type: "list"
4+
enable_colors_for_tag_labels:
5+
default: false
6+
type: "bool"
47
svg_icons:
58
default: "circle-question"
69
type: "list"

0 commit comments

Comments
 (0)