11import type React from "react" ;
2+ import { useState } from "react" ;
23
34import type { Task } from "@/data/task" ;
45import { groupBy } from "@/data/transformations/grouping" ;
6+ import { ObsidianIcon } from "@/ui/components/obsidian-icon" ;
57import { QueryContext } from "@/ui/context" ;
68import { ListDisplay } from "@/ui/query/displays/ListDisplay" ;
79
@@ -12,15 +14,50 @@ type Props = {
1214export const GroupedDisplay : React . FC < Props > = ( { tasks } ) => {
1315 const query = QueryContext . use ( ) ;
1416 const groups = groupBy ( tasks , query . groupBy ) ;
17+ const [ collapsedGroups , setCollapsedGroups ] = useState < Record < string , boolean > > ( { } ) ;
18+
19+ const toggleGroup = ( groupHeader : string ) => {
20+ setCollapsedGroups ( ( prev ) => {
21+ const newState = { ...prev } ;
22+ if ( newState [ groupHeader ] ) {
23+ delete newState [ groupHeader ] ;
24+ } else {
25+ newState [ groupHeader ] = true ;
26+ }
27+ return newState ;
28+ } ) ;
29+ } ;
1530
1631 return (
1732 < >
18- { groups . map ( ( group ) => (
19- < div className = "todoist-group" key = { group . header } >
20- < div className = "todoist-group-title" > { group . header } </ div >
21- < ListDisplay tasks = { group . tasks } />
22- </ div >
23- ) ) }
33+ { groups . map ( ( group ) => {
34+ const isCollapsed = group . header in collapsedGroups ;
35+ return (
36+ < div className = "todoist-group" key = { group . header } >
37+ { /* biome-ignore lint/a11y/useSemanticElements: Keeping as div to preserve CSS styling */ }
38+ < div
39+ className = { `todoist-group-title ${ isCollapsed ? "collapsed" : "" } ` }
40+ onClick = { ( ) => toggleGroup ( group . header ) }
41+ onKeyDown = { ( e ) => {
42+ if ( e . key === "Enter" || e . key === " " ) {
43+ e . preventDefault ( ) ;
44+ toggleGroup ( group . header ) ;
45+ }
46+ } }
47+ role = "button"
48+ tabIndex = { 0 }
49+ >
50+ < span > { group . header } </ span >
51+ < ObsidianIcon
52+ size = "s"
53+ id = { isCollapsed ? "chevron-right" : "chevron-down" }
54+ className = "todoist-group-collapse-icon"
55+ />
56+ </ div >
57+ { ! isCollapsed && < ListDisplay tasks = { group . tasks } /> }
58+ </ div >
59+ ) ;
60+ } ) }
2461 </ >
2562 ) ;
2663} ;
0 commit comments