beads-kanban-ui 0.1.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/.designs/beads-kanban-ui-bj0.md +73 -0
- package/.designs/beads-kanban-ui-qxq.md +144 -0
- package/.designs/epic-support.md +282 -0
- package/.env.local.example +2 -0
- package/.eslintrc.json +3 -0
- package/.gitattributes +3 -0
- package/.github/workflows/release.yml +123 -0
- package/.history/README_20260121193710.md +227 -0
- package/.history/README_20260121193918.md +227 -0
- package/.history/README_20260121193921.md +227 -0
- package/.history/README_20260121193933.md +227 -0
- package/.history/README_20260121193934.md +227 -0
- package/.history/README_20260121193944.md +227 -0
- package/.history/README_20260121193953.md +227 -0
- package/.history/src/app/page_20260121133429.tsx +134 -0
- package/.history/src/app/page_20260121133928.tsx +134 -0
- package/.history/src/app/page_20260121144850.tsx +138 -0
- package/.history/src/app/page_20260121144854.tsx +138 -0
- package/.history/src/app/page_20260121144858.tsx +138 -0
- package/.history/src/app/page_20260121144902.tsx +138 -0
- package/.history/src/app/page_20260121144906.tsx +138 -0
- package/.history/src/app/page_20260121144911.tsx +138 -0
- package/.history/src/app/page_20260121144928.tsx +138 -0
- package/.playwright-mcp/.playwright-mcp/morphing-dialog-wheel-scroll-fix.png +0 -0
- package/.playwright-mcp/beams-test.png +0 -0
- package/.playwright-mcp/card-verification.png +0 -0
- package/.playwright-mcp/design-doc-dialog-fix-verification.png +0 -0
- package/.playwright-mcp/dialog-width-test.png +0 -0
- package/.playwright-mcp/homepage.png +0 -0
- package/.playwright-mcp/morphing-dialog-expanded.png +0 -0
- package/.playwright-mcp/morphing-dialog-fixes-final.png +0 -0
- package/.playwright-mcp/morphing-dialog-open.png +0 -0
- package/.playwright-mcp/page-2026-01-21T14-08-31-529Z.png +0 -0
- package/.playwright-mcp/page-2026-01-21T14-09-23-431Z.png +0 -0
- package/.playwright-mcp/page-2026-01-21T14-10-28-773Z.png +0 -0
- package/.playwright-mcp/page-2026-01-21T14-10-47-432Z.png +0 -0
- package/.playwright-mcp/page-2026-01-21T14-11-12-350Z.png +0 -0
- package/.playwright-mcp/screenshot-after-click.png +0 -0
- package/.playwright-mcp/screenshot-after-dialog-click.png +0 -0
- package/.playwright-mcp/sheet-restored-after-dialog-close.png +0 -0
- package/.playwright-mcp/test-1-sheet-open-with-overlay.png +0 -0
- package/.playwright-mcp/test-2-morphing-dialog-with-overlay.png +0 -0
- package/.playwright-mcp/test-3-sheet-open-dark-overlay.png +0 -0
- package/.playwright-mcp/test-4-morphing-dialog-with-dark-overlay.png +0 -0
- package/.playwright-mcp/test-5-morphing-dialog-scrolled.png +0 -0
- package/.playwright-mcp/test-6-sheet-restored-after-dialog-close.png +0 -0
- package/.playwright-mcp/wheel-scroll-fixed.png +0 -0
- package/README.md +243 -0
- package/Screenshots/bead-detail.png +0 -0
- package/Screenshots/dashboard.png +0 -0
- package/Screenshots/kanban-board.png +0 -0
- package/components.json +27 -0
- package/logo/logo.svg +1 -0
- package/next.config.js +9 -0
- package/npm/README.md +37 -0
- package/npm/bin/cli.js +107 -0
- package/npm/package.json +20 -0
- package/npm/scripts/postinstall.js +132 -0
- package/package.json +62 -0
- package/postcss.config.js +6 -0
- package/public/logo.svg +1 -0
- package/restart.sh +5 -0
- package/server/Cargo.lock +1685 -0
- package/server/Cargo.toml +24 -0
- package/server/src/db.rs +570 -0
- package/server/src/main.rs +141 -0
- package/server/src/routes/beads.rs +413 -0
- package/server/src/routes/cli.rs +150 -0
- package/server/src/routes/fs.rs +360 -0
- package/server/src/routes/git.rs +169 -0
- package/server/src/routes/mod.rs +107 -0
- package/server/src/routes/projects.rs +177 -0
- package/server/src/routes/watch.rs +211 -0
- package/src/app/globals.css +101 -0
- package/src/app/layout.tsx +36 -0
- package/src/app/page.tsx +348 -0
- package/src/app/project/kanban-board.tsx +356 -0
- package/src/app/project/page.tsx +18 -0
- package/src/app/settings/page.tsx +224 -0
- package/src/components/Beams.css +5 -0
- package/src/components/Beams.jsx +307 -0
- package/src/components/Galaxy.css +5 -0
- package/src/components/Galaxy.jsx +333 -0
- package/src/components/activity-timeline.tsx +172 -0
- package/src/components/add-project-dialog.tsx +219 -0
- package/src/components/bead-card.tsx +196 -0
- package/src/components/bead-detail.tsx +306 -0
- package/src/components/color-picker.tsx +101 -0
- package/src/components/comment-input.tsx +155 -0
- package/src/components/comment-list.tsx +147 -0
- package/src/components/dependency-badge.tsx +106 -0
- package/src/components/design-doc-dialog.tsx +58 -0
- package/src/components/design-doc-preview.tsx +97 -0
- package/src/components/design-doc-viewer.tsx +199 -0
- package/src/components/editable-project-name.tsx +178 -0
- package/src/components/epic-card.tsx +263 -0
- package/src/components/folder-browser.tsx +273 -0
- package/src/components/footer.tsx +27 -0
- package/src/components/kanban/default.tsx +184 -0
- package/src/components/kanban-column.tsx +167 -0
- package/src/components/project-card.tsx +191 -0
- package/src/components/quick-filter-bar.tsx +279 -0
- package/src/components/scan-directory-dialog.tsx +368 -0
- package/src/components/status-donut.tsx +197 -0
- package/src/components/subtask-list.tsx +128 -0
- package/src/components/tag-picker.tsx +252 -0
- package/src/components/ui/.gitkeep +0 -0
- package/src/components/ui/alert-dialog.tsx +141 -0
- package/src/components/ui/avatar.tsx +67 -0
- package/src/components/ui/badge.tsx +230 -0
- package/src/components/ui/button.tsx +433 -0
- package/src/components/ui/card/index.tsx +24 -0
- package/src/components/ui/card/roiui-card.module.css +197 -0
- package/src/components/ui/card/roiui-card.tsx +154 -0
- package/src/components/ui/card/shadcn-card.tsx +76 -0
- package/src/components/ui/chart.tsx +369 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/dropdown-menu.tsx +201 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/kanban.tsx +522 -0
- package/src/components/ui/morphing-dialog.tsx +457 -0
- package/src/components/ui/popover.tsx +33 -0
- package/src/components/ui/progress.tsx +28 -0
- package/src/components/ui/scroll-area.tsx +48 -0
- package/src/components/ui/select.tsx +159 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/sheet.tsx +142 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/toast.tsx +129 -0
- package/src/components/ui/toaster.tsx +35 -0
- package/src/components/ui/tooltip.tsx +30 -0
- package/src/hooks/.gitkeep +0 -0
- package/src/hooks/use-bead-filters.ts +261 -0
- package/src/hooks/use-beads.ts +162 -0
- package/src/hooks/use-branch-statuses.ts +161 -0
- package/src/hooks/use-epics.ts +173 -0
- package/src/hooks/use-file-watcher.ts +111 -0
- package/src/hooks/use-keyboard-navigation.ts +282 -0
- package/src/hooks/use-project.ts +61 -0
- package/src/hooks/use-projects.ts +93 -0
- package/src/hooks/use-toast.ts +194 -0
- package/src/hooks/useClickOutside.tsx +26 -0
- package/src/lib/.gitkeep +0 -0
- package/src/lib/api.ts +186 -0
- package/src/lib/beads-parser.ts +252 -0
- package/src/lib/cli.ts +193 -0
- package/src/lib/db.ts +145 -0
- package/src/lib/design-doc.ts +74 -0
- package/src/lib/epic-parser.ts +242 -0
- package/src/lib/git.ts +102 -0
- package/src/lib/utils.ts +12 -0
- package/src/types/index.ts +107 -0
- package/tailwind.config.ts +85 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import dynamic from "next/dynamic";
|
|
6
|
+
import { Settings } from "lucide-react";
|
|
7
|
+
import { ProjectCard } from "@/components/project-card";
|
|
8
|
+
import { AddProjectDialog } from "@/components/add-project-dialog";
|
|
9
|
+
import { useProjects } from "@/hooks/use-projects";
|
|
10
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
11
|
+
|
|
12
|
+
// Dynamic import with SSR disabled for WebGL canvas component
|
|
13
|
+
const RippleGrid = dynamic(() => import("@/components/RippleGrid"), { ssr: false });
|
|
14
|
+
|
|
15
|
+
export default function ProjectsPage() {
|
|
16
|
+
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
|
|
17
|
+
const { projects, isLoading, error, addProject, updateProjectTags } = useProjects();
|
|
18
|
+
|
|
19
|
+
const handleAddProject = async (input: { name: string; path: string }) => {
|
|
20
|
+
await addProject(input);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className="dark relative min-h-screen bg-[#0d0b14]">
|
|
25
|
+
{/* RippleGrid Background - fixed, full-screen, z-0 */}
|
|
26
|
+
<div className="fixed inset-0 z-0 overflow-hidden">
|
|
27
|
+
<RippleGrid
|
|
28
|
+
gridColor="#302a4c"
|
|
29
|
+
rippleIntensity={0.02}
|
|
30
|
+
gridSize={15}
|
|
31
|
+
gridThickness={15}
|
|
32
|
+
fadeDistance={1.8}
|
|
33
|
+
vignetteStrength={0.5}
|
|
34
|
+
glowIntensity={0.4}
|
|
35
|
+
opacity={1}
|
|
36
|
+
gridRotation={0}
|
|
37
|
+
mouseInteractionRadius={0.8}
|
|
38
|
+
mouseInteraction={false}
|
|
39
|
+
enableRainbow={false}
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
{/* Settings Icon - fixed top-right, z-20 */}
|
|
44
|
+
<Link
|
|
45
|
+
href="/settings"
|
|
46
|
+
aria-label="Settings"
|
|
47
|
+
className="fixed right-6 top-6 z-20 rounded-md p-2 text-zinc-400 hover:bg-zinc-800/50 hover:text-zinc-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-400 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent"
|
|
48
|
+
>
|
|
49
|
+
<Settings className="h-5 w-5" aria-hidden="true" />
|
|
50
|
+
</Link>
|
|
51
|
+
|
|
52
|
+
{/* Main Content */}
|
|
53
|
+
<main className="relative z-10 flex flex-col items-center px-6 py-16">
|
|
54
|
+
{/* Centered Heading with Space Grotesk */}
|
|
55
|
+
<h1 className="mb-12 text-center text-balance font-heading text-4xl font-bold tracking-tight text-white sm:text-5xl">
|
|
56
|
+
Manage Your Beads Projects
|
|
57
|
+
</h1>
|
|
58
|
+
|
|
59
|
+
<div className="w-full max-w-[1200px]">
|
|
60
|
+
{isLoading ? (
|
|
61
|
+
<div role="status" aria-label="Loading projects" className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
62
|
+
{[1, 2, 3].map((i) => (
|
|
63
|
+
<div key={i} className="rounded-xl border bg-card/70 p-4 backdrop-blur-md">
|
|
64
|
+
<div className="mb-3 flex gap-1.5">
|
|
65
|
+
<Skeleton className="h-5 w-16" />
|
|
66
|
+
<Skeleton className="h-5 w-12" />
|
|
67
|
+
</div>
|
|
68
|
+
<Skeleton className="h-5 w-40" />
|
|
69
|
+
<Skeleton className="mt-2 h-4 w-48" />
|
|
70
|
+
<Skeleton className="mt-4 h-4 w-32" />
|
|
71
|
+
<Skeleton className="mt-2 h-3 w-28" />
|
|
72
|
+
</div>
|
|
73
|
+
))}
|
|
74
|
+
</div>
|
|
75
|
+
) : error ? (
|
|
76
|
+
<div className="rounded-lg border border-red-800/50 bg-red-950/70 p-6 text-center backdrop-blur-md">
|
|
77
|
+
<p className="text-red-400">Error loading projects: {error.message}</p>
|
|
78
|
+
<p className="mt-2 text-sm text-red-500">
|
|
79
|
+
Make sure the Tauri backend is running.
|
|
80
|
+
</p>
|
|
81
|
+
</div>
|
|
82
|
+
) : projects.length === 0 ? (
|
|
83
|
+
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
84
|
+
<div className="rounded-lg border border-dashed border-zinc-700 bg-card/70 p-6 text-center text-zinc-400 backdrop-blur-md">
|
|
85
|
+
<p>No projects yet</p>
|
|
86
|
+
<p className="mt-1 text-sm text-zinc-500">Click the button below to add a project</p>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
) : (
|
|
90
|
+
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
91
|
+
{projects.map((project) => (
|
|
92
|
+
<ProjectCard
|
|
93
|
+
key={project.id}
|
|
94
|
+
id={project.id}
|
|
95
|
+
name={project.name}
|
|
96
|
+
path={project.path}
|
|
97
|
+
tags={project.tags}
|
|
98
|
+
beadCounts={project.beadCounts}
|
|
99
|
+
onTagsChange={(tags) => updateProjectTags(project.id, tags)}
|
|
100
|
+
/>
|
|
101
|
+
))}
|
|
102
|
+
</div>
|
|
103
|
+
)}
|
|
104
|
+
</div>
|
|
105
|
+
</main>
|
|
106
|
+
|
|
107
|
+
{/* FAB - Add Project, z-20 */}
|
|
108
|
+
<button
|
|
109
|
+
onClick={() => setIsAddDialogOpen(true)}
|
|
110
|
+
className="fixed bottom-6 right-6 z-20 flex h-14 w-14 items-center justify-center rounded-full bg-zinc-100 text-zinc-900 shadow-lg hover:bg-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-100 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent"
|
|
111
|
+
aria-label="Add Project"
|
|
112
|
+
>
|
|
113
|
+
<svg
|
|
114
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
115
|
+
width="24"
|
|
116
|
+
height="24"
|
|
117
|
+
viewBox="0 0 24 24"
|
|
118
|
+
fill="none"
|
|
119
|
+
stroke="currentColor"
|
|
120
|
+
strokeWidth="2"
|
|
121
|
+
strokeLinecap="round"
|
|
122
|
+
strokeLinejoin="round"
|
|
123
|
+
aria-hidden="true"
|
|
124
|
+
>
|
|
125
|
+
<path d="M5 12h14" />
|
|
126
|
+
<path d="M12 5v14" />
|
|
127
|
+
</svg>
|
|
128
|
+
</button>
|
|
129
|
+
|
|
130
|
+
{/* Add Project Dialog */}
|
|
131
|
+
<AddProjectDialog
|
|
132
|
+
open={isAddDialogOpen}
|
|
133
|
+
onOpenChange={setIsAddDialogOpen}
|
|
134
|
+
onAddProject={handleAddProject}
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import dynamic from "next/dynamic";
|
|
6
|
+
import { Settings } from "lucide-react";
|
|
7
|
+
import { ProjectCard } from "@/components/project-card";
|
|
8
|
+
import { AddProjectDialog } from "@/components/add-project-dialog";
|
|
9
|
+
import { useProjects } from "@/hooks/use-projects";
|
|
10
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
11
|
+
|
|
12
|
+
// Dynamic import with SSR disabled for WebGL canvas component
|
|
13
|
+
const RippleGrid = dynamic(() => import("@/components/RippleGrid"), { ssr: false });
|
|
14
|
+
|
|
15
|
+
export default function ProjectsPage() {
|
|
16
|
+
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
|
|
17
|
+
const { projects, isLoading, error, addProject, updateProjectTags } = useProjects();
|
|
18
|
+
|
|
19
|
+
const handleAddProject = async (input: { name: string; path: string }) => {
|
|
20
|
+
await addProject(input);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className="dark relative min-h-screen bg-[#0d0b14]">
|
|
25
|
+
{/* RippleGrid Background - fixed, full-screen, z-0 */}
|
|
26
|
+
<div className="fixed inset-0 z-0 overflow-hidden">
|
|
27
|
+
<RippleGrid
|
|
28
|
+
gridColor="#302a4c"
|
|
29
|
+
rippleIntensity={0.02}
|
|
30
|
+
gridSize={15}
|
|
31
|
+
gridThickness={15}
|
|
32
|
+
fadeDistance={1.8}
|
|
33
|
+
vignetteStrength={0.5}
|
|
34
|
+
glowIntensity={0.4}
|
|
35
|
+
opacity={1}
|
|
36
|
+
gridRotation={45}
|
|
37
|
+
mouseInteractionRadius={0.8}
|
|
38
|
+
mouseInteraction={false}
|
|
39
|
+
enableRainbow={false}
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
{/* Settings Icon - fixed top-right, z-20 */}
|
|
44
|
+
<Link
|
|
45
|
+
href="/settings"
|
|
46
|
+
aria-label="Settings"
|
|
47
|
+
className="fixed right-6 top-6 z-20 rounded-md p-2 text-zinc-400 hover:bg-zinc-800/50 hover:text-zinc-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-400 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent"
|
|
48
|
+
>
|
|
49
|
+
<Settings className="h-5 w-5" aria-hidden="true" />
|
|
50
|
+
</Link>
|
|
51
|
+
|
|
52
|
+
{/* Main Content */}
|
|
53
|
+
<main className="relative z-10 flex flex-col items-center px-6 py-16">
|
|
54
|
+
{/* Centered Heading with Space Grotesk */}
|
|
55
|
+
<h1 className="mb-12 text-center text-balance font-heading text-4xl font-bold tracking-tight text-white sm:text-5xl">
|
|
56
|
+
Manage Your Beads Projects
|
|
57
|
+
</h1>
|
|
58
|
+
|
|
59
|
+
<div className="w-full max-w-[1200px]">
|
|
60
|
+
{isLoading ? (
|
|
61
|
+
<div role="status" aria-label="Loading projects" className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
62
|
+
{[1, 2, 3].map((i) => (
|
|
63
|
+
<div key={i} className="rounded-xl border bg-card/70 p-4 backdrop-blur-md">
|
|
64
|
+
<div className="mb-3 flex gap-1.5">
|
|
65
|
+
<Skeleton className="h-5 w-16" />
|
|
66
|
+
<Skeleton className="h-5 w-12" />
|
|
67
|
+
</div>
|
|
68
|
+
<Skeleton className="h-5 w-40" />
|
|
69
|
+
<Skeleton className="mt-2 h-4 w-48" />
|
|
70
|
+
<Skeleton className="mt-4 h-4 w-32" />
|
|
71
|
+
<Skeleton className="mt-2 h-3 w-28" />
|
|
72
|
+
</div>
|
|
73
|
+
))}
|
|
74
|
+
</div>
|
|
75
|
+
) : error ? (
|
|
76
|
+
<div className="rounded-lg border border-red-800/50 bg-red-950/70 p-6 text-center backdrop-blur-md">
|
|
77
|
+
<p className="text-red-400">Error loading projects: {error.message}</p>
|
|
78
|
+
<p className="mt-2 text-sm text-red-500">
|
|
79
|
+
Make sure the Tauri backend is running.
|
|
80
|
+
</p>
|
|
81
|
+
</div>
|
|
82
|
+
) : projects.length === 0 ? (
|
|
83
|
+
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
84
|
+
<div className="rounded-lg border border-dashed border-zinc-700 bg-card/70 p-6 text-center text-zinc-400 backdrop-blur-md">
|
|
85
|
+
<p>No projects yet</p>
|
|
86
|
+
<p className="mt-1 text-sm text-zinc-500">Click the button below to add a project</p>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
) : (
|
|
90
|
+
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
91
|
+
{projects.map((project) => (
|
|
92
|
+
<ProjectCard
|
|
93
|
+
key={project.id}
|
|
94
|
+
id={project.id}
|
|
95
|
+
name={project.name}
|
|
96
|
+
path={project.path}
|
|
97
|
+
tags={project.tags}
|
|
98
|
+
beadCounts={project.beadCounts}
|
|
99
|
+
onTagsChange={(tags) => updateProjectTags(project.id, tags)}
|
|
100
|
+
/>
|
|
101
|
+
))}
|
|
102
|
+
</div>
|
|
103
|
+
)}
|
|
104
|
+
</div>
|
|
105
|
+
</main>
|
|
106
|
+
|
|
107
|
+
{/* FAB - Add Project, z-20 */}
|
|
108
|
+
<button
|
|
109
|
+
onClick={() => setIsAddDialogOpen(true)}
|
|
110
|
+
className="fixed bottom-6 right-6 z-20 flex h-14 w-14 items-center justify-center rounded-full bg-zinc-100 text-zinc-900 shadow-lg hover:bg-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-100 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent"
|
|
111
|
+
aria-label="Add Project"
|
|
112
|
+
>
|
|
113
|
+
<svg
|
|
114
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
115
|
+
width="24"
|
|
116
|
+
height="24"
|
|
117
|
+
viewBox="0 0 24 24"
|
|
118
|
+
fill="none"
|
|
119
|
+
stroke="currentColor"
|
|
120
|
+
strokeWidth="2"
|
|
121
|
+
strokeLinecap="round"
|
|
122
|
+
strokeLinejoin="round"
|
|
123
|
+
aria-hidden="true"
|
|
124
|
+
>
|
|
125
|
+
<path d="M5 12h14" />
|
|
126
|
+
<path d="M12 5v14" />
|
|
127
|
+
</svg>
|
|
128
|
+
</button>
|
|
129
|
+
|
|
130
|
+
{/* Add Project Dialog */}
|
|
131
|
+
<AddProjectDialog
|
|
132
|
+
open={isAddDialogOpen}
|
|
133
|
+
onOpenChange={setIsAddDialogOpen}
|
|
134
|
+
onAddProject={handleAddProject}
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/README.md
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Beads Kanban UI
|
|
2
|
+
|
|
3
|
+
**See all your tasks at a glance. Organize, and track progress across projects - no CLI required.**
|
|
4
|
+
|
|
5
|
+
A beautiful visual Kanban board for the [Beads CLI](https://github.com/steveyegge/beads) task tracker. Beads stores tasks as git-native files (`.beads/issues.jsonl`), and this UI gives you the dashboard and board you've been missing.
|
|
6
|
+
|
|
7
|
+
> **Works great with [Beads Orchestration](https://github.com/AvivK5498/Claude-Code-Beads-Orchestration)** — A multi-agent orchestration framework for Claude Code that uses beads for git-native task tracking.
|
|
8
|
+
|
|
9
|
+
## See It in Action
|
|
10
|
+
|
|
11
|
+
**Dashboard** — All your projects in one place with status at a glance:
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
**Kanban Board** — Organize tasks across Open → In Progress → In Review → Closed:
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
**Bead Details** — Dive into epics with full context and subtasks:
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
## What You Get
|
|
21
|
+
|
|
22
|
+
- **Multi-project dashboard** — Manage all your beads projects in one place with status donut charts
|
|
23
|
+
- **Kanban board** — Open → In Progress → In Review → Closed
|
|
24
|
+
- **Epic support** — Group related tasks, track progress with bars, view all subtasks
|
|
25
|
+
- **Real-time sync** — File watcher auto-updates when beads files change on disk
|
|
26
|
+
- **Git integration** — See branch status for each task at a glance
|
|
27
|
+
- **Search & filter** — Quick filters for status, priority, owner, and tags
|
|
28
|
+
- **Project tagging** — Organize with colored tags and filter by them
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
### Option 1: npm install (Recommended)
|
|
33
|
+
|
|
34
|
+
**Prerequisites:**
|
|
35
|
+
- Beads CLI: `brew install steveyegge/beads/bd`
|
|
36
|
+
|
|
37
|
+
**Install and run:**
|
|
38
|
+
```bash
|
|
39
|
+
npm install -g beads-ui
|
|
40
|
+
bead-kanban
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
That's it! The server starts automatically and opens your browser.
|
|
44
|
+
|
|
45
|
+
> On first run, the postinstall script downloads the platform binary (~15MB). This is one-time only.
|
|
46
|
+
|
|
47
|
+
### Option 2: Build from source
|
|
48
|
+
|
|
49
|
+
**Prerequisites:**
|
|
50
|
+
```bash
|
|
51
|
+
# Install beads CLI
|
|
52
|
+
brew install steveyegge/beads/bd
|
|
53
|
+
|
|
54
|
+
# You'll also need Node.js 18+ and Rust
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Install and run:**
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/AvivK5498/beads-kanban-ui
|
|
60
|
+
cd beads-kanban-ui
|
|
61
|
+
npm install
|
|
62
|
+
npm run dev:full
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Then navigate to **`http://localhost:3007`** and add your beads projects.
|
|
66
|
+
|
|
67
|
+
The app watches for file changes and syncs in real-time.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Detailed Setup
|
|
72
|
+
|
|
73
|
+
### Development Mode
|
|
74
|
+
|
|
75
|
+
Run both frontend and backend together:
|
|
76
|
+
```bash
|
|
77
|
+
npm run dev:full
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Or run separately:
|
|
81
|
+
```bash
|
|
82
|
+
# Terminal 1: Frontend (http://localhost:3007)
|
|
83
|
+
npm run dev
|
|
84
|
+
|
|
85
|
+
# Terminal 2: Backend (http://localhost:3008)
|
|
86
|
+
npm run server:dev
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The Rust backend builds automatically on first run. If you need to rebuild it:
|
|
90
|
+
```bash
|
|
91
|
+
cd server && cargo build --release && cd ..
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Production Build
|
|
95
|
+
|
|
96
|
+
For a single binary deployment:
|
|
97
|
+
```bash
|
|
98
|
+
npm run build
|
|
99
|
+
npm run server:build
|
|
100
|
+
./server/target/release/beads-server
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The production server embeds the frontend and serves everything from a single binary on port 3008.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## How It Works
|
|
108
|
+
|
|
109
|
+
### Dashboard
|
|
110
|
+
1. Click **+ Add Project** and select a directory with a `.beads/` folder
|
|
111
|
+
2. See all projects with status donuts showing task distribution
|
|
112
|
+
3. Click any project to view its Kanban board
|
|
113
|
+
|
|
114
|
+
### Kanban Board
|
|
115
|
+
1. Tasks are organized by status: Open, In Progress, In Review, Closed
|
|
116
|
+
2. Drag cards between columns to update status
|
|
117
|
+
3. Click any task to see full details, comments, and related subtasks (for epics)
|
|
118
|
+
|
|
119
|
+
### Features in Detail
|
|
120
|
+
|
|
121
|
+
**Search & Filter**
|
|
122
|
+
- Quick filters for status, priority, and assigned owner
|
|
123
|
+
- Project tags for organization
|
|
124
|
+
|
|
125
|
+
**Real-time Sync**
|
|
126
|
+
- The app watches `.beads/issues.jsonl` and updates automatically
|
|
127
|
+
- No refresh needed—changes appear instantly
|
|
128
|
+
|
|
129
|
+
**Git Integration**
|
|
130
|
+
- Each task shows its git branch status
|
|
131
|
+
- Useful for tracking which branch a task lives on
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Architecture
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
┌─────────────────────────────────────────────────────────┐
|
|
139
|
+
│ Beads Kanban UI │
|
|
140
|
+
├─────────────────────────────────────────────────────────┤
|
|
141
|
+
│ Frontend (Next.js 14) │ Backend (Rust/Axum) │
|
|
142
|
+
│ ───────────────────── │ ────────────────────│
|
|
143
|
+
│ • React 18 │ • SQLite (projects) │
|
|
144
|
+
│ • shadcn/ui components │ • beads CLI bridge │
|
|
145
|
+
│ • Tailwind CSS │ • File watcher │
|
|
146
|
+
│ • TypeScript │ • Git integration │
|
|
147
|
+
└─────────────────────────────────────────────────────────┘
|
|
148
|
+
│
|
|
149
|
+
▼
|
|
150
|
+
┌─────────────────────────┐
|
|
151
|
+
│ .beads/ directory │
|
|
152
|
+
│ (issues.jsonl, etc.) │
|
|
153
|
+
└─────────────────────────┘
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Tech Stack
|
|
157
|
+
- **Frontend**: Next.js 14, React 18, Tailwind CSS, shadcn/ui
|
|
158
|
+
- **Backend**: Rust with Axum framework
|
|
159
|
+
- **Database**: SQLite for project metadata
|
|
160
|
+
- **File Sync**: Real-time watcher for `.beads/` changes
|
|
161
|
+
|
|
162
|
+
### Project Structure
|
|
163
|
+
```
|
|
164
|
+
beads-kanban-ui/
|
|
165
|
+
├── src/
|
|
166
|
+
│ ├── app/ # Next.js pages and routes
|
|
167
|
+
│ │ ├── page.tsx # Projects dashboard
|
|
168
|
+
│ │ ├── project/ # Kanban board view
|
|
169
|
+
│ │ └── settings/ # Settings page
|
|
170
|
+
│ ├── components/ # React components
|
|
171
|
+
│ │ ├── ui/ # shadcn/ui components
|
|
172
|
+
│ │ ├── kanban-column.tsx
|
|
173
|
+
│ │ ├── bead-card.tsx
|
|
174
|
+
│ │ └── bead-detail.tsx
|
|
175
|
+
│ ├── hooks/ # Custom React hooks
|
|
176
|
+
│ ├── lib/ # Utilities and API client
|
|
177
|
+
│ └── types/ # TypeScript type definitions
|
|
178
|
+
├── server/
|
|
179
|
+
│ └── src/
|
|
180
|
+
│ ├── main.rs # Axum server entry point
|
|
181
|
+
│ ├── db.rs # SQLite database layer
|
|
182
|
+
│ └── routes/ # API route handlers
|
|
183
|
+
└── package.json
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## API Endpoints
|
|
189
|
+
|
|
190
|
+
| Endpoint | Method | Description |
|
|
191
|
+
|----------|--------|-------------|
|
|
192
|
+
| `/api/health` | GET | Server health check |
|
|
193
|
+
| `/api/projects` | GET/POST | List or create projects |
|
|
194
|
+
| `/api/projects/:id` | GET/PUT/DELETE | Manage individual projects |
|
|
195
|
+
| `/api/beads?path=` | GET | Read beads from a project path |
|
|
196
|
+
| `/api/beads/comment` | POST | Add comment to a bead |
|
|
197
|
+
| `/api/bd/command` | POST | Execute beads CLI commands |
|
|
198
|
+
| `/api/git/branch-status` | GET | Get git branch status for a bead |
|
|
199
|
+
| `/api/fs/list` | GET | List directory contents |
|
|
200
|
+
| `/api/fs/exists` | GET | Check if a path exists |
|
|
201
|
+
| `/api/watch/beads` | GET | Server-sent events for file changes |
|
|
202
|
+
|
|
203
|
+
### Environment Variables
|
|
204
|
+
|
|
205
|
+
| Variable | Default | Description |
|
|
206
|
+
|----------|---------|-------------|
|
|
207
|
+
| `PORT` | `3008` | Backend server port |
|
|
208
|
+
| `NEXT_PUBLIC_BACKEND_URL` | `http://localhost:3008` | Backend URL for frontend API calls |
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Development Commands
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# Run both frontend and backend
|
|
216
|
+
npm run dev:full
|
|
217
|
+
|
|
218
|
+
# Run frontend only
|
|
219
|
+
npm run dev
|
|
220
|
+
|
|
221
|
+
# Run backend only
|
|
222
|
+
npm run server:dev
|
|
223
|
+
|
|
224
|
+
# Build for production
|
|
225
|
+
npm run build
|
|
226
|
+
npm run server:build
|
|
227
|
+
|
|
228
|
+
# Linting
|
|
229
|
+
npm run lint
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Related Projects
|
|
235
|
+
|
|
236
|
+
- **[Beads CLI](https://github.com/steveyegge/beads)** — Git-native issue tracker (the core tool this UI wraps)
|
|
237
|
+
- **[Beads Orchestration](https://github.com/AvivK5498/Claude-Code-Beads-Orchestration)** — Multi-agent orchestration framework for Claude Code using beads
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
MIT
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/components.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
+
"style": "new-york",
|
|
4
|
+
"rsc": true,
|
|
5
|
+
"tsx": true,
|
|
6
|
+
"tailwind": {
|
|
7
|
+
"config": "tailwind.config.ts",
|
|
8
|
+
"css": "src/app/globals.css",
|
|
9
|
+
"baseColor": "neutral",
|
|
10
|
+
"cssVariables": true,
|
|
11
|
+
"prefix": ""
|
|
12
|
+
},
|
|
13
|
+
"iconLibrary": "lucide",
|
|
14
|
+
"aliases": {
|
|
15
|
+
"components": "@/components",
|
|
16
|
+
"utils": "@/lib/utils",
|
|
17
|
+
"ui": "@/components/ui",
|
|
18
|
+
"lib": "@/lib",
|
|
19
|
+
"hooks": "@/hooks"
|
|
20
|
+
},
|
|
21
|
+
"registries": {
|
|
22
|
+
"@motion-primitives": "https://motion-primitives.com/c/{name}.json",
|
|
23
|
+
"@reui": "https://reui.io/r/{name}.json",
|
|
24
|
+
"@roiui": "https://roiui.com/r/{name}.json",
|
|
25
|
+
"@react-bits": "https://reactbits.dev/r/{name}.json"
|
|
26
|
+
}
|
|
27
|
+
}
|