Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a7657c8
remove selecting text on mobile
nushea Jun 16, 2026
4f6c4a8
separate menu into its own file
nushea Jun 16, 2026
0f0fd9e
separate quickmenu
nushea Jun 17, 2026
df16944
Merge remote-tracking branch 'origin/dev' into feat-better-mobile-con…
nushea Jun 17, 2026
40ed6bc
add more mobile styling with shadows, fix more stuff about the separa…
nushea Jun 18, 2026
9108f7f
add wrapping the message to ensure it gets sent to the modal properly
nushea Jun 18, 2026
ac630a5
Merge remote-tracking branch 'origin/dev' into feat-better-mobile-con…
nushea Jun 18, 2026
a3a85af
emojiboard styling fixes, unified event containers into messageInternal
nushea Jun 19, 2026
3c00726
prevent ouside clicks to not misclick sth while closing the menu
nushea Jun 19, 2026
2508a73
forgot to wrap it
nushea Jun 19, 2026
a1edee4
remove reply swipe from example
nushea Jun 20, 2026
1fd626c
merge upstream
nushea Jun 22, 2026
f9bb547
make it work on ios, disable double tap, and protect against double p…
7w1 Jun 23, 2026
5f1c586
add slide up animation
7w1 Jun 23, 2026
77dc2a2
add ability to swipe menu down
7w1 Jun 23, 2026
2850d5f
make drag handle appear
7w1 Jun 23, 2026
760a779
revert menu positioning adjustment
7w1 Jun 23, 2026
28c34f7
Change drag handle style
7w1 Jun 23, 2026
cfad2cb
disable swipe gestures and adjust padding
7w1 Jun 23, 2026
b2e2314
actually stop swipe gestures i think
7w1 Jun 23, 2026
76d75cc
make everything flickable
nushea Jun 23, 2026
9c01b79
make make dragging work *around* message
nushea Jun 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/feat_add_better_mobile_context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
default: minor
---

Add a new Mobile Context
5 changes: 5 additions & 0 deletions .changeset/feat_add_event_reactions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
default: minor
---

Add reactions to arbitrary events
5 changes: 5 additions & 0 deletions .changeset/fix_ghost_quickmenu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
default: patch
---

