feat: 添加自定义终端背景html功能

This commit is contained in:
Baobhan Sith
2025-05-27 09:33:25 +08:00
parent 180a5f6182
commit e11cc66114
9 changed files with 268 additions and 119 deletions
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref } from 'vue';
import { ref, onMounted, onUnmounted, nextTick, reactive } from 'vue';
import { useI18n } from 'vue-i18n';
import type { TerminalTheme } from '../types/terminal-theme.types';
import StyleCustomizerUiTab from './style-customizer/StyleCustomizerUiTab.vue';
@@ -42,15 +42,102 @@ const handleResetUiTheme = async () => {
const modalRootRef = ref<HTMLDivElement | null>(null);
const headerRef = ref<HTMLElement | null>(null);
const dialogContentRef = ref<HTMLDivElement | null>(null);
const draggableState = reactive({
isDragging: false,
startX: 0,
startY: 0,
initialLeft: 0,
initialTop: 0,
});
onMounted(() => {
const headerElement = headerRef.value;
const dialogEl = dialogContentRef.value;
const rootEl = modalRootRef.value;
if (!headerElement || !dialogEl || !rootEl) {
// console.warn("Draggable elements not found for StyleCustomizer modal."); // 用于调试的可选日志
return;
}
nextTick(() => {
//确保对话框已渲染且其尺寸可用
if (dialogEl && rootEl) {
dialogEl.style.position = 'absolute'; // 使对话框在rootEl内绝对定位
const rootWidth = rootEl.clientWidth;
const rootHeight = rootEl.clientHeight;
const dialogWidth = dialogEl.offsetWidth;
const dialogHeight = dialogEl.offsetHeight;
// 使对话框居中
dialogEl.style.left = `${Math.max(0, (rootWidth - dialogWidth) / 2)}px`;
dialogEl.style.top = `${Math.max(0, (rootHeight - dialogHeight) / 2)}px`;
}
});
const onMouseDown = (event: MouseEvent) => {
if (!dialogEl) return;
event.preventDefault(); // 防止文本选择等默认行为
draggableState.isDragging = true;
draggableState.startX = event.clientX;
draggableState.startY = event.clientY;
draggableState.initialLeft = dialogEl.offsetLeft;
draggableState.initialTop = dialogEl.offsetTop;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
};
const onMouseMove = (event: MouseEvent) => {
if (!draggableState.isDragging || !dialogEl || !rootEl) return;
const dx = event.clientX - draggableState.startX;
const dy = event.clientY - draggableState.startY;
let newLeft = draggableState.initialLeft + dx;
let newTop = draggableState.initialTop + dy;
// 边界检查,使对话框保持在 modalRootRef (视口) 内
newLeft = Math.max(0, Math.min(newLeft, rootEl.clientWidth - dialogEl.offsetWidth));
newTop = Math.max(0, Math.min(newTop, rootEl.clientHeight - dialogEl.offsetHeight));
dialogEl.style.left = `${newLeft}px`;
dialogEl.style.top = `${newTop}px`;
};
const onMouseUp = () => {
if (!draggableState.isDragging) return;
draggableState.isDragging = false;
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
};
headerElement.addEventListener('mousedown', onMouseDown);
headerElement.style.cursor = 'move'; // 设置页眉鼠标样式为可拖动
onUnmounted(() => {
if (headerElement) {
headerElement.removeEventListener('mousedown', onMouseDown);
headerElement.style.cursor = ''; // 重置鼠标样式
}
// 清理全局监听器
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
});
});
</script>
<template>
<div ref="modalRootRef" class="fixed inset-0 bg-black/60 flex justify-center items-center z-[1000] p-2 md:p-4" @click.self="closeCustomizer">
<div class="bg-background text-foreground rounded-lg shadow-lg w-full h-full md:w-[90%] md:max-w-[800px] md:h-[85vh] md:max-h-[700px] flex flex-col overflow-hidden">
<header class="flex justify-between items-center px-4 py-3 border-b border-border bg-header flex-shrink-0">
<div ref="modalRootRef" class="fixed inset-0 z-[1000]" @click.self="closeCustomizer">
<div ref="dialogContentRef" class="bg-background text-foreground rounded-lg shadow-lg w-full h-full md:w-[90%] md:max-w-[800px] md:h-[85vh] md:max-h-[700px] flex flex-col overflow-hidden">
<header ref="headerRef" class="flex justify-between items-center px-4 py-3 border-b border-border bg-header flex-shrink-0">
<h2 class="m-0 text-lg md:text-xl text-foreground">{{ t('styleCustomizer.title') }}</h2>
<button @click="closeCustomizer" class="bg-transparent border-none text-2xl md:text-3xl leading-none cursor-pointer text-text-secondary px-2 py-1 rounded hover:text-foreground hover:bg-black/10">&times;</button>
</header>