feat: enhance room navigation with sub-room indicators and styling adjustments
This commit is contained in:
@@ -236,8 +236,8 @@ function HomeEmpty() {
|
||||
}
|
||||
|
||||
type RoomListItem =
|
||||
| { type: 'room'; roomId: string; room: Room; depth: number; parentId?: string }
|
||||
| { type: 'unjoined-subroom'; roomId: string; depth: number; parentId: string };
|
||||
| { type: 'room'; roomId: string; room: Room; depth: number; parentId?: string; isLast?: boolean }
|
||||
| { type: 'unjoined-subroom'; roomId: string; depth: number; parentId: string; isLast?: boolean };
|
||||
|
||||
const DEFAULT_CATEGORY_ID = makeNavCategoryId('home', 'room');
|
||||
export function Home() {
|
||||
@@ -273,7 +273,7 @@ export function Home() {
|
||||
const items: RoomListItem[] = [];
|
||||
const processedRooms = new Set<string>();
|
||||
|
||||
const addRoomAndSubRooms = (roomId: string, depth: number = 0, parentId?: string) => {
|
||||
const addRoomAndSubRooms = (roomId: string, depth: number = 0, parentId?: string, isLast: boolean = false) => {
|
||||
if (processedRooms.has(roomId)) return; // Prevent infinite loops
|
||||
processedRooms.add(roomId);
|
||||
|
||||
@@ -281,19 +281,19 @@ export function Home() {
|
||||
|
||||
if (room) {
|
||||
// Joined room - show normally
|
||||
items.push({ type: 'room', roomId, room, depth, parentId });
|
||||
items.push({ type: 'room', roomId, room, depth, parentId, isLast });
|
||||
|
||||
// Get sub-rooms from room state
|
||||
const subRoomsEvent = room.currentState.getStateEvents(StateEvent.PaarrotSubRooms, '');
|
||||
const subRooms = subRoomsEvent?.getContent<{ children: string[] }>()?.children ?? [];
|
||||
|
||||
// Add sub-rooms recursively
|
||||
subRooms.forEach(subRoomId => {
|
||||
addRoomAndSubRooms(subRoomId, depth + 1, roomId);
|
||||
subRooms.forEach((subRoomId, index) => {
|
||||
addRoomAndSubRooms(subRoomId, depth + 1, roomId, index === subRooms.length - 1);
|
||||
});
|
||||
} else if (parentId) {
|
||||
// Unjoined sub-room - show with join button
|
||||
items.push({ type: 'unjoined-subroom', roomId, depth, parentId });
|
||||
items.push({ type: 'unjoined-subroom', roomId, depth, parentId, isLast });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -321,7 +321,7 @@ export function Home() {
|
||||
const virtualizer = useVirtualizer({
|
||||
count: listItems.length,
|
||||
getScrollElement: () => scrollRef.current,
|
||||
estimateSize: () => 38,
|
||||
estimateSize: () => 32,
|
||||
overscan: 10,
|
||||
});
|
||||
|
||||
@@ -336,7 +336,7 @@ export function Home() {
|
||||
<HomeEmpty />
|
||||
) : (
|
||||
<PageNavContent scrollRef={scrollRef}>
|
||||
<Box direction="Column" gap="300">
|
||||
<Box direction="Column" gap="100">
|
||||
<NavCategory>
|
||||
<NavItem variant="Background" radii="400" aria-selected={createRoomSelected}>
|
||||
<NavButton onClick={() => navigate(getHomeCreatePath())}>
|
||||
@@ -378,7 +378,9 @@ export function Home() {
|
||||
onCancel={() => setOpen(false)}
|
||||
onOpen={(roomIdOrAlias, viaServers, eventId) => {
|
||||
setOpen(false);
|
||||
const searchParams: _RoomSearchParams = { viaServers, eventId };
|
||||
const searchParams: _RoomSearchParams = {
|
||||
viaServers: viaServers?.join(',')
|
||||
};
|
||||
navigate(
|
||||
withSearchParam(
|
||||
getHomeRoomPath(roomIdOrAlias),
|
||||
@@ -435,13 +437,18 @@ export function Home() {
|
||||
key={vItem.index}
|
||||
ref={virtualizer.measureElement}
|
||||
>
|
||||
<UnjoinedSubRoomItem roomId={item.roomId} depth={item.depth} />
|
||||
<UnjoinedSubRoomItem roomId={item.roomId} depth={item.depth} isLast={item.isLast} />
|
||||
</VirtualTile>
|
||||
);
|
||||
}
|
||||
|
||||
const selected = selectedRoomId === item.roomId;
|
||||
const paddingLeft = item.depth > 0 ? `${item.depth * 24}px` : undefined;
|
||||
const paddingLeft = item.depth > 0 ? '30px' : undefined;
|
||||
|
||||
let treeIcon = '';
|
||||
if (item.depth > 0) {
|
||||
treeIcon = item.isLast ? '╰' : '├';
|
||||
}
|
||||
|
||||
return (
|
||||
<VirtualTile
|
||||
@@ -449,16 +456,31 @@ export function Home() {
|
||||
key={vItem.index}
|
||||
ref={virtualizer.measureElement}
|
||||
>
|
||||
<div style={{ paddingLeft }}>
|
||||
<RoomNavItem
|
||||
room={item.room}
|
||||
selected={selected}
|
||||
linkPath={getHomeRoomPath(getCanonicalAliasOrRoomId(mx, item.roomId))}
|
||||
notificationMode={getRoomNotificationMode(
|
||||
notificationPreferences,
|
||||
item.room.roomId
|
||||
)}
|
||||
/>
|
||||
<div style={{ paddingLeft, display: 'flex', alignItems: 'center', minHeight: item.depth > 0 ? '1.5rem' : undefined }}>
|
||||
{treeIcon && (
|
||||
<span style={{
|
||||
paddingRight: '2px',
|
||||
opacity: 0.5,
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '14px',
|
||||
lineHeight: '1',
|
||||
userSelect: 'none'
|
||||
}}>
|
||||
{treeIcon}
|
||||
</span>
|
||||
)}
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
<RoomNavItem
|
||||
room={item.room}
|
||||
selected={selected}
|
||||
hideIcon={item.depth > 0}
|
||||
linkPath={getHomeRoomPath(getCanonicalAliasOrRoomId(mx, item.roomId))}
|
||||
notificationMode={getRoomNotificationMode(
|
||||
notificationPreferences,
|
||||
item.room.roomId
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</VirtualTile>
|
||||
);
|
||||
|
||||
@@ -445,8 +445,8 @@ export function Space() {
|
||||
// Flatten hierarchy to include sub-rooms
|
||||
type HierarchyItem =
|
||||
| { type: 'hierarchy'; roomId: string }
|
||||
| { type: 'subroom'; roomId: string; room: Room; depth: number }
|
||||
| { type: 'unjoined-subroom'; roomId: string; depth: number };
|
||||
| { type: 'subroom'; roomId: string; room: Room; depth: number; isLast?: boolean }
|
||||
| { type: 'unjoined-subroom'; roomId: string; depth: number; isLast?: boolean };
|
||||
|
||||
const flattenedHierarchy = useMemo(() => {
|
||||
const items: HierarchyItem[] = [];
|
||||
@@ -459,19 +459,20 @@ export function Space() {
|
||||
const subRoomsEvent = room.currentState.getStateEvents(StateEvent.PaarrotSubRooms, '');
|
||||
const subRooms = subRoomsEvent?.getContent<{ children: string[] }>()?.children ?? [];
|
||||
|
||||
subRooms.forEach(subRoomId => {
|
||||
subRooms.forEach((subRoomId, index) => {
|
||||
if (processedSubRooms.has(subRoomId)) return;
|
||||
processedSubRooms.add(subRoomId);
|
||||
|
||||
const isLast = index === subRooms.length - 1;
|
||||
const subRoom = mx.getRoom(subRoomId);
|
||||
if (subRoom) {
|
||||
// Joined sub-room
|
||||
items.push({ type: 'subroom', roomId: subRoomId, room: subRoom, depth: baseDepth + 1 });
|
||||
items.push({ type: 'subroom', roomId: subRoomId, room: subRoom, depth: baseDepth + 1, isLast });
|
||||
// Recursively add sub-rooms of sub-rooms
|
||||
addSubRooms(subRoomId, baseDepth + 1);
|
||||
} else {
|
||||
// Unjoined sub-room - show with join button
|
||||
items.push({ type: 'unjoined-subroom', roomId: subRoomId, depth: baseDepth + 1 });
|
||||
items.push({ type: 'unjoined-subroom', roomId: subRoomId, depth: baseDepth + 1, isLast });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -562,26 +563,46 @@ export function Space() {
|
||||
if (item.type === 'unjoined-subroom') {
|
||||
return (
|
||||
<VirtualTile virtualItem={vItem} key={vItem.index} ref={virtualizer.measureElement}>
|
||||
<UnjoinedSubRoomItem roomId={item.roomId} depth={item.depth} />
|
||||
<UnjoinedSubRoomItem roomId={item.roomId} depth={item.depth} isLast={item.isLast} />
|
||||
</VirtualTile>
|
||||
);
|
||||
}
|
||||
|
||||
// Sub-room item (nested under parent)
|
||||
if (item.type === 'subroom') {
|
||||
const paddingLeft = `${item.depth * 24}px`;
|
||||
const paddingLeft = '30px';
|
||||
|
||||
let treeIcon = '';
|
||||
if (item.depth > 0) {
|
||||
treeIcon = item.isLast ? '╰' : '├';
|
||||
}
|
||||
|
||||
return (
|
||||
<VirtualTile virtualItem={vItem} key={vItem.index} ref={virtualizer.measureElement}>
|
||||
<div style={{ paddingLeft }}>
|
||||
<RoomNavItem
|
||||
room={item.room}
|
||||
selected={selectedRoomId === item.roomId}
|
||||
showAvatar={mDirects.has(item.roomId)}
|
||||
direct={mDirects.has(item.roomId)}
|
||||
linkPath={getToLink(item.roomId)}
|
||||
notificationMode={getRoomNotificationMode(notificationPreferences, item.room.roomId)}
|
||||
/>
|
||||
<div style={{ paddingLeft, display: 'flex', alignItems: 'center', minHeight: '1.5rem' }}>
|
||||
{treeIcon && (
|
||||
<span style={{
|
||||
paddingRight: '2px',
|
||||
opacity: 0.5,
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '14px',
|
||||
lineHeight: '1',
|
||||
userSelect: 'none'
|
||||
}}>
|
||||
{treeIcon}
|
||||
</span>
|
||||
)}
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
<RoomNavItem
|
||||
room={item.room}
|
||||
selected={selectedRoomId === item.roomId}
|
||||
hideIcon={item.depth > 0}
|
||||
showAvatar={mDirects.has(item.roomId)}
|
||||
direct={mDirects.has(item.roomId)}
|
||||
linkPath={getToLink(item.roomId)}
|
||||
notificationMode={getRoomNotificationMode(notificationPreferences, item.room.roomId)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</VirtualTile>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user