feat(members): carve rounded TL/BL on members drawer with 12px void seam to chat and extract VoidGap helper consolidating four per-pane seams
This commit is contained in:
parent
8400ef54ee
commit
646cb7b124
2 changed files with 58 additions and 28 deletions
|
|
@ -1,8 +1,18 @@
|
||||||
import { keyframes, style } from '@vanilla-extract/css';
|
import { keyframes, style } from '@vanilla-extract/css';
|
||||||
import { config, toRem } from 'folds';
|
import { config, toRem } from 'folds';
|
||||||
|
import { VOJO_HORSESHOE_RADIUS_PX } from '../../styles/horseshoe';
|
||||||
|
|
||||||
|
// Left edge carves TL + BL the same way `RoomViewProfileSidePanel` does
|
||||||
|
// across the 12px horseshoe void gap rendered by Room.tsx — same design
|
||||||
|
// language as the page-nav <-> chat split. `overflow: hidden` keeps the
|
||||||
|
// rounded corners clean against header / scroll content; the void
|
||||||
|
// colour beneath is painted by the parent flex row, not by the panel
|
||||||
|
// itself.
|
||||||
export const MembersDrawer = style({
|
export const MembersDrawer = style({
|
||||||
width: toRem(266),
|
width: toRem(266),
|
||||||
|
overflow: 'hidden',
|
||||||
|
borderTopLeftRadius: toRem(VOJO_HORSESHOE_RADIUS_PX),
|
||||||
|
borderBottomLeftRadius: toRem(VOJO_HORSESHOE_RADIUS_PX),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const MembersDrawerHeader = style({
|
export const MembersDrawerHeader = style({
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,22 @@ type RoomProps = {
|
||||||
renderRoomView?: (props: { eventId?: string }) => React.ReactNode;
|
renderRoomView?: (props: { eventId?: string }) => React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 12px black seam between the chat column and the right-side pane (profile,
|
||||||
|
// media, thread, members). Every active right-side pane renders one of
|
||||||
|
// these locally; the parent flex row is painted the same void colour by
|
||||||
|
// `Room` so each pane's TL/BL rounded carve can expose the void cleanly.
|
||||||
|
function VoidGap() {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
shrink="No"
|
||||||
|
style={{
|
||||||
|
width: toRem(VOJO_HORSESHOE_GAP_PX),
|
||||||
|
backgroundColor: VOJO_HORSESHOE_VOID_COLOR,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function Room({ renderRoomView }: RoomProps) {
|
export function Room({ renderRoomView }: RoomProps) {
|
||||||
const { eventId } = useParams();
|
const { eventId } = useParams();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
|
|
@ -115,18 +131,40 @@ export function Room({ renderRoomView }: RoomProps) {
|
||||||
// parent void can't bleed through any transparent slivers.
|
// parent void can't bleed through any transparent slivers.
|
||||||
const profileOpen = !!useAtomValue(userRoomProfileAtom);
|
const profileOpen = !!useAtomValue(userRoomProfileAtom);
|
||||||
const mediaOpen = !!useAtomValue(mediaViewerAtom);
|
const mediaOpen = !!useAtomValue(mediaViewerAtom);
|
||||||
|
const callView = room.isCallRoom();
|
||||||
const showProfileHorseshoe = profileOpen && !isMobile && !showThreadDrawer;
|
const showProfileHorseshoe = profileOpen && !isMobile && !showThreadDrawer;
|
||||||
// Media viewer side pane on desktop — same horseshoe seam idiom
|
// Media viewer side pane on desktop — same horseshoe seam idiom
|
||||||
// as the profile pane. The two are mutually exclusive in practice
|
// as the profile pane. The two are mutually exclusive in practice
|
||||||
// (the open hooks clear the other atom), so at most one shows at
|
// (the open hooks clear the other atom), so at most one shows at
|
||||||
// a time; both feed into `showAnyHorseshoe` for the chat-column
|
// a time; both feed into `paintParentVoid` for the chat-column bg
|
||||||
// bg + the void-gap render gate.
|
// and locally gate the shared `<VoidGap />` seam.
|
||||||
const showMediaHorseshoe = mediaOpen && !isMobile && !showThreadDrawer;
|
const showMediaHorseshoe = mediaOpen && !isMobile && !showThreadDrawer;
|
||||||
// Thread drawer side pane on desktop. Mobile hides the chat column
|
// Thread drawer side pane on desktop. Mobile hides the chat column
|
||||||
// entirely (`drawerHidesChat`) so the seam doesn't apply there.
|
// entirely (`drawerHidesChat`) so the seam doesn't apply there.
|
||||||
const showThreadHorseshoe = showThreadDrawer && !isMobile;
|
const showThreadHorseshoe = showThreadDrawer && !isMobile;
|
||||||
const showAnyHorseshoe =
|
// Members drawer side pane — mirrors the same horseshoe seam as the
|
||||||
showProfileHorseshoe || showMediaHorseshoe || showThreadHorseshoe;
|
// profile/media/thread panes. Gated on the exact same conditions that
|
||||||
|
// mount `<MembersDrawer>` below (group room, desktop, drawer setting on,
|
||||||
|
// no thread overlay, no call surface) so the void gap appears iff the
|
||||||
|
// pane appears.
|
||||||
|
const showMembersHorseshoe =
|
||||||
|
!callView &&
|
||||||
|
!isOneOnOne &&
|
||||||
|
!showThreadDrawer &&
|
||||||
|
screenSize === ScreenSize.Desktop &&
|
||||||
|
isDrawer;
|
||||||
|
// True whenever any right-side pane is mounted. Drives the parent flex
|
||||||
|
// row's void background and the chat column's explicit Background paint
|
||||||
|
// — both prevent the chat-side surface from bleeding through the carved
|
||||||
|
// TL/BL of whichever pane is open. The per-pane `<VoidGap />` decisions
|
||||||
|
// remain local to each render site (a single `paintParentVoid` gate
|
||||||
|
// would over-render when only members is open — there is no
|
||||||
|
// profile/media slot to anchor it to).
|
||||||
|
const paintParentVoid =
|
||||||
|
showProfileHorseshoe ||
|
||||||
|
showMediaHorseshoe ||
|
||||||
|
showThreadHorseshoe ||
|
||||||
|
showMembersHorseshoe;
|
||||||
|
|
||||||
useKeyDown(
|
useKeyDown(
|
||||||
window,
|
window,
|
||||||
|
|
@ -152,8 +190,6 @@ export function Room({ renderRoomView }: RoomProps) {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const callView = room.isCallRoom();
|
|
||||||
|
|
||||||
// Disable the atom-driven media viewer when the desktop thread
|
// Disable the atom-driven media viewer when the desktop thread
|
||||||
// drawer is open — the side-pane mount block below is gated on
|
// drawer is open — the side-pane mount block below is gated on
|
||||||
// `!showThreadDrawer`, so the new viewer's right pane wouldn't
|
// `!showThreadDrawer`, so the new viewer's right pane wouldn't
|
||||||
|
|
@ -181,7 +217,7 @@ export function Room({ renderRoomView }: RoomProps) {
|
||||||
<Box
|
<Box
|
||||||
grow="Yes"
|
grow="Yes"
|
||||||
style={
|
style={
|
||||||
showAnyHorseshoe
|
paintParentVoid
|
||||||
? { backgroundColor: VOJO_HORSESHOE_VOID_COLOR }
|
? { backgroundColor: VOJO_HORSESHOE_VOID_COLOR }
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +227,7 @@ export function Room({ renderRoomView }: RoomProps) {
|
||||||
grow="Yes"
|
grow="Yes"
|
||||||
direction="Column"
|
direction="Column"
|
||||||
className={
|
className={
|
||||||
showAnyHorseshoe
|
paintParentVoid
|
||||||
? ContainerColor({ variant: 'Background' })
|
? ContainerColor({ variant: 'Background' })
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
@ -213,7 +249,7 @@ export function Room({ renderRoomView }: RoomProps) {
|
||||||
grow="Yes"
|
grow="Yes"
|
||||||
direction="Column"
|
direction="Column"
|
||||||
className={
|
className={
|
||||||
showAnyHorseshoe
|
paintParentVoid
|
||||||
? ContainerColor({ variant: 'Background' })
|
? ContainerColor({ variant: 'Background' })
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
@ -245,15 +281,7 @@ export function Room({ renderRoomView }: RoomProps) {
|
||||||
exclusive via the open hooks. */}
|
exclusive via the open hooks. */}
|
||||||
{!isMobile && !showThreadDrawer && (
|
{!isMobile && !showThreadDrawer && (
|
||||||
<>
|
<>
|
||||||
{showAnyHorseshoe && (
|
{(showProfileHorseshoe || showMediaHorseshoe) && <VoidGap />}
|
||||||
<Box
|
|
||||||
shrink="No"
|
|
||||||
style={{
|
|
||||||
width: toRem(VOJO_HORSESHOE_GAP_PX),
|
|
||||||
backgroundColor: VOJO_HORSESHOE_VOID_COLOR,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<RoomViewProfileSidePanel />
|
<RoomViewProfileSidePanel />
|
||||||
<RoomViewMediaSidePanel />
|
<RoomViewMediaSidePanel />
|
||||||
</>
|
</>
|
||||||
|
|
@ -277,21 +305,13 @@ export function Room({ renderRoomView }: RoomProps) {
|
||||||
screenSize === ScreenSize.Desktop &&
|
screenSize === ScreenSize.Desktop &&
|
||||||
isDrawer && (
|
isDrawer && (
|
||||||
<>
|
<>
|
||||||
<Line variant="Background" direction="Vertical" size="300" />
|
{showMembersHorseshoe && <VoidGap />}
|
||||||
<MembersDrawer key={room.roomId} room={room} members={members} />
|
<MembersDrawer key={room.roomId} room={room} members={members} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{showThreadDrawer && decodedRootId && parentRoomPath && (
|
{showThreadDrawer && decodedRootId && parentRoomPath && (
|
||||||
<>
|
<>
|
||||||
{showThreadHorseshoe && (
|
{showThreadHorseshoe && <VoidGap />}
|
||||||
<Box
|
|
||||||
shrink="No"
|
|
||||||
style={{
|
|
||||||
width: toRem(VOJO_HORSESHOE_GAP_PX),
|
|
||||||
backgroundColor: VOJO_HORSESHOE_VOID_COLOR,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<ThreadDrawer
|
<ThreadDrawer
|
||||||
key={`${room.roomId}/${decodedRootId}`}
|
key={`${room.roomId}/${decodedRootId}`}
|
||||||
room={room}
|
room={room}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue