mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 06:20:28 +03:00 
			
		
		
		
	Apply requested changes
This commit is contained in:
		
							parent
							
								
									3cc7c085c2
								
							
						
					
					
						commit
						3eea7dd074
					
				
					 3 changed files with 197 additions and 169 deletions
				
			
		| 
						 | 
				
			
			@ -11,7 +11,7 @@ export const useExploreSelected = (): boolean => {
 | 
			
		|||
  return !!match;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useExploreFeaturedRooms = (): boolean => {
 | 
			
		||||
export const useExploreFeaturedSelected = (): boolean => {
 | 
			
		||||
  const match = useMatch({
 | 
			
		||||
    path: getExploreFeaturedPath(),
 | 
			
		||||
    caseSensitive: true,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,22 +7,22 @@ export type InCinnyExploreServersContent = {
 | 
			
		|||
  servers?: string[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useExploreServers = (
 | 
			
		||||
  exclude?: string[]
 | 
			
		||||
): [string[], (server: string) => Promise<void>, (server: string) => Promise<void>] => {
 | 
			
		||||
export const useExploreServers = (): [
 | 
			
		||||
  string[],
 | 
			
		||||
  (server: string) => Promise<void>,
 | 
			
		||||
  (server: string) => Promise<void>
 | 
			
		||||
] => {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const accountData = useAccountData(AccountDataEvent.CinnyExplore);
 | 
			
		||||
  const userAddedServers = useMemo(
 | 
			
		||||
    () =>
 | 
			
		||||
      accountData
 | 
			
		||||
        ?.getContent<InCinnyExploreServersContent>()
 | 
			
		||||
        ?.servers?.filter((server) => !exclude?.includes(server)) ?? [],
 | 
			
		||||
    [exclude, accountData]
 | 
			
		||||
    () => accountData?.getContent<InCinnyExploreServersContent>()?.servers ?? [],
 | 
			
		||||
    [accountData]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const addServer = useCallback(
 | 
			
		||||
    async (server: string) => {
 | 
			
		||||
      if (userAddedServers.indexOf(server) === -1) {
 | 
			
		||||
        // @ts-expect-error Custom account data event
 | 
			
		||||
        await mx.setAccountData(AccountDataEvent.CinnyExplore, {
 | 
			
		||||
          servers: [...userAddedServers, server],
 | 
			
		||||
        });
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +33,7 @@ export const useExploreServers = (
 | 
			
		|||
 | 
			
		||||
  const removeServer = useCallback(
 | 
			
		||||
    async (server: string) => {
 | 
			
		||||
      // @ts-expect-error Custom account data event
 | 
			
		||||
      await mx.setAccountData(AccountDataEvent.CinnyExplore, {
 | 
			
		||||
        servers: userAddedServers.filter((addedServer) => server !== addedServer),
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ import {
 | 
			
		|||
} from '../../../components/nav';
 | 
			
		||||
import { getExploreFeaturedPath, getExploreServerPath } from '../../pathUtils';
 | 
			
		||||
import {
 | 
			
		||||
  useExploreFeaturedRooms,
 | 
			
		||||
  useExploreFeaturedSelected,
 | 
			
		||||
  useExploreServer,
 | 
			
		||||
} from '../../../hooks/router/useExploreSelected';
 | 
			
		||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
 | 
			
		||||
| 
						 | 
				
			
			@ -44,21 +44,18 @@ import { stopPropagation } from '../../../utils/keyboard';
 | 
			
		|||
import { useExploreServers } from '../../../hooks/useExploreServers';
 | 
			
		||||
import { useAlive } from '../../../hooks/useAlive';
 | 
			
		||||
import { useClientConfig } from '../../../hooks/useClientConfig';
 | 
			
		||||
import { UseStateProvider } from '../../../components/UseStateProvider';
 | 
			
		||||
 | 
			
		||||
type AddExploreServerPromptProps = {
 | 
			
		||||
  onSubmit: (server: string, save: boolean) => Promise<void>;
 | 
			
		||||
  header: ReactNode;
 | 
			
		||||
  children: ReactNode;
 | 
			
		||||
  selected?: boolean;
 | 
			
		||||
  open: boolean;
 | 
			
		||||
  requestClose: () => void;
 | 
			
		||||
};
 | 
			
		||||
export function AddExploreServerPrompt({
 | 
			
		||||
  onSubmit,
 | 
			
		||||
  header,
 | 
			
		||||
  children,
 | 
			
		||||
  selected = false,
 | 
			
		||||
  open,
 | 
			
		||||
  requestClose,
 | 
			
		||||
}: AddExploreServerPromptProps) {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [dialog, setDialog] = useState(false);
 | 
			
		||||
  const alive = useAlive();
 | 
			
		||||
  const serverInputRef = useRef<HTMLInputElement>(null);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,13 +71,12 @@ export function AddExploreServerPrompt({
 | 
			
		|||
      const server = getInputServer();
 | 
			
		||||
      if (!server) return;
 | 
			
		||||
 | 
			
		||||
      await mx.publicRooms({ server, limit: 1 });
 | 
			
		||||
      await onSubmit(server, save);
 | 
			
		||||
      if (alive()) {
 | 
			
		||||
        setDialog(false);
 | 
			
		||||
        requestClose();
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    [alive, onSubmit, mx]
 | 
			
		||||
    [onSubmit, alive, requestClose]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const [viewState, handleView] = useAsyncCallback(() => submit(false));
 | 
			
		||||
| 
						 | 
				
			
			@ -89,113 +85,91 @@ export function AddExploreServerPrompt({
 | 
			
		|||
    viewState.status === AsyncStatus.Loading || saveViewState.status === AsyncStatus.Loading;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <Overlay open={dialog} backdrop={<OverlayBackdrop />}>
 | 
			
		||||
        <OverlayCenter>
 | 
			
		||||
          <FocusTrap
 | 
			
		||||
            focusTrapOptions={{
 | 
			
		||||
              initialFocus: false,
 | 
			
		||||
              clickOutsideDeactivates: true,
 | 
			
		||||
              onDeactivate: () => setDialog(false),
 | 
			
		||||
              escapeDeactivates: stopPropagation,
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            <Dialog variant="Surface">
 | 
			
		||||
              <Header
 | 
			
		||||
                style={{
 | 
			
		||||
                  padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
 | 
			
		||||
                  borderBottomWidth: config.borderWidth.B300,
 | 
			
		||||
                }}
 | 
			
		||||
                variant="Surface"
 | 
			
		||||
                size="500"
 | 
			
		||||
              >
 | 
			
		||||
                <Box grow="Yes">{header}</Box>
 | 
			
		||||
                <IconButton size="300" onClick={() => setDialog(false)} radii="300">
 | 
			
		||||
                  <Icon src={Icons.Cross} />
 | 
			
		||||
                </IconButton>
 | 
			
		||||
              </Header>
 | 
			
		||||
              <Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
 | 
			
		||||
                <Text priority="400">Add server name to explore public communities.</Text>
 | 
			
		||||
                <Box direction="Column" gap="100">
 | 
			
		||||
                  <Text size="L400">Server Name</Text>
 | 
			
		||||
                  <Input ref={serverInputRef} name="serverInput" variant="Background" required />
 | 
			
		||||
                  {viewState.status === AsyncStatus.Error && (
 | 
			
		||||
                    <Text style={{ color: color.Critical.Main }} size="T300">
 | 
			
		||||
                      Failed to load public rooms. Please try again.
 | 
			
		||||
                    </Text>
 | 
			
		||||
                  )}
 | 
			
		||||
                </Box>
 | 
			
		||||
                <Box direction="Column" gap="200">
 | 
			
		||||
                  <Button
 | 
			
		||||
                    type="submit"
 | 
			
		||||
                    onClick={handleView}
 | 
			
		||||
                    variant="Secondary"
 | 
			
		||||
                    fill="Soft"
 | 
			
		||||
                    before={
 | 
			
		||||
                      viewState.status === AsyncStatus.Loading && (
 | 
			
		||||
                        <Spinner fill="Solid" variant="Secondary" size="200" />
 | 
			
		||||
                      )
 | 
			
		||||
                    }
 | 
			
		||||
                    disabled={busy}
 | 
			
		||||
                  >
 | 
			
		||||
                    <Text size="B400">View</Text>
 | 
			
		||||
                  </Button>
 | 
			
		||||
                  <Button
 | 
			
		||||
                    type="submit"
 | 
			
		||||
                    onClick={handleSaveView}
 | 
			
		||||
                    variant="Primary"
 | 
			
		||||
                    fill="Soft"
 | 
			
		||||
                    before={
 | 
			
		||||
                      saveViewState.status === AsyncStatus.Loading && (
 | 
			
		||||
                        <Spinner fill="Solid" variant="Secondary" size="200" />
 | 
			
		||||
                      )
 | 
			
		||||
                    }
 | 
			
		||||
                    disabled={busy}
 | 
			
		||||
                  >
 | 
			
		||||
                    <Text size="B400">Save & View</Text>
 | 
			
		||||
                  </Button>
 | 
			
		||||
                </Box>
 | 
			
		||||
    <Overlay open={open} backdrop={<OverlayBackdrop />}>
 | 
			
		||||
      <OverlayCenter>
 | 
			
		||||
        <FocusTrap
 | 
			
		||||
          focusTrapOptions={{
 | 
			
		||||
            initialFocus: false,
 | 
			
		||||
            clickOutsideDeactivates: true,
 | 
			
		||||
            onDeactivate: requestClose,
 | 
			
		||||
            escapeDeactivates: stopPropagation,
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <Dialog variant="Surface">
 | 
			
		||||
            <Header
 | 
			
		||||
              style={{
 | 
			
		||||
                padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
 | 
			
		||||
                borderBottomWidth: config.borderWidth.B300,
 | 
			
		||||
              }}
 | 
			
		||||
              variant="Surface"
 | 
			
		||||
              size="500"
 | 
			
		||||
            >
 | 
			
		||||
              <Box grow="Yes">
 | 
			
		||||
                <Text size="H4">Add Server</Text>
 | 
			
		||||
              </Box>
 | 
			
		||||
            </Dialog>
 | 
			
		||||
          </FocusTrap>
 | 
			
		||||
        </OverlayCenter>
 | 
			
		||||
      </Overlay>
 | 
			
		||||
      <NavItem variant="Background" aria-selected={selected}>
 | 
			
		||||
        <NavButton onClick={() => setDialog(true)}>
 | 
			
		||||
          <NavItemContent>{children}</NavItemContent>
 | 
			
		||||
        </NavButton>
 | 
			
		||||
      </NavItem>
 | 
			
		||||
    </>
 | 
			
		||||
              <IconButton size="300" onClick={requestClose} radii="300">
 | 
			
		||||
                <Icon src={Icons.Cross} />
 | 
			
		||||
              </IconButton>
 | 
			
		||||
            </Header>
 | 
			
		||||
            <Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
 | 
			
		||||
              <Text priority="400">Add server name to explore public communities.</Text>
 | 
			
		||||
              <Box direction="Column" gap="100">
 | 
			
		||||
                <Text size="L400">Server Name</Text>
 | 
			
		||||
                <Input ref={serverInputRef} name="serverInput" variant="Background" required />
 | 
			
		||||
                {viewState.status === AsyncStatus.Error && (
 | 
			
		||||
                  <Text style={{ color: color.Critical.Main }} size="T300">
 | 
			
		||||
                    Failed to load public rooms. Please try again.
 | 
			
		||||
                  </Text>
 | 
			
		||||
                )}
 | 
			
		||||
              </Box>
 | 
			
		||||
              <Box direction="Column" gap="200">
 | 
			
		||||
                <Button
 | 
			
		||||
                  type="submit"
 | 
			
		||||
                  onClick={handleView}
 | 
			
		||||
                  variant="Primary"
 | 
			
		||||
                  fill="Soft"
 | 
			
		||||
                  before={
 | 
			
		||||
                    viewState.status === AsyncStatus.Loading && (
 | 
			
		||||
                      <Spinner fill="Soft" variant="Secondary" size="200" />
 | 
			
		||||
                    )
 | 
			
		||||
                  }
 | 
			
		||||
                  disabled={busy}
 | 
			
		||||
                >
 | 
			
		||||
                  <Text size="B400">View</Text>
 | 
			
		||||
                </Button>
 | 
			
		||||
                <Button
 | 
			
		||||
                  type="submit"
 | 
			
		||||
                  onClick={handleSaveView}
 | 
			
		||||
                  variant="Primary"
 | 
			
		||||
                  fill="Solid"
 | 
			
		||||
                  before={
 | 
			
		||||
                    saveViewState.status === AsyncStatus.Loading && (
 | 
			
		||||
                      <Spinner fill="Solid" variant="Secondary" size="200" />
 | 
			
		||||
                    )
 | 
			
		||||
                  }
 | 
			
		||||
                  disabled={busy}
 | 
			
		||||
                >
 | 
			
		||||
                  <Text size="B400">Save & View</Text>
 | 
			
		||||
                </Button>
 | 
			
		||||
              </Box>
 | 
			
		||||
            </Box>
 | 
			
		||||
          </Dialog>
 | 
			
		||||
        </FocusTrap>
 | 
			
		||||
      </OverlayCenter>
 | 
			
		||||
    </Overlay>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ExploreServerNavItemAction = {
 | 
			
		||||
  onClick: () => Promise<void>;
 | 
			
		||||
  icon: IconSrc;
 | 
			
		||||
  alwaysVisible: boolean;
 | 
			
		||||
};
 | 
			
		||||
type ExploreServerNavItemProps = {
 | 
			
		||||
  server: string;
 | 
			
		||||
  selected: boolean;
 | 
			
		||||
  icon: IconSrc;
 | 
			
		||||
  action?: ExploreServerNavItemAction;
 | 
			
		||||
  after?: (hover: boolean) => ReactNode;
 | 
			
		||||
};
 | 
			
		||||
export function ExploreServerNavItem({
 | 
			
		||||
  server,
 | 
			
		||||
  selected,
 | 
			
		||||
  icon,
 | 
			
		||||
  action,
 | 
			
		||||
}: ExploreServerNavItemProps) {
 | 
			
		||||
export function ExploreServerNavItem({ server, selected, icon, after }: ExploreServerNavItemProps) {
 | 
			
		||||
  const [hover, setHover] = useState(false);
 | 
			
		||||
  const { hoverProps } = useHover({ onHoverChange: setHover });
 | 
			
		||||
  const { focusWithinProps } = useFocusWithin({ onFocusWithinChange: setHover });
 | 
			
		||||
  const [actionState, actionCallback] = useAsyncCallback(
 | 
			
		||||
    useCallback(async () => {
 | 
			
		||||
      await action?.onClick();
 | 
			
		||||
    }, [action])
 | 
			
		||||
  );
 | 
			
		||||
  const actionInProgress =
 | 
			
		||||
    actionState.status === AsyncStatus.Loading || actionState.status === AsyncStatus.Success;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <NavItem
 | 
			
		||||
| 
						 | 
				
			
			@ -219,7 +193,7 @@ export function ExploreServerNavItem({
 | 
			
		|||
          </Box>
 | 
			
		||||
        </NavItemContent>
 | 
			
		||||
      </NavLink>
 | 
			
		||||
      {action !== undefined && (hover || actionInProgress || action.alwaysVisible) && (
 | 
			
		||||
      {/* {action !== undefined && (hover || actionInProgress || action.alwaysVisible) && (
 | 
			
		||||
        <NavItemOptions>
 | 
			
		||||
          <IconButton
 | 
			
		||||
            onClick={actionCallback}
 | 
			
		||||
| 
						 | 
				
			
			@ -236,7 +210,8 @@ export function ExploreServerNavItem({
 | 
			
		|||
            )}
 | 
			
		||||
          </IconButton>
 | 
			
		||||
        </NavItemOptions>
 | 
			
		||||
      )}
 | 
			
		||||
      )} */}
 | 
			
		||||
      {after && <NavItemOptions>{after(hover)}</NavItemOptions>}
 | 
			
		||||
    </NavItem>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -253,10 +228,10 @@ export function Explore() {
 | 
			
		|||
      clientConfig.featuredCommunities?.servers?.filter((server) => server !== userServer) ?? [],
 | 
			
		||||
    [clientConfig, userServer]
 | 
			
		||||
  );
 | 
			
		||||
  const [exploreServers, addServer, removeServer] = useExploreServers(featuredServers);
 | 
			
		||||
  const [exploreServers, addServer, removeServer] = useExploreServers();
 | 
			
		||||
 | 
			
		||||
  const selectedServer = useExploreServer();
 | 
			
		||||
  const exploringFeaturedRooms = useExploreFeaturedRooms();
 | 
			
		||||
  const exploringFeaturedRooms = useExploreFeaturedSelected();
 | 
			
		||||
  const exploringUnlistedServer = useMemo(
 | 
			
		||||
    () =>
 | 
			
		||||
      !(
 | 
			
		||||
| 
						 | 
				
			
			@ -268,21 +243,25 @@ export function Explore() {
 | 
			
		|||
    [exploreServers, selectedServer, userServer, featuredServers]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const addServerCallback = useCallback(
 | 
			
		||||
    async (server: string, save: boolean) => {
 | 
			
		||||
      if (save && server !== userServer && !featuredServers.includes(server) && selectedServer) {
 | 
			
		||||
        await addServer(server);
 | 
			
		||||
      }
 | 
			
		||||
      navigate(getExploreServerPath(server));
 | 
			
		||||
    },
 | 
			
		||||
    [addServer, navigate, userServer, featuredServers, selectedServer]
 | 
			
		||||
  const [addServerState, addServerCallback] = useAsyncCallback(
 | 
			
		||||
    useCallback(
 | 
			
		||||
      async (server: string, save: boolean) => {
 | 
			
		||||
        if (save && server !== userServer && !featuredServers.includes(server) && selectedServer) {
 | 
			
		||||
          await addServer(server);
 | 
			
		||||
        }
 | 
			
		||||
        navigate(getExploreServerPath(server));
 | 
			
		||||
      },
 | 
			
		||||
      [addServer, navigate, userServer, featuredServers, selectedServer]
 | 
			
		||||
    )
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const removeServerCallback = useCallback(
 | 
			
		||||
    async (server: string) => {
 | 
			
		||||
      await removeServer(server);
 | 
			
		||||
    },
 | 
			
		||||
    [removeServer]
 | 
			
		||||
  const [removeServerState, removeServerCallback] = useAsyncCallback(
 | 
			
		||||
    useCallback(
 | 
			
		||||
      async (server: string) => {
 | 
			
		||||
        await removeServer(server);
 | 
			
		||||
      },
 | 
			
		||||
      [removeServer]
 | 
			
		||||
    )
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			@ -320,19 +299,7 @@ export function Explore() {
 | 
			
		|||
              <ExploreServerNavItem
 | 
			
		||||
                server={userServer}
 | 
			
		||||
                selected={userServer === selectedServer}
 | 
			
		||||
                icon={Icons.Home}
 | 
			
		||||
              />
 | 
			
		||||
            )}
 | 
			
		||||
            {exploringUnlistedServer && selectedServer !== undefined && (
 | 
			
		||||
              <ExploreServerNavItem
 | 
			
		||||
                server={selectedServer}
 | 
			
		||||
                selected
 | 
			
		||||
                icon={Icons.Server}
 | 
			
		||||
                action={{
 | 
			
		||||
                  alwaysVisible: true,
 | 
			
		||||
                  icon: Icons.Plus,
 | 
			
		||||
                  onClick: () => addServerCallback(selectedServer, true),
 | 
			
		||||
                }}
 | 
			
		||||
              />
 | 
			
		||||
            )}
 | 
			
		||||
          </NavCategory>
 | 
			
		||||
| 
						 | 
				
			
			@ -350,34 +317,94 @@ export function Explore() {
 | 
			
		|||
                icon={Icons.Server}
 | 
			
		||||
              />
 | 
			
		||||
            ))}
 | 
			
		||||
            {exploreServers.map((server) => (
 | 
			
		||||
            {exploreServers
 | 
			
		||||
              .filter((server) => !featuredServers.includes(server))
 | 
			
		||||
              .map((server) => (
 | 
			
		||||
                <ExploreServerNavItem
 | 
			
		||||
                  key={server}
 | 
			
		||||
                  server={server}
 | 
			
		||||
                  selected={server === selectedServer}
 | 
			
		||||
                  icon={Icons.Server}
 | 
			
		||||
                  after={(hover) => {
 | 
			
		||||
                    const busy = removeServerState.status === AsyncStatus.Loading;
 | 
			
		||||
 | 
			
		||||
                    if (!(hover || busy)) {
 | 
			
		||||
                      return undefined;
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
                    return (
 | 
			
		||||
                      <IconButton
 | 
			
		||||
                        onClick={() => removeServerCallback(server)}
 | 
			
		||||
                        variant="Background"
 | 
			
		||||
                        fill="None"
 | 
			
		||||
                        size="300"
 | 
			
		||||
                        radii="300"
 | 
			
		||||
                        disabled={busy}
 | 
			
		||||
                      >
 | 
			
		||||
                        {busy ? (
 | 
			
		||||
                          <Spinner variant="Secondary" fill="Solid" size="200" />
 | 
			
		||||
                        ) : (
 | 
			
		||||
                          <Icon size="50" src={Icons.Minus} />
 | 
			
		||||
                        )}
 | 
			
		||||
                      </IconButton>
 | 
			
		||||
                    );
 | 
			
		||||
                  }}
 | 
			
		||||
                />
 | 
			
		||||
              ))}
 | 
			
		||||
            {exploringUnlistedServer && selectedServer !== undefined && (
 | 
			
		||||
              <ExploreServerNavItem
 | 
			
		||||
                key={server}
 | 
			
		||||
                server={server}
 | 
			
		||||
                selected={server === selectedServer}
 | 
			
		||||
                server={selectedServer}
 | 
			
		||||
                selected
 | 
			
		||||
                icon={Icons.Server}
 | 
			
		||||
                action={{
 | 
			
		||||
                  alwaysVisible: false,
 | 
			
		||||
                  icon: Icons.Minus,
 | 
			
		||||
                  onClick: () => removeServerCallback(server),
 | 
			
		||||
                after={() => {
 | 
			
		||||
                  const busy = addServerState.status === AsyncStatus.Loading;
 | 
			
		||||
 | 
			
		||||
                  return (
 | 
			
		||||
                    <IconButton
 | 
			
		||||
                      onClick={() => addServerCallback(selectedServer, true)}
 | 
			
		||||
                      variant="Background"
 | 
			
		||||
                      fill="None"
 | 
			
		||||
                      size="300"
 | 
			
		||||
                      radii="300"
 | 
			
		||||
                      disabled={busy}
 | 
			
		||||
                    >
 | 
			
		||||
                      {busy ? (
 | 
			
		||||
                        <Spinner variant="Secondary" fill="Solid" size="200" />
 | 
			
		||||
                      ) : (
 | 
			
		||||
                        <Icon size="50" src={Icons.Bookmark} />
 | 
			
		||||
                      )}
 | 
			
		||||
                    </IconButton>
 | 
			
		||||
                  );
 | 
			
		||||
                }}
 | 
			
		||||
              />
 | 
			
		||||
            ))}
 | 
			
		||||
            <AddExploreServerPrompt
 | 
			
		||||
              onSubmit={addServerCallback}
 | 
			
		||||
              header={<Text size="H4">Add Server</Text>}
 | 
			
		||||
            >
 | 
			
		||||
              <Box as="span" grow="Yes" alignItems="Center" gap="200">
 | 
			
		||||
                <Avatar size="200" radii="400">
 | 
			
		||||
                  <Icon src={Icons.Plus} size="100" />
 | 
			
		||||
                </Avatar>
 | 
			
		||||
                <Box as="span" grow="Yes">
 | 
			
		||||
                  <Text as="span" size="Inherit" truncate>
 | 
			
		||||
                    Add Server
 | 
			
		||||
                  </Text>
 | 
			
		||||
                </Box>
 | 
			
		||||
              </Box>
 | 
			
		||||
            </AddExploreServerPrompt>
 | 
			
		||||
            )}
 | 
			
		||||
            <UseStateProvider initial={false}>
 | 
			
		||||
              {(dialogOpen, setDialogOpen) => (
 | 
			
		||||
                <>
 | 
			
		||||
                  <NavItem variant="Background">
 | 
			
		||||
                    <NavButton onClick={() => setDialogOpen(true)}>
 | 
			
		||||
                      <NavItemContent>
 | 
			
		||||
                        <Box as="span" grow="Yes" alignItems="Center" gap="200">
 | 
			
		||||
                          <Avatar size="200" radii="400">
 | 
			
		||||
                            <Icon src={Icons.Plus} size="100" />
 | 
			
		||||
                          </Avatar>
 | 
			
		||||
                          <Box as="span" grow="Yes">
 | 
			
		||||
                            <Text as="span" size="Inherit" truncate>
 | 
			
		||||
                              Add Server
 | 
			
		||||
                            </Text>
 | 
			
		||||
                          </Box>
 | 
			
		||||
                        </Box>
 | 
			
		||||
                      </NavItemContent>
 | 
			
		||||
                    </NavButton>
 | 
			
		||||
                  </NavItem>
 | 
			
		||||
                  <AddExploreServerPrompt
 | 
			
		||||
                    onSubmit={addServerCallback}
 | 
			
		||||
                    open={dialogOpen}
 | 
			
		||||
                    requestClose={() => setDialogOpen(false)}
 | 
			
		||||
                  />
 | 
			
		||||
                </>
 | 
			
		||||
              )}
 | 
			
		||||
            </UseStateProvider>
 | 
			
		||||
          </NavCategory>
 | 
			
		||||
        </Box>
 | 
			
		||||
      </PageNavContent>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue