Backgrounds: theme-aware patterns and visual preview grid
This commit is contained in:
@@ -32,7 +32,7 @@ import FocusTrap from 'focus-trap-react';
|
||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||
import { SequenceCard } from '../../../components/sequence-card';
|
||||
import { useSetting } from '../../../state/hooks/settings';
|
||||
import { DateFormat, MessageLayout, MessageSpacing, settingsAtom } from '../../../state/settings';
|
||||
import { ChatBackground, DateFormat, MessageLayout, MessageSpacing, settingsAtom } from '../../../state/settings';
|
||||
import { SettingTile } from '../../../components/setting-tile';
|
||||
import { KeySymbol } from '../../../utils/key-symbol';
|
||||
import { isMacOS } from '../../../utils/user-agent';
|
||||
@@ -42,10 +42,12 @@ import {
|
||||
Theme,
|
||||
ThemeKind,
|
||||
useSystemThemeKind,
|
||||
useTheme,
|
||||
useThemeNames,
|
||||
useThemes,
|
||||
} from '../../../hooks/useTheme';
|
||||
import { stopPropagation } from '../../../utils/keyboard';
|
||||
import { BG_OPTIONS, getChatBg } from '../../lotus/chatBackground';
|
||||
import { useMessageLayoutItems } from '../../../hooks/useMessageLayout';
|
||||
import { useMessageSpacingItems } from '../../../hooks/useMessageSpacing';
|
||||
import { useDateFormatItems } from '../../../hooks/useDateFormat';
|
||||
@@ -352,12 +354,14 @@ function Appearance() {
|
||||
<SettingTile title="Page Zoom" after={<PageZoomInput />} />
|
||||
</SequenceCard>
|
||||
|
||||
<SequenceCard className={SequenceCardStyle} variant="SurfaceVariant" direction="Column">
|
||||
<SequenceCard className={SequenceCardStyle} variant="SurfaceVariant" direction="Column" gap="200">
|
||||
<SettingTile
|
||||
title="Chat Background"
|
||||
description="Pattern applied behind the message timeline."
|
||||
after={<SelectChatBackground />}
|
||||
/>
|
||||
<Box style={{ padding: `0 ${config.space.S400} ${config.space.S300}` }}>
|
||||
<ChatBgGrid />
|
||||
</Box>
|
||||
</SequenceCard>
|
||||
|
||||
<SequenceCard className={SequenceCardStyle} variant="SurfaceVariant" direction="Column">
|
||||
@@ -759,81 +763,43 @@ function Editor() {
|
||||
}
|
||||
|
||||
|
||||
const BG_OPTIONS: { value: ChatBackground; label: string }[] = [
|
||||
{ value: 'none', label: 'None' },
|
||||
{ value: 'blueprint', label: 'Blueprint' },
|
||||
{ value: 'carbon', label: 'Carbon' },
|
||||
{ value: 'stars', label: 'Stars' },
|
||||
{ value: 'topographic', label: 'Topographic' },
|
||||
{ value: 'herringbone', label: 'Herringbone' },
|
||||
{ value: 'crosshatch', label: 'Crosshatch' },
|
||||
];
|
||||
|
||||
function SelectChatBackground() {
|
||||
const [menuCords, setMenuCords] = useState<RectCords>();
|
||||
function ChatBgGrid() {
|
||||
const [chatBackground, setChatBackground] = useSetting(settingsAtom, 'chatBackground');
|
||||
|
||||
const handleMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
||||
setMenuCords(evt.currentTarget.getBoundingClientRect());
|
||||
};
|
||||
|
||||
const handleSelect = (value: ChatBackground) => {
|
||||
setChatBackground(value);
|
||||
setMenuCords(undefined);
|
||||
};
|
||||
const theme = useTheme();
|
||||
const isDark = theme.kind === ThemeKind.Dark;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
size="300"
|
||||
variant="Secondary"
|
||||
outlined
|
||||
fill="Soft"
|
||||
radii="300"
|
||||
after={<Icon size="300" src={Icons.ChevronBottom} />}
|
||||
onClick={handleMenu}
|
||||
>
|
||||
<Text size="T300">
|
||||
{BG_OPTIONS.find((o) => o.value === chatBackground)?.label ?? 'None'}
|
||||
</Text>
|
||||
</Button>
|
||||
<PopOut
|
||||
anchor={menuCords}
|
||||
offset={5}
|
||||
position="Bottom"
|
||||
align="End"
|
||||
content={
|
||||
<FocusTrap
|
||||
focusTrapOptions={{
|
||||
initialFocus: false,
|
||||
onDeactivate: () => setMenuCords(undefined),
|
||||
clickOutsideDeactivates: true,
|
||||
isKeyForward: (evt: KeyboardEvent) =>
|
||||
evt.key === 'ArrowDown' || evt.key === 'ArrowRight',
|
||||
isKeyBackward: (evt: KeyboardEvent) =>
|
||||
evt.key === 'ArrowUp' || evt.key === 'ArrowLeft',
|
||||
escapeDeactivates: stopPropagation,
|
||||
<Box wrap="Wrap" gap="200">
|
||||
{BG_OPTIONS.map((opt) => (
|
||||
<Box key={opt.value} direction="Column" gap="100" style={{ alignItems: 'center' }}>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={opt.label}
|
||||
aria-pressed={chatBackground === opt.value}
|
||||
onClick={() => setChatBackground(opt.value as ChatBackground)}
|
||||
style={{
|
||||
display: 'block',
|
||||
width: toRem(76),
|
||||
height: toRem(50),
|
||||
borderRadius: toRem(8),
|
||||
cursor: 'pointer',
|
||||
border: chatBackground === opt.value
|
||||
? '2px solid #980000'
|
||||
: '2px solid rgba(128,128,128,0.25)',
|
||||
padding: 0,
|
||||
overflow: 'hidden',
|
||||
...getChatBg(opt.value as ChatBackground, isDark),
|
||||
}}
|
||||
/>
|
||||
<Text
|
||||
size="T200"
|
||||
style={chatBackground === opt.value ? { color: '#980000' } : undefined}
|
||||
>
|
||||
<Menu>
|
||||
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
||||
{BG_OPTIONS.map((opt) => (
|
||||
<MenuItem
|
||||
key={opt.value}
|
||||
size="300"
|
||||
variant={chatBackground === opt.value ? 'Primary' : 'Surface'}
|
||||
radii="300"
|
||||
onClick={() => handleSelect(opt.value)}
|
||||
>
|
||||
<Text size="T300">{opt.label}</Text>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Box>
|
||||
</Menu>
|
||||
</FocusTrap>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
{opt.label}
|
||||
</Text>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user