@@ -3,7 +3,6 @@ import type TaskNotesPlugin from "../main";
33import type { TaskInfo } from "../types" ;
44import { createTaskNotesLogger } from "../utils/tasknotesLogger" ;
55import {
6- createProjectClickHandler ,
76 createRecurrenceClickHandler ,
87 createReminderClickHandler ,
98} from "./taskCardActions" ;
@@ -153,6 +152,51 @@ function createChevronClickHandler(
153152 } ;
154153}
155154
155+ /**
156+ * Toggles the inline subtask list for a project task card. Used by the folder
157+ * (project) badge so it works whether or not the expand chevron is rendered,
158+ * keeping the chevron visual in sync when it is present. Shares expansion state
159+ * with the chevron via expandedProjectsService, so the two never diverge.
160+ */
161+ function createProjectSubtasksToggleHandler (
162+ task : TaskInfo ,
163+ plugin : TaskNotesPlugin ,
164+ card : HTMLElement ,
165+ handlers : TaskCardSecondaryBadgeHandlers
166+ ) : ( ) => void {
167+ return ( ) => {
168+ void ( async ( ) => {
169+ const logger = getTaskCardBadgeLogger ( plugin ) ;
170+ try {
171+ if ( ! plugin . expandedProjectsService ) {
172+ new Notice ( "Service not available. Please try reloading the plugin." ) ;
173+ return ;
174+ }
175+
176+ const newExpanded = plugin . expandedProjectsService . toggle (
177+ task . path ,
178+ shouldExpandSubtasksByDefault ( plugin )
179+ ) ;
180+
181+ const chevron = card . querySelector < HTMLElement > ( ".task-card__chevron" ) ;
182+ if ( chevron ) {
183+ updateChevronElement ( chevron , plugin , newExpanded ) ;
184+ }
185+
186+ await handlers . toggleSubtasks ( card , task , newExpanded ) ;
187+ } catch ( error ) {
188+ logger . error ( "Error toggling project subtasks" , {
189+ category : "internal" ,
190+ operation : "toggle-project-subtasks" ,
191+ details : { taskPath : task . path } ,
192+ error,
193+ } ) ;
194+ new Notice ( "Failed to toggle subtasks" ) ;
195+ }
196+ } ) ( ) ;
197+ } ;
198+ }
199+
156200function createBlockingToggleClickHandler (
157201 task : TaskInfo ,
158202 card : HTMLElement ,
@@ -217,27 +261,31 @@ function renderProjectBadges(
217261 return ;
218262 }
219263
264+ const isExpanded = isTaskCardSubtasksExpanded ( task , plugin ) ;
265+
266+ // The folder badge toggles the inline subtask list. It is always rendered for
267+ // a project and works on its own, so subtasks remain reachable from the card
268+ // even when the expand chevron is disabled.
220269 createBadgeIndicator ( {
221270 container : badgesContainer ,
222271 className : "task-card__project-indicator" ,
223272 icon : "folder" ,
224273 tooltip : tTaskCard ( plugin , "projectTooltip" ) ,
225- onClick : createProjectClickHandler ( task , plugin ) ,
274+ onClick : createProjectSubtasksToggleHandler ( task , plugin , card , handlers ) ,
226275 } ) ;
227276
228- if ( ! plugin . settings ?. showExpandableSubtasks ) {
229- return ;
277+ if ( plugin . settings ?. showExpandableSubtasks ) {
278+ createBadgeIndicator ( {
279+ container : badgesContainer ,
280+ className : `task-card__chevron${ isExpanded ? " task-card__chevron--expanded" : "" } ` ,
281+ icon : "chevron-right" ,
282+ tooltip : getChevronTooltip ( plugin , isExpanded ) ,
283+ onClick : createChevronClickHandler ( task , plugin , card , handlers ) ,
284+ } ) ;
230285 }
231286
232- const isExpanded = isTaskCardSubtasksExpanded ( task , plugin ) ;
233- createBadgeIndicator ( {
234- container : badgesContainer ,
235- className : `task-card__chevron${ isExpanded ? " task-card__chevron--expanded" : "" } ` ,
236- icon : "chevron-right" ,
237- tooltip : getChevronTooltip ( plugin , isExpanded ) ,
238- onClick : createChevronClickHandler ( task , plugin , card , handlers ) ,
239- } ) ;
240-
287+ // Render the subtask list immediately when expanded, regardless of whether the
288+ // chevron is shown — otherwise a folder-driven expansion would not re-render.
241289 if ( isExpanded ) {
242290 handlers . toggleSubtasks ( card , task , true ) . catch ( ( error : unknown ) => {
243291 getTaskCardBadgeLogger ( plugin ) . error ( "Error showing initial subtasks" , {
@@ -346,14 +394,15 @@ function updateProjectBadges(options: UpdateTaskCardSecondaryBadgesOptions): voi
346394 className : "task-card__project-indicator" ,
347395 icon : "folder" ,
348396 tooltip : tTaskCard ( plugin , "projectTooltip" ) ,
349- onClick : createProjectClickHandler ( task , plugin ) ,
397+ onClick : createProjectSubtasksToggleHandler ( task , plugin , card , handlers ) ,
350398 } ) ;
351399
352400 const showChevron = isProject && plugin . settings ?. showExpandableSubtasks ;
353401 const existingChevron = card . querySelector < HTMLElement > ( ".task-card__chevron" ) ;
402+ const isExpanded = isProject && isTaskCardSubtasksExpanded ( task , plugin ) ;
354403
404+ // Keep the chevron in sync with the setting (create / update / remove).
355405 if ( showChevron && ! existingChevron ) {
356- const isExpanded = isTaskCardSubtasksExpanded ( task , plugin ) ;
357406 createBadgeIndicator ( {
358407 container :
359408 card . querySelector < HTMLElement > ( ".task-card__badges" ) ?? mainRow ?? card ,
@@ -362,35 +411,24 @@ function updateProjectBadges(options: UpdateTaskCardSecondaryBadgesOptions): voi
362411 tooltip : getChevronTooltip ( plugin , isExpanded ) ,
363412 onClick : createChevronClickHandler ( task , plugin , card , handlers ) ,
364413 } ) ;
365-
366- if ( isExpanded ) {
367- handlers . toggleSubtasks ( card , task , true ) . catch ( ( error : unknown ) => {
368- logger . error ( "Error showing initial subtasks in update" , {
369- category : "internal" ,
370- operation : "show-initial-subtasks-update" ,
371- details : { taskPath : task . path } ,
372- error,
373- } ) ;
374- } ) ;
375- }
376414 } else if ( showChevron && existingChevron ) {
377- const isExpanded = isTaskCardSubtasksExpanded ( task , plugin ) ;
378415 updateChevronElement ( existingChevron , plugin , isExpanded ) ;
379-
380- if ( isExpanded ) {
381- handlers . toggleSubtasks ( card , task , true ) . catch ( ( error : unknown ) => {
382- logger . error ( "Error refreshing default-expanded subtasks" , {
383- category : "internal" ,
384- operation : "refresh-default-expanded-subtasks" ,
385- details : { taskPath : task . path } ,
386- error,
387- } ) ;
388- } ) ;
389- } else {
390- removeRelationshipContainer ( card , ".task-card__subtasks" ) ;
391- }
392416 } else if ( ! showChevron && existingChevron ) {
393417 existingChevron . remove ( ) ;
418+ }
419+
420+ // Sync the inline subtask list independently of the chevron, so the
421+ // folder badge can drive expansion even when the chevron is disabled.
422+ if ( isExpanded ) {
423+ handlers . toggleSubtasks ( card , task , true ) . catch ( ( error : unknown ) => {
424+ logger . error ( "Error showing subtasks in update" , {
425+ category : "internal" ,
426+ operation : "show-subtasks-update" ,
427+ details : { taskPath : task . path } ,
428+ error,
429+ } ) ;
430+ } ) ;
431+ } else {
394432 removeRelationshipContainer ( card , ".task-card__subtasks" ) ;
395433 }
396434 } )
0 commit comments