TemplateDetails.vue 26.7 KB
Newer Older
LiangLiu's avatar
LiangLiu committed
1
<script setup>
LiangLiu's avatar
LiangLiu committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { showTemplateDetailModal,
        closeTemplateDetailModal,
        useTemplate,
        getTemplateFileUrl,
        onVideoLoaded,
        selectedTemplate,
        applyTemplateAudio,
        applyTemplateImage,
        applyTemplatePrompt,
        showImageZoom,
        copyPrompt,
        generateTemplateShareUrl,
        copyShareLink,
        shareTemplateToSocial,
         } from '../utils/other'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
LiangLiu's avatar
LiangLiu committed
19
import { ref, onMounted, onUnmounted } from 'vue'
LiangLiu's avatar
LiangLiu committed
20
21
22
23
24
25
26
27
28
29
const { t, locale } = useI18n()
const route = useRoute()
const router = useRouter()

// 添加响应式变量
const showDetails = ref(false)

// 获取图片素材
const getImageMaterials = () => {
    if (!selectedTemplate.value?.inputs?.input_image) return []
30
31
32
    const imageUrl = getTemplateFileUrl(selectedTemplate.value.inputs.input_image, 'images')
    if (!imageUrl) return []
    return [['input_image', imageUrl]]
LiangLiu's avatar
LiangLiu committed
33
34
35
36
37
}

// 获取音频素材
const getAudioMaterials = () => {
    if (!selectedTemplate.value?.inputs?.input_audio) return []
38
39
40
    const audioUrl = getTemplateFileUrl(selectedTemplate.value.inputs.input_audio, 'audios')
    if (!audioUrl) return []
    return [['input_audio', audioUrl]]
LiangLiu's avatar
LiangLiu committed
41
42
43
44
45
}

// 路由关闭功能
const closeWithRoute = () => {
    closeTemplateDetailModal()
LiangLiu's avatar
LiangLiu committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    // 只有当前路由是模板详情页面时才进行路由跳转
    // 如果在其他页面(如 generate)打开的弹窗,关闭时保持在原页面
    if (route.path.startsWith('/template/')) {
        // 从模板详情路由进入的,返回到上一页或首页
        if (window.history.length > 1) {
            router.go(-1)
        } else {
            router.push('/')
        }
    }
    // 如果不是模板详情路由,不做任何路由跳转,保持在当前页面
}

// 滚动到生成区域(仅在 generate 页面)
const scrollToCreationArea = () => {
LiangLiu's avatar
LiangLiu committed
61
62
63
64
65
66
    const creationArea = document.querySelector('#task-creator')
    if (creationArea) {
        creationArea.scrollIntoView({
            behavior: 'smooth',
            block: 'start'
        })
LiangLiu's avatar
LiangLiu committed
67
68
69
70
    }
}

// 包装 useTemplate 函数,在 generate 页面时滚动到生成区域
LiangLiu's avatar
LiangLiu committed
71
72
73
74
75
76
const handleUseTemplate = () => {
    const template = selectedTemplate.value
    if (!template) {
        return
    }
    void useTemplate(template)
LiangLiu's avatar
LiangLiu committed
77
78
79
80
81
82
    // 如果当前在 generate 页面,滚动到生成区域
    if (route.path === '/generate' || route.name === 'Generate') {
        // 等待 DOM 更新和展开动画完成
        setTimeout(() => {
            scrollToCreationArea()
        }, 300)
LiangLiu's avatar
LiangLiu committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
    }
}

// 键盘事件处理
const handleKeydown = (event) => {
    if (event.key === 'Escape' && showTemplateDetailModal.value) {
        closeWithRoute()
    }
}

// 生命周期钩子
onMounted(() => {
    document.addEventListener('keydown', handleKeydown)
})

onUnmounted(() => {
    document.removeEventListener('keydown', handleKeydown)
})
</script>
<template>
LiangLiu's avatar
LiangLiu committed
103
            <!-- 模板详情弹窗 - Apple 极简风格 -->
LiangLiu's avatar
LiangLiu committed
104
105
            <div v-cloak>
                <div v-if="showTemplateDetailModal"
