Skip to content

feat(desktop): add user-defined channel sections to sidebar#789

Open
wpfleger96 wants to merge 6 commits into
mainfrom
worktree-wpfleger+channel-sections
Open

feat(desktop): add user-defined channel sections to sidebar#789
wpfleger96 wants to merge 6 commits into
mainfrom
worktree-wpfleger+channel-sections

Conversation

@wpfleger96
Copy link
Copy Markdown
Collaborator

@wpfleger96 wpfleger96 commented May 29, 2026

I added Slack-style sidebar sections to let users organize stream channels into custom named groups — the flat channel list gets unwieldy as the channel count grows.

Users create sections via right-click on any stream channel ("Move to section → New section…") and manage them via right-click on the section header (rename, move up/down, delete). Each section collapses independently. Channels not assigned to a section remain in the default "Channels" group below all custom sections.

  • New channelSectionsStorage.ts — pure localStorage read/write keyed by sprout-channel-sections.v1:{pubkey} with type-guard validation and a safe default; sections and channel assignments stored separately for O(1) lookups
  • New useChannelSections.ts — hook owning all CRUD mutations (create, rename, delete, reorder, assign/unassign), with cross-tab sync via StorageEvent
  • New ChannelSectionDialogs.tsxCreateSectionDialog, RenameSectionDialog, DeleteSectionAlertDialog using existing Dialog/AlertDialog/Input primitives
  • New CustomChannelSection.tsx — extracted ChannelGroupSection, SectionHeaderActions, CustomChannelSection, and supporting submenu components; AppSidebar.tsx updated to drive section state and render custom sections above the default group

Stacked: cross-device sync added in #792

@wpfleger96 wpfleger96 force-pushed the worktree-wpfleger+channel-sections branch from c99021f to bfbdbad Compare May 29, 2026 16:19
@wesbillman
Copy link
Copy Markdown
Collaborator

@wpfleger96 will this work across devices as well? Like will the mobile app have access to these same groups to display?

@wpfleger96
Copy link
Copy Markdown
Collaborator Author

@wesbillman no, as-is the PR will save channel sections to localStorage on each device

I'm gonna add Nostr event syncing so that sections will be shared between devices in a stacked PR so this one doesn't get too chonky

@wpfleger96
Copy link
Copy Markdown
Collaborator Author

Channel section creation:

  1. image
  2. image
  3. image

@wpfleger96
Copy link
Copy Markdown
Collaborator Author

multiple sections:
image

section context menu:
image

All stream channels appear in a single flat list which becomes hard to
navigate as channel count grows. Channel sections let users create custom
named groups (e.g., "Starred", "Work") to organize channels in the
sidebar, similar to Slack's sidebar sections.

Sections are purely cosmetic and client-side -- stored in localStorage
keyed by pubkey, with no backend changes. Users manage sections via
right-click context menus: create, rename, delete, reorder (move
up/down), and assign/unassign channels. Each section is independently
collapsible. Channels not assigned to a section remain in the default
"Channels" group.
Export storageKey from channelSectionsStorage to eliminate duplicate
key definitions that could diverge during refactors. Fix createSection
to return null on write failure instead of a phantom section, preventing
stale channel assignments. Clean up collapsedSections state when a
section is deleted. Freeze DEFAULT_STORE to guard against accidental
mutation.
Extract shared parseChannelSectionPayload validator and
stripOrphanedAssignments helper to channelSectionsStorage.ts.
Deduplicate Create/Rename dialogs into shared SectionNameDialog base.
Add per-section mark-all-read button to CustomChannelSection.
markChannelRead bailed when lastMessageAt was null because it lacked the
latestByChannelRef fallback that markChannelUnread already had. This made
the per-section "mark all as read" button and the individual channel
"mark as read" context menu action silently do nothing. Also clear
forcedContexts immediately in markContextRead so the forced-unread flag
from "mark unread" is removed when the user re-opens the channel.
…ssignment

Channels can be dragged between sections or back to the ungrouped list,
and sections can be dragged to reorder. Uses @dnd-kit pointer events
(no conflict with existing file drop prevention). DnD primitives
extracted to SidebarDnd.tsx; existing context-menu and move up/down
keyboard alternatives remain as accessibility fallbacks.
closestCenter collision detection required dragging to the vertical
midpoint of a tall channel list before the drop target activated. Switch
to pointerWithin so the drop fires as soon as the pointer enters the
droppable rect, and move the droppable wrappers up to cover the entire
section (header + content) instead of just the channel list.
@wpfleger96 wpfleger96 force-pushed the worktree-wpfleger+channel-sections branch from 881b951 to f081fbf Compare May 29, 2026 22:31
@wpfleger96
Copy link
Copy Markdown
Collaborator Author

Click-and-drag channels in/out of sections:

sprout_click_and_drag_channel_section

@wpfleger96
Copy link
Copy Markdown
Collaborator Author

deleting a section returns its channels back to default Channels

image

@wpfleger96 wpfleger96 marked this pull request as ready for review May 29, 2026 22:47
@wpfleger96 wpfleger96 requested a review from a team as a code owner May 29, 2026 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants