feat(quick-260329-ton): replace textContent with innerHTML + renderInlineMarkdown at all AI-text insertion points
- src/app.ts: greeting text now renders inline markdown - src/ui/screens.ts: letter intro text now renders inline markdown - src/forest/reward.ts: forest comment now renders inline markdown - All 3 sites use innerHTML with XSS-safe renderInlineMarkdown
This commit is contained in:
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
import { speakText } from "./audio/speech";
|
import { speakText } from "./audio/speech";
|
||||||
import { companions } from "./companion/characters";
|
import { companions } from "./companion/characters";
|
||||||
import { getGreeting } from "./companion/companion";
|
import { getGreeting } from "./companion/companion";
|
||||||
|
import { renderInlineMarkdown } from "./utils/markdown";
|
||||||
import { initRewardScreen, startPreGeneration } from "./forest/reward";
|
import { initRewardScreen, startPreGeneration } from "./forest/reward";
|
||||||
import { initForestScreen, renderForestScene } from "./forest/scene";
|
import { initForestScreen, renderForestScene } from "./forest/scene";
|
||||||
import { getProgress, openDB, saveProgress } from "./storage/db";
|
import { getProgress, openDB, saveProgress } from "./storage/db";
|
||||||
@@ -224,7 +225,7 @@ export async function initApp(): Promise<void> {
|
|||||||
|
|
||||||
// Fetch greeting async (shows immediately with avatar, text fills in)
|
// Fetch greeting async (shows immediately with avatar, text fills in)
|
||||||
getGreeting(progress.selectedCharacter, db).then((text) => {
|
getGreeting(progress.selectedCharacter, db).then((text) => {
|
||||||
textEl.textContent = text;
|
textEl.innerHTML = renderInlineMarkdown(text);
|
||||||
speakText(text);
|
speakText(text);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { getRandomFallbackForestComment } from "../companion/fallbacks";
|
|||||||
import type { CompanionType, ForestElement } from "../types";
|
import type { CompanionType, ForestElement } from "../types";
|
||||||
import { playRewardSound } from "../audio/sounds";
|
import { playRewardSound } from "../audio/sounds";
|
||||||
import { speakText } from "../audio/speech";
|
import { speakText } from "../audio/speech";
|
||||||
|
import { renderInlineMarkdown } from "../utils/markdown";
|
||||||
|
|
||||||
// --- Element types for random selection ---
|
// --- Element types for random selection ---
|
||||||
|
|
||||||
@@ -204,7 +205,7 @@ export async function initRewardScreen(
|
|||||||
playRewardSound();
|
playRewardSound();
|
||||||
|
|
||||||
// 7. Show companion comment + speak it aloud
|
// 7. Show companion comment + speak it aloud
|
||||||
companionTextEl.textContent = comment;
|
companionTextEl.innerHTML = renderInlineMarkdown(comment);
|
||||||
speakText(comment);
|
speakText(comment);
|
||||||
|
|
||||||
// 8. Wire buttons
|
// 8. Wire buttons
|
||||||
|
|||||||
+2
-1
@@ -20,6 +20,7 @@ import { getLevelByNumber } from "../game/levels";
|
|||||||
import { getLetterIntro } from "../companion/companion";
|
import { getLetterIntro } from "../companion/companion";
|
||||||
import { getWordsForLevel } from "../game/words";
|
import { getWordsForLevel } from "../game/words";
|
||||||
import { playCorrectSound } from "../audio/sounds";
|
import { playCorrectSound } from "../audio/sounds";
|
||||||
|
import { renderInlineMarkdown } from "../utils/markdown";
|
||||||
|
|
||||||
export function initWelcomeScreen(
|
export function initWelcomeScreen(
|
||||||
db: IDBDatabase,
|
db: IDBDatabase,
|
||||||
@@ -419,7 +420,7 @@ export function initLessonScreen(
|
|||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
|
|
||||||
// Show companion intro text
|
// Show companion intro text
|
||||||
companionText.textContent = introText;
|
companionText.innerHTML = renderInlineMarkdown(introText);
|
||||||
companionArea.style.display = "flex";
|
companionArea.style.display = "flex";
|
||||||
|
|
||||||
// Show the letter
|
// Show the letter
|
||||||
|
|||||||
Reference in New Issue
Block a user