Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion desktop/src/app/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,6 @@ export function AppShell() {
onCreateChannel={handleCreateChannel}
onCreateForum={handleCreateForum}
onHideDm={handleHideDm}
onMarkAllChannelsRead={markAllChannelsRead}
onMarkChannelRead={markChannelRead}
onMarkChannelUnread={markChannelUnread}
onBrowseChannels={handleOpenBrowseChannels}
Expand Down
37 changes: 31 additions & 6 deletions desktop/src/features/sidebar/ui/AppSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ type AppSidebarProps = {
channelId: string,
lastMessageAt: string | null | undefined,
) => void;
onMarkAllChannelsRead: () => void;
onBrowseChannels?: (onCreated?: (channelId: string) => void) => void;
onOpenDm: (input: { pubkeys: string[] }) => Promise<void>;
onUpdateCommunity: (
Expand Down Expand Up @@ -200,7 +199,6 @@ export function AppSidebar({
onHideDm,
onMarkChannelUnread,
onMarkChannelRead,
onMarkAllChannelsRead,
onBrowseChannels,
onOpenDm,
onUpdateCommunity,
Expand Down Expand Up @@ -481,6 +479,15 @@ export function AppSidebar({
),
[directMessages, dmChannelLabels, sortModeFor],
);
const unassignedChannelsHaveUnread = sectionBuckets.unassigned.some(
(channel) => unreadChannelIds.has(channel.id),
);
const forumsHaveUnread = forumChannels.some((channel) =>
unreadChannelIds.has(channel.id),
);
const directMessagesHaveUnread = sortedDirectMessages.some((channel) =>
unreadChannelIds.has(channel.id),
);
const sidebarLoadingShape = useSidebarLoadingShape({
activeCommunityId: activeCommunity?.id,
currentPubkey,
Expand Down Expand Up @@ -709,7 +716,7 @@ export function AppSidebar({
))}
<ChannelGroupSection
draggable
hasUnread={unreadChannelIds.size > 0}
hasUnread={unassignedChannelsHaveUnread}
isCollapsed={collapsedGroups.channels}
isActiveChannel={selectedView === "channel"}
activeWorkingByChannelId={activeWorkingByChannelId}
Expand All @@ -723,7 +730,11 @@ export function AppSidebar({
quickCreateLabel="Add channel"
onQuickCreateClick={onBrowseChannels}
showQuickCreate
onMarkAllRead={onMarkAllChannelsRead}
onMarkAllRead={() => {
for (const channel of sectionBuckets.unassigned) {
onMarkChannelRead(channel.id, channel.lastMessageAt);
}
}}
onMarkChannelRead={onMarkChannelRead}
onMarkChannelUnread={onMarkChannelUnread}
onSelectChannel={onSelectChannel}
Expand All @@ -749,7 +760,7 @@ export function AppSidebar({
<FeatureGate feature="forum">
<ChannelGroupSection
createLabel="New forum"
hasUnread={unreadChannelIds.size > 0}
hasUnread={forumsHaveUnread}
isCollapsed={collapsedGroups.forums}
isActiveChannel={selectedView === "channel"}
activeWorkingByChannelId={activeWorkingByChannelId}
Expand All @@ -761,7 +772,11 @@ export function AppSidebar({
actionsTestId="section-actions-forums"
listTestId="forum-list"
onCreateClick={() => openCreateDialog("forum")}
onMarkAllRead={onMarkAllChannelsRead}
onMarkAllRead={() => {
for (const channel of forumChannels) {
onMarkChannelRead(channel.id, channel.lastMessageAt);
}
}}
onMarkChannelRead={onMarkChannelRead}
onMarkChannelUnread={onMarkChannelUnread}
onSelectChannel={onSelectChannel}
Expand All @@ -787,6 +802,15 @@ export function AppSidebar({
sectionLabel="direct messages"
testId="section-actions-dms"
onOpenChange={setDmActionsMenuOpen}
hasUnread={directMessagesHaveUnread}
onMarkAllRead={() => {
for (const channel of sortedDirectMessages) {
onMarkChannelRead(
channel.id,
channel.lastMessageAt,
);
}
}}
onNewMessage={onNewMessage}
sortMode={sortModeFor("dms")}
onSortModeChange={(mode) =>
Expand All @@ -796,6 +820,7 @@ export function AppSidebar({
</div>
}
dmParticipantsByChannelId={dmParticipantsByChannelId}
hasUnread={directMessagesHaveUnread}
isCollapsed={collapsedGroups.directMessages}
isActiveChannel={selectedView === "channel"}
activeWorkingByChannelId={activeWorkingByChannelId}
Expand Down
32 changes: 32 additions & 0 deletions desktop/src/features/sidebar/ui/CustomChannelSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -288,15 +288,28 @@ export function SectionActionsMenu({
);
}

function SectionUnreadIndicator({ testId }: { testId: string }) {
return (
<span
aria-hidden="true"
className="ml-0.5 size-1.5 shrink-0 rounded-full bg-primary"
data-testid={testId}
title="Contains unread channels"
/>
);
}

function ChannelSectionHeader({
contentId,
hasUnread,
isCollapsed,
onToggleCollapsed,
title,
testId,
actions,
}: {
contentId: string;
hasUnread?: boolean;
isCollapsed: boolean;
onToggleCollapsed: () => void;
title: string;
Expand All @@ -315,6 +328,14 @@ function ChannelSectionHeader({
type="button"
>
<span data-sidebar-section-title>{title}</span>
{isCollapsed && hasUnread ? (
<>
<SectionUnreadIndicator
testId={`${testId}-section-unread-indicator`}
/>
<span className="sr-only">Contains unread channels</span>
</>
) : null}
<span aria-hidden="true" className={SECTION_LABEL_CHEVRON_CLASS}>
<ChevronDown
className={cn(
Expand Down Expand Up @@ -493,6 +514,7 @@ export function ChannelGroupSection({
>
<ChannelSectionHeader
contentId={contentId}
hasUnread={hasUnread}
isCollapsed={isCollapsed}
onToggleCollapsed={onToggleCollapsed}
title={title}
Expand Down Expand Up @@ -663,6 +685,16 @@ export function CustomChannelSection({
>
{section.name}
</span>
{isCollapsed && hasUnread ? (
<>
<SectionUnreadIndicator
testId={`section-unread-indicator-${section.id}`}
/>
<span className="sr-only">
Contains unread channels
</span>
</>
) : null}
<span
aria-hidden="true"
className={SECTION_LABEL_CHEVRON_CLASS}
Expand Down
13 changes: 13 additions & 0 deletions desktop/src/features/sidebar/ui/SidebarSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ export function SidebarSection({
emptyState,
items,
channelLabels,
hasUnread = false,
isCollapsed,
isActiveChannel,
presenceByChannelId,
Expand All @@ -367,6 +368,7 @@ export function SidebarSection({
emptyState?: React.ReactNode;
items: Channel[];
channelLabels?: Record<string, string>;
hasUnread?: boolean;
isCollapsed?: boolean;
isActiveChannel: boolean;
presenceByChannelId?: Record<string, PresenceStatus>;
Expand Down Expand Up @@ -412,6 +414,17 @@ export function SidebarSection({
type="button"
>
<span data-sidebar-section-title>{title}</span>
{isCollapsed && hasUnread ? (
<>
<span
aria-hidden="true"
className="ml-0.5 size-1.5 shrink-0 rounded-full bg-primary"
data-testid={`${testId}-section-unread-indicator`}
title="Contains unread channels"
/>
<span className="sr-only">Contains unread channels</span>
</>
) : null}
<span aria-hidden="true" className={SECTION_LABEL_CHEVRON_CLASS}>
<ChevronDown
className={cn(
Expand Down
Loading
Loading