diff --git a/src/components/Layout/LayoutStyles.js b/src/components/Layout/LayoutStyles.js
index 597caf24..32be2483 100644
--- a/src/components/Layout/LayoutStyles.js
+++ b/src/components/Layout/LayoutStyles.js
@@ -57,15 +57,9 @@ const standardLayout = css`
}
details {
- margin-bottom: 1rem;
-
& summary {
cursor: pointer;
}
-
- &:last-of-type {
- margin-bottom: 2rem;
- }
}
blockquote {
diff --git a/src/components/Layout/MainStyles.js b/src/components/Layout/MainStyles.js
index 384c6dbc..b27db7fa 100644
--- a/src/components/Layout/MainStyles.js
+++ b/src/components/Layout/MainStyles.js
@@ -62,14 +62,11 @@ html body {
}
ul, ol {
- padding-left: 3rem;
-
+ padding-left: 1.5rem;
+ padding-top: 0.5rem;
li {
margin-bottom: 0.5rem;
}
- li:first-of-type {
- margin-top: 0.5rem;
- }
}
h1, h2, h3, h4, h5, h6 {
@@ -136,5 +133,9 @@ html body {
text-decoration: underline;
}
}
+
+ summary::before {
+ margin-right: 0.5rem;
+ }
}
`;
diff --git a/src/components/Layout/MarkdownStyles.js b/src/components/Layout/MarkdownStyles.js
index a667f893..1a833471 100644
--- a/src/components/Layout/MarkdownStyles.js
+++ b/src/components/Layout/MarkdownStyles.js
@@ -29,10 +29,37 @@ export const MarkdownStyles = createGlobalStyle`
text-decoration: underline;
}
}
+ code {
+ font-size: 80%;
+ }
a, code, strong {
white-space: pre-wrap;
word-break: break-word;
word-wrap: break-word;
}
+ li > details {
+ display: block;
+ }
+ summary {
+ cursor: pointer;
+ user-select: none;
+ list-style: none;
+ display: block;
+ &::marker,
+ &::-webkit-details-marker {
+ display: none;
+ }
+ &::before {
+ content: '▶ ';
+ display: inline;
+ font-size: 0.75em;
+ transition: transform 0.15s ease;
+ display: inline-block;
+ width: 1em;
+ }
+ }
+ details[open] > summary::before {
+ transform: rotate(90deg);
+ }
}
`;
diff --git a/src/helpers/rehypeWrapFirstList.ts b/src/helpers/rehypeWrapFirstList.ts
new file mode 100644
index 00000000..fcb5a532
--- /dev/null
+++ b/src/helpers/rehypeWrapFirstList.ts
@@ -0,0 +1,57 @@
+import { visit } from "unist-util-visit";
+import type { Root, Element, ElementContent } from "hast";
+
+/**
+ * Rehype plugin that makes nested list items individually collapsible.
+ * For each
that contains a nested , wraps the content in
+ * to enable collapse/expand functionality.
+ */
+export default function rehypeWrapFirstList() {
+ return (tree: Root) => {
+ visit(tree, "element", (node) => {
+ // Only process - elements
+ if (node.tagName !== "li") {
+ return;
+ }
+
+ // Check if this
- has a nested
child
+ const nestedUlIndex = node.children.findIndex(
+ (child): child is Element =>
+ child.type === "element" && child.tagName === "ul",
+ );
+
+ // If no nested , nothing to do
+ if (nestedUlIndex === -1) {
+ return;
+ }
+
+ // Split children into summary content (before ul) and nested ul
+ const summaryContent = node.children.slice(0, nestedUlIndex);
+ const nestedUl = node.children[nestedUlIndex] as Element;
+
+ // Only wrap if there's content to put in the summary
+ if (summaryContent.length === 0) {
+ return;
+ }
+
+ // Create the summary element with the content before the nested ul
+ const summary: Element = {
+ type: "element",
+ tagName: "summary",
+ properties: {},
+ children: summaryContent as ElementContent[],
+ };
+
+ // Create the details element
+ const details: Element = {
+ type: "element",
+ tagName: "details",
+ properties: { open: true }, // Open by default
+ children: [summary, nestedUl],
+ };
+
+ // Replace the - 's children with just the details element
+ node.children = [details];
+ });
+ };
+}
diff --git a/src/helpers/retrieveMdPages.ts b/src/helpers/retrieveMdPages.ts
index 4a45dec3..6cf905fe 100644
--- a/src/helpers/retrieveMdPages.ts
+++ b/src/helpers/retrieveMdPages.ts
@@ -10,6 +10,7 @@ import rehypeStringify from "rehype-stringify";
import rehypeSlug from "rehype-slug";
import remarkHeadings, { hasHeadingsData } from "@vcarl/remark-headings";
import { toString } from "mdast-util-to-string";
+import rehypeWrapFirstList from "./rehypeWrapFirstList";
const loadMd = async (path: string) => {
const fullPath = join(process.cwd(), `${path}.md`);
@@ -39,8 +40,26 @@ const remarkHtmlProcessor = unified()
.use(rehypeSlug)
.use(rehypeStringify, { allowDangerousHtml: true });
-export const processMd = (mdSource: string) => {
- const vfile = remarkHtmlProcessor.processSync(mdSource);
+export interface ProcessMdOptions {
+ wrapFirstList?: boolean;
+}
+
+export const processMd = (mdSource: string, options?: ProcessMdOptions) => {
+ let processor = remarkHtmlProcessor;
+
+ // If wrapFirstList is enabled, add the rehype plugin
+ if (options?.wrapFirstList) {
+ processor = unified()
+ .use(parse)
+ .use(remarkGfm)
+ .use(remarkHeadings as ReturnType["use"]>)
+ .use(remarkRehype, { allowDangerousHtml: true })
+ .use(rehypeSlug)
+ .use(rehypeWrapFirstList)
+ .use(rehypeStringify, { allowDangerousHtml: true });
+ }
+
+ const vfile = processor.processSync(mdSource);
if (hasHeadingsData(vfile.data)) {
return { html: vfile.toString(), headings: vfile.data.headings };
}
diff --git a/src/pages/transcripts/[slug].tsx b/src/pages/transcripts/[slug].tsx
index e9d4dbaf..8cb665e2 100644
--- a/src/pages/transcripts/[slug].tsx
+++ b/src/pages/transcripts/[slug].tsx
@@ -88,7 +88,7 @@ export const getStaticProps = async ({
props: {
all,
...pick(["title", "date"], doc),
- html: processMd(doc.content).html,
+ html: processMd(doc.content, { wrapFirstList: true }).html,
description: processMdPlaintext(doc.description).html,
},
};