LiangLiu's avatar
LiangLiu committed
106
                    class="fixed inset-0 bg-black/50 dark:bg-black/60 backdrop-blur-sm z-[60] flex items-center justify-center p-2 sm:p-1"
LiangLiu's avatar
LiangLiu committed
107
                    @click="closeWithRoute">
LiangLiu's avatar
LiangLiu committed
108
109
110
111
112
                    <div class="w-full h-full max-w-7xl max-h-[100vh] bg-white/95 dark:bg-[#1e1e1e]/95 backdrop-blur-[40px] backdrop-saturate-[180%] border border-black/10 dark:border-white/10 rounded-3xl shadow-[0_20px_60px_rgba(0,0,0,0.2)] dark:shadow-[0_20px_60px_rgba(0,0,0,0.6)] overflow-hidden flex flex-col" @click.stop>
                        <!-- 弹窗头部 - Apple 风格 -->
                        <div class="flex items-center justify-between px-8 py-5 border-b border-black/8 dark:border-white/8 bg-white/50 dark:bg-[#1e1e1e]/50 backdrop-blur-[20px]">
                            <h3 class="text-xl font-semibold text-[#1d1d1f] dark:text-[#f5f5f7] flex items-center gap-3 tracking-tight">
                                <i class="fas fa-star text-[color:var(--brand-primary)] dark:text-[color:var(--brand-primary-light)]"></i>
LiangLiu's avatar
LiangLiu committed
113
114
                                {{ t('templateDetail') }}
                            </h3>
LiangLiu's avatar
LiangLiu committed
115
116
117
118
119
                            <div class="flex items-center gap-2">
                                <button @click="closeWithRoute"
                                        class="w-9 h-9 flex items-center justify-center bg-white/80 dark:bg-[#2c2c2e]/80 border border-black/8 dark:border-white/8 text-[#86868b] dark:text-[#98989d] hover:text-red-500 dark:hover:text-red-400 hover:bg-white dark:hover:bg-[#3a3a3c] rounded-full transition-all duration-200 hover:scale-110 active:scale-100"
                                        :title="t('close')">
                                    <i class="fas fa-times text-sm"></i>
LiangLiu's avatar
LiangLiu committed
120
121
122
123
                                </button>
                            </div>
                        </div>

LiangLiu's avatar
LiangLiu committed
124
125
126
                        <!-- 主要内容区域 - Apple 风格 -->
                        <div class="flex-1 overflow-y-auto main-scrollbar">
                            <div class="grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-12 p-8 lg:p-12">
LiangLiu's avatar
LiangLiu committed
127
                                <!-- 左侧视频区域 -->
LiangLiu's avatar
LiangLiu committed
128
129
                                <div class="flex items-center justify-center">
                                    <div class="w-full max-w-[400px] aspect-[9/16] bg-black dark:bg-[#000000] rounded-2xl overflow-hidden shadow-[0_8px_24px_rgba(0,0,0,0.15)] dark:shadow-[0_8px_24px_rgba(0,0,0,0.5)]">
LiangLiu's avatar
LiangLiu committed
130
131
132
133
                                        <!-- 视频播放器 -->
                                        <video
                                            v-if="selectedTemplate?.outputs?.output_video"
                                            :src="getTemplateFileUrl(selectedTemplate.outputs.output_video,'videos')"
134
                                            :poster="selectedTemplate?.inputs?.input_image ? getTemplateFileUrl(selectedTemplate.inputs.input_image,'images') : undefined"
LiangLiu's avatar
LiangLiu committed
135
                                            class="w-full h-full object-contain"
LiangLiu's avatar
LiangLiu committed
136
137
138
                                            controls
                                            loop
                                            preload="metadata"
LiangLiu's avatar
LiangLiu committed
139
                                            @loadeddata="onVideoLoaded">
LiangLiu's avatar
LiangLiu committed
140
141
                                            {{ t('browserNotSupported') }}
                                        </video>
LiangLiu's avatar
LiangLiu committed
142
143
144
                                        <div v-else class="w-full h-full flex flex-col items-center justify-center bg-[#f5f5f7] dark:bg-[#1c1c1e]">
                                            <div class="w-16 h-16 rounded-full bg-black/5 dark:bg-white/5 flex items-center justify-center mb-4">
                                                <i class="fas fa-video text-3xl text-[#86868b] dark:text-[#98989d]"></i>
LiangLiu's avatar
LiangLiu committed
145
                                            </div>
LiangLiu's avatar
LiangLiu committed
146
                                            <p class="text-sm text-[#86868b] dark:text-[#98989d] tracking-tight">{{ t('videoNotAvailable') }}</p>
LiangLiu's avatar
LiangLiu committed
147
148
149
150
                                        </div>
                                    </div>
                                </div>

LiangLiu's avatar
LiangLiu committed
151
152
153
154
155
                                <!-- 右侧信息区域 - Apple 风格 -->
                                <div class="flex items-center justify-center">
                                    <div class="w-full max-w-[400px]">
                                        <!-- 标题 - Apple 风格 -->
                                        <h1 class="text-3xl sm:text-4xl font-semibold text-[#1d1d1f] dark:text-[#f5f5f7] mb-4 tracking-tight">
LiangLiu's avatar
LiangLiu committed
156
157
158
                                            {{ t('template') }}
                                        </h1>

LiangLiu's avatar
LiangLiu committed
159
160
                                        <!-- 描述 - Apple 风格 -->
                                        <p class="text-sm sm:text-base text-[#86868b] dark:text-[#98989d] mb-8 tracking-tight">
LiangLiu's avatar
LiangLiu committed
161
162
163
                                            {{ t('templateDescription') }}
                                        </p>

LiangLiu's avatar
LiangLiu committed
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
                                        <!-- 快速操作 - Apple 风格 -->
                                        <div class="grid grid-cols-2 gap-2 mb-8">
                                            <button @click="applyTemplateImage(selectedTemplate)"
                                                    class="flex items-center gap-2 p-3 bg-white/80 dark:bg-[#2c2c2e]/80 backdrop-blur-[20px] border border-black/8 dark:border-white/8 rounded-xl transition-all duration-200 hover:bg-white dark:hover:bg-[#3a3a3c] hover:border-[color:var(--brand-primary)]/30 dark:hover:border-[color:var(--brand-primary-light)]/30 hover:shadow-[0_4px_12px_rgba(var(--brand-primary-rgb),0.15)] dark:hover:shadow-[0_4px_12px_rgba(var(--brand-primary-light-rgb),0.2)] active:scale-[0.98]">
                                                <div class="w-8 h-8 flex items-center justify-center bg-[color:var(--brand-primary)]/10 dark:bg-[color:var(--brand-primary-light)]/15 rounded-lg flex-shrink-0">
                                                    <i class="fas fa-image text-sm text-[color:var(--brand-primary)] dark:text-[color:var(--brand-primary-light)]"></i>
                                                </div>
                                                <span class="text-xs font-medium text-[#1d1d1f] dark:text-[#f5f5f7] tracking-tight">{{ t('onlyUseImage') }}</span>
                                            </button>
                                            <button @click="applyTemplateAudio(selectedTemplate)"
                                                    class="flex items-center gap-2 p-3 bg-white/80 dark:bg-[#2c2c2e]/80 backdrop-blur-[20px] border border-black/8 dark:border-white/8 rounded-xl transition-all duration-200 hover:bg-white dark:hover:bg-[#3a3a3c] hover:border-[color:var(--brand-primary)]/30 dark:hover:border-[color:var(--brand-primary-light)]/30 hover:shadow-[0_4px_12px_rgba(var(--brand-primary-rgb),0.15)] dark:hover:shadow-[0_4px_12px_rgba(var(--brand-primary-light-rgb),0.2)] active:scale-[0.98]">
                                                <div class="w-8 h-8 flex items-center justify-center bg-[color:var(--brand-primary)]/10 dark:bg-[color:var(--brand-primary-light)]/15 rounded-lg flex-shrink-0">
                                                    <i class="fas fa-music text-sm text-[color:var(--brand-primary)] dark:text-[color:var(--brand-primary-light)]"></i>
                                                </div>
                                                <span class="text-xs font-medium text-[#1d1d1f] dark:text-[#f5f5f7] tracking-tight">{{ t('onlyUseAudio') }}</span>
                                            </button>
LiangLiu's avatar
LiangLiu committed
180
181
                                        </div>

LiangLiu's avatar
LiangLiu committed
182
183
184
185
186
187
                                        <!-- 操作按钮 - Apple 风格 -->
                                        <div class="space-y-2.5">
                                            <button @click="handleUseTemplate"
                                                    class="w-full rounded-full bg-[color:var(--brand-primary)] dark:bg-[color:var(--brand-primary-light)] border-0 px-6 py-3 text-[15px] font-semibold text-white hover:scale-[1.02] hover:shadow-[0_8px_24px_rgba(var(--brand-primary-rgb),0.35)] dark:hover:shadow-[0_8px_24px_rgba(var(--brand-primary-light-rgb),0.4)] active:scale-100 transition-all duration-200 ease-out tracking-tight flex items-center justify-center gap-2">
                                                <i class="fas fa-magic text-sm"></i>
                                                <span>{{ t('useTemplate') }}</span>
LiangLiu's avatar
LiangLiu committed
188
189
                                            </button>

LiangLiu's avatar
LiangLiu committed
190
191
192
193
                                            <button @click="copyShareLink(selectedTemplate?.task_id, 'template')"
                                                    class="w-full rounded-full bg-white dark:bg-[#3a3a3c] border border-black/8 dark:border-white/8 px-6 py-2.5 text-[15px] font-medium text-[#1d1d1f] dark:text-[#f5f5f7] hover:bg-white/80 dark:hover:bg-[#3a3a3c]/80 hover:border-black/12 dark:hover:border-white/12 hover:shadow-[0_4px_12px_rgba(0,0,0,0.1)] dark:hover:shadow-[0_4px_12px_rgba(0,0,0,0.3)] active:scale-[0.98] transition-all duration-200 tracking-tight flex items-center justify-center gap-2">
                                                <i class="fas fa-share-alt text-sm"></i>
                                                <span>{{ t('shareTemplate') }}</span>
LiangLiu's avatar
LiangLiu committed
194
195
                                            </button>

LiangLiu's avatar
LiangLiu committed
196
197
198
199
                                            <button @click="showDetails = !showDetails"
                                                    class="w-full rounded-full bg-white dark:bg-[#3a3a3c] border border-black/8 dark:border-white/8 px-6 py-2.5 text-[15px] font-medium text-[#1d1d1f] dark:text-[#f5f5f7] hover:bg-white/80 dark:hover:bg-[#3a3a3c]/80 hover:border-black/12 dark:hover:border-white/12 hover:shadow-[0_4px_12px_rgba(0,0,0,0.1)] dark:hover:shadow-[0_4px_12px_rgba(0,0,0,0.3)] active:scale-[0.98] transition-all duration-200 tracking-tight flex items-center justify-center gap-2">
                                                <i :class="showDetails ? 'fas fa-chevron-up' : 'fas fa-info-circle'" class="text-sm"></i>
                                                <span>{{ showDetails ? t('hideDetails') : t('showDetails') }}</span>
LiangLiu's avatar
LiangLiu committed
200
201
202
                                            </button>
                                        </div>

LiangLiu's avatar
LiangLiu committed
203
204
205
206
207
208
209
210
211
212
                                        <!-- 技术信息 - Apple 风格 -->
                                        <div class="text-center pt-6 mt-6 border-t border-black/8 dark:border-white/8">
                                            <a href="https://github.com/ModelTC/LightX2V"
                                               target="_blank"
                                               rel="noopener noreferrer"
                                               class="inline-flex items-center gap-2 text-sm text-[#86868b] dark:text-[#98989d] hover:text-[color:var(--brand-primary)] dark:hover:text-[color:var(--brand-primary-light)] transition-colors tracking-tight">
                                                <i class="fab fa-github text-base"></i>
                                                <span>{{ t('poweredByLightX2V') }}</span>
                                                <i class="fas fa-external-link-alt text-xs"></i>
                                            </a>
