Add a page and config option for a room directory server

This commit is contained in:
Ginger 2025-09-06 13:24:50 -04:00
parent 3de1ce8f2f
commit 401d8ed930
No known key found for this signature in database
5 changed files with 113 additions and 37 deletions

View file

@ -9,7 +9,6 @@
"xmr.se"
],
"allowCustomHomeservers": true,
"featuredCommunities": {
"openAsDefault": false,
"spaces": [
@ -28,9 +27,14 @@
"#PrivSec.dev:arcticfoxes.net",
"#disroot:aria-net.org"
],
"servers": ["envs.net", "matrix.org", "monero.social", "mozilla.org"]
"servers": [
"envs.net",
"matrix.org",
"monero.social",
"mozilla.org"
],
"directoryServer": "matrixrooms.info"
},
"hashRouter": {
"enabled": false,
"basename": "/"

View file

@ -1,5 +1,6 @@
import { useMatch, useParams } from 'react-router-dom';
import { getExploreFeaturedPath, getExplorePath } from '../../pages/pathUtils';
import { useClientConfig } from '../useClientConfig';
export const useExploreSelected = (): boolean => {
const match = useMatch({
@ -26,3 +27,8 @@ export const useExploreServer = (): string | undefined => {
return server;
};
export const useDirectoryServer = (): string | undefined => {
const { featuredCommunities } = useClientConfig();
return featuredCommunities?.directoryServer;
};

View file

@ -15,6 +15,7 @@ export type ClientConfig = {
spaces?: string[];
rooms?: string[];
servers?: string[];
directoryServer?: string;
};
hashRouter?: HashRouterConfig;

View file

@ -32,6 +32,7 @@ import {
} from '../../../components/nav';
import { getExploreFeaturedPath, getExploreServerPath } from '../../pathUtils';
import {
useDirectoryServer,
useExploreFeaturedRooms,
useExploreServer,
} from '../../../hooks/router/useExploreSelected';
@ -250,28 +251,31 @@ export function Explore() {
useNavToActivePathMapper('explore');
const userId = mx.getUserId();
const userServer = userId ? getMxIdServer(userId) : undefined;
const directoryServer = useDirectoryServer();
const [bookmarkedServers, addServerBookmark, removeServerBookmark] = useBookmarkedServers();
const selectedServer = useExploreServer();
const exploringFeaturedRooms = useExploreFeaturedRooms();
const exploringDirectory = directoryServer !== undefined && selectedServer === directoryServer;
const exploringUnlistedServer = useMemo(
() =>
!(
selectedServer === undefined ||
selectedServer === userServer ||
exploringDirectory ||
bookmarkedServers.includes(selectedServer)
),
[bookmarkedServers, selectedServer, userServer]
[bookmarkedServers, selectedServer, userServer, exploringDirectory]
);
const viewServerCallback = useCallback(
async (server: string, saveBookmark: boolean) => {
if (saveBookmark && server !== userServer && selectedServer) {
if (saveBookmark && server !== userServer && server !== directoryServer && selectedServer) {
await addServerBookmark(server);
}
navigate(getExploreServerPath(server));
},
[addServerBookmark, navigate, userServer, selectedServer]
[addServerBookmark, navigate, userServer, directoryServer, selectedServer]
);
const removeServerBookmarkCallback = useCallback(
@ -312,6 +316,24 @@ export function Explore() {
</NavItemContent>
</NavLink>
</NavItem>
{directoryServer && (
<NavItem variant="Background" radii="400" aria-selected={exploringDirectory}>
<NavLink to={getExploreServerPath(directoryServer)}>
<NavItemContent>
<Box as="span" grow="Yes" alignItems="Center" gap="200">
<Avatar size="200" radii="400">
<Icon src={Icons.Search} size="100" filled={exploringDirectory} />
</Avatar>
<Box as="span" grow="Yes">
<Text as="span" size="Inherit" truncate>
Public Room Directory
</Text>
</Box>
</Box>
</NavItemContent>
</NavLink>
</NavItem>
)}
{userServer && (
<ExploreServerNavItem
server={userServer}

View file

@ -9,11 +9,13 @@ import React, {
useState,
} from 'react';
import {
Badge,
Box,
Button,
Chip,
Icon,
IconButton,
IconSrc,
Icons,
Input,
Line,
@ -49,6 +51,7 @@ import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
import { BackRouteHandler } from '../../../components/BackRouteHandler';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { useBookmarkedServers } from '../../../hooks/useBookmarkedServers';
import { useDirectoryServer } from '../../../hooks/router/useExploreSelected';
const useServerSearchParams = (searchParams: URLSearchParams): ExploreServerPathSearchParams =>
useMemo(
@ -349,6 +352,7 @@ export function PublicRooms() {
const mx = useMatrixClient();
const userId = mx.getUserId();
const userServer = userId && getMxIdServer(userId);
const directoryServer = useDirectoryServer();
const allRooms = useAtomValue(allRoomsAtom);
const { navigateSpace, navigateRoom } = useRoomNavigate();
const screenSize = useScreenSizeContext();
@ -363,6 +367,15 @@ export function PublicRooms() {
const [bookmarkedServers, addServerBookmark, removeServerBookmark] = useBookmarkedServers();
const isUserHomeserver = server !== undefined && server === userServer;
const isBookmarkedServer = server !== undefined && bookmarkedServers.includes(server);
const isDirectoryServer = server !== undefined && server === directoryServer;
let headerIcon: IconSrc;
if (isUserHomeserver) {
headerIcon = Icons.Home;
} else if (isDirectoryServer) {
headerIcon = Icons.Search;
} else {
headerIcon = Icons.Server;
}
const currentLimit: number = useMemo(() => {
const limitParam = serverSearchParams.limit;
@ -526,14 +539,43 @@ export function PublicRooms() {
)}
</Box>
<Box grow="Yes" basis="Yes" justifyContent="Center" alignItems="Center" gap="200">
{screenSize !== ScreenSize.Mobile && (
<Icon size="400" src={isUserHomeserver ? Icons.Home : Icons.Server} />
)}
{screenSize !== ScreenSize.Mobile && <Icon size="400" src={headerIcon} />}
<Text size="H3" truncate>
{server}
{isDirectoryServer ? 'Public Room Directory' : server}
</Text>
</Box>
<Box shrink="No" grow="Yes" basis="No" justifyContent="End">
{isDirectoryServer ? (
<TooltipProvider
position="Bottom"
align="End"
offset={4}
tooltip={
<Tooltip>
<Text>provided by {directoryServer}</Text>
</Tooltip>
}
>
{(triggerRef) => (
<Chip
as="a"
href={`https://${directoryServer}`}
target="_blank"
rel="noreferrer noopener"
variant="Secondary"
radii="Pill"
fill="Soft"
ref={screenSize === ScreenSize.Mobile ? triggerRef : undefined}
style={{ maxWidth: '100%' }}
before={<Icon src={Icons.External} size="50" />}
>
<Text size="T200" truncate>
provided by {directoryServer}
</Text>
</Chip>
)}
</TooltipProvider>
) : (
<TooltipProvider
position="Bottom"
align="End"
@ -560,6 +602,7 @@ export function PublicRooms() {
)
}
</TooltipProvider>
)}
</Box>
</>
)}