Complete GFM support: tables, task lists, strikethrough
Editor: add tablePlugin so markdown tables round-trip and render. Task lists (`- [ ]`), strikethrough, code (inline + fenced), headings, lists, quotes, and links already work via listsPlugin/core/markdownShortcut. CSS: suppress the disc bullet on task-list items (they draw their own checkbox) and style tables. Display: render task-list checkboxes (no stray bullet), GFM tables, and strikethrough so the read view matches what the editor produces. https://claude.ai/code/session_019DU6V5z6Nr4Vu7b1fBDnq4
This commit is contained in:
@@ -108,6 +108,10 @@
|
|||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
line-height: 1.625;
|
line-height: 1.625;
|
||||||
}
|
}
|
||||||
|
/* Task-list items draw their own checkbox — no disc bullet. */
|
||||||
|
.llink-mdx-content li[class*="_listItem"] {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Blockquote */
|
/* Blockquote */
|
||||||
.llink-mdx-content blockquote {
|
.llink-mdx-content blockquote {
|
||||||
@@ -132,3 +136,20 @@
|
|||||||
border: none;
|
border: none;
|
||||||
border-top: 1px solid rgb(255 255 255 / 0.1);
|
border-top: 1px solid rgb(255 255 255 / 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tables */
|
||||||
|
.llink-mdx-content table {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.llink-mdx-content th,
|
||||||
|
.llink-mdx-content td {
|
||||||
|
border: 1px solid rgb(255 255 255 / 0.2);
|
||||||
|
padding: 0.375rem 0.625rem;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.llink-mdx-content th {
|
||||||
|
background: rgb(255 255 255 / 0.08);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
linkPlugin,
|
linkPlugin,
|
||||||
codeBlockPlugin,
|
codeBlockPlugin,
|
||||||
codeMirrorPlugin,
|
codeMirrorPlugin,
|
||||||
|
tablePlugin,
|
||||||
markdownShortcutPlugin,
|
markdownShortcutPlugin,
|
||||||
} from "@mdxeditor/editor";
|
} from "@mdxeditor/editor";
|
||||||
import "@mdxeditor/editor/style.css";
|
import "@mdxeditor/editor/style.css";
|
||||||
@@ -90,6 +91,10 @@ export function MarkdownEditor({
|
|||||||
linkPlugin({ disableAutoLink: true }),
|
linkPlugin({ disableAutoLink: true }),
|
||||||
codeBlockPlugin({ defaultCodeBlockLanguage: "" }),
|
codeBlockPlugin({ defaultCodeBlockLanguage: "" }),
|
||||||
codeMirrorPlugin({ codeBlockLanguages: CODE_BLOCK_LANGUAGES }),
|
codeMirrorPlugin({ codeBlockLanguages: CODE_BLOCK_LANGUAGES }),
|
||||||
|
tablePlugin(),
|
||||||
|
// Headings, lists (incl. `- [ ]` task lists), emphasis, strikethrough,
|
||||||
|
// inline code, quotes, and links all transform as you type via these
|
||||||
|
// shortcuts; fenced code blocks and tables are inserted via paste/import.
|
||||||
markdownShortcutPlugin(),
|
markdownShortcutPlugin(),
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -95,14 +95,55 @@ const markdownComponents: React.ComponentProps<typeof ReactMarkdown>["components
|
|||||||
{children}
|
{children}
|
||||||
</pre>
|
</pre>
|
||||||
),
|
),
|
||||||
ul: ({ children }) => <ul className="mb-3 list-disc pl-5 text-white last:mb-0">{children}</ul>,
|
del: ({ children }) => <del className="text-white/70 line-through">{children}</del>,
|
||||||
|
ul: ({ className, children }) => (
|
||||||
|
<ul
|
||||||
|
className={cn(
|
||||||
|
"mb-3 text-white last:mb-0",
|
||||||
|
className?.includes("contains-task-list") ? "list-none pl-0" : "list-disc pl-5",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ul>
|
||||||
|
),
|
||||||
ol: ({ children }) => <ol className="mb-3 list-decimal pl-5 text-white last:mb-0">{children}</ol>,
|
ol: ({ children }) => <ol className="mb-3 list-decimal pl-5 text-white last:mb-0">{children}</ol>,
|
||||||
li: ({ children }) => <li className="mb-1 leading-relaxed">{children}</li>,
|
li: ({ className, children }) => (
|
||||||
|
<li
|
||||||
|
className={cn(
|
||||||
|
"mb-1 leading-relaxed",
|
||||||
|
className?.includes("task-list-item") && "flex list-none items-start gap-2",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</li>
|
||||||
|
),
|
||||||
|
input: ({ type, checked }) =>
|
||||||
|
type === "checkbox" ? (
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={!!checked}
|
||||||
|
readOnly
|
||||||
|
className="mt-1.5 size-3.5 shrink-0 accent-blue-500"
|
||||||
|
/>
|
||||||
|
) : null,
|
||||||
blockquote: ({ children }) => (
|
blockquote: ({ children }) => (
|
||||||
<blockquote className="mb-3 border-l-2 border-white/30 pl-4 italic text-white/70 last:mb-0">
|
<blockquote className="mb-3 border-l-2 border-white/30 pl-4 italic text-white/70 last:mb-0">
|
||||||
{children}
|
{children}
|
||||||
</blockquote>
|
</blockquote>
|
||||||
),
|
),
|
||||||
|
table: ({ children }) => (
|
||||||
|
<div className="mb-3 overflow-x-auto last:mb-0">
|
||||||
|
<table className="w-auto border-collapse text-sm text-white">{children}</table>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
th: ({ children }) => (
|
||||||
|
<th className="border border-white/20 bg-white/10 px-2.5 py-1.5 text-left font-semibold">
|
||||||
|
{children}
|
||||||
|
</th>
|
||||||
|
),
|
||||||
|
td: ({ children }) => (
|
||||||
|
<td className="border border-white/20 px-2.5 py-1.5">{children}</td>
|
||||||
|
),
|
||||||
hr: () => <hr className="my-4 border-white/10" />,
|
hr: () => <hr className="my-4 border-white/10" />,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user