mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-04 22:40:29 +03:00
Add arrow to message bubbles and improve spacing (#2474)
Some checks failed
Deploy to Netlify (dev) / Deploy to Netlify (push) Has been cancelled
Some checks failed
Deploy to Netlify (dev) / Deploy to Netlify (push) Has been cancelled
* Add arrow to message bubbles and improve spacing * make bubble message avatar smaller * add bubble layout for event content * adjust bubble arrow * fix missing return statement for event content * hide bubble for event content * add new arrow to bubble message * fix avatar username relative alignment * fix types * fix code block header background * revert avatar size and make arrow less sharp * show event messages timestamp to right when bubble is hidden * fix avatar base css * move message header outside bubble * fix event time appears on left in hidden bubles
This commit is contained in:
parent
31efbf73b7
commit
afc251aa7c
6 changed files with 111 additions and 27 deletions
|
|
@ -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
|
|||
</Box>
|
||||
);
|
||||
|
||||
return messageLayout === MessageLayout.Compact ? (
|
||||
<CompactLayout before={beforeJSX}>{msgContentJSX}</CompactLayout>
|
||||
) : (
|
||||
<ModernLayout before={beforeJSX}>{msgContentJSX}</ModernLayout>
|
||||
);
|
||||
if (messageLayout === MessageLayout.Compact) {
|
||||
return <CompactLayout before={beforeJSX}>{msgContentJSX}</CompactLayout>;
|
||||
}
|
||||
if (messageLayout === MessageLayout.Bubble) {
|
||||
return (
|
||||
<BubbleLayout hideBubble before={beforeJSX}>
|
||||
{msgContentJSX}
|
||||
</BubbleLayout>
|
||||
);
|
||||
}
|
||||
return <ModernLayout before={beforeJSX}>{msgContentJSX}</ModernLayout>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<svg
|
||||
className={css.BubbleLeftArrow}
|
||||
width="9"
|
||||
height="8"
|
||||
viewBox="0 0 9 8"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M9.00004 8V0H4.82847C3.04666 0 2.15433 2.15428 3.41426 3.41421L8.00004 8H9.00004Z"
|
||||
fill={color[variant].Container}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
type BubbleLayoutProps = {
|
||||
hideBubble?: boolean;
|
||||
before?: ReactNode;
|
||||
header?: ReactNode;
|
||||
};
|
||||
|
||||
export const BubbleLayout = as<'div', BubbleLayoutProps>(({ before, children, ...props }, ref) => (
|
||||
<Box gap="300" {...props} ref={ref}>
|
||||
<Box className={css.BubbleBefore} shrink="No">
|
||||
{before}
|
||||
export const BubbleLayout = as<'div', BubbleLayoutProps>(
|
||||
({ hideBubble, before, header, children, ...props }, ref) => (
|
||||
<Box gap="300" {...props} ref={ref}>
|
||||
<Box className={css.BubbleBefore} shrink="No">
|
||||
{before}
|
||||
</Box>
|
||||
<Box grow="Yes" direction="Column">
|
||||
{header}
|
||||
{hideBubble ? (
|
||||
children
|
||||
) : (
|
||||
<Box>
|
||||
<Box
|
||||
className={
|
||||
hideBubble
|
||||
? undefined
|
||||
: classNames(css.BubbleContent, before ? css.BubbleContentArrowLeft : undefined)
|
||||
}
|
||||
direction="Column"
|
||||
>
|
||||
{before ? <BubbleLeftArrow variant="SurfaceVariant" /> : null}
|
||||
{children}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box className={css.BubbleContent} direction="Column">
|
||||
{children}
|
||||
</Box>
|
||||
</Box>
|
||||
));
|
||||
)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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 && (
|
||||
<AvatarBase>
|
||||
<AvatarBase
|
||||
className={messageLayout === MessageLayout.Bubble ? css.BubbleAvatarBase : undefined}
|
||||
>
|
||||
<Avatar
|
||||
className={css.MessageAvatar}
|
||||
as="button"
|
||||
|
|
@ -875,7 +878,9 @@ export const Message = as<'div', MessageProps>(
|
|||
|
||||
return (
|
||||
<MessageBase
|
||||
className={classNames(css.MessageBase, className)}
|
||||
className={classNames(css.MessageBase, className, {
|
||||
[css.MessageBaseBubbleCollapsed]: messageLayout === MessageLayout.Bubble && collapse,
|
||||
})}
|
||||
tabIndex={0}
|
||||
space={messageSpacing}
|
||||
collapse={collapse}
|
||||
|
|
@ -1132,8 +1137,7 @@ export const Message = as<'div', MessageProps>(
|
|||
</CompactLayout>
|
||||
)}
|
||||
{messageLayout === MessageLayout.Bubble && (
|
||||
<BubbleLayout before={avatarJSX} onContextMenu={handleContextMenu}>
|
||||
{headerJSX}
|
||||
<BubbleLayout before={avatarJSX} header={headerJSX} onContextMenu={handleContextMenu}>
|
||||
{msgContentJSX}
|
||||
</BubbleLayout>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue