feat: 添加自定义终端背景html功能
This commit is contained in:
@@ -12,10 +12,12 @@ const {
|
||||
terminalBackgroundImage,
|
||||
isTerminalBackgroundEnabled,
|
||||
currentTerminalBackgroundOverlayOpacity,
|
||||
terminalCustomHTML,
|
||||
} = storeToRefs(appearanceStore);
|
||||
|
||||
const localTerminalBackgroundEnabled = ref(true);
|
||||
const editableTerminalBackgroundOverlayOpacity = ref(0.5);
|
||||
const localTerminalCustomHTML = ref('');
|
||||
|
||||
const terminalBgFileInput = ref<HTMLInputElement | null>(null);
|
||||
const uploadError = ref<string | null>(null);
|
||||
@@ -23,6 +25,7 @@ const uploadError = ref<string | null>(null);
|
||||
const initializeEditableState = () => {
|
||||
localTerminalBackgroundEnabled.value = isTerminalBackgroundEnabled.value;
|
||||
editableTerminalBackgroundOverlayOpacity.value = currentTerminalBackgroundOverlayOpacity.value;
|
||||
localTerminalCustomHTML.value = terminalCustomHTML.value || '';
|
||||
uploadError.value = null;
|
||||
};
|
||||
|
||||
@@ -40,6 +43,13 @@ watch(currentTerminalBackgroundOverlayOpacity, (newValue) => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
watch(terminalCustomHTML, (newValue) => {
|
||||
if (localTerminalCustomHTML.value !== (newValue || '')) {
|
||||
localTerminalCustomHTML.value = newValue || '';
|
||||
}
|
||||
});
|
||||
|
||||
const handleTriggerTerminalBgUpload = () => {
|
||||
uploadError.value = null;
|
||||
terminalBgFileInput.value?.click();
|
||||
@@ -104,6 +114,17 @@ const handleSaveTerminalBackgroundOverlayOpacity = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleSaveCustomHTML = async () => {
|
||||
try {
|
||||
await appearanceStore.setTerminalCustomHTML(localTerminalCustomHTML.value);
|
||||
notificationsStore.addNotification({ type: 'success', message: t('styleCustomizer.customTerminalHTMLSaved') });
|
||||
} catch (error: any) {
|
||||
console.error("保存自定义终端 HTML 失败:", error);
|
||||
notificationsStore.addNotification({ type: 'error', message: t('styleCustomizer.customTerminalHTMLSaveFailed', { message: error.message }) });
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -171,6 +192,26 @@ const handleSaveTerminalBackgroundOverlayOpacity = async () => {
|
||||
<button @click="handleSaveTerminalBackgroundOverlayOpacity" class="px-3 py-1.5 text-sm border border-border rounded bg-header hover:bg-border transition duration-200 ease-in-out whitespace-nowrap">{{ t('common.save') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自定义终端背景 HTML -->
|
||||
<div class="mt-4 pt-4 border-t border-border/50">
|
||||
<label for="terminalCustomHTML" class="block text-sm font-medium text-foreground mb-1">{{ t('styleCustomizer.customTerminalHTML', '自定义终端背景 HTML') }}</label>
|
||||
<textarea
|
||||
id="terminalCustomHTML"
|
||||
v-model="localTerminalCustomHTML"
|
||||
rows="10"
|
||||
class="w-full p-2 border border-border rounded bg-input text-foreground focus:ring-primary focus:border-primary"
|
||||
:placeholder="t('styleCustomizer.customTerminalHTMLPlaceholder', '例如:<h1>Hello</h1>')"
|
||||
></textarea>
|
||||
<div class="mt-2 flex justify-end">
|
||||
<button
|
||||
@click="handleSaveCustomHTML"
|
||||
class="px-3 py-1.5 text-sm border border-border rounded bg-header hover:bg-border transition duration-200 ease-in-out whitespace-nowrap"
|
||||
>
|
||||
{{ t('common.save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="p-4 text-center text-text-secondary italic border border-dashed border-border/50 rounded-md">
|
||||
{{ t('styleCustomizer.terminalBgDisabled', '终端背景功能已禁用。') }}
|
||||
|
||||
@@ -57,10 +57,6 @@ brightMagenta: #ff55ff
|
||||
brightCyan: #55ffff
|
||||
brightWhite: #ffffff`;
|
||||
// Theme preview refs
|
||||
const originalModalRootBackgroundColor = ref<string | null>(null);
|
||||
const originalModalContentOpacity = ref<string | null>(null);
|
||||
const originalModalRootTransition = ref<string | null>(null);
|
||||
const originalModalContentTransition = ref<string | null>(null);
|
||||
|
||||
const initializeEditableState = () => {
|
||||
editableTerminalFontFamily.value = currentTerminalFontFamily.value;
|
||||
@@ -341,73 +337,6 @@ const handleFocusAndSelect = (event: FocusEvent) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handlePreviewButtonMouseDown = async (event: MouseEvent, themeToPreview: TerminalTheme) => {
|
||||
event.preventDefault();
|
||||
if (props.modalRootRef && themeToPreview._id) {
|
||||
const modalContentElement = props.modalRootRef.firstElementChild as HTMLElement;
|
||||
try {
|
||||
const themeData = await appearanceStore.loadTerminalThemeData(themeToPreview._id);
|
||||
if (!themeData) {
|
||||
console.error('Preview failed: Could not load theme data for', themeToPreview.name);
|
||||
return;
|
||||
}
|
||||
appearanceStore.startTerminalThemePreview(themeData);
|
||||
|
||||
if (originalModalRootBackgroundColor.value === null && modalContentElement) {
|
||||
originalModalRootBackgroundColor.value = window.getComputedStyle(props.modalRootRef).backgroundColor;
|
||||
originalModalRootTransition.value = props.modalRootRef.style.transition;
|
||||
originalModalContentOpacity.value = window.getComputedStyle(modalContentElement).opacity;
|
||||
originalModalContentTransition.value = modalContentElement.style.transition;
|
||||
}
|
||||
|
||||
props.modalRootRef.style.transition = 'background-color 0.05s ease-out, opacity 0.05s ease-out';
|
||||
props.modalRootRef.style.backgroundColor = 'transparent';
|
||||
if (modalContentElement) {
|
||||
modalContentElement.style.transition = 'opacity 0.05s ease-out';
|
||||
modalContentElement.style.opacity = '0';
|
||||
}
|
||||
|
||||
const restoreOnMouseUp = () => {
|
||||
appearanceStore.stopTerminalThemePreview();
|
||||
if (props.modalRootRef) {
|
||||
props.modalRootRef.style.backgroundColor = originalModalRootBackgroundColor.value || '';
|
||||
props.modalRootRef.style.transition = originalModalRootTransition.value || '';
|
||||
}
|
||||
if (modalContentElement) {
|
||||
modalContentElement.style.opacity = originalModalContentOpacity.value || '1';
|
||||
modalContentElement.style.transition = originalModalContentTransition.value || '';
|
||||
}
|
||||
originalModalRootBackgroundColor.value = null;
|
||||
originalModalContentOpacity.value = null;
|
||||
originalModalRootTransition.value = null;
|
||||
originalModalContentTransition.value = null;
|
||||
document.removeEventListener('mouseup', restoreOnMouseUp);
|
||||
const currentTargetButton = event.currentTarget as HTMLElement | null;
|
||||
if (currentTargetButton) {
|
||||
currentTargetButton.removeEventListener('mouseleave', restoreOnMouseUp);
|
||||
}
|
||||
};
|
||||
document.addEventListener('mouseup', restoreOnMouseUp, { once: true });
|
||||
const currentTargetButton = event.currentTarget as HTMLElement | null;
|
||||
if (currentTargetButton) {
|
||||
currentTargetButton.addEventListener('mouseleave', restoreOnMouseUp, { once: true });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error during theme preview:', error);
|
||||
appearanceStore.stopTerminalThemePreview();
|
||||
if (props.modalRootRef && modalContentElement) {
|
||||
props.modalRootRef.style.backgroundColor = originalModalRootBackgroundColor.value || '';
|
||||
props.modalRootRef.style.transition = originalModalRootTransition.value || '';
|
||||
modalContentElement.style.opacity = originalModalContentOpacity.value || '1';
|
||||
modalContentElement.style.transition = originalModalContentTransition.value || '';
|
||||
originalModalRootBackgroundColor.value = null;
|
||||
originalModalContentOpacity.value = null;
|
||||
originalModalRootTransition.value = null;
|
||||
originalModalContentTransition.value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Computed Properties
|
||||
const activeThemeName = computed(() => {
|
||||
@@ -543,15 +472,6 @@ watch(() => props.isEditingTheme, (isEditing) => {
|
||||
>
|
||||
{{ t('styleCustomizer.applyButton', 'Apply') }}
|
||||
</button>
|
||||
<button
|
||||
@mousedown="(event) => handlePreviewButtonMouseDown(event, theme)"
|
||||
:class="[
|
||||
'px-3 py-1.5 text-xs md:text-sm border rounded transition-colors duration-200 ease-in-out whitespace-nowrap',
|
||||
theme._id === activeTerminalThemeId?.toString() ? 'text-button-text border-white/30 bg-white/10 hover:bg-white/20 hover:border-white/50' : 'border-border bg-header text-foreground hover:bg-border hover:border-text-secondary'
|
||||
]"
|
||||
>
|
||||
{{ t('styleCustomizer.previewButton', 'Preview') }}
|
||||
</button>
|
||||
<button @click="handleEditTheme(theme)" :title="theme.isPreset ? t('styleCustomizer.editAsCopy', 'Edit as Copy') : t('common.edit')"
|
||||
:class="[
|
||||
'px-3 py-1.5 text-xs md:text-sm border rounded transition-colors duration-200 ease-in-out whitespace-nowrap disabled:opacity-60 disabled:cursor-not-allowed',
|
||||
|
||||
Reference in New Issue
Block a user