diff --git a/frontend/src/postBodyDisplay.test.ts b/frontend/src/postBodyDisplay.test.ts
index 743739697..d757a77b0 100644
--- a/frontend/src/postBodyDisplay.test.ts
+++ b/frontend/src/postBodyDisplay.test.ts
@@ -61,6 +61,28 @@ describe("splitPostBody", () => {
]);
});
+ it("preserves nested HTML list depth as semantic indentation", () => {
+ expect(
+ splitPostBody("
- Parent
- Child
- Sibling
"),
+ ).toEqual([
+ { kind: "text", text: "Parent" },
+ { kind: "text", text: "Child", indentLevel: 1 },
+ { kind: "text", text: "Sibling" },
+ ]);
+ });
+
+ it("preserves nested list depth when item text is wrapped in a block child", () => {
+ expect(
+ splitPostBody(
+ "Parent
Child
Sibling
",
+ ),
+ ).toEqual([
+ { kind: "text", text: "Parent" },
+ { kind: "text", text: "Child", indentLevel: 1 },
+ { kind: "text", text: "Sibling" },
+ ]);
+ });
+
it("labels HTML, Word, and OOXML footnotes in the fallback renderer", () => {
expect(
splitPostBody(
diff --git a/frontend/src/postBodyDisplay.ts b/frontend/src/postBodyDisplay.ts
index 1f69962e9..5c59470f1 100644
--- a/frontend/src/postBodyDisplay.ts
+++ b/frontend/src/postBodyDisplay.ts
@@ -143,11 +143,20 @@ function indentMarker(width: number): string {
function stripHtmlTags(text: string): string {
text = markFootnoteTags(text).replace(/]*>(.*?)<\/sup>/gi, "^$1");
+ let listDepth = 0;
const withBoundaries = text
.replace(BREAK_TAG, "\n")
.replace(BLOCK_TAG, (tag) => {
- if (/^<\//.test(tag)) return "\n\n";
- return `\n\n${indentMarker(declaredIndentWidth(tag))}`;
+ const name = tag.match(/^<\/?\s*([a-z0-9:]+)/i)?.[1]?.toLowerCase() ?? "";
+ const closing = /^<\//.test(tag);
+ if (name === "ul" || name === "ol") {
+ if (closing) listDepth = Math.max(0, listDepth - 1);
+ else listDepth += 1;
+ return "\n\n";
+ }
+ if (closing) return "\n\n";
+ const nestedListIndent = !closing && listDepth > 0 ? Math.max(0, listDepth - 1) * 4 : 0;
+ return `\n\n${indentMarker(declaredIndentWidth(tag) + nestedListIndent)}`;
})
.replace(WORD_INDENT_TAG, (tag) => indentMarker(declaredIndentWidth(tag)));
const withoutTags = withBoundaries.replace(HTML_TAG, (tag) => {