LiangLiu's avatar
LiangLiu committed
213
214
215
216
217
                                        </div>
                                    </div>
                                </div>
                            </div>

LiangLiu's avatar
LiangLiu committed
218
219
220
221
222
223
224
                            <!-- 详细信息面板 - Apple 风格 -->
                            <div v-if="showDetails && selectedTemplate" class="bg-[#f5f5f7] dark:bg-[#1c1c1e] border-t border-black/8 dark:border-white/8 py-12">
                                <div class="max-w-6xl mx-auto px-8">
                                    <!-- 输入素材标题 - Apple 风格 -->
                                    <h2 class="text-2xl font-semibold text-[#1d1d1f] dark:text-[#f5f5f7] flex items-center justify-center gap-3 mb-8 tracking-tight">
                                        <i class="fas fa-upload text-[color:var(--brand-primary)] dark:text-[color:var(--brand-primary-light)]"></i>
                                        <span>{{ t('inputMaterials') }}</span>
LiangLiu's avatar
LiangLiu committed
225
226
                                    </h2>

LiangLiu's avatar
LiangLiu committed
227
228
229
230
231
232
233
234
235
236
                                    <!-- 三个并列的分块卡片 - Apple 风格 -->
                                    <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
                                        <!-- 图片卡片 - Apple 风格 -->
                                        <div class="bg-white/80 dark:bg-[#2c2c2e]/80 backdrop-blur-[20px] border border-black/8 dark:border-white/8 rounded-2xl overflow-hidden transition-all duration-200 hover:bg-white dark:hover:bg-[#3a3a3c] hover:border-black/12 dark:hover:border-white/12 hover:shadow-[0_8px_24px_rgba(0,0,0,0.1)] dark:hover:shadow-[0_8px_24px_rgba(0,0,0,0.3)]">
                                            <!-- 卡片头部 -->
                                            <div class="flex items-center justify-between px-5 py-4 bg-[color:var(--brand-primary)]/5 dark:bg-[color:var(--brand-primary-light)]/10 border-b border-black/8 dark:border-white/8">
                                                <div class="flex items-center gap-3">
                                                    <i class="fas fa-image text-lg text-[color:var(--brand-primary)] dark:text-[color:var(--brand-primary-light)]"></i>
                                                    <h3 class="text-base font-semibold text-[#1d1d1f] dark:text-[#f5f5f7] tracking-tight">{{ t('image') }}</h3>
                                                </div>
LiangLiu's avatar
LiangLiu committed
237
238
                                                <button v-if="selectedTemplate?.inputs?.input_image"
                                                        @click="applyTemplateImage(selectedTemplate)"
LiangLiu's avatar
LiangLiu committed
239
                                                        class="w-8 h-8 flex items-center justify-center bg-[color:var(--brand-primary)]/10 dark:bg-[color:var(--brand-primary-light)]/15 border border-[color:var(--brand-primary)]/20 dark:border-[color:var(--brand-primary-light)]/20 text-[color:var(--brand-primary)] dark:text-[color:var(--brand-primary-light)] rounded-lg transition-all duration-200 hover:scale-110 active:scale-100"
LiangLiu's avatar
LiangLiu committed
240
                                                        :title="t('applyImage')">
LiangLiu's avatar
LiangLiu committed
241
                                                    <i class="fas fa-magic text-xs"></i>
LiangLiu's avatar
LiangLiu committed
242
243
                                                </button>
                                            </div>
LiangLiu's avatar
LiangLiu committed
244
245
246
247
248
249
250
                                            <!-- 卡片内容 -->
                                            <div class="p-6 min-h-[200px]">
                                                <div v-if="getImageMaterials().length > 0">
                                                    <div v-for="[inputName, url] in getImageMaterials()" :key="inputName"
                                                         class="rounded-xl overflow-hidden border border-black/8 dark:border-white/8 cursor-pointer hover:border-[color:var(--brand-primary)]/50 dark:hover:border-[color:var(--brand-primary-light)]/50 transition-all duration-200"
                                                         @click="showImageZoom(url)">
                                                        <img :src="url" :alt="inputName" class="w-full h-auto object-contain">
