1- import escape from "discourse/lib/escape" ;
2- import getURL from "discourse/lib/get-url" ;
31import TagHashtagType from "discourse/lib/hashtag-types/tag" ;
4- import { helperContext } from "discourse/lib/helpers" ;
52import { iconHTML } from "discourse/lib/icon-library" ;
63import { withPluginApi } from "discourse/lib/plugin-api" ;
7- import { escapeExpression } from "discourse/lib/utilities" ;
4+ import { defaultRenderTag } from "discourse/lib/render-tag" ;
5+ import { contrastColor } from "../lib/colors" ;
86
97function iconTagRenderer ( tag , params ) {
10- let { siteSettings, currentUser } = helperContext ( ) ;
11- let tagIconList = settings . tag_icon_list . split ( "|" ) ;
12-
13- params = params || { } ;
14- // TODO(https://github.com/discourse/discourse/pull/36678): The string check can be
15- // removed using .discourse-compatibility once the PR is merged.
16- const tagStr = typeof tag === "string" ? tag : tag . name ;
17- const visibleName = escapeExpression ( tagStr ) ;
18- tag = visibleName . toLowerCase ( ) ;
19-
20- const classes = [ "discourse-tag" ] ;
21- const htmlTagName = params . tagName || "a" ;
22- let path ;
23- if ( htmlTagName === "a" && ! params . noHref ) {
24- if ( ( params . isPrivateMessage || params . pmOnly ) && currentUser ) {
25- const username = params . tagsForUser
26- ? params . tagsForUser
27- : currentUser . username ;
28- path = `/u/${ username } /messages/tags/${ tag } ` ;
29- } else {
30- path = `/tag/${ tag } ` ;
31- }
32- }
33- const href = path ? ` href='${ getURL ( path ) } ' ` : "" ;
34- if ( siteSettings . tag_style || params . style ) {
35- classes . push ( params . style || siteSettings . tag_style ) ;
36- }
37-
38- if ( params . extraClass ) {
39- classes . push ( params . extraClass ) ;
40- }
41-
42- if ( params . size ) {
43- classes . push ( params . size ) ;
44- }
8+ // Get the rendered default tag markup.
9+ const renderedTag = defaultRenderTag ( tag , params ) ;
4510
46- // remove all html tags from hover text
47- const hoverDescription =
48- params . description && params . description . replace ( / < .+ ?> / g, "" ) ;
11+ // Get the tag configuration list from the settings.
12+ const tagIconList = settings . tag_icon_list . split ( "|" ) ;
4913
50- /// Add custom tag icon from theme settings
51- let tagIconItem = tagIconList . find ( ( str ) => {
52- return str . indexOf ( "," ) > - 1
53- ? tag === str . substr ( 0 , str . indexOf ( "," ) ) . toLowerCase ( )
54- : "" ;
55- } ) ;
14+ // Returns the tag configuration if found.
15+ const tagIconItem = tagIconList . find (
16+ ( line ) =>
17+ line . indexOf ( "," ) > - 1 &&
18+ tag . toLowerCase ( ) === line . substr ( 0 , line . indexOf ( "," ) ) . toLowerCase ( )
19+ ) ;
5620
57- let tagIconHTML = "" ;
21+ // Update the tag markup with an SVG icon, and inline-styles for the colors.
5822 if ( tagIconItem ) {
59- let tagIcon = tagIconItem . split ( "," ) ;
60-
61- let itemColor = tagIcon [ 2 ] ? `style="color: ${ tagIcon [ 2 ] } "` : "" ;
62- tagIconHTML = `<span ${ itemColor } class="tag-icon">${ iconHTML (
63- tagIcon [ 1 ]
64- ) } </span>`;
65- }
66- /// End custom tag icon
67-
68- let val =
69- "<" +
70- htmlTagName +
71- href +
72- " data-tag-name=" +
73- tag +
74- ( params . description ? ' title="' + escape ( hoverDescription ) + '" ' : "" ) +
75- " class='" +
76- classes . join ( " " ) +
77- "'>" +
78- tagIconHTML + // inject tag Icon in html
79- ( params . displayName ? escape ( params . displayName ) : visibleName ) +
80- "</" +
81- htmlTagName +
82- ">" ;
83-
84- if ( params . count ) {
85- val += " <span class='discourse-tag-count'>x" + params . count + "</span>" ;
23+ const [ , iconName , color ] = tagIconItem . split ( "," ) ;
24+
25+ const parser = new DOMParser ( ) ;
26+ const tagElement = parser . parseFromString ( renderedTag , "text/html" ) . body
27+ . firstChild ;
28+ const iconElement = parser . parseFromString (
29+ `<span class="tag-icon">${ iconHTML ( iconName ) } </span>` ,
30+ "text/html"
31+ ) . body . firstChild ;
32+
33+ tagElement . prepend ( iconElement ) ;
34+ tagElement . classList . add ( "discourse-tag--tag-icons-style" ) ;
35+ tagElement . style . setProperty ( "--color1" , color ?? "" ) ;
36+ tagElement . style . setProperty ( "--color2" , color ? contrastColor ( color ) : "" ) ;
37+
38+ return tagElement . outerHTML ;
8639 }
8740
88- return val ;
41+ return renderedTag ;
8942}
9043
9144class TagHashtagTypeWithIcon extends TagHashtagType {
@@ -97,27 +50,36 @@ class TagHashtagTypeWithIcon extends TagHashtagType {
9750 generateIconHTML ( hashtag ) {
9851 const opt = hashtag . slug && this . dict [ hashtag . slug ] ;
9952 if ( opt ) {
53+ const svgIcon = iconHTML ( opt . icon , {
54+ class : `hashtag-color--${ this . type } -${ hashtag . id } ` ,
55+ } ) ;
10056 const newIcon = document . createElement ( "span" ) ;
10157 newIcon . classList . add ( "hashtag-tag-icon" ) ;
102- newIcon . innerHTML = iconHTML ( opt . icon ) ;
58+ newIcon . innerHTML = svgIcon ;
10359 if ( opt . color ) {
104- 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+ ) ;
10565 }
10666 return newIcon . outerHTML ;
107- } else {
108- return super . generateIconHTML ( hashtag ) ;
10967 }
68+
69+ return super . generateIconHTML ( hashtag ) ;
11070 }
11171}
11272
11373export default {
11474 name : "tag-icons" ,
11575
76+ before : "hashtag-css-generator" ,
77+
11678 initialize ( owner ) {
11779 withPluginApi ( ( api ) => {
11880 api . replaceTagRenderer ( iconTagRenderer ) ;
11981
120- /** @type {Record<string, {icon: string, color: string?}? > } */
82+ /** @type {Record<string, { icon: string, color? : string } > } */
12183 const tagsMap = { } ;
12284
12385 const tagIconList = settings . tag_icon_list . split ( "|" ) ;
0 commit comments