style(settings): replace the boxed setting cards with a flat edge-to-edge list parted by hairlines
This commit is contained in:
parent
390149d1f6
commit
587d117f96
5 changed files with 73 additions and 51 deletions
|
|
@ -17,8 +17,7 @@ import Linkify from 'linkify-react';
|
|||
import classNames from 'classnames';
|
||||
import { JoinRule, MatrixError } from 'matrix-js-sdk';
|
||||
import type { StateEvents } from 'matrix-js-sdk';
|
||||
import { SequenceCard } from '../../../components/sequence-card';
|
||||
import { SequenceCardStyle } from '../../room-settings/styles.css';
|
||||
import { SectionLabel, SettingRule } from '../../settings/styles.css';
|
||||
import { useRoom } from '../../../hooks/useRoom';
|
||||
import {
|
||||
useRoomAvatar,
|
||||
|
|
@ -298,14 +297,11 @@ export function RoomProfile({ permissions }: RoomProfileProps) {
|
|||
const handleCloseEdit = useCallback(() => setEdit(false), []);
|
||||
|
||||
return (
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="L400">{t('RoomSettings.profile')}</Text>
|
||||
<SequenceCard
|
||||
className={SequenceCardStyle}
|
||||
variant="SurfaceVariant"
|
||||
direction="Column"
|
||||
gap="400"
|
||||
>
|
||||
<Box direction="Column" gap="200">
|
||||
<Text as="span" className={SectionLabel}>
|
||||
{t('RoomSettings.profile')}
|
||||
</Text>
|
||||
<Box direction="Column" gap="400">
|
||||
{edit ? (
|
||||
<RoomProfileEdit
|
||||
canEditAvatar={canEditAvatar}
|
||||
|
|
@ -363,7 +359,8 @@ export function RoomProfile({ permissions }: RoomProfileProps) {
|
|||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</SequenceCard>
|
||||
</Box>
|
||||
<hr className={SettingRule} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||
import { SettingsSection } from '../../settings/SettingsSection';
|
||||
import { SectionLabel } from '../../settings/styles.css';
|
||||
import { usePowerLevels } from '../../../hooks/usePowerLevels';
|
||||
import { useRoom } from '../../../hooks/useRoom';
|
||||
import {
|
||||
|
|
@ -55,13 +56,17 @@ export function General({ requestClose }: GeneralProps) {
|
|||
<RoomEncryption permissions={permissions} />
|
||||
<RoomPublish permissions={permissions} />
|
||||
</SettingsSection>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="L400">{t('RoomSettings.addresses')}</Text>
|
||||
<Box direction="Column" gap="200">
|
||||
<Text as="span" className={SectionLabel}>
|
||||
{t('RoomSettings.addresses')}
|
||||
</Text>
|
||||
<RoomPublishedAddresses permissions={permissions} />
|
||||
<RoomLocalAddresses permissions={permissions} />
|
||||
</Box>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="L400">{t('RoomSettings.advanced_options')}</Text>
|
||||
<Box direction="Column" gap="200">
|
||||
<Text as="span" className={SectionLabel}>
|
||||
{t('RoomSettings.advanced_options')}
|
||||
</Text>
|
||||
<RoomUpgrade permissions={permissions} requestClose={requestClose} />
|
||||
</Box>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -1,39 +1,29 @@
|
|||
import React, { Children, ReactNode } from 'react';
|
||||
import { Box, Text } from 'folds';
|
||||
import { SequenceCard } from '../../components/sequence-card';
|
||||
import { ContainerColorVariants } from '../../styles/ContainerColor.css';
|
||||
import { SectionFootnote, SectionLabel, SettingRow } from './styles.css';
|
||||
import { SectionFootnote, SectionLabel, SettingFlatGroup, SettingFlatRow } from './styles.css';
|
||||
|
||||
type SettingsSectionProps = {
|
||||
// Uppercase muted heading above the panel. Omit for an unlabelled panel.
|
||||
// Uppercase muted heading above the list. Omit for an unlabelled section.
|
||||
label?: ReactNode;
|
||||
// Small caption under the label (rare — e.g. a privacy note).
|
||||
footnote?: ReactNode;
|
||||
// Surface tone for the rows. Default `Background` = the inset darker panel
|
||||
// (#0d0e11) on the SurfaceVariant page (#181a20).
|
||||
variant?: NonNullable<ContainerColorVariants>['variant'];
|
||||
// Each direct child becomes one row of the grouped panel. Falsy children
|
||||
// (conditional rows) are dropped so dividers/rounding stay correct.
|
||||
// Each direct child becomes one row of the flat list. Falsy children
|
||||
// (conditional rows) are dropped so the hairline dividers stay correct.
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* A Dawn grouped settings panel: an uppercase muted label over a single
|
||||
* outlined card whose rows are separated by hairline dividers (via
|
||||
* `SequenceCard`'s `mergeBorder` + first/last auto-rounding). Replaces the
|
||||
* stock-Cinny "one floating card per setting" pattern.
|
||||
* A Dawn flat settings list: an uppercase muted label over edge-to-edge rows
|
||||
* parted by hairline dividers — no card box or surface fill (iOS/Telegram
|
||||
* grouped-list feel). Replaces the stock-Cinny "floating outlined card per
|
||||
* setting" pattern.
|
||||
*/
|
||||
export function SettingsSection({
|
||||
label,
|
||||
footnote,
|
||||
variant = 'Background',
|
||||
children,
|
||||
}: SettingsSectionProps) {
|
||||
export function SettingsSection({ label, footnote, children }: SettingsSectionProps) {
|
||||
const rows = Children.toArray(children).filter(Boolean);
|
||||
if (rows.length === 0) return null;
|
||||
|
||||
return (
|
||||
<Box direction="Column" gap="200">
|
||||
<Box direction="Column" gap="100">
|
||||
{label && (
|
||||
<Box direction="Column">
|
||||
<Text as="span" className={SectionLabel}>
|
||||
|
|
@ -46,23 +36,19 @@ export function SettingsSection({
|
|||
)}
|
||||
</Box>
|
||||
)}
|
||||
<Box direction="Column">
|
||||
<div className={SettingFlatGroup}>
|
||||
{rows.map((row, index) => (
|
||||
<SequenceCard
|
||||
<div
|
||||
// Rows are positional and have no stable id; index key is correct
|
||||
// here — the list never reorders, only conditionally includes rows.
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={index}
|
||||
variant={variant}
|
||||
outlined
|
||||
mergeBorder
|
||||
direction="Column"
|
||||
className={SettingRow}
|
||||
className={SettingFlatRow}
|
||||
>
|
||||
{row}
|
||||
</SequenceCard>
|
||||
</div>
|
||||
))}
|
||||
</Box>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ import { color, config, toRem } from 'folds';
|
|||
// Dawn canon's "КОМАНДЫ" / "УЧАСТНИКИ · 28" panel headers (sans, not mono).
|
||||
export const SectionLabel = style({
|
||||
display: 'block',
|
||||
fontSize: toRem(11),
|
||||
fontSize: toRem(12),
|
||||
lineHeight: toRem(16),
|
||||
fontWeight: config.fontWeight.W600,
|
||||
letterSpacing: '0.06em',
|
||||
letterSpacing: '0.08em',
|
||||
textTransform: 'uppercase',
|
||||
color: color.Surface.OnContainer,
|
||||
opacity: 0.5,
|
||||
opacity: 0.55,
|
||||
paddingLeft: config.space.S100,
|
||||
paddingRight: config.space.S100,
|
||||
});
|
||||
|
|
@ -37,6 +37,35 @@ export const SettingRow = style({
|
|||
paddingRight: config.space.S400,
|
||||
});
|
||||
|
||||
// Dawn flat-list settings — no card box/fill. Rows sit edge-to-edge directly on
|
||||
// the page, parted by hairlines (iOS/Telegram grouped-list feel). Replaces the
|
||||
// outlined-filled SequenceCard panel.
|
||||
export const SettingFlatGroup = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
});
|
||||
|
||||
export const SettingFlatRow = style({
|
||||
paddingTop: config.space.S300,
|
||||
paddingBottom: config.space.S300,
|
||||
paddingLeft: config.space.S100,
|
||||
paddingRight: config.space.S100,
|
||||
selectors: {
|
||||
'&:not(:last-child)': {
|
||||
borderBottom: '1px solid rgba(255, 255, 255, 0.08)',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// A full-bleed hairline rule under a section/profile header — the "ДОСТУП ───"
|
||||
// divider in the flat layout.
|
||||
export const SettingRule = style({
|
||||
height: '1px',
|
||||
border: 'none',
|
||||
margin: 0,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.08)',
|
||||
});
|
||||
|
||||
// JetBrains Mono for technical values — mxid, device ids, version, tokens —
|
||||
// the same stack the DM stream / bot surfaces use for handles & timestamps.
|
||||
export const Mono = style({
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||
import { SettingsSection } from '../../settings/SettingsSection';
|
||||
import { SectionLabel } from '../../settings/styles.css';
|
||||
import { usePowerLevels } from '../../../hooks/usePowerLevels';
|
||||
import { useRoom } from '../../../hooks/useRoom';
|
||||
import {
|
||||
|
|
@ -51,13 +52,17 @@ export function General({ requestClose }: GeneralProps) {
|
|||
<RoomJoinRules permissions={permissions} />
|
||||
<RoomPublish permissions={permissions} />
|
||||
</SettingsSection>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="L400">{t('RoomSettings.addresses')}</Text>
|
||||
<Box direction="Column" gap="200">
|
||||
<Text as="span" className={SectionLabel}>
|
||||
{t('RoomSettings.addresses')}
|
||||
</Text>
|
||||
<RoomPublishedAddresses permissions={permissions} />
|
||||
<RoomLocalAddresses permissions={permissions} />
|
||||
</Box>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="L400">{t('RoomSettings.advanced_options')}</Text>
|
||||
<Box direction="Column" gap="200">
|
||||
<Text as="span" className={SectionLabel}>
|
||||
{t('RoomSettings.advanced_options')}
|
||||
</Text>
|
||||
<RoomUpgrade permissions={permissions} requestClose={requestClose} />
|
||||
</Box>
|
||||
</Box>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue