Skip to content

Commit 18b5ed4

Browse files
committed
feat: Convert HTML to Markdown on copy for markdown blockquotes
Add turndown library for converting html to markdown. Add options to turndown for atx style headings and emDelimiter as *
1 parent 15ea510 commit 18b5ed4

3 files changed

Lines changed: 43 additions & 2 deletions

File tree

package-lock.json

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"react-router-dom": "^6.30.0",
2828
"react-use": "^17.6.0",
2929
"strip-ansi": "^7.1.0",
30+
"turndown": "^7.2.0",
3031
"vite-plugin-commit-hash": "^1.0.8",
3132
"web-vitals": "^3.5.2"
3233
},
@@ -54,6 +55,7 @@
5455
"@types/react": "^18.3.20",
5556
"@types/react-beforeunload": "^2.1.5",
5657
"@types/react-dom": "^18.3.6",
58+
"@types/turndown": "^5.0.5",
5759
"@vitejs/plugin-react": "^4.3.4",
5860
"cross-env": "^7.0.3",
5961
"jsdom": "^26.0.0",

src/components/output.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import MudClient from "../client";
66
import ReactDOMServer from "react-dom/server";
77
import DOMPurify from 'dompurify';
88
import { setInputText } from '../InputStore';
9+
import TurndownService from 'turndown'; // <-- Import TurndownService
910

1011
interface Props {
1112
client: MudClient;
@@ -26,6 +27,8 @@ class Output extends React.Component<Props, State> {
2627
static MAX_OUTPUT_LENGTH = 7500; // Maximum number of messages to display in the output
2728
static LOCAL_STORAGE_KEY = "outputLog"; // Key for saving output in LocalStorage
2829
messageKey: number = 0;
30+
// Add a TurndownService instance (can be reused)
31+
turndownService = new TurndownService({headingStyle: 'atx', emDelimiter: '*'});
2932

3033
constructor(props: Props) {
3134
super(props);
@@ -258,8 +261,20 @@ scrollToBottom = () => { const output = this.outputRef.current; if (output) {
258261
if (buttonInClone) {
259262
buttonInClone.remove();
260263
}
261-
// Get text content from the clone, which now excludes the button text
262-
const textToCopy = clonedBlockquote.textContent || '';
264+
265+
let textToCopy: string;
266+
const contentType = blockquote.dataset.contentType; // Check for data-content-type
267+
268+
// Check if the content type is markdown
269+
if (contentType === 'text/markdown') {
270+
// Get the inner HTML of the clone (without the button)
271+
const htmlContent = clonedBlockquote.innerHTML;
272+
// Convert HTML to Markdown using Turndown
273+
textToCopy = this.turndownService.turndown(htmlContent);
274+
} else {
275+
// Default behavior: Get text content from the clone
276+
textToCopy = clonedBlockquote.textContent || '';
277+
}
263278

264279
navigator.clipboard.writeText(textToCopy.trim())
265280
.then(() => {

0 commit comments

Comments
 (0)