From 191a2dff29b57e56790c76fd2cff0dbfab148bb2 Mon Sep 17 00:00:00 2001
From: DerYokoya <133297414+DerYokoya@users.noreply.github.com>
Date: Fri, 29 May 2026 12:32:35 -0400
Subject: [PATCH 01/11] Korean version
---
_locales/kr/messages.json | 522 ++++++++++++++++++++++++++++++++++++++
popup/popup.html | 1 +
2 files changed, 523 insertions(+)
create mode 100644 _locales/kr/messages.json
diff --git a/_locales/kr/messages.json b/_locales/kr/messages.json
new file mode 100644
index 0000000..37df6d4
--- /dev/null
+++ b/_locales/kr/messages.json
@@ -0,0 +1,522 @@
+{
+ "extensionName": {
+ "message": "DeepShare: AI 채팅 내용을 Word로 내보내기"
+ },
+ "extensionDescription": {
+ "message": "DeepSeek, ChatGPT, Gemini, Grok 등의 AI 채팅 내용을 Word 문서로 내보내고, 수식을 복사하며, DeepSeek 채팅의 긴 스크린샷을 찍을 수 있습니다."
+ },
+ "shareButton": {
+ "message": "대화 공유"
+ },
+ "modalTitle": {
+ "message": "대화 공유"
+ },
+ "imageTab": {
+ "message": "이미지"
+ },
+ "textTab": {
+ "message": "텍스트"
+ },
+ "wordTab": {
+ "message": "Word"
+ },
+ "wordExportInfo": {
+ "message": "다운로드 또는 복사 버튼을 클릭하여 사용자 질문과 AI 응답을 모두 Word 문서로 내보내세요"
+ },
+ "noAiResponses": {
+ "message": "AI 응답이 없습니다"
+ },
+ "downloadButton": {
+ "message": "다운로드"
+ },
+ "copyButton": {
+ "message": "복사"
+ },
+ "docxButton": {
+ "message": "DOCX로 저장"
+ },
+ "docxFeatureExplanation": {
+ "message": "AI를 Word로 변환하는 기능을 설정하세요. 스크린샷 및 수식 복사는 무료로 제공되며 별도의 설정이 필요하지 않습니다."
+ },
+ "docxConversionSuccess": {
+ "message": "Word 문서로 성공적으로 저장되었습니다!"
+ },
+ "docxConverting": {
+ "message": "Word 문서로 저장 중입니다. 창을 닫지 마세요."
+ },
+ "docxConversionError": {
+ "message": "Word 문서로 저장하는 데 실패했습니다. 네트워크 연결을 확인하거나 페이지를 새로 고친 후 다시 시도해 주세요!"
+ },
+ "watermarkSettings": {
+ "message": "워터마크 설정"
+ },
+ "screenshotSettings": {
+ "message": "채팅 스크린샷"
+ },
+ "docxSettings": {
+ "message": "AI 채팅에서 Word로"
+ },
+ "docxServerUrlLabel": {
+ "message": "서버 URL"
+ },
+ "docxApiKeyLabel": {
+ "message": "API 키"
+ },
+ "docxModeLabel": {
+ "message": "변환 모드"
+ },
+ "modeLocalLabel": {
+ "message": "로컬 (Pandoc)"
+ },
+ "modeApiLabel": {
+ "message": "API"
+ },
+ "copied": {
+ "message": "복사됨!"
+ },
+ "copyFailed": {
+ "message": "복사 실패!"
+ },
+ "formulaCopied": {
+ "message": "수식 복사됨!"
+ },
+ "clickToCopyFormula": {
+ "message": "수식을 복사하려면 클릭하세요"
+ },
+ "generatingImage": {
+ "message": "스크린샷 생성 중..."
+ },
+ "generateFailed": {
+ "message": "스크린샷 생성에 실패했습니다. 페이지를 새로 고침해 주세요!"
+ },
+ "defaultWatermark": {
+ "message": "DeepSeek AI에서 생성하고 DeepShare 확장 프로그램으로 캡처한 콘텐츠"
+ },
+ "settingsButton": {
+ "message": "워터마크 설정"
+ },
+ "hideDefaultWatermarkLabel": {
+ "message": "기본 워터마크 숨기기"
+ },
+ "customWatermarkLabel": {
+ "message": "사용자 지정 워터마크 텍스트 (선택 사항)"
+ },
+ "customWatermarkPlaceholder": {
+ "message": "여기에 사용자 지정 워터마크를 입력하세요"
+ },
+ "saveSettings": {
+ "message": "설정 저장"
+ },
+ "settingsSaved": {
+ "message": "저장됨"
+ },
+ "sponsorTitle": {
+ "message": "이용해 주셔서 감사합니다! 도움이 되셨다면, 위챗 QR 코드를 통해 후원해 주세요 😊"
+ },
+ "selectButton": {
+ "message": "메시지 선택"
+ },
+ "selectAllButton": {
+ "message": "모두 선택"
+ },
+ "selectAllResponsesButton": {
+ "message": "모든 응답 선택"
+ },
+ "unselectAllButton": {
+ "message": "모두 선택 해제"
+ },
+ "loadingHistory": {
+ "message": "로딩 중..."
+ },
+ "noMessageSelected": {
+ "message": "메시지를 하나 이상 선택해 주세요"
+ },
+ "sponsorTabLabel": {
+ "message": "소개"
+ },
+ "totalQuotaLabel": {
+ "message": "총량:"
+ },
+ "usedQuotaLabel": {
+ "message": "사용량:"
+ },
+ "remainingQuotaLabel": {
+ "message": "잔여량:"
+ },
+ "quotaTitle": {
+ "message": "전환 할당량"
+ },
+ "dailyQuotaLabel": {
+ "message": "일일 할당량"
+ },
+ "addonQuotaLabel": {
+ "message": "애드온 할당량"
+ },
+ "dailyResetNote": {
+ "message": "매일 초기화됨"
+ },
+ "subscriptionExpiryNote": {
+ "message": "매일 초기화됨 · {date}까지"
+ },
+ "addonExpiryNote": {
+ "message": "{date}에 만료됨"
+ },
+ "apiKeyHint": {
+ "message": "API 키를 구매하시겠습니까? 여기를 클릭하세요"
+ },
+ "apiKeyMissing": {
+ "message": "문서 변환 기능을 사용하려면 확장 프로그램 아이콘을 클릭하여 API 키를 구매하고 입력해 주세요."
+ },
+ "apiKeyMissingShort": {
+ "message": "구매 후 API 키를 입력해 주세요"
+ },
+ "manualConversionExplanation": {
+ "message": "Grok, Claude, Meta AI 등을 지원합니다. 대화 내용을 마크다운 입력란에 복사한 후 \"문서로 변환\"을 클릭하면 수식 지원이 포함된 깔끔하게 서식 처리된 Word 문서를 다운로드할 수 있습니다!"
+ },
+ "manualConversionTitle": {
+ "message": "AI 채팅 내용 붙여넣기"
+ },
+ "markdownInputLabel": {
+ "message": "마크다운 텍스트"
+ },
+ "markdownInputPlaceholder": {
+ "message": "여기에 마크다운 형식의 텍스트를 붙여넣으세요..."
+ },
+ "convertToDocx": {
+ "message": "문서로 변환"
+ },
+ "clearMarkdown": {
+ "message": "지우기"
+ },
+ "emptyMarkdownError": {
+ "message": "마크다운 텍스트를 입력해 주세요"
+ },
+ "manualDocxSettings": {
+ "message": "AI 채팅 내용 붙여넣기"
+ },
+ "formulaTabLabel": {
+ "message": "수식 복사"
+ },
+ "formulaSettingsTitle": {
+ "message": "수식 복사 설정"
+ },
+ "formulaCopyTutorialText": {
+ "message": "수식 복사에 대해 자세히 알아보기:"
+ },
+ "formulaCopyTutorialLink": {
+ "message": "튜토리얼 보기"
+ },
+ "enableFormulaCopyLabel": {
+ "message": "수식 복사 활성화"
+ },
+ "formulaFormatLabel": {
+ "message": "수식 복사 형식"
+ },
+ "formatMathMLLabel": {
+ "message": "MathML"
+ },
+ "formatLaTeXLabel": {
+ "message": "LaTeX"
+ },
+ "formatDollarLatexLabel": {
+ "message": "마크다운"
+ },
+ "formulaFormatHint": {
+ "message": "Word용 MathML, WPS/Overleaf용 LaTeX, Lark/Notion/Obsidian용 마크다운"
+ },
+ "formulaEngineLabel": {
+ "message": "변환 엔진"
+ },
+ "engineMathJaxLabel": {
+ "message": "MathJax"
+ },
+ "engineKaTeXLabel": {
+ "message": "KaTeX"
+ },
+ "formulaEngineHint": {
+ "message": "MathJax는 호환성이 더 우수하고, KaTeX는 더 빠릅니다"
+ },
+ "screenshotMethodLabel": {
+ "message": "스크린샷 방법"
+ },
+ "methodDomToImageLabel": {
+ "message": "dom-to-image"
+ },
+ "methodHtml2CanvasLabel": {
+ "message": "html2canvas"
+ },
+ "screenshotMethodHint": {
+ "message": "스크린샷에 사용할 방법을 선택하세요. 한 방법이 작동하지 않으면 다른 방법을 시도해 보세요. 방법을 변경한 후 페이지를 새로 고침해 주세요."
+ },
+ "removeDividersLabel": {
+ "message": "구분선 제거"
+ },
+ "removeEmojisLabel": {
+ "message": "이모지 제거"
+ },
+ "convertMermaidLabel": {
+ "message": "Mermaid 변환"
+ },
+ "compatModeLabel": {
+ "message": "호환 모드"
+ },
+ "compatModeTooltip": {
+ "message": "비표준 마크다운 지원"
+ },
+ "compatModeDocUrl": {
+ "message": "https://docs.deepshare.app/en/faq/compat-mode"
+ },
+ "hardLineBreaksLabel": {
+ "message": "강제 줄바꿈"
+ },
+ "hardLineBreaksTooltip": {
+ "message": "단일 줄 바꿈을 강제 줄 바꿈으로 처리"
+ },
+ "hardLineBreaksDocUrl": {
+ "message": "https://docs.deepshare.app/en/faq/hard-line-breaks"
+ },
+ "disableAutoNumberingLabel": {
+ "message": "자동 번호 매기기 안 함"
+ },
+ "disableAutoNumberingTooltip": {
+ "message": "번호가 매겨진 순서 목록을 일반 텍스트로 변환함"
+ },
+ "disableAutoNumberingDocUrl": {
+ "message": "https://docs.deepshare.app/en/faq/hard-line-breaks"
+ },
+ "getClipboardError": {
+ "message": "콘텐츠 가져오기에 실패했습니다"
+ },
+ "clipboardPermissionError": {
+ "message": "콘텐츠 가져오기에 실패했습니다. 클립보드 읽기 권한을 허용해 주세요"
+ },
+ "refreshButton": {
+ "message": "새로 고침"
+ },
+ "purchaseQuota": {
+ "message": "할당량 구매"
+ },
+ "purchaseAddonQuota": {
+ "message": "애드온 할당량 구매"
+ },
+ "purchaseSubscription": {
+ "message": "구독 구매"
+ },
+ "renewSubscription": {
+ "message": "구독 갱신"
+ },
+ "manageSubscription": {
+ "message": "구독 관리"
+ },
+ "pricePageUrl": {
+ "message": "https://ds.rick216.cn/en/price.html"
+ },
+ "subscriptionExpiredDays": {
+ "message": "{days}일 전에 만료됨"
+ },
+ "expirationLabel": {
+ "message": "유효 기간:"
+ },
+ "unknown": {
+ "message": "알 수 없음"
+ },
+ "templateLabel": {
+ "message": "Word 템플릿"
+ },
+ "universalTemplate": {
+ "message": "범용"
+ },
+ "saveAsImageButton": {
+ "message": "이미지로 저장"
+ },
+ "screenshotInitiated": {
+ "message": "스크린샷 생성 중..."
+ },
+ "screenshotSuccess": {
+ "message": "스크린샷 저장됨"
+ },
+ "screenshotFailed": {
+ "message": "스크린샷 생성에 실패했습니다. 새로 고침을 시도해 보시겠습니까?"
+ },
+ "conversationTooLong": {
+ "message": "대화가 너무 길어 하나의 이미지로 캡처할 수 없습니다. 메시지를 더 적게 선택하고 다시 시도해 주세요."
+ },
+ "imageCopied": {
+ "message": "이미지가 클립보드에 복사되었습니다"
+ },
+ "imageCopyFailed": {
+ "message": "이미지를 클립보드에 복사하는 데 실패했습니다"
+ },
+ "apiKeyError": {
+ "message": "API 키 오류 또는 만료되었습니다. 이메일을 확인하거나 고객 서비스(contact@deepshare.app)에 문의해 주세요."
+ },
+ "quotaExceededError": {
+ "message": "할당량 초과. 충전해 주십시오."
+ },
+ "aboutTabTitle": {
+ "message": "DeepShare 정보"
+ },
+ "versionLabel": {
+ "message": "버전:"
+ },
+ "documentationLabel": {
+ "message": "문서:"
+ },
+ "documentationUrl": {
+ "message": "https://docs.deepshare.app/en"
+ },
+
+ "githubLabel": {
+ "message": "GitHub:"
+ },
+ "developerEmailLabel": {
+ "message": "개발자 이메일:"
+ },
+ "acknowledgmentText": {
+ "message": "DeepShare에 대한 제안을 보내주신 모든 분께 감사드립니다! 많은 기능이 실제 사용자의 필요에서 탄생합니다. 함께 생산성을 높이고, 인생에서 진정으로 중요한 일에 더 많은 시간을 할애해 봅시다."
+ },
+ "referenceSources": {
+ "message": "참조 자료"
+ },
+ "unusedSources": {
+ "message": "검토했으나 사용되지 않은 자료"
+ },
+ "saveAsMarkdown": {
+ "message": "Markdown으로 저장"
+ },
+ "otherSettingsTabLabel": {
+ "message": "기타 설정"
+ },
+ "otherSettingsTitle": {
+ "message": "기타 설정"
+ },
+ "geminiSettingsTitle": {
+ "message": "Gemini"
+ },
+ "exportGeminiSourcesLabel": {
+ "message": "Deep Research 출처 내보내기"
+ },
+ "exportGeminiSourcesHint": {
+ "message": "Gemini Deep Research 보고서를 내보낼 때 참조 출처 포함"
+ },
+ "includeGeminiChatLinkLabel": {
+ "message": "채팅 링크 내보내기"
+ },
+ "includeGeminiChatLinkHint": {
+ "message": "내보낸 콘텐츠에는 원본 대화 링크가 포함됩니다"
+ },
+ "itemsSelected": {
+ "message": "$COUNT$개 항목 선택됨",
+ "description": "Gemini 선택 막대에서 선택한 개수",
+ "placeholders": {
+ "COUNT": {
+ "content": "$1"
+ }
+ }
+ },
+ "selectAllQuestions": {
+ "message": "모든 질문 선택"
+ },
+ "confirmExport": {
+ "message": "내보내기 확인"
+ },
+ "cancelButton": {
+ "message": "취소"
+ },
+ "roleUser": {
+ "message": "사용자"
+ },
+ "roleAssistant": {
+ "message": "어시스턴트"
+ },
+ "exportedViaDeepShare": {
+ "message": "DeepShare를 통해 내보냄"
+ },
+ "geminiConversation": {
+ "message": "Gemini 대화"
+ },
+ "sourceConversationLabel": {
+ "message": "소스"
+ },
+ "languageSettingsTitle": {
+ "message": "언어"
+ },
+ "languageSelectLabel": {
+ "message": "표시 언어"
+ },
+ "languageAuto": {
+ "message": "자동 (브라우저 기본값)"
+ },
+ "languageHint": {
+ "message": "원하는 표시 언어를 선택하세요"
+ },
+ "networkError": {
+ "message": "변환에 실패했습니다. 네트워크 연결을 확인해 주세요"
+ },
+ "onboardingWelcomeTitle": {
+ "message": "DeepShare에 오신 것을 환영합니다!"
+ },
+ "onboardingWelcomeSubtitle": {
+ "message": "적절한 수식 형식을 선택하고 확장 프로그램을 고정해 보세요"
+ },
+ "onboardingSelectionTitle": {
+ "message": "수식 형식 선택"
+ },
+ "onboardingSelectionDescription": {
+ "message": "나중에 확장 프로그램 설정에서 변경할 수 있습니다"
+ },
+ "onboardingMathMLDescription": {
+ "message": "Microsoft Word 사용자에게 안성맞춤입니다"
+ },
+ "onboardingLaTeXDescription": {
+ "message": "WPS, MathType 및 Overleaf 사용자용"
+ },
+ "onboardingDollarLatexDescription": {
+ "message": "Lark, Notion 및 Obsidian 사용자용"
+ },
+ "onboardingRecommended": {
+ "message": "권장"
+ },
+ "onboardingLearnMoreText": {
+ "message": "수식 복사에 대해 자세히 알아보기:"
+ },
+ "onboardingLearnMoreLink": {
+ "message": "튜토리얼 보기"
+ },
+ "onboardingContinue": {
+ "message": "계속하기"
+ },
+ "onboardingPinTitle": {
+ "message": "DeepShare를 도구 모음에 고정하세요"
+ },
+ "onboardingPinSubtitle": {
+ "message": "설정에 빠르게 접근하려면 확장 프로그램을 고정하세요"
+ },
+ "onboardingPinStep1": {
+ "message": "브라우저 툴바에서 퍼즐 아이콘을 클릭하세요"
+ },
+ "onboardingPinStep2": {
+ "message": "DeepShare를 찾아 핀 아이콘을 클릭하세요"
+ },
+ "onboardingPinStep3": {
+ "message": "설정에 액세스하려면 언제든지 DeepShare 아이콘을 클릭하세요"
+ },
+ "onboardingFinish": {
+ "message": "알겠습니다!"
+ },
+ "onboardingBack": {
+ "message": "뒤로"
+ },
+ "onboardingLearnMoreUsageText": {
+ "message": "확장 프로그램 사용법에 대해 자세히 알아보기:"
+ },
+ "onboardingLearnMoreUsageLink": {
+ "message": "튜토리얼 보기"
+ },
+ "onboardingRefreshHint": {
+ "message": "처음 사용하시는 경우, 열려 있는 모든 AI 대화를 새로 고침해 주세요."
+ },
+ "scrollCollecting": {
+ "message": "메시지를 수집하기 위해 스크롤 중입니다. 잠시만 기다려 주세요..."
+ }
+}
\ No newline at end of file
diff --git a/popup/popup.html b/popup/popup.html
index 111ba2e..dc1bdd2 100644
--- a/popup/popup.html
+++ b/popup/popup.html
@@ -409,6 +409,7 @@
Language
+
Select your preferred display language
From 2e282e1fba8b84d6137d023ce7374508782f37d1 Mon Sep 17 00:00:00 2001
From: DerYokoya <133297414+DerYokoya@users.noreply.github.com>
Date: Fri, 29 May 2026 22:09:35 -0400
Subject: [PATCH 02/11] doubao typo
---
manifest.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/manifest.json b/manifest.json
index a95c26e..5b784b0 100644
--- a/manifest.json
+++ b/manifest.json
@@ -129,7 +129,7 @@
"lib/katex.min.js",
"scripts/formulaConverter.js",
"scripts/notifications.js",
- "scripts/copyKatex4Doubao.js"
+ "scripts/copyKatex4DouBao.js"
]
},
{
From e507b3020067c1b4568a42908beb579dfd3fc651 Mon Sep 17 00:00:00 2001
From: DerYokoya <133297414+DerYokoya@users.noreply.github.com>
Date: Fri, 29 May 2026 22:54:14 -0400
Subject: [PATCH 03/11] Copy markdown DeepSeek
---
_locales/en/messages.json | 18 ++
_locales/zh_CN/messages.json | 20 +-
manifest.json | 3 +-
popup/popup.html | 11 +
popup/popup.js | 6 +
scripts/copyDeepSeekMarkdown.js | 500 ++++++++++++++++++++++++++++++++
6 files changed, 556 insertions(+), 2 deletions(-)
create mode 100644 scripts/copyDeepSeekMarkdown.js
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 1de7fae..c4eaaec 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -529,5 +529,23 @@
},
"scrollCollecting": {
"message": "Scrolling to collect messages, please wait..."
+ },
+ "copyAsMarkdown": {
+ "message": "Copy as Markdown"
+ },
+ "markdownCopied": {
+ "message": "Markdown copied to clipboard"
+ },
+ "copyConversationMarkdown": {
+ "message": "Copy All as Markdown"
+ },
+ "featureDisabled": {
+ "message": "Markdown copy feature is disabled"
+ },
+ "noMessages": {
+ "message": "No messages found"
+ },
+ "noContent": {
+ "message": "No content to copy"
}
}
diff --git a/_locales/zh_CN/messages.json b/_locales/zh_CN/messages.json
index fb8c8a9..be37b08 100644
--- a/_locales/zh_CN/messages.json
+++ b/_locales/zh_CN/messages.json
@@ -528,5 +528,23 @@
},
"scrollCollecting": {
"message": "正在滚动读取对话内容,请勿操作..."
+ },
+ "copyAsMarkdown": {
+ "message": "复制为Markdown"
+ },
+ "markdownCopied": {
+ "message": "Markdown已复制到剪贴板"
+ },
+ "copyConversationMarkdown": {
+ "message": "复制全部为Markdown"
+ },
+ "featureDisabled": {
+ "message": "Markdown复制功能已禁用"
+ },
+ "noMessages": {
+ "message": "未找到消息"
+ },
+ "noContent": {
+ "message": "没有内容可复制"
}
-}
+}
\ No newline at end of file
diff --git a/manifest.json b/manifest.json
index 5b784b0..adfeb20 100644
--- a/manifest.json
+++ b/manifest.json
@@ -66,7 +66,8 @@
"scripts/injectDocxButton.js",
"scripts/captureDeepSeek.js",
"scripts/saveDeepSeekAsDocx.js",
- "scripts/injectDeepSeekButtons.js"
+ "scripts/injectDeepSeekButtons.js",
+ "scripts/copyDeepSeekMarkdown.js"
]
},
{
diff --git a/popup/popup.html b/popup/popup.html
index dc1bdd2..6237195 100644
--- a/popup/popup.html
+++ b/popup/popup.html
@@ -439,6 +439,17 @@ Gemini
How long to wait for Gemini to load more history after each auto-scroll (3-10 seconds)
+
+
diff --git a/popup/popup.js b/popup/popup.js
index a9cf821..39a2be5 100644
--- a/popup/popup.js
+++ b/popup/popup.js
@@ -172,6 +172,12 @@ function loadSettings(highlightApiKey = false, forceDocxTab = false) {
// Language preference
document.getElementById('languageSelect').value = data.preferredLanguage || 'auto';
+ // DeepSeek Markdown setting
+ document.getElementById('copyDeepSeekMarkdownEnabled').checked = settings.copyDeepSeekMarkdownEnabled !== false;
+ document.getElementById('copyDeepSeekMarkdownEnabled').addEventListener('change', (e) => {
+ chrome.storage.sync.set({ copyDeepSeekMarkdownEnabled: e.target.checked });
+ });
+
// If API key is set, check quota and update renewal/purchase links
if (data.docxApiKey) {
checkQuota();
diff --git a/scripts/copyDeepSeekMarkdown.js b/scripts/copyDeepSeekMarkdown.js
new file mode 100644
index 0000000..8b485a4
--- /dev/null
+++ b/scripts/copyDeepSeekMarkdown.js
@@ -0,0 +1,500 @@
+/**
+ * DeepSeek Markdown Copy functionality
+ * Adds a button to copy AI responses as Markdown format
+ */
+
+(function() {
+ 'use strict';
+ console.debug('DeepShare: Initializing DeepSeek Markdown copy functionality');
+
+ // Load settings
+ let copyMarkdownSettings = {
+ enabled: true,
+ includeUserQuestion: true,
+ includeAiResponse: true
+ };
+
+ function loadSettings() {
+ chrome.storage.sync.get({
+ copyDeepSeekMarkdownEnabled: true,
+ includeUserQuestion: true,
+ includeAiResponse: true
+ }, (settings) => {
+ copyMarkdownSettings = {
+ enabled: settings.copyDeepSeekMarkdownEnabled,
+ includeUserQuestion: settings.includeUserQuestion,
+ includeAiResponse: settings.includeAiResponse
+ };
+ });
+ }
+
+ // Function to extract AI response as markdown
+ function extractAiResponseAsMarkdown(messageDiv) {
+ // Find the markdown content
+ const markdownDiv = messageDiv.querySelector('.ds-markdown');
+ if (!markdownDiv) return null;
+
+ // Use the same extraction logic as in injectDocxButton.js
+ return extractMarkdownFromElement(markdownDiv);
+ }
+
+ // Extract user question as markdown
+ function extractUserQuestionAsMarkdown(messageDiv) {
+ const userElement = messageDiv.querySelector('.fbb737a4');
+ if (!userElement) return null;
+
+ // Get text content from user message
+ const userText = Array.from(userElement.childNodes || [])
+ .find(node => node.nodeType === Node.TEXT_NODE)?.textContent?.trim();
+
+ return userText || null;
+ }
+
+ // Extract markdown from element with formula handling
+ function extractMarkdownFromElement(element) {
+ let result = '';
+
+ const processNode = (node) => {
+ // Skip checkboxes and selection UI
+ if (node.nodeType === Node.ELEMENT_NODE) {
+ if (node.classList && (
+ node.classList.contains('message-checkbox-wrapper') ||
+ node.classList.contains('ds-checkbox-wrapper')
+ )) {
+ return;
+ }
+ }
+
+ // Handle math formulas (KaTeX)
+ if (node.classList && node.classList.contains('katex')) {
+ const annotation = node.querySelector('annotation[encoding="application/x-tex"]');
+ if (annotation) {
+ const isDisplay = node.closest('.katex-display');
+ const latex = annotation.textContent.trim();
+ if (isDisplay) {
+ result += '\n$$\n' + latex + '\n$$\n';
+ } else {
+ result += '$' + latex + '$';
+ }
+ return;
+ }
+ }
+
+ // Handle code blocks
+ if (node.tagName === 'PRE') {
+ const code = node.querySelector('code');
+ if (code) {
+ const language = code.className.match(/language-(\w+)/)?.[1] || '';
+ result += '\n```' + language + '\n' + code.textContent + '\n```\n';
+ }
+ return;
+ }
+
+ // Handle inline code
+ if (node.tagName === 'CODE' && !node.closest('pre')) {
+ result += '`' + node.textContent + '`';
+ return;
+ }
+
+ // Handle headings
+ if (node.tagName && /^H[1-6]$/.test(node.tagName)) {
+ const level = node.tagName[1];
+ const headingMark = '#'.repeat(parseInt(level));
+ result += '\n' + headingMark + ' ' + node.textContent.trim() + '\n';
+ return;
+ }
+
+ // Handle bold
+ if (node.tagName === 'STRONG' || node.tagName === 'B') {
+ result += '**' + node.textContent + '**';
+ return;
+ }
+
+ // Handle italic
+ if (node.tagName === 'EM' || node.tagName === 'I') {
+ result += '*' + node.textContent + '*';
+ return;
+ }
+
+ // Handle links
+ if (node.tagName === 'A') {
+ const href = node.getAttribute('href');
+ const text = node.textContent;
+ if (href && href !== text) {
+ result += '[' + text + '](' + href + ')';
+ } else {
+ result += text;
+ }
+ return;
+ }
+
+ // Handle lists
+ if (node.tagName === 'UL' || node.tagName === 'OL') {
+ const items = node.querySelectorAll(':scope > li');
+ const isOrdered = node.tagName === 'OL';
+ items.forEach((item, idx) => {
+ const prefix = isOrdered ? `${idx + 1}. ` : '- ';
+ result += prefix + item.textContent.trim() + '\n';
+ });
+ return;
+ }
+
+ // Handle paragraphs
+ if (node.tagName === 'P') {
+ result += node.textContent.trim() + '\n\n';
+ return;
+ }
+
+ // Handle line breaks
+ if (node.tagName === 'BR') {
+ result += '\n';
+ return;
+ }
+
+ // Handle text nodes
+ if (node.nodeType === Node.TEXT_NODE) {
+ result += node.textContent;
+ return;
+ }
+
+ // Recursively process children
+ if (node.childNodes && node.childNodes.length > 0) {
+ node.childNodes.forEach(processNode);
+ }
+ };
+
+ processNode(element);
+
+ // Clean up excessive newlines
+ result = result.replace(/\n{3,}/g, '\n\n').trim();
+
+ return result;
+ }
+
+ // Copy markdown to clipboard
+ async function copyMarkdownToClipboard(content) {
+ await navigator.clipboard.writeText(content);
+ window.showToastNotification(chrome.i18n?.getMessage('markdownCopied') || 'Markdown copied to clipboard', 'success');
+ }
+
+ // Main copy function
+ async function copyAsMarkdown(copyButton) {
+ if (!copyMarkdownSettings.enabled) {
+ window.showToastNotification(chrome.i18n?.getMessage('featureDisabled') || 'Markdown copy feature is disabled', 'info');
+ return;
+ }
+
+ // Find the message container
+ let messageDiv = copyButton.closest('._4f9bf79, ._9663006');
+ if (!messageDiv) {
+ console.error('Could not find message container');
+ window.showToastNotification(chrome.i18n?.getMessage('copyFailed') || 'Failed to copy', 'error');
+ return;
+ }
+
+ const isAiMessage = messageDiv.matches('._4f9bf79');
+ let markdownContent = '';
+
+ if (isAiMessage) {
+ // For AI responses, only copy AI content (user question can be optionally included via selection)
+ const aiContent = extractAiResponseAsMarkdown(messageDiv);
+ if (aiContent) {
+ markdownContent = `## AI Response\n\n${aiContent}`;
+ } else {
+ markdownContent = await getContentViaCopyButton(copyButton);
+ if (markdownContent) {
+ markdownContent = `## AI Response\n\n${markdownContent}`;
+ }
+ }
+ } else {
+ // For user messages, copy as is
+ const userContent = extractUserQuestionAsMarkdown(messageDiv);
+ if (userContent) {
+ markdownContent = `## User Question\n\n${userContent}`;
+ }
+ }
+
+ if (markdownContent && markdownContent.trim()) {
+ await copyMarkdownToClipboard(markdownContent);
+ } else {
+ window.showToastNotification(chrome.i18n?.getMessage('noContent') || 'No content to copy', 'error');
+ }
+ }
+
+ // Fallback: use copy button to get content
+ async function getContentViaCopyButton(copyButton) {
+ let originalClipboardContent = null;
+ try {
+ // Backup original clipboard
+ try {
+ originalClipboardContent = await navigator.clipboard.readText();
+ } catch (e) {
+ // Ignore - clipboard might be empty or permission not granted
+ }
+
+ // Click copy button
+ copyButton.click();
+ await new Promise(resolve => setTimeout(resolve, 300));
+
+ // Get content
+ const content = await navigator.clipboard.readText();
+
+ // Restore original
+ if (originalClipboardContent !== null) {
+ try {
+ await navigator.clipboard.writeText(originalClipboardContent);
+ } catch (e) {}
+ }
+
+ return content;
+ } catch (error) {
+ console.error('Failed to get content via copy button:', error);
+ return null;
+ }
+ }
+
+ // Copy entire conversation as markdown
+ async function copyConversationAsMarkdown() {
+ if (!copyMarkdownSettings.enabled) {
+ window.showToastNotification(chrome.i18n?.getMessage('featureDisabled') || 'Markdown copy feature is disabled', 'info');
+ return;
+ }
+
+ // Find all messages
+ const messageSelector = '._9663006, ._4f9bf79._43c05b5, ._4f9bf79.d7dc56a8._43c05b5';
+ const messages = document.querySelectorAll(messageSelector);
+
+ if (messages.length === 0) {
+ window.showToastNotification(chrome.i18n?.getMessage('noMessages') || 'No messages found', 'error');
+ return;
+ }
+
+ let conversationContent = '';
+ let messageIndex = 1;
+
+ for (const messageDiv of messages) {
+ const isUserMessage = messageDiv.matches('._9663006') || messageDiv.querySelector('.d29f3d7d');
+
+ if (isUserMessage && copyMarkdownSettings.includeUserQuestion) {
+ const userContent = extractUserQuestionAsMarkdown(messageDiv);
+ if (userContent) {
+ conversationContent += `## Message ${messageIndex}: User Question\n\n${userContent}\n\n---\n\n`;
+ messageIndex++;
+ }
+ } else if (!isUserMessage && copyMarkdownSettings.includeAiResponse) {
+ const copyButton = messageDiv.querySelector('.ds-icon-button[role="button"]');
+ let aiContent = extractAiResponseAsMarkdown(messageDiv);
+
+ if (!aiContent && copyButton) {
+ aiContent = await getContentViaCopyButton(copyButton);
+ }
+
+ if (aiContent) {
+ conversationContent += `## Message ${messageIndex}: AI Response\n\n${aiContent}\n\n---\n\n`;
+ messageIndex++;
+ }
+ }
+ }
+
+ if (conversationContent.trim()) {
+ // Add title
+ const title = document.querySelector('.afa34042')?.textContent?.trim() || 'DeepSeek Conversation';
+ const timestamp = new Date().toLocaleString();
+ const fullMarkdown = `# ${title}\n\n*Exported on ${timestamp} via DeepShare*\n\n---\n\n${conversationContent}`;
+
+ await copyMarkdownToClipboard(fullMarkdown);
+ } else {
+ window.showToastNotification(chrome.i18n?.getMessage('noContent') || 'No content to copy', 'error');
+ }
+ }
+
+ // Inject markdown copy button next to existing copy button
+ function injectMarkdownButton(copyButton, container) {
+ if (container.querySelector('.deepseek-markdown-copy-btn')) return;
+
+ const mdButton = document.createElement('div');
+ mdButton.className = copyButton.className + ' deepseek-markdown-copy-btn';
+ mdButton.tabIndex = copyButton.tabIndex || -1;
+ mdButton.setAttribute('role', 'button');
+ mdButton.setAttribute('aria-label', chrome.i18n?.getMessage('copyAsMarkdown') || 'Copy as Markdown');
+ mdButton.title = chrome.i18n?.getMessage('copyAsMarkdown') || 'Copy as Markdown';
+
+ // Copy styling
+ const copyStyle = copyButton.getAttribute('style') || '';
+ mdButton.style.cssText = copyStyle;
+
+ // Create icon
+ const iconHTML = `
+
+
+ `;
+ mdButton.innerHTML = iconHTML;
+
+ // Insert after copy button
+ copyButton.parentNode.insertBefore(mdButton, copyButton.nextSibling);
+
+ // Add tooltip
+ let tooltipWrapper = null;
+ let floatingContainer = null;
+
+ mdButton.addEventListener('mouseenter', () => {
+ const tooltipText = mdButton.title;
+ if (!tooltipText) return;
+
+ if (!floatingContainer) {
+ floatingContainer = document.querySelector('.ds-floating-container');
+ if (!floatingContainer) {
+ floatingContainer = document.createElement('div');
+ floatingContainer.className = 'ds-floating-container';
+ floatingContainer.style.zIndex = '9999';
+ document.body.appendChild(floatingContainer);
+ }
+ }
+
+ tooltipWrapper = document.createElement('div');
+ tooltipWrapper.className = 'ds-floating-position-wrapper ds-theme';
+ tooltipWrapper.style.zIndex = '10000';
+
+ const tooltipElement = document.createElement('div');
+ tooltipElement.className = 'ds-tooltip ds-tooltip--s ds-elevated ds-theme';
+ tooltipElement.textContent = tooltipText;
+
+ tooltipWrapper.appendChild(tooltipElement);
+ floatingContainer.appendChild(tooltipWrapper);
+
+ const btnRect = mdButton.getBoundingClientRect();
+ tooltipWrapper.style.opacity = '0';
+ const tooltipRect = tooltipWrapper.getBoundingClientRect();
+ tooltipWrapper.style.opacity = '1';
+
+ let top = btnRect.bottom + 4;
+ let left = btnRect.left + (btnRect.width / 2) - (tooltipRect.width / 2);
+ tooltipWrapper.setAttribute('data-transform-origin', 'bottom');
+
+ if (left < 5) left = 5;
+ if ((left + tooltipRect.width) > (window.innerWidth - 5)) {
+ left = window.innerWidth - tooltipRect.width - 5;
+ }
+
+ tooltipWrapper.style.top = `${top}px`;
+ tooltipWrapper.style.left = `${left}px`;
+ });
+
+ mdButton.addEventListener('mouseleave', () => {
+ if (tooltipWrapper) {
+ tooltipWrapper.remove();
+ tooltipWrapper = null;
+ }
+ });
+
+ // Click handler
+ mdButton.addEventListener('click', async (e) => {
+ e.stopPropagation();
+
+ // Disable button during copy
+ mdButton.style.opacity = '0.5';
+ mdButton.style.pointerEvents = 'none';
+
+ await copyAsMarkdown(copyButton);
+
+ // Re-enable
+ mdButton.style.opacity = '';
+ mdButton.style.pointerEvents = '';
+ });
+ }
+
+ // Inject conversation markdown copy button in the share panel
+ function injectConversationMarkdownButton() {
+ const shareContainer = document.querySelector('._43d222b');
+ if (!shareContainer) return;
+
+ const buttonContainer = shareContainer.querySelector('.fab07e97');
+ if (!buttonContainer) return;
+
+ // Check if already injected
+ if (document.getElementById('copy-conversation-md-btn')) return;
+
+ const createLinkButton = buttonContainer.querySelector('.ds-basic-button--primary');
+ if (!createLinkButton) return;
+
+ const mdCopyButton = createLinkButton.cloneNode(true);
+ mdCopyButton.id = 'copy-conversation-md-btn';
+ const span = mdCopyButton.querySelector('span');
+ span.textContent = chrome.i18n?.getMessage('copyConversationMarkdown') || 'Copy Markdown';
+
+ // Remove icon if exists
+ const iconContainer = mdCopyButton.querySelector('.ds-icon');
+ if (iconContainer) {
+ iconContainer.remove();
+ }
+
+ mdCopyButton.addEventListener('click', async () => {
+ await copyConversationAsMarkdown();
+ });
+
+ buttonContainer.insertBefore(mdCopyButton, createLinkButton);
+ }
+
+ // Observe and inject buttons
+ function observeAndInject() {
+ loadSettings();
+
+ const observer = new MutationObserver((mutations) => {
+ for (const mutation of mutations) {
+ if (mutation.type === 'childList') {
+ // Inject per-message markdown buttons
+ const buttonContainers = document.querySelectorAll('.ds-flex[style*="align-items"][style*="gap"], div[class*="ds-flex"][style*="align-items: center"]');
+
+ buttonContainers.forEach(container => {
+ const buttonGroup = container.querySelector('.ds-flex[style*="align-items"][style*="gap"], div[class*="ds-flex"][style*="align-items"]') || container;
+
+ const copyButtons = buttonGroup.querySelectorAll('.ds-icon-button[role="button"]');
+
+ copyButtons.forEach(copyBtn => {
+ // Check if this is an AI response (not user message)
+ const isUserMessage = copyBtn.closest('.d29f3d7d, [class*="d29f3d7d"]');
+ const isAIContainer = copyBtn.closest('._4f9bf79, [class*="_4f9bf79"]');
+ const isAIResponse = isAIContainer && !isUserMessage;
+
+ if (isAIResponse && !copyBtn.parentNode?.querySelector('.deepseek-markdown-copy-btn')) {
+ injectMarkdownButton(copyBtn, buttonGroup);
+ }
+ });
+ });
+
+ // Inject conversation-level markdown button
+ injectConversationMarkdownButton();
+ }
+ }
+ });
+
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true
+ });
+
+ // Listen for settings changes
+ chrome.storage.onChanged.addListener((changes) => {
+ if (changes.copyDeepSeekMarkdownEnabled) {
+ copyMarkdownSettings.enabled = changes.copyDeepSeekMarkdownEnabled.newValue;
+ }
+ if (changes.includeUserQuestion) {
+ copyMarkdownSettings.includeUserQuestion = changes.includeUserQuestion.newValue;
+ }
+ if (changes.includeAiResponse) {
+ copyMarkdownSettings.includeAiResponse = changes.includeAiResponse.newValue;
+ }
+ });
+ }
+
+ // Initialize
+ observeAndInject();
+})();
\ No newline at end of file
From cd65ef5774143c684fe0a799843e9ea90a438a50 Mon Sep 17 00:00:00 2001
From: DerYokoya <133297414+DerYokoya@users.noreply.github.com>
Date: Fri, 29 May 2026 23:07:42 -0400
Subject: [PATCH 04/11] DeepSeek Save as markdown fixed
---
popup/popup.html | 4 +-
popup/popup.js | 6 -
scripts/copyDeepSeekMarkdown.js | 286 ++++++++++++++++++++------------
3 files changed, 178 insertions(+), 118 deletions(-)
diff --git a/popup/popup.html b/popup/popup.html
index 6237195..2f566c5 100644
--- a/popup/popup.html
+++ b/popup/popup.html
@@ -445,9 +445,9 @@ DeepSeek
diff --git a/popup/popup.js b/popup/popup.js
index 39a2be5..a9cf821 100644
--- a/popup/popup.js
+++ b/popup/popup.js
@@ -172,12 +172,6 @@ function loadSettings(highlightApiKey = false, forceDocxTab = false) {
// Language preference
document.getElementById('languageSelect').value = data.preferredLanguage || 'auto';
- // DeepSeek Markdown setting
- document.getElementById('copyDeepSeekMarkdownEnabled').checked = settings.copyDeepSeekMarkdownEnabled !== false;
- document.getElementById('copyDeepSeekMarkdownEnabled').addEventListener('change', (e) => {
- chrome.storage.sync.set({ copyDeepSeekMarkdownEnabled: e.target.checked });
- });
-
// If API key is set, check quota and update renewal/purchase links
if (data.docxApiKey) {
checkQuota();
diff --git a/scripts/copyDeepSeekMarkdown.js b/scripts/copyDeepSeekMarkdown.js
index 8b485a4..63239cb 100644
--- a/scripts/copyDeepSeekMarkdown.js
+++ b/scripts/copyDeepSeekMarkdown.js
@@ -52,135 +52,203 @@
// Extract markdown from element with formula handling
function extractMarkdownFromElement(element) {
- let result = '';
-
- const processNode = (node) => {
- // Skip checkboxes and selection UI
- if (node.nodeType === Node.ELEMENT_NODE) {
- if (node.classList && (
- node.classList.contains('message-checkbox-wrapper') ||
- node.classList.contains('ds-checkbox-wrapper')
- )) {
- return;
- }
- }
- // Handle math formulas (KaTeX)
+ // Returns inline markdown string for a node and its children
+ function extractInline(node) {
+ if (node.nodeType === Node.TEXT_NODE) return node.textContent;
+
+ if (node.nodeType !== Node.ELEMENT_NODE) return '';
+
+ // Skip UI chrome
+ if (node.classList && (
+ node.classList.contains('message-checkbox-wrapper') ||
+ node.classList.contains('ds-checkbox-wrapper')
+ )) return '';
+
+ // KaTeX inline
if (node.classList && node.classList.contains('katex')) {
- const annotation = node.querySelector('annotation[encoding="application/x-tex"]');
- if (annotation) {
- const isDisplay = node.closest('.katex-display');
- const latex = annotation.textContent.trim();
- if (isDisplay) {
- result += '\n$$\n' + latex + '\n$$\n';
- } else {
- result += '$' + latex + '$';
- }
- return;
- }
+ if (node.closest('.katex-display')) return ''; // handled at block level
+ const ann = node.querySelector('annotation[encoding="application/x-tex"]');
+ return ann ? '$' + ann.textContent.trim() + '$' : node.textContent;
}
+ // Skip the MathML sibling inside katex-display (avoid double output)
+ if (node.classList && node.classList.contains('katex-mathml')) return '';
- // Handle code blocks
- if (node.tagName === 'PRE') {
- const code = node.querySelector('code');
- if (code) {
- const language = code.className.match(/language-(\w+)/)?.[1] || '';
- result += '\n```' + language + '\n' + code.textContent + '\n```\n';
- }
- return;
- }
+ const tag = node.tagName;
- // Handle inline code
- if (node.tagName === 'CODE' && !node.closest('pre')) {
- result += '`' + node.textContent + '`';
- return;
+ if (tag === 'STRONG' || tag === 'B') return '**' + extractChildren(node) + '**';
+ if (tag === 'EM' || tag === 'I') return '*' + extractChildren(node) + '*';
+ if (tag === 'S' || tag === 'DEL') return '~~' + extractChildren(node) + '~~';
+ if (tag === 'CODE' && !node.closest('pre')) return '`' + node.textContent + '`';
+ if (tag === 'A') {
+ const href = node.getAttribute('href');
+ const text = extractChildren(node);
+ return (href && href !== text) ? '[' + text + '](' + href + ')' : text;
}
+ if (tag === 'BR') return '\n';
+
+ return extractChildren(node);
+ }
- // Handle headings
- if (node.tagName && /^H[1-6]$/.test(node.tagName)) {
- const level = node.tagName[1];
- const headingMark = '#'.repeat(parseInt(level));
- result += '\n' + headingMark + ' ' + node.textContent.trim() + '\n';
- return;
+ function extractChildren(node) {
+ return Array.from(node.childNodes).map(extractInline).join('');
+ }
+
+ // Returns block-level markdown string (with surrounding newlines)
+ function extractBlock(node, depth) {
+ if (depth === undefined) depth = 0;
+
+ if (node.nodeType === Node.TEXT_NODE) {
+ const t = node.textContent;
+ return t.trim() ? t : '';
}
- // Handle bold
- if (node.tagName === 'STRONG' || node.tagName === 'B') {
- result += '**' + node.textContent + '**';
- return;
+ if (node.nodeType !== Node.ELEMENT_NODE) return '';
+
+ // Skip UI chrome
+ if (node.classList && (
+ node.classList.contains('message-checkbox-wrapper') ||
+ node.classList.contains('ds-checkbox-wrapper')
+ )) return '';
+
+ const tag = node.tagName;
+
+ // KaTeX display block
+ if (node.classList && node.classList.contains('katex-display')) {
+ const ann = node.querySelector('annotation[encoding="application/x-tex"]');
+ if (ann) return '\n$$\n' + ann.textContent.trim() + '\n$$\n';
+ return '';
+ }
+ if (node.classList && (node.classList.contains('katex') || node.classList.contains('katex-mathml'))) {
+ return extractInline(node);
}
- // Handle italic
- if (node.tagName === 'EM' || node.tagName === 'I') {
- result += '*' + node.textContent + '*';
- return;
+ // Headings
+ if (/^H[1-6]$/.test(tag)) {
+ const level = '#'.repeat(parseInt(tag[1]));
+ return '\n' + level + ' ' + extractChildren(node).trim() + '\n';
}
- // Handle links
- if (node.tagName === 'A') {
- const href = node.getAttribute('href');
- const text = node.textContent;
- if (href && href !== text) {
- result += '[' + text + '](' + href + ')';
- } else {
- result += text;
+ // Code block
+ if (tag === 'PRE') {
+ const code = node.querySelector('code');
+ if (code) {
+ const lang = code.className.match(/language-(\w+)/)?.[1] || '';
+ return '\n```' + lang + '\n' + code.textContent.replace(/\n$/, '') + '\n```\n';
}
- return;
+ return '\n```\n' + node.textContent + '\n```\n';
}
- // Handle lists
- if (node.tagName === 'UL' || node.tagName === 'OL') {
- const items = node.querySelectorAll(':scope > li');
- const isOrdered = node.tagName === 'OL';
- items.forEach((item, idx) => {
- const prefix = isOrdered ? `${idx + 1}. ` : '- ';
- result += prefix + item.textContent.trim() + '\n';
- });
- return;
+ // Blockquote
+ if (tag === 'BLOCKQUOTE') {
+ const inner = extractChildren(node).trim();
+ return '\n' + inner.split('\n').map(l => '> ' + l).join('\n') + '\n';
}
- // Handle paragraphs
- if (node.tagName === 'P') {
- result += node.textContent.trim() + '\n\n';
- return;
+ // Horizontal rule
+ if (tag === 'HR') return '\n---\n';
+
+ // Table
+ if (tag === 'TABLE') {
+ let out = '\n';
+ const rows = Array.from(node.querySelectorAll('tr'));
+ rows.forEach((row, i) => {
+ const cells = Array.from(row.querySelectorAll('th, td'));
+ out += '| ' + cells.map(c => extractChildren(c).trim()).join(' | ') + ' |\n';
+ if (i === 0) {
+ out += '| ' + cells.map(() => '---').join(' | ') + ' |\n';
+ }
+ });
+ return out;
}
+ if (tag === 'THEAD' || tag === 'TBODY' || tag === 'TR' || tag === 'TH' || tag === 'TD') return '';
- // Handle line breaks
- if (node.tagName === 'BR') {
- result += '\n';
- return;
+ // Lists
+ if (tag === 'UL' || tag === 'OL') {
+ return extractList(node, depth);
}
+ if (tag === 'LI') return ''; // handled inside extractList
- // Handle text nodes
- if (node.nodeType === Node.TEXT_NODE) {
- result += node.textContent;
- return;
+ // Paragraph
+ if (tag === 'P') {
+ return '\n' + extractChildren(node).trim() + '\n';
}
- // Recursively process children
- if (node.childNodes && node.childNodes.length > 0) {
- node.childNodes.forEach(processNode);
+ // Inline elements inside block context — emit inline
+ if (['STRONG','B','EM','I','S','DEL','CODE','A','SPAN','BR'].includes(tag)) {
+ return extractInline(node);
}
- };
- processNode(element);
+ // Generic container — recurse
+ return Array.from(node.childNodes).map(c => extractBlock(c, depth)).join('');
+ }
- // Clean up excessive newlines
- result = result.replace(/\n{3,}/g, '\n\n').trim();
+ function extractList(listNode, depth) {
+ const isOrdered = listNode.tagName === 'OL';
+ const indent = ' '.repeat(depth);
+ let out = '\n';
+ let orderedIdx = 1;
+ Array.from(listNode.children).forEach(li => {
+ if (li.tagName !== 'LI') return;
+ const prefix = isOrdered ? (orderedIdx++) + '. ' : '* ';
+
+ // Separate inline content from nested lists
+ let inlinePart = '';
+ let nestedPart = '';
+ Array.from(li.childNodes).forEach(child => {
+ if (child.nodeType === Node.ELEMENT_NODE && (child.tagName === 'UL' || child.tagName === 'OL')) {
+ nestedPart += extractList(child, depth + 1);
+ } else {
+ inlinePart += extractInline(child);
+ }
+ });
- return result;
+ out += indent + prefix + inlinePart.trim() + '\n';
+ if (nestedPart) out += nestedPart;
+ });
+ return out;
+ }
+
+ const raw = Array.from(element.childNodes).map(c => extractBlock(c, 0)).join('');
+ return raw.replace(/\n{3,}/g, '\n\n').trim();
+ }
+
+ // Save markdown content as a .md file
+ function saveMarkdownFile(content) {
+ const filename = generateFilename(content) + '.md';
+ const blob = new Blob([content], { type: 'text/markdown;charset=utf-8' });
+ const url = URL.createObjectURL(blob);
+ const link = document.createElement('a');
+ link.href = url;
+ link.download = filename;
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ URL.revokeObjectURL(url);
+ window.showToastNotification(chrome.i18n?.getMessage('markdownSaved') || 'Saved as Markdown file', 'success');
}
- // Copy markdown to clipboard
- async function copyMarkdownToClipboard(content) {
- await navigator.clipboard.writeText(content);
- window.showToastNotification(chrome.i18n?.getMessage('markdownCopied') || 'Markdown copied to clipboard', 'success');
+ function generateFilename(content) {
+ const now = new Date();
+ const timestamp = now.toLocaleString('zh-CN', {
+ year: 'numeric', month: '2-digit', day: '2-digit',
+ hour: '2-digit', minute: '2-digit', second: '2-digit',
+ hour12: false
+ }).replace(/[\/\s:]/g, '-').replace(',', '');
+
+ if (!content) return `deepseek_${timestamp}`;
+ const lines = content.split('\n').filter(l => l.trim().length > 0);
+ let firstLine = '';
+ if (lines.length > 0) {
+ firstLine = lines[0].replace(/^#+\s*/, '').replace(/[^a-zA-Z0-9_\u4e00-\u9fa5]/g, '').substring(0, 15).trim();
+ }
+ return `${firstLine || 'deepseek'}_${timestamp}`;
}
- // Main copy function
- async function copyAsMarkdown(copyButton) {
+ // Main save function
+ async function saveAsMarkdown(copyButton) {
if (!copyMarkdownSettings.enabled) {
- window.showToastNotification(chrome.i18n?.getMessage('featureDisabled') || 'Markdown copy feature is disabled', 'info');
+ window.showToastNotification(chrome.i18n?.getMessage('featureDisabled') || 'Save as Markdown feature is disabled', 'info');
return;
}
@@ -188,7 +256,7 @@
let messageDiv = copyButton.closest('._4f9bf79, ._9663006');
if (!messageDiv) {
console.error('Could not find message container');
- window.showToastNotification(chrome.i18n?.getMessage('copyFailed') || 'Failed to copy', 'error');
+ window.showToastNotification(chrome.i18n?.getMessage('saveFailed') || 'Failed to save', 'error');
return;
}
@@ -196,7 +264,6 @@
let markdownContent = '';
if (isAiMessage) {
- // For AI responses, only copy AI content (user question can be optionally included via selection)
const aiContent = extractAiResponseAsMarkdown(messageDiv);
if (aiContent) {
markdownContent = `## AI Response\n\n${aiContent}`;
@@ -207,7 +274,6 @@
}
}
} else {
- // For user messages, copy as is
const userContent = extractUserQuestionAsMarkdown(messageDiv);
if (userContent) {
markdownContent = `## User Question\n\n${userContent}`;
@@ -215,9 +281,9 @@
}
if (markdownContent && markdownContent.trim()) {
- await copyMarkdownToClipboard(markdownContent);
+ saveMarkdownFile(markdownContent);
} else {
- window.showToastNotification(chrome.i18n?.getMessage('noContent') || 'No content to copy', 'error');
+ window.showToastNotification(chrome.i18n?.getMessage('noContent') || 'No content to save', 'error');
}
}
@@ -254,9 +320,9 @@
}
// Copy entire conversation as markdown
- async function copyConversationAsMarkdown() {
+ async function saveConversationAsMarkdown() {
if (!copyMarkdownSettings.enabled) {
- window.showToastNotification(chrome.i18n?.getMessage('featureDisabled') || 'Markdown copy feature is disabled', 'info');
+ window.showToastNotification(chrome.i18n?.getMessage('featureDisabled') || 'Save as Markdown feature is disabled', 'info');
return;
}
@@ -302,9 +368,9 @@
const timestamp = new Date().toLocaleString();
const fullMarkdown = `# ${title}\n\n*Exported on ${timestamp} via DeepShare*\n\n---\n\n${conversationContent}`;
- await copyMarkdownToClipboard(fullMarkdown);
+ saveMarkdownFile(fullMarkdown);
} else {
- window.showToastNotification(chrome.i18n?.getMessage('noContent') || 'No content to copy', 'error');
+ window.showToastNotification(chrome.i18n?.getMessage('noContent') || 'No content to save', 'error');
}
}
@@ -316,8 +382,8 @@
mdButton.className = copyButton.className + ' deepseek-markdown-copy-btn';
mdButton.tabIndex = copyButton.tabIndex || -1;
mdButton.setAttribute('role', 'button');
- mdButton.setAttribute('aria-label', chrome.i18n?.getMessage('copyAsMarkdown') || 'Copy as Markdown');
- mdButton.title = chrome.i18n?.getMessage('copyAsMarkdown') || 'Copy as Markdown';
+ mdButton.setAttribute('aria-label', chrome.i18n?.getMessage('saveAsMarkdown') || 'Save as Markdown');
+ mdButton.title = chrome.i18n?.getMessage('saveAsMarkdown') || 'Save as Markdown';
// Copy styling
const copyStyle = copyButton.getAttribute('style') || '';
@@ -403,7 +469,7 @@
mdButton.style.opacity = '0.5';
mdButton.style.pointerEvents = 'none';
- await copyAsMarkdown(copyButton);
+ await saveAsMarkdown(copyButton);
// Re-enable
mdButton.style.opacity = '';
@@ -428,7 +494,7 @@
const mdCopyButton = createLinkButton.cloneNode(true);
mdCopyButton.id = 'copy-conversation-md-btn';
const span = mdCopyButton.querySelector('span');
- span.textContent = chrome.i18n?.getMessage('copyConversationMarkdown') || 'Copy Markdown';
+ span.textContent = chrome.i18n?.getMessage('saveConversationMarkdown') || 'Save as Markdown';
// Remove icon if exists
const iconContainer = mdCopyButton.querySelector('.ds-icon');
@@ -437,7 +503,7 @@
}
mdCopyButton.addEventListener('click', async () => {
- await copyConversationAsMarkdown();
+ await saveConversationAsMarkdown();
});
buttonContainer.insertBefore(mdCopyButton, createLinkButton);
From 774abf6c9365427dceff99b4ba0d2c47bf6153e0 Mon Sep 17 00:00:00 2001
From: DerYokoya <133297414+DerYokoya@users.noreply.github.com>
Date: Fri, 29 May 2026 23:12:09 -0400
Subject: [PATCH 05/11] portugueses and taiwan chinese
---
_locales/pt_BR/messages.json | 18 ++++++++++++++++++
_locales/pt_PT/messages.json | 18 ++++++++++++++++++
_locales/zh_TW/messages.json | 18 ++++++++++++++++++
3 files changed, 54 insertions(+)
diff --git a/_locales/pt_BR/messages.json b/_locales/pt_BR/messages.json
index 1f0b4a1..7da3a0d 100644
--- a/_locales/pt_BR/messages.json
+++ b/_locales/pt_BR/messages.json
@@ -528,5 +528,23 @@
},
"scrollCollecting": {
"message": "Rolando para coletar mensagens, por favor aguarde..."
+ },
+ "copyAsMarkdown": {
+ "message": "Copiar como Markdown"
+ },
+ "markdownCopied": {
+ "message": "Markdown copiado para a área de transferência"
+ },
+ "copyConversationMarkdown": {
+ "message": "Copiar tudo como Markdown"
+ },
+ "featureDisabled": {
+ "message": "O recurso de cópia Markdown está desativado"
+ },
+ "noMessages": {
+ "message": "Nenhuma mensagem encontrada"
+ },
+ "noContent": {
+ "message": "Nenhum conteúdo para copiar"
}
}
diff --git a/_locales/pt_PT/messages.json b/_locales/pt_PT/messages.json
index 8ba06b5..0635b99 100644
--- a/_locales/pt_PT/messages.json
+++ b/_locales/pt_PT/messages.json
@@ -528,5 +528,23 @@
},
"scrollCollecting": {
"message": "A percorrer para recolher mensagens, por favor aguarde..."
+ },
+ "copyAsMarkdown": {
+ "message": "Copiar como Markdown"
+ },
+ "markdownCopied": {
+ "message": "Markdown copiado para a área de transferência"
+ },
+ "copyConversationMarkdown": {
+ "message": "Copiar tudo como Markdown"
+ },
+ "featureDisabled": {
+ "message": "A funcionalidade de cópia Markdown está desativada"
+ },
+ "noMessages": {
+ "message": "Nenhuma mensagem encontrada"
+ },
+ "noContent": {
+ "message": "Nenhum conteúdo para copiar"
}
}
diff --git a/_locales/zh_TW/messages.json b/_locales/zh_TW/messages.json
index ee113e8..c169e63 100644
--- a/_locales/zh_TW/messages.json
+++ b/_locales/zh_TW/messages.json
@@ -510,5 +510,23 @@
},
"documentationUrl": {
"message": "https://docs.deepshare.app/en"
+ },
+ "aboutTabTitle": {
+ "message": "關於 DeepShare"
+ },
+ "versionLabel": {
+ "message": "版本:"
+ },
+ "documentationLabel": {
+ "message": "文件:"
+ },
+ "githubLabel": {
+ "message": "GitHub:"
+ },
+ "developerEmailLabel": {
+ "message": "開發者電子郵件:"
+ },
+ "acknowledgmentText": {
+ "message": "感謝所有為 DeepShare 提出建議的人!許多功能都源自真實用戶的需求。讓我們一起提升生產力,為生活中真正重要的事情節省時間。"
}
}
From 041fb2b06c313d49b1c0b2da525eceadca6fb6d8 Mon Sep 17 00:00:00 2001
From: DerYokoya <133297414+DerYokoya@users.noreply.github.com>
Date: Fri, 29 May 2026 23:13:45 -0400
Subject: [PATCH 06/11] spanish, french, japanese
---
_locales/es/messages.json | 18 ++++++++++++++++++
_locales/fr/messages.json | 18 ++++++++++++++++++
_locales/ja/messages.json | 18 ++++++++++++++++++
3 files changed, 54 insertions(+)
diff --git a/_locales/es/messages.json b/_locales/es/messages.json
index 1821ee8..0b8aba6 100644
--- a/_locales/es/messages.json
+++ b/_locales/es/messages.json
@@ -528,5 +528,23 @@
},
"scrollCollecting": {
"message": "Desplazando para recopilar mensajes, por favor espere..."
+ },
+ "copyAsMarkdown": {
+ "message": "Copiar como Markdown"
+ },
+ "markdownCopied": {
+ "message": "Markdown copiado al portapapeles"
+ },
+ "copyConversationMarkdown": {
+ "message": "Copiar todo como Markdown"
+ },
+ "featureDisabled": {
+ "message": "La función de copia de Markdown está desactivada"
+ },
+ "noMessages": {
+ "message": "No se encontraron mensajes"
+ },
+ "noContent": {
+ "message": "No hay contenido para copiar"
}
}
diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json
index a59efcf..fd34372 100644
--- a/_locales/fr/messages.json
+++ b/_locales/fr/messages.json
@@ -529,5 +529,23 @@
},
"scrollCollecting": {
"message": "Défilement en cours pour collecter les messages, veuillez patienter..."
+ },
+ "copyAsMarkdown": {
+ "message": "Copier en Markdown"
+ },
+ "markdownCopied": {
+ "message": "Markdown copié dans le presse-papiers"
+ },
+ "copyConversationMarkdown": {
+ "message": "Tout copier en Markdown"
+ },
+ "featureDisabled": {
+ "message": "La fonction de copie Markdown est désactivée"
+ },
+ "noMessages": {
+ "message": "Aucun message trouvé"
+ },
+ "noContent": {
+ "message": "Aucun contenu à copier"
}
}
diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json
index ee1c63c..2323fe6 100644
--- a/_locales/ja/messages.json
+++ b/_locales/ja/messages.json
@@ -528,5 +528,23 @@
},
"scrollCollecting": {
"message": "スクロールしてメッセージを収集しています。しばらくお待ちください..."
+ },
+ "copyAsMarkdown": {
+ "message": "Markdownとしてコピー"
+ },
+ "markdownCopied": {
+ "message": "Markdownをクリップボードにコピーしました"
+ },
+ "copyConversationMarkdown": {
+ "message": "すべてをMarkdownとしてコピー"
+ },
+ "featureDisabled": {
+ "message": "Markdownコピー機能は無効になっています"
+ },
+ "noMessages": {
+ "message": "メッセージが見つかりません"
+ },
+ "noContent": {
+ "message": "コピーする内容がありません"
}
}
From 22ed0beeb90c572792882a08b3bdb76f17db9903 Mon Sep 17 00:00:00 2001
From: DerYokoya <133297414+DerYokoya@users.noreply.github.com>
Date: Fri, 29 May 2026 23:17:18 -0400
Subject: [PATCH 07/11] german
---
_locales/de/messages.json | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/_locales/de/messages.json b/_locales/de/messages.json
index 5015072..9cbc064 100644
--- a/_locales/de/messages.json
+++ b/_locales/de/messages.json
@@ -529,5 +529,23 @@
},
"scrollCollecting": {
"message": "Nachrichten werden gesammelt, bitte warten..."
+ },
+ "copyAsMarkdown": {
+ "message": "Als Markdown kopieren"
+ },
+ "markdownCopied": {
+ "message": "Markdown in die Zwischenablage kopiert"
+ },
+ "copyConversationMarkdown": {
+ "message": "Alles als Markdown kopieren"
+ },
+ "featureDisabled": {
+ "message": "Die Markdown-Kopierfunktion ist deaktiviert"
+ },
+ "noMessages": {
+ "message": "Keine Nachrichten gefunden"
+ },
+ "noContent": {
+ "message": "Kein Inhalt zum Kopieren"
}
}
From 0ef1d88f0968d2c67def2e97f9d8d59e20faa70d Mon Sep 17 00:00:00 2001
From: DerYokoya <133297414+DerYokoya@users.noreply.github.com>
Date: Fri, 29 May 2026 23:18:43 -0400
Subject: [PATCH 08/11] Removed outdated feature that was for testing
---
scripts/copyDeepSeekMarkdown.js | 198 --------------------------------
1 file changed, 198 deletions(-)
diff --git a/scripts/copyDeepSeekMarkdown.js b/scripts/copyDeepSeekMarkdown.js
index 63239cb..cef02aa 100644
--- a/scripts/copyDeepSeekMarkdown.js
+++ b/scripts/copyDeepSeekMarkdown.js
@@ -245,79 +245,7 @@
return `${firstLine || 'deepseek'}_${timestamp}`;
}
- // Main save function
- async function saveAsMarkdown(copyButton) {
- if (!copyMarkdownSettings.enabled) {
- window.showToastNotification(chrome.i18n?.getMessage('featureDisabled') || 'Save as Markdown feature is disabled', 'info');
- return;
- }
-
- // Find the message container
- let messageDiv = copyButton.closest('._4f9bf79, ._9663006');
- if (!messageDiv) {
- console.error('Could not find message container');
- window.showToastNotification(chrome.i18n?.getMessage('saveFailed') || 'Failed to save', 'error');
- return;
- }
-
- const isAiMessage = messageDiv.matches('._4f9bf79');
- let markdownContent = '';
-
- if (isAiMessage) {
- const aiContent = extractAiResponseAsMarkdown(messageDiv);
- if (aiContent) {
- markdownContent = `## AI Response\n\n${aiContent}`;
- } else {
- markdownContent = await getContentViaCopyButton(copyButton);
- if (markdownContent) {
- markdownContent = `## AI Response\n\n${markdownContent}`;
- }
- }
- } else {
- const userContent = extractUserQuestionAsMarkdown(messageDiv);
- if (userContent) {
- markdownContent = `## User Question\n\n${userContent}`;
- }
- }
-
- if (markdownContent && markdownContent.trim()) {
- saveMarkdownFile(markdownContent);
- } else {
- window.showToastNotification(chrome.i18n?.getMessage('noContent') || 'No content to save', 'error');
- }
- }
-
- // Fallback: use copy button to get content
- async function getContentViaCopyButton(copyButton) {
- let originalClipboardContent = null;
- try {
- // Backup original clipboard
- try {
- originalClipboardContent = await navigator.clipboard.readText();
- } catch (e) {
- // Ignore - clipboard might be empty or permission not granted
- }
-
- // Click copy button
- copyButton.click();
- await new Promise(resolve => setTimeout(resolve, 300));
-
- // Get content
- const content = await navigator.clipboard.readText();
-
- // Restore original
- if (originalClipboardContent !== null) {
- try {
- await navigator.clipboard.writeText(originalClipboardContent);
- } catch (e) {}
- }
- return content;
- } catch (error) {
- console.error('Failed to get content via copy button:', error);
- return null;
- }
- }
// Copy entire conversation as markdown
async function saveConversationAsMarkdown() {
@@ -348,12 +276,8 @@
messageIndex++;
}
} else if (!isUserMessage && copyMarkdownSettings.includeAiResponse) {
- const copyButton = messageDiv.querySelector('.ds-icon-button[role="button"]');
let aiContent = extractAiResponseAsMarkdown(messageDiv);
- if (!aiContent && copyButton) {
- aiContent = await getContentViaCopyButton(copyButton);
- }
if (aiContent) {
conversationContent += `## Message ${messageIndex}: AI Response\n\n${aiContent}\n\n---\n\n`;
@@ -374,108 +298,6 @@
}
}
- // Inject markdown copy button next to existing copy button
- function injectMarkdownButton(copyButton, container) {
- if (container.querySelector('.deepseek-markdown-copy-btn')) return;
-
- const mdButton = document.createElement('div');
- mdButton.className = copyButton.className + ' deepseek-markdown-copy-btn';
- mdButton.tabIndex = copyButton.tabIndex || -1;
- mdButton.setAttribute('role', 'button');
- mdButton.setAttribute('aria-label', chrome.i18n?.getMessage('saveAsMarkdown') || 'Save as Markdown');
- mdButton.title = chrome.i18n?.getMessage('saveAsMarkdown') || 'Save as Markdown';
-
- // Copy styling
- const copyStyle = copyButton.getAttribute('style') || '';
- mdButton.style.cssText = copyStyle;
-
- // Create icon
- const iconHTML = `
-
-
- `;
- mdButton.innerHTML = iconHTML;
-
- // Insert after copy button
- copyButton.parentNode.insertBefore(mdButton, copyButton.nextSibling);
-
- // Add tooltip
- let tooltipWrapper = null;
- let floatingContainer = null;
-
- mdButton.addEventListener('mouseenter', () => {
- const tooltipText = mdButton.title;
- if (!tooltipText) return;
-
- if (!floatingContainer) {
- floatingContainer = document.querySelector('.ds-floating-container');
- if (!floatingContainer) {
- floatingContainer = document.createElement('div');
- floatingContainer.className = 'ds-floating-container';
- floatingContainer.style.zIndex = '9999';
- document.body.appendChild(floatingContainer);
- }
- }
-
- tooltipWrapper = document.createElement('div');
- tooltipWrapper.className = 'ds-floating-position-wrapper ds-theme';
- tooltipWrapper.style.zIndex = '10000';
-
- const tooltipElement = document.createElement('div');
- tooltipElement.className = 'ds-tooltip ds-tooltip--s ds-elevated ds-theme';
- tooltipElement.textContent = tooltipText;
-
- tooltipWrapper.appendChild(tooltipElement);
- floatingContainer.appendChild(tooltipWrapper);
-
- const btnRect = mdButton.getBoundingClientRect();
- tooltipWrapper.style.opacity = '0';
- const tooltipRect = tooltipWrapper.getBoundingClientRect();
- tooltipWrapper.style.opacity = '1';
-
- let top = btnRect.bottom + 4;
- let left = btnRect.left + (btnRect.width / 2) - (tooltipRect.width / 2);
- tooltipWrapper.setAttribute('data-transform-origin', 'bottom');
-
- if (left < 5) left = 5;
- if ((left + tooltipRect.width) > (window.innerWidth - 5)) {
- left = window.innerWidth - tooltipRect.width - 5;
- }
-
- tooltipWrapper.style.top = `${top}px`;
- tooltipWrapper.style.left = `${left}px`;
- });
-
- mdButton.addEventListener('mouseleave', () => {
- if (tooltipWrapper) {
- tooltipWrapper.remove();
- tooltipWrapper = null;
- }
- });
-
- // Click handler
- mdButton.addEventListener('click', async (e) => {
- e.stopPropagation();
-
- // Disable button during copy
- mdButton.style.opacity = '0.5';
- mdButton.style.pointerEvents = 'none';
-
- await saveAsMarkdown(copyButton);
-
- // Re-enable
- mdButton.style.opacity = '';
- mdButton.style.pointerEvents = '';
- });
- }
// Inject conversation markdown copy button in the share panel
function injectConversationMarkdownButton() {
@@ -516,26 +338,6 @@
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
- // Inject per-message markdown buttons
- const buttonContainers = document.querySelectorAll('.ds-flex[style*="align-items"][style*="gap"], div[class*="ds-flex"][style*="align-items: center"]');
-
- buttonContainers.forEach(container => {
- const buttonGroup = container.querySelector('.ds-flex[style*="align-items"][style*="gap"], div[class*="ds-flex"][style*="align-items"]') || container;
-
- const copyButtons = buttonGroup.querySelectorAll('.ds-icon-button[role="button"]');
-
- copyButtons.forEach(copyBtn => {
- // Check if this is an AI response (not user message)
- const isUserMessage = copyBtn.closest('.d29f3d7d, [class*="d29f3d7d"]');
- const isAIContainer = copyBtn.closest('._4f9bf79, [class*="_4f9bf79"]');
- const isAIResponse = isAIContainer && !isUserMessage;
-
- if (isAIResponse && !copyBtn.parentNode?.querySelector('.deepseek-markdown-copy-btn')) {
- injectMarkdownButton(copyBtn, buttonGroup);
- }
- });
- });
-
// Inject conversation-level markdown button
injectConversationMarkdownButton();
}
From bb19eb9244ba8ffe76da6fd6da44d12040938ab7 Mon Sep 17 00:00:00 2001
From: DerYokoya <133297414+DerYokoya@users.noreply.github.com>
Date: Fri, 29 May 2026 23:37:32 -0400
Subject: [PATCH 09/11] Restore button fix and DeepSeek save as markdown
---
scripts/copyDeepSeekMarkdown.js | 44 +--
styles/style.css | 462 ++++++++++++++++++++++++++++++++
2 files changed, 464 insertions(+), 42 deletions(-)
diff --git a/scripts/copyDeepSeekMarkdown.js b/scripts/copyDeepSeekMarkdown.js
index cef02aa..9e4b5e4 100644
--- a/scripts/copyDeepSeekMarkdown.js
+++ b/scripts/copyDeepSeekMarkdown.js
@@ -7,27 +7,6 @@
'use strict';
console.debug('DeepShare: Initializing DeepSeek Markdown copy functionality');
- // Load settings
- let copyMarkdownSettings = {
- enabled: true,
- includeUserQuestion: true,
- includeAiResponse: true
- };
-
- function loadSettings() {
- chrome.storage.sync.get({
- copyDeepSeekMarkdownEnabled: true,
- includeUserQuestion: true,
- includeAiResponse: true
- }, (settings) => {
- copyMarkdownSettings = {
- enabled: settings.copyDeepSeekMarkdownEnabled,
- includeUserQuestion: settings.includeUserQuestion,
- includeAiResponse: settings.includeAiResponse
- };
- });
- }
-
// Function to extract AI response as markdown
function extractAiResponseAsMarkdown(messageDiv) {
// Find the markdown content
@@ -249,11 +228,6 @@
// Copy entire conversation as markdown
async function saveConversationAsMarkdown() {
- if (!copyMarkdownSettings.enabled) {
- window.showToastNotification(chrome.i18n?.getMessage('featureDisabled') || 'Save as Markdown feature is disabled', 'info');
- return;
- }
-
// Find all messages
const messageSelector = '._9663006, ._4f9bf79._43c05b5, ._4f9bf79.d7dc56a8._43c05b5';
const messages = document.querySelectorAll(messageSelector);
@@ -269,13 +243,13 @@
for (const messageDiv of messages) {
const isUserMessage = messageDiv.matches('._9663006') || messageDiv.querySelector('.d29f3d7d');
- if (isUserMessage && copyMarkdownSettings.includeUserQuestion) {
+ if (isUserMessage) {
const userContent = extractUserQuestionAsMarkdown(messageDiv);
if (userContent) {
conversationContent += `## Message ${messageIndex}: User Question\n\n${userContent}\n\n---\n\n`;
messageIndex++;
}
- } else if (!isUserMessage && copyMarkdownSettings.includeAiResponse) {
+ } else if (!isUserMessage) {
let aiContent = extractAiResponseAsMarkdown(messageDiv);
@@ -333,8 +307,6 @@
// Observe and inject buttons
function observeAndInject() {
- loadSettings();
-
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
@@ -349,18 +321,6 @@
subtree: true
});
- // Listen for settings changes
- chrome.storage.onChanged.addListener((changes) => {
- if (changes.copyDeepSeekMarkdownEnabled) {
- copyMarkdownSettings.enabled = changes.copyDeepSeekMarkdownEnabled.newValue;
- }
- if (changes.includeUserQuestion) {
- copyMarkdownSettings.includeUserQuestion = changes.includeUserQuestion.newValue;
- }
- if (changes.includeAiResponse) {
- copyMarkdownSettings.includeAiResponse = changes.includeAiResponse.newValue;
- }
- });
}
// Initialize
diff --git a/styles/style.css b/styles/style.css
index b565f8b..41c91b8 100644
--- a/styles/style.css
+++ b/styles/style.css
@@ -1,3 +1,376 @@
+:root {
+ --modal-bg: #ffffff;
+ --modal-text: #333333;
+ --modal-border: #eeeeee;
+ --button-color: rgb(139, 139, 139);
+ --button-hover-bg: rgba(77, 107, 254, 0.1);
+ --button-hover-color: rgb(77, 107, 254);
+ --modal-overlay: rgba(0, 0, 0, 0.5);
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --modal-bg: #1e1e1e;
+ --modal-text: #e0e0e0;
+ --modal-border: #333333;
+ --button-color: rgb(173, 178, 184);
+ --button-hover-bg: rgba(77, 107, 254, 0.2);
+ --button-hover-color: rgb(107, 137, 254);
+ --modal-overlay: rgba(0, 0, 0, 0.7);
+ }
+}
+
+/* 分享按钮样式 */
+.deepseek-share-btn {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ /* 增加按钮之间的间距 */
+ margin-right: 8px;
+ /* 添加右边距 */
+}
+
+/* 按钮通用样式 */
+.deepseek-share-btn .share-button,
+.deepseek-share-btn .select-button {
+ background: none;
+ border: none;
+ cursor: pointer;
+ padding: 6px;
+ color: rgb(139, 139, 139);
+ border-radius: 6px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
+ transition: all 0.2s ease;
+}
+
+.deepseek-share-btn .share-button:hover,
+.deepseek-share-btn .select-button:hover {
+ background: rgba(139, 139, 139, 0.1);
+ color: rgb(139, 139, 139);
+ transform: scale(1.05);
+}
+
+.deepseek-share-btn .share-button:active {
+ transform: scale(0.95);
+}
+
+/* 深色模式覆盖 */
+@media (prefers-color-scheme: dark) {
+
+ .deepseek-share-btn .share-button,
+ .deepseek-share-btn .select-button {
+ color: rgb(173, 178, 184);
+ /* 深色模式下的颜色 */
+ }
+
+ .deepseek-share-btn .share-button:hover,
+ .deepseek-share-btn .select-button:hover {
+ background: rgba(173, 178, 184, 0.1);
+ /* 深色模式下的悬停背景色 */
+ color: rgb(98, 99, 99);
+ }
+}
+
+.select-button svg {
+ width: 23px;
+ /* 增加SVG图标大小 */
+ height: 23px;
+ min-width: 23px;
+ /* 确保最小尺寸 */
+ min-height: 23px;
+}
+
+.f8d1e4c0 {
+ position: relative;
+}
+
+.deepseek-share-modal {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: var(--modal-overlay);
+ z-index: 1000;
+}
+
+.deepseek-share-modal .modal-content {
+ background: var(--modal-bg);
+ color: var(--modal-text);
+ width: 46%;
+ min-width: 400px;
+ max-width: 1200px;
+ margin: 30px auto;
+ /* 减小顶部边距 */
+ border-radius: 12px;
+ /* 增加圆角 */
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+}
+
+.modal-header {
+ padding: 6px 20px;
+ border-bottom: 1px solid var(--modal-border);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.header-buttons {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.header-btn {
+ width: 32px;
+ height: 32px;
+ background: none;
+ border: none;
+ padding: 6px;
+ cursor: pointer;
+ color: var(--button-color);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 6px;
+ transition: all 0.2s ease;
+}
+
+.header-btn:hover {
+ background: var(--button-hover-bg);
+ color: var(--button-hover-color);
+}
+
+.header-btn:active {
+ transform: scale(0.95);
+}
+
+.modal-body {
+ padding: 17px 20px 20px 20px;
+ max-height: 80vh;
+ /* 增加最大高度 */
+ overflow-y: auto;
+}
+
+#conversation-content {
+ white-space: pre-wrap;
+ word-break: break-all;
+ color: var(--modal-text);
+}
+
+/* 标签页样式 */
+.tab-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+}
+
+.tab-container {
+ display: flex;
+ gap: 2px;
+ border-bottom: 1px solid var(--modal-border);
+ position: relative;
+}
+
+.tab-btn {
+ padding: 6px;
+ background: none;
+ border: none;
+ color: var(--modal-text);
+ cursor: pointer;
+ opacity: 0.7;
+ transition: all 0.2s;
+ min-width: 60px;
+ text-align: center;
+ position: relative;
+}
+
+.tab-btn.active {
+ opacity: 1;
+}
+
+.tab-indicator {
+ position: absolute;
+ bottom: -1px;
+ left: 0;
+ height: 2px;
+ background-color: var(--button-hover-color);
+ transition: transform 0.3s ease;
+ width: 60px;
+}
+
+.tab-btn[data-tab="text"].active~.tab-indicator {
+ transform: translateX(calc(100% + 2px));
+}
+
+.tab-btn[data-tab="image"].active~.tab-indicator {
+ transform: translateX(0);
+}
+
+/* 面板样式 */
+.tab-panel {
+ display: none;
+}
+
+.tab-panel.active {
+ display: block;
+}
+
+/* 文本容器样式 */
+#text-panel {
+ min-height: 200px;
+ max-height: 70vh;
+ overflow-y: auto;
+ border: 1px solid var(--modal-border);
+ border-radius: 8px;
+ background: var(--modal-bg);
+ position: relative;
+}
+
+#conversation-content {
+ white-space: pre-wrap;
+ word-break: break-all;
+ color: var(--modal-text);
+ padding: 16px;
+ margin: 0;
+}
+
+/* 图片容器样式 */
+.image-container {
+ min-height: 200px;
+ max-height: 70vh;
+ /* 增加图片容器最大高度 */
+ overflow-y: auto;
+ /* 移除底部间距 */
+ border: 1px solid var(--modal-border);
+ border-radius: 8px;
+ /* 增加图片容器圆角 */
+ background: var(--modal-bg);
+ position: relative;
+}
+
+#conversation-image {
+ width: 100%;
+ height: auto;
+ display: block;
+}
+
+.image-loading {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ color: var(--modal-text);
+}
+
+.action-buttons {
+ display: flex;
+ gap: 8px;
+}
+
+/* 按钮样式 */
+.download-btn,
+.copy-btn {
+ padding: 4px 10px;
+ font-size: 12px;
+ background: var(--button-hover-bg);
+ color: var(--button-hover-color);
+ border: 1px solid var(--button-hover-color);
+ border-radius: 4px;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.download-btn:hover,
+.copy-btn:hover {
+ background: var(--button-hover-color);
+ color: white;
+ opacity: 0.9;
+}
+
+/* 对话选择复选框样式 */
+.message-checkbox-wrapper {
+ position: absolute;
+ top: 3px;
+ right: 3px;
+}
+
+.message-checkbox {
+ appearance: none;
+ -webkit-appearance: none;
+ width: 18px;
+ height: 18px;
+ border: 2px solid var(--button-color);
+ border-radius: 50%;
+ cursor: pointer;
+ position: relative;
+ outline: none;
+ transition: all 0.2s ease;
+}
+
+.message-checkbox:checked {
+ background-color: var(--button-hover-color);
+ border-color: var(--button-hover-color);
+}
+
+.message-checkbox:checked::after {
+ content: '';
+ position: absolute;
+ top: 3px;
+ left: 3px;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: white;
+}
+
+.message-checkbox:hover {
+ border-color: var(--button-hover-color);
+}
+
+.select-all-btn,
+.select-all-responses-btn {
+ margin-right: 8px;
+ padding: 4px 12px;
+ background: none;
+ border: 1px solid var(--button-color);
+ cursor: pointer;
+ color: var(--button-color);
+ border-radius: 4px;
+ font-size: 13px;
+ height: 28px;
+ transition: all 0.2s ease;
+}
+
+.select-all-btn:hover,
+.select-all-responses-btn:hover {
+ background: var(--button-hover-bg);
+ color: var(--button-hover-color);
+ border-color: var(--button-hover-color);
+}
+
+@media (prefers-color-scheme: dark) {
+
+ .select-all-btn,
+ .select-all-responses-btn {
+ color: rgb(173, 178, 184);
+ border-color: rgb(173, 178, 184);
+ }
+
+ .select-all-btn:hover,
+ .select-all-responses-btn:hover {
+ background: var(--button-hover-bg);
+ color: var(--button-hover-color);
+ border-color: var(--button-hover-color);
+ }
+}
+
/* KaTeX copy functionality styles */
.katex {
position: relative;
@@ -46,6 +419,82 @@
}
}
+/* Show format selector when text tab is active */
+.tab-btn[data-tab="text"].active~.action-buttons .format-dropdown-container {
+ display: inline-block;
+}
+
+/* Format select dropdown styles */
+.format-dropdown-container {
+ position: relative;
+ display: inline-block;
+}
+
+.format-select {
+ appearance: none;
+ -webkit-appearance: none;
+ background: var(--modal-bg);
+ color: var(--modal-text);
+ border: 1px solid var(--modal-border);
+ border-radius: 4px;
+ padding: 4px 24px 4px 8px;
+ font-size: 13px;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ outline: none;
+}
+
+.format-select:hover {
+ border-color: var(--button-hover-color);
+ background: var(--button-hover-bg);
+}
+
+.format-select:focus {
+ border-color: var(--button-hover-color);
+ box-shadow: 0 0 0 2px rgba(77, 107, 254, 0.1);
+}
+
+/* Custom dropdown arrow */
+.format-dropdown-container::after {
+ content: '';
+ position: absolute;
+ right: 8px;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 0;
+ height: 0;
+ border-left: 4px solid transparent;
+ border-right: 4px solid transparent;
+ border-top: 4px solid var(--button-color);
+ pointer-events: none;
+ transition: all 0.2s ease;
+}
+
+.format-dropdown-container:hover::after {
+ border-top-color: var(--button-hover-color);
+}
+
+/* Dark mode adjustments */
+@media (prefers-color-scheme: dark) {
+ .format-select {
+ background: var(--modal-bg);
+ color: var(--modal-text);
+ border-color: var(--modal-border);
+ }
+
+ .format-select:hover {
+ background: var(--button-hover-bg);
+ }
+
+ .format-dropdown-container::after {
+ border-top-color: var(--button-color);
+ }
+
+ .format-dropdown-container:hover::after {
+ border-top-color: var(--button-hover-color);
+ }
+}
+
/* Tooltips for injected buttons (JS-controlled) */
.deepshare-gpt-tooltip {
position: fixed;
@@ -126,3 +575,16 @@
border-bottom-color: #000000;
}
}
+
+/* Compact the share panel button row so all buttons fit on one line */
+._43d222b .fab07e97 {
+ flex-wrap: nowrap;
+ gap: 6px !important;
+}
+
+._43d222b .fab07e97 .ds-basic-button {
+ padding: 4px 10px !important;
+ font-size: 12px !important;
+ min-width: unset !important;
+ white-space: nowrap;
+}
From 16e2e270687d12ad84ec03ee348790f14ef5e17b Mon Sep 17 00:00:00 2001
From: DerYokoya <133297414+DerYokoya@users.noreply.github.com>
Date: Fri, 29 May 2026 23:41:17 -0400
Subject: [PATCH 10/11] removing testing feature
---
popup/popup.html | 17 +----------------
1 file changed, 1 insertion(+), 16 deletions(-)
diff --git a/popup/popup.html b/popup/popup.html
index 2f566c5..6f130e8 100644
--- a/popup/popup.html
+++ b/popup/popup.html
@@ -433,23 +433,8 @@ Gemini
Include reference sources when exporting Gemini Deep
Research reports
-
-
-
- How long to wait for Gemini to load more history after each auto-scroll (3-10 seconds)
-
-
@@ -494,4 +479,4 @@