feat(web): open spaces as a plain chat on phones with a side drawer

Spaces, channels, files, members and the account move into a left drawer,
the top bar keeps only the essentials, and touch devices get a tap menu
instead of always-visible delete buttons. Also fixes the history checkboxes
in the channel settings sheet.
This commit is contained in:
justme committed 2026-10-16 05:34:38 +08:00
1 parent 06fe077ef1
commit 1db3795d6a
16 files changed
+383 -56

No files matched your search

+40
View File
@@ -0,0 +1,40 @@
.scrim {
position: fixed;
inset: 0;
z-index: 50;
background: var(--scrim);
animation: drawer-scrim-in 0.15s ease-out;
}
.drawer {
display: flex;
flex-direction: column;
width: min(320px, 86vw);
height: 100%;
padding-top: env(safe-area-inset-top);
border-right: 1px solid var(--line);
background: var(--bg);
box-shadow: var(--shadow-sheet);
outline: none;
animation: drawer-in 0.2s ease-out;
}
@keyframes drawer-scrim-in {
from {
opacity: 0;
}
}
@keyframes drawer-in {
from {
translate: -24px 0;
opacity: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.scrim,
.drawer {
animation: none;
}
}
+29
View File
@@ -0,0 +1,29 @@
import { useEffect, useRef, type ReactNode } from 'react';
import { createPortal } from 'react-dom';
import { useBackToClose } from '@/lib/useBackToClose';
import styles from './Drawer.module.css';
interface Props { label: string; onClose: () => void; children: ReactNode }
/** 手机的左侧抽屉:遮罩是纯色,返回键关闭(与 Sheet 一致) */
export function Drawer({ label, onClose, children }: Props) {
const ref = useRef<HTMLDivElement>(null);
const close = useRef(onClose);
useEffect(() => { close.current = onClose; }, [onClose]);
useBackToClose(onClose);
useEffect(() => {
const prev = document.activeElement as HTMLElement | null;
ref.current?.focus();
const onKey = (event: KeyboardEvent) => { if (event.key === 'Escape') close.current(); };
window.addEventListener('keydown', onKey);
return () => { window.removeEventListener('keydown', onKey); prev?.focus(); };
}, []);
return createPortal(
<div className={styles.scrim} onClick={onClose}>
<div ref={ref} tabIndex={-1} role="dialog" aria-modal="true" aria-label={label} className={styles.drawer} onClick={(event) => event.stopPropagation()}>
{children}
</div>
</div>,
document.body,
);
}
+2
View File
@@ -21,6 +21,8 @@ const PATHS = {
phone: 'M8 3h8v18H8z M11 18h2',
tablet: 'M5 4h14v16H5z M11 17h2',
more: 'M5 12h.01 M12 12h.01 M19 12h.01',
menu: 'M4 7h16 M4 12h16 M4 17h16',
users: 'M9 11a3 3 0 100-6 3 3 0 000 6z M3 19a6 6 0 0112 0 M16 6a3 3 0 010 6 M18 19a5 5 0 00-3-4.6',
undo: 'M9 14L4 9l5-5 M4 9h10a6 6 0 010 12h-3',
warn: 'M12 4l9 16H3z M12 10v4 M12 17h.01',
sun: 'M12 8a4 4 0 100 8 4 4 0 000-8z M12 2v2 M12 20v2 M2 12h2 M20 12h2 M5 5l1.5 1.5 M17.5 17.5L19 19 M5 19l1.5-1.5 M17.5 6.5L19 5',