更新ui
This commit is contained in:
parent
4798647b40
commit
c855cf5be7
@ -5,7 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>CrossSubtitle-AI</title>
|
<title>CrossSubtitle-AI</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-slate-950">
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script type="module" src="/src/main.ts"></script>
|
<script type="module" src="/src/main.ts"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
12
src/App.vue
12
src/App.vue
@ -240,12 +240,14 @@ async function handleExport(format: 'srt' | 'vtt' | 'ass') {
|
|||||||
<div class="toolbar-main">
|
<div class="toolbar-main">
|
||||||
<div class="toolbar-title">
|
<div class="toolbar-title">
|
||||||
<strong>CrossSubtitle</strong>
|
<strong>CrossSubtitle</strong>
|
||||||
<span>桌面字幕工作台</span>
|
|
||||||
<span class="credit-line">
|
<span class="credit-line">
|
||||||
作者:<a href="https://kuraa.cc" target="_blank" rel="noreferrer">kuraa</a> gpt5.4
|
by <a href="https://kuraa.cc" target="_blank" rel="noreferrer">kuraa</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="toolbar-actions">
|
<div class="toolbar-actions">
|
||||||
|
<button class="button secondary toggle-button" type="button" @click="showAdvanced = !showAdvanced">
|
||||||
|
{{ showAdvanced ? '收起' : '设置' }}
|
||||||
|
</button>
|
||||||
<button class="button" type="button" :disabled="pending" @click="handlePickFiles">
|
<button class="button" type="button" :disabled="pending" @click="handlePickFiles">
|
||||||
{{ pending ? '提交中...' : '添加任务' }}
|
{{ pending ? '提交中...' : '添加任务' }}
|
||||||
</button>
|
</button>
|
||||||
@ -254,7 +256,6 @@ async function handleExport(format: 'srt' | 'vtt' | 'ass') {
|
|||||||
|
|
||||||
<div class="workspace-toolbar">
|
<div class="workspace-toolbar">
|
||||||
<div class="toolbar-group">
|
<div class="toolbar-group">
|
||||||
<span class="group-title">任务参数</span>
|
|
||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<label class="field">
|
<label class="field">
|
||||||
<span>模式</span>
|
<span>模式</span>
|
||||||
@ -286,13 +287,10 @@ async function handleExport(format: 'srt' | 'vtt' | 'ass') {
|
|||||||
<input v-model="bilingualOutput" type="checkbox" />
|
<input v-model="bilingualOutput" type="checkbox" />
|
||||||
<span>双语导出</span>
|
<span>双语导出</span>
|
||||||
</label>
|
</label>
|
||||||
<button class="button secondary toggle-button" type="button" @click="showAdvanced = !showAdvanced">
|
|
||||||
{{ showAdvanced ? '隐藏高级设置' : '显示高级设置' }}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="feedback status-text">{{ feedback }}</p>
|
<p v-if="feedback" class="feedback status-text">{{ feedback }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="showAdvanced" class="advanced-shell">
|
<div v-if="showAdvanced" class="advanced-shell">
|
||||||
|
|||||||
@ -7,6 +7,15 @@ const props = defineProps<{
|
|||||||
logs: string[]
|
logs: string[]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const isProcessing = computed(() => {
|
||||||
|
if (!props.task) return false
|
||||||
|
return !['completed', 'failed'].includes(props.task.status)
|
||||||
|
})
|
||||||
|
|
||||||
|
const canExport = computed(() => {
|
||||||
|
return props.task?.status === 'completed' && (props.task.segments?.length ?? 0) > 0
|
||||||
|
})
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
save: [segment: SubtitleSegment]
|
save: [segment: SubtitleSegment]
|
||||||
export: [format: 'srt' | 'vtt' | 'ass']
|
export: [format: 'srt' | 'vtt' | 'ass']
|
||||||
@ -44,19 +53,22 @@ function updateTranslatedText(segment: SubtitleSegment, value: string) {
|
|||||||
{{ task ? `${segments.length} 条片段` : '选择左侧任务后开始查看' }}
|
{{ task ? `${segments.length} 条片段` : '选择左侧任务后开始查看' }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="export-actions">
|
<div v-if="task" class="export-actions">
|
||||||
<button class="button secondary small" @click="emit('export', 'srt')">SRT</button>
|
<button class="button secondary small" :disabled="!canExport" @click="emit('export', 'srt')">SRT</button>
|
||||||
<button class="button secondary small" @click="emit('export', 'vtt')">VTT</button>
|
<button class="button secondary small" :disabled="!canExport" @click="emit('export', 'vtt')">VTT</button>
|
||||||
<button class="button secondary small" @click="emit('export', 'ass')">ASS</button>
|
<button class="button secondary small" :disabled="!canExport" @click="emit('export', 'ass')">ASS</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!task" class="empty-state">
|
<div v-if="!task" class="empty-state">
|
||||||
选择任务后显示字幕
|
<p>选择任务后显示字幕</p>
|
||||||
|
<p style="margin-top: 6px; font-size: 11px;">点击左侧任务列表中的任务开始查看</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="segments.length === 0" class="empty-state">
|
<div v-else-if="segments.length === 0" class="empty-state">
|
||||||
暂无字幕片段
|
<template v-if="isProcessing">正在处理中,请稍候...</template>
|
||||||
|
<template v-else-if="task?.status === 'failed'">任务处理失败,无法生成字幕</template>
|
||||||
|
<template v-else>暂无字幕片段</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="segment-list">
|
<div v-else class="segment-list">
|
||||||
@ -67,13 +79,14 @@ function updateTranslatedText(segment: SubtitleSegment, value: string) {
|
|||||||
>
|
>
|
||||||
<div class="task-row subtle">
|
<div class="task-row subtle">
|
||||||
<span>{{ formatTime(segment.start) }} - {{ formatTime(segment.end) }}</span>
|
<span>{{ formatTime(segment.start) }} - {{ formatTime(segment.end) }}</span>
|
||||||
<span>{{ segment.id }}</span>
|
<span class="segment-id">{{ segment.id }}</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="source-text">{{ segment.sourceText || '等待识别结果...' }}</p>
|
<p class="source-text">{{ segment.sourceText || '等待识别结果...' }}</p>
|
||||||
<textarea
|
<textarea
|
||||||
class="editor-input"
|
class="editor-input"
|
||||||
:value="segment.translatedText ?? ''"
|
:value="segment.translatedText ?? ''"
|
||||||
placeholder="译文"
|
:placeholder="task.outputMode === 'translate' ? '译文' : '原文'"
|
||||||
|
:disabled="task.outputMode === 'source'"
|
||||||
@change="updateTranslatedText(segment, ($event.target as HTMLTextAreaElement).value)"
|
@change="updateTranslatedText(segment, ($event.target as HTMLTextAreaElement).value)"
|
||||||
/>
|
/>
|
||||||
</article>
|
</article>
|
||||||
@ -81,9 +94,9 @@ function updateTranslatedText(segment: SubtitleSegment, value: string) {
|
|||||||
|
|
||||||
<div class="log-drawer" :class="{ expanded: logsExpanded }">
|
<div class="log-drawer" :class="{ expanded: logsExpanded }">
|
||||||
<button class="log-toggle" type="button" @click="logsExpanded = !logsExpanded">
|
<button class="log-toggle" type="button" @click="logsExpanded = !logsExpanded">
|
||||||
<span>运行日志</span>
|
<span>日志</span>
|
||||||
<span class="subtle">{{ logs.length }} 条</span>
|
<span class="subtle">{{ logs.length }}</span>
|
||||||
<span>{{ logsExpanded ? '收起' : '展开' }}</span>
|
<span class="log-chevron">{{ logsExpanded ? '−' : '+' }}</span>
|
||||||
</button>
|
</button>
|
||||||
<div v-if="logsExpanded" class="log-panel">
|
<div v-if="logsExpanded" class="log-panel">
|
||||||
<div v-if="logs.length === 0" class="empty-state">
|
<div v-if="logs.length === 0" class="empty-state">
|
||||||
|
|||||||
@ -25,8 +25,8 @@ const statusLabel: Record<SubtitleTask['status'], string> = {
|
|||||||
<aside class="panel sidebar-panel">
|
<aside class="panel sidebar-panel">
|
||||||
<div class="panel-title">
|
<div class="panel-title">
|
||||||
<div>
|
<div>
|
||||||
<strong>任务队列</strong>
|
<strong>任务</strong>
|
||||||
<p class="panel-subtitle">选择任务查看字幕和日志</p>
|
<p class="panel-subtitle">选择任务查看字幕</p>
|
||||||
</div>
|
</div>
|
||||||
<span class="badge">{{ tasks.length }}</span>
|
<span class="badge">{{ tasks.length }}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -40,16 +40,18 @@ const statusLabel: Record<SubtitleTask['status'], string> = {
|
|||||||
v-for="task in tasks"
|
v-for="task in tasks"
|
||||||
:key="task.id"
|
:key="task.id"
|
||||||
class="task-item"
|
class="task-item"
|
||||||
:class="{ active: task.id === selectedTaskId }"
|
:class="{
|
||||||
|
active: task.id === selectedTaskId,
|
||||||
|
completed: task.status === 'completed',
|
||||||
|
}"
|
||||||
@click="emit('select', task.id)"
|
@click="emit('select', task.id)"
|
||||||
>
|
>
|
||||||
<div class="task-row">
|
<div class="task-row">
|
||||||
<strong class="truncate">{{ task.fileName }}</strong>
|
<strong class="truncate">{{ task.fileName }}</strong>
|
||||||
<span>{{ Math.round(task.progress) }}%</span>
|
<span
|
||||||
</div>
|
class="subtle"
|
||||||
<div class="task-row subtle">
|
:class="{ 'status-active': task.status !== 'completed' && task.status !== 'failed' && task.status !== 'queued' }"
|
||||||
<span>{{ statusLabel[task.status] }}</span>
|
>{{ statusLabel[task.status] }}</span>
|
||||||
<span>{{ task.segments.length }} 条</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<div class="progress-bar" :style="{ width: `${task.progress}%` }" />
|
<div class="progress-bar" :style="{ width: `${task.progress}%` }" />
|
||||||
|
|||||||
384
src/style.css
384
src/style.css
@ -3,10 +3,33 @@
|
|||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
color: #111827;
|
--c-bg: #fafafa;
|
||||||
background: #eef1f5;
|
--c-surface: #ffffff;
|
||||||
font-family: "PingFang SC", "Helvetica Neue", Arial, sans-serif;
|
--c-border: #ebebeb;
|
||||||
line-height: 1.4;
|
--c-border-hover: #d4d4d4;
|
||||||
|
--c-text: #1a1a2e;
|
||||||
|
--c-text-secondary: #6b6b7b;
|
||||||
|
--c-text-tertiary: #9999a8;
|
||||||
|
--c-accent: #1a1a2e;
|
||||||
|
--c-accent-hover: #2a2a3e;
|
||||||
|
--c-focus: rgba(26, 26, 46, 0.08);
|
||||||
|
--c-progress: #1a1a2e;
|
||||||
|
--c-error: #dc2626;
|
||||||
|
--c-log-bg: #1a1a2e;
|
||||||
|
--c-log-text: #d4d4d4;
|
||||||
|
--radius-sm: 6px;
|
||||||
|
--radius-md: 10px;
|
||||||
|
--radius-lg: 14px;
|
||||||
|
--radius-full: 999px;
|
||||||
|
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
|
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
--transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
color: var(--c-text);
|
||||||
|
background: var(--c-bg);
|
||||||
|
font-family: "PingFang SC", "Helvetica Neue", -apple-system, BlinkMacSystemFont, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
@ -30,26 +53,57 @@ textarea {
|
|||||||
font: inherit;
|
font: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--c-border);
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
background-clip: content-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: var(--c-border-hover);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
background-clip: content-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
background: rgba(26, 26, 46, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
.app-shell {
|
.app-shell {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 1680px;
|
max-width: 1600px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 14px;
|
padding: 20px;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 14px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
background: linear-gradient(180deg, #ffffff 0%, #fbfcfe 100%);
|
background: var(--c-surface);
|
||||||
border: 1px solid #d9e0e8;
|
border: 1px solid var(--c-border);
|
||||||
border-radius: 12px;
|
border-radius: var(--radius-lg);
|
||||||
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.05);
|
box-shadow: var(--shadow-sm);
|
||||||
|
transition: box-shadow var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel:hover {
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.topbar {
|
.topbar {
|
||||||
padding: 14px 16px;
|
padding: 20px 24px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +114,7 @@ textarea {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 10px;
|
gap: 12px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,8 +130,9 @@ textarea {
|
|||||||
.panel-title strong,
|
.panel-title strong,
|
||||||
.workspace-header strong {
|
.workspace-header strong {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
color: #0f172a;
|
color: var(--c-text);
|
||||||
|
letter-spacing: -0.01em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-title span,
|
.toolbar-title span,
|
||||||
@ -85,8 +140,9 @@ textarea {
|
|||||||
.subtle,
|
.subtle,
|
||||||
.feedback,
|
.feedback,
|
||||||
.empty-state {
|
.empty-state {
|
||||||
color: #64748b;
|
color: var(--c-text-secondary);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.credit-line {
|
.credit-line {
|
||||||
@ -97,33 +153,37 @@ textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.credit-line a {
|
.credit-line a {
|
||||||
color: #0f172a;
|
color: var(--c-text);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
transition: border-color var(--transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.credit-line a:hover {
|
.credit-line a:hover {
|
||||||
text-decoration: underline;
|
border-bottom-color: var(--c-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-toolbar,
|
.workspace-toolbar,
|
||||||
.advanced-shell {
|
.advanced-shell {
|
||||||
margin-top: 12px;
|
margin-top: 16px;
|
||||||
padding-top: 12px;
|
padding-top: 16px;
|
||||||
border-top: 1px solid #e6ebf1;
|
border-top: 1px solid var(--c-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-title {
|
.group-title {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 10px;
|
||||||
color: #475569;
|
color: var(--c-text-secondary);
|
||||||
font-size: 12px;
|
font-size: 11px;
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-grid,
|
.form-grid,
|
||||||
.advanced-grid {
|
.advanced-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 10px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-grid {
|
.form-grid {
|
||||||
@ -139,12 +199,13 @@ textarea {
|
|||||||
.check {
|
.check {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 5px;
|
gap: 6px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field span {
|
.field span {
|
||||||
color: #475569;
|
color: var(--c-text-secondary);
|
||||||
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field input,
|
.field input,
|
||||||
@ -160,35 +221,53 @@ textarea {
|
|||||||
.field select,
|
.field select,
|
||||||
.editor-input {
|
.editor-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 34px;
|
min-height: 36px;
|
||||||
padding: 6px 9px;
|
padding: 8px 12px;
|
||||||
border: 1px solid #cfd8e3;
|
border: 1px solid var(--c-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--radius-sm);
|
||||||
background: #fff;
|
background: var(--c-surface);
|
||||||
color: #0f172a;
|
color: var(--c-text);
|
||||||
|
transition: border-color var(--transition), box-shadow var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.field input::placeholder,
|
||||||
|
.field select::placeholder,
|
||||||
|
.editor-input::placeholder {
|
||||||
|
color: var(--c-text-tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.field input:focus,
|
.field input:focus,
|
||||||
.field select:focus,
|
.field select:focus,
|
||||||
.editor-input:focus {
|
.editor-input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #94a3b8;
|
border-color: var(--c-accent);
|
||||||
box-shadow: 0 0 0 3px rgba(148, 163, 184, 0.16);
|
box-shadow: 0 0 0 3px var(--c-focus);
|
||||||
}
|
}
|
||||||
|
|
||||||
.check {
|
.check {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-height: 34px;
|
gap: 8px;
|
||||||
padding: 0 10px;
|
min-height: 36px;
|
||||||
border: 1px solid #d9e0e8;
|
padding: 0 12px;
|
||||||
border-radius: 8px;
|
border: 1px solid var(--c-border);
|
||||||
background: #f8fafc;
|
border-radius: var(--radius-sm);
|
||||||
|
background: var(--c-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transition: border-color var(--transition), background var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.check:hover {
|
||||||
|
border-color: var(--c-border-hover);
|
||||||
|
background: var(--c-surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
.check input {
|
.check input {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
accent-color: var(--c-accent);
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.desktop-check {
|
.desktop-check {
|
||||||
@ -200,50 +279,57 @@ textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
min-height: 34px;
|
min-height: 36px;
|
||||||
padding: 0 12px;
|
padding: 0 16px;
|
||||||
border: 1px solid #1f2937;
|
border: 1px solid var(--c-accent);
|
||||||
border-radius: 8px;
|
border-radius: var(--radius-sm);
|
||||||
background: #1f2937;
|
background: var(--c-accent);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.15s ease, border-color 0.15s ease;
|
font-weight: 400;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
transition: background var(--transition), border-color var(--transition), transform 0.1s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:hover {
|
.button:hover {
|
||||||
background: #111827;
|
background: var(--c-accent-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:active {
|
||||||
|
transform: scale(0.98);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button.secondary {
|
.button.secondary {
|
||||||
background: #fff;
|
background: transparent;
|
||||||
color: #111827;
|
color: var(--c-text);
|
||||||
border-color: #cfd8e3;
|
border-color: var(--c-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button.secondary:hover {
|
.button.secondary:hover {
|
||||||
background: #f8fafc;
|
background: var(--c-bg);
|
||||||
|
border-color: var(--c-border-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button.small {
|
.button.small {
|
||||||
min-height: 30px;
|
min-height: 30px;
|
||||||
padding: 0 10px;
|
padding: 0 12px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:disabled {
|
.button:disabled {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
opacity: 0.6;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-text {
|
.status-text {
|
||||||
min-height: 18px;
|
min-height: 18px;
|
||||||
margin: 10px 0 0;
|
margin: 12px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-grid {
|
.content-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 320px minmax(0, 1fr);
|
grid-template-columns: 300px minmax(0, 1fr);
|
||||||
gap: 14px;
|
gap: 16px;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
@ -256,31 +342,33 @@ textarea {
|
|||||||
.sidebar-panel {
|
.sidebar-panel {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 12px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-panel {
|
.workspace-panel {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 14px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-width: 26px;
|
min-width: 24px;
|
||||||
height: 26px;
|
height: 24px;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
border-radius: 999px;
|
border-radius: var(--radius-full);
|
||||||
background: #e2e8f0;
|
background: var(--c-bg);
|
||||||
color: #334155;
|
color: var(--c-text-secondary);
|
||||||
font-size: 12px;
|
font-size: 11px;
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
|
border: 1px solid var(--c-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-state {
|
.empty-state {
|
||||||
padding: 14px 0;
|
padding: 20px 0;
|
||||||
|
color: var(--c-text-tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-stack,
|
.list-stack,
|
||||||
@ -305,16 +393,44 @@ textarea {
|
|||||||
.task-item,
|
.task-item,
|
||||||
.segment-item {
|
.segment-item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 10px;
|
padding: 12px 14px;
|
||||||
border: 1px solid #e3e8ef;
|
border: 1px solid var(--c-border);
|
||||||
border-radius: 10px;
|
border-radius: var(--radius-md);
|
||||||
background: #f8fafc;
|
background: var(--c-surface);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-item:hover,
|
||||||
|
.segment-item:hover {
|
||||||
|
border-color: var(--c-border-hover);
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-item.active {
|
.task-item.active {
|
||||||
border-color: #94a3b8;
|
border-color: var(--c-accent);
|
||||||
background: #eef2f7;
|
background: rgba(26, 26, 46, 0.03);
|
||||||
|
box-shadow: inset 0 0 0 1px var(--c-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-item.completed {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-item.completed::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
right: 12px;
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--c-success, #2d6a4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-item {
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.truncate {
|
.truncate {
|
||||||
@ -324,48 +440,57 @@ textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.progress {
|
.progress {
|
||||||
height: 4px;
|
height: 2px;
|
||||||
margin-top: 6px;
|
margin-top: 8px;
|
||||||
background: #dbe4ee;
|
background: var(--c-border);
|
||||||
border-radius: 999px;
|
border-radius: var(--radius-full);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: #334155;
|
background: var(--c-progress);
|
||||||
|
transition: width 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-text {
|
.error-text {
|
||||||
margin: 6px 0 0;
|
margin: 8px 0 0;
|
||||||
color: #b91c1c;
|
color: var(--c-error);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.export-actions {
|
.export-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 6px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.source-text {
|
.source-text {
|
||||||
margin: 8px 0;
|
margin: 10px 0;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #0f172a;
|
color: var(--c-text);
|
||||||
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-input {
|
.editor-input {
|
||||||
min-height: 64px;
|
min-height: 64px;
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-input:disabled {
|
||||||
|
background: var(--c-bg);
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-drawer {
|
.log-drawer {
|
||||||
margin-top: 12px;
|
margin-top: 16px;
|
||||||
border-top: 1px solid #e6ebf1;
|
border-top: 1px solid var(--c-border);
|
||||||
padding-top: 12px;
|
padding-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-toggle {
|
.log-toggle {
|
||||||
@ -375,12 +500,18 @@ textarea {
|
|||||||
grid-template-columns: 1fr auto auto;
|
grid-template-columns: 1fr auto auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 0 12px;
|
padding: 0 14px;
|
||||||
border: 1px solid #d9e0e8;
|
border: 1px solid var(--c-border);
|
||||||
border-radius: 10px;
|
border-radius: var(--radius-md);
|
||||||
background: #f8fafc;
|
background: var(--c-surface);
|
||||||
color: #0f172a;
|
color: var(--c-text);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: border-color var(--transition), background var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-toggle:hover {
|
||||||
|
border-color: var(--c-border-hover);
|
||||||
|
background: var(--c-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-panel {
|
.log-panel {
|
||||||
@ -390,10 +521,10 @@ textarea {
|
|||||||
.log-list {
|
.log-list {
|
||||||
max-height: 220px;
|
max-height: 220px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 10px;
|
padding: 14px;
|
||||||
border: 1px solid #dfe6ee;
|
border: 1px solid var(--c-border);
|
||||||
border-radius: 10px;
|
border-radius: var(--radius-md);
|
||||||
background: #0f172a;
|
background: var(--c-log-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-line {
|
.log-line {
|
||||||
@ -401,17 +532,72 @@ textarea {
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1.5;
|
line-height: 1.6;
|
||||||
color: #dbe4ee;
|
color: var(--c-log-text);
|
||||||
|
font-family: "SF Mono", "Fira Code", "Cascadia Code", monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-line + .log-line {
|
.log-line + .log-line {
|
||||||
margin-top: 4px;
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segment-id {
|
||||||
|
color: var(--c-text-tertiary);
|
||||||
|
font-family: "SF Mono", "Fira Code", monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-chevron {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 300;
|
||||||
|
color: var(--c-text-secondary);
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-button {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-item strong {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-item .subtle {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-item .status-active {
|
||||||
|
color: var(--c-accent);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segment-item {
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.segment-item:hover {
|
||||||
|
border-left-color: var(--c-border-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.segment-item .task-row {
|
||||||
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1360px) {
|
@media (max-width: 1360px) {
|
||||||
.content-grid {
|
.content-grid {
|
||||||
grid-template-columns: 300px minmax(0, 1fr);
|
grid-template-columns: 280px minmax(0, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-grid {
|
.form-grid {
|
||||||
|
|||||||
@ -4,14 +4,14 @@ export default {
|
|||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
ink: '#0f172a',
|
ink: '#1a1a2e',
|
||||||
mist: '#f8fafc',
|
mist: '#fafafa',
|
||||||
ember: '#c2410c',
|
ember: '#e85d04',
|
||||||
lagoon: '#0f766e',
|
lagoon: '#2d6a4f',
|
||||||
haze: '#dbeafe',
|
haze: '#f0f0f0',
|
||||||
},
|
},
|
||||||
boxShadow: {
|
boxShadow: {
|
||||||
float: '0 24px 60px rgba(15, 23, 42, 0.18)',
|
float: '0 8px 32px rgba(0, 0, 0, 0.08)',
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
display: ['"Avenir Next"', '"PingFang SC"', 'sans-serif'],
|
display: ['"Avenir Next"', '"PingFang SC"', 'sans-serif'],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user