Files
watermark-wizard/src/components/SettingsPanel.vue
Julian Freeman 6439759b04 support restore
2026-01-19 12:18:08 -04:00

244 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { useGalleryStore } from "../stores/gallery";
import { Settings, CheckSquare, Type, Palette, Copy, Eraser, PlusSquare, Brush, Sparkles, Trash2, RotateCw, RotateCcw } from 'lucide-vue-next';
import { computed } from "vue";
const store = useGalleryStore();
// Computed properties to handle "Get from Image OR Global" and "Set to Image" logic
const currentScale = computed({
get: () => store.selectedImage?.scale ?? store.watermarkSettings.scale,
set: (val) => {
if (store.selectedIndex >= 0) {
store.setImageSetting(store.selectedIndex, 'scale', val);
} else {
store.updateWatermarkSettings({ scale: val });
}
}
});
const currentOpacity = computed({
get: () => store.selectedImage?.opacity ?? store.watermarkSettings.opacity,
set: (val) => {
if (store.selectedIndex >= 0) {
store.setImageSetting(store.selectedIndex, 'opacity', val);
} else {
store.updateWatermarkSettings({ opacity: val });
}
}
});
const currentColor = computed({
get: () => store.selectedImage?.color ?? store.watermarkSettings.color,
set: (val) => {
if (store.selectedIndex >= 0) {
store.setImageSetting(store.selectedIndex, 'color', val);
} else {
store.updateWatermarkSettings({ color: val });
}
}
});
const applyAll = () => {
if (confirm("是否将当前设置(大小、透明度、颜色)应用到所有图片?")) {
store.applySettingsToAll();
}
};
</script>
<template>
<div class="h-full bg-gray-800 text-white flex flex-col w-80 border-l border-gray-700">
<!-- Mode Switcher Tabs -->
<div class="flex border-b border-gray-700">
<button
@click="store.editMode = 'add'"
class="flex-1 py-3 text-sm font-medium flex items-center justify-center gap-2 transition-colors"
:class="store.editMode === 'add' ? 'bg-gray-700 text-blue-400 border-b-2 border-blue-400' : 'text-gray-400 hover:bg-gray-750'"
>
<PlusSquare class="w-4 h-4" /> 添加
</button>
<button
@click="store.editMode = 'remove'"
class="flex-1 py-3 text-sm font-medium flex items-center justify-center gap-2 transition-colors"
:class="store.editMode === 'remove' ? 'bg-gray-700 text-red-400 border-b-2 border-red-400' : 'text-gray-400 hover:bg-gray-750'"
>
<Eraser class="w-4 h-4" /> 移除
</button>
</div>
<!-- Content Area -->
<div class="flex-1 overflow-y-auto p-4 flex flex-col gap-6">
<!-- ADD MODE SETTINGS -->
<div v-if="store.editMode === 'add'" class="flex flex-col gap-6">
<h2 class="text-lg font-bold flex items-center justify-between">
<div class="flex items-center gap-2">
<Settings class="w-5 h-5" />
水印设置
</div>
<button
@click="applyAll"
title="应用设置到所有图片"
class="bg-gray-700 hover:bg-gray-600 p-1.5 rounded text-xs text-blue-300 transition-colors flex items-center gap-1"
>
<Copy class="w-3 h-3" /> 全部
</button>
</h2>
<!-- Text Input -->
<div class="flex flex-col gap-2">
<label class="text-sm text-gray-400 uppercase tracking-wider font-semibold">水印内容</label>
<div class="flex gap-2">
<div class="relative flex-1">
<Type class="absolute left-3 top-2.5 w-4 h-4 text-gray-500" />
<input
type="text"
v-model="store.watermarkSettings.text"
class="w-full bg-gray-700 text-white pl-10 pr-3 py-2 rounded border border-gray-600 focus:border-blue-500 focus:outline-none"
placeholder="输入水印文字..."
/>
</div>
<button
@click="store.recalcAllWatermarks()"
class="bg-blue-600 hover:bg-blue-500 text-white p-2 rounded flex items-center justify-center transition-colors"
title="应用并重新计算所有图片布局"
>
<RotateCw class="w-4 h-4" />
</button>
</div>
</div>
<!-- Color Picker -->
<div class="flex flex-col gap-2">
<label class="text-sm text-gray-400 uppercase tracking-wider font-semibold">字体颜色</label>
<div class="flex items-center gap-2 bg-gray-700 p-2 rounded border border-gray-600">
<Palette class="w-4 h-4 text-gray-400" />
<input
type="color"
v-model="currentColor"
class="w-8 h-8 rounded cursor-pointer bg-transparent border-none p-0"
/>
<span class="text-xs text-gray-300 font-mono">{{ currentColor }}</span>
</div>
</div>
<!-- Controls -->
<div class="space-y-4">
<div>
<div class="flex justify-between mb-1">
<label class="text-xs text-gray-400">字体大小 (比例)</label>
<span class="text-xs text-gray-300">{{ (currentScale * 100).toFixed(1) }}%</span>
</div>
<input
type="range"
min="0.01"
max="0.20"
step="0.001"
v-model.number="currentScale"
class="w-full h-1 bg-gray-600 rounded-lg appearance-none cursor-pointer accent-blue-500"
/>
<p class="text-[10px] text-gray-500 mt-1">基于图片高度的比例</p>
</div>
<div>
<div class="flex justify-between mb-1">
<label class="text-xs text-gray-400">不透明度</label>
<span class="text-xs text-gray-300">{{ (currentOpacity * 100).toFixed(0) }}%</span>
</div>
<input
type="range"
min="0.1"
max="1.0"
step="0.01"
v-model.number="currentOpacity"
class="w-full h-1 bg-gray-600 rounded-lg appearance-none cursor-pointer accent-blue-500"
/>
</div>
</div>
<!-- Placement Info -->
<div class="flex flex-col gap-2">
<label class="text-sm text-gray-400 uppercase tracking-wider font-semibold">位置状态</label>
<div class="flex items-center gap-2 p-2 rounded bg-gray-700/50 border border-gray-600">
<div class="p-1 rounded bg-green-500/20 text-green-400">
<CheckSquare class="w-4 h-4" v-if="!store.selectedImage?.manualPosition" />
<div class="w-4 h-4" v-else></div>
</div>
<div class="flex-1">
<p class="text-sm font-medium text-gray-200" v-if="!store.selectedImage?.manualPosition">自动 (ZCA)</p>
<p class="text-sm font-medium text-blue-300" v-else>手动调整</p>
</div>
</div>
</div>
</div>
<!-- REMOVE MODE SETTINGS -->
<div v-else class="flex flex-col gap-6">
<h2 class="text-lg font-bold flex items-center gap-2 text-red-400">
<Brush class="w-5 h-5" />
魔法橡皮擦
</h2>
<!-- Auto Detect Controls -->
<div class="flex gap-2">
<button
@click="store.detectAllWatermarks()"
class="flex-1 bg-blue-600 hover:bg-blue-500 text-white py-2 rounded flex items-center justify-center gap-2 text-sm transition-colors"
>
<Sparkles class="w-4 h-4" /> 自动检测
</button>
<button
@click="store.selectedIndex >= 0 && store.clearMask(store.selectedIndex)"
class="bg-gray-700 hover:bg-gray-600 text-gray-300 px-3 rounded flex items-center justify-center transition-colors"
title="清空遮罩"
:disabled="store.selectedIndex < 0"
>
<Trash2 class="w-4 h-4" />
</button>
</div>
<p class="text-xs text-gray-400">涂抹想要移除的水印AI 将自动填充背景</p>
<div>
<div class="flex justify-between mb-1">
<label class="text-xs text-gray-400">画笔大小</label>
<span class="text-xs text-gray-300">{{ store.brushSettings.size }}px</span>
</div>
<input
type="range"
min="5"
max="100"
step="1"
v-model.number="store.brushSettings.size"
class="w-full h-1 bg-gray-600 rounded-lg appearance-none cursor-pointer accent-red-500"
/>
</div>
<div class="p-3 bg-red-900/20 border border-red-900/50 rounded text-xs text-red-200">
AI 修复功能已就绪
</div>
<button
@click="store.selectedIndex >= 0 && store.processInpainting(store.selectedIndex)"
class="w-full bg-red-600 hover:bg-red-500 text-white py-3 rounded font-bold shadow-lg transition-colors flex items-center justify-center gap-2"
:disabled="store.selectedIndex < 0"
>
<Eraser class="w-5 h-5" />
执行移除
</button>
<button
v-if="store.selectedImage && store.selectedImage.path !== store.selectedImage.originalPath"
@click="store.selectedIndex >= 0 && store.restoreImage(store.selectedIndex)"
class="w-full bg-gray-700 hover:bg-gray-600 text-gray-300 py-2 rounded text-sm transition-colors flex items-center justify-center gap-2"
>
<RotateCcw class="w-4 h-4" />
还原原图
</button>
</div>
</div>
</div>
</template>