LiangLiu's avatar
LiangLiu committed
251
252
                                                    </div>
                                                </div>
LiangLiu's avatar
LiangLiu committed
253
254
255
256
                                                <div v-else class="flex flex-col items-center justify-center h-[150px]">
                                                    <i class="fas fa-image text-3xl text-[#86868b]/30 dark:text-[#98989d]/30 mb-3"></i>
                                                    <p class="text-sm text-[#86868b] dark:text-[#98989d] tracking-tight">{{ t('noImage') }}</p>
                                                </div>
LiangLiu's avatar
LiangLiu committed
257
258
259
                                            </div>
                                        </div>

LiangLiu's avatar
LiangLiu committed
260
261
262
263
264
265
266
267
                                        <!-- 音频卡片 - Apple 风格 -->
                                        <div class="bg-white/80 dark:bg-[#2c2c2e]/80 backdrop-blur-[20px] border border-black/8 dark:border-white/8 rounded-2xl overflow-hidden transition-all duration-200 hover:bg-white dark:hover:bg-[#3a3a3c] hover:border-black/12 dark:hover:border-white/12 hover:shadow-[0_8px_24px_rgba(0,0,0,0.1)] dark:hover:shadow-[0_8px_24px_rgba(0,0,0,0.3)]">
                                            <!-- 卡片头部 -->
                                            <div class="flex items-center justify-between px-5 py-4 bg-[color:var(--brand-primary)]/5 dark:bg-[color:var(--brand-primary-light)]/10 border-b border-black/8 dark:border-white/8">
                                                <div class="flex items-center gap-3">
                                                    <i class="fas fa-music text-lg text-[color:var(--brand-primary)] dark:text-[color:var(--brand-primary-light)]"></i>
                                                    <h3 class="text-base font-semibold text-[#1d1d1f] dark:text-[#f5f5f7] tracking-tight">{{ t('audio') }}</h3>
                                                </div>
LiangLiu's avatar
LiangLiu committed
268
269
                                                <button v-if="selectedTemplate?.inputs?.input_audio"
                                                        @click="applyTemplateAudio(selectedTemplate)"
LiangLiu's avatar
LiangLiu committed
270
                                                        class="w-8 h-8 flex items-center justify-center bg-[color:var(--brand-primary)]/10 dark:bg-[color:var(--brand-primary-light)]/15 border border-[color:var(--brand-primary)]/20 dark:border-[color:var(--brand-primary-light)]/20 text-[color:var(--brand-primary)] dark:text-[color:var(--brand-primary-light)] rounded-lg transition-all duration-200 hover:scale-110 active:scale-100"
LiangLiu's avatar
LiangLiu committed
271
                                                        :title="t('applyAudio')">
LiangLiu's avatar
LiangLiu committed
272
                                                    <i class="fas fa-magic text-xs"></i>
LiangLiu's avatar
LiangLiu committed
273
274
                                                </button>
                                            </div>
LiangLiu's avatar
LiangLiu committed
275
276
277
278
                                            <!-- 卡片内容 -->
                                            <div class="p-6 min-h-[200px]">
                                                <div v-if="getAudioMaterials().length > 0" class="space-y-4">
                                                    <div v-for="[inputName, url] in getAudioMaterials()" :key="inputName">
LiangLiu's avatar
LiangLiu committed
279
                                                        <audio :src="url" controls class="w-full rounded-xl"></audio>
LiangLiu's avatar
LiangLiu committed
280
281
282
283
284
                                                    </div>
                                                </div>
                                                <div v-else class="flex flex-col items-center justify-center h-[150px]">
                                                    <i class="fas fa-music text-3xl text-[#86868b]/30 dark:text-[#98989d]/30 mb-3"></i>
                                                    <p class="text-sm text-[#86868b] dark:text-[#98989d] tracking-tight">{{ t('noAudio') }}</p>
LiangLiu's avatar
LiangLiu committed
285
286
287
288
                                                </div>
                                            </div>
                                        </div>

