import * as stylex from "@stylexjs/stylex"; import { createElement, memo } from "react"; import { Link } from "react-router"; import { controlColor } from "./theme.stylex"; import { color, markColor, size } from "./tokens.stylex"; export type UserLinkStyle = "theme" | "plain"; export interface UserNameProps { /** @remarks We use a `string` instead of `api.UserName` because we don't want to pull in API types into the dependencies of this component. */ name: string; /** Undefined means no link. Otherwise, the link style. */ linkStyle?: UserLinkStyle | undefined; /** @remarks We use a `number` instead of `api.UserMark` because we don't want to pull in API types into the dependencies of this component. */ mark?: number; isOp?: boolean; } export default memo(UserName); const styles = stylex.create({ userName: { display: "inline-flex", // Not using size units here, because we want the size to be oriented along the font gap: "0.125em", alignItems: "center", }, plain: { color: color.white900, }, mark: { "::after": { content: "''", // Not using size units here, because we want the size to be oriented along the font of the parent content: "''", width: "0.55em", height: "0.55em", marginLeft: "0.3em", pointerEvents: "none", userSelect: "none", touchAction: "none", maskImage: "var(--mark-shape-default)", maskSize: "contain", maskRepeat: "no-repeat", maskPosition: "center", }, }, op: { "::before": { content: "'OP'", borderRadius: size.px0_5, color: controlColor.buttonPrimaryColor, backgroundColor: controlColor.buttonPrimaryBackground, paddingBlock: 0, paddingInline: size.rem1, fontSize: "60%", pointerEvents: "none", userSelect: "none", touchAction: "none", }, }, }); // Old unicode shapes: // $default-shape: "\25CF"; // SCSS map: // $shapes: ( // "legend": "\25C6", // "special": "\25A7", // "helper": "\2764", // ); const markSpecificStyles = stylex.create({ 0: { // none "::after": { backgroundColor: markColor[0], }, }, 1: { // newfag "::after": { backgroundColor: markColor[1], }, }, 2: { // oldfag "::after": { backgroundColor: markColor[2], }, }, 3: { // admin "::after": { backgroundColor: markColor[3], }, }, 4: { // banned "::after": { backgroundColor: markColor[4], }, }, 5: { // mod "::after": { backgroundColor: markColor[5], }, }, 6: { // superfag "::after": { backgroundColor: markColor[6], }, }, 7: { // legend "::after": { backgroundColor: markColor[7], maskImage: "var(--mark-shape-legend)", }, }, 8: { // special "::after": { backgroundColor: markColor[8], maskImage: "var(--mark-shape-special)", }, }, 9: { // paid "::after": { backgroundColor: markColor[9], }, }, 10: { // mediumfag "::after": { backgroundColor: markColor[10], }, }, 11: { // oldmod "::after": { backgroundColor: markColor[11], }, }, 12: { // helper "::after": { backgroundColor: markColor[12], maskImage: "var(--mark-shape-helper)", }, }, 13: { // bot "::after": { backgroundColor: markColor[13], }, }, 14: { // sysbot "::after": { backgroundColor: markColor[14], }, }, 15: { // oldhelper "::after": { backgroundColor: markColor[15], }, }, 16: { // team-blue "::after": { backgroundColor: markColor[16], }, }, 17: { // team-red "::after": { backgroundColor: markColor[17], }, }, }); function UserName({ name, isOp, linkStyle, mark }: UserNameProps) { const p = stylex.props( styles.userName, isOp && styles.op, typeof mark === "number" && styles.mark, typeof mark === "number" && markSpecificStyles[mark as keyof typeof markSpecificStyles], linkStyle === "plain" && styles.plain, ); return linkStyle === undefined ? ( createElement("span", p, name) ) : ( {name} ); }