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
5 changes: 5 additions & 0 deletions .changeset/add_basic_hiding_rooms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
default: minor
---

Add per Space setting for when to show room icons in sidebar
2 changes: 1 addition & 1 deletion .changeset/fix-various-banner-fixes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
default: fix
default: patch
---

Various small banner changes
39 changes: 37 additions & 2 deletions src/app/components/GlobalKeyboardShortcuts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import { getCanonicalAliasOrRoomId } from '$utils/matrix';
import { announce } from '$utils/announce';
import { roomIdToReplyDraftAtomFamily } from '$state/room/roomInputDrafts';
import type { Room } from '$types/matrix-sdk';
import { useSetting } from '$state/hooks/settings';
import { settingsAtom } from '$state/settings';
import { allRoomsAtom } from '$state/room-list/roomList';
import { useSelectedRoom } from '$hooks/router/useSelectedRoom';

export function GlobalKeyboardShortcuts() {
const navigate = useNavigate();
Expand All @@ -32,6 +36,16 @@ export function GlobalKeyboardShortcuts() {
const roomToUnread = useAtomValue(roomToUnreadAtom);
const unreadIndexRef = useRef(0);

const allRooms = useAtomValue(allRoomsAtom);
const [isHidingRooms, setIsHidingRooms] = useSetting(settingsAtom, 'isHidingRooms');
const [hiddenRooms] = useSetting(settingsAtom, 'hiddenRooms');
const [hiddenSpaces] = useSetting(settingsAtom, 'hiddenSpaces');
const selectedRoomId = useSelectedRoom();

const filteredRooms = allRooms.filter(
(item) => !hiddenRooms.includes(item) && !hiddenSpaces.includes(item)
);

// Derive the current room ID from the URL so we know which room is active.
const roomMatch =
matchPath(HOME_ROOM_PATH, location.pathname) ??
Expand All @@ -54,7 +68,7 @@ export function GlobalKeyboardShortcuts() {

/** Navigate to a room by ID and announce it to screen readers. */
const navigateToRoom = useCallback(
(roomId: string, remaining: number) => {
(roomId: string, remaining?: number) => {
const roomIdOrAliasToNav = getCanonicalAliasOrRoomId(mx, roomId);
const isDirect = mDirects.has(roomId);
if (isDirect) {
Expand All @@ -75,7 +89,9 @@ export function GlobalKeyboardShortcuts() {
}
const roomName = mx.getRoom(roomId)?.name ?? 'Room';
const roomType = isDirect ? 'Direct Message' : 'Group Room';
announce(`${roomName}, ${roomType}. ${remaining} room${remaining === 1 ? '' : 's'} unread.`);
announce(
`${roomName}, ${roomType}.${remaining && `${remaining} room${remaining === 1 ? '' : 's'} unread.`}`
);
},
[mx, mDirects, roomToParents, navigate]
);
Expand Down Expand Up @@ -151,9 +167,28 @@ export function GlobalKeyboardShortcuts() {
[currentRoom, replyDraft, setReplyDraft]
);

/** Alt+Shift+H: Toggle Hide Rooms. */
const handleHideRoomsKeyDown = useCallback(
(evt: KeyboardEvent) => {
if (!isKeyHotkey('alt+shift+h', evt)) return;
evt.preventDefault();
announce(`${isHidingRooms ? 'Disabling' : 'Enabling'} hiding rooms.`);
setIsHidingRooms(!isHidingRooms);
if (
selectedRoomId &&
filteredRooms.length > 0 &&
filteredRooms[0] &&
!filteredRooms.includes(selectedRoomId)
)
navigateToRoom(filteredRooms[0]);
},
[setIsHidingRooms, isHidingRooms, navigateToRoom, filteredRooms, selectedRoomId]
);

useKeyDown(window, handleNextUnreadKeyDown);
useKeyDown(window, handleUnreadNavKeyDown);
useKeyDown(window, handleReplyKeyDown);
useKeyDown(window, handleHideRoomsKeyDown);

return null;
}
27 changes: 21 additions & 6 deletions src/app/components/user-profile/UserChips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ import { SettingTile } from '$components/setting-tile';
import { RoomAvatar, RoomIcon } from '$components/room-avatar';
import { heroMenuItemStyle } from './heroMenuItemStyle';
import * as css from './styles.css';
import { useSetting } from '$state/hooks/settings';
import { settingsAtom } from '$state/settings';

export function ServerChip({
server,
Expand Down Expand Up @@ -368,6 +370,21 @@ export function MutualRoomsChip({

const [cords, setCords] = useState<RectCords>();

const [isHidingRooms] = useSetting(settingsAtom, 'isHidingRooms');
const [hiddenRooms] = useSetting(settingsAtom, 'hiddenRooms');
const [hiddenSpaces] = useSetting(settingsAtom, 'hiddenSpaces');
const baseMutualRooms = useMemo(
() =>
(mutualRoomsState.status === AsyncStatus.Success &&
(!isHidingRooms
? mutualRoomsState.data
: mutualRoomsState.data.filter(
(item) => !hiddenRooms.includes(item) && !hiddenSpaces.includes(item)
))) ||
[],
[isHidingRooms, hiddenRooms, hiddenSpaces, mutualRoomsState]
);

const open: MouseEventHandler<HTMLButtonElement> = (evt) => {
setCords(evt.currentTarget.getBoundingClientRect());
};
Expand All @@ -382,7 +399,7 @@ export function MutualRoomsChip({
};

if (mutualRoomsState.status === AsyncStatus.Success) {
const mutualRooms = mutualRoomsState.data
const mutualRooms = baseMutualRooms
.toSorted(factoryRoomIdByAtoZ(mx))
.map(getRoom)
.filter((room) => !!room);
Expand All @@ -399,7 +416,7 @@ export function MutualRoomsChip({
});
}
return data;
}, [mutualRoomsState, getRoom, directs, mx]);
}, [mutualRoomsState, getRoom, directs, mx, baseMutualRooms]);

if (
userId === mx.getSafeUserId() ||
Expand Down Expand Up @@ -541,9 +558,7 @@ export function MutualRoomsChip({
variant={cardColor ? undefined : 'SurfaceVariant'}
radii="Pill"
before={mutualRoomsState.status === AsyncStatus.Loading && <Spinner size="50" />}
disabled={
mutualRoomsState.status !== AsyncStatus.Success || mutualRoomsState.data.length === 0
}
disabled={mutualRoomsState.status !== AsyncStatus.Success || baseMutualRooms.length === 0}
onClick={open}
aria-pressed={!!cords}
className={cardColor ? css.UserHeroChipThemed : css.UserHeroBrightnessHover}
Expand All @@ -554,7 +569,7 @@ export function MutualRoomsChip({
>
<Text size="B300" style={{ color: textColor }}>
{mutualRoomsState.status === AsyncStatus.Success &&
`${mutualRoomsState.data.length} Mutual Rooms`}
`${baseMutualRooms.length} Mutual Rooms`}
{mutualRoomsState.status === AsyncStatus.Loading && 'Mutual Rooms'}
</Text>
</Chip>
Expand Down
44 changes: 39 additions & 5 deletions src/app/features/common-settings/appearance/Appearance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
MenuItem,
PopOut,
type RectCords,
Switch,
} from 'folds';
import { Page, PageContent, PageHeader } from '$components/page';
import { SequenceCard } from '$components/sequence-card';
Expand Down Expand Up @@ -98,11 +99,35 @@ export function SelectShowPerRoomRoomIcon({ roomId }: { roomId: string }) {
);
}

export function SelectHideRoom({ roomId, isSpace }: { roomId: string; isSpace?: boolean }) {
const [hideRoom, setHideRoom] = useSetting(
settingsAtom,
isSpace ? 'hiddenSpaces' : 'hiddenRooms'
);
const isHidden = hideRoom.includes(roomId);

function handleHideRoom() {
const newHideRoomList = !isHidden
? [...hideRoom, roomId]
: hideRoom.filter((roomItem) => roomItem !== roomId);
setHideRoom(newHideRoomList);
}

return (
<SettingTile
title="Add Room to Hide list"
description="Should this room be hidden upon enabling the Hide Rooms option?"
after={<Switch variant="Primary" value={isHidden} onChange={handleHideRoom} />}
/>
);
}

type AppearanceProps = {
requestClose: () => void;
};
export function Appearance({ requestClose }: AppearanceProps) {
const room = useRoom();
const isSpace = room.isSpaceRoom();

return (
<Page>
Expand All @@ -126,16 +151,25 @@ export function Appearance({ requestClose }: AppearanceProps) {
<Box direction="Column" gap="700">
<Box direction="Column" gap="100">
<Text size="L400">Visual Tweaks</Text>
{isSpace && (
<SequenceCard
className={SequenceCardStyle}
variant="SurfaceVariant"
direction="Column"
>
<SettingTile
title="Show Room Icons In Sidebar"
description="When do you want to show the specific room icons in the sidebar within this space?"
after={<SelectShowPerRoomRoomIcon roomId={room.roomId} />}
/>
</SequenceCard>
)}
<SequenceCard
className={SequenceCardStyle}
variant="SurfaceVariant"
direction="Column"
>
<SettingTile
title="Show Room Icons In Sidebar"
description="When do you want to show the specific room icons in the sidebar within this space?"
after={<SelectShowPerRoomRoomIcon roomId={room.roomId} />}
/>
<SelectHideRoom roomId={room.roomId} isSpace={isSpace} />
</SequenceCard>
</Box>
</Box>
Expand Down
10 changes: 10 additions & 0 deletions src/app/features/room-settings/RoomSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { useSetting } from '$state/hooks/settings';
import { Permissions } from './permissions';
import { General } from './general';
import { RoomAbbreviations } from './abbreviations/RoomAbbreviations';
import { Appearance } from '$features/common-settings/appearance/Appearance';

type RoomSettingsMenuItem = {
page: RoomSettingsPage;
Expand Down Expand Up @@ -70,6 +71,12 @@ const useRoomSettingsMenuItems = (): RoomSettingsMenuItem[] =>
name: 'Developer Tools',
icon: Icons.Terminal,
},
{
page: RoomSettingsPage.AppearancePage,
name: 'Appearance',
icon: Icons.Alphabet,
activeIcon: Icons.AlphabetUnderline,
},
],
[]
);
Expand Down Expand Up @@ -209,6 +216,9 @@ export function RoomSettings({ initialPage, requestClose }: RoomSettingsProps) {
{activePage === RoomSettingsPage.AbbreviationsPage && (
<RoomAbbreviations requestClose={handlePageRequestClose} />
)}
{activePage === RoomSettingsPage.AppearancePage && (
<Appearance requestClose={handlePageRequestClose} />
)}
</PageRoot>
</SwipeableOverlayWrapper>
);
Expand Down
36 changes: 36 additions & 0 deletions src/app/features/settings/cosmetics/Themes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
Chip,
config,
Icon,
IconButton,
Icons,
Input,
Menu,
Expand Down Expand Up @@ -787,6 +788,9 @@ export function Appearance({
const [twitterEmoji, setTwitterEmoji] = useSetting(settingsAtom, 'twitterEmoji');
const [customDMCards, setCustomDMCards] = useSetting(settingsAtom, 'customDMCards');
const [showEasterEggs, setShowEasterEggs] = useSetting(settingsAtom, 'showEasterEggs');
const [isHidingRooms, setIsHidingRooms] = useSetting(settingsAtom, 'isHidingRooms');
const [hiddenSpaces, setHiddenSpaces] = useSetting(settingsAtom, 'hiddenSpaces');
const [hiddenRooms, setHiddenRooms] = useSetting(settingsAtom, 'hiddenRooms');
const [themeBrowserOpen, setThemeBrowserOpen] = useState(false);
const [closeFoldersByDefault, setCloseFoldersByDefault] = useSetting(
settingsAtom,
Expand Down Expand Up @@ -855,6 +859,38 @@ export function Appearance({
/>
</SequenceCard>

<SequenceCard className={SequenceCardStyle} variant="SurfaceVariant" direction="Column">
<SettingTile
title="Hide rooms"
focusId="toggle-hide-rooms"
description="Hide the rooms that are set to be in the hidden list"
after={
<Switch variant="Primary" value={isHidingRooms} onChange={setIsHidingRooms} />
}
/>
</SequenceCard>

<SequenceCard className={SequenceCardStyle} variant="SurfaceVariant" direction="Column">
<SettingTile
title="Clear Hidden Room List"
focusId="clear-hidden-room-list"
description="Clear the list of rooms and spaces that should be hidden"
after={
<IconButton
size="300"
onClick={() => {
setHiddenRooms([]);
setHiddenSpaces([]);
}}
radii="300"
disabled={hiddenRooms?.length === 0 && hiddenSpaces?.length === 0}
>
<Icon src={Icons.Reload} />
</IconButton>
}
/>
</SequenceCard>

<SequenceCard className={SequenceCardStyle} variant="SurfaceVariant" direction="Column">
<SettingTile title="Page Zoom" focusId="page-zoom" after={<PageZoomInput />} />
</SequenceCard>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ const SHORTCUT_CATEGORIES: ShortcutCategory[] = [
{ keys: 'Ctrl+U / ⌘+U', description: 'Underline' },
],
},
{
name: 'Other',
shortcuts: [{ keys: 'Alt+Shift+H', description: 'Toggle Hiding Rooms' }],
},
];

function ShortcutRow({ keys, description }: ShortcutEntry) {
Expand Down
2 changes: 2 additions & 0 deletions src/app/features/settings/settingsLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ const settingsLinkFocusIdsBySection: Record<SettingsSectionId, readonly string[]
'saturation',
'selected-language-for-pronouns',
'show-easter-eggs',
'toggle-hide-rooms',
'clear-hidden-room-list',
'show-pronoun-pills',
'show-pronouns-only-in-selected-language',
'subspace-hierarchy-limit',
Expand Down
18 changes: 15 additions & 3 deletions src/app/pages/client/direct/Direct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,11 @@ export function Direct() {
const roomToUnread = useAtomValue(roomToUnreadAtom);
const navigate = useNavigate();
const [customDMCards] = useSetting(settingsAtom, 'customDMCards');
const [hiddenRooms] = useSetting(settingsAtom, 'hiddenRooms');
const [isHidingRooms] = useSetting(settingsAtom, 'isHidingRooms');

const [roomSidebarWidth, setRoomSidebarWidth] = useSetting(settingsAtom, 'roomSidebarWidth');
const [curWidth, setCurWidth] = useState(roomSidebarWidth);

useEffect(() => {
setCurWidth(roomSidebarWidth);
}, [roomSidebarWidth]);
Expand Down Expand Up @@ -233,7 +235,8 @@ export function Direct() {

const sortedDirects = useMemo(() => {
void activityCounter;
const items = Array.from(directs).toSorted(factoryRoomIdByActivity(mx));
let items = Array.from(directs).toSorted(factoryRoomIdByActivity(mx));
if (isHidingRooms) items = items.filter((rId) => !hiddenRooms.includes(rId));
const hasUnread = (roomId: string) => {
const unread = roomToUnread.get(roomId);
return !!unread && (unread.total > 0 || unread.highlight > 0);
Expand All @@ -242,7 +245,16 @@ export function Direct() {
return items.filter((rId) => hasUnread(rId) || rId === selectedRoomId);
}
return items;
}, [mx, directs, closedCategories, roomToUnread, selectedRoomId, activityCounter]);
}, [
mx,
directs,
closedCategories,
roomToUnread,
selectedRoomId,
activityCounter,
hiddenRooms,
isHidingRooms,
]);

const virtualizer = useVirtualizer({
count: sortedDirects.length,
Expand Down
Loading
Loading