this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: sidebar init

+97 -38
+8 -36
mast-react-vite/src/App.tsx
··· 145 145 ); 146 146 } catch (error) { 147 147 console.log("Could not parse command"); 148 + console.log( getSelectionString() + " " + currentAction + " " + newText) 148 149 return {}; 149 150 } 150 151 }, [getSelectionString(), currentAction, newText]); ··· 380 381 } 381 382 }; 382 383 383 - //const parseTodos = (e) => { 384 - // // On enter execute the command 385 - // if (e.key === "Enter") { 386 - // // TODO We should pass selectionContext here 387 - // executeCommand(currentAction + " " + e.target.value); 388 - // } 389 - // // React to key presses for selection 390 - // else if (e.target.value.trim() !== "") { 391 - // try { 392 - // // TODO: 393 - // // This allows editing selectionContext from the newText field 394 - // // But we've moved selectionContext into it's own place 395 - // // So we shouldn't have to do this here 396 - // const parsed = commandParser.parse(currentAction + " " + e.target.value); 397 - // if (parsed.filters && parsed.filters.length > 0) { 398 - // const idFilters = parsed.filters.filter(f => f.type === "id"); 399 - // // Create new selection state 400 - // const newSelection = {}; 401 - // idFilters.forEach(filter => { 402 - // filter.ids.forEach(id => { 403 - // newSelection[id - 1] = true; 404 - // }) 405 - // }); 406 - 407 - // } 408 - // } catch (error) { 409 - // console.log("Unable to parse field onUpdate") 410 - // return; 411 - // } 412 - // } else { 413 - // } 414 - //} 415 - 416 384 return ( 417 385 <> 418 - <SidebarProvider defaultOpen={false} className="h-screen"> 386 + <SidebarProvider defaultOpen={false} className="h-screen dark"> 419 387 <div className="hidden md:flex flex-col w-full h-svh"> 420 - <AppSidebar /> 388 + <AppSidebar ctx={ctx} 389 + filterContext={filterContext} 390 + setFilterContext={setFilterContext} /> 421 391 <div className="bg-muted h-14 w-full absolute top-0 " /> 422 392 <section className="flex-1 container py-12 h-[calc(100vh-theme(spacing.4))] overflow-hidden relative"> 423 393 <SidebarTrigger className="absolute top-4 left-8 border border-foreground" /> ··· 456 426 457 427 {/* Mobile view layout - shown only on mobile */} 458 428 <div className="md:hidden flex left-0 w-full h-full flex flex-col items-center pb-2"> 459 - <AppSidebar /> 429 + <AppSidebar ctx={ctx} 430 + filterContext={filterContext} 431 + setFilterContext={setFilterContext} /> 460 432 <section className="flex-1 py-12 h-[calc(100vh-theme(spacing.4))] w-full overflow-hidden relative"> 461 433 <div className="flex-1 bg-muted border-b border-foreground h-14 absolute inset-x-0 top-0 " /> 462 434 <SidebarTrigger className="fixed top-4 border border-foreground left-8" />
+89 -2
mast-react-vite/src/components/ui/app-sidebar.tsx
··· 3 3 SidebarContent, 4 4 SidebarFooter, 5 5 SidebarGroup, 6 + SidebarGroupLabel, 6 7 SidebarHeader, 8 + SidebarMenu, 9 + SidebarMenuItem, 10 + SidebarMenuButton, 7 11 } from "@/components/ui/sidebar"; 12 + import { useQuery } from "@vlcn.io/react"; 8 13 9 - export function AppSidebar() { 14 + export function AppSidebar({ctx, filterContext, setFilterContext}) { 15 + const projects = useQuery( 16 + ctx, 17 + `SELECT DISTINCT project FROM active_todos WHERE project != '' ORDER BY project` 18 + ).data || []; 19 + 20 + const handleProjectClick = (project) => { 21 + // Toggle project selection - if already selected, remove it 22 + if (filterContext.filterProject === project) { 23 + // Create a new object without the filterProject property 24 + const { filterProject, ...restFilterContext } = filterContext; 25 + setFilterContext(restFilterContext); 26 + } else { 27 + // Set the new project 28 + setFilterContext({ 29 + ...filterContext, 30 + filterProject: project, 31 + filterTemp: false, 32 + }); 33 + } 34 + }; 35 + 36 + const tags = useQuery( 37 + ctx, 38 + `SELECT DISTINCT value as tag FROM active_todos, json_each(active_todos.tags) ORDER BY tag` 39 + ).data || []; 40 + 41 + const handleTagClick = (tag) => { 42 + const currentTags = filterContext.filterTags || []; 43 + const newTags = currentTags.includes(tag) 44 + ? currentTags.filter(t => t !== tag) 45 + : [...currentTags, tag]; 46 + 47 + setFilterContext({ 48 + ...filterContext, 49 + filterTags: newTags, 50 + filterTemp: false, 51 + }); 52 + }; 53 + 10 54 return ( 11 55 <Sidebar> 12 56 <SidebarHeader /> 13 57 <SidebarContent> 14 - <SidebarGroup /> 58 + <SidebarGroup> 59 + <SidebarGroupLabel>Projects</SidebarGroupLabel> 60 + <SidebarMenu> 61 + <div className="flex flex-wrap gap-1.5 p-2 max-h-40 overflow-y-auto"> 62 + {projects.map((item) => ( 63 + <SidebarMenuItem key={item.project}> 64 + <SidebarMenuButton 65 + isActive={filterContext.filterProject === item.project} 66 + onClick={() => handleProjectClick(item.project)} 67 + > 68 + {item.project} 69 + </SidebarMenuButton> 70 + </SidebarMenuItem> 71 + ))} 72 + {projects.length === 0 && ( 73 + <div className="px-2 py-1 text-sm text-muted-foreground"> 74 + No projects found 75 + </div> 76 + )} 77 + </div> 78 + </SidebarMenu> 79 + </SidebarGroup> 80 + <SidebarGroup> 81 + <SidebarGroupLabel>Tags</SidebarGroupLabel> 82 + <SidebarMenu> 83 + <div className="flex flex-wrap gap-1.5 p-2 max-h-40 overflow-y-auto"> 84 + {tags.map((item) => ( 85 + <SidebarMenuItem key={item.tag}> 86 + <SidebarMenuButton 87 + isActive={filterContext.filterTags && filterContext.filterTags.includes(item.tag)} 88 + onClick={() => handleTagClick(item.tag)} 89 + > 90 + {item.tag} 91 + </SidebarMenuButton> 92 + </SidebarMenuItem> 93 + ))} 94 + {tags.length === 0 && ( 95 + <div className="px-2 py-1 text-sm text-muted-foreground"> 96 + No tags found 97 + </div> 98 + )} 99 + </div> 100 + </SidebarMenu> 101 + </SidebarGroup> 15 102 <SidebarGroup /> 16 103 </SidebarContent> 17 104 <SidebarFooter />