improve GUI markup support

This commit is contained in:
Brian Beck 2026-02-19 06:45:15 -08:00
parent 5694f07e1f
commit 94bca6f35c
25 changed files with 59 additions and 36 deletions

View file

@ -3,7 +3,11 @@ import { FaVolumeUp, FaVolumeMute } from "react-icons/fa";
import { useQuery } from "@tanstack/react-query";
import { loadMission, getUrlForPath, RESOURCE_ROOT_URL } from "../loaders";
import { getStandardTextureResourceKey } from "../manifest";
import { GuiMarkup, filterMissionStringByMode } from "../torqueGuiMarkup";
import {
GuiMarkup,
filterMissionStringByMode,
hasGuiMarkup,
} from "../torqueGuiMarkup";
import type * as AST from "../torqueScript/ast";
function useParsedMission(name: string) {
@ -223,16 +227,20 @@ export function MapInfoDialog({
? filterMissionStringByMode(parsedMission.missionString, missionType)
: null;
// Split quote into body text and attribution line
const quoteLines = parsedMission?.missionQuote?.trim().split("\n") ?? [];
// Split quote into body text and attribution line.
// If the quote contains GUI markup tags, render through GuiMarkup instead.
const rawQuote = parsedMission?.missionQuote?.trim() ?? "";
const quoteHasMarkup = hasGuiMarkup(rawQuote);
let quoteText = "";
let quoteAttrib = "";
for (const line of quoteLines) {
const trimmed = line.trim();
if (trimmed.match(/^-+\s/)) {
quoteAttrib = trimmed.replace(/^-+\s*/, "").trim();
} else if (trimmed) {
quoteText += (quoteText ? " " : "") + trimmed;
if (!quoteHasMarkup) {
for (const line of rawQuote.split("\n")) {
const trimmed = line.trim();
if (trimmed.match(/^-+\s/)) {
quoteAttrib = trimmed.replace(/^-+\s*/, "").trim();
} else if (trimmed) {
quoteText += (quoteText ? " " : "") + trimmed;
}
}
}
@ -267,17 +275,25 @@ export function MapInfoDialog({
)}
</div>
{quoteText && (
{quoteHasMarkup ? (
<blockquote className="MapInfoDialog-quote">
<GuiMarkup markup={rawQuote} />
</blockquote>
) : quoteText ? (
<blockquote className="MapInfoDialog-quote">
<p>{quoteText}</p>
{quoteAttrib && <cite> {quoteAttrib}</cite>}
</blockquote>
)}
) : null}
{parsedMission?.missionBlurb && (
<p className="MapInfoDialog-blurb">
{parsedMission.missionBlurb.trim()}
</p>
<div className="MapInfoDialog-blurb">
{hasGuiMarkup(parsedMission.missionBlurb) ? (
<GuiMarkup markup={parsedMission.missionBlurb.trim()} />
) : (
<p>{parsedMission.missionBlurb.trim()}</p>
)}
</div>
)}
{missionString && missionString.trim() && (

View file

@ -225,6 +225,13 @@ function SpanEl({ span }: { span: Span }) {
// Public API
const guiMarkupTagPattern = /<(?:font|color|bitmap|just|lmargin):/i;
/** Whether a string contains Torque GUI markup tags. */
export function hasGuiMarkup(text: string): boolean {
return guiMarkupTagPattern.test(text);
}
/**
* Filter a mission string by game mode prefix, e.g. `[CTF]`, `[DM Bounty]`.
* Lines without a prefix are shown for all modes.