Skip to content

Commit 1e20168

Browse files
committed
feat: add toast notification and checkmark icon on copy success
Show a toast above the button with format-specific message (e.g. "已复制 Markdown 格式") and swap the copy icon to a checkmark, similar to volcengine docs.
1 parent 0e4b64d commit 1e20168

File tree

5 files changed

+60
-19
lines changed

5 files changed

+60
-19
lines changed

assets/js/copy-to-llm.js

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,15 @@
4646
});
4747
});
4848

49+
var toast = document.getElementById('copy-fulltext-toast');
50+
4951
function getSourceData() {
5052
var mdEl = document.getElementById('copy-fulltext-markdown');
5153
return {
5254
title: container.getAttribute('data-title') || '',
5355
url: container.getAttribute('data-url') || '',
54-
successText: container.getAttribute('data-success-text') || 'Copied',
56+
successMarkdown: container.getAttribute('data-success-markdown') || 'Copied as Markdown',
57+
successText: container.getAttribute('data-success-text') || 'Copied as plain text',
5558
markdown: mdEl ? mdEl.textContent : ''
5659
};
5760
}
@@ -90,32 +93,34 @@
9093
function copyContent(type) {
9194
var data = getSourceData();
9295
var text = '';
96+
var actualType = type;
9397

9498
if (type === 'markdown' && data && data.markdown) {
9599
text = '# ' + data.title + '\n\n' + data.markdown;
96100
if (data.url) {
97101
text += '\n\n---\nSource: ' + data.url;
98102
}
99103
} else {
104+
actualType = 'text';
100105
text = getPlainText();
101106
}
102107

103-
copyToClipboard(text, data);
108+
copyToClipboard(text, data, actualType);
104109
}
105110

106-
function copyToClipboard(text, data) {
111+
function copyToClipboard(text, data, type) {
107112
if (navigator.clipboard && navigator.clipboard.writeText) {
108113
navigator.clipboard.writeText(text).then(function () {
109-
showFeedback(data);
114+
showFeedback(data, type);
110115
}).catch(function () {
111-
fallbackCopy(text, data);
116+
fallbackCopy(text, data, type);
112117
});
113118
} else {
114-
fallbackCopy(text, data);
119+
fallbackCopy(text, data, type);
115120
}
116121
}
117122

118-
function fallbackCopy(text, data) {
123+
function fallbackCopy(text, data, type) {
119124
var textarea = document.createElement('textarea');
120125
textarea.value = text;
121126
textarea.style.position = 'fixed';
@@ -124,22 +129,28 @@
124129
textarea.select();
125130
try {
126131
document.execCommand('copy');
127-
showFeedback(data);
132+
showFeedback(data, type);
128133
} catch (e) {
129134
// silent fail
130135
}
131136
document.body.removeChild(textarea);
132137
}
133138

134-
function showFeedback(data) {
135-
var span = defaultBtn.querySelector('span');
136-
var original = span.textContent;
137-
var successText = (data && data.successText) || 'Copied';
138-
span.textContent = '✓ ' + successText;
139+
function showFeedback(data, type) {
140+
// Swap icon to checkmark
141+
var icon = defaultBtn.querySelector('i');
142+
icon.classList.replace('fa-copy', 'fa-check');
139143
defaultBtn.classList.add('copy-fulltext__btn--success');
144+
145+
// Show toast
146+
var toastText = type === 'markdown' ? data.successMarkdown : data.successText;
147+
toast.textContent = '✅ ' + toastText;
148+
toast.classList.add('copy-fulltext__toast--visible');
149+
140150
setTimeout(function () {
141-
span.textContent = original;
151+
icon.classList.replace('fa-check', 'fa-copy');
142152
defaultBtn.classList.remove('copy-fulltext__btn--success');
153+
toast.classList.remove('copy-fulltext__toast--visible');
143154
}, 2000);
144155
}
145156
})();

assets/scss/_copy-to-llm.scss

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,28 @@
5656
}
5757
}
5858

59+
&__toast {
60+
display: none;
61+
position: absolute;
62+
bottom: 100%;
63+
left: 50%;
64+
transform: translateX(-50%);
65+
margin-bottom: 0.5rem;
66+
padding: 0.5rem 0.75rem;
67+
background: $white;
68+
border: 1px solid $gray-300;
69+
border-radius: $border-radius;
70+
box-shadow: 0 4px 12px rgba($black, 0.1);
71+
font-size: 0.875rem;
72+
color: $gray-700;
73+
white-space: nowrap;
74+
z-index: 11;
75+
76+
&--visible {
77+
display: block;
78+
}
79+
}
80+
5981
&__dropdown {
6082
display: none;
6183
position: absolute;

i18n/en.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,8 @@ other = "Copy Markdown"
9191
[copy_plain_text]
9292
other = "Copy Text"
9393

94-
[copy_success]
95-
other = "Copied"
94+
[copy_success_markdown]
95+
other = "Copied as Markdown"
96+
97+
[copy_success_text]
98+
other = "Copied as plain text"

i18n/zh.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,8 @@ other = "复制 Markdown"
8585
[copy_plain_text]
8686
other = "复制文本"
8787

88-
[copy_success]
89-
other = "已复制"
88+
[copy_success_markdown]
89+
other = "已复制 Markdown 格式"
90+
91+
[copy_success_text]
92+
other = "已复制纯文本"

layouts/partials/copy-to-llm.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
<div class="copy-fulltext" id="copy-fulltext"
33
data-title="{{ .Title }}"
44
data-url="{{ .Permalink }}"
5-
data-success-text="{{ T "copy_success" }}">
5+
data-success-markdown="{{ T "copy_success_markdown" }}"
6+
data-success-text="{{ T "copy_success_text" }}">
67
<div class="copy-fulltext__main">
78
<button class="copy-fulltext__btn" id="copy-fulltext-default" title="{{ T "copy_full_text" }}">
89
<i class="fa-regular fa-copy"></i>
@@ -12,6 +13,7 @@
1213
<i class="fa-solid fa-chevron-up"></i>
1314
</button>
1415
</div>
16+
<div class="copy-fulltext__toast" id="copy-fulltext-toast"></div>
1517
<div class="copy-fulltext__dropdown" id="copy-fulltext-dropdown">
1618
<button class="copy-fulltext__option" data-copy-type="markdown">
1719
{{ T "copy_markdown" }}

0 commit comments

Comments
 (0)