11111
This commit is contained in:
158
src/components/subtitle/TitleSubtitleSettings.vue
Normal file
158
src/components/subtitle/TitleSubtitleSettings.vue
Normal file
@@ -0,0 +1,158 @@
|
||||
<script setup>
|
||||
import { computed, ref, watch } from "vue";
|
||||
import TitleLineStyleEditor from "./TitleLineStyleEditor.vue";
|
||||
import { syncTitleLinesFromReference } from "../../utils/subtitleTemplateDraft.js";
|
||||
|
||||
const config = defineModel("config", { type: Object, required: true });
|
||||
|
||||
const props = defineProps({
|
||||
referenceTitle: { type: String, default: "" },
|
||||
});
|
||||
|
||||
const titleConfig = computed({
|
||||
get: () => config.value.titleSubtitleConfig,
|
||||
set: (v) => {
|
||||
config.value.titleSubtitleConfig = v;
|
||||
},
|
||||
});
|
||||
|
||||
const enabled = computed({
|
||||
get: () => titleConfig.value?.enabled !== false,
|
||||
set: (v) => {
|
||||
titleConfig.value.enabled = v;
|
||||
},
|
||||
});
|
||||
|
||||
const openLineIndex = ref(0);
|
||||
|
||||
const displayTitle = computed(
|
||||
() => props.referenceTitle?.trim() || titleConfig.value?.sourceTitle || "(暂无标题,请先在步骤 04 生成)",
|
||||
);
|
||||
|
||||
function reloadFromReference() {
|
||||
syncTitleLinesFromReference(
|
||||
{ config: config.value },
|
||||
props.referenceTitle || titleConfig.value?.sourceTitle,
|
||||
);
|
||||
}
|
||||
|
||||
const linePreviews = computed(() => titleConfig.value?.lines || []);
|
||||
|
||||
const maxCharMarks = [8, 12, 15, 20];
|
||||
|
||||
function markLeft(value) {
|
||||
return `${((value - 8) / (20 - 8)) * 100}%`;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => titleConfig.value?.maxCharsPerLine,
|
||||
() => {
|
||||
reloadFromReference();
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="title-subtitle-settings space-y-4 rounded-lg border border-slate-600/40 bg-slate-800/30 p-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<Checkbox v-model="enabled" binary />
|
||||
<span class="font-medium text-slate-100">标题字幕</span>
|
||||
</div>
|
||||
|
||||
<div v-if="enabled" class="space-y-4">
|
||||
<div>
|
||||
<div class="mb-2 text-xs text-slate-400">
|
||||
当前标题(自动读取步骤 04「标题标签关键词」生成结果):
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-2 rounded bg-slate-900/50 p-3">
|
||||
<div class="flex-1 text-sm text-slate-200">{{ displayTitle }}</div>
|
||||
<Button label="重新加载" size="small" severity="secondary" @click="reloadFromReference" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-28 shrink-0 text-sm text-slate-300">每行最大字符数:</div>
|
||||
<div class="relative flex-1 pb-5">
|
||||
<Slider
|
||||
v-model="titleConfig.maxCharsPerLine"
|
||||
:min="8"
|
||||
:max="20"
|
||||
:step="1"
|
||||
class="w-full"
|
||||
/>
|
||||
<div class="pointer-events-none absolute inset-x-0 top-6 text-xs text-slate-500">
|
||||
<span
|
||||
v-for="mark in maxCharMarks"
|
||||
:key="mark"
|
||||
class="absolute -translate-x-1/2"
|
||||
:style="{ left: markLeft(mark) }"
|
||||
>
|
||||
{{ mark }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-28 shrink-0 text-sm text-slate-300">行间距(%):</div>
|
||||
<InputNumber
|
||||
v-model="titleConfig.lineSpacingPercent"
|
||||
:min="3"
|
||||
:max="15"
|
||||
class="w-32"
|
||||
/>
|
||||
<span class="text-xs text-slate-500">相对于视频高度</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-28 shrink-0 text-sm text-slate-300">顶部边距(%):</div>
|
||||
<InputNumber
|
||||
v-model="titleConfig.topMarginPercent"
|
||||
:min="2"
|
||||
:max="20"
|
||||
class="w-32"
|
||||
/>
|
||||
<span class="text-xs text-slate-500">相对于视频高度</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="linePreviews.length">
|
||||
<div class="mb-2 text-xs text-slate-400">分行预览(共 {{ linePreviews.length }} 行)</div>
|
||||
<div class="space-y-1">
|
||||
<div
|
||||
v-for="(line, i) in linePreviews"
|
||||
:key="i"
|
||||
class="rounded bg-slate-900/40 px-2 py-1 text-sm text-slate-300"
|
||||
>
|
||||
<span class="text-slate-500">第{{ i + 1 }}行:</span>{{ line.text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="mb-2 text-sm font-medium text-slate-200">每行样式配置</div>
|
||||
<div class="space-y-2">
|
||||
<div
|
||||
v-for="(line, index) in titleConfig.lines"
|
||||
:key="index"
|
||||
class="overflow-hidden rounded-lg border border-slate-600/50"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="flex w-full items-center justify-between bg-slate-900/50 px-3 py-2 text-left text-sm text-slate-200 hover:bg-slate-900/70"
|
||||
@click="openLineIndex = openLineIndex === index ? -1 : index"
|
||||
>
|
||||
<span>第{{ index + 1 }}行:{{ line.text || "(空)" }}</span>
|
||||
<i
|
||||
class="pi text-xs"
|
||||
:class="openLineIndex === index ? 'pi-chevron-up' : 'pi-chevron-down'"
|
||||
/>
|
||||
</button>
|
||||
<div v-show="openLineIndex === index" class="border-t border-slate-600/40 bg-white p-3">
|
||||
<TitleLineStyleEditor v-model:line="titleConfig.lines[index]" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user