diff --git a/src/app/components/message/content/EventContent.tsx b/src/app/components/message/content/EventContent.tsx index 97ff26f7..130ba8c9 100644 --- a/src/app/components/message/content/EventContent.tsx +++ b/src/app/components/message/content/EventContent.tsx @@ -1,6 +1,6 @@ import { Box, Icon, IconSrc } from 'folds'; import React, { ReactNode } from 'react'; -import { CompactLayout, ModernLayout } from '..'; +import { BubbleLayout, CompactLayout, ModernLayout } from '..'; import { MessageLayout } from '../../../state/settings'; export type EventContentProps = { @@ -30,9 +30,15 @@ export function EventContent({ messageLayout, time, iconSrc, content }: EventCon ); - return messageLayout === MessageLayout.Compact ? ( - {msgContentJSX} - ) : ( - {msgContentJSX} - ); + if (messageLayout === MessageLayout.Compact) { + return {msgContentJSX}; + } + if (messageLayout === MessageLayout.Bubble) { + return ( + + {msgContentJSX} + + ); + } + return {msgContentJSX}; } diff --git a/src/app/components/message/layout/Bubble.tsx b/src/app/components/message/layout/Bubble.tsx index 6f8e70da..93ff84bc 100644 --- a/src/app/components/message/layout/Bubble.tsx +++ b/src/app/components/message/layout/Bubble.tsx @@ -1,18 +1,63 @@ import React, { ReactNode } from 'react'; -import { Box, as } from 'folds'; +import classNames from 'classnames'; +import { Box, ContainerColor, as, color } from 'folds'; import * as css from './layout.css'; +type BubbleArrowProps = { + variant: ContainerColor; +}; +function BubbleLeftArrow({ variant }: BubbleArrowProps) { + return ( + + + + ); +} + type BubbleLayoutProps = { + hideBubble?: boolean; before?: ReactNode; + header?: ReactNode; }; -export const BubbleLayout = as<'div', BubbleLayoutProps>(({ before, children, ...props }, ref) => ( - - - {before} +export const BubbleLayout = as<'div', BubbleLayoutProps>( + ({ hideBubble, before, header, children, ...props }, ref) => ( + + + {before} + + + {header} + {hideBubble ? ( + children + ) : ( + + + {before ? : null} + {children} + + + )} + - - {children} - - -)); + ) +); diff --git a/src/app/components/message/layout/layout.css.ts b/src/app/components/message/layout/layout.css.ts index 43949cef..cc2cd0c6 100644 --- a/src/app/components/message/layout/layout.css.ts +++ b/src/app/components/message/layout/layout.css.ts @@ -120,6 +120,7 @@ export const CompactHeader = style([ export const AvatarBase = style({ paddingTop: toRem(4), transition: 'transform 200ms cubic-bezier(0, 0.8, 0.67, 0.97)', + display: 'flex', alignSelf: 'start', selectors: { @@ -133,14 +134,31 @@ export const ModernBefore = style({ minWidth: toRem(36), }); -export const BubbleBefore = style([ModernBefore]); +export const BubbleBefore = style({ + minWidth: toRem(36), +}); export const BubbleContent = style({ maxWidth: toRem(800), padding: config.space.S200, backgroundColor: color.SurfaceVariant.Container, color: color.SurfaceVariant.OnContainer, - borderRadius: config.radii.R400, + borderRadius: config.radii.R500, + position: 'relative', +}); + +export const BubbleContentArrowLeft = style({ + borderTopLeftRadius: 0, +}); + +export const BubbleLeftArrow = style({ + width: toRem(9), + height: toRem(8), + + position: 'absolute', + top: 0, + left: toRem(-8), + zIndex: 1, }); export const Username = style({ diff --git a/src/app/features/room/message/Message.tsx b/src/app/features/room/message/Message.tsx index fbe35770..9324e1c2 100644 --- a/src/app/features/room/message/Message.tsx +++ b/src/app/features/room/message/Message.tsx @@ -723,6 +723,7 @@ export const Message = as<'div', MessageProps>( const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const senderId = mEvent.getSender() ?? ''; + const [hover, setHover] = useState(false); const { hoverProps } = useHover({ onHoverChange: setHover }); const { focusWithinProps } = useFocusWithin({ onFocusWithinChange: setHover }); @@ -790,7 +791,9 @@ export const Message = as<'div', MessageProps>( ); const avatarJSX = !collapse && messageLayout !== MessageLayout.Compact && ( - + ( return ( ( )} {messageLayout === MessageLayout.Bubble && ( - - {headerJSX} + {msgContentJSX} )} diff --git a/src/app/features/room/message/styles.css.ts b/src/app/features/room/message/styles.css.ts index b87cb505..4be501bd 100644 --- a/src/app/features/room/message/styles.css.ts +++ b/src/app/features/room/message/styles.css.ts @@ -4,6 +4,9 @@ import { DefaultReset, config, toRem } from 'folds'; export const MessageBase = style({ position: 'relative', }); +export const MessageBaseBubbleCollapsed = style({ + paddingTop: 0, +}); export const MessageOptionsBase = style([ DefaultReset, @@ -21,6 +24,10 @@ export const MessageOptionsBar = style([ }, ]); +export const BubbleAvatarBase = style({ + paddingTop: 0, +}); + export const MessageAvatar = style({ cursor: 'pointer', }); diff --git a/src/app/styles/CustomHtml.css.ts b/src/app/styles/CustomHtml.css.ts index f717669c..ba7b9214 100644 --- a/src/app/styles/CustomHtml.css.ts +++ b/src/app/styles/CustomHtml.css.ts @@ -1,6 +1,7 @@ import { style } from '@vanilla-extract/css'; import { recipe } from '@vanilla-extract/recipes'; import { color, config, DefaultReset, toRem } from 'folds'; +import { ContainerColor } from './ContainerColor.css'; export const MarginSpaced = style({ marginBottom: config.space.S200, @@ -92,11 +93,14 @@ export const CodeBlock = style([ overflow: 'hidden', }, ]); -export const CodeBlockHeader = style({ - padding: `0 ${config.space.S200} 0 ${config.space.S300}`, - borderBottomWidth: config.borderWidth.B300, - gap: config.space.S200, -}); +export const CodeBlockHeader = style([ + ContainerColor({ variant: 'Surface' }), + { + padding: `0 ${config.space.S200} 0 ${config.space.S300}`, + borderBottomWidth: config.borderWidth.B300, + gap: config.space.S200, + }, +]); export const CodeBlockInternal = style([ CodeFont, {