mirror of
https://github.com/discourse/discourse.git
synced 2025-05-26 05:51:48 +08:00
FEATURE: Update Font Awesome to v5.4.1 and SVGs (#6557)
* First take on subsetting svg icons * FontAwesome 5 svg subset WIP * Include icons from plugins/badges into svg sprite subset * add svg icon support to themes * Add spec for SvgSprite * Misc. SVG icon fixes * Use FA5 svgs in local-dates plugin * CSS adjustments, fix SVG icons in group flair * Use SVG icons in poll plugin * Add SVG icons to /wizard
This commit is contained in:
@ -1,37 +1,200 @@
|
||||
import { h } from "virtual-dom";
|
||||
import attributeHook from "discourse-common/lib/attribute-hook";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
|
||||
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
||||
let _renderers = [];
|
||||
|
||||
const REPLACEMENTS = {
|
||||
"d-tracking": "circle",
|
||||
"d-muted": "times-circle",
|
||||
"d-regular": "circle-o",
|
||||
"d-regular": "far-circle",
|
||||
"d-watching": "exclamation-circle",
|
||||
"d-watching-first": "dot-circle-o",
|
||||
"d-watching-first": "far-dot-circle",
|
||||
"d-drop-expanded": "caret-down",
|
||||
"d-drop-collapsed": "caret-right",
|
||||
"d-unliked": "heart-o",
|
||||
"d-unliked": "far-heart",
|
||||
"d-liked": "heart",
|
||||
"notification.mentioned": "at",
|
||||
"notification.group_mentioned": "at",
|
||||
"notification.quoted": "quote-right",
|
||||
"notification.replied": "reply",
|
||||
"notification.posted": "reply",
|
||||
"notification.edited": "pencil",
|
||||
"notification.edited": "pencil-alt",
|
||||
"notification.liked": "heart",
|
||||
"notification.liked_2": "heart",
|
||||
"notification.liked_many": "heart",
|
||||
"notification.private_message": "envelope-o",
|
||||
"notification.invited_to_private_message": "envelope-o",
|
||||
"notification.invited_to_topic": "hand-o-right",
|
||||
"notification.private_message": "far-envelope",
|
||||
"notification.invited_to_private_message": "far-envelope",
|
||||
"notification.invited_to_topic": "far-hand-point-right",
|
||||
"notification.invitee_accepted": "user",
|
||||
"notification.moved_post": "sign-out",
|
||||
"notification.linked": "link",
|
||||
"notification.granted_badge": "certificate",
|
||||
"notification.topic_reminder": "hand-o-right",
|
||||
"notification.watching_first_post": "dot-circle-o",
|
||||
"notification.watching_first_post": "far-dot-circle",
|
||||
"notification.group_message_summary": "group"
|
||||
};
|
||||
|
||||
const fa4Replacements = {
|
||||
"area-chart": "chart-area",
|
||||
"bar-chart": "far-chart-bar",
|
||||
"bar-chart-o": "far-chart-bar",
|
||||
"chain-broken": "unlink",
|
||||
"circle-thin": "far-circle",
|
||||
"code-fork": "code-branch",
|
||||
"commenting-o": "far-comment-dots",
|
||||
"credit-card": "far-credit-card",
|
||||
"drivers-license": "id-card",
|
||||
"drivers-license-o": "far-id-card",
|
||||
"external-link": "external-link-alt",
|
||||
"external-link-square": "external-link-square-alt",
|
||||
"eye-slash": "far-eye-slash",
|
||||
"facebook-square": "fab-facebook-square",
|
||||
"file-sound-o": "far-file-audio",
|
||||
"file-text": "file-alt",
|
||||
"file-text-o": "far-file-alt",
|
||||
"files-o": "far-copy",
|
||||
"floppy-o": "far-save",
|
||||
"github-alt": "fab-github-alt",
|
||||
"github-square": "fab-github-square",
|
||||
"hacker-news": "fab-hacker-news",
|
||||
"hand-grab-o": "far-hand-rock",
|
||||
"id-badge": "far-id-badge",
|
||||
"internet-explorer": "fab-internet-explorer",
|
||||
"line-chart": "chart-line",
|
||||
"linkedin-square": "fab-linkedin",
|
||||
"list-alt": "far-list-alt",
|
||||
"mail-forward": "share",
|
||||
"mail-reply": "reply",
|
||||
"mail-reply-all": "reply-all",
|
||||
"map-marker": "map-marker-alt",
|
||||
"mobile-phone": "mobile-alt",
|
||||
"object-group": "far-object-group",
|
||||
"object-ungroup": "far-object-ungroup",
|
||||
"pencil-square": "pen-square",
|
||||
"pencil-square-o": "far-edit",
|
||||
"picture-o": "far-image",
|
||||
"pie-chart": "chart-pie",
|
||||
"rotate-left": "undo",
|
||||
"rotate-right": "redo",
|
||||
"send-o": "far-paper-plane",
|
||||
"sign-in": "sign-in-alt",
|
||||
"sign-out": "sign-out-alt",
|
||||
"soccer-ball-o": "far-futbol",
|
||||
"sort-alpha-asc": "sort-alpha-down",
|
||||
"sort-alpha-desc": "sort-alpha-up",
|
||||
"sort-amount-asc": "sort-amount-down",
|
||||
"sort-amount-desc": "sort-amount-up",
|
||||
"sort-asc": "sort-up",
|
||||
"sort-desc": "sort-down",
|
||||
"sort-numeric-asc": "sort-numeric-down",
|
||||
"sort-numeric-desc": "sort-numeric-up",
|
||||
"star-half-empty": "far-star-half",
|
||||
"star-half-full": "far-star-half",
|
||||
"thumb-tack": "thumbtack",
|
||||
"thumbs-o-down": "far-thumbs-down",
|
||||
"thumbs-o-up": "far-thumbs-up",
|
||||
"times-rectangle": "window-close",
|
||||
"times-rectangle-o": "far-window-close",
|
||||
"toggle-down": "far-caret-square-down",
|
||||
"toggle-left": "far-caret-square-left",
|
||||
"toggle-right": "far-caret-square-right",
|
||||
"toggle-up": "far-caret-square-up",
|
||||
"trash-o": "far-trash-alt",
|
||||
"twitter-square": "fab-twitter-square",
|
||||
"vcard-o": "far-address-card",
|
||||
"video-camera": "video",
|
||||
"vimeo-square": "fab-vimeo-square",
|
||||
"wheelchair-alt": "fab-accessible-icon",
|
||||
"window-maximize": "far-window-maximize",
|
||||
"window-restore": "far-window-restore",
|
||||
"youtube-play": "fab-youtube",
|
||||
"youtube-square": "fab-youtube-square",
|
||||
apple: "fab-apple",
|
||||
bank: "university",
|
||||
cab: "taxi",
|
||||
calendar: "calendar-alt",
|
||||
chain: "link",
|
||||
clipboard: "far-clipboard",
|
||||
clone: "far-clone",
|
||||
close: "times",
|
||||
cny: "yen-sign",
|
||||
commenting: "far-comment-dots",
|
||||
compass: "far-compass",
|
||||
copyright: "far-copyright",
|
||||
cutlery: "utensils",
|
||||
dashboard: "tachometer-alt",
|
||||
deafness: "deaf",
|
||||
dedent: "outdent",
|
||||
diamond: "far-gem",
|
||||
dollar: "dollar-sign",
|
||||
exchange: "exchange-alt",
|
||||
eye: "far-eye",
|
||||
eyedropper: "eye-dropper",
|
||||
facebook: "fab-facebook-f",
|
||||
feed: "rss",
|
||||
flash: "bolt",
|
||||
gbp: "pound-sign",
|
||||
gear: "cog",
|
||||
gears: "cogs",
|
||||
github: "fab-github",
|
||||
glass: "glass-martini",
|
||||
glass: "glass-martini",
|
||||
google: "fab-google",
|
||||
group: "users",
|
||||
header: "heading",
|
||||
hotel: "bed",
|
||||
ils: "shekel-sign",
|
||||
image: "far-image",
|
||||
inr: "rupee-sign",
|
||||
instagram: "fab-instagram",
|
||||
institution: "university",
|
||||
intersex: "transgender",
|
||||
jpy: "yen-sign",
|
||||
legal: "gavel",
|
||||
linkedin: "fab-linkedin-in",
|
||||
linode: "fab-linode",
|
||||
linux: "fab-linux",
|
||||
meetup: "fab-meetup",
|
||||
mobile: "mobile-alt",
|
||||
navicon: "bars",
|
||||
paste: "far-clipboard",
|
||||
pencil: "pencil-alt",
|
||||
photo: "far-image",
|
||||
refresh: "sync",
|
||||
registered: "far-registered",
|
||||
remove: "times",
|
||||
remove: "times",
|
||||
reorder: "bars",
|
||||
repeat: "redo",
|
||||
rmb: "yen-sign",
|
||||
rouble: "ruble-sign",
|
||||
ruble: "ruble-sign",
|
||||
rupee: "rupee-sign",
|
||||
s15: "bath",
|
||||
scissors: "cut",
|
||||
send: "paper-plane",
|
||||
shekel: "shekel-sign",
|
||||
shield: "shield-alt",
|
||||
signing: "sign-language",
|
||||
support: "far-life-ring",
|
||||
tablet: "tablet-alt",
|
||||
tachometer: "tachometer-alt",
|
||||
television: "tv",
|
||||
ticket: "ticket-alt",
|
||||
trash: "trash-alt",
|
||||
twitter: "fab-twitter",
|
||||
unsorted: "sort",
|
||||
vcard: "address-card",
|
||||
vimeo: "fab-vimeo-v",
|
||||
warning: "exclamation-triangle",
|
||||
whatsapp: "fab-whatsapp",
|
||||
windows: "fab-windows",
|
||||
yahoo: "fab-yahoo",
|
||||
youtube: "fab-youtube"
|
||||
};
|
||||
|
||||
export function replaceIcon(source, destination) {
|
||||
REPLACEMENTS[source] = destination;
|
||||
}
|
||||
@ -59,6 +222,13 @@ export function iconNode(id, params) {
|
||||
return renderIcon("node", id, params);
|
||||
}
|
||||
|
||||
export function convertIconClass(icon) {
|
||||
return icon
|
||||
.replace("far fa-", "far-")
|
||||
.replace("fab fa-", "fab-")
|
||||
.replace("fa-", "");
|
||||
}
|
||||
|
||||
// TODO: Improve how helpers are registered for vdom compliation
|
||||
if (typeof Discourse !== "undefined") {
|
||||
Discourse.__widget_helpers.iconNode = iconNode;
|
||||
@ -68,58 +238,114 @@ export function registerIconRenderer(renderer) {
|
||||
_renderers.unshift(renderer);
|
||||
}
|
||||
|
||||
// Support for font awesome icons
|
||||
function faClasses(icon, params) {
|
||||
let classNames = `fa fa-${icon.replacementId || icon.id} d-icon d-icon-${
|
||||
icon.id
|
||||
}`;
|
||||
function iconClasses(icon, params) {
|
||||
// "notification." is invalid syntax for classes, use replacement instead
|
||||
const dClass =
|
||||
icon.replacementId && icon.id.indexOf("notification.") > -1
|
||||
? icon.replacementId
|
||||
: icon.id;
|
||||
|
||||
if (params) {
|
||||
if (params.modifier) {
|
||||
classNames += " fa-" + params.modifier;
|
||||
}
|
||||
if (params["class"]) {
|
||||
classNames += " " + params["class"];
|
||||
}
|
||||
let classNames = `fa d-icon d-icon-${dClass} svg-icon`;
|
||||
|
||||
if (params && params["class"]) {
|
||||
classNames += " " + params["class"];
|
||||
}
|
||||
|
||||
return classNames;
|
||||
}
|
||||
|
||||
function warnIfMissing(id) {
|
||||
if (
|
||||
typeof Discourse !== "undefined" &&
|
||||
Discourse.Environment === "development" &&
|
||||
Discourse.SvgIconList &&
|
||||
Discourse.SvgIconList.indexOf(id) === -1
|
||||
) {
|
||||
console.warn(`The icon "${id}" is missing from the SVG subset.`);
|
||||
}
|
||||
}
|
||||
|
||||
function warnIfDeprecated(oldId, newId) {
|
||||
if (
|
||||
typeof Discourse !== "undefined" &&
|
||||
Discourse.Environment === "development" &&
|
||||
!Ember.testing
|
||||
) {
|
||||
deprecated(`Icon "${oldId}" is now "${newId}".`);
|
||||
}
|
||||
}
|
||||
|
||||
function handleIconId(icon) {
|
||||
let id = icon.replacementId || icon.id || "";
|
||||
|
||||
if (fa4Replacements.hasOwnProperty(id)) {
|
||||
warnIfDeprecated(id, fa4Replacements[id]);
|
||||
id = fa4Replacements[id];
|
||||
} else if (id.substr(id.length - 2) === "-o") {
|
||||
let newId = "far-" + id.replace("-o", "");
|
||||
warnIfDeprecated(id, newId);
|
||||
id = newId;
|
||||
}
|
||||
|
||||
// TODO: clean up "thumbtack unpinned" at source instead of here
|
||||
id = id.replace(" unpinned", "");
|
||||
|
||||
warnIfMissing(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
// default resolver is font awesome
|
||||
registerIconRenderer({
|
||||
name: "font-awesome",
|
||||
|
||||
string(icon, params) {
|
||||
let tagName = params.tagName || "i";
|
||||
let html = `<${tagName} class='${faClasses(icon, params)}'`;
|
||||
if (params.title) {
|
||||
html += ` title='${I18n.t(params.title).replace(/'/g, "'")}'`;
|
||||
}
|
||||
const id = handleIconId(icon);
|
||||
let html = `<svg class='${iconClasses(icon, params)} svg-string'`;
|
||||
|
||||
if (params.label) {
|
||||
html += " aria-hidden='true'";
|
||||
}
|
||||
html += `></${tagName}>`;
|
||||
html += ` xmlns="${SVG_NAMESPACE}"><use xlink:href="#${id}" /></svg>`;
|
||||
if (params.label) {
|
||||
html += `<span class='sr-only'>${params.label}</span>`;
|
||||
}
|
||||
if (params.title) {
|
||||
html = `<span class="svg-icon-title" title='${I18n.t(
|
||||
params.title
|
||||
).replace(/'/g, "'")}'>${html}</span>`;
|
||||
}
|
||||
return html;
|
||||
},
|
||||
|
||||
node(icon, params) {
|
||||
let tagName = params.tagName || "i";
|
||||
const id = handleIconId(icon);
|
||||
const classes = iconClasses(icon, params) + " svg-node";
|
||||
|
||||
const properties = {
|
||||
className: faClasses(icon, params),
|
||||
attributes: { "aria-hidden": true }
|
||||
};
|
||||
const svg = h(
|
||||
"svg",
|
||||
{
|
||||
attributes: { class: classes, "aria-hidden": true },
|
||||
namespace: SVG_NAMESPACE
|
||||
},
|
||||
[
|
||||
h("use", {
|
||||
"xlink:href": attributeHook("http://www.w3.org/1999/xlink", `#${id}`),
|
||||
namespace: SVG_NAMESPACE
|
||||
})
|
||||
]
|
||||
);
|
||||
|
||||
if (params.title) {
|
||||
properties.attributes.title = params.title;
|
||||
}
|
||||
if (params.label) {
|
||||
return h(tagName, properties, h("span.sr-only", I18n.t(params.label)));
|
||||
return h(
|
||||
"span",
|
||||
{
|
||||
title: params.title,
|
||||
attributes: { class: "svg-icon-title" }
|
||||
},
|
||||
[svg]
|
||||
);
|
||||
} else {
|
||||
return h(tagName, properties);
|
||||
return svg;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
Reference in New Issue
Block a user