mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-06 15:30:27 +03:00
Allow more servers to be added to the list in the explore tab
This commit is contained in:
parent
d8009978e5
commit
25cfdbc6ff
3 changed files with 125 additions and 53 deletions
38
src/app/hooks/useExploreServers.ts
Normal file
38
src/app/hooks/useExploreServers.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { AccountDataEvent } from '../../types/matrix/accountData';
|
||||||
|
import { useAccountData } from './useAccountData';
|
||||||
|
import { useMatrixClient } from './useMatrixClient';
|
||||||
|
|
||||||
|
export type InCinnyExploreServersContent = {
|
||||||
|
servers?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ExploreServerListAction =
|
||||||
|
| {
|
||||||
|
type: 'APPEND';
|
||||||
|
server: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'DELETE';
|
||||||
|
server: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useExploreServers = (): [string[], (action: ExploreServerListAction) => void] => {
|
||||||
|
const mx = useMatrixClient();
|
||||||
|
const userAddedServers =
|
||||||
|
useAccountData(AccountDataEvent.CinnyExploreServers)?.getContent<InCinnyExploreServersContent>()
|
||||||
|
?.servers ?? [];
|
||||||
|
|
||||||
|
const setUserAddedServers = (action: ExploreServerListAction) => {
|
||||||
|
if (action.type === 'APPEND') {
|
||||||
|
mx.setAccountData(AccountDataEvent.CinnyExploreServers, {
|
||||||
|
servers: [...userAddedServers, action.server],
|
||||||
|
});
|
||||||
|
} else if (action.type === 'DELETE') {
|
||||||
|
mx.setAccountData(AccountDataEvent.CinnyExploreServers, {
|
||||||
|
servers: userAddedServers.filter((server) => server !== action.server),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [userAddedServers, setUserAddedServers];
|
||||||
|
};
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { FormEventHandler, useCallback, useRef, useState } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import FocusTrap from 'focus-trap-react';
|
import FocusTrap from 'focus-trap-react';
|
||||||
import {
|
import {
|
||||||
|
|
@ -18,11 +18,13 @@ import {
|
||||||
color,
|
color,
|
||||||
config,
|
config,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
|
import { useFocusWithin, useHover } from 'react-aria';
|
||||||
import {
|
import {
|
||||||
NavCategory,
|
NavCategory,
|
||||||
NavCategoryHeader,
|
NavCategoryHeader,
|
||||||
NavItem,
|
NavItem,
|
||||||
NavItemContent,
|
NavItemContent,
|
||||||
|
NavItemOptions,
|
||||||
NavLink,
|
NavLink,
|
||||||
} from '../../../components/nav';
|
} from '../../../components/nav';
|
||||||
import { getExploreFeaturedPath, getExploreServerPath } from '../../pathUtils';
|
import { getExploreFeaturedPath, getExploreServerPath } from '../../pathUtils';
|
||||||
|
|
@ -37,11 +39,13 @@ import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
||||||
import { useNavToActivePathMapper } from '../../../hooks/useNavToActivePathMapper';
|
import { useNavToActivePathMapper } from '../../../hooks/useNavToActivePathMapper';
|
||||||
import { PageNav, PageNavContent, PageNavHeader } from '../../../components/page';
|
import { PageNav, PageNavContent, PageNavHeader } from '../../../components/page';
|
||||||
import { stopPropagation } from '../../../utils/keyboard';
|
import { stopPropagation } from '../../../utils/keyboard';
|
||||||
|
import { useExploreServers } from '../../../hooks/useExploreServers';
|
||||||
|
|
||||||
export function AddServer() {
|
export function AddExploreServerPrompt() {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [dialog, setDialog] = useState(false);
|
const [dialog, setDialog] = useState(false);
|
||||||
|
const [, setExploreServers] = useExploreServers();
|
||||||
const serverInputRef = useRef<HTMLInputElement>(null);
|
const serverInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const [exploreState] = useAsyncCallback(
|
const [exploreState] = useAsyncCallback(
|
||||||
|
|
@ -55,22 +59,14 @@ export function AddServer() {
|
||||||
return server || undefined;
|
return server || undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit: FormEventHandler<HTMLFormElement> = (evt) => {
|
const handleSubmit = useCallback(() => {
|
||||||
evt.preventDefault();
|
|
||||||
const server = getInputServer();
|
const server = getInputServer();
|
||||||
if (!server) return;
|
if (!server) return;
|
||||||
// explore(server);
|
|
||||||
|
|
||||||
navigate(getExploreServerPath(server));
|
|
||||||
setDialog(false);
|
setDialog(false);
|
||||||
};
|
setExploreServers({ type: 'APPEND', server });
|
||||||
|
|
||||||
const handleView = () => {
|
|
||||||
const server = getInputServer();
|
|
||||||
if (!server) return;
|
|
||||||
navigate(getExploreServerPath(server));
|
navigate(getExploreServerPath(server));
|
||||||
setDialog(false);
|
}, [navigate, setExploreServers]);
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -102,7 +98,10 @@ export function AddServer() {
|
||||||
</Header>
|
</Header>
|
||||||
<Box
|
<Box
|
||||||
as="form"
|
as="form"
|
||||||
onSubmit={handleSubmit}
|
onSubmit={(evt) => {
|
||||||
|
evt.preventDefault();
|
||||||
|
handleSubmit();
|
||||||
|
}}
|
||||||
style={{ padding: config.space.S400 }}
|
style={{ padding: config.space.S400 }}
|
||||||
direction="Column"
|
direction="Column"
|
||||||
gap="400"
|
gap="400"
|
||||||
|
|
@ -131,7 +130,7 @@ export function AddServer() {
|
||||||
<Text size="B400">Save</Text>
|
<Text size="B400">Save</Text>
|
||||||
</Button> */}
|
</Button> */}
|
||||||
|
|
||||||
<Button type="submit" onClick={handleView} variant="Secondary" fill="Soft">
|
<Button type="submit" onClick={handleSubmit} variant="Secondary" fill="Soft">
|
||||||
<Text size="B400">View</Text>
|
<Text size="B400">View</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -155,14 +154,62 @@ export function AddServer() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ExploreServerNavItemProps = {
|
||||||
|
server: string;
|
||||||
|
selected: boolean;
|
||||||
|
onRemove?: (() => void) | null;
|
||||||
|
};
|
||||||
|
export function ExploreServerNavItem({
|
||||||
|
server,
|
||||||
|
selected,
|
||||||
|
onRemove = null,
|
||||||
|
}: ExploreServerNavItemProps) {
|
||||||
|
const [hover, setHover] = useState(false);
|
||||||
|
const { hoverProps } = useHover({ onHoverChange: setHover });
|
||||||
|
const { focusWithinProps } = useFocusWithin({ onFocusWithinChange: setHover });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NavItem
|
||||||
|
variant="Background"
|
||||||
|
radii="400"
|
||||||
|
aria-selected={selected}
|
||||||
|
{...hoverProps}
|
||||||
|
{...focusWithinProps}
|
||||||
|
>
|
||||||
|
<NavLink to={getExploreServerPath(server)}>
|
||||||
|
<NavItemContent>
|
||||||
|
<Box as="span" grow="Yes" alignItems="Center" gap="200">
|
||||||
|
<Avatar size="200" radii="400">
|
||||||
|
<Icon src={Icons.Category} size="100" filled={selected} />
|
||||||
|
</Avatar>
|
||||||
|
<Box as="span" grow="Yes">
|
||||||
|
<Text as="span" size="Inherit" truncate>
|
||||||
|
{server}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</NavItemContent>
|
||||||
|
</NavLink>
|
||||||
|
{onRemove !== null && hover && (
|
||||||
|
<NavItemOptions>
|
||||||
|
<IconButton onClick={onRemove} variant="Background" fill="None" size="300" radii="300">
|
||||||
|
<Icon size="50" src={Icons.Minus} />
|
||||||
|
</IconButton>
|
||||||
|
</NavItemOptions>
|
||||||
|
)}
|
||||||
|
</NavItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function Explore() {
|
export function Explore() {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
useNavToActivePathMapper('explore');
|
useNavToActivePathMapper('explore');
|
||||||
const userId = mx.getUserId();
|
const userId = mx.getUserId();
|
||||||
const clientConfig = useClientConfig();
|
const clientConfig = useClientConfig();
|
||||||
const userServer = userId ? getMxIdServer(userId) : undefined;
|
const userServer = userId ? getMxIdServer(userId) : undefined;
|
||||||
const servers =
|
const featuredServers =
|
||||||
clientConfig.featuredCommunities?.servers?.filter((server) => server !== userServer) ?? [];
|
clientConfig.featuredCommunities?.servers?.filter((server) => server !== userServer) ?? [];
|
||||||
|
const [exploreServers, setExploreServers] = useExploreServers();
|
||||||
|
|
||||||
const featuredSelected = useExploreFeaturedSelected();
|
const featuredSelected = useExploreFeaturedSelected();
|
||||||
const selectedServer = useExploreServer();
|
const selectedServer = useExploreServer();
|
||||||
|
|
@ -225,44 +272,30 @@ export function Explore() {
|
||||||
</NavItem>
|
</NavItem>
|
||||||
)}
|
)}
|
||||||
</NavCategory>
|
</NavCategory>
|
||||||
{servers.length > 0 && (
|
<NavCategory>
|
||||||
<NavCategory>
|
<NavCategoryHeader>
|
||||||
<NavCategoryHeader>
|
<Text size="O400" style={{ paddingLeft: config.space.S200 }}>
|
||||||
<Text size="O400" style={{ paddingLeft: config.space.S200 }}>
|
Servers
|
||||||
Servers
|
</Text>
|
||||||
</Text>
|
</NavCategoryHeader>
|
||||||
</NavCategoryHeader>
|
{featuredServers.map((server) => (
|
||||||
{servers.map((server) => (
|
<ExploreServerNavItem
|
||||||
<NavItem
|
key={server}
|
||||||
key={server}
|
server={server}
|
||||||
variant="Background"
|
selected={server === selectedServer}
|
||||||
radii="400"
|
/>
|
||||||
aria-selected={server === selectedServer}
|
))}
|
||||||
>
|
{exploreServers.map((server) => (
|
||||||
<NavLink to={getExploreServerPath(server)}>
|
<ExploreServerNavItem
|
||||||
<NavItemContent>
|
key={server}
|
||||||
<Box as="span" grow="Yes" alignItems="Center" gap="200">
|
server={server}
|
||||||
<Avatar size="200" radii="400">
|
selected={server === selectedServer}
|
||||||
<Icon
|
onRemove={() => setExploreServers({ type: 'DELETE', server })}
|
||||||
src={Icons.Category}
|
/>
|
||||||
size="100"
|
))}
|
||||||
filled={server === selectedServer}
|
</NavCategory>
|
||||||
/>
|
|
||||||
</Avatar>
|
|
||||||
<Box as="span" grow="Yes">
|
|
||||||
<Text as="span" size="Inherit" truncate>
|
|
||||||
{server}
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</NavItemContent>
|
|
||||||
</NavLink>
|
|
||||||
</NavItem>
|
|
||||||
))}
|
|
||||||
</NavCategory>
|
|
||||||
)}
|
|
||||||
<Box direction="Column">
|
<Box direction="Column">
|
||||||
<AddServer />
|
<AddExploreServerPrompt />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</PageNavContent>
|
</PageNavContent>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ export enum AccountDataEvent {
|
||||||
IgnoredUserList = 'm.ignored_user_list',
|
IgnoredUserList = 'm.ignored_user_list',
|
||||||
|
|
||||||
CinnySpaces = 'in.cinny.spaces',
|
CinnySpaces = 'in.cinny.spaces',
|
||||||
|
CinnyExploreServers = 'in.cinny.explore_servers',
|
||||||
|
|
||||||
ElementRecentEmoji = 'io.element.recent_emoji',
|
ElementRecentEmoji = 'io.element.recent_emoji',
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue