@assistkick/create 1.7.0 → 1.9.0
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/dist/bin/create.js +0 -0
- package/package.json +9 -7
- package/templates/assistkick-product-system/.env.example +1 -0
- package/templates/assistkick-product-system/local.db +0 -0
- package/templates/assistkick-product-system/package.json +4 -2
- package/templates/assistkick-product-system/packages/backend/package.json +2 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/agents.ts +165 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/files.test.ts +358 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/files.ts +356 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/git.ts +96 -1
- package/templates/assistkick-product-system/packages/backend/src/routes/graph.ts +1 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/kanban.ts +61 -6
- package/templates/assistkick-product-system/packages/backend/src/routes/pipeline.ts +200 -84
- package/templates/assistkick-product-system/packages/backend/src/routes/projects.ts +6 -3
- package/templates/assistkick-product-system/packages/backend/src/routes/terminal.ts +53 -17
- package/templates/assistkick-product-system/packages/backend/src/routes/video.ts +218 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/workflow_groups.ts +119 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/workflows.ts +158 -0
- package/templates/assistkick-product-system/packages/backend/src/server.ts +60 -9
- package/templates/assistkick-product-system/packages/backend/src/services/agent_service.test.ts +489 -0
- package/templates/assistkick-product-system/packages/backend/src/services/agent_service.ts +416 -0
- package/templates/assistkick-product-system/packages/backend/src/services/bundle_service.test.ts +189 -0
- package/templates/assistkick-product-system/packages/backend/src/services/bundle_service.ts +182 -0
- package/templates/assistkick-product-system/packages/backend/src/services/init.ts +43 -77
- package/templates/assistkick-product-system/packages/backend/src/services/project_service.test.ts +16 -0
- package/templates/assistkick-product-system/packages/backend/src/services/project_service.ts +73 -2
- package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.test.ts +4 -4
- package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.ts +87 -11
- package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.test.ts +210 -69
- package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.ts +210 -215
- package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.test.ts +162 -0
- package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.ts +148 -0
- package/templates/assistkick-product-system/packages/backend/src/services/terminal_ws_handler.ts +11 -5
- package/templates/assistkick-product-system/packages/backend/src/services/tts_service.test.ts +64 -0
- package/templates/assistkick-product-system/packages/backend/src/services/tts_service.ts +134 -0
- package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.test.ts +256 -0
- package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.ts +258 -0
- package/templates/assistkick-product-system/packages/backend/src/services/workflow_group_service.ts +106 -0
- package/templates/assistkick-product-system/packages/backend/src/services/workflow_service.test.ts +275 -0
- package/templates/assistkick-product-system/packages/backend/src/services/workflow_service.ts +245 -0
- package/templates/assistkick-product-system/packages/frontend/package-lock.json +3455 -0
- package/templates/assistkick-product-system/packages/frontend/package.json +6 -0
- package/templates/assistkick-product-system/packages/frontend/src/App.tsx +8 -0
- package/templates/assistkick-product-system/packages/frontend/src/api/client.ts +458 -18
- package/templates/assistkick-product-system/packages/frontend/src/api/client_files.test.ts +172 -0
- package/templates/assistkick-product-system/packages/frontend/src/api/client_video.test.ts +238 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/AgentsView.tsx +307 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/CoherenceView.tsx +82 -66
- package/templates/assistkick-product-system/packages/frontend/src/components/CompositionPlaceholder.tsx +97 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/DesignSystemView.tsx +20 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/EditorTabBar.tsx +57 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FileTree.tsx +313 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeContextMenu.tsx +61 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeInlineInput.tsx +73 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FilesView.tsx +404 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/GitRepoModal.tsx +187 -56
- package/templates/assistkick-product-system/packages/frontend/src/components/GraphLegend.tsx +71 -73
- package/templates/assistkick-product-system/packages/frontend/src/components/GraphSettings.tsx +8 -8
- package/templates/assistkick-product-system/packages/frontend/src/components/GraphView.tsx +1 -1
- package/templates/assistkick-product-system/packages/frontend/src/components/InviteUserDialog.tsx +15 -11
- package/templates/assistkick-product-system/packages/frontend/src/components/IterationCommentModal.tsx +80 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/KanbanView.tsx +263 -167
- package/templates/assistkick-product-system/packages/frontend/src/components/LoginPage.tsx +14 -14
- package/templates/assistkick-product-system/packages/frontend/src/components/ProjectSelector.tsx +54 -33
- package/templates/assistkick-product-system/packages/frontend/src/components/QaIssueSheet.tsx +32 -49
- package/templates/assistkick-product-system/packages/frontend/src/components/SidePanel.tsx +43 -48
- package/templates/assistkick-product-system/packages/frontend/src/components/TerminalView.tsx +121 -52
- package/templates/assistkick-product-system/packages/frontend/src/components/Toolbar.tsx +20 -14
- package/templates/assistkick-product-system/packages/frontend/src/components/UsersView.tsx +52 -52
- package/templates/assistkick-product-system/packages/frontend/src/components/VideoGallery.tsx +313 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/VideographyView.tsx +250 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/WorkflowsView.tsx +474 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/AccentBorderList.tsx +53 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/Button.tsx +87 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/ButtonGroup.tsx +29 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/ButtonShowcase.tsx +221 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/CardGlass.tsx +141 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/CompletionRing.tsx +30 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/ContentCard.tsx +34 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/IconButton.tsx +74 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/KanbanCard.tsx +103 -87
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/KanbanCardShowcase.tsx +9 -188
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/Kbd.tsx +11 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/KindBadge.tsx +21 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/NavBarSidekick.tsx +81 -37
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/SidePanelShowcase.tsx +370 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/SideSheet.tsx +64 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/StatusDot.tsx +18 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/CheckCardPositionNode.tsx +36 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/CheckCycleCountNode.tsx +60 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/EndNode.tsx +42 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/GenerateTTSNode.tsx +52 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/GroupNode.tsx +189 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/NodePalette.tsx +123 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/RebuildBundleNode.tsx +20 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/RenderVideoNode.tsx +72 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/RunAgentNode.tsx +51 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/SetCardMetadataNode.tsx +53 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/StartNode.tsx +18 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/TransitionCardNode.tsx +59 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowCanvas.tsx +341 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowMonitorModal.tsx +643 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/autoLayout.ts +103 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/edgeColors.ts +35 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/monitor_nodes.tsx +246 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.test.ts +119 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.ts +136 -0
- package/templates/assistkick-product-system/packages/frontend/src/constants/graph.ts +13 -11
- package/templates/assistkick-product-system/packages/frontend/src/hooks/useAutoSave.ts +75 -0
- package/templates/assistkick-product-system/packages/frontend/src/hooks/useToast.tsx +16 -3
- package/templates/assistkick-product-system/packages/frontend/src/pages/accept_invitation_page.tsx +30 -27
- package/templates/assistkick-product-system/packages/frontend/src/pages/forgot_password_page.tsx +18 -15
- package/templates/assistkick-product-system/packages/frontend/src/pages/register_page.tsx +21 -18
- package/templates/assistkick-product-system/packages/frontend/src/pages/reset_password_page.tsx +28 -25
- package/templates/assistkick-product-system/packages/frontend/src/routes/AgentsRoute.tsx +6 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/CoherenceRoute.tsx +1 -1
- package/templates/assistkick-product-system/packages/frontend/src/routes/DashboardLayout.tsx +2 -2
- package/templates/assistkick-product-system/packages/frontend/src/routes/FilesRoute.tsx +13 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/GraphRoute.tsx +2 -2
- package/templates/assistkick-product-system/packages/frontend/src/routes/VideographyRoute.tsx +13 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/WorkflowsRoute.tsx +6 -0
- package/templates/assistkick-product-system/packages/frontend/src/stores/useProjectStore.ts +6 -3
- package/templates/assistkick-product-system/packages/frontend/src/stores/useSidePanelStore.ts +4 -4
- package/templates/assistkick-product-system/packages/frontend/src/styles/index.css +275 -3535
- package/templates/assistkick-product-system/packages/frontend/src/utils/auto_save_service.test.ts +167 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/auto_save_service.ts +101 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/composition_matcher.test.ts +42 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/composition_matcher.ts +17 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/file_utils.test.ts +145 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/file_utils.ts +42 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/task_status.test.ts +4 -10
- package/templates/assistkick-product-system/packages/frontend/src/utils/task_status.ts +19 -1
- package/templates/assistkick-product-system/packages/frontend/vite.config.ts +5 -0
- package/templates/assistkick-product-system/packages/shared/db/local.db +0 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0004_tidy_matthew_murdock.sql +9 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0005_mysterious_falcon.sql +692 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0006_next_venom.sql +9 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0007_deep_barracuda.sql +39 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0008_puzzling_hannibal_king.sql +1 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0009_amused_beast.sql +8 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0010_spotty_moira_mactaggert.sql +9 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0011_goofy_snowbird.sql +3 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0011_supreme_doctor_octopus.sql +3 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0013_reflective_prowler.sql +15 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0014_nifty_punisher.sql +15 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0004_snapshot.json +921 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0005_snapshot.json +1042 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0006_snapshot.json +1101 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0007_snapshot.json +1336 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0008_snapshot.json +1275 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0009_snapshot.json +1327 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0010_snapshot.json +1393 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0011_snapshot.json +1436 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0013_snapshot.json +1538 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0014_snapshot.json +1545 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/_journal.json +77 -0
- package/templates/assistkick-product-system/packages/shared/db/schema.ts +114 -0
- package/templates/assistkick-product-system/packages/shared/lib/claude-service.ts +32 -7
- package/templates/assistkick-product-system/packages/shared/lib/constants.ts +9 -0
- package/templates/assistkick-product-system/packages/shared/lib/git_workflow.ts +12 -4
- package/templates/assistkick-product-system/packages/shared/lib/graph.ts +5 -0
- package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.test.ts +1999 -0
- package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.ts +1437 -0
- package/templates/assistkick-product-system/packages/shared/lib/workflow_orchestrator.ts +211 -0
- package/templates/assistkick-product-system/packages/shared/tools/add_node.test.ts +43 -0
- package/templates/assistkick-product-system/packages/shared/tools/add_node.ts +13 -2
- package/templates/assistkick-product-system/packages/shared/tools/get_kanban.ts +1 -1
- package/templates/assistkick-product-system/packages/shared/tools/migrate_epics.test.ts +226 -0
- package/templates/assistkick-product-system/packages/shared/tools/migrate_epics.ts +251 -0
- package/templates/assistkick-product-system/packages/shared/tools/update_node.ts +2 -2
- package/templates/assistkick-product-system/packages/shared/utils/hello_workflow.test.ts +10 -0
- package/templates/assistkick-product-system/packages/shared/utils/hello_workflow.ts +6 -0
- package/templates/assistkick-product-system/packages/video/Root.tsx +85 -0
- package/templates/assistkick-product-system/packages/video/components/email_scene.tsx +231 -0
- package/templates/assistkick-product-system/packages/video/components/outro_scene.tsx +153 -0
- package/templates/assistkick-product-system/packages/video/components/part_divider.tsx +90 -0
- package/templates/assistkick-product-system/packages/video/components/scene.tsx +226 -0
- package/templates/assistkick-product-system/packages/video/components/theme.ts +22 -0
- package/templates/assistkick-product-system/packages/video/components/title_scene.tsx +169 -0
- package/templates/assistkick-product-system/packages/video/components/video_split_layout.tsx +84 -0
- package/templates/assistkick-product-system/packages/video/compositions/.gitkeep +0 -0
- package/templates/assistkick-product-system/packages/video/index.ts +4 -0
- package/templates/assistkick-product-system/packages/video/package.json +28 -0
- package/templates/assistkick-product-system/packages/video/remotion.config.ts +11 -0
- package/templates/assistkick-product-system/packages/video/scripts/process_script.test.ts +326 -0
- package/templates/assistkick-product-system/packages/video/scripts/process_script.ts +630 -0
- package/templates/assistkick-product-system/packages/video/style.css +1 -0
- package/templates/assistkick-product-system/packages/video/tsconfig.json +18 -0
- package/templates/assistkick-product-system/tests/graph_legend.test.ts +2 -1
- package/templates/assistkick-product-system/tests/video_render_service.test.ts +181 -0
- package/templates/assistkick-product-system/tests/web_terminal.test.ts +219 -455
- package/templates/assistkick-product-system/tests/workflow_integration.test.ts +341 -0
- package/templates/skills/assistkick-developer/SKILL.md +3 -0
- package/templates/skills/assistkick-developer/references/react_development_guidelines.md +225 -0
- package/templates/skills/product-system/graph.json +1890 -0
- package/templates/skills/product-system/kanban.json +304 -0
- package/templates/skills/product-system/nodes/comp_001.md +56 -0
- package/templates/skills/product-system/nodes/comp_002.md +57 -0
- package/templates/skills/product-system/nodes/data_001.md +51 -0
- package/templates/skills/product-system/nodes/data_002.md +40 -0
- package/templates/skills/product-system/nodes/data_004.md +38 -0
- package/templates/skills/product-system/nodes/dec_001.md +34 -0
- package/templates/skills/product-system/nodes/dec_016.md +32 -0
- package/templates/skills/product-system/nodes/feat_008.md +30 -0
- package/templates/skills/video-composition-agent/SKILL.md +232 -0
- package/templates/skills/video-script-writer/SKILL.md +136 -0
package/templates/assistkick-product-system/packages/frontend/src/components/ds/KanbanCard.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import {
|
|
3
|
-
Play, AlertTriangle, Lock, CircleDot, Copy, Check,
|
|
3
|
+
Play, AlertTriangle, Lock, CircleDot, Copy, Check, ChevronDown,
|
|
4
4
|
} from 'lucide-react';
|
|
5
|
+
import { KindBadge } from './KindBadge';
|
|
5
6
|
|
|
6
7
|
/* ── Types ── */
|
|
7
8
|
|
|
@@ -13,36 +14,43 @@ export interface KanbanCardProps {
|
|
|
13
14
|
kind?: string;
|
|
14
15
|
rejectionCount: number;
|
|
15
16
|
blocked: boolean;
|
|
16
|
-
/**
|
|
17
|
+
/** Workflow execution status string */
|
|
17
18
|
pipeline: string;
|
|
18
|
-
/**
|
|
19
|
+
/** Status badge label (e.g. "Running", "Completed") */
|
|
19
20
|
pipelineLabel?: string;
|
|
20
|
-
/** Tool call counts — { Read: 6, Tools: 11, Write: 3, Edit: 2 } */
|
|
21
|
-
toolCalls?: Record<string, number>;
|
|
22
|
-
/** Session meta pills — e.g. ["Ctx 17%", "19t", "$0.3948", "opus-4"] */
|
|
23
|
-
meta?: string[];
|
|
24
|
-
/** Stop reason (e.g. "end_turn", "max_turns") */
|
|
25
|
-
stopReason?: string;
|
|
26
21
|
/** Number of issues / notes */
|
|
27
22
|
issueCount: number;
|
|
28
23
|
/** Issue button label override */
|
|
29
24
|
issueLabel?: string;
|
|
30
25
|
/** Show play button */
|
|
31
26
|
showPlay?: boolean;
|
|
27
|
+
/** Show dropdown arrow next to play button for workflow selection */
|
|
28
|
+
showPlayDropdown?: boolean;
|
|
29
|
+
/** Show stop button (for epic cards when orchestrator is running) */
|
|
30
|
+
showStop?: boolean;
|
|
32
31
|
/** Show resume button */
|
|
33
32
|
showResume?: boolean;
|
|
34
33
|
/** Whether copy was just triggered */
|
|
35
34
|
copied?: boolean;
|
|
36
35
|
/** Is this the currently-playing card in Play All */
|
|
37
36
|
playAllActive?: boolean;
|
|
37
|
+
/** Name of the currently executing agent (when on a RunAgent node) */
|
|
38
|
+
agentName?: string | null;
|
|
39
|
+
/** Error message from a failed workflow execution */
|
|
40
|
+
errorMessage?: string | null;
|
|
41
|
+
/** Whether this card represents an epic node */
|
|
42
|
+
isEpic?: boolean;
|
|
38
43
|
|
|
39
44
|
/* Callbacks */
|
|
40
45
|
onClick?: () => void;
|
|
41
46
|
onCopy?: () => void;
|
|
42
47
|
onPlay?: () => void;
|
|
48
|
+
onPlayDropdown?: () => void;
|
|
49
|
+
onStop?: () => void;
|
|
43
50
|
onResume?: () => void;
|
|
44
51
|
onUnblock?: () => void;
|
|
45
52
|
onIssuesClick?: () => void;
|
|
53
|
+
onMonitorClick?: () => void;
|
|
46
54
|
|
|
47
55
|
/* Drag */
|
|
48
56
|
draggable?: boolean;
|
|
@@ -50,57 +58,41 @@ export interface KanbanCardProps {
|
|
|
50
58
|
onDragEnd?: (e: React.DragEvent) => void;
|
|
51
59
|
}
|
|
52
60
|
|
|
53
|
-
/* ──
|
|
61
|
+
/* ── Status style helpers ── */
|
|
54
62
|
|
|
55
|
-
function
|
|
56
|
-
if (
|
|
63
|
+
function statusCls(status: string): string {
|
|
64
|
+
if (status === 'running') return 'bg-accent/10 text-accent animate-pulse';
|
|
57
65
|
switch (status) {
|
|
58
66
|
case 'completed': return 'bg-emerald-500/10 text-emerald-400';
|
|
59
67
|
case 'failed': return 'bg-error/10 text-error';
|
|
60
|
-
case 'blocked': return 'bg-error/10 text-error';
|
|
61
|
-
case 'interrupted': return 'bg-amber-500/10 text-amber-400';
|
|
62
68
|
default: return 'bg-white/[0.06] text-content-muted';
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
71
|
|
|
66
|
-
function
|
|
67
|
-
if (
|
|
72
|
+
function statusIcon(status: string) {
|
|
73
|
+
if (status === 'running') return <CircleDot size={12} strokeWidth={2.5} />;
|
|
68
74
|
if (status === 'failed') return <AlertTriangle size={12} strokeWidth={2.5} />;
|
|
69
75
|
return null;
|
|
70
76
|
}
|
|
71
77
|
|
|
72
|
-
/* ──
|
|
78
|
+
/* ── Component ── */
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
if (!kind || kind === 'new') return null;
|
|
76
|
-
const cls = kind === 'improvement'
|
|
77
|
-
? 'text-blue-400 bg-blue-400/15'
|
|
78
|
-
: 'text-amber-400 bg-amber-400/15';
|
|
79
|
-
return (
|
|
80
|
-
<span className={`rounded px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide ${cls}`}>
|
|
81
|
-
{kind}
|
|
82
|
-
</span>
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/* ── Card component ── */
|
|
87
|
-
|
|
88
|
-
export function KanbanCard({
|
|
80
|
+
export const KanbanCard = ({
|
|
89
81
|
id, name, pct, kind, rejectionCount, blocked, pipeline, pipelineLabel: pipLabel,
|
|
90
|
-
|
|
91
|
-
playAllActive,
|
|
92
|
-
|
|
82
|
+
issueCount, issueLabel, showPlay, showPlayDropdown, showStop, showResume, copied,
|
|
83
|
+
playAllActive, agentName, errorMessage,
|
|
84
|
+
isEpic,
|
|
85
|
+
onClick, onCopy, onPlay, onPlayDropdown, onStop, onResume, onUnblock, onIssuesClick, onMonitorClick,
|
|
93
86
|
draggable, onDragStart, onDragEnd,
|
|
94
|
-
}: KanbanCardProps) {
|
|
87
|
+
}: KanbanCardProps) => {
|
|
95
88
|
const hasPipeline = pipeline !== 'idle' && !!pipLabel;
|
|
96
|
-
const
|
|
97
|
-
const hasStatusRow = rejectionCount > 0 || hasPipeline || !!stopReason;
|
|
89
|
+
const hasStatusRow = rejectionCount > 0 || hasPipeline;
|
|
98
90
|
|
|
99
91
|
const stripColor = blocked
|
|
100
92
|
? 'from-error/60 to-error/20'
|
|
101
93
|
: rejectionCount >= 3
|
|
102
94
|
? 'from-error/40 to-amber-500/20'
|
|
103
|
-
:
|
|
95
|
+
: pipeline === 'running'
|
|
104
96
|
? 'from-accent/60 to-accent/20'
|
|
105
97
|
: pipeline === 'completed'
|
|
106
98
|
? 'from-emerald-400/60 to-emerald-400/20'
|
|
@@ -115,7 +107,12 @@ export function KanbanCard({
|
|
|
115
107
|
|
|
116
108
|
return (
|
|
117
109
|
<div
|
|
118
|
-
className=
|
|
110
|
+
className={[
|
|
111
|
+
'group relative shrink-0 overflow-hidden rounded-2xl border shadow-lg shadow-black/10 backdrop-blur-sm transition-all duration-200 hover:border-content/15 hover:shadow-xl hover:shadow-black/15 cursor-pointer',
|
|
112
|
+
isEpic
|
|
113
|
+
? 'bg-gradient-to-br from-accent/[0.06] to-accent/[0.02] border-accent/15'
|
|
114
|
+
: 'bg-surface border-edge',
|
|
115
|
+
].join(' ')}
|
|
119
116
|
draggable={draggable}
|
|
120
117
|
onDragStart={onDragStart}
|
|
121
118
|
onDragEnd={onDragEnd}
|
|
@@ -142,18 +139,37 @@ export function KanbanCard({
|
|
|
142
139
|
<span className="flex items-center gap-1.5 rounded-full bg-error/15 px-2.5 py-1 text-[11px] font-bold text-error backdrop-blur">
|
|
143
140
|
<Lock size={11} strokeWidth={2.5} /> Blocked
|
|
144
141
|
</span>
|
|
145
|
-
) :
|
|
142
|
+
) : showStop ? (
|
|
146
143
|
<button
|
|
147
|
-
className="flex h-7 w-7 items-center justify-center rounded-full
|
|
148
|
-
title="
|
|
149
|
-
onClick={(e) => { e.stopPropagation();
|
|
144
|
+
className="flex h-7 w-7 items-center justify-center rounded-full border border-error text-error text-[12px] hover:bg-error hover:text-surface transition-colors cursor-pointer"
|
|
145
|
+
title="Stop processing epic"
|
|
146
|
+
onClick={(e) => { e.stopPropagation(); onStop?.(); }}
|
|
150
147
|
>
|
|
151
|
-
|
|
148
|
+
{'\u25A0'}
|
|
152
149
|
</button>
|
|
150
|
+
) : showPlay ? (
|
|
151
|
+
<div className="flex items-center">
|
|
152
|
+
<button
|
|
153
|
+
className="flex h-7 w-7 items-center justify-center rounded-full bg-accent/10 text-accent backdrop-blur transition-all hover:bg-accent hover:text-surface hover:shadow-[0_0_12px_-2px_var(--accent)] cursor-pointer"
|
|
154
|
+
title="Start default workflow"
|
|
155
|
+
onClick={(e) => { e.stopPropagation(); onPlay?.(); }}
|
|
156
|
+
>
|
|
157
|
+
<Play size={12} strokeWidth={2.5} fill="currentColor" />
|
|
158
|
+
</button>
|
|
159
|
+
{showPlayDropdown && (
|
|
160
|
+
<button
|
|
161
|
+
className="flex h-7 w-5 items-center justify-center rounded-r-full text-accent/60 hover:text-accent transition-colors cursor-pointer"
|
|
162
|
+
title="Choose workflow"
|
|
163
|
+
onClick={(e) => { e.stopPropagation(); onPlayDropdown?.(); }}
|
|
164
|
+
>
|
|
165
|
+
<ChevronDown size={12} strokeWidth={2.5} />
|
|
166
|
+
</button>
|
|
167
|
+
)}
|
|
168
|
+
</div>
|
|
153
169
|
) : showResume ? (
|
|
154
170
|
<button
|
|
155
171
|
className="flex h-7 w-7 items-center justify-center rounded-full bg-accent/10 text-accent backdrop-blur transition-all hover:bg-accent hover:text-surface hover:shadow-[0_0_12px_-2px_var(--accent)] cursor-pointer"
|
|
156
|
-
title="Resume
|
|
172
|
+
title="Resume workflow from last completed step"
|
|
157
173
|
onClick={(e) => { e.stopPropagation(); onResume?.(); }}
|
|
158
174
|
>
|
|
159
175
|
<Play size={12} strokeWidth={2.5} fill="currentColor" />
|
|
@@ -164,6 +180,26 @@ export function KanbanCard({
|
|
|
164
180
|
{/* Name */}
|
|
165
181
|
<div className="mt-2.5 text-[14px] font-semibold leading-snug text-content">{name}</div>
|
|
166
182
|
|
|
183
|
+
{/* Agent tag — shows when a RunAgent node is executing */}
|
|
184
|
+
{agentName && (
|
|
185
|
+
<div className="mt-2 inline-flex items-center gap-1.5 rounded-full bg-accent/10 px-2.5 py-1 text-[10px] font-semibold text-accent animate-pulse backdrop-blur">
|
|
186
|
+
<CircleDot size={10} strokeWidth={2.5} />
|
|
187
|
+
{agentName}
|
|
188
|
+
</div>
|
|
189
|
+
)}
|
|
190
|
+
|
|
191
|
+
{/* Error tag — shows when workflow failed, clickable to open monitor */}
|
|
192
|
+
{errorMessage && pipeline === 'failed' && (
|
|
193
|
+
<button
|
|
194
|
+
className="mt-2 inline-flex items-center gap-1.5 rounded-full bg-error/10 px-2.5 py-1 text-[10px] font-semibold text-error backdrop-blur cursor-pointer transition-opacity hover:opacity-80"
|
|
195
|
+
title={errorMessage}
|
|
196
|
+
onClick={(e) => { e.stopPropagation(); onMonitorClick?.(); }}
|
|
197
|
+
>
|
|
198
|
+
<AlertTriangle size={10} strokeWidth={2.5} />
|
|
199
|
+
Error
|
|
200
|
+
</button>
|
|
201
|
+
)}
|
|
202
|
+
|
|
167
203
|
{/* Spec disc */}
|
|
168
204
|
<div className="mt-3 flex items-center gap-2">
|
|
169
205
|
<svg width="22" height="22" viewBox="0 0 22 22" className="shrink-0 -rotate-90">
|
|
@@ -183,46 +219,26 @@ export function KanbanCard({
|
|
|
183
219
|
<span className="font-mono text-[11px] text-content-secondary">{pct}%</span>
|
|
184
220
|
</div>
|
|
185
221
|
|
|
186
|
-
{/*
|
|
187
|
-
{
|
|
188
|
-
<div className="mt-3
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
)}
|
|
207
|
-
{/* Status row: rejected + pipeline + stop reason */}
|
|
208
|
-
{hasStatusRow && (
|
|
209
|
-
<div className="flex gap-1">
|
|
210
|
-
{rejectionCount > 0 && (
|
|
211
|
-
<span className="flex-1 rounded-full bg-amber-400/15 py-1 text-center text-[10px] font-semibold text-amber-400 backdrop-blur">
|
|
212
|
-
{rejectionCount}x rejected
|
|
213
|
-
</span>
|
|
214
|
-
)}
|
|
215
|
-
{hasPipeline && (
|
|
216
|
-
<span className={`flex-1 inline-flex items-center justify-center gap-1.5 rounded-full py-1 text-[10px] font-semibold backdrop-blur ${pipelineCls(pipeline)}`}>
|
|
217
|
-
{pipelineIcon(pipeline)}
|
|
218
|
-
{pipLabel}
|
|
219
|
-
</span>
|
|
220
|
-
)}
|
|
221
|
-
{stopReason && (
|
|
222
|
-
<span className="flex-1 rounded-full bg-accent-secondary/10 py-1 text-center font-mono text-[10px] text-accent-secondary backdrop-blur">{stopReason}</span>
|
|
223
|
-
)}
|
|
224
|
-
</div>
|
|
225
|
-
)}
|
|
222
|
+
{/* Status pills */}
|
|
223
|
+
{hasStatusRow && (
|
|
224
|
+
<div className="mt-3" onClick={(e) => e.stopPropagation()}>
|
|
225
|
+
<div className="flex gap-1">
|
|
226
|
+
{rejectionCount > 0 && (
|
|
227
|
+
<span className="flex-1 rounded-full bg-amber-400/15 py-1 text-center text-[10px] font-semibold text-amber-400 backdrop-blur">
|
|
228
|
+
{rejectionCount}x rejected
|
|
229
|
+
</span>
|
|
230
|
+
)}
|
|
231
|
+
{hasPipeline && (
|
|
232
|
+
<button
|
|
233
|
+
className={`flex-1 inline-flex items-center justify-center gap-1.5 rounded-full py-1 text-[10px] font-semibold backdrop-blur cursor-pointer transition-opacity hover:opacity-80 ${statusCls(pipeline)}`}
|
|
234
|
+
onClick={(e) => { e.stopPropagation(); onMonitorClick?.(); }}
|
|
235
|
+
title="Open workflow monitor"
|
|
236
|
+
>
|
|
237
|
+
{statusIcon(pipeline)}
|
|
238
|
+
{pipLabel}
|
|
239
|
+
</button>
|
|
240
|
+
)}
|
|
241
|
+
</div>
|
|
226
242
|
</div>
|
|
227
243
|
)}
|
|
228
244
|
|
|
@@ -251,4 +267,4 @@ export function KanbanCard({
|
|
|
251
267
|
</div>
|
|
252
268
|
</div>
|
|
253
269
|
);
|
|
254
|
-
}
|
|
270
|
+
};
|
|
@@ -1,216 +1,37 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
Play, AlertTriangle, Lock, CircleDot, Copy,
|
|
4
|
-
} from 'lucide-react';
|
|
1
|
+
import { CardGlass } from './CardGlass';
|
|
2
|
+
import type { DemoCard } from './CardGlass';
|
|
5
3
|
|
|
6
4
|
/* ── Demo data ── */
|
|
7
5
|
|
|
8
|
-
interface DemoCard {
|
|
9
|
-
id: string;
|
|
10
|
-
name: string;
|
|
11
|
-
pct: number;
|
|
12
|
-
kind: 'new' | 'improvement' | 'bugfix';
|
|
13
|
-
rejections: number;
|
|
14
|
-
pipeline: 'idle' | 'active' | 'completed' | 'failed' | 'interrupted' | 'blocked';
|
|
15
|
-
blocked: boolean;
|
|
16
|
-
issues: number;
|
|
17
|
-
stage: 'in_progress' | 'in_review' | 'qa';
|
|
18
|
-
tools: { read: number; tools: number; write: number; edit: number };
|
|
19
|
-
ctx: string;
|
|
20
|
-
turns: number;
|
|
21
|
-
cost: string;
|
|
22
|
-
model: string;
|
|
23
|
-
stop: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
6
|
const DEMO_CARDS: DemoCard[] = [
|
|
27
7
|
{
|
|
28
8
|
id: 'feat_0f2d6616', name: 'TailwindCSS Integration', pct: 100, kind: 'new',
|
|
29
9
|
rejections: 1, pipeline: 'interrupted', blocked: false, issues: 1,
|
|
30
|
-
stage: 'in_review',
|
|
31
|
-
ctx: '17%', turns: 19, cost: '$0.3948', model: 'opus-4', stop: 'end_turn',
|
|
10
|
+
stage: 'in_review',
|
|
32
11
|
},
|
|
33
12
|
{
|
|
34
13
|
id: 'feat_a3c71b02', name: 'Auth Flow Redesign', pct: 72, kind: 'improvement',
|
|
35
14
|
rejections: 0, pipeline: 'active', blocked: false, issues: 0,
|
|
36
|
-
stage: 'in_progress',
|
|
37
|
-
ctx: '34%', turns: 26, cost: '$0.5120', model: 'sonnet-4', stop: '',
|
|
15
|
+
stage: 'in_progress',
|
|
38
16
|
},
|
|
39
17
|
{
|
|
40
18
|
id: 'feat_9e45f1d8', name: 'WebSocket Events', pct: 45, kind: 'new',
|
|
41
19
|
rejections: 3, pipeline: 'failed', blocked: false, issues: 3,
|
|
42
|
-
stage: 'qa',
|
|
43
|
-
ctx: '9%', turns: 11, cost: '$0.1840', model: 'opus-4', stop: 'max_turns',
|
|
20
|
+
stage: 'qa',
|
|
44
21
|
},
|
|
45
22
|
{
|
|
46
23
|
id: 'feat_b7d20cc4', name: 'Rate Limiter Middleware', pct: 88, kind: 'bugfix',
|
|
47
24
|
rejections: 0, pipeline: 'idle', blocked: true, issues: 0,
|
|
48
|
-
stage: 'in_progress',
|
|
49
|
-
ctx: '', turns: 0, cost: '', model: '', stop: '',
|
|
25
|
+
stage: 'in_progress',
|
|
50
26
|
},
|
|
51
27
|
];
|
|
52
28
|
|
|
53
|
-
/* ──
|
|
54
|
-
|
|
55
|
-
function pipelineStyle(status: DemoCard['pipeline']): string {
|
|
56
|
-
switch (status) {
|
|
57
|
-
case 'active': return 'bg-accent/10 text-accent animate-pulse';
|
|
58
|
-
case 'completed': return 'bg-emerald-500/10 text-emerald-400';
|
|
59
|
-
case 'failed': return 'bg-error/10 text-error';
|
|
60
|
-
case 'blocked': return 'bg-error/10 text-error';
|
|
61
|
-
case 'interrupted': return 'bg-amber-500/10 text-amber-400';
|
|
62
|
-
default: return '';
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function pipelineLabel(status: DemoCard['pipeline'], rejections: number): string {
|
|
67
|
-
if (rejections >= 1 && status !== 'idle') return `Retry ${rejections + 1}`;
|
|
68
|
-
switch (status) {
|
|
69
|
-
case 'active': return 'Running...';
|
|
70
|
-
case 'completed': return 'Completed';
|
|
71
|
-
case 'failed': return 'Failed';
|
|
72
|
-
case 'blocked': return 'Blocked';
|
|
73
|
-
case 'interrupted': return 'Interrupted';
|
|
74
|
-
default: return '';
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/* ── Kind badge ── */
|
|
79
|
-
|
|
80
|
-
function KindBadge({ kind }: { kind: DemoCard['kind'] }) {
|
|
81
|
-
if (kind === 'new') return null;
|
|
82
|
-
const cls = kind === 'improvement'
|
|
83
|
-
? 'text-blue-400 bg-blue-400/15'
|
|
84
|
-
: 'text-amber-400 bg-amber-400/15';
|
|
85
|
-
return (
|
|
86
|
-
<span className={`rounded px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide ${cls}`}>
|
|
87
|
-
{kind}
|
|
88
|
-
</span>
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/* ── Glass Card ── */
|
|
93
|
-
|
|
94
|
-
function CardGlass({ card }: { card: DemoCard }) {
|
|
95
|
-
const hasTools = Object.values(card.tools).some(v => v > 0);
|
|
96
|
-
const hasPipeline = card.pipeline !== 'idle';
|
|
97
|
-
const hasStatusRow = card.rejections > 0 || hasPipeline || card.stop;
|
|
98
|
-
const stripColor = card.blocked
|
|
99
|
-
? 'from-error/60 to-error/20'
|
|
100
|
-
: card.rejections >= 3
|
|
101
|
-
? 'from-error/40 to-amber-500/20'
|
|
102
|
-
: card.pipeline === 'active'
|
|
103
|
-
? 'from-accent/60 to-accent/20'
|
|
104
|
-
: card.pipeline === 'completed'
|
|
105
|
-
? 'from-emerald-400/60 to-emerald-400/20'
|
|
106
|
-
: 'from-edge to-transparent';
|
|
107
|
-
|
|
108
|
-
return (
|
|
109
|
-
<div className="group relative overflow-hidden rounded-2xl bg-surface border border-edge shadow-lg shadow-black/10 backdrop-blur-sm transition-all duration-200 hover:border-content/15 hover:shadow-xl hover:shadow-black/15">
|
|
110
|
-
<div className={`absolute left-0 top-0 h-full w-1 bg-gradient-to-b ${stripColor}`} />
|
|
111
|
-
<div className="p-5 pl-6">
|
|
112
|
-
{/* Header */}
|
|
113
|
-
<div className="flex items-center gap-2.5">
|
|
114
|
-
<span className="font-mono text-[12px] text-content-secondary">{card.id}</span>
|
|
115
|
-
<KindBadge kind={card.kind} />
|
|
116
|
-
<button className="flex h-6 w-6 items-center justify-center rounded-md bg-white/[0.08] text-content-secondary transition-colors hover:bg-white/15 hover:text-content cursor-pointer">
|
|
117
|
-
<Copy size={12} strokeWidth={2} />
|
|
118
|
-
</button>
|
|
119
|
-
<div className="flex-1" />
|
|
120
|
-
{card.blocked ? (
|
|
121
|
-
<span className="flex items-center gap-1.5 rounded-full bg-error/15 px-2.5 py-1 text-[11px] font-bold text-error backdrop-blur">
|
|
122
|
-
<Lock size={11} strokeWidth={2.5} /> Blocked
|
|
123
|
-
</span>
|
|
124
|
-
) : card.pipeline === 'idle' ? (
|
|
125
|
-
<button className="flex h-7 w-7 items-center justify-center rounded-full bg-accent/10 text-accent backdrop-blur transition-all hover:bg-accent hover:text-surface hover:shadow-[0_0_12px_-2px_var(--accent)] cursor-pointer">
|
|
126
|
-
<Play size={12} strokeWidth={2.5} fill="currentColor" />
|
|
127
|
-
</button>
|
|
128
|
-
) : null}
|
|
129
|
-
</div>
|
|
130
|
-
|
|
131
|
-
{/* Name */}
|
|
132
|
-
<div className="mt-3 text-[15px] font-semibold leading-snug text-content">{card.name}</div>
|
|
133
|
-
|
|
134
|
-
{/* Spec disc */}
|
|
135
|
-
<div className="mt-3.5 flex items-center gap-2.5">
|
|
136
|
-
<svg width="24" height="24" viewBox="0 0 24 24" className="shrink-0 -rotate-90">
|
|
137
|
-
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" strokeWidth="2.5" className="text-white/5" />
|
|
138
|
-
<circle
|
|
139
|
-
cx="12" cy="12" r="10" fill="none" strokeWidth="2.5"
|
|
140
|
-
stroke="url(#specGrad)" strokeLinecap="round"
|
|
141
|
-
strokeDasharray={`${(card.pct / 100) * 2 * Math.PI * 10} ${2 * Math.PI * 10}`}
|
|
142
|
-
/>
|
|
143
|
-
<defs>
|
|
144
|
-
<linearGradient id="specGrad" x1="0" y1="0" x2="1" y2="1">
|
|
145
|
-
<stop offset="0%" stopColor="var(--completeness-fill)" />
|
|
146
|
-
<stop offset="100%" stopColor="var(--accent)" stopOpacity="0.6" />
|
|
147
|
-
</linearGradient>
|
|
148
|
-
</defs>
|
|
149
|
-
</svg>
|
|
150
|
-
<span className="font-mono text-[12px] text-content-secondary">{card.pct}%</span>
|
|
151
|
-
</div>
|
|
152
|
-
|
|
153
|
-
{/* Stats — evenly spaced pills */}
|
|
154
|
-
{(hasTools || hasStatusRow) && (
|
|
155
|
-
<div className="mt-3.5 space-y-2">
|
|
156
|
-
{hasTools && (
|
|
157
|
-
<div className="flex gap-1.5">
|
|
158
|
-
{Object.entries(card.tools).filter(([, v]) => v > 0).map(([k, v]) => (
|
|
159
|
-
<span key={k} className="flex-1 rounded-full bg-accent/10 py-1 text-center font-mono text-[11px] font-medium text-accent backdrop-blur">
|
|
160
|
-
{k.charAt(0).toUpperCase() + k.slice(1)}: {v}
|
|
161
|
-
</span>
|
|
162
|
-
))}
|
|
163
|
-
</div>
|
|
164
|
-
)}
|
|
165
|
-
{hasTools && (
|
|
166
|
-
<div className="flex gap-1.5">
|
|
167
|
-
{[card.ctx && `Ctx ${card.ctx}`, card.turns > 0 && `${card.turns}t`, card.cost, card.model].filter(Boolean).map(t => (
|
|
168
|
-
<span key={t as string} className="flex-1 rounded-full bg-white/[0.08] py-1 text-center font-mono text-[11px] text-content backdrop-blur">{t}</span>
|
|
169
|
-
))}
|
|
170
|
-
</div>
|
|
171
|
-
)}
|
|
172
|
-
{hasStatusRow && (
|
|
173
|
-
<div className="flex gap-1.5">
|
|
174
|
-
{card.rejections > 0 && (
|
|
175
|
-
<span className="flex-1 rounded-full bg-amber-400/15 py-1 text-center text-[11px] font-semibold text-amber-400 backdrop-blur">
|
|
176
|
-
{card.rejections}x rejected
|
|
177
|
-
</span>
|
|
178
|
-
)}
|
|
179
|
-
{hasPipeline && (
|
|
180
|
-
<span className={`flex-1 inline-flex items-center justify-center gap-1.5 rounded-full py-1 text-[11px] font-semibold backdrop-blur ${pipelineStyle(card.pipeline)}`}>
|
|
181
|
-
{card.pipeline === 'active' && <CircleDot size={12} strokeWidth={2.5} />}
|
|
182
|
-
{card.pipeline === 'failed' && <AlertTriangle size={12} strokeWidth={2.5} />}
|
|
183
|
-
{pipelineLabel(card.pipeline, card.rejections)}
|
|
184
|
-
</span>
|
|
185
|
-
)}
|
|
186
|
-
{card.stop && (
|
|
187
|
-
<span className="flex-1 rounded-full bg-accent-secondary/10 py-1 text-center font-mono text-[11px] text-accent-secondary backdrop-blur">{card.stop}</span>
|
|
188
|
-
)}
|
|
189
|
-
</div>
|
|
190
|
-
)}
|
|
191
|
-
</div>
|
|
192
|
-
)}
|
|
193
|
-
|
|
194
|
-
{/* Issues */}
|
|
195
|
-
<button className={[
|
|
196
|
-
'mt-3.5 w-full rounded-full border py-2 text-center text-[12px] font-mono backdrop-blur transition-all cursor-pointer',
|
|
197
|
-
card.issues > 0
|
|
198
|
-
? 'border-white/10 text-content-secondary hover:border-accent/30 hover:text-accent'
|
|
199
|
-
: 'border-white/5 text-content-muted/50 hover:border-white/10 hover:text-content-muted',
|
|
200
|
-
].join(' ')}>
|
|
201
|
-
{card.issues > 0 ? `${card.issues} issue${card.issues !== 1 ? 's' : ''} reported` : 'No issues'}
|
|
202
|
-
</button>
|
|
203
|
-
</div>
|
|
204
|
-
</div>
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/* ── Showcase export ── */
|
|
29
|
+
/* ── Component ── */
|
|
209
30
|
|
|
210
|
-
export
|
|
31
|
+
export const KanbanCardShowcase = () => {
|
|
211
32
|
return (
|
|
212
33
|
<div className="grid grid-cols-2 gap-3 lg:grid-cols-4">
|
|
213
34
|
{DEMO_CARDS.map(c => <CardGlass key={c.id} card={c} />)}
|
|
214
35
|
</div>
|
|
215
36
|
);
|
|
216
|
-
}
|
|
37
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const Kbd = ({ children }: Props) => (
|
|
8
|
+
<kbd className="inline-block px-1.5 py-px text-[11px] font-inherit bg-surface-raised border border-edge rounded text-content">
|
|
9
|
+
{children}
|
|
10
|
+
</kbd>
|
|
11
|
+
);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* ── Types ── */
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
kind: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/* ── Component ── */
|
|
8
|
+
|
|
9
|
+
export const KindBadge = ({ kind }: Props) => {
|
|
10
|
+
if (!kind || kind === 'new') return null;
|
|
11
|
+
|
|
12
|
+
const cls = kind === 'improvement'
|
|
13
|
+
? 'text-blue-400 bg-blue-400/15'
|
|
14
|
+
: 'text-amber-400 bg-amber-400/15';
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<span className={`rounded px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide ${cls}`}>
|
|
18
|
+
{kind}
|
|
19
|
+
</span>
|
|
20
|
+
);
|
|
21
|
+
};
|