LiangLiu's avatar
LiangLiu committed
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
                                        <!-- 提示词卡片 - Apple 风格 -->
                                        <div class="bg-white/80 dark:bg-[#2c2c2e]/80 backdrop-blur-[20px] border border-black/8 dark:border-white/8 rounded-2xl overflow-hidden transition-all duration-200 hover:bg-white dark:hover:bg-[#3a3a3c] hover:border-black/12 dark:hover:border-white/12 hover:shadow-[0_8px_24px_rgba(0,0,0,0.1)] dark:hover:shadow-[0_8px_24px_rgba(0,0,0,0.3)]">
                                            <!-- 卡片头部 -->
                                            <div class="flex items-center justify-between px-5 py-4 bg-[color:var(--brand-primary)]/5 dark:bg-[color:var(--brand-primary-light)]/10 border-b border-black/8 dark:border-white/8">
                                                <div class="flex items-center gap-3">
                                                    <i class="fas fa-file-alt text-lg text-[color:var(--brand-primary)] dark:text-[color:var(--brand-primary-light)]"></i>
                                                    <h3 class="text-base font-semibold text-[#1d1d1f] dark:text-[#f5f5f7] tracking-tight">{{ t('prompt') }}</h3>
                                                </div>
                                                <div class="flex items-center gap-1">
                                                    <button v-if="selectedTemplate?.params?.prompt"
                                                            @click="copyPrompt(selectedTemplate?.params?.prompt)"
                                                            class="w-8 h-8 flex items-center justify-center bg-[#86868b]/10 dark:bg-[#98989d]/15 border border-[#86868b]/20 dark:border-[#98989d]/20 text-[#86868b] dark:text-[#98989d] rounded-lg transition-all duration-200 hover:scale-110 active:scale-100"
                                                            :title="t('copy')">
                                                        <i class="fas fa-copy text-xs"></i>
                                                    </button>
                                                    <button v-if="selectedTemplate?.params?.prompt"
                                                            @click="applyTemplatePrompt(selectedTemplate)"
                                                            class="w-8 h-8 flex items-center justify-center bg-[color:var(--brand-primary)]/10 dark:bg-[color:var(--brand-primary-light)]/15 border border-[color:var(--brand-primary)]/20 dark:border-[color:var(--brand-primary-light)]/20 text-[color:var(--brand-primary)] dark:text-[color:var(--brand-primary-light)] rounded-lg transition-all duration-200 hover:scale-110 active:scale-100"
                                                            :title="t('applyPrompt')">
                                                        <i class="fas fa-magic text-xs"></i>
                                                    </button>
                                                </div>
LiangLiu's avatar
LiangLiu committed
311
                                            </div>
LiangLiu's avatar
LiangLiu committed
312
313
314
315
316
317
318
319
320
                                            <!-- 卡片内容 -->
                                            <div class="p-6 min-h-[200px]">
                                                <div v-if="selectedTemplate?.params?.prompt" class="bg-white/50 dark:bg-[#1e1e1e]/50 backdrop-blur-[10px] border border-black/6 dark:border-white/6 rounded-xl p-4">
                                                    <p class="text-sm text-[#1d1d1f] dark:text-[#f5f5f7] leading-relaxed tracking-tight break-words">{{ selectedTemplate.params.prompt }}</p>
                                                </div>
                                                <div v-else class="flex flex-col items-center justify-center h-[150px]">
                                                    <i class="fas fa-file-alt text-3xl text-[#86868b]/30 dark:text-[#98989d]/30 mb-3"></i>
                                                    <p class="text-sm text-[#86868b] dark:text-[#98989d] tracking-tight">{{ t('noPrompt') }}</p>
                                                </div>
LiangLiu's avatar
LiangLiu committed
321
322
323
324
325
326
327
328
329
330
331
332
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
</template>

<style scoped>
LiangLiu's avatar
LiangLiu committed
333
334
/* 所有样式已通过 Tailwind CSS 的 dark: 前缀在 template 中定义 */
/* Apple 风格极简黑白设计 */
LiangLiu's avatar
LiangLiu committed
335
</style>