fix hierarchy indenting and order

This commit is contained in:
Gimle Larpes 2025-06-27 10:05:56 +02:00
parent c0799142d6
commit 2fae418132
2 changed files with 68 additions and 36 deletions

View file

@ -1,6 +1,6 @@
import { atom, useAtom, useAtomValue } from 'jotai';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { MatrixError, Room } from 'matrix-js-sdk';
import { MatrixError, MatrixEvent, Room } from 'matrix-js-sdk';
import { IHierarchyRoom } from 'matrix-js-sdk/lib/@types/spaces';
import { QueryFunction, useInfiniteQuery } from '@tanstack/react-query';
import { useMatrixClient } from './useMatrixClient';
@ -18,6 +18,7 @@ export type HierarchyItemSpace = {
ts: number;
space: true;
parentId?: string;
depth: number;
};
export type HierarchyItemRoom = {
@ -25,6 +26,7 @@ export type HierarchyItemRoom = {
content: MSpaceChildContent;
ts: number;
parentId: string;
depth: number;
};
export type HierarchyItem = HierarchyItemSpace | HierarchyItemRoom;
@ -35,6 +37,10 @@ const hierarchyItemTs: SortFunc<HierarchyItem> = (a, b) => byTsOldToNew(a.ts, b.
const hierarchyItemByOrder: SortFunc<HierarchyItem> = (a, b) =>
byOrderKey(a.content.order, b.content.order);
const childEventTs: SortFunc<MatrixEvent> = (a, b) => byTsOldToNew(a.getTs(), b.getTs());
const childEventByOrder: SortFunc<MatrixEvent> = (a, b) =>
byOrderKey(a.getContent<MSpaceChildContent>().order, b.getContent<MSpaceChildContent>().order);
const getHierarchySpaces = (
rootSpaceId: string,
getRoom: GetRoomCallback,
@ -45,8 +51,9 @@ const getHierarchySpaces = (
content: { via: [] },
ts: 0,
space: true,
depth: 0,
};
let spaceItems: HierarchyItemSpace[] = [];
const spaceItems: HierarchyItemSpace[] = [];
const findAndCollectHierarchySpaces = (spaceItem: HierarchyItemSpace) => {
if (spaceItems.find((item) => item.roomId === spaceItem.roomId)) return;
@ -55,37 +62,37 @@ const getHierarchySpaces = (
if (!space) return;
const childEvents = getStateEvents(space, StateEvent.SpaceChild);
childEvents.forEach((childEvent) => {
if (!isValidChild(childEvent)) return;
childEvents
.filter((childEvent) => {
if (!isValidChild(childEvent)) return false;
const childId = childEvent.getStateKey();
if (!childId || !isRoomId(childId)) return;
if (!childId || !isRoomId(childId)) return false;
// because we can not find if a childId is space without joining
// or requesting room summary, we will look it into spaceRooms local
// cache which we maintain as we load summary in UI.
if (getRoom(childId)?.isSpaceRoom() || spaceRooms.has(childId)) {
return getRoom(childId)?.isSpaceRoom() || spaceRooms.has(childId);
})
.sort(childEventTs)
.sort(childEventByOrder);
childEvents.forEach((childEvent) => {
const childId = childEvent.getStateKey();
if (!childId || !isRoomId(childId)) return;
const childItem: HierarchyItemSpace = {
roomId: childId,
content: childEvent.getContent<MSpaceChildContent>(),
ts: childEvent.getTs(),
space: true,
parentId: spaceItem.roomId,
depth: spaceItem.depth + 1,
};
findAndCollectHierarchySpaces(childItem);
}
});
};
findAndCollectHierarchySpaces(rootSpaceItem);
spaceItems = [
rootSpaceItem,
...spaceItems
.filter((item) => item.roomId !== rootSpaceId)
.sort(hierarchyItemTs)
.sort(hierarchyItemByOrder),
];
return spaceItems;
};
@ -121,6 +128,7 @@ const getSpaceHierarchy = (
content: childEvent.getContent<MSpaceChildContent>(),
ts: childEvent.getTs(),
parentId: spaceItem.roomId,
depth: spaceItem.depth,
};
childItems.push(childItem);
});
@ -208,6 +216,7 @@ const getSpaceJoinedHierarchy = (
content: childEvent.getContent<MSpaceChildContent>(),
ts: childEvent.getTs(),
parentId: spaceItem.roomId,
depth: spaceItem.depth,
};
childItems.push(childItem);
});

View file

@ -318,7 +318,8 @@ export function Space() {
useCallback(
(parentId, roomId) => {
if (!closedCategories.has(makeNavCategoryId(space.roomId, parentId))) {
return false;
// REWORK HOW THIS WORKS?
return false; // This does not account for sub-subspaces, best way to do? - first fix useSpaceHie...
}
const showRoom = roomToUnread.has(roomId) || roomId === selectedRoomId;
if (showRoom) return false;
@ -346,6 +347,12 @@ export function Space() {
const getToLink = (roomId: string) =>
getSpaceRoomPath(spaceIdOrAlias, getCanonicalAliasOrRoomId(mx, roomId));
const getCategoryPadding = (depth: number): string | undefined => {
if (depth === 0) return undefined;
if (depth === 1) return config.space.S400;
return config.space.S200;
};
return (
<PageNav>
<SpaceHeader />
@ -392,12 +399,17 @@ export function Space() {
}}
>
{virtualizer.getVirtualItems().map((vItem) => {
const { roomId } = hierarchy[vItem.index] ?? {};
const { roomId, depth } = hierarchy[vItem.index] ?? {};
const room = mx.getRoom(roomId);
if (!room) return null;
const paddingLeft = `calc((${depth} - 1) * ${config.space.S200})`;
if (room.isSpaceRoom()) {
const categoryId = makeNavCategoryId(space.roomId, roomId);
const closed = closedCategories.has(categoryId);
const paddingTop = getCategoryPadding(depth);
return (
<VirtualTile
@ -405,12 +417,18 @@ export function Space() {
key={vItem.index}
ref={virtualizer.measureElement}
>
<div style={{ paddingTop: vItem.index === 0 ? undefined : config.space.S400 }}>
<div
style={{
paddingTop,
paddingLeft,
}}
>
<NavCategoryHeader>
<RoomNavCategoryButton
data-category-id={categoryId}
onClick={handleCategoryClick}
closed={closedCategories.has(categoryId)}
closed={closed}
aria-expanded={!closed}
>
{roomId === space.roomId ? 'Rooms' : room?.name}
</RoomNavCategoryButton>
@ -422,14 +440,19 @@ export function Space() {
return (
<VirtualTile virtualItem={vItem} key={vItem.index} ref={virtualizer.measureElement}>
<div style={{ paddingLeft }}>
<RoomNavItem
room={room}
selected={selectedRoomId === roomId}
showAvatar={mDirects.has(roomId)}
direct={mDirects.has(roomId)}
linkPath={getToLink(roomId)}
notificationMode={getRoomNotificationMode(notificationPreferences, room.roomId)}
notificationMode={getRoomNotificationMode(
notificationPreferences,
room.roomId
)}
/>
</div>
</VirtualTile>
);
})}