Skip to content

Commit

Permalink
feat: support markdown export
Browse files Browse the repository at this point in the history
  • Loading branch information
pionxzh committed Dec 28, 2022
1 parent 69c2066 commit 306ed2b
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 22 deletions.
8 changes: 2 additions & 6 deletions packages/userscript/src/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,8 @@ export const fileCode = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 38
// source: fontawesome: file-image
export const iconCamera = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="w-4 h-4" fill="currentColor"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M149.1 64.8L138.7 96H64C28.7 96 0 124.7 0 160V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H373.3L362.9 64.8C356.4 45.2 338.1 32 317.4 32H194.6c-20.7 0-39 13.2-45.5 32.8zM256 384c-53 0-96-43-96-96s43-96 96-96s96 43 96 96s-43 96-96 96z"/></svg>'

// source: ChatGPT generated
// export const fileGif = `
// <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="w-4 h-4" fill="currentColor">
// <rect x="10" y="10" width="80" height="80" fill="#EFEFEF" />
// <text x="50" y="60" font-size="40" text-anchor="middle">GIF</text>
// </svg>`
// source: fontawesome: markdown
export const iconMarkdown = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" class="w-4 h-4" fill="currentColor"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M593.8 59.1H46.2C20.7 59.1 0 79.8 0 105.2v301.5c0 25.5 20.7 46.2 46.2 46.2h547.7c25.5 0 46.2-20.7 46.1-46.1V105.2c0-25.4-20.7-46.1-46.2-46.1zM338.5 360.6H277v-120l-61.5 76.9-61.5-76.9v120H92.3V151.4h61.5l61.5 76.9 61.5-76.9h61.5v209.2zm135.3 3.1L381.5 256H443V151.4h61.5V256H566z"/></svg>'

// source: fontawesome: copy
export const iconCopy = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="w-4 h-4" fill="currentColor"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg>'
Expand Down
51 changes: 35 additions & 16 deletions packages/userscript/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import html2canvas from 'html2canvas'
import sentinel from 'sentinel-js'
import { chatGPTAvatarSVG, fileCode, iconCamera, iconCopy } from './icons'
import { chatGPTAvatarSVG, fileCode, iconCamera, iconCopy, iconMarkdown } from './icons'
import { copyToClipboard, downloadFile, downloadUrl, escapeHtml, getBase64FromImg, onloadSafe, sleep, timestamp } from './utils'
import templateHtml from './template.html?raw'

Expand Down Expand Up @@ -52,9 +52,10 @@ function main() {
const divider = createDivider()
const textExport = createMenuItem(iconCopy, 'Copy Text', onCopyText)
const pngExport = createMenuItem(iconCamera, 'Screenshot', exportToPng)
const mdExport = createMenuItem(iconMarkdown, 'Export Markdown', exportToMarkdown)
const htmlExport = createMenuItem(fileCode, 'Export WebPage', exportToHtml)
const container = createMenuContainer()
container.append(textExport, pngExport, htmlExport, divider)
container.append(textExport, pngExport, mdExport, htmlExport, divider)
})
}

Expand Down Expand Up @@ -102,6 +103,14 @@ function createMenuItem(icon: string, title: string, onClick: (e: MouseEvent) =>
return menuItem
}

function exportToMarkdown() {
const items = getConversation()
if (items.length === 0) return alert('No conversation found. Please send a message first.')

const text = conversationToMarkdown(items)
downloadFile(`chatgpt-${timestamp()}.md`, 'text/markdown', text)
}

function exportToHtml() {
const items = getConversation()
if (items.length === 0) return alert('No conversation found. Please send a message first.')
Expand Down Expand Up @@ -287,20 +296,30 @@ function parseTextNode(textNode: HTMLDivElement): ConversationLine[] {
function conversationToText(conversation: Conversation[]) {
return conversation.map((item) => {
const { author: { name }, lines } = item
const text = lines.map((line) => {
return line.map((item) => {
switch (item.type) {
case 'text': return item.text
case 'image': return '[image]'
case 'link': return `[${item.text}](${item.href})`
case 'ordered-list-item': return item.items.map((item, index) => `${index + 1}. ${item}`).join('\r\n')
case 'unordered-list-item': return item.items.map(item => `- ${item}`).join('\r\n')
case 'code': return `\`${item.code}\``
case 'code-block': return `\`\`\`${item.lang}\r\n${item.code}\`\`\``
default: return ''
}
}).join('')
}).join('\r\n\r\n')
const text = lines.map(line => lineToText(line)).join('\r\n\r\n')
return `${name}:\r\n${text}`
}).join('\r\n\r\n')
}

function conversationToMarkdown(conversation: Conversation[]) {
return conversation.map((item) => {
const { author: { name }, lines } = item
const text = lines.map(line => lineToText(line)).join('\r\n\r\n')
return `#### ${name}:\r\n${text}`
}).join('\r\n\r\n')
}

function lineToText(line: ConversationLine): string {
return line.map((item) => {
switch (item.type) {
case 'text': return item.text
case 'image': return '[image]'
case 'link': return `[${item.text}](${item.href})`
case 'ordered-list-item': return item.items.map((item, index) => `${index + 1}. ${item}`).join('\r\n')
case 'unordered-list-item': return item.items.map(item => `- ${item}`).join('\r\n')
case 'code': return `\`${item.code}\``
case 'code-block': return `\`\`\`${item.lang}\r\n${item.code}\`\`\``
default: return ''
}
}).join('')
}

1 comment on commit 306ed2b

@Notarin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @pionxzh , Very cool.

Please sign in to comment.