Add ability to copy messages to clipboard from Obsidian Khoj chat

This commit is contained in:
Debanjum Singh Solanky 2024-05-07 08:33:17 +08:00
parent 57f1c53214
commit 032ad3b521
3 changed files with 77 additions and 2 deletions

View file

@ -1,7 +1,7 @@
import { MarkdownRenderer, WorkspaceLeaf, request, requestUrl, setIcon } from 'obsidian';
import { KhojSetting } from 'src/settings';
import { KhojPaneView } from 'src/pane_view';
import { KhojView } from 'src/utils';
import { KhojView, createCopyParentText } from 'src/utils';
export interface ChatJsonResult {
image?: string;
@ -214,7 +214,7 @@ export class KhojChatView extends KhojPaneView {
referenceExpandButton.innerHTML = expandButtonText;
}
renderMessage(chatEl: Element, message: string, sender: string, dt?: Date, raw: boolean=false): Element {
renderMessage(chatEl: Element, message: string, sender: string, dt?: Date, raw: boolean=false, willReplace: boolean=true): Element {
let message_time = this.formatDate(dt ?? new Date());
let emojified_sender = sender == "khoj" ? "🏮 Khoj" : "🤔 You";
@ -236,6 +236,16 @@ export class KhojChatView extends KhojPaneView {
MarkdownRenderer.renderMarkdown(message, chat_message_body_text_el, '', null);
}
// Add a copy button to each chat message
if (willReplace === true) {
let copyButton = chatMessageEl.createEl('button');
copyButton.classList.add("copy-button");
copyButton.title = "Copy Message to Clipboard";
setIcon(copyButton, "copy-plus");
copyButton.addEventListener('click', createCopyParentText(message));
chat_message_body_text_el.append(copyButton);
}
// Remove user-select: none property to make text selectable
chatMessageEl.style.userSelect = "text";

View file

@ -304,3 +304,32 @@ export async function populateHeaderPane(headerEl: Element, setting: KhojSetting
export enum KhojView {
CHAT = "khoj-chat-view",
}
function copyParentText(event: MouseEvent, message: string, originalButton: string) {
const button = event.currentTarget as HTMLElement;
if (!button || !button?.parentNode?.textContent) return;
if (!!button.firstChild) button.removeChild(button.firstChild as HTMLImageElement);
const textContent = message ?? button.parentNode.textContent.trim();
navigator.clipboard.writeText(textContent).then(() => {
setIcon((button as HTMLElement), 'copy-check');
setTimeout(() => {
setIcon((button as HTMLElement), originalButton);
}, 1000);
}).catch((error) => {
console.error("Error copying text to clipboard:", error);
const originalButtonText = button.innerHTML;
button.innerHTML = "⛔️";
setTimeout(() => {
button.innerHTML = originalButtonText;
setIcon((button as HTMLElement), originalButton);
}, 2000);
});
return textContent;
}
export function createCopyParentText(message: string, originalButton: string = 'copy-plus') {
return function(event: MouseEvent) {
return copyParentText(event, message, originalButton);
}
}

View file

@ -416,6 +416,42 @@ span.khoj-nav-item-text {
padding-left: 8px;
}
/* Copy button */
button.copy-button {
border-radius: 4px;
background-color: var(--background-color);
border: 1px solid var(--main-text-color);
text-align: center;
font-size: 16px;
transition: all 0.5s;
cursor: pointer;
padding: 4px;
float: right;
}
button.copy-button span {
cursor: pointer;
display: inline-block;
position: relative;
transition: 0.5s;
}
img.copy-icon {
width: 16px;
height: 16px;
}
.you button.copy-button {
color: var(--text-on-accent);
}
.khoj button.copy-button {
color: var(--khoj-storm-grey);
}
.you button.copy-button:hover {
color: var(--khoj-storm-grey);
background: var(--text-on-accent);
}
.khoj button.copy-button:hover {
background: var(--text-on-accent);
}
@media only screen and (max-width: 600px) {
div.khoj-header {
display: grid;