feat(bots): M1 wire Direct segment to /bots/ placeholder and rename label to Роботы

This commit is contained in:
heaven 2026-05-01 14:42:00 +03:00
parent 96085ba6a1
commit 357a2024f4
9 changed files with 84 additions and 23 deletions

View file

@ -370,7 +370,7 @@
"start_first_chat": "Start a chat",
"segment_dm": "DM",
"segment_channels": "Channels",
"segment_bots": "Bots",
"segment_bots": "Robots",
"segment_coming_soon": "Coming soon",
"self_row_label": "You",
"self_row_preview": "Settings & profile",
@ -917,5 +917,8 @@
"invite_body_no_room": "{{inviter}} invited you to a room",
"invite_body_no_inviter": "Invited you to {{roomName}}",
"invite_body_generic": "New invitation"
},
"Bots": {
"title": "Robots"
}
}

View file

@ -370,7 +370,7 @@
"start_first_chat": "Начать чат",
"segment_dm": "Личные",
"segment_channels": "Каналы",
"segment_bots": "Боты",
"segment_bots": "Роботы",
"segment_coming_soon": "Скоро",
"self_row_label": "Я",
"self_row_preview": "Настройки и профиль",
@ -921,5 +921,8 @@
"invite_body_no_room": "{{inviter}} приглашает вас в комнату",
"invite_body_no_inviter": "Приглашение в {{roomName}}",
"invite_body_generic": "Новое приглашение"
},
"Bots": {
"title": "Роботы"
}
}

View file

