fix(chat): Copy buttons working again
This commit is contained in:
@@ -42,7 +42,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: "JetBrains Mono", Consolas, Menlo, monospace;
|
font-family: "JetBrains Mono", Consolas, Menlo, monospace;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
font-size: 16px;
|
font-size: 14px;
|
||||||
background: var(--bg-primary);
|
background: var(--bg-primary);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
transition: background-color 0.2s, color 0.2s;
|
transition: background-color 0.2s, color 0.2s;
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
border-radius: 0.4rem;
|
border-radius: 0.4rem;
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
font-size: 1rem;
|
font-size: inherit;
|
||||||
background: var(--bg-input);
|
background: var(--bg-input);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
transition: background-color 0.2s, color 0.2s;
|
transition: background-color 0.2s, color 0.2s;
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
.submit {
|
.submit {
|
||||||
font-size: 1rem;
|
font-size: inherit;
|
||||||
grid-area: submit;
|
grid-area: submit;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0.8rem 2rem;
|
padding: 0.8rem 2rem;
|
||||||
@@ -229,19 +229,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.spinner {
|
.spinner {
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
background: #888;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
border: 3px solid var(--text-secondary);
|
|
||||||
border-top-color: transparent;
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
vertical-align: baseline;
|
box-sizing: border-box;
|
||||||
animation: spin 1s ease-in infinite;
|
animation: grow 1s ease-in infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes grow {
|
||||||
to {
|
0% {
|
||||||
transform: rotate(360deg);
|
transform: scale(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -250,7 +254,7 @@
|
|||||||
<div id="app" x-data="chatApp()" x-cloak>
|
<div id="app" x-data="chatApp()" x-cloak>
|
||||||
<div class="chat-container">
|
<div class="chat-container">
|
||||||
<!-- Messages -->
|
<!-- Messages -->
|
||||||
<div class="messages" x-ref="msgBox" @scroll="handleScroll">
|
<div class="messages" x-ref="msgBox" @click="onClickMessage" @scroll="handleScroll">
|
||||||
<template x-for="(msg, idx) in visibleMessages" :key="idx">
|
<template x-for="(msg, idx) in visibleMessages" :key="idx">
|
||||||
<div :class="msg.role === 'user' ? 'message user-message' : 'message system-message'">
|
<div :class="msg.role === 'user' ? 'message user-message' : 'message system-message'">
|
||||||
<template x-if="msg.role === 'user'">
|
<template x-if="msg.role === 'user'">
|
||||||
@@ -317,7 +321,7 @@
|
|||||||
You are a helpful AI assistant.
|
You are a helpful AI assistant.
|
||||||
Do not preach about implications, do not praise excessively.
|
Do not preach about implications, do not praise excessively.
|
||||||
Keep a critical mindset, do not assume blindly.
|
Keep a critical mindset, do not assume blindly.
|
||||||
When I ask for code, assume that I am a senior backend developer (do not mention that) and do not explain excessively, but and challenge my statements if I don't sound right, especially in coding.
|
When I ask for code, keep in mind that I am a senior backend developer (but do not mention that explicitly), and do not explain excessively, but and challenge my statements with better alternatives if I don't sound right, especially in coding.
|
||||||
Answer in valid markdown only, no exceptions.
|
Answer in valid markdown only, no exceptions.
|
||||||
`
|
`
|
||||||
.replace(/^\s+/gm, "")
|
.replace(/^\s+/gm, "")
|
||||||
@@ -341,19 +345,21 @@
|
|||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
this.historyItems = loadHistory();
|
this.historyItems = loadHistory();
|
||||||
// Delegate copy button clicks
|
|
||||||
this.$refs.msgBox.addEventListener("click", (e) => {
|
|
||||||
if (e.target.classList.contains("copy-btn")) {
|
|
||||||
const code = e.target.closest("pre").querySelector("code").innerText;
|
|
||||||
copyToClipboard(code);
|
|
||||||
const original = e.target.textContent;
|
|
||||||
e.target.textContent = "Copied!";
|
|
||||||
setTimeout(() => (e.target.textContent = original), 1200);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setTimeout(() => this.$refs.promptInput.focus(), 0);
|
setTimeout(() => this.$refs.promptInput.focus(), 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async onClickMessage(e) {
|
||||||
|
if (e.target.classList.contains("copy-btn")) {
|
||||||
|
const $btn = e.target;
|
||||||
|
const code = $btn.closest("pre").querySelector("code").innerText;
|
||||||
|
copyToClipboard(code);
|
||||||
|
|
||||||
|
const buttonText = $btn.textContent;
|
||||||
|
$btn.textContent = "Copied!";
|
||||||
|
setTimeout(() => ($btn.textContent = buttonText), 1200);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
get visibleMessages() {
|
get visibleMessages() {
|
||||||
return this.messages.filter((m) => m.role !== "system");
|
return this.messages.filter((m) => m.role !== "system");
|
||||||
},
|
},
|
||||||
@@ -455,10 +461,9 @@
|
|||||||
const md = markdownit({ html: false });
|
const md = markdownit({ html: false });
|
||||||
|
|
||||||
function renderMarkdown(markdown) {
|
function renderMarkdown(markdown) {
|
||||||
const $container = document.createElement("template");
|
const $placeholder = document.createElement("template");
|
||||||
$container.innerHTML = md.render(markdown);
|
$placeholder.innerHTML = md.render(markdown);
|
||||||
this.attachCopyButtons($container);
|
return $placeholder.innerHTML;
|
||||||
return $container.innerHTML;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chatWithOpenAI({ baseUrl = "https://api.openai.com/v1", onContent, onError, messages, signal, apiKey, model, extraHeaders = {}, ...rest }) {
|
async function chatWithOpenAI({ baseUrl = "https://api.openai.com/v1", onContent, onError, messages, signal, apiKey, model, extraHeaders = {}, ...rest }) {
|
||||||
|
|||||||
Reference in New Issue
Block a user