Fix ghost quickmenu
4 changes: 2 additions & 2 deletions src/app/components/SwipeableMessageWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export function SwipeableMessageWrapper({
onReply,
}: {
children: ReactNode;
onReply: () => void;
onReply?: () => void;
}) {
const settings = useAtomValue(settingsAtom);

Expand All @@ -83,7 +83,7 @@ export function SwipeableMessageWrapper({
[settings.mobileGestures, settings.rightSwipeAction]
);

if (!isSwipeToReplyEnabled) {
if (!isSwipeToReplyEnabled || !onReply) {
return children;
}

Expand Down
11 changes: 9 additions & 2 deletions src/app/components/emoji-board/EmojiBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ type EmojiBoardProps = {
onStickerSelect?: (mxc: string, shortcode: string, label: string) => void;
allowTextCustomEmoji?: boolean;
addToRecentEmoji?: boolean;
isFullWidth?: boolean;
};

export function EmojiBoard({
Expand All @@ -399,6 +400,7 @@ export function EmojiBoard({
onStickerSelect,
allowTextCustomEmoji,
addToRecentEmoji = true,
isFullWidth,
}: Readonly<EmojiBoardProps>) {
const mx = useMatrixClient();
const [saveStickerEmojiBandwidth] = useSetting(settingsAtom, 'saveStickerEmojiBandwidth');
Expand Down Expand Up @@ -539,8 +541,12 @@ export function EmojiBoard({
returnFocusOnDeactivate,
initialFocus: false,
onDeactivate: requestClose,
clickOutsideDeactivates: true,
allowOutsideClick: true,

allowOutsideClick: (e) => {
e.preventDefault();
requestClose();
return false;
},
isKeyForward: (evt: KeyboardEvent) =>
!editableActiveElement() && isKeyHotkey(['arrowdown', 'arrowright'], evt),
isKeyBackward: (evt: KeyboardEvent) =>
Expand Down Expand Up @@ -578,6 +584,7 @@ export function EmojiBoard({
/>
)
}
isFullWidth={isFullWidth}
>
<Box grow="Yes">
<EmojiGroupHolder
Expand Down
5 changes: 3 additions & 2 deletions src/app/components/emoji-board/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ export const EmojiBoardLayout = as<
header: ReactNode;
sidebar?: ReactNode;
children: ReactNode;
isFullWidth?: boolean;
}
>(({ className, header, sidebar, children, ...props }, ref) => (
>(({ className, header, sidebar, children, isFullWidth, ...props }, ref) => (
<Box
display="InlineFlex"
className={classNames(css.Base, className)}
className={classNames(css.Base({ isFullWidth }), className)}
direction="Row"
{...props}
ref={ref}
Expand Down
33 changes: 23 additions & 10 deletions src/app/components/emoji-board/components/styles.css.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
import { style } from '@vanilla-extract/css';
import { recipe } from '@vanilla-extract/recipes';
import { toRem, color, config, DefaultReset, FocusOutline } from 'folds';

/**
* Layout
*/

export const Base = style({
maxWidth: toRem(432),
width: `calc(100vw - 2 * ${config.space.S400})`,
height: toRem(450),
backgroundColor: color.Surface.Container,
color: color.Surface.OnContainer,
border: `${config.borderWidth.B300} solid ${color.Surface.ContainerLine}`,
borderRadius: config.radii.R400,
boxShadow: config.shadow.E200,
overflow: 'hidden',
export const Base = recipe({
base: [
{
maxWidth: toRem(432),
width: `calc(100vw - 2 * ${config.space.S400})`,
height: toRem(450),
backgroundColor: color.Surface.Container,
color: color.Surface.OnContainer,
border: `${config.borderWidth.B300} solid ${color.Surface.ContainerLine}`,
borderRadius: config.radii.R400,
boxShadow: config.shadow.E200,
overflow: 'hidden',
},
],
variants: {
isFullWidth: {
true: {
maxWidth: '100vw',
width: `calc(100vw - ${config.borderWidth.B300})`,
},
},
},
});

export const Header = style({
Expand Down
1 change: 0 additions & 1 deletion src/app/components/event-readers/EventReaders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export const EventReaders = as<'div', EventReadersProps>(
const openProfile = useOpenUserRoomProfile();
const space = useSpaceOptionally();
const nicknames = useAtomValue(nicknamesAtom);

const getName = (userId: string) =>
getMemberDisplayName(room, userId, nicknames) ?? getMxIdLocalPart(userId) ?? userId;

Expand Down
2 changes: 2 additions & 0 deletions src/app/components/message/layout/Base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const MessageBase = as<'div', css.MessageBaseVariants>(
collapse,
autoCollapse,
space,
mobile,
...props
},
ref
Expand All @@ -27,6 +28,7 @@ export const MessageBase = as<'div', css.MessageBaseVariants>(
collapse,
autoCollapse,
space,
mobile,
}),
className
)}
Expand Down
12 changes: 12 additions & 0 deletions src/app/components/message/layout/layout.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ export const messageJumpHighlight = style({
animationIterationCount: 'infinite',
});

const MobileVariant = styleVariants({
true: {
WebkitUserSelect: 'none',
msUserSelect: 'none',
userSelect: 'none',
MozUserSelect: 'none',
},
});

const HighlightVariant = styleVariants({
true: [messageJumpHighlight],
});
Expand Down Expand Up @@ -108,6 +117,8 @@ export const MessageBase = recipe({
borderRadius: `0 ${config.radii.R400} ${config.radii.R400} 0`,
minHeight: toRem(16),
contain: 'layout',
flexGrow: '1',
width: '100',
},
],
variants: {
Expand All @@ -124,6 +135,7 @@ export const MessageBase = recipe({
notifyHighlight: NotifyHighlightVariant,
selected: SelectedVariant,
isMarked: MarkedVariant,
mobile: MobileVariant,
},
defaultVariants: {
space: '400',
Expand Down
21 changes: 11 additions & 10 deletions src/app/components/message/modals/GlobalModalManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,23 @@ import { MessageSourceInternal } from './MessageSource';
import { MessageForwardInternal } from './MessageForward';
import { MessageAllReactionInternal } from './MessageReactions';
import { MessageReadReceiptInternal } from './MessageReadRecipts';
import { MobileOptionsInternal } from './Options';

export function GlobalModalManager() {
const [modal, setModal] = useAtom(modalAtom);

const close = () => setModal(null);

if (modal?.type === ModalType.Forward) {
return <MessageForwardInternal room={modal.room} mEvent={modal.mEvent} onClose={close} />;
}
const close = () => {
setModal(null);
};

if (!modal) return null;

if (modal.type === ModalType.Forward) {
return <MessageForwardInternal room={modal.room} mEvent={modal.mEvent} onClose={close} />;
}
if (modal.type === ModalType.MobileOptions) {
return <MobileOptionsInternal options={modal.options} />;
}
return (
<Overlay open backdrop={<OverlayBackdrop />}>
<OverlayCenter>
Expand All @@ -34,24 +39,22 @@ export function GlobalModalManager() {
}}
>
<div>
{' '}
{modal.type === ModalType.Report && (
<Box>
<MessageReportInternal room={modal.room} mEvent={modal.mEvent} onClose={close} />
</Box>
)}

{modal.type === ModalType.Delete && (
<Box>
<MessageDeleteInternal room={modal.room} mEvent={modal.mEvent} onClose={close} />
</Box>
)}

{modal.type === ModalType.Source && (
<Modal variant="Surface" size="300">
<MessageSourceInternal room={modal.room} mEvent={modal.mEvent} onClose={close} />
</Modal>
)}

{modal.type === ModalType.Reactions && (
<Modal variant="Surface" size="300">
<MessageAllReactionInternal
Expand All @@ -61,7 +64,6 @@ export function GlobalModalManager() {
/>
</Modal>
)}

{modal.type === ModalType.EditHistory && (
<Modal variant="Surface" size="300">
<MessageEditHistoryInternal
Expand All @@ -71,7 +73,6 @@ export function GlobalModalManager() {
/>
</Modal>
)}

{modal.type === ModalType.ReadReceipts && (
<Modal variant="Surface" size="300">
<MessageReadReceiptInternal
Expand Down
11 changes: 10 additions & 1 deletion src/app/components/message/modals/MessageDelete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,15 @@ import * as Sentry from '@sentry/react';

const debugLog = createDebugLogger('MessageDelete');

export function MessageDeleteItem({ room, mEvent }: { room: Room; mEvent: MatrixEvent }) {
export function MessageDeleteItem({
room,
mEvent,
closeMenu,
}: {
room: Room;
mEvent: MatrixEvent;
closeMenu?: () => void;
}) {
const setModal = useSetAtom(modalAtom);

return (
Expand All @@ -43,6 +51,7 @@ export function MessageDeleteItem({ room, mEvent }: { room: Room; mEvent: Matrix
room,
mEvent,
});
closeMenu?.();
}}
>
<Text className={css.MessageMenuItemText} as="span" size="T300" truncate>
Expand Down
11 changes: 10 additions & 1 deletion src/app/components/message/modals/MessageReadRecipts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ import { modalAtom, ModalType } from '$state/modal';
import { EventReaders } from '$components/event-readers';
import * as css from '$features/room/message/styles.css';

export function MessageReadReceiptItem({ room, eventId }: { room: Room; eventId: string }) {
export function MessageReadReceiptItem({
room,
eventId,
closeMenu,
}: {
room: Room;
eventId: string;
closeMenu?: () => void;
}) {
const setModal = useSetAtom(modalAtom);

return (
Expand All @@ -23,6 +31,7 @@ export function MessageReadReceiptItem({ room, eventId }: { room: Room; eventId:
room,
eventId,
});
closeMenu?.();
}}
>
<Text className={css.MessageMenuItemText} as="span" size="T300" truncate>
Expand Down
11 changes: 10 additions & 1 deletion src/app/components/message/modals/MessageReport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,15 @@ import * as Sentry from '@sentry/react';

const debugLog = createDebugLogger('MessageReport');

export function MessageReportItem({ room, mEvent }: { room: Room; mEvent: MatrixEvent }) {
export function MessageReportItem({
room,
mEvent,
closeMenu,
}: {
room: Room;
mEvent: MatrixEvent;
closeMenu?: () => void;
}) {
const setModal = useSetAtom(modalAtom);

return (
Expand All @@ -43,6 +51,7 @@ export function MessageReportItem({ room, mEvent }: { room: Room; mEvent: Matrix
room,
mEvent,
});
closeMenu?.();
}}
>
<Text className={css.MessageMenuItemText} as="span" size="T300" truncate>
Expand Down
11 changes: 10 additions & 1 deletion src/app/components/message/modals/MessageSource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ import { getEventEdits } from '$utils/room';
import { modalAtom, ModalType } from '$state/modal';
import * as css from '$features/room/message/styles.css';

export function MessageSourceCodeItem({ room, mEvent }: { room: Room; mEvent: MatrixEvent }) {
export function MessageSourceCodeItem({
room,
mEvent,
closeMenu,
}: {
room: Room;
mEvent: MatrixEvent;
closeMenu: () => void;
}) {
const setModal = useSetAtom(modalAtom);

return (
Expand All @@ -24,6 +32,7 @@ export function MessageSourceCodeItem({ room, mEvent }: { room: Room; mEvent: Ma
room,
mEvent,
});
closeMenu();
}}
>
<Text className={css.MessageMenuItemText} as="span" size="T300" truncate>
Expand Down
Loading
Loading