style(create-chat): Dawn grouped form with a mono server and one native layout without the hero
This commit is contained in:
parent
4c6f662939
commit
7ea273eca8
3 changed files with 70 additions and 124 deletions
|
|
@ -8,11 +8,11 @@ type Props = {
|
|||
onClose: () => void;
|
||||
};
|
||||
|
||||
// Thin shell around the shared `CreateChat` form. The legacy
|
||||
// `/direct/_create` route renders the same component with a Page/
|
||||
// PageHero shell; here we only feed it the `onClose` callback and the
|
||||
// tighter `gap='400'` rhythm so the form fits comfortably under the
|
||||
// header.
|
||||
// Thin shell around the shared `CreateChat` form. This curtain is the
|
||||
// canonical native new-chat surface; the `/direct/_create` route renders
|
||||
// the same grouped block under a back-chevron PageHeader. Here we only
|
||||
// feed it the `onClose` callback and the tighter `gap='400'` rhythm so the
|
||||
// form fits comfortably under the header.
|
||||
export function InlineNewChatForm({ onClose }: Props) {
|
||||
return <CreateChat gap="400" onCreated={onClose} />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,11 @@
|
|||
import {
|
||||
Box,
|
||||
Button,
|
||||
color,
|
||||
config,
|
||||
Icon,
|
||||
Icons,
|
||||
Input,
|
||||
Spinner,
|
||||
Switch,
|
||||
Text,
|
||||
toRem,
|
||||
} from 'folds';
|
||||
import { Box, Button, color, Icon, Icons, Input, Spinner, Switch, Text, toRem } from 'folds';
|
||||
import React, { FormEventHandler, useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ICreateRoomStateEvent, MatrixError, Preset, Visibility } from 'matrix-js-sdk';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { SettingTile } from '../../components/setting-tile';
|
||||
import { SequenceCard } from '../../components/sequence-card';
|
||||
import { SettingsSection } from '../settings/SettingsSection';
|
||||
import { Mono, SectionLabel } from '../settings/styles.css';
|
||||
import {
|
||||
addRoomIdToMDirect,
|
||||
getDMRoomFor,
|
||||
|
|
@ -136,17 +125,25 @@ export function CreateChat({ defaultUserId, onCreated, gap = '500' }: CreateChat
|
|||
|
||||
return (
|
||||
<Box as="form" onSubmit={handleSubmit} grow="Yes" direction="Column" gap={gap}>
|
||||
<Box direction="Column" gap="100">
|
||||
<Box direction="Column" gap="200">
|
||||
<Text as="span" className={SectionLabel}>
|
||||
{t('Direct.address')}
|
||||
</Text>
|
||||
<Box direction="Row" wrap="Wrap" gap="200">
|
||||
<Box grow="Yes" style={{ minWidth: toRem(120) }} direction="Column" gap="100">
|
||||
<Text size="L400">{t('Direct.username')}</Text>
|
||||
<Input
|
||||
defaultValue={defaultUsername}
|
||||
placeholder={t('Direct.username_placeholder')}
|
||||
name="usernameInput"
|
||||
variant="SurfaceVariant"
|
||||
variant="Background"
|
||||
size="500"
|
||||
radii="400"
|
||||
outlined
|
||||
before={
|
||||
<Text as="span" size="B500" className={Mono} style={{ opacity: 0.5 }}>
|
||||
@
|
||||
</Text>
|
||||
}
|
||||
required
|
||||
autoFocus
|
||||
autoComplete="off"
|
||||
|
|
@ -154,16 +151,17 @@ export function CreateChat({ defaultUserId, onCreated, gap = '500' }: CreateChat
|
|||
/>
|
||||
</Box>
|
||||
<Box shrink="No" style={{ minWidth: toRem(150) }} direction="Column" gap="100">
|
||||
<Text size="L400">{t('Direct.server')}</Text>
|
||||
<Input
|
||||
defaultValue={
|
||||
defaultServer && defaultServer !== userServer ? defaultServer : undefined
|
||||
}
|
||||
placeholder={userServer}
|
||||
name="serverInput"
|
||||
variant="SurfaceVariant"
|
||||
variant="Background"
|
||||
size="500"
|
||||
radii="400"
|
||||
outlined
|
||||
className={Mono}
|
||||
autoComplete="off"
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
|
@ -171,50 +169,40 @@ export function CreateChat({ defaultUserId, onCreated, gap = '500' }: CreateChat
|
|||
</Box>
|
||||
{invalidUserId && (
|
||||
<Box style={{ color: color.Critical.Main }} alignItems="Center" gap="100">
|
||||
<Icon src={Icons.Warning} filled size="50" />
|
||||
<Icon src={Icons.Warning} size="50" />
|
||||
<Text size="T200" style={{ color: color.Critical.Main }}>
|
||||
<b>{t('Direct.invalid_user_id')}</b>
|
||||
{t('Direct.invalid_user_id')}
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
<Box shrink="No" direction="Column" gap="100">
|
||||
<Text size="L400">{t('Direct.options')}</Text>
|
||||
<SequenceCard
|
||||
style={{ padding: config.space.S300 }}
|
||||
variant="SurfaceVariant"
|
||||
direction="Column"
|
||||
gap="500"
|
||||
>
|
||||
<SettingTile
|
||||
title={t('Direct.e2e_encryption')}
|
||||
description={t('Direct.e2e_encryption_desc')}
|
||||
after={
|
||||
<Switch
|
||||
variant="Primary"
|
||||
value={encryption}
|
||||
onChange={setEncryption}
|
||||
disabled={disabled}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</SequenceCard>
|
||||
</Box>
|
||||
<SettingsSection label={t('Direct.options')}>
|
||||
<SettingTile
|
||||
title={t('Direct.e2e_encryption')}
|
||||
description={t('Direct.e2e_encryption_desc')}
|
||||
after={
|
||||
<Switch
|
||||
variant="Primary"
|
||||
value={encryption}
|
||||
onChange={setEncryption}
|
||||
disabled={disabled}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</SettingsSection>
|
||||
{error && (
|
||||
<Box style={{ color: color.Critical.Main }} alignItems="Center" gap="200">
|
||||
<Icon src={Icons.Warning} filled size="100" />
|
||||
<Icon src={Icons.Warning} size="100" />
|
||||
<Text size="T300" style={{ color: color.Critical.Main }}>
|
||||
<b>
|
||||
{(() => {
|
||||
if (error instanceof MatrixError && error.name === ErrorCode.M_LIMIT_EXCEEDED) {
|
||||
const ra = error.data?.retry_after_ms;
|
||||
return t('Direct.rate_limited', {
|
||||
minutes: millisecondsToMinutes(typeof ra === 'number' ? ra : 0),
|
||||
});
|
||||
}
|
||||
return error.message;
|
||||
})()}
|
||||
</b>
|
||||
{(() => {
|
||||
if (error instanceof MatrixError && error.name === ErrorCode.M_LIMIT_EXCEEDED) {
|
||||
const ra = error.data?.retry_after_ms;
|
||||
return t('Direct.rate_limited', {
|
||||
minutes: millisecondsToMinutes(typeof ra === 'number' ? ra : 0),
|
||||
});
|
||||
}
|
||||
return error.message;
|
||||
})()}
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -7,24 +7,13 @@ import { getDirectCreateSearchParams } from '../../pathSearchParam';
|
|||
import { getDirectRoomPath } from '../../pathUtils';
|
||||
import { getDMRoomFor } from '../../../utils/matrix';
|
||||
import { useDirectRooms } from './useDirectRooms';
|
||||
import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
|
||||
import {
|
||||
Page,
|
||||
PageContent,
|
||||
PageContentCenter,
|
||||
PageHeader,
|
||||
PageHero,
|
||||
PageHeroSection,
|
||||
} from '../../../components/page';
|
||||
import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page';
|
||||
import { BackRouteHandler } from '../../../components/BackRouteHandler';
|
||||
import { CreateChat } from '../../../features/create-chat';
|
||||
import { isNativePlatform } from '../../../utils/capacitor';
|
||||
|
||||
export function DirectCreate() {
|
||||
const { t } = useTranslation();
|
||||
const mx = useMatrixClient();
|
||||
const screenSize = useScreenSizeContext();
|
||||
const native = isNativePlatform();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
|
|
@ -41,64 +30,33 @@ export function DirectCreate() {
|
|||
}
|
||||
}, [mx, navigate, directs, userId]);
|
||||
|
||||
// Native phone (Capacitor + Mobile screen): compact layout — title goes into
|
||||
// the back-arrow header, form sits directly below with light padding, no
|
||||
// oversized hero whitespace. The on-screen keyboard otherwise pushed the
|
||||
// centered hero layout into a visibly long scrollable area. Native tablets,
|
||||
// desktop, and web (any size) keep the original hero-section layout.
|
||||
if (native && screenSize === ScreenSize.Mobile) {
|
||||
return (
|
||||
<Page>
|
||||
<PageHeader balance outlined={false}>
|
||||
<Box grow="Yes" alignItems="Center" gap="200">
|
||||
<BackRouteHandler>
|
||||
{(onBack) => (
|
||||
<IconButton onClick={onBack}>
|
||||
<Icon src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
)}
|
||||
</BackRouteHandler>
|
||||
<Text size="H4" truncate>
|
||||
{t('Direct.create_chat')}
|
||||
</Text>
|
||||
</Box>
|
||||
</PageHeader>
|
||||
<Box grow="Yes">
|
||||
<Scroll size="0" hideTrack visibility="Hover">
|
||||
<Box style={{ padding: config.space.S400 }}>
|
||||
<CreateChat defaultUserId={userId} />
|
||||
</Box>
|
||||
</Scroll>
|
||||
</Box>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
// One Dawn layout for every size: a left-aligned back-chevron header over the
|
||||
// grouped CreateChat block in a padded Scroll. No centered hero — the curtain
|
||||
// (InlineNewChatForm) is the canonical native new-chat surface, and the
|
||||
// keyboard no longer fights an oversized hero on short native viewports.
|
||||
return (
|
||||
<Page>
|
||||
{screenSize === ScreenSize.Mobile && (
|
||||
<PageHeader balance outlined={false}>
|
||||
<Box grow="Yes" alignItems="Center" gap="200">
|
||||
<BackRouteHandler>
|
||||
{(onBack) => (
|
||||
<IconButton onClick={onBack}>
|
||||
<Icon src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
)}
|
||||
</BackRouteHandler>
|
||||
</Box>
|
||||
</PageHeader>
|
||||
)}
|
||||
<PageHeader balance outlined={false}>
|
||||
<Box grow="Yes" alignItems="Center" gap="200">
|
||||
<BackRouteHandler>
|
||||
{(onBack) => (
|
||||
<IconButton onClick={onBack}>
|
||||
<Icon src={Icons.ArrowLeft} />
|
||||
</IconButton>
|
||||
)}
|
||||
</BackRouteHandler>
|
||||
<Text size="H4" truncate>
|
||||
{t('Direct.create_chat')}
|
||||
</Text>
|
||||
</Box>
|
||||
</PageHeader>
|
||||
<Box grow="Yes">
|
||||
<Scroll hideTrack visibility="Hover">
|
||||
<PageContent>
|
||||
<PageContentCenter>
|
||||
<PageHeroSection>
|
||||
<Box direction="Column" gap="700">
|
||||
<PageHero title={t('Direct.create_chat')} />
|
||||
<CreateChat defaultUserId={userId} />
|
||||
</Box>
|
||||
</PageHeroSection>
|
||||
<Box style={{ paddingTop: config.space.S200 }}>
|
||||
<CreateChat defaultUserId={userId} />
|
||||
</Box>
|
||||
</PageContentCenter>
|
||||
</PageContent>
|
||||
</Scroll>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue