diff --git a/overlay/src/app/components/editor/Editor.css.ts b/overlay/src/app/components/editor/Editor.css.ts
new file mode 100644
index 0000000..062ce0e
--- /dev/null
+++ b/overlay/src/app/components/editor/Editor.css.ts
@@ -0,0 +1,79 @@
+import { style } from '@vanilla-extract/css';
+import { color, config, DefaultReset, toRem } from 'folds';
+
+export const Editor = style([
+ DefaultReset,
+ {
+ backgroundColor: color.SurfaceVariant.Container,
+ color: color.SurfaceVariant.OnContainer,
+ boxShadow: `inset 0 0 0 ${config.borderWidth.B300} ${color.SurfaceVariant.ContainerLine}`,
+ borderRadius: config.radii.R400,
+ overflow: 'hidden',
+ selectors: {
+ // Keyboard-flush dock: only a top edge so the input can sit on the IME.
+ '[data-composer-flush="true"] &': {
+ borderRadius: 0,
+ boxShadow: `inset 0 ${config.borderWidth.B300} 0 0 ${color.SurfaceVariant.ContainerLine}`,
+ },
+ },
+ },
+]);
+
+export const EditorOptions = style([
+ DefaultReset,
+ {
+ padding: config.space.S200,
+ },
+]);
+
+export const EditorTextareaScroll = style({});
+
+export const EditorTextarea = style([
+ DefaultReset,
+ {
+ flexGrow: 1,
+ height: '100%',
+ padding: `${toRem(13)} ${toRem(1)}`,
+ selectors: {
+ [`${EditorTextareaScroll}:first-child &`]: {
+ paddingLeft: toRem(13),
+ },
+ [`${EditorTextareaScroll}:last-child &`]: {
+ paddingRight: toRem(13),
+ },
+ '&:focus': {
+ outline: 'none',
+ },
+ },
+ },
+]);
+
+export const EditorPlaceholderContainer = style([
+ DefaultReset,
+ {
+ opacity: config.opacity.Placeholder,
+ pointerEvents: 'none',
+ userSelect: 'none',
+ },
+]);
+
+export const EditorPlaceholderTextVisual = style([
+ DefaultReset,
+ {
+ display: 'block',
+ paddingTop: toRem(13),
+ paddingLeft: toRem(1),
+ },
+]);
+
+export const EditorToolbarBase = style({
+ padding: `0 ${config.borderWidth.B300}`,
+});
+
+export const EditorToolbar = style({
+ padding: config.space.S100,
+});
+
+export const MarkdownBtnBox = style({
+ paddingRight: config.space.S100,
+});
diff --git a/overlay/src/app/features/room/RoomView.tsx b/overlay/src/app/features/room/RoomView.tsx
index 652805f..2b891ae 100644
--- a/overlay/src/app/features/room/RoomView.tsx
+++ b/overlay/src/app/features/room/RoomView.tsx
@@ -14,7 +14,7 @@ import { RoomTimeline } from './RoomTimeline';
import { RoomViewTyping } from './RoomViewTyping';
import { RoomTombstone } from './RoomTombstone';
import { RoomInput } from './RoomInput';
-import { RoomViewFollowing, RoomViewFollowingPlaceholder } from './RoomViewFollowing';
+import { RoomViewFollowing } from './RoomViewFollowing';
import { Page } from '../../components/page';
import { RoomViewHeader } from './RoomViewHeader';
import { useKeyDown } from '../../hooks/useKeyDown';
@@ -27,6 +27,7 @@ import { activeThreadIdAtomFamily } from '../../state/activeThread';
import { ThreadView } from './ThreadView';
import { MobileSwipeToReplyLayer } from '../../components/mobile/MobileSwipeToReplyLayer';
import { useMobileKeyboardLayout } from '../../hooks/useMobileKeyboardLayout';
+import * as composerCss from './room-composer-mobile.css';
const FN_KEYS_REGEX = /^F\d+$/;
const shouldFocusMessageField = (evt: KeyboardEvent): boolean => {
@@ -103,7 +104,8 @@ export function RoomView({ room, eventId }: { room: Room; eventId?: string }) {
)
);
- const composerPadding = isLandscape ? '0' : `0 ${config.space.S400}`;
+ const flushComposer = keyboardOpen || isLandscape;
+ const composerPadding = flushComposer ? '0' : `0 ${config.space.S400}`;
const showHeader = !keyboardOpen;
return (
@@ -125,7 +127,20 @@ export function RoomView({ room, eventId }: { room: Room; eventId?: string }) {
-
+
+ {!hideActivity && (
+
+ )}
{tombstoneEvent ? (
)}
- {hideActivity ? : }
>
)}
diff --git a/overlay/src/app/features/room/RoomViewFollowing.css.ts b/overlay/src/app/features/room/RoomViewFollowing.css.ts
new file mode 100644
index 0000000..58a326a
--- /dev/null
+++ b/overlay/src/app/features/room/RoomViewFollowing.css.ts
@@ -0,0 +1,41 @@
+import { style } from '@vanilla-extract/css';
+import { recipe } from '@vanilla-extract/recipes';
+import { DefaultReset, color, config } from 'folds';
+
+export const RoomViewFollowingPlaceholder = style([
+ DefaultReset,
+ {
+ display: 'none',
+ height: 0,
+ },
+]);
+
+export const RoomViewFollowing = recipe({
+ base: [
+ DefaultReset,
+ {
+ minHeight: 0,
+ padding: `${config.space.S100} ${config.space.S200}`,
+ width: 'auto',
+ maxWidth: '100%',
+ backgroundColor: 'transparent',
+ color: color.Surface.OnContainer,
+ outline: 'none',
+ },
+ ],
+ variants: {
+ clickable: {
+ true: {
+ cursor: 'pointer',
+ selectors: {
+ '&:hover, &:focus-visible': {
+ color: color.Primary.Main,
+ },
+ '&:active': {
+ color: color.Primary.Main,
+ },
+ },
+ },
+ },
+ },
+});
diff --git a/overlay/src/app/features/room/room-composer-mobile.css.ts b/overlay/src/app/features/room/room-composer-mobile.css.ts
new file mode 100644
index 0000000..9f8beee
--- /dev/null
+++ b/overlay/src/app/features/room/room-composer-mobile.css.ts
@@ -0,0 +1,63 @@
+import { style } from '@vanilla-extract/css';
+import { recipe } from '@vanilla-extract/recipes';
+import { DefaultReset, color, config } from 'folds';
+
+export const ComposerDock = style({
+ position: 'relative',
+});
+
+/** Read receipts float above the input so they don't reserve layout height. */
+export const FollowingFloat = style({
+ position: 'absolute',
+ bottom: '100%',
+ left: 0,
+ right: 0,
+ zIndex: 2,
+ display: 'flex',
+ justifyContent: 'flex-end',
+ pointerEvents: 'none',
+ padding: `0 ${config.space.S200}`,
+});
+
+export const FollowingFloatHit = style({
+ pointerEvents: 'auto',
+ maxWidth: '100%',
+});
+
+export const RoomViewFollowingPlaceholder = style([
+ DefaultReset,
+ {
+ display: 'none',
+ height: 0,
+ },
+]);
+
+export const RoomViewFollowing = recipe({
+ base: [
+ DefaultReset,
+ {
+ minHeight: 0,
+ padding: `${config.space.S100} ${config.space.S200}`,
+ width: 'auto',
+ maxWidth: '100%',
+ backgroundColor: 'transparent',
+ color: color.Surface.OnContainer,
+ outline: 'none',
+ },
+ ],
+ variants: {
+ clickable: {
+ true: {
+ cursor: 'pointer',
+ selectors: {
+ '&:hover, &:focus-visible': {
+ color: color.Primary.Main,
+ },
+ '&:active': {
+ color: color.Primary.Main,
+ },
+ },
+ },
+ },
+ },
+});