import { assetUrl } from "@openfront/shared/AssetUrls";
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
interface IconFile {
file: string;
/** Drawn as an
to keep its colours; other icons take currentColor. */
multicolor?: boolean;
/** A 4:5 file whose art is its top square. */
crop?: boolean;
}
export const OF_ICONS = {
close: { file: "XIcon.svg", crop: true },
back: { file: "BackIconWhite.svg" },
check: { file: "CheckIconWhite.svg" },
"chevron-right": { file: "ChevronRightIconWhite.svg" },
plus: { file: "PlusIconWhite.svg" },
hourglass: { file: "HourglassIconWhite.svg" },
settings: { file: "SettingIconWhite.svg" },
graphics: { file: "MonitorIconWhite.svg" },
terrain: { file: "TreeIconWhite.svg" },
debug: { file: "BugIconWhite.svg" },
save: { file: "SaveIconWhite.svg" },
exit: { file: "ExitIconWhite.svg" },
share: { file: "ShareIconWhite.svg" },
land: { file: "ClaimIcon.svg" },
leaderboard: { file: "LeaderboardIconSolidWhite.svg" },
team: { file: "TeamIconSolidWhite.svg" },
gold: { file: "GoldCoinIcon.svg", multicolor: true },
troops: { file: "SoldierIcon.svg" },
traitor: { file: "TraitorIcon.svg" },
trade: { file: "TradingIconWhite.svg" },
embargo: { file: "StopIconWhite.svg" },
alliance: { file: "AllianceIconWhite.svg" },
"break-alliance": { file: "TraitorIconWhite.svg" },
chat: { file: "ChatIconWhite.svg" },
emoji: { file: "EmojiIconWhite.svg" },
target: { file: "TargetIconWhite.svg" },
"donate-troops": { file: "DonateTroopIconWhite.svg" },
"donate-gold": { file: "DonateGoldIconWhite.svg" },
report: { file: "SirenIconWhite.svg" },
shield: { file: "ShieldIconWhite.svg" },
nation: { file: "CityIconWhite.svg" },
tribe: { file: "SwordIconWhite.svg" },
swap: { file: "SwapIconWhite.svg" },
sword: { file: "SwordIconWhite.svg" },
max: { file: "UpperLimitIcon.svg" },
info: { file: "InfoIconRegularWhite.svg" },
warning: { file: "WarningIconWhite.svg" },
lock: { file: "LockIconWhite.svg" },
city: { file: "CityIconWhite.svg" },
factory: { file: "FactoryIconWhite.svg" },
port: { file: "PortIcon.svg" },
"missile-silo": { file: "MissileSiloIconWhite.svg" },
"sam-launcher": { file: "SamLauncherIconWhite.svg" },
warship: { file: "BattleshipIconWhite.svg" },
"atom-bomb": { file: "NukeIconWhite.svg" },
"hydrogen-bomb": { file: "MushroomCloudIconWhite.svg", crop: true },
mirv: { file: "MIRVIcon.svg" },
} as const satisfies Record;
export type OfIconName = keyof typeof OF_ICONS;
/**
* One of the game's icons, painted in the current text colour. Decorative
* only: the control around it carries the accessible name.
*/
@customElement("of-icon")
export class OfIcon extends LitElement {
@property()
name!: OfIconName;
@property({ type: Number })
size: number = 16;
createRenderRoot() {
return this;
}
render() {
const icon: IconFile | undefined = OF_ICONS[this.name];
if (icon === undefined) {
return html``;
}
const src = assetUrl(`images/${icon.file}`);
if (icon.multicolor) {
return html`
`;
}
// The mask uses the file's alpha, so its fill colour does not matter. A
// cropped file is sized to the box's width, so what is under its top
// square falls below the box.
const mask = `url('${src}') ${icon.crop ? "top / 100% 125%" : "center / contain"} no-repeat`;
return html``;
}
}