@@ -463,44 +463,17 @@ export default function RepoSelector(props: RepoSelectorProps) {
463463
464464 { /* Per-org repo lists — Index (not For) avoids tearing down every org's
465465 DOM subtree when a single org's state updates via setOrgStates(prev.map(...)) */ }
466+ < div class = { isAccordion ( ) ? "overflow-hidden rounded-lg border border-base-300 divide-y divide-base-300" : "contents" } >
466467 < Index each = { sortedOrgStates ( ) } >
467468 { ( state ) => {
468469 const visible = createMemo ( ( ) => filteredReposForOrg ( state ( ) ) ) ;
469470 const selectedCount = createMemo ( ( ) =>
470471 visible ( ) . filter ( ( r ) => isSelected ( r . fullName ) ) . length
471472 ) ;
473+ const orgId = createMemo ( ( ) => state ( ) . org . replace ( / [ ^ a - z A - Z 0 - 9 - ] / g, "-" ) ) ;
472474
473475 const orgContent = ( ) => (
474476 < >
475- { /* Per-org bulk selection bar (accordion mode only — in non-accordion, these are in the header) */ }
476- < Show when = { isAccordion ( ) && ! state ( ) . loading && ! state ( ) . error } >
477- < div class = "flex justify-end gap-2 border-b border-base-300 px-4 py-1" >
478- < button
479- type = "button"
480- onClick = { ( ) => selectAllInOrg ( state ( ) ) }
481- disabled = {
482- visible ( ) . length === 0 ||
483- visible ( ) . every ( ( r ) => isSelected ( r . fullName ) )
484- }
485- class = "btn btn-ghost btn-xs"
486- >
487- Select All
488- </ button >
489- < span class = "text-base-content/30" > ·</ span >
490- < button
491- type = "button"
492- onClick = { ( ) => deselectAllInOrg ( state ( ) ) }
493- disabled = {
494- visible ( ) . length === 0 ||
495- visible ( ) . every ( ( r ) => ! isSelected ( r . fullName ) )
496- }
497- class = "btn btn-ghost btn-xs"
498- >
499- Deselect All
500- </ button >
501- </ div >
502- </ Show >
503-
504477 { /* Loading state for this org */ }
505478 < Show when = { state ( ) . loading } >
506479 < div class = "flex justify-center py-6" >
@@ -602,7 +575,7 @@ export default function RepoSelector(props: RepoSelectorProps) {
602575 ) ;
603576
604577 return (
605- < div class = " overflow-hidden rounded-lg border border-base-300">
578+ < div class = { isAccordion ( ) ? "" : " overflow-hidden rounded-lg border border-base-300"} >
606579 { /* Org header — accordion button when >= 6 orgs, plain header otherwise */ }
607580 < Show
608581 when = { isAccordion ( ) }
@@ -641,38 +614,74 @@ export default function RepoSelector(props: RepoSelectorProps) {
641614 </ div >
642615 }
643616 >
644- < button
645- type = "button"
646- id = { `accordion-header-${ state ( ) . org } ` }
647- class = "flex w-full items-center gap-2 border-b border-base-300 bg-base-200 px-4 py-2 text-left"
648- aria-expanded = { expandedOrg ( ) === state ( ) . org }
649- aria-controls = { `accordion-panel-${ state ( ) . org } ` }
650- onClick = { ( ) => setUserExpandedOrg ( state ( ) . org ) }
651- >
652- < ChevronIcon size = "md" rotated = { expandedOrg ( ) !== state ( ) . org } />
653- < span class = "text-sm font-semibold text-base-content flex-1" >
654- { state ( ) . org }
655- </ span >
656- < span class = "badge badge-sm badge-ghost" > { visible ( ) . length } { visible ( ) . length === 1 ? "repo" : "repos" } </ span >
657- < Show when = { selectedCount ( ) > 0 } >
658- < span class = "badge badge-sm badge-ghost" > { selectedCount ( ) } selected</ span >
617+ < div class = "flex items-center border-b border-base-300 bg-base-200" >
618+ < button
619+ type = "button"
620+ id = { `accordion-header-${ orgId ( ) } ` }
621+ class = "flex flex-1 items-center gap-2 px-4 py-2 text-left"
622+ aria-expanded = { expandedOrg ( ) === state ( ) . org }
623+ aria-controls = { `accordion-panel-${ orgId ( ) } ` }
624+ // Always-one-open: clicking the already-expanded header is intentionally a no-op
625+ onClick = { ( ) => setUserExpandedOrg ( state ( ) . org ) }
626+ >
627+ < ChevronIcon size = "md" rotated = { expandedOrg ( ) !== state ( ) . org } />
628+ < span class = "text-sm font-semibold text-base-content flex-1" >
629+ { state ( ) . org }
630+ </ span >
631+ < Show
632+ when = { ! state ( ) . loading }
633+ fallback = { < span class = "loading loading-spinner loading-xs" /> }
634+ >
635+ < span class = "badge badge-sm badge-ghost" > { visible ( ) . length } { visible ( ) . length === 1 ? "repo" : "repos" } </ span >
636+ < Show when = { selectedCount ( ) > 0 } >
637+ < span class = "badge badge-sm badge-ghost" > { selectedCount ( ) } selected</ span >
638+ </ Show >
639+ </ Show >
640+ </ button >
641+ { /* Per-org bulk actions — inline in the header bar when expanded */ }
642+ < Show when = { expandedOrg ( ) === state ( ) . org && ! state ( ) . loading && ! state ( ) . error } >
643+ < div class = "flex items-center gap-2 pr-3" >
644+ < button
645+ type = "button"
646+ onClick = { ( ) => selectAllInOrg ( state ( ) ) }
647+ disabled = {
648+ visible ( ) . length === 0 ||
649+ visible ( ) . every ( ( r ) => isSelected ( r . fullName ) )
650+ }
651+ class = "btn btn-ghost btn-xs"
652+ >
653+ Select All
654+ </ button >
655+ < span class = "text-base-content/30" > ·</ span >
656+ < button
657+ type = "button"
658+ onClick = { ( ) => deselectAllInOrg ( state ( ) ) }
659+ disabled = {
660+ visible ( ) . length === 0 ||
661+ visible ( ) . every ( ( r ) => ! isSelected ( r . fullName ) )
662+ }
663+ class = "btn btn-ghost btn-xs"
664+ >
665+ Deselect All
666+ </ button >
667+ </ div >
659668 </ Show >
660- </ button >
669+ </ div >
661670 </ Show >
662671
663672 { /* Content: wrapped in grid animation for accordion, direct otherwise */ }
664- < Show when = { ! isAccordion ( ) } >
665- { orgContent ( ) }
666- </ Show >
667- < Show when = { isAccordion ( ) } >
673+ < Show
674+ when = { isAccordion ( ) }
675+ fallback = { orgContent ( ) }
676+ >
668677 < div
669678 class = "accordion-panel grid transition-[grid-template-rows] duration-200"
670679 style = { { "grid-template-rows" : expandedOrg ( ) === state ( ) . org ? "1fr" : "0fr" } }
671680 >
672681 < div
673- id = { `accordion-panel-${ state ( ) . org } ` }
682+ id = { `accordion-panel-${ orgId ( ) } ` }
674683 role = "region"
675- aria-labelledby = { `accordion-header-${ state ( ) . org } ` }
684+ aria-labelledby = { `accordion-header-${ orgId ( ) } ` }
676685 class = "overflow-hidden"
677686 inert = { expandedOrg ( ) !== state ( ) . org }
678687 >
@@ -684,6 +693,7 @@ export default function RepoSelector(props: RepoSelectorProps) {
684693 ) ;
685694 } }
686695 </ Index >
696+ </ div >
687697
688698 { /* Upstream Repositories section */ }
689699 < Show when = { props . showUpstreamDiscovery } >
0 commit comments