mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-09 13:25:11 +00:00
Add ability to copy messages to clipboard from Obsidian Khoj chat
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { MarkdownRenderer, WorkspaceLeaf, request, requestUrl, setIcon } from 'obsidian';
|
import { MarkdownRenderer, WorkspaceLeaf, request, requestUrl, setIcon } from 'obsidian';
|
||||||
import { KhojSetting } from 'src/settings';
|
import { KhojSetting } from 'src/settings';
|
||||||
import { KhojPaneView } from 'src/pane_view';
|
import { KhojPaneView } from 'src/pane_view';
|
||||||
import { KhojView } from 'src/utils';
|
import { KhojView, createCopyParentText } from 'src/utils';
|
||||||
|
|
||||||
export interface ChatJsonResult {
|
export interface ChatJsonResult {
|
||||||
image?: string;
|
image?: string;
|
||||||
@@ -214,7 +214,7 @@ export class KhojChatView extends KhojPaneView {
|
|||||||
referenceExpandButton.innerHTML = expandButtonText;
|
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 message_time = this.formatDate(dt ?? new Date());
|
||||||
let emojified_sender = sender == "khoj" ? "🏮 Khoj" : "🤔 You";
|
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);
|
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
|
// Remove user-select: none property to make text selectable
|
||||||
chatMessageEl.style.userSelect = "text";
|
chatMessageEl.style.userSelect = "text";
|
||||||
|
|
||||||
|
|||||||
@@ -304,3 +304,32 @@ export async function populateHeaderPane(headerEl: Element, setting: KhojSetting
|
|||||||
export enum KhojView {
|
export enum KhojView {
|
||||||
CHAT = "khoj-chat-view",
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -416,6 +416,42 @@ span.khoj-nav-item-text {
|
|||||||
padding-left: 8px;
|
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) {
|
@media only screen and (max-width: 600px) {
|
||||||
div.khoj-header {
|
div.khoj-header {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
Reference in New Issue
Block a user