From bf972b95730459574132a6a4009788c438dcd893 Mon Sep 17 00:00:00 2001 From: Lhc_fl Date: Mon, 15 Jul 2024 14:08:43 +0800 Subject: [PATCH] FEATURE: display category icon in post body This commit allows displaying category icons in the body of the post. Related meta topic: https://meta.discourse.org/t/category-icons-dont-show-up-in-post-text/315851 --- .../discourse/initializers/category-icons.js | 47 ++++++++++ settings.yml | 3 + .../post-body-category-icons-test.js | 89 +++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 test/acceptance/post-body-category-icons-test.js diff --git a/javascripts/discourse/initializers/category-icons.js b/javascripts/discourse/initializers/category-icons.js index 85128c4..2aa898c 100644 --- a/javascripts/discourse/initializers/category-icons.js +++ b/javascripts/discourse/initializers/category-icons.js @@ -199,6 +199,53 @@ export default { } }); } + + if (settings.render_category_icon_in_post) { + const site = api.container.lookup("service:site"); + const slugMap = {}; + for (const str of categoryThemeList) { + const [slug, icon, color, match] = str.split(","); + if (slug && icon) { + for (const cat of site.categories) { + if (match === "partial") { + if (!cat.slug.toLowerCase().includes(slug.toLowerCase())) { + continue; + } + } else { + if (cat.slug.toLowerCase() !== slug.toLowerCase()) { + continue; + } + } + const opts = { + icon, + color, + }; + if (!color || color?.match(/categoryColo(u*)r/g)) { + opts.color = `#${cat.color}`; + } + slugMap[cat.slug.toLowerCase()] = opts; + } + } + } + api.decorateCookedElement((elem) => { + const categorgHashtags = elem.querySelectorAll( + '.hashtag-cooked[data-type="category"]' + ); + for (const hashtag of categorgHashtags) { + const opt = slugMap[hashtag.dataset?.slug?.toLowerCase()]; + if (!opt) { + continue; + } + const newIcon = document.createElement("span"); + newIcon.classList.add("hashtag-category-icon"); + newIcon.innerHTML = iconHTML(opt.icon); + newIcon.style.color = opt.color; + hashtag + .querySelector("span.hashtag-category-badge") + ?.replaceWith(newIcon); + } + }); + } }); }, }; diff --git a/settings.yml b/settings.yml index b6f49c9..4de81d7 100644 --- a/settings.yml +++ b/settings.yml @@ -3,6 +3,9 @@ category_icon_list: type: "list" list_type: "simple" description: 'Enter comma-delimited configuration for categories, in the format "slug,icon,color,match". Color can be in hex format (#123456) or left blank, then the default color for the category is used (same as the Badge color). If match is "partial" then the slug need only partially match the category-slug, otherwise an exact match is required' +render_category_icon_in_post: + default: true + description: "Show category icons in the post body" svg_icons: default: "question-circle" type: "list" diff --git a/test/acceptance/post-body-category-icons-test.js b/test/acceptance/post-body-category-icons-test.js new file mode 100644 index 0000000..5fbaf95 --- /dev/null +++ b/test/acceptance/post-body-category-icons-test.js @@ -0,0 +1,89 @@ +import { visit } from "@ember/test-helpers"; +import { test } from "qunit"; +import TopicFixtures from "discourse/tests/fixtures/topic"; +import { acceptance } from "discourse/tests/helpers/qunit-helpers"; +import { cloneJSON } from "discourse-common/lib/object"; + +function makeHashtagHTML(category) { + return `${category.name}`; +} + +acceptance("Post body - Category icons", function (needs) { + needs.user(); + + const categories = [ + { + id: 1, + name: "Category 1", + slug: "category-1", + color: "111111", + }, + { + id: 2, + name: "Category 2", + slug: "category-2", + color: "000000", + }, + { + id: 3, + name: "Category 3", + slug: "category-3", + color: "888888", + }, + ]; + + needs.site({ + categories, + }); + + needs.hooks.beforeEach(function () { + settings.category_lock_icon = "wrench"; + settings.category_icon_list = `category-1,wrench,#FF0000|category-2,question-circle,categoryColor`; + }); + + needs.pretender((server, helper) => { + server.get("/t/131.json", () => { + const topicList = cloneJSON(TopicFixtures["/t/130.json"]); + topicList.post_stream.posts[0].cooked = `

${makeHashtagHTML( + categories[0] + )} ${makeHashtagHTML(categories[1])} ${makeHashtagHTML( + categories[2] + )}

`; + return helper.response(topicList); + }); + }); + + test("Icon for category when `category_icon_list` theme setting has been configured", async function (assert) { + await visit("/t/131"); + + assert + .dom( + `.cooked .hashtag-cooked[data-id="1"] .hashtag-category-icon .d-icon-wrench` + ) + .exists("wrench icon is displayed for category-1"); + + assert + .dom(`.cooked .hashtag-cooked[data-id="1"] .hashtag-category-icon`) + .hasStyle( + { color: "rgb(255, 0, 0)" }, + "category-1 's icon has the right color" + ); + + assert + .dom( + `.cooked .hashtag-cooked[data-id="2"] .hashtag-category-icon .d-icon-question-circle` + ) + .exists("question-circle icon is displayed for category-2"); + + assert + .dom(`.cooked .hashtag-cooked[data-id="2"] .hashtag-category-icon`) + .hasStyle( + { color: "rgb(0, 0, 0)" }, + "category-2 's icon has the right categoryColor" + ); + + assert + .dom(`.cooked .hashtag-cooked[data-id="3"] .hashtag-category-badge`) + .exists("unconfigured categories have a default badge"); + }); +});