feat(social): add listening activity, shared rooms and modern chat
ci / api / api (push) Canceled after 0s
ci / module boundaries / boundaries (push) Canceled after 0s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Canceled after 11m29s
ci / db / db (push) Canceled after 11m22s
ci / mobile / mobile (Metro-бандл Android) (push) Canceled after 6m43s
ci / recommender / recommender (push) Canceled after 6m47s
ci / ts / ts (packages + web) (push) Canceled after 1s

This commit is contained in:
mrleo1nid committed 2026-10-23 10:45:40 +03:00
1 parent 0a05bfe2cd
commit 11a16cd023
59 files changed
+5022 -542

No files matched your search

+13 -3
View File
@@ -210,6 +210,7 @@ export function Menu({
header,
align = 'end',
triggerClassName,
portal = false,
}: {
label: string;
trigger: ReactNode;
@@ -217,8 +218,10 @@ export function Menu({
header?: ReactNode;
align?: 'start' | 'end';
triggerClassName?: string;
portal?: boolean;
}) {
const [open, setOpen] = useState(false);
const [position, setPosition] = useState<CSSProperties>();
const ref = useRef<HTMLDivElement>(null);
const menuRef = useRef<HTMLDivElement>(null);
useEffect(() => {
@@ -246,7 +249,7 @@ export function Menu({
els[next]?.focus();
};
const menu = (
<div ref={menuRef} className={cx(s.menu, align === 'start' && s.menuStart)} role="menu" aria-label={label} onKeyDown={onMenuKey}>
<div ref={menuRef} style={portal && !window.matchMedia?.('(max-width: 767px)').matches ? position : undefined} className={cx(s.menu, align === 'start' && s.menuStart)} role="menu" aria-label={label} onKeyDown={onMenuKey}>
{header}
{items.map((it) => (
<button
@@ -273,11 +276,18 @@ export function Menu({
aria-label={label}
aria-haspopup="menu"
aria-expanded={open}
onClick={() => setOpen((v) => !v)}
onClick={e => {
if (portal) {
const rect = e.currentTarget.getBoundingClientRect();
const bottom = Math.max(12, window.innerHeight - rect.top + 6);
setPosition({ position: 'fixed', zIndex: 60, top: 'auto', bottom, right: Math.max(12, window.innerWidth - rect.right), maxHeight: Math.max(120, window.innerHeight - bottom - 12), overflowY: 'auto' });
}
setOpen(v => !v);
}}
>
{trigger}
</button>
{open && (window.matchMedia?.('(max-width: 767px)').matches
{open && (portal || window.matchMedia?.('(max-width: 767px)').matches
? createPortal(menu, document.body)
: menu)}
</div>