optimize copy feedback
This commit is contained in:
57
src/App.vue
57
src/App.vue
@@ -88,14 +88,6 @@ const deleteHistoryItem = (id: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyHistoryText = async (text: string) => {
|
|
||||||
try {
|
|
||||||
await navigator.clipboard.writeText(text);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Failed to copy history text: ', err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Logs Management
|
// Logs Management
|
||||||
const selectedLogId = ref<string | null>(null);
|
const selectedLogId = ref<string | null>(null);
|
||||||
const selectedLogItem = computed(() =>
|
const selectedLogItem = computed(() =>
|
||||||
@@ -116,6 +108,23 @@ const getLogSummary = (log: any) => {
|
|||||||
return 'JSON Data';
|
return 'JSON Data';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Universal Copy with Feedback
|
||||||
|
const activeCopyId = ref<string | null>(null);
|
||||||
|
|
||||||
|
const copyWithFeedback = async (text: string, id: string) => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
activeCopyId.value = id;
|
||||||
|
setTimeout(() => {
|
||||||
|
if (activeCopyId.value === id) {
|
||||||
|
activeCopyId.value = null;
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to copy text: ', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Profile Management
|
// Profile Management
|
||||||
const newProfileName = ref('');
|
const newProfileName = ref('');
|
||||||
const isSavingProfile = ref(false);
|
const isSavingProfile = ref(false);
|
||||||
@@ -197,7 +206,6 @@ const sourceText = ref('');
|
|||||||
const context = ref('');
|
const context = ref('');
|
||||||
const targetText = ref('');
|
const targetText = ref('');
|
||||||
const isTranslating = ref(false);
|
const isTranslating = ref(false);
|
||||||
const showCopyFeedback = ref(false);
|
|
||||||
|
|
||||||
interface Suggestion {
|
interface Suggestion {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -287,18 +295,6 @@ const clearSource = () => {
|
|||||||
evaluationResult.value = null;
|
evaluationResult.value = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyTarget = async () => {
|
|
||||||
try {
|
|
||||||
await navigator.clipboard.writeText(targetText.value);
|
|
||||||
showCopyFeedback.value = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
showCopyFeedback.value = false;
|
|
||||||
}, 2000);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Failed to copy text: ', err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const evaluateTranslation = async () => {
|
const evaluateTranslation = async () => {
|
||||||
if (!targetText.value) return;
|
if (!targetText.value) return;
|
||||||
|
|
||||||
@@ -776,8 +772,8 @@ const translate = async () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ml-auto flex items-center gap-2">
|
<div class="ml-auto flex items-center gap-2">
|
||||||
<button @click="copyTarget" class="p-1.5 hover:bg-slate-200 dark:hover:bg-slate-700 rounded-md transition-colors relative" title="复制结果">
|
<button @click="copyWithFeedback(targetText, 'main-target')" class="p-1.5 hover:bg-slate-200 dark:hover:bg-slate-700 rounded-md transition-colors relative" title="复制结果">
|
||||||
<Check v-if="showCopyFeedback" class="w-4 h-4 text-green-600" />
|
<Check v-if="activeCopyId === 'main-target'" class="w-4 h-4 text-green-600" />
|
||||||
<Copy v-else class="w-4 h-4 text-slate-500 dark:text-slate-400" />
|
<Copy v-else class="w-4 h-4 text-slate-500 dark:text-slate-400" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1008,10 +1004,11 @@ const translate = async () => {
|
|||||||
<h3 class="text-xs font-black text-slate-400 uppercase tracking-widest">{{ selectedHistoryItem.sourceLang.displayName }} (原文)</h3>
|
<h3 class="text-xs font-black text-slate-400 uppercase tracking-widest">{{ selectedHistoryItem.sourceLang.displayName }} (原文)</h3>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
@click="copyHistoryText(selectedHistoryItem.sourceText)"
|
@click="copyWithFeedback(selectedHistoryItem.sourceText, `history-source-${selectedHistoryItem.id}`)"
|
||||||
class="p-2 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-lg text-slate-400 transition-colors"
|
class="p-2 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-lg text-slate-400 transition-colors"
|
||||||
>
|
>
|
||||||
<Copy class="w-4 h-4" />
|
<Check v-if="activeCopyId === `history-source-${selectedHistoryItem.id}`" class="w-4 h-4 text-green-600" />
|
||||||
|
<Copy v-else class="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-slate-50 dark:bg-slate-800/30 p-6 rounded-2xl border border-slate-100 dark:border-slate-800 text-lg leading-relaxed text-slate-700 dark:text-slate-200 whitespace-pre-wrap">
|
<div class="bg-slate-50 dark:bg-slate-800/30 p-6 rounded-2xl border border-slate-100 dark:border-slate-800 text-lg leading-relaxed text-slate-700 dark:text-slate-200 whitespace-pre-wrap">
|
||||||
@@ -1038,10 +1035,11 @@ const translate = async () => {
|
|||||||
<h3 class="text-xs font-black text-blue-500/60 uppercase tracking-widest">{{ selectedHistoryItem.targetLang.displayName }} (译文)</h3>
|
<h3 class="text-xs font-black text-blue-500/60 uppercase tracking-widest">{{ selectedHistoryItem.targetLang.displayName }} (译文)</h3>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
@click="copyHistoryText(selectedHistoryItem.targetText)"
|
@click="copyWithFeedback(selectedHistoryItem.targetText, `history-target-${selectedHistoryItem.id}`)"
|
||||||
class="p-2 bg-blue-50 dark:bg-blue-900/30 hover:bg-blue-100 dark:hover:bg-blue-900/50 rounded-lg text-blue-600 dark:text-blue-400 transition-colors"
|
class="p-2 bg-blue-50 dark:bg-blue-900/30 hover:bg-blue-100 dark:hover:bg-blue-900/50 rounded-lg text-blue-600 dark:text-blue-400 transition-colors"
|
||||||
>
|
>
|
||||||
<Copy class="w-4 h-4" />
|
<Check v-if="activeCopyId === `history-target-${selectedHistoryItem.id}`" class="w-4 h-4 text-green-600" />
|
||||||
|
<Copy v-else class="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-blue-50/20 dark:bg-blue-900/10 p-6 rounded-2xl border border-blue-100/50 dark:border-blue-900/20 text-xl leading-relaxed font-medium text-slate-800 dark:text-slate-100 whitespace-pre-wrap shadow-sm">
|
<div class="bg-blue-50/20 dark:bg-blue-900/10 p-6 rounded-2xl border border-blue-100/50 dark:border-blue-900/20 text-xl leading-relaxed font-medium text-slate-800 dark:text-slate-100 whitespace-pre-wrap shadow-sm">
|
||||||
@@ -1385,10 +1383,11 @@ const translate = async () => {
|
|||||||
>{{ selectedLogItem.type === 'request' ? 'Request' : selectedLogItem.type === 'response' ? 'Response' : 'Error' }}</span>
|
>{{ selectedLogItem.type === 'request' ? 'Request' : selectedLogItem.type === 'response' ? 'Response' : 'Error' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
@click="copyHistoryText(typeof selectedLogItem.content === 'object' ? JSON.stringify(selectedLogItem.content, null, 2) : String(selectedLogItem.content))"
|
@click="copyWithFeedback(typeof selectedLogItem.content === 'object' ? JSON.stringify(selectedLogItem.content, null, 2) : String(selectedLogItem.content), `log-${selectedLogItem.id}`)"
|
||||||
class="flex items-center gap-2 px-3 py-2 text-xs font-medium text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800 rounded-lg transition-colors border border-slate-200 dark:border-slate-700"
|
class="flex items-center gap-2 px-3 py-2 text-xs font-medium text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800 rounded-lg transition-colors border border-slate-200 dark:border-slate-700"
|
||||||
>
|
>
|
||||||
<Copy class="w-4 h-4" />
|
<Check v-if="activeCopyId === `log-${selectedLogItem.id}`" class="w-4 h-4 text-green-600" />
|
||||||
|
<Copy v-else class="w-4 h-4" />
|
||||||
复制内容
|
复制内容
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user