@ -1,7 +1,7 @@
import { ReactNode } from 'react';
import { useMatch } from 'react-router-dom';
import { ScreenSize, useScreenSizeContext } from '../hooks/useScreenSize';
import { DIRECT_PATH, EXPLORE_PATH, HOME_PATH, INBOX_PATH, SPACE_PATH } from './paths';
import { BOTS_PATH, DIRECT_PATH, EXPLORE_PATH, HOME_PATH, INBOX_PATH, SPACE_PATH } from './paths';
type MobileFriendlyClientNavProps = {
children: ReactNode;
@ -13,10 +13,11 @@ export function MobileFriendlyClientNav({ children }: MobileFriendlyClientNavPro
const spaceMatch = useMatch({ path: SPACE_PATH, caseSensitive: true, end: true });
const exploreMatch = useMatch({ path: EXPLORE_PATH, caseSensitive: true, end: true });
const inboxMatch = useMatch({ path: INBOX_PATH, caseSensitive: true, end: true });
const botsMatch = useMatch({ path: BOTS_PATH, caseSensitive: true, end: true });
if (
screenSize === ScreenSize.Mobile &&
!(homeMatch || directMatch || spaceMatch || exploreMatch || inboxMatch)
!(homeMatch || directMatch || spaceMatch || exploreMatch || inboxMatch || botsMatch)
) {
return null;
}

View file

@ -13,6 +13,7 @@ import {
import { ClientConfig } from '../hooks/useClientConfig';
import { AuthLayout, Login, Register, ResetPassword } from './auth';
import {
BOTS_PATH,
DIRECT_PATH,
EXPLORE_PATH,
HOME_PATH,
@ -50,6 +51,7 @@ import { getMxIdServer, isUserId } from '../utils/matrix';
import { ClientBindAtoms, ClientLayout, ClientRoot } from './client';
import { HomeRouteRoomProvider } from './client/home';
import { Direct, DirectCreate, DirectRouteRoomProvider } from './client/direct';
import { Bots } from './client/bots';
import { RouteSpaceProvider, Space, SpaceRouteRoomProvider, SpaceSearch } from './client/space';
import { Explore, FeaturedRooms, PublicRooms } from './client/explore';
import { Notifications, Inbox, Invites } from './client/inbox';
@ -243,6 +245,24 @@ export const createRouter = (clientConfig: ClientConfig, screenSize: ScreenSize)
}
/>
</Route>
{/* Bots reuses DirectStreamHeader segments. /bots/* is reserved before SPACE_PATH so deep URLs don't fall to /:spaceIdOrAlias/. Real bot list lands in M2. */}
<Route
path={BOTS_PATH}
element={
<PageRoot
nav={
<MobileFriendlyPageNav path={BOTS_PATH}>
<Bots />
</MobileFriendlyPageNav>
}
>
<Outlet />
</PageRoot>
}
>
{mobile ? null : <Route index element={<WelcomePage />} />}
</Route>
<Route path="/bots/*" element={<Navigate to={BOTS_PATH} replace />} />
<Route
path={SPACE_PATH}
element={

View file

@ -0,0 +1,28 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Icon, Icons, Text } from 'folds';
import { useNavToActivePathMapper } from '../../../hooks/useNavToActivePathMapper';
import { NavEmptyCenter, NavEmptyLayout } from '../../../components/nav';
import { PageNav } from '../../../components/page';
import { DirectStreamHeader } from '../direct/DirectStreamHeader';
export function Bots() {
const { t } = useTranslation();
useNavToActivePathMapper('bots');
return (
<PageNav size="500">
<DirectStreamHeader />
<NavEmptyCenter>
<NavEmptyLayout
icon={<Icon size="600" src={Icons.Bulb} />}
title={
<Text size="H5" align="Center">
{t('Bots.title')}
</Text>
}
/>
</NavEmptyCenter>
</PageNav>
);
}

View file

@ -0,0 +1 @@
export * from './Bots';

View file

@ -1,7 +1,10 @@
import React, { forwardRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useMatch, useNavigate } from 'react-router-dom';
import { Box, Text, Tooltip, TooltipProvider, color, toRem } from 'folds';
import { PageNavHeader } from '../../../components/page';
import { BOTS_PATH, DIRECT_PATH } from '../../paths';
import { isNativePlatform } from '../../../utils/capacitor';
type SegmentProps = {
active: boolean;
@ -39,12 +42,22 @@ const Segment = forwardRef<HTMLButtonElement, SegmentProps>(
export function DirectStreamHeader() {
const { t } = useTranslation();
const navigate = useNavigate();
const comingSoon = t('Direct.segment_coming_soon');
const directMatch = useMatch({ path: DIRECT_PATH, caseSensitive: true, end: false });
const botsMatch = useMatch({ path: BOTS_PATH, caseSensitive: true, end: false });
const navOpts = { replace: isNativePlatform() };
return (
<PageNavHeader>
<Box alignItems="Center" grow="Yes" gap="100">
<Segment active label={t('Direct.segment_dm')} />
<Segment
active={!!directMatch}
label={t('Direct.segment_dm')}
onClick={() => navigate(DIRECT_PATH, navOpts)}
/>
<TooltipProvider
delay={400}
position="Bottom"
@ -63,24 +76,11 @@ export function DirectStreamHeader() {
/>
)}
</TooltipProvider>
<TooltipProvider
delay={400}
position="Bottom"
tooltip={
<Tooltip>
<Text size="T200">{comingSoon}</Text>
</Tooltip>
}
>
{(triggerRef) => (
<Segment
ref={triggerRef as React.RefCallback<HTMLButtonElement>}
active={false}
disabled
label={t('Direct.segment_bots')}
/>
)}
</TooltipProvider>
<Segment
active={!!botsMatch}
label={t('Direct.segment_bots')}
onClick={() => navigate(BOTS_PATH, navOpts)}
/>
</Box>
</PageNavHeader>
);

View file

@ -1,5 +1,6 @@
import { generatePath, Path } from 'react-router-dom';
import {
BOTS_PATH,
DIRECT_CREATE_PATH,
DIRECT_PATH,
DIRECT_ROOM_PATH,
@ -158,3 +159,5 @@ export const getCreatePath = (): string => CREATE_PATH;
export const getInboxPath = (): string => INBOX_PATH;
export const getInboxNotificationsPath = (): string => INBOX_NOTIFICATIONS_PATH;
export const getInboxInvitesPath = (): string => INBOX_INVITES_PATH;
export const getBotsPath = (): string => BOTS_PATH;

View file

@ -85,6 +85,8 @@ export const CREATE_PATH = '/create';
export const USER_LINK_HOST = 'vojo.chat';
export const USER_LINK_PATH = '/u/:userIdOrLocalPart';
export const BOTS_PATH = '/bots/';
export const _NOTIFICATIONS_PATH = 'notifications/';
export const _INVITES_PATH = 'invites/';
export const INBOX_PATH = '/inbox/';