beads-kanban-ui 0.1.0 → 0.1.1

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.
Files changed (154) hide show
  1. package/README.md +16 -222
  2. package/package.json +18 -55
  3. package/.designs/beads-kanban-ui-bj0.md +0 -73
  4. package/.designs/beads-kanban-ui-qxq.md +0 -144
  5. package/.designs/epic-support.md +0 -282
  6. package/.env.local.example +0 -2
  7. package/.eslintrc.json +0 -3
  8. package/.gitattributes +0 -3
  9. package/.github/workflows/release.yml +0 -123
  10. package/.history/README_20260121193710.md +0 -227
  11. package/.history/README_20260121193918.md +0 -227
  12. package/.history/README_20260121193921.md +0 -227
  13. package/.history/README_20260121193933.md +0 -227
  14. package/.history/README_20260121193934.md +0 -227
  15. package/.history/README_20260121193944.md +0 -227
  16. package/.history/README_20260121193953.md +0 -227
  17. package/.history/src/app/page_20260121133429.tsx +0 -134
  18. package/.history/src/app/page_20260121133928.tsx +0 -134
  19. package/.history/src/app/page_20260121144850.tsx +0 -138
  20. package/.history/src/app/page_20260121144854.tsx +0 -138
  21. package/.history/src/app/page_20260121144858.tsx +0 -138
  22. package/.history/src/app/page_20260121144902.tsx +0 -138
  23. package/.history/src/app/page_20260121144906.tsx +0 -138
  24. package/.history/src/app/page_20260121144911.tsx +0 -138
  25. package/.history/src/app/page_20260121144928.tsx +0 -138
  26. package/.playwright-mcp/.playwright-mcp/morphing-dialog-wheel-scroll-fix.png +0 -0
  27. package/.playwright-mcp/beams-test.png +0 -0
  28. package/.playwright-mcp/card-verification.png +0 -0
  29. package/.playwright-mcp/design-doc-dialog-fix-verification.png +0 -0
  30. package/.playwright-mcp/dialog-width-test.png +0 -0
  31. package/.playwright-mcp/homepage.png +0 -0
  32. package/.playwright-mcp/morphing-dialog-expanded.png +0 -0
  33. package/.playwright-mcp/morphing-dialog-fixes-final.png +0 -0
  34. package/.playwright-mcp/morphing-dialog-open.png +0 -0
  35. package/.playwright-mcp/page-2026-01-21T14-08-31-529Z.png +0 -0
  36. package/.playwright-mcp/page-2026-01-21T14-09-23-431Z.png +0 -0
  37. package/.playwright-mcp/page-2026-01-21T14-10-28-773Z.png +0 -0
  38. package/.playwright-mcp/page-2026-01-21T14-10-47-432Z.png +0 -0
  39. package/.playwright-mcp/page-2026-01-21T14-11-12-350Z.png +0 -0
  40. package/.playwright-mcp/screenshot-after-click.png +0 -0
  41. package/.playwright-mcp/screenshot-after-dialog-click.png +0 -0
  42. package/.playwright-mcp/sheet-restored-after-dialog-close.png +0 -0
  43. package/.playwright-mcp/test-1-sheet-open-with-overlay.png +0 -0
  44. package/.playwright-mcp/test-2-morphing-dialog-with-overlay.png +0 -0
  45. package/.playwright-mcp/test-3-sheet-open-dark-overlay.png +0 -0
  46. package/.playwright-mcp/test-4-morphing-dialog-with-dark-overlay.png +0 -0
  47. package/.playwright-mcp/test-5-morphing-dialog-scrolled.png +0 -0
  48. package/.playwright-mcp/test-6-sheet-restored-after-dialog-close.png +0 -0
  49. package/.playwright-mcp/wheel-scroll-fixed.png +0 -0
  50. package/Screenshots/bead-detail.png +0 -0
  51. package/Screenshots/dashboard.png +0 -0
  52. package/Screenshots/kanban-board.png +0 -0
  53. package/components.json +0 -27
  54. package/logo/logo.svg +0 -1
  55. package/next.config.js +0 -9
  56. package/npm/README.md +0 -37
  57. package/npm/package.json +0 -20
  58. package/postcss.config.js +0 -6
  59. package/public/logo.svg +0 -1
  60. package/restart.sh +0 -5
  61. package/server/Cargo.lock +0 -1685
  62. package/server/Cargo.toml +0 -24
  63. package/server/src/db.rs +0 -570
  64. package/server/src/main.rs +0 -141
  65. package/server/src/routes/beads.rs +0 -413
  66. package/server/src/routes/cli.rs +0 -150
  67. package/server/src/routes/fs.rs +0 -360
  68. package/server/src/routes/git.rs +0 -169
  69. package/server/src/routes/mod.rs +0 -107
  70. package/server/src/routes/projects.rs +0 -177
  71. package/server/src/routes/watch.rs +0 -211
  72. package/src/app/globals.css +0 -101
  73. package/src/app/layout.tsx +0 -36
  74. package/src/app/page.tsx +0 -348
  75. package/src/app/project/kanban-board.tsx +0 -356
  76. package/src/app/project/page.tsx +0 -18
  77. package/src/app/settings/page.tsx +0 -224
  78. package/src/components/Beams.css +0 -5
  79. package/src/components/Beams.jsx +0 -307
  80. package/src/components/Galaxy.css +0 -5
  81. package/src/components/Galaxy.jsx +0 -333
  82. package/src/components/activity-timeline.tsx +0 -172
  83. package/src/components/add-project-dialog.tsx +0 -219
  84. package/src/components/bead-card.tsx +0 -196
  85. package/src/components/bead-detail.tsx +0 -306
  86. package/src/components/color-picker.tsx +0 -101
  87. package/src/components/comment-input.tsx +0 -155
  88. package/src/components/comment-list.tsx +0 -147
  89. package/src/components/dependency-badge.tsx +0 -106
  90. package/src/components/design-doc-dialog.tsx +0 -58
  91. package/src/components/design-doc-preview.tsx +0 -97
  92. package/src/components/design-doc-viewer.tsx +0 -199
  93. package/src/components/editable-project-name.tsx +0 -178
  94. package/src/components/epic-card.tsx +0 -263
  95. package/src/components/folder-browser.tsx +0 -273
  96. package/src/components/footer.tsx +0 -27
  97. package/src/components/kanban/default.tsx +0 -184
  98. package/src/components/kanban-column.tsx +0 -167
  99. package/src/components/project-card.tsx +0 -191
  100. package/src/components/quick-filter-bar.tsx +0 -279
  101. package/src/components/scan-directory-dialog.tsx +0 -368
  102. package/src/components/status-donut.tsx +0 -197
  103. package/src/components/subtask-list.tsx +0 -128
  104. package/src/components/tag-picker.tsx +0 -252
  105. package/src/components/ui/.gitkeep +0 -0
  106. package/src/components/ui/alert-dialog.tsx +0 -141
  107. package/src/components/ui/avatar.tsx +0 -67
  108. package/src/components/ui/badge.tsx +0 -230
  109. package/src/components/ui/button.tsx +0 -433
  110. package/src/components/ui/card/index.tsx +0 -24
  111. package/src/components/ui/card/roiui-card.module.css +0 -197
  112. package/src/components/ui/card/roiui-card.tsx +0 -154
  113. package/src/components/ui/card/shadcn-card.tsx +0 -76
  114. package/src/components/ui/chart.tsx +0 -369
  115. package/src/components/ui/dialog.tsx +0 -122
  116. package/src/components/ui/dropdown-menu.tsx +0 -201
  117. package/src/components/ui/input.tsx +0 -22
  118. package/src/components/ui/kanban.tsx +0 -522
  119. package/src/components/ui/morphing-dialog.tsx +0 -457
  120. package/src/components/ui/popover.tsx +0 -33
  121. package/src/components/ui/progress.tsx +0 -28
  122. package/src/components/ui/scroll-area.tsx +0 -48
  123. package/src/components/ui/select.tsx +0 -159
  124. package/src/components/ui/separator.tsx +0 -31
  125. package/src/components/ui/sheet.tsx +0 -142
  126. package/src/components/ui/skeleton.tsx +0 -15
  127. package/src/components/ui/toast.tsx +0 -129
  128. package/src/components/ui/toaster.tsx +0 -35
  129. package/src/components/ui/tooltip.tsx +0 -30
  130. package/src/hooks/.gitkeep +0 -0
  131. package/src/hooks/use-bead-filters.ts +0 -261
  132. package/src/hooks/use-beads.ts +0 -162
  133. package/src/hooks/use-branch-statuses.ts +0 -161
  134. package/src/hooks/use-epics.ts +0 -173
  135. package/src/hooks/use-file-watcher.ts +0 -111
  136. package/src/hooks/use-keyboard-navigation.ts +0 -282
  137. package/src/hooks/use-project.ts +0 -61
  138. package/src/hooks/use-projects.ts +0 -93
  139. package/src/hooks/use-toast.ts +0 -194
  140. package/src/hooks/useClickOutside.tsx +0 -26
  141. package/src/lib/.gitkeep +0 -0
  142. package/src/lib/api.ts +0 -186
  143. package/src/lib/beads-parser.ts +0 -252
  144. package/src/lib/cli.ts +0 -193
  145. package/src/lib/db.ts +0 -145
  146. package/src/lib/design-doc.ts +0 -74
  147. package/src/lib/epic-parser.ts +0 -242
  148. package/src/lib/git.ts +0 -102
  149. package/src/lib/utils.ts +0 -12
  150. package/src/types/index.ts +0 -107
  151. package/tailwind.config.ts +0 -85
  152. package/tsconfig.json +0 -26
  153. /package/{npm/bin → bin}/cli.js +0 -0
  154. /package/{npm/scripts → scripts}/postinstall.js +0 -0
package/src/app/page.tsx DELETED
@@ -1,348 +0,0 @@
1
- "use client";
2
-
3
- import { useMemo, useState } from "react";
4
- import Link from "next/link";
5
- import { Plus, ChevronDown, FolderPlus, FolderSearch, Github, Settings, Search, X } from "lucide-react";
6
- import { ProjectCard } from "@/components/project-card";
7
- import { AddProjectDialog } from "@/components/add-project-dialog";
8
- import { ScanDirectoryDialog } from "@/components/scan-directory-dialog";
9
- import { useProjects } from "@/hooks/use-projects";
10
- import { useToast } from "@/hooks/use-toast";
11
- import { Skeleton } from "@/components/ui/skeleton";
12
- import { Button, ButtonArrow } from "@/components/ui/button";
13
- import { Input } from "@/components/ui/input";
14
- import { Badge } from "@/components/ui/badge";
15
- import {
16
- DropdownMenu,
17
- DropdownMenuContent,
18
- DropdownMenuItem,
19
- DropdownMenuTrigger,
20
- } from "@/components/ui/dropdown-menu";
21
-
22
- export default function ProjectsPage() {
23
- const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
24
- const [isScanDialogOpen, setIsScanDialogOpen] = useState(false);
25
- const [searchQuery, setSearchQuery] = useState("");
26
- const [selectedTagIds, setSelectedTagIds] = useState<string[]>([]);
27
- const { projects, isLoading, error, addProject, updateProjectTags } = useProjects();
28
- const { toast } = useToast();
29
-
30
- // Get all unique tags across projects
31
- const allTags = useMemo(() => {
32
- const tagMap = new Map<string, { id: string; name: string; color: string }>();
33
- projects.forEach((project) => {
34
- project.tags.forEach((tag) => {
35
- if (!tagMap.has(tag.id)) {
36
- tagMap.set(tag.id, tag);
37
- }
38
- });
39
- });
40
- return Array.from(tagMap.values()).sort((a, b) => a.name.localeCompare(b.name));
41
- }, [projects]);
42
-
43
- // Filter projects by search query and selected tags (AND logic)
44
- const filteredProjects = useMemo(() => {
45
- return projects.filter((project) => {
46
- // Search filter - match name or path
47
- const searchLower = searchQuery.toLowerCase().trim();
48
- const matchesSearch = searchLower === "" ||
49
- project.name.toLowerCase().includes(searchLower) ||
50
- project.path.toLowerCase().includes(searchLower);
51
-
52
- // Tag filter - AND logic: project must have ALL selected tags
53
- const matchesTags = selectedTagIds.length === 0 ||
54
- selectedTagIds.every((tagId) =>
55
- project.tags.some((tag) => tag.id === tagId)
56
- );
57
-
58
- return matchesSearch && matchesTags;
59
- });
60
- }, [projects, searchQuery, selectedTagIds]);
61
-
62
- const toggleTag = (tagId: string) => {
63
- setSelectedTagIds((prev) =>
64
- prev.includes(tagId)
65
- ? prev.filter((id) => id !== tagId)
66
- : [...prev, tagId]
67
- );
68
- };
69
-
70
- const clearFilters = () => {
71
- setSearchQuery("");
72
- setSelectedTagIds([]);
73
- };
74
-
75
- const hasActiveFilters = searchQuery.trim() !== "" || selectedTagIds.length > 0;
76
-
77
- const handleAddProject = async (input: { name: string; path: string }) => {
78
- // Check for duplicate
79
- const isDuplicate = projects.some(p => p.path === input.path);
80
- if (isDuplicate) {
81
- toast({
82
- title: "Project already exists",
83
- description: "This project is already in your dashboard.",
84
- variant: "destructive",
85
- });
86
- throw new Error("Project already exists"); // Let the dialog know it failed
87
- }
88
- await addProject(input);
89
- };
90
-
91
- const handleAddMultipleProjects = async (projectsToAdd: { name: string; path: string }[]) => {
92
- // Filter out projects that already exist
93
- const existingPaths = new Set(projects.map(p => p.path));
94
- const newProjects = projectsToAdd.filter(p => !existingPaths.has(p.path));
95
- const duplicateCount = projectsToAdd.length - newProjects.length;
96
-
97
- // If all are duplicates, show error
98
- if (newProjects.length === 0) {
99
- toast({
100
- title: "All projects already exist",
101
- description: `${duplicateCount === 1 ? "This project is" : "All " + duplicateCount + " projects are"} already in your dashboard.`,
102
- variant: "destructive",
103
- });
104
- throw new Error("All projects already exist");
105
- }
106
-
107
- // Add new projects
108
- for (const project of newProjects) {
109
- await addProject(project);
110
- }
111
-
112
- // If some were duplicates, notify the user
113
- if (duplicateCount > 0) {
114
- toast({
115
- title: "Some projects skipped",
116
- description: `${duplicateCount} duplicate project${duplicateCount > 1 ? "s were" : " was"} skipped.`,
117
- });
118
- }
119
- };
120
-
121
- return (
122
- <div className="dark flex min-h-dvh flex-col bg-[#0a0a0a]">
123
- {/* Navigation Bar */}
124
- <nav className="sticky top-0 z-30 border-b border-zinc-800 bg-[#0a0a0a]/80 backdrop-blur-sm">
125
- <div className="mx-auto flex max-w-[1200px] items-center justify-center gap-4 px-6 py-2">
126
- <a
127
- href="https://github.com/AvivK5498/Beads-Kanban-UI"
128
- target="_blank"
129
- rel="noopener noreferrer"
130
- aria-label="GitHub repository"
131
- className="rounded-md p-2 text-zinc-400 transition-colors duration-150 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-[#0a0a0a]"
132
- >
133
- <Github className="h-5 w-5" aria-hidden="true" />
134
- </a>
135
- <Link
136
- href="/settings"
137
- aria-label="Settings"
138
- className="rounded-md p-2 text-zinc-400 transition-colors duration-150 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-[#0a0a0a]"
139
- >
140
- <Settings className="h-5 w-5" aria-hidden="true" />
141
- </Link>
142
- </div>
143
- </nav>
144
-
145
- {/* Hero Section - pushed down with padding */}
146
- <main className="flex flex-col items-center px-6 pt-32">
147
- {/* Centered Heading with Space Grotesk */}
148
- <h1 className="mb-12 text-center text-balance font-heading text-4xl font-bold tracking-tight text-white sm:text-5xl">
149
- Manage Your Beads Projects
150
- </h1>
151
-
152
- <div className="w-full max-w-[1200px]">
153
- {/* Add Project Dropdown */}
154
- <div className="mb-6 flex justify-end">
155
- <DropdownMenu>
156
- <DropdownMenuTrigger asChild>
157
- <Button variant="mono" size="md">
158
- <Plus aria-hidden="true" />
159
- Add Project
160
- <ButtonArrow icon={ChevronDown} />
161
- </Button>
162
- </DropdownMenuTrigger>
163
- <DropdownMenuContent align="end">
164
- <DropdownMenuItem onSelect={() => setIsAddDialogOpen(true)}>
165
- <FolderPlus aria-hidden="true" />
166
- Add Project
167
- </DropdownMenuItem>
168
- <DropdownMenuItem onSelect={() => setIsScanDialogOpen(true)}>
169
- <FolderSearch aria-hidden="true" />
170
- Scan Directory
171
- </DropdownMenuItem>
172
- </DropdownMenuContent>
173
- </DropdownMenu>
174
- </div>
175
-
176
- {/* Search and Filter Bar */}
177
- {projects.length > 0 && (
178
- <div className="mb-6 space-y-3">
179
- {/* Search Input */}
180
- <div className="relative">
181
- <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-zinc-500" aria-hidden="true" />
182
- <Input
183
- type="search"
184
- placeholder="Search projects..."
185
- value={searchQuery}
186
- onChange={(e) => setSearchQuery(e.target.value)}
187
- className="pl-10 bg-zinc-900/50 border-zinc-700"
188
- aria-label="Search projects"
189
- />
190
- </div>
191
-
192
- {/* Tag Filter Chips */}
193
- {allTags.length > 0 && (
194
- <div className="flex flex-wrap items-center gap-2">
195
- <span className="text-xs text-zinc-500">Filter by tag:</span>
196
- {allTags.map((tag) => {
197
- const isSelected = selectedTagIds.includes(tag.id);
198
- return (
199
- <button
200
- key={tag.id}
201
- type="button"
202
- onClick={() => toggleTag(tag.id)}
203
- className="transition-opacity"
204
- aria-pressed={isSelected}
205
- aria-label={`Filter by ${tag.name}`}
206
- >
207
- <Badge
208
- variant={isSelected ? "primary" : "outline"}
209
- size="sm"
210
- style={
211
- isSelected
212
- ? {
213
- backgroundColor: tag.color,
214
- color: "#fff",
215
- borderColor: tag.color,
216
- }
217
- : {
218
- backgroundColor: `${tag.color}10`,
219
- color: tag.color,
220
- borderColor: `${tag.color}50`,
221
- }
222
- }
223
- >
224
- {tag.name}
225
- </Badge>
226
- </button>
227
- );
228
- })}
229
- {hasActiveFilters && (
230
- <button
231
- type="button"
232
- onClick={clearFilters}
233
- className="ml-2 flex items-center gap-1 text-xs text-zinc-500 hover:text-zinc-300 transition-colors"
234
- aria-label="Clear all filters"
235
- >
236
- <X className="h-3 w-3" aria-hidden="true" />
237
- Clear
238
- </button>
239
- )}
240
- </div>
241
- )}
242
-
243
- {/* Results count when filtering */}
244
- {hasActiveFilters && (
245
- <p className="text-xs text-zinc-500">
246
- Showing {filteredProjects.length} of {projects.length} project{projects.length !== 1 ? "s" : ""}
247
- </p>
248
- )}
249
- </div>
250
- )}
251
-
252
- {isLoading ? (
253
- <div role="status" aria-label="Loading projects" className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
254
- {[1, 2, 3].map((i) => (
255
- <div key={i} className="rounded-xl border border-zinc-800 bg-zinc-900/70 p-4">
256
- <div className="mb-3 flex gap-1.5">
257
- <Skeleton className="h-5 w-16" />
258
- <Skeleton className="h-5 w-12" />
259
- </div>
260
- <Skeleton className="h-5 w-40" />
261
- <Skeleton className="mt-2 h-4 w-48" />
262
- <Skeleton className="mt-4 h-4 w-32" />
263
- <Skeleton className="mt-2 h-3 w-28" />
264
- </div>
265
- ))}
266
- </div>
267
- ) : error ? (
268
- <div role="alert" className="rounded-lg border border-red-800/50 bg-red-950/70 p-6 text-center">
269
- <p className="text-red-400">Error loading projects: {error.message}</p>
270
- <p className="mt-2 text-sm text-red-500">
271
- Make sure the Tauri backend is running.
272
- </p>
273
- </div>
274
- ) : filteredProjects.length === 0 ? (
275
- <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
276
- <div className="rounded-lg border border-dashed border-zinc-700 bg-zinc-900/70 p-6 text-center text-zinc-400">
277
- {hasActiveFilters ? (
278
- <>
279
- <p>No matching projects</p>
280
- <p className="mt-1 text-sm text-zinc-500">Try adjusting your search or filters</p>
281
- </>
282
- ) : (
283
- <>
284
- <p>No projects yet</p>
285
- <p className="mt-1 text-sm text-zinc-500">Click the Add Project button above to get started</p>
286
- </>
287
- )}
288
- </div>
289
- </div>
290
- ) : (
291
- <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
292
- {filteredProjects.map((project) => (
293
- <ProjectCard
294
- key={project.id}
295
- id={project.id}
296
- name={project.name}
297
- path={project.path}
298
- tags={project.tags}
299
- beadCounts={project.beadCounts}
300
- onTagsChange={(tags) => updateProjectTags(project.id, tags)}
301
- />
302
- ))}
303
- </div>
304
- )}
305
- </div>
306
- </main>
307
-
308
- {/* Footer */}
309
- <footer className="mt-auto border-t border-zinc-800 py-6">
310
- <div className="mx-auto flex max-w-[1200px] items-center justify-center gap-4 px-6">
311
- <a
312
- href="https://github.com/AvivK5498/beads-kanban-ui"
313
- target="_blank"
314
- rel="noopener noreferrer"
315
- className="flex items-center gap-2 text-sm text-zinc-500 transition-colors hover:text-zinc-300"
316
- >
317
- <Github className="h-4 w-4" aria-hidden="true" />
318
- <span>Beads Kanban UI</span>
319
- </a>
320
- <span className="text-zinc-600" aria-hidden="true">·</span>
321
- <a
322
- href="https://github.com/steveyegge/beads"
323
- target="_blank"
324
- rel="noopener noreferrer"
325
- className="flex items-center gap-2 text-sm text-zinc-500 transition-colors hover:text-zinc-300"
326
- >
327
- <Github className="h-4 w-4" aria-hidden="true" />
328
- <span>Beads CLI</span>
329
- </a>
330
- </div>
331
- </footer>
332
-
333
- {/* Add Project Dialog */}
334
- <AddProjectDialog
335
- open={isAddDialogOpen}
336
- onOpenChange={setIsAddDialogOpen}
337
- onAddProject={handleAddProject}
338
- />
339
-
340
- {/* Scan Directory Dialog */}
341
- <ScanDirectoryDialog
342
- open={isScanDialogOpen}
343
- onOpenChange={setIsScanDialogOpen}
344
- onAddProjects={handleAddMultipleProjects}
345
- />
346
- </div>
347
- );
348
- }