feat: export complete Discourse themes ecosystem (16 themes, SCSS, JS components and color schemes)

This commit is contained in:
eldov
2026-08-30 18:07:57 +02:00
parent 0d76aaa622
commit 3a411c2643
258 changed files with 16878 additions and 0 deletions
@@ -0,0 +1,10 @@
{
"name": "Discourse Phosphor Icons",
"description": "Replaces Discourse icons with the Phosphor icon set",
"about_url": null,
"license_url": "https://github.com/discourse/discourse-phosphor-icons/blob/main/LICENSE",
"component": true,
"assets": {
"icons-sprite": "/assets/icons-sprite.svg"
}
}
@@ -0,0 +1,26 @@
import { apiInitializer } from "discourse/lib/api";
import { FORCE_FILL, ICON_MAP, WEIGHTS } from "../lib/icon-map";
export default apiInitializer((api) => {
const configuredWeight = WEIGHTS.includes(settings.weight)
? settings.weight
: "regular";
const forceFill = new Set(FORCE_FILL);
const ignored = new Set(
(settings.ignored_icons || "")
.split("|")
.map((name) => name.trim())
.filter(Boolean)
);
Object.entries(ICON_MAP).forEach(([faIcon, phosphorIcon]) => {
if (ignored.has(faIcon)) {
return;
}
const weight = forceFill.has(faIcon) ? "fill" : configuredWeight;
api.replaceIcon(faIcon, `ph-${weight}-${phosphorIcon}`);
});
});
@@ -0,0 +1,414 @@
// Source of truth for FontAwesome -> Phosphor icon name mappings.
// Imported by the api-initializer at runtime and by scripts/generate-sprite.mjs
// at build time. After editing, run `pnpm build` to regenerate the sprite.
// Names are weight-agnostic; the chosen weight is applied at runtime.
// Weights an admin can choose from (kept in sync with settings.yml). `fill` is
// intentionally excluded — filled is a product state, applied only to the
// FORCE_FILL icons below.
export const WEIGHTS = ["light", "regular", "bold", "duotone"];
export const ICON_MAP = {
"address-book": "address-book",
"address-card": "identification-card",
"align-left": "text-align-left",
anchor: "anchor",
"angle-down": "caret-down",
"angle-left": "caret-left",
"angle-right": "caret-right",
"angle-up": "caret-up",
"angles-down": "caret-double-down",
"angles-left": "caret-double-left",
"angles-right": "caret-double-right",
"angles-up": "caret-double-up",
"arrow-circle-o-right": "arrow-circle-right",
"arrow-circle-up": "arrow-circle-up",
"arrow-down": "arrow-down",
"arrow-left": "arrow-left",
"arrow-right": "arrow-right",
"arrow-rotate-left": "arrow-counter-clockwise",
"arrow-rotate-right": "arrow-clockwise",
"arrow-up": "arrow-up",
"arrows-rotate": "arrow-clockwise",
asterisk: "asterisk",
at: "at",
award: "medal",
backward: "rewind",
"backward-fast": "skip-back",
"backward-step": "skip-back",
ban: "prohibit",
"band-aid": "bandaids",
bars: "list",
"bars-staggered": "list-dashes",
bed: "bed",
bell: "bell",
"bell-slash": "bell-slash",
"birthday-cake": "cake",
bold: "text-b",
book: "book",
"book-open-reader": "book-open-text",
bookmark: "bookmark-simple",
"box-archive": "archive",
briefcase: "briefcase",
bullseye: "target",
"cake-candles": "cake",
"calendar-day": "calendar-dot",
"calendar-days": "calendar-blank",
campground: "tent",
"caret-down": "caret-circle-down",
"caret-left": "caret-circle-left",
"caret-right": "caret-circle-right",
"caret-up": "caret-circle-up",
certificate: "certificate",
"chart-bar": "chart-bar",
"chart-line": "chart-line",
"chart-pie": "chart-pie",
check: "check",
"check-square": "check-square",
"check-to-slot": "check-fat",
"chevron-down": "caret-down",
"chevron-left": "caret-left",
"chevron-right": "caret-right",
"chevron-up": "caret-up",
circle: "circle",
"circle-check": "check-circle",
"circle-chevron-down": "caret-circle-down",
"circle-exclamation": "warning-circle",
"circle-half-stroke": "circle-half",
"circle-info": "info",
"circle-minus": "minus-circle",
"circle-plus": "plus-circle",
"circle-question": "question",
"circle-stop": "stop-circle",
"circle-user": "user-circle",
"circle-xmark": "x-circle",
clipboard: "clipboard",
clock: "clock",
"clock-rotate-left": "clock-counter-clockwise",
"cloud-arrow-down": "cloud-arrow-down",
"cloud-arrow-up": "cloud-arrow-up",
code: "code",
"code-branch": "git-branch",
comment: "chat-centered",
"comment-dots": "chat-centered-dots",
"comment-slash": "chat-centered-slash",
comments: "chats",
compress: "arrows-in",
copy: "copy",
crosshairs: "crosshair",
crown: "crown",
cube: "cube",
cubes: "stack",
"d-chat": "chat-circle",
"d-drop-collapsed": "arrow-circle-right",
"d-drop-expanded": "arrow-circle-down",
"d-liked": "heart",
"d-muted": "bell-slash",
"d-post-share": "link-simple",
"d-regular": "bell",
"d-topic-share": "link-simple",
"d-tracking": "bell",
"d-unliked": "heart",
"d-watching": "bell",
"d-watching-first": "bell",
desktop: "desktop",
"diagram-project": "tree-structure",
"discourse-add-translation": "translate",
"discourse-amazon": "amazon-logo",
"discourse-bell-exclamation": "bell-ringing",
"discourse-bell-one": "bell",
"discourse-bell-slash": "bell-slash",
"discourse-chevron-collapse": "arrows-in-line-vertical",
"discourse-chevron-expand": "arrows-out-line-vertical",
"discourse-circle-minus": "minus-circle",
"discourse-circle-plus": "plus-circle",
"discourse-compress": "arrows-in-simple",
"discourse-dnd": "moon",
"discourse-emojis": "smiley",
"discourse-expand": "arrows-out-simple",
"discourse-flask-check": "flask",
"discourse-h1": "text-h-one",
"discourse-h2": "text-h-two",
"discourse-h3": "text-h-three",
"discourse-h4": "text-h-four",
"discourse-h5": "text-h-five",
"discourse-other-tab": "squares-four",
"discourse-sidebar": "sidebar",
"discourse-sparkles": "sparkle",
"discourse-table": "table",
"discourse-text": "text-t",
"discourse-threads": "chats",
download: "download",
"earth-americas": "globe-hemisphere-west",
ellipsis: "dots-three-outline",
"ellipsis-vertical": "dots-three-outline-vertical",
envelope: "envelope",
"exclamation-circle": "warning-circle",
expand: "arrows-out",
eye: "eye",
"eye-dropper": "eyedropper",
"eye-slash": "eye-slash",
"fab-amazon": "amazon-logo",
"fab-android": "android-logo",
"fab-apple": "apple-logo",
"fab-chrome": "google-chrome-logo",
"fab-discord": "discord-logo",
"fab-facebook": "facebook-logo",
"fab-facebook-square": "facebook-logo",
"fab-github": "github-logo",
"fab-google": "google-logo",
"fab-instagram": "instagram-logo",
"fab-linkedin-in": "linkedin-logo",
"fab-linux": "linux-logo",
"fab-markdown": "markdown-logo",
"fab-patreon": "patreon-logo",
"fab-steam": "steam-logo",
"fab-threads": "threads-logo",
"fab-threads-square": "threads-logo",
"fab-twitter": "twitter-logo",
"fab-twitter-square": "twitter-logo",
"fab-windows": "windows-logo",
"fab-x-twitter": "x-logo",
"face-smile": "smiley",
"far-bell": "bell",
"far-bell-slash": "bell-slash",
"far-bookmark": "bookmark-simple",
"far-calendar-alt": "calendar-blank",
"far-calendar-plus": "calendar-plus",
"far-chart-bar": "chart-bar",
"far-check-circle": "check-circle",
"far-circle": "circle",
"far-circle-check": "check-circle",
"far-circle-dot": "radio-button",
"far-clipboard": "clipboard",
"far-clock": "clock",
"far-comment": "chat-centered",
"far-comments": "chats",
"far-copyright": "copyright",
"far-credit-card": "credit-card",
"far-envelope": "envelope-simple",
"far-eye": "eye",
"far-eye-slash": "eye-slash",
"far-face-frown": "smiley-sad",
"far-face-meh": "smiley-meh",
"far-face-smile": "smiley",
"far-file": "file",
"far-file-lines": "file-text",
"far-heart": "heart",
"far-image": "image",
"far-map": "map-trifold",
"far-moon": "moon",
"far-pen-to-square": "pencil-line",
"far-rectangle-list": "list-bullets",
"far-square": "square",
"far-square-check": "check-square",
"far-star": "star",
"far-sun": "sun",
"far-thumbs-down": "thumbs-down",
"far-thumbs-up": "thumbs-up",
"far-trash-can": "trash",
file: "file",
"file-arrow-up": "file-arrow-up",
"file-audio": "file-audio",
"file-csv": "file-csv",
"file-image": "file-image",
"file-lines": "file-text",
"file-signature": "file-text",
"file-video": "file-video",
film: "film-strip",
filter: "funnel",
"filter-circle-xmark": "funnel-x",
fingerprint: "fingerprint",
flag: "flag",
flask: "flask",
"floppy-disk": "floppy-disk",
folder: "folder",
"folder-open": "folder-open",
font: "text-aa",
forward: "fast-forward",
"forward-fast": "skip-forward",
"forward-step": "skip-forward",
gavel: "gavel",
gear: "gear",
gift: "gift",
globe: "globe",
"graduation-cap": "graduation-cap",
"grip-lines": "rows",
"grip-vertical": "dots-six-vertical",
hand: "hand",
"hand-point-right": "hand-pointing",
handshake: "handshake",
"handshake-angle": "handshake",
hashtag: "hash",
headset: "headset",
heart: "heart",
history: "clock-counter-clockwise",
"hourglass-start": "hourglass-high",
house: "house",
"id-card": "identification-card",
image: "image",
images: "images",
inbox: "tray",
info: "info",
italic: "text-italic",
key: "key",
keyboard: "keyboard",
language: "translate",
"laptop-code": "laptop",
"layer-group": "stack",
"left-right": "arrows-horizontal",
link: "link-simple-horizontal",
"link-slash": "link-break",
list: "list",
"list-check": "list-checks",
"list-ol": "list-numbers",
"list-ul": "list",
"location-dot": "map-pin",
"location-pin": "map-pin",
lock: "lock",
"magnifying-glass": "magnifying-glass",
"magnifying-glass-minus": "magnifying-glass-minus",
"magnifying-glass-plus": "magnifying-glass-plus",
medal: "medal",
"microphone-slash": "microphone-slash",
minus: "minus",
"mobile-screen-button": "device-mobile",
moon: "moon",
"nested-thread": "tree-view",
"notification.assigned": "user-plus",
"notification.bookmark_reminder": "clock",
"notification.chat_quoted": "quotes",
"notification.edited": "pencil",
"notification.granted_badge": "seal",
"notification.group_mentioned": "users",
"notification.group_message_summary": "users",
"notification.invited_to_private_message": "envelope",
"notification.invited_to_topic": "arrow-right",
"notification.invitee_accepted": "user",
"notification.liked": "heart",
"notification.liked_2": "heart",
"notification.liked_consolidated": "heart",
"notification.liked_many": "heart",
"notification.linked": "link-simple-horizontal",
"notification.mentioned": "at",
"notification.moved_post": "arrow-square-out",
"notification.post_approved": "check",
"notification.posted": "arrow-arc-left",
"notification.private_message": "envelope",
"notification.quoted": "quotes",
"notification.reaction": "bell",
"notification.replied": "arrow-arc-left",
"notification.topic_reminder": "clock",
"notification.votes_released": "plus-circle",
"notification.watching_first_post": "bell",
paintbrush: "paint-brush",
palette: "palette",
"paper-plane": "paper-plane-tilt",
"patreon-new": "patreon-logo",
pause: "pause",
pen: "pen",
"pen-to-square": "pencil",
pencil: "pencil",
"pencil-alt": "pencil-simple",
play: "play",
plug: "plug",
plus: "plus",
"power-off": "power",
"puzzle-piece": "puzzle-piece",
question: "question",
"quote-left": "quotes",
"quote-right": "quotes",
repeat: "repeat",
reply: "arrow-arc-left",
"right-from-bracket": "sign-out",
"right-left": "arrows-left-right",
"right-to-bracket": "sign-in",
robot: "robot",
rocket: "rocket",
rotate: "arrow-clockwise",
rss: "rss",
save: "floppy-disk",
"screwdriver-wrench": "toolbox",
scroll: "scroll",
share: "share",
"share-nodes": "share-network",
"shield-halved": "shield",
shuffle: "shuffle",
"sign-hanging": "signpost",
signal: "cell-signal-full",
sliders: "sliders-horizontal",
sort: "arrows-down-up",
"sort-alpha-down": "sort-ascending",
"sort-alpha-up": "sort-descending",
"sort-numeric-down": "sort-ascending",
"sort-numeric-up": "sort-descending",
spinner: "spinner",
"square-check": "check-square",
"square-envelope": "envelope-simple",
"square-full": "square",
"square-plus": "plus-square",
"square-root-variable": "math-operations",
stamp: "stamp",
star: "star",
"sticky-note": "note",
sun: "sun",
table: "table",
"table-cells": "grid-four",
"table-columns": "columns",
tag: "tag",
tags: "tag",
"temperature-three-quarters": "thermometer",
"thumbs-down": "thumbs-down",
"thumbs-up": "thumbs-up",
thumbtack: "push-pin-simple",
"ticket-simple": "ticket",
"toggle-off": "toggle-left",
"toggle-on": "toggle-right",
translate: "translate",
"trash-can": "trash",
"triangle-exclamation": "warning",
trophy: "trophy",
"truck-medical": "ambulance",
unlock: "lock-open",
"unlock-keyhole": "lock-key-open",
"up-down": "arrows-vertical",
"up-right-from-square": "arrow-square-out",
upload: "upload",
user: "user",
"user-check": "user-circle-check",
"user-gear": "user-gear",
"user-group": "users",
"user-pen": "user-gear",
"user-plus": "user-plus",
"user-secret": "detective",
"user-shield": "user-circle-check",
"user-xmark": "user-minus",
users: "users",
video: "video-camera",
"volume-high": "speaker-high",
"volume-xmark": "speaker-x",
"vote-up": "arrow-fat-up",
"vote-up-filled": "arrow-fat-up",
"wand-magic": "magic-wand",
"wand-magic-sparkles": "magic-wand",
wrench: "wrench",
xmark: "x",
};
// FA icons that must render filled regardless of the configured weight:
// solid shapes (status dots, swatches) and "active state" indicators whose
// outline sibling conveys the inactive state. Pinned to the `fill` weight.
export const FORCE_FILL = [
"circle",
"square-full",
"bookmark",
"heart",
"star",
"thumbs-up",
"thumbs-down",
"square-check",
"circle-check",
"check-square",
"d-liked",
"vote-up-filled",
];
@@ -0,0 +1,14 @@
weight:
default: regular
type: enum
refresh: true
choices:
- light
- regular
- bold
- duotone
ignored_icons:
default: ""
type: list
list_type: compact
refresh: true
@@ -0,0 +1,57 @@
{
"id": 40,
"name": "Discourse Phosphor Icons",
"user_selectable": false,
"color_scheme": null,
"fields_count": 6,
"files": [
{
"field_id": 759,
"target_id": 0,
"target_name": "common",
"name": "icons-sprite",
"filename": "common_icons-sprite.txt",
"bytes": 0
},
{
"field_id": 764,
"target_id": 3,
"target_name": "settings",
"name": "yaml",
"filename": "settings_yaml.yml",
"bytes": 197
},
{
"field_id": 763,
"target_id": 4,
"target_name": "translations",
"name": "en",
"filename": "translations_en.yml",
"bytes": 313
},
{
"field_id": 761,
"target_id": 6,
"target_name": "javascript",
"name": "discourse/api-initializers/phosphor-icons.js",
"filename": "javascript_discourse_api-initializers_phosphor-icons.js",
"bytes": 703
},
{
"field_id": 762,
"target_id": 6,
"target_name": "javascript",
"name": "discourse/lib/icon-map.js",
"filename": "javascript_discourse_lib_icon-map.js",
"bytes": 12790
},
{
"field_id": 760,
"target_id": 9,
"target_name": "about",
"name": "about",
"filename": "about_about.yml",
"bytes": 313
}
]
}
@@ -0,0 +1,6 @@
en:
theme_metadata:
description: "Phosphor icons for Discourse"
settings:
weight: "Which Phosphor icon weight to use. Changing this swaps every replaced icon to the selected style."
ignored_icons: "The icons in this list will use the default Font Awesome icon instead of the Phosphor icon."