feat: 实现剧本创作与拆解前端工作台

This commit is contained in:
GouJ
2026-08-27 19:33:51 +08:00
parent edc003443f
commit 2ee6f049f6
56 changed files with 7597 additions and 2 deletions
+43
View File
@@ -0,0 +1,43 @@
<script setup lang="ts">
import {
DialogRoot,
DialogPortal,
DialogOverlay,
DialogContent,
DialogTitle,
DialogDescription,
DialogClose
} from 'reka-ui'
import { X } from '@lucide/vue'
/** 统一弹窗容器,Reka UI 负责焦点锁定、Escape 和无障碍语义。 */
defineProps<{ title: string; description: string; busy?: boolean }>()
const open = defineModel<boolean>('open', { default: false })
</script>
<template>
<DialogRoot v-model:open="open">
<slot name="trigger"></slot>
<DialogPortal>
<DialogOverlay class="dialog-overlay" />
<DialogContent
class="dialog-content"
@interact-outside="busy && $event.preventDefault()"
@escape-key-down="busy && $event.preventDefault()"
>
<div class="flex items-start justify-between gap-4">
<div>
<DialogTitle class="text-xl font-semibold">{{ title }}</DialogTitle
><DialogDescription class="mt-2 text-sm leading-6 text-muted">{{
description
}}</DialogDescription>
</div>
<DialogClose class="icon-button shrink-0" aria-label="关闭弹窗" :disabled="busy"
><X :size="18"
/></DialogClose>
</div>
<slot></slot>
</DialogContent>
</DialogPortal>
</DialogRoot>
</template>
+15
View File
@@ -0,0 +1,15 @@
<script setup lang="ts">
import { FileText } from '@lucide/vue'
/** 空数据与等待生成共用的轻量占位,不放入演示数据。 */
defineProps<{ title: string; description: string }>()
</script>
<template>
<div class="empty-state">
<FileText :size="28" :stroke-width="1.4" class="mb-4 text-muted" />
<h3 class="font-medium">{{ title }}</h3>
<p class="mt-2 max-w-md text-sm leading-6 text-muted">{{ description }}</p>
<div class="mt-5"><slot></slot></div>
</div>
</template>
+14
View File
@@ -0,0 +1,14 @@
<script setup lang="ts">
import { statusLabels } from '../../lib/format'
import type { ProjectStatus } from '../../features/projects/types'
/** 状态同时提供文字和颜色,避免只依赖色觉。 */
defineProps<{ status: string; label?: string }>()
</script>
<template>
<span class="status-badge" :data-status="status">
<span class="status-dot" aria-hidden="true"></span
>{{ label || statusLabels[status as ProjectStatus] || status }}
</span>
</template>
+4
View File
@@ -0,0 +1,4 @@
/** 公共 UI 的统一导出入口。 */
export { default as AppDialog } from './AppDialog.vue'
export { default as EmptyState } from './EmptyState.vue'
export { default as StatusBadge } from './StatusBadge.vue'