168 lines
5.9 KiB
Vue
168 lines
5.9 KiB
Vue
<script setup>
|
||
import { computed } from "vue";
|
||
import { SUBTITLE_FONT_OPTIONS } from "../../config/subtitleStylePresets.js";
|
||
|
||
const line = defineModel("line", { type: Object, required: true });
|
||
|
||
const enableBackground = computed({
|
||
get: () =>
|
||
line.value.backgroundColor &&
|
||
line.value.backgroundColor !== "transparent" &&
|
||
(line.value.backgroundOpacity ?? 0) > 0,
|
||
set: (on) => {
|
||
if (on) {
|
||
line.value.backgroundColor = line.value.backgroundColor || "#000000";
|
||
line.value.backgroundOpacity = line.value.backgroundOpacity || 0.5;
|
||
} else {
|
||
line.value.backgroundColor = "transparent";
|
||
line.value.backgroundOpacity = 0;
|
||
}
|
||
},
|
||
});
|
||
|
||
const backgroundOpacityPercent = computed({
|
||
get: () => Math.round((Number(line.value.backgroundOpacity) || 0) * 100),
|
||
set: (value) => {
|
||
line.value.backgroundOpacity = Math.max(0, Math.min(100, Number(value) || 0)) / 100;
|
||
},
|
||
});
|
||
|
||
const enableShadow = computed({
|
||
get: () => (line.value.shadowOffset ?? 0) > 0,
|
||
set: (on) => {
|
||
line.value.shadowOffset = on ? line.value.shadowOffset || 2 : 0;
|
||
},
|
||
});
|
||
|
||
const previewStyle = computed(() => {
|
||
const outline = Number(line.value.outlineWidth) || 0;
|
||
const offset = Number(line.value.shadowOffset) || 0;
|
||
const shadows = [];
|
||
if (outline > 0) {
|
||
const c = line.value.outlineColor || "#000";
|
||
for (let x = -outline; x <= outline; x++) {
|
||
for (let y = -outline; y <= outline; y++) {
|
||
if (x || y) shadows.push(`${x}px ${y}px 0 ${c}`);
|
||
}
|
||
}
|
||
}
|
||
if (offset > 0) {
|
||
shadows.push(`${offset}px ${offset}px 0 ${line.value.shadowColor || "#000"}`);
|
||
}
|
||
return {
|
||
fontFamily: line.value.fontName ? `'${line.value.fontName}'` : "优设标题黑",
|
||
fontSize: `${Number(line.value.fontSize) || 80}px`,
|
||
color: line.value.fontColor || "#fff",
|
||
backgroundColor:
|
||
enableBackground.value && line.value.backgroundColor !== "transparent"
|
||
? line.value.backgroundColor
|
||
: "transparent",
|
||
textShadow: shadows.join(", ") || "none",
|
||
padding: "8px 16px",
|
||
display: "inline-block",
|
||
lineHeight: 1.12,
|
||
};
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<div class="line-style-editor space-y-4 text-slate-800">
|
||
<div>
|
||
<div class="mb-2 text-sm font-medium text-slate-700">字体设置</div>
|
||
<div class="space-y-3">
|
||
<div>
|
||
<label class="mb-1 block text-xs text-slate-500">字体</label>
|
||
<Select
|
||
v-model="line.fontName"
|
||
:options="SUBTITLE_FONT_OPTIONS"
|
||
option-label="label"
|
||
option-value="value"
|
||
class="w-full"
|
||
size="small"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label class="mb-1 block text-xs text-slate-500">字体大小(像素)</label>
|
||
<InputNumber v-model="line.fontSize" :min="24" :max="120" class="w-full" size="small" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="mb-2 text-sm font-medium text-slate-700">颜色设置</div>
|
||
<div class="flex items-center gap-2">
|
||
<input v-model="line.fontColor" type="color" class="h-8 w-10" />
|
||
<span class="font-mono text-xs">{{ line.fontColor }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="mb-2 text-sm font-medium text-slate-700">描边设置</div>
|
||
<div class="space-y-2">
|
||
<div class="flex items-center gap-2">
|
||
<label class="text-xs text-slate-500">描边宽度</label>
|
||
<Slider v-model="line.outlineWidth" :min="0" :max="10" class="flex-1" />
|
||
<span class="w-8 text-right text-xs">{{ line.outlineWidth }}</span>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<label class="text-xs text-slate-500">描边颜色</label>
|
||
<input v-model="line.outlineColor" type="color" class="h-8 w-10" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="mb-2 text-sm font-medium text-slate-700">背景设置</div>
|
||
<label class="flex items-center gap-2 text-sm">
|
||
<Checkbox v-model="enableBackground" binary />
|
||
启用背景
|
||
</label>
|
||
<div v-if="enableBackground" class="mt-2 grid grid-cols-2 gap-3">
|
||
<div>
|
||
<label class="mb-1 block text-xs text-slate-500">背景颜色</label>
|
||
<div class="flex items-center gap-2">
|
||
<input v-model="line.backgroundColor" type="color" class="h-8 w-10" />
|
||
<InputText v-model="line.backgroundColor" size="small" class="flex-1" />
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<label class="mb-1 block text-xs text-slate-500">背景透明度</label>
|
||
<div class="flex items-center gap-2">
|
||
<Slider v-model="backgroundOpacityPercent" :min="0" :max="100" class="flex-1" />
|
||
<span class="w-10 text-right text-xs">{{ backgroundOpacityPercent }}%</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="mb-2 text-sm font-medium text-slate-700">阴影设置(可选)</div>
|
||
<label class="mb-2 flex items-center gap-2 text-sm">
|
||
<Checkbox v-model="enableShadow" binary />
|
||
启用阴影
|
||
</label>
|
||
<div v-if="enableShadow" class="space-y-2">
|
||
<div class="flex items-center gap-2">
|
||
<label class="text-xs text-slate-500">阴影偏移</label>
|
||
<Slider v-model="line.shadowOffset" :min="1" :max="10" class="flex-1" />
|
||
<span class="w-8 text-right text-xs">{{ line.shadowOffset }}</span>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<label class="text-xs text-slate-500">阴影颜色</label>
|
||
<input v-model="line.shadowColor" type="color" class="h-8 w-10" />
|
||
<InputText v-model="line.shadowColor" size="small" class="flex-1" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="mb-2 text-sm font-medium text-slate-700">效果预览</div>
|
||
<div class="overflow-hidden rounded bg-slate-100 py-4 text-center">
|
||
<div :style="previewStyle">
|
||
{{ line.text || "标题文字" }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|