sillyspec 3.8.5 → 3.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -6
- package/docs/.vitepress/config.mts +45 -0
- package/docs/.vitepress/dist/404.html +25 -0
- package/docs/.vitepress/dist/assets/app.YytxICdd.js +1 -0
- package/docs/.vitepress/dist/assets/chunks/framework.Czhw_PXq.js +19 -0
- package/docs/.vitepress/dist/assets/chunks/theme.DusTRZQk.js +1 -0
- package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.js +1 -0
- package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.lean.js +1 -0
- package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
- package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.js +15 -0
- package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.js +4 -0
- package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.js +4 -0
- package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.js +5 -0
- package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.js +28 -0
- package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.js +30 -0
- package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.lean.js +1 -0
- package/docs/.vitepress/dist/assets/style.DFTx90Kk.css +1 -0
- package/docs/.vitepress/dist/hashmap.json +1 -0
- package/docs/.vitepress/dist/index.html +28 -0
- package/docs/.vitepress/dist/sillyspec/commands.html +42 -0
- package/docs/.vitepress/dist/sillyspec/dashboard.html +31 -0
- package/docs/.vitepress/dist/sillyspec/file-io.html +28 -0
- package/docs/.vitepress/dist/sillyspec/getting-started.html +31 -0
- package/docs/.vitepress/dist/sillyspec/install.html +32 -0
- package/docs/.vitepress/dist/sillyspec/lifecycle.html +55 -0
- package/docs/.vitepress/dist/sillyspec/structure.html +57 -0
- package/docs/.vitepress/dist/vp-icons.css +1 -0
- package/docs/index.md +34 -0
- package/docs/sillyspec/commands.md +218 -0
- package/docs/sillyspec/dashboard.md +51 -0
- package/docs/sillyspec/file-io.md +34 -0
- package/docs/sillyspec/getting-started.md +61 -0
- package/docs/sillyspec/install.md +51 -0
- package/docs/sillyspec/lifecycle.md +146 -0
- package/docs/sillyspec/structure.md +62 -0
- package/package.json +11 -9
- package/packages/dashboard/dist/assets/index-Bh-GPjKY.css +1 -0
- package/packages/dashboard/dist/assets/index-CrCn5Gg6.js +17 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/package-lock.json +0 -220
- package/packages/dashboard/package.json +5 -8
- package/packages/dashboard/server/index.js +106 -255
- package/packages/dashboard/server/parser.js +29 -333
- package/packages/dashboard/server/watcher.js +131 -203
- package/packages/dashboard/src/App.vue +10 -181
- package/packages/dashboard/src/components/ActionBar.vue +42 -26
- package/packages/dashboard/src/components/CommandPalette.vue +65 -40
- package/packages/dashboard/src/components/DetailPanel.vue +53 -68
- package/packages/dashboard/src/components/LogStream.vue +33 -13
- package/packages/dashboard/src/components/PipelineStage.vue +8 -8
- package/packages/dashboard/src/components/PipelineView.vue +45 -80
- package/packages/dashboard/src/components/ProjectList.vue +45 -103
- package/packages/dashboard/src/components/StageBadge.vue +13 -13
- package/packages/dashboard/src/components/StepCard.vue +15 -15
- package/packages/dashboard/src/composables/useDashboard.js +6 -20
- package/packages/dashboard/src/composables/useKeyboard.js +4 -6
- package/packages/dashboard/src/main.js +1 -4
- package/packages/dashboard/src/style.css +17 -17
- package/src/index.js +12 -123
- package/src/init.js +227 -86
- package/src/setup.js +9 -1
- package/templates/archive.md +120 -0
- package/templates/brainstorm.md +170 -0
- package/{.claude/skills/sillyspec-commit/SKILL.md → templates/commit.md} +45 -29
- package/templates/continue.md +32 -0
- package/templates/execute.md +304 -0
- package/templates/explore.md +59 -0
- package/templates/export.md +21 -0
- package/templates/init.md +61 -0
- package/templates/plan.md +146 -0
- package/templates/quick.md +135 -0
- package/templates/scan-quick.md +49 -0
- package/templates/scan.md +156 -0
- package/templates/skills/playwright-e2e/SKILL.md +340 -0
- package/templates/status.md +75 -0
- package/templates/verify.md +236 -0
- package/templates/workspace-sync.md +99 -0
- package/templates/workspace.md +70 -0
- package/.claude/skills/sillyspec-archive/SKILL.md +0 -17
- package/.claude/skills/sillyspec-auto/SKILL.md +0 -77
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -17
- package/.claude/skills/sillyspec-continue/SKILL.md +0 -44
- package/.claude/skills/sillyspec-doctor/SKILL.md +0 -22
- package/.claude/skills/sillyspec-execute/SKILL.md +0 -17
- package/.claude/skills/sillyspec-explore/SKILL.md +0 -96
- package/.claude/skills/sillyspec-export/SKILL.md +0 -53
- package/.claude/skills/sillyspec-init/SKILL.md +0 -170
- package/.claude/skills/sillyspec-plan/SKILL.md +0 -52
- package/.claude/skills/sillyspec-propose/SKILL.md +0 -17
- package/.claude/skills/sillyspec-quick/SKILL.md +0 -17
- package/.claude/skills/sillyspec-resume/SKILL.md +0 -111
- package/.claude/skills/sillyspec-scan/SKILL.md +0 -17
- package/.claude/skills/sillyspec-state/SKILL.md +0 -54
- package/.claude/skills/sillyspec-status/SKILL.md +0 -17
- package/.claude/skills/sillyspec-verify/SKILL.md +0 -17
- package/.claude/skills/sillyspec-workspace/SKILL.md +0 -149
- package/.sillyspec/changes/archive/2026-04-08-derive-state/design.md +0 -97
- package/.sillyspec/changes/archive/2026-04-08-derive-state/plan.md +0 -51
- package/.sillyspec/changes/archive/2026-04-08-derive-state/proposal.md +0 -29
- package/.sillyspec/changes/archive/2026-04-08-derive-state/requirements.md +0 -34
- package/.sillyspec/changes/archive/2026-04-08-derive-state/tasks.md +0 -13
- package/.sillyspec/changes/archive/2026-04-08-derive-state/verify-result.md +0 -43
- package/.sillyspec/changes/auto-mode/design.md +0 -50
- package/.sillyspec/changes/auto-mode/proposal.md +0 -19
- package/.sillyspec/changes/auto-mode/requirements.md +0 -21
- package/.sillyspec/changes/auto-mode/tasks.md +0 -7
- package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +0 -199
- package/.sillyspec/changes/dashboard/design.md.braindraft +0 -206
- package/.sillyspec/changes/run-command-design/design.md +0 -1230
- package/.sillyspec/changes/unified-docs-design/design.md +0 -199
- package/.sillyspec/docs/sillyspec/scan/.gitkeep +0 -0
- package/.sillyspec/knowledge/INDEX.md +0 -8
- package/.sillyspec/knowledge/uncategorized.md +0 -3
- package/.sillyspec/projects/sillyspec.yaml +0 -3
- package/packages/dashboard/dist/assets/index-D1EVTLmc.js +0 -7446
- package/packages/dashboard/dist/assets/index-DGe8CqeP.css +0 -1
- package/packages/dashboard/public/logo.jpg +0 -0
- package/packages/dashboard/src/components/DocPreview.vue +0 -160
- package/packages/dashboard/src/components/DocTree.vue +0 -58
- package/packages/dashboard/src/components/ProjectOverview.vue +0 -178
- package/packages/dashboard/src/components/detail/DocsDetail.vue +0 -48
- package/packages/dashboard/src/components/detail/GitDetail.vue +0 -61
- package/packages/dashboard/src/components/detail/TechDetail.vue +0 -43
- package/src/derive.js +0 -147
- package/src/migrate.js +0 -117
- package/src/progress.js +0 -495
- package/src/run.js +0 -640
- package/src/stages/archive.js +0 -54
- package/src/stages/brainstorm.js +0 -239
- package/src/stages/doctor.js +0 -312
- package/src/stages/execute.js +0 -259
- package/src/stages/index.js +0 -35
- package/src/stages/plan.js +0 -259
- package/src/stages/propose.js +0 -115
- package/src/stages/quick.js +0 -64
- package/src/stages/scan.js +0 -141
- package/src/stages/status.js +0 -65
- package/src/stages/verify.js +0 -135
- /package/.sillyspec/{changes/brainstorm-archive → specs}/2026-04-05-dashboard-design.md +0 -0
- /package/{packages/dashboard → docs/.vitepress}/dist/favicon.jpg +0 -0
- /package/{logo.jpg → docs/.vitepress/dist/logo.jpg} +0 -0
- /package/{packages/dashboard → docs}/public/favicon.jpg +0 -0
- /package/{packages/dashboard/dist → docs/public}/logo.jpg +0 -0
|
@@ -1,73 +1,53 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="flex flex-col h-full" style="background: #
|
|
3
|
-
<!-- Header
|
|
4
|
-
<div class="px-6 pt-
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<n-tab name="docs">文档</n-tab>
|
|
12
|
-
</n-tabs>
|
|
13
|
-
</div>
|
|
2
|
+
<div class="flex flex-col h-full" style="background: #0E0E10;">
|
|
3
|
+
<!-- Header -->
|
|
4
|
+
<div class="px-6 pt-6 pb-4" style="border-bottom: 1px solid #1F1F22;">
|
|
5
|
+
<h2 class="text-[11px] font-semibold uppercase tracking-[0.2em] font-[JetBrains_Mono,monospace]" style="color: #525252;">
|
|
6
|
+
Pipeline
|
|
7
|
+
</h2>
|
|
8
|
+
<p v-if="project" class="text-[12px] mt-1.5 font-[JetBrains_Mono,monospace]" style="color: #8B8B8E;">
|
|
9
|
+
{{ project.name }} <span style="color: #2A2A2D;">/</span> <span style="color: #FBBF24;">{{ currentStage }}</span>
|
|
10
|
+
</p>
|
|
14
11
|
</div>
|
|
15
12
|
|
|
16
|
-
<!--
|
|
17
|
-
<div
|
|
18
|
-
<div v-if="project && currentStage" class="px-6 pt-4 pb-2">
|
|
19
|
-
<p class="text-[12px] font-[JetBrains_Mono,monospace]" style="color: #636366;">
|
|
20
|
-
<span style="color: #D97706;">{{ currentStage }}</span>
|
|
21
|
-
</p>
|
|
22
|
-
</div>
|
|
23
|
-
|
|
13
|
+
<!-- Stages -->
|
|
14
|
+
<div class="flex-1 overflow-y-auto px-6 py-5">
|
|
24
15
|
<!-- Empty state -->
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<div v-if="hasStage('verify')" class="flex items-center pl-[3px]"><div class="w-px h-4" style="background: #F0F0F3;" /></div>
|
|
35
|
-
<PipelineStage name="verify" title="验证" :steps="getStageSteps('verify')" :status="getStageStatus('verify')" :is-active="currentStage === 'verify'" :active-step="activeStep" @select-step="handleSelectStep" />
|
|
16
|
+
<div v-if="!project || !project.state" class="flex items-center justify-center h-full">
|
|
17
|
+
<div class="text-center">
|
|
18
|
+
<div class="w-14 h-14 mx-auto mb-4 rounded-md flex items-center justify-center" style="border: 1px dashed #2A2A2D; transform: rotate(45deg);">
|
|
19
|
+
<svg class="w-5 h-5" style="color: #525252; transform: rotate(-45deg);" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
20
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/>
|
|
21
|
+
</svg>
|
|
22
|
+
</div>
|
|
23
|
+
<p class="text-[12px] font-[JetBrains_Mono,monospace]" style="color: #525252;">Select a project</p>
|
|
24
|
+
</div>
|
|
36
25
|
</div>
|
|
37
26
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<div class="
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
<div class="
|
|
45
|
-
|
|
46
|
-
<n-timeline-item
|
|
47
|
-
v-for="(log, i) in activityLogs"
|
|
48
|
-
:key="i"
|
|
49
|
-
:type="log.status === 'completed' ? 'success' : 'warning'"
|
|
50
|
-
>
|
|
51
|
-
<template #default>
|
|
52
|
-
<span class="text-[11px]" style="color: #636366;">{{ log.description }}</span>
|
|
53
|
-
</template>
|
|
54
|
-
<template #time>
|
|
55
|
-
<span class="text-[10px] font-mono-log" style="color: #D1D1D6;">{{ log.time }}</span>
|
|
56
|
-
</template>
|
|
57
|
-
</n-timeline-item>
|
|
58
|
-
</n-timeline>
|
|
59
|
-
<div v-if="activityLogs.length === 0" class="text-[10px] py-1" style="color: #D1D1D6;">暂无活动记录</div>
|
|
60
|
-
</div>
|
|
27
|
+
<div v-else class="space-y-5">
|
|
28
|
+
<PipelineStage name="brainstorm" title="BRAINSTORM" :steps="getStageSteps('brainstorm')" :status="getStageStatus('brainstorm')" :is-active="currentStage === 'brainstorm'" :active-step="activeStep" @select-step="handleSelectStep" />
|
|
29
|
+
<div v-if="hasStage('plan')" class="flex items-center pl-[3px]"><div class="w-px h-4" style="background: #1F1F22;" /></div>
|
|
30
|
+
<PipelineStage name="plan" title="PLAN" :steps="getStageSteps('plan')" :status="getStageStatus('plan')" :is-active="currentStage === 'plan'" :active-step="activeStep" @select-step="handleSelectStep" />
|
|
31
|
+
<div v-if="hasStage('execute')" class="flex items-center pl-[3px]"><div class="w-px h-4" style="background: #1F1F22;" /></div>
|
|
32
|
+
<PipelineStage name="execute" title="EXECUTE" :steps="getStageSteps('execute')" :status="getStageStatus('execute')" :is-active="currentStage === 'execute'" :active-step="activeStep" @select-step="handleSelectStep" />
|
|
33
|
+
<div v-if="hasStage('verify')" class="flex items-center pl-[3px]"><div class="w-px h-4" style="background: #1F1F22;" /></div>
|
|
34
|
+
<PipelineStage name="verify" title="VERIFY" :steps="getStageSteps('verify')" :status="getStageStatus('verify')" :is-active="currentStage === 'verify'" :active-step="activeStep" @select-step="handleSelectStep" />
|
|
61
35
|
</div>
|
|
62
36
|
</div>
|
|
63
37
|
|
|
64
|
-
<!--
|
|
65
|
-
<div v-if="
|
|
66
|
-
<div class="
|
|
67
|
-
<
|
|
38
|
+
<!-- Activity Log -->
|
|
39
|
+
<div v-if="project?.state?.progress" style="border-top: 1px solid #1F1F22; background: rgba(10,10,11,0.6);">
|
|
40
|
+
<div class="px-6 py-2.5 flex items-center justify-between">
|
|
41
|
+
<div class="text-[9px] font-semibold uppercase tracking-[0.25em] font-[JetBrains_Mono,monospace]" style="color: #525252;">Activity</div>
|
|
42
|
+
<div class="text-[10px] font-mono-log" style="color: #3A3A3D;">{{ activityLogs.length }}</div>
|
|
68
43
|
</div>
|
|
69
|
-
<div class="
|
|
70
|
-
<
|
|
44
|
+
<div class="px-6 pb-3 space-y-0.5 max-h-32 overflow-y-auto">
|
|
45
|
+
<div v-for="(log, i) in activityLogs" :key="i" class="flex items-start gap-2.5 text-[11px] py-0.5">
|
|
46
|
+
<span class="w-10 font-mono-log flex-shrink-0" style="color: #3A3A3D;">{{ log.time }}</span>
|
|
47
|
+
<span :style="{ color: log.status === 'completed' ? '#34D399' : '#FBBF24' }">›</span>
|
|
48
|
+
<span style="color: #8B8B8E;">{{ log.description }}</span>
|
|
49
|
+
</div>
|
|
50
|
+
<div v-if="activityLogs.length === 0" class="text-[10px] py-1" style="color: #3A3A3D;">No activity</div>
|
|
71
51
|
</div>
|
|
72
52
|
</div>
|
|
73
53
|
</div>
|
|
@@ -76,39 +56,24 @@
|
|
|
76
56
|
<script setup>
|
|
77
57
|
import { computed } from 'vue'
|
|
78
58
|
import PipelineStage from './PipelineStage.vue'
|
|
79
|
-
import DocTree from './DocTree.vue'
|
|
80
|
-
import DocPreview from './DocPreview.vue'
|
|
81
59
|
|
|
82
60
|
const props = defineProps({
|
|
83
61
|
project: { type: Object, default: null },
|
|
84
|
-
activeStep: { type: Object, default: null }
|
|
85
|
-
activeTab: { type: String, default: 'pipeline' },
|
|
86
|
-
docs: { type: Object, default: () => ({ groups: [] }) },
|
|
87
|
-
selectedDocFile: { type: Object, default: null },
|
|
88
|
-
docContent: { type: String, default: '' },
|
|
89
|
-
docLoading: { type: Boolean, default: false }
|
|
62
|
+
activeStep: { type: Object, default: null }
|
|
90
63
|
})
|
|
91
64
|
|
|
92
|
-
const emit = defineEmits(['select-step'
|
|
65
|
+
const emit = defineEmits(['select-step'])
|
|
93
66
|
|
|
94
|
-
const currentStage = computed(() => props.project?.state?.currentStage || '')
|
|
67
|
+
const currentStage = computed(() => props.project?.state?.currentStage || 'unknown')
|
|
95
68
|
const progress = computed(() => props.project?.state?.progress || {})
|
|
96
69
|
const stages = computed(() => progress.value.stages || {})
|
|
97
70
|
|
|
98
|
-
const stageNameMap = {
|
|
99
|
-
brainstorm: '头脑风暴',
|
|
100
|
-
plan: '规划',
|
|
101
|
-
execute: '执行',
|
|
102
|
-
verify: '验证'
|
|
103
|
-
}
|
|
104
|
-
|
|
105
71
|
const activityLogs = computed(() => {
|
|
106
72
|
if (!props.project?.state) return []
|
|
107
73
|
const logs = []
|
|
108
74
|
for (const [name, data] of Object.entries(progress.value.stages || {})) {
|
|
109
|
-
|
|
110
|
-
if (data.status === '
|
|
111
|
-
else if (data.status === 'in-progress') logs.push({ time: '--:--', status: 'in-progress', description: `${label} 运行中` })
|
|
75
|
+
if (data.status === 'completed') logs.push({ time: data.completedAt ? formatTime(data.completedAt) : '--:--', status: 'completed', description: `${name} completed` })
|
|
76
|
+
else if (data.status === 'in-progress') logs.push({ time: '--:--', status: 'in-progress', description: `${name} running` })
|
|
112
77
|
}
|
|
113
78
|
return logs.reverse()
|
|
114
79
|
})
|
|
@@ -3,109 +3,84 @@
|
|
|
3
3
|
<!-- Header -->
|
|
4
4
|
<div class="relative z-10 px-5 pt-5 pb-4">
|
|
5
5
|
<div class="flex items-center gap-3">
|
|
6
|
-
<div class="w-8 h-8 rounded-md flex items-center justify-center" style="background: linear-gradient(135deg, #
|
|
6
|
+
<div class="w-8 h-8 rounded-md flex items-center justify-center" style="background: linear-gradient(135deg, #FBBF24 0%, #F59E0B 100%); clip-path: polygon(0 0, 100% 0, 85% 100%, 15% 100%);">
|
|
7
7
|
<span class="text-[10px] font-bold text-black font-[JetBrains_Mono,monospace]">S</span>
|
|
8
8
|
</div>
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
<h1 class="text-[13px] font-semibold tracking-tight font-[JetBrains_Mono,monospace]" style="color: #1C1C1E;">
|
|
9
|
+
<div>
|
|
10
|
+
<h1 class="text-[13px] font-semibold tracking-tight font-[JetBrains_Mono,monospace]" style="color: #E4E4E7;">
|
|
12
11
|
SillySpec
|
|
13
12
|
</h1>
|
|
14
|
-
<p class="text-[10px] tracking-widest uppercase" style="color: #
|
|
13
|
+
<p class="text-[10px] tracking-widest uppercase" style="color: #525252;">Dashboard</p>
|
|
15
14
|
</div>
|
|
16
|
-
<!-- Scan paths gear button -->
|
|
17
|
-
<n-button quaternary size="tiny" @click="showScanPanel = !showScanPanel" :type="showScanPanel ? 'primary' : 'default'">
|
|
18
|
-
<template #icon>
|
|
19
|
-
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
20
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
|
|
21
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
|
22
|
-
</svg>
|
|
23
|
-
</template>
|
|
24
|
-
</n-button>
|
|
25
15
|
</div>
|
|
26
|
-
|
|
27
|
-
<!-- Scan paths panel (inline) -->
|
|
28
|
-
<Transition name="slide">
|
|
29
|
-
<div v-if="showScanPanel" class="mt-3 rounded-md p-3" style="background: #FFFFFF; border: 1px solid #F0F0F3;">
|
|
30
|
-
<div class="text-[10px] font-semibold uppercase tracking-[0.15em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">扫描路径</div>
|
|
31
|
-
|
|
32
|
-
<div v-if="scanPaths.length === 0" class="text-[10px] py-1" style="color: #D1D1D6;">暂无自定义路径</div>
|
|
33
|
-
<div v-else class="space-y-1 mb-2">
|
|
34
|
-
<div v-for="(p, i) in scanPaths" :key="i" class="flex items-center gap-2 text-[10px] group">
|
|
35
|
-
<span class="flex-1 truncate font-mono-log" style="color: #636366;">{{ p }}</span>
|
|
36
|
-
<n-button quaternary size="tiny" type="error" @click="removePath(p)">✕</n-button>
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
|
|
40
|
-
<!-- Add path -->
|
|
41
|
-
<div v-if="showAddInput" class="flex items-center gap-2">
|
|
42
|
-
<n-input v-model:value="newPath" size="tiny" placeholder="输入目录路径..." @keydown.enter="addPath" @keydown.escape="showAddInput = false" ref="pathInput" />
|
|
43
|
-
<n-button size="tiny" type="primary" @click="addPath">添加</n-button>
|
|
44
|
-
</div>
|
|
45
|
-
<n-button v-else size="tiny" dashed @click="showAddInput = true">+ 添加目录</n-button>
|
|
46
|
-
</div>
|
|
47
|
-
</Transition>
|
|
48
16
|
</div>
|
|
49
17
|
|
|
50
18
|
<!-- Divider -->
|
|
51
|
-
<div class="mx-4 h-px" style="background: linear-gradient(90deg, transparent, #
|
|
19
|
+
<div class="mx-4 h-px" style="background: linear-gradient(90deg, transparent, #2A2A2D, transparent);"></div>
|
|
52
20
|
|
|
53
21
|
<!-- Projects List -->
|
|
54
22
|
<div class="flex-1 overflow-y-auto py-3 relative z-10">
|
|
55
23
|
<!-- Loading skeleton -->
|
|
56
24
|
<div v-if="isLoading" class="px-4 space-y-2">
|
|
57
|
-
<
|
|
58
|
-
<
|
|
59
|
-
<
|
|
60
|
-
</
|
|
61
|
-
<p class="text-center text-[10px] mt-4 font-[JetBrains_Mono,monospace]" style="color: #
|
|
62
|
-
|
|
25
|
+
<div v-for="i in 4" :key="i" class="rounded-lg p-3" style="background: #141416;">
|
|
26
|
+
<div class="h-3 rounded w-20 skeleton-shimmer mb-2"></div>
|
|
27
|
+
<div class="h-2 rounded w-32 skeleton-shimmer"></div>
|
|
28
|
+
</div>
|
|
29
|
+
<p class="text-center text-[10px] mt-4 font-[JetBrains_Mono,monospace]" style="color: #525252;">
|
|
30
|
+
scanning projects...
|
|
63
31
|
</p>
|
|
64
32
|
</div>
|
|
65
33
|
|
|
66
34
|
<!-- Empty state -->
|
|
67
|
-
<
|
|
35
|
+
<div v-else-if="projects.length === 0" class="px-4 py-12 text-center">
|
|
36
|
+
<div class="w-10 h-10 mx-auto mb-3 rounded-full flex items-center justify-center" style="border: 1px dashed #2A2A2D;">
|
|
37
|
+
<svg class="w-4 h-4" style="color: #525252;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
38
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
|
|
39
|
+
</svg>
|
|
40
|
+
</div>
|
|
41
|
+
<p class="text-[11px]" style="color: #8B8B8E;">No projects found</p>
|
|
42
|
+
<p class="text-[10px] mt-1" style="color: #525252;">Looking for .sillyspec dirs</p>
|
|
43
|
+
</div>
|
|
68
44
|
|
|
69
45
|
<!-- Projects -->
|
|
70
46
|
<div v-else class="px-3 space-y-0.5">
|
|
71
47
|
<div
|
|
72
48
|
v-for="project in projects"
|
|
73
|
-
:key="project.
|
|
74
|
-
:class="[
|
|
49
|
+
:key="project.name"
|
|
50
|
+
:class="[
|
|
51
|
+
'relative rounded-md cursor-pointer transition-all duration-150 overflow-hidden group',
|
|
52
|
+
]"
|
|
75
53
|
:style="{
|
|
76
|
-
background: isActive(project) ? 'rgba(
|
|
77
|
-
borderLeft: isActive(project) ? '2px solid #
|
|
54
|
+
background: isActive(project) ? 'rgba(251,191,36,0.06)' : 'transparent',
|
|
55
|
+
borderLeft: isActive(project) ? '2px solid #FBBF24' : '2px solid transparent',
|
|
78
56
|
}"
|
|
79
|
-
@mouseenter="$event.currentTarget.style.background = isActive(project) ? 'rgba(
|
|
80
|
-
@mouseleave="$event.currentTarget.style.background = isActive(project) ? 'rgba(
|
|
57
|
+
@mouseenter="$event.currentTarget.style.background = isActive(project) ? 'rgba(251,191,36,0.08)' : 'rgba(255,255,255,0.02)'"
|
|
58
|
+
@mouseleave="$event.currentTarget.style.background = isActive(project) ? 'rgba(251,191,36,0.06)' : 'transparent'"
|
|
81
59
|
@click="$emit('select', project)"
|
|
82
60
|
>
|
|
83
61
|
<div class="px-3 py-2.5">
|
|
84
62
|
<div class="flex items-center justify-between gap-2">
|
|
85
63
|
<div class="flex-1 min-w-0">
|
|
86
64
|
<h3
|
|
87
|
-
class="text-[12px] font-medium truncate transition-colors duration-150 font-[JetBrains_Mono,monospace]"
|
|
88
|
-
:style="{ color: isActive(project) ? '#
|
|
65
|
+
:class="['text-[12px] font-medium truncate transition-colors duration-150 font-[JetBrains_Mono,monospace]']"
|
|
66
|
+
:style="{ color: isActive(project) ? '#FBBF24' : '#E4E4E7' }"
|
|
89
67
|
>
|
|
90
68
|
{{ project.name }}
|
|
91
69
|
</h3>
|
|
92
|
-
<p class="text-[10px] mt-0.5 truncate font-mono-log" style="color: #
|
|
70
|
+
<p class="text-[10px] mt-0.5 truncate font-mono-log" style="color: #525252;">
|
|
93
71
|
{{ project.path }}
|
|
94
72
|
</p>
|
|
95
73
|
</div>
|
|
96
|
-
<
|
|
74
|
+
<StageBadge
|
|
97
75
|
v-if="project.state?.currentStage"
|
|
98
|
-
:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
>
|
|
103
|
-
{{ stageLabel(project) }}
|
|
104
|
-
</n-tag>
|
|
76
|
+
:status="getProjectStatus(project)"
|
|
77
|
+
:label="stageLabel(project)"
|
|
78
|
+
size="sm"
|
|
79
|
+
/>
|
|
105
80
|
</div>
|
|
106
81
|
|
|
107
82
|
<!-- Progress -->
|
|
108
|
-
<div v-if="project.state?.progress" class="mt-2 h-[2px] rounded-full overflow-hidden" style="background: #
|
|
83
|
+
<div v-if="project.state?.progress" class="mt-2 h-[2px] rounded-full overflow-hidden" style="background: #1C1C1F;">
|
|
109
84
|
<div
|
|
110
85
|
class="h-full rounded-full transition-all duration-500 progress-gradient"
|
|
111
86
|
:style="{ width: getProjectProgress(project) + '%' }"
|
|
@@ -117,43 +92,29 @@
|
|
|
117
92
|
</div>
|
|
118
93
|
|
|
119
94
|
<!-- Footer -->
|
|
120
|
-
<div class="relative z-10 px-4 py-2.5" style="border-top: 1px solid #
|
|
95
|
+
<div class="relative z-10 px-4 py-2.5" style="border-top: 1px solid #1F1F22;">
|
|
121
96
|
<div class="flex items-center justify-between">
|
|
122
|
-
<span class="text-[10px] font-[JetBrains_Mono,monospace]" style="color: #
|
|
123
|
-
<kbd class="text-[9px] px-1.5 py-0.5 rounded font-mono-log" style="color: #
|
|
97
|
+
<span class="text-[10px] font-[JetBrains_Mono,monospace]" style="color: #525252;">{{ projects.length }} proj</span>
|
|
98
|
+
<kbd class="text-[9px] px-1.5 py-0.5 rounded font-mono-log" style="color: #525252; background: #141416; border: 1px solid #2A2A2D;">⌘K</kbd>
|
|
124
99
|
</div>
|
|
125
100
|
</div>
|
|
126
101
|
</div>
|
|
127
102
|
</template>
|
|
128
103
|
|
|
129
104
|
<script setup>
|
|
130
|
-
import {
|
|
105
|
+
import { computed } from 'vue'
|
|
106
|
+
import StageBadge from './StageBadge.vue'
|
|
131
107
|
|
|
132
108
|
const props = defineProps({
|
|
133
109
|
projects: { type: Array, default: () => [] },
|
|
134
110
|
activeProject: { type: Object, default: null },
|
|
135
|
-
isLoading: { type: Boolean, default: false }
|
|
136
|
-
scanPaths: { type: Array, default: () => [] }
|
|
111
|
+
isLoading: { type: Boolean, default: false }
|
|
137
112
|
})
|
|
138
113
|
|
|
139
|
-
const emit = defineEmits(['select'
|
|
140
|
-
|
|
141
|
-
const showScanPanel = ref(false)
|
|
142
|
-
const showAddInput = ref(false)
|
|
143
|
-
const newPath = ref('')
|
|
144
|
-
const pathInput = ref(null)
|
|
145
|
-
|
|
146
|
-
watch(showAddInput, (v) => {
|
|
147
|
-
if (v) nextTick(() => { pathInput.value?.focus() })
|
|
148
|
-
})
|
|
114
|
+
const emit = defineEmits(['select'])
|
|
149
115
|
|
|
150
116
|
function isActive(project) {
|
|
151
|
-
return props.activeProject?.
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function statusTagType(status) {
|
|
155
|
-
const map = { 'in-progress': 'warning', 'completed': 'success', 'failed': 'error', 'blocked': 'warning' }
|
|
156
|
-
return map[status] || 'default'
|
|
117
|
+
return props.activeProject?.name === project.name
|
|
157
118
|
}
|
|
158
119
|
|
|
159
120
|
function getProjectStatus(project) {
|
|
@@ -188,23 +149,4 @@ function getProjectProgress(project) {
|
|
|
188
149
|
}
|
|
189
150
|
return total === 0 ? 0 : Math.round((done / total) * 100)
|
|
190
151
|
}
|
|
191
|
-
|
|
192
|
-
function addPath() {
|
|
193
|
-
const p = newPath.value.trim()
|
|
194
|
-
if (p) {
|
|
195
|
-
emit('scan:add-path', p)
|
|
196
|
-
newPath.value = ''
|
|
197
|
-
showAddInput.value = false
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function removePath(p) {
|
|
202
|
-
emit('scan:remove-path', p)
|
|
203
|
-
}
|
|
204
152
|
</script>
|
|
205
|
-
|
|
206
|
-
<style scoped>
|
|
207
|
-
.slide-enter-active, .slide-leave-active { transition: all 200ms ease; }
|
|
208
|
-
.slide-enter-from, .slide-leave-to { opacity: 0; max-height: 0; overflow: hidden; }
|
|
209
|
-
.slide-enter-to, .slide-leave-from { max-height: 300px; }
|
|
210
|
-
</style>
|
|
@@ -19,19 +19,19 @@ const props = defineProps({
|
|
|
19
19
|
|
|
20
20
|
const displayLabel = computed(() => {
|
|
21
21
|
if (props.label) return props.label
|
|
22
|
-
const labels = { 'completed': 'done', 'in-progress': 'running', 'blocked': 'blocked', 'failed': 'error' }
|
|
23
|
-
return labels[props.status] || ''
|
|
22
|
+
const labels = { 'completed': 'done', 'in-progress': 'running', 'blocked': 'blocked', 'failed': 'error', 'pending': 'idle' }
|
|
23
|
+
return labels[props.status] || 'idle'
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
const sizeClass = computed(() => props.size === 'sm' ? 'px-1.5 py-0.5' : 'px-2 py-1')
|
|
27
27
|
|
|
28
28
|
const badgeStyle = computed(() => {
|
|
29
29
|
const styles = {
|
|
30
|
-
'completed': { background: 'rgba(
|
|
31
|
-
'in-progress': { background: 'rgba(251,191,36,0.1)', color: '#
|
|
32
|
-
'blocked': { background: 'rgba(251,146,60,0.1)', color: '#
|
|
33
|
-
'failed': { background: 'rgba(239,68,68,0.1)', color: '#
|
|
34
|
-
'pending': { background: 'rgba(82,82,82,0.15)', color: '#
|
|
30
|
+
'completed': { background: 'rgba(52,211,153,0.1)', color: '#34D399' },
|
|
31
|
+
'in-progress': { background: 'rgba(251,191,36,0.1)', color: '#FBBF24' },
|
|
32
|
+
'blocked': { background: 'rgba(251,146,60,0.1)', color: '#FB923C' },
|
|
33
|
+
'failed': { background: 'rgba(239,68,68,0.1)', color: '#EF4444' },
|
|
34
|
+
'pending': { background: 'rgba(82,82,82,0.15)', color: '#525252' }
|
|
35
35
|
}
|
|
36
36
|
return styles[props.status] || styles.pending
|
|
37
37
|
})
|
|
@@ -42,12 +42,12 @@ const dotClass = computed(() => {
|
|
|
42
42
|
|
|
43
43
|
const dotStyle = computed(() => {
|
|
44
44
|
const colors = {
|
|
45
|
-
'completed': '#
|
|
46
|
-
'in-progress': '#
|
|
47
|
-
'blocked': '#
|
|
48
|
-
'failed': '#
|
|
49
|
-
'pending': '#
|
|
45
|
+
'completed': '#34D399',
|
|
46
|
+
'in-progress': '#FBBF24',
|
|
47
|
+
'blocked': '#FB923C',
|
|
48
|
+
'failed': '#EF4444',
|
|
49
|
+
'pending': '#525252'
|
|
50
50
|
}
|
|
51
|
-
return { background: colors[props.status] || '#
|
|
51
|
+
return { background: colors[props.status] || '#525252' }
|
|
52
52
|
})
|
|
53
53
|
</script>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
:class="['group relative rounded-md cursor-pointer transition-all duration-200']"
|
|
3
|
+
:class="['group relative rounded-md cursor-pointer overflow-hidden transition-all duration-200']"
|
|
4
4
|
:style="cardStyle"
|
|
5
5
|
@mouseenter="hovered = true"
|
|
6
6
|
@mouseleave="hovered = false"
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
<!-- Left accent bar -->
|
|
10
10
|
<div class="absolute left-0 top-0 bottom-0 w-[2px]" :style="{ background: barColor }" />
|
|
11
11
|
|
|
12
|
-
<div class="pl-
|
|
12
|
+
<div class="pl-3.5 pr-3 py-2.5">
|
|
13
13
|
<div class="flex items-center gap-2">
|
|
14
|
-
<h3 class="text-[12px] font-medium transition-colors duration-150" :style="{ color: isActive ? '#
|
|
14
|
+
<h3 class="text-[12px] font-medium transition-colors duration-150" :style="{ color: isActive ? '#FBBF24' : '#E4E4E7', fontFamily: '\'JetBrains Mono\', monospace' }">
|
|
15
15
|
{{ step.title || step.name }}
|
|
16
16
|
</h3>
|
|
17
17
|
<StageBadge v-if="step.status" :status="step.status" :label="statusLabel" />
|
|
@@ -20,28 +20,28 @@
|
|
|
20
20
|
<!-- Hover summary -->
|
|
21
21
|
<div
|
|
22
22
|
v-if="step.summary || step.description"
|
|
23
|
-
class="transition-all duration-200"
|
|
24
|
-
:style="{ maxHeight: hovered ? '
|
|
23
|
+
class="overflow-hidden transition-all duration-200"
|
|
24
|
+
:style="{ maxHeight: hovered ? '60px' : '0', opacity: hovered ? 1 : 0 }"
|
|
25
25
|
>
|
|
26
|
-
<p class="mt-1.5 text-[11px] line-clamp-2" style="color: #
|
|
26
|
+
<p class="mt-1.5 text-[11px] line-clamp-2" style="color: #8B8B8E;">
|
|
27
27
|
{{ step.summary || step.description }}
|
|
28
28
|
</p>
|
|
29
29
|
</div>
|
|
30
30
|
|
|
31
31
|
<!-- Active details -->
|
|
32
32
|
<div v-if="isActive" class="mt-2 space-y-1">
|
|
33
|
-
<p v-if="step.conclusion" class="text-[11px]" style="color: #
|
|
34
|
-
<span style="color: #
|
|
33
|
+
<p v-if="step.conclusion" class="text-[11px]" style="color: #E4E4E7;">
|
|
34
|
+
<span style="color: #FBBF24; font-weight: 600;">结论:</span> {{ step.conclusion }}
|
|
35
35
|
</p>
|
|
36
|
-
<p v-if="step.decision" class="text-[11px]" style="color: #
|
|
37
|
-
<span style="color: #
|
|
36
|
+
<p v-if="step.decision" class="text-[11px]" style="color: #E4E4E7;">
|
|
37
|
+
<span style="color: #FBBF24; font-weight: 600;">决策:</span> {{ step.decision }}
|
|
38
38
|
</p>
|
|
39
|
-
<p v-if="step.userQuery" class="text-[11px] italic" style="color: #
|
|
39
|
+
<p v-if="step.userQuery" class="text-[11px] italic" style="color: #8B8B8E;">
|
|
40
40
|
"{{ step.userQuery }}"
|
|
41
41
|
</p>
|
|
42
42
|
</div>
|
|
43
43
|
|
|
44
|
-
<div v-if="step.duration" class="mt-1 text-[10px] font-mono-log" style="color: #
|
|
44
|
+
<div v-if="step.duration" class="mt-1 text-[10px] font-mono-log" style="color: #525252;">
|
|
45
45
|
{{ step.duration }}
|
|
46
46
|
</div>
|
|
47
47
|
</div>
|
|
@@ -62,13 +62,13 @@ const emit = defineEmits(['select'])
|
|
|
62
62
|
const hovered = ref(false)
|
|
63
63
|
|
|
64
64
|
const barColor = computed(() => {
|
|
65
|
-
const colors = { 'completed': '#
|
|
65
|
+
const colors = { 'completed': '#34D399', 'in-progress': '#FBBF24', 'blocked': '#FB923C', 'failed': '#EF4444', 'pending': '#2A2A2D' }
|
|
66
66
|
return colors[props.step.status] || colors.pending
|
|
67
67
|
})
|
|
68
68
|
|
|
69
69
|
const cardStyle = computed(() => ({
|
|
70
|
-
background: props.isActive ? 'rgba(
|
|
71
|
-
border: `1px solid ${props.isActive ? 'rgba(251,191,36,0.2)' : '#
|
|
70
|
+
background: props.isActive ? 'rgba(251,191,36,0.04)' : (hovered.value ? 'rgba(255,255,255,0.015)' : '#141416'),
|
|
71
|
+
border: `1px solid ${props.isActive ? 'rgba(251,191,36,0.2)' : '#1F1F22'}`,
|
|
72
72
|
}))
|
|
73
73
|
|
|
74
74
|
const statusLabel = computed(() => {
|
|
@@ -13,12 +13,7 @@ export function useDashboard() {
|
|
|
13
13
|
logs: [],
|
|
14
14
|
isPanelOpen: true,
|
|
15
15
|
executingProject: null,
|
|
16
|
-
isLoading: true
|
|
17
|
-
activeTab: 'pipeline',
|
|
18
|
-
docs: { groups: [] },
|
|
19
|
-
selectedDocFile: null,
|
|
20
|
-
docContent: '',
|
|
21
|
-
docLoading: false
|
|
16
|
+
isLoading: true
|
|
22
17
|
})
|
|
23
18
|
|
|
24
19
|
/**
|
|
@@ -26,13 +21,13 @@ export function useDashboard() {
|
|
|
26
21
|
* @param {string} name - Project name
|
|
27
22
|
* @returns {object|null} Project or null
|
|
28
23
|
*/
|
|
29
|
-
function getProject(
|
|
30
|
-
return state.projects.find(p => p.
|
|
24
|
+
function getProject(name) {
|
|
25
|
+
return state.projects.find(p => p.name === name) || null
|
|
31
26
|
}
|
|
32
27
|
|
|
33
28
|
/**
|
|
34
29
|
* Select a project as active
|
|
35
|
-
* @param {object|string} project - Project object or
|
|
30
|
+
* @param {object|string} project - Project object or name
|
|
36
31
|
*/
|
|
37
32
|
function selectProject(project) {
|
|
38
33
|
const proj = typeof project === 'string'
|
|
@@ -43,8 +38,6 @@ export function useDashboard() {
|
|
|
43
38
|
state.activeProject = proj
|
|
44
39
|
state.activeStep = null
|
|
45
40
|
state.logs = []
|
|
46
|
-
state.selectedDocFile = null
|
|
47
|
-
state.docContent = ''
|
|
48
41
|
|
|
49
42
|
// Load initial logs from project state if available
|
|
50
43
|
if (proj.state?.progress?.currentLogs) {
|
|
@@ -122,7 +115,7 @@ export function useDashboard() {
|
|
|
122
115
|
|
|
123
116
|
// Restore active project if it still exists
|
|
124
117
|
if (state.activeProject) {
|
|
125
|
-
const updated = getProject(state.activeProject.
|
|
118
|
+
const updated = getProject(state.activeProject.name)
|
|
126
119
|
if (updated) {
|
|
127
120
|
state.activeProject = updated
|
|
128
121
|
}
|
|
@@ -148,7 +141,6 @@ export function useDashboard() {
|
|
|
148
141
|
|
|
149
142
|
// Computed properties
|
|
150
143
|
const activeProjectName = computed(() => state.activeProject?.name || null)
|
|
151
|
-
const activeProjectPath = computed(() => state.activeProject?.path || null)
|
|
152
144
|
const activeProjectStage = computed(() => state.activeProject?.state?.currentStage || null)
|
|
153
145
|
const hasProjects = computed(() => state.projects.length > 0)
|
|
154
146
|
const activeProjectSteps = computed(() => {
|
|
@@ -172,14 +164,8 @@ export function useDashboard() {
|
|
|
172
164
|
setExecuting,
|
|
173
165
|
isExecuting,
|
|
174
166
|
activeProjectName,
|
|
175
|
-
activeProjectPath,
|
|
176
167
|
activeProjectStage,
|
|
177
168
|
hasProjects,
|
|
178
|
-
activeProjectSteps
|
|
179
|
-
setActiveTab(tab) { state.activeTab = tab },
|
|
180
|
-
updateDocs(docs) { state.docs = docs },
|
|
181
|
-
selectDocFile(file) { state.selectedDocFile = file },
|
|
182
|
-
setDocContent(content) { state.docContent = content },
|
|
183
|
-
setDocLoading(loading) { state.docLoading = loading }
|
|
169
|
+
activeProjectSteps
|
|
184
170
|
}
|
|
185
171
|
}
|
|
@@ -14,17 +14,15 @@ export function useKeyboard(options = {}) {
|
|
|
14
14
|
onEnter = null,
|
|
15
15
|
onArrowUp = null,
|
|
16
16
|
onArrowDown = null,
|
|
17
|
-
disabled
|
|
17
|
+
disabled = false
|
|
18
18
|
} = options
|
|
19
19
|
|
|
20
|
-
let isDisabled = initialDisabled
|
|
21
|
-
|
|
22
20
|
/**
|
|
23
21
|
* Handle keyboard events
|
|
24
22
|
* @param {KeyboardEvent} event
|
|
25
23
|
*/
|
|
26
24
|
function handleKeyDown(event) {
|
|
27
|
-
if (
|
|
25
|
+
if (disabled) return
|
|
28
26
|
|
|
29
27
|
// Ignore if in input field
|
|
30
28
|
const target = event.target
|
|
@@ -89,8 +87,8 @@ export function useKeyboard(options = {}) {
|
|
|
89
87
|
})
|
|
90
88
|
|
|
91
89
|
return {
|
|
92
|
-
disable: () => {
|
|
93
|
-
enable: () => {
|
|
90
|
+
disable: () => { disabled = true },
|
|
91
|
+
enable: () => { disabled = false }
|
|
94
92
|
}
|
|
95
93
|
}
|
|
96
94
|
|