forked from github/cinny
🦉 additional reaction chip left
This commit is contained in:
@@ -79,6 +79,7 @@ import { MemberPowerTag, StateEvent } from '../../../../types/matrix/room';
|
|||||||
import { PowerIcon } from '../../../components/power';
|
import { PowerIcon } from '../../../components/power';
|
||||||
import colorMXID from '../../../../util/colorMXID';
|
import colorMXID from '../../../../util/colorMXID';
|
||||||
import { getPowerTagIconSrc } from '../../../hooks/useMemberPowerTag';
|
import { getPowerTagIconSrc } from '../../../hooks/useMemberPowerTag';
|
||||||
|
import { AddReactionButton } from '../../../../owl/components/AddReactionButton';
|
||||||
|
|
||||||
export type ReactionHandler = (keyOrMxc: string, shortcode: string) => void;
|
export type ReactionHandler = (keyOrMxc: string, shortcode: string) => void;
|
||||||
|
|
||||||
@@ -813,6 +814,15 @@ export const Message = as<'div', MessageProps>(
|
|||||||
</AvatarBase>
|
</AvatarBase>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const visibleReactions = relations?.getSortedAnnotationsByKey();
|
||||||
|
const hasVisibleReactions = !!visibleReactions && visibleReactions.some(
|
||||||
|
([key, events]) => typeof key === 'string' && Array.from(events).length > 0
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleInlineAddReaction: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
||||||
|
setEmojiBoardAnchor(evt.currentTarget.getBoundingClientRect());
|
||||||
|
};
|
||||||
|
|
||||||
const msgContentJSX = (
|
const msgContentJSX = (
|
||||||
<Box direction="Column" alignSelf="Start" style={{ maxWidth: '100%' }}>
|
<Box direction="Column" alignSelf="Start" style={{ maxWidth: '100%' }}>
|
||||||
{reply}
|
{reply}
|
||||||
@@ -831,7 +841,11 @@ export const Message = as<'div', MessageProps>(
|
|||||||
) : (
|
) : (
|
||||||
children
|
children
|
||||||
)}
|
)}
|
||||||
{reactions}
|
{reactions && React.isValidElement(reactions)
|
||||||
|
? React.cloneElement(reactions as React.ReactElement<any>, {
|
||||||
|
onAddReaction: handleInlineAddReaction,
|
||||||
|
})
|
||||||
|
: reactions}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1129,6 +1143,11 @@ export const Message = as<'div', MessageProps>(
|
|||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{!edit && collapse && canSendReaction && !hasVisibleReactions
|
||||||
|
&& messageLayout !== MessageLayout.Compact
|
||||||
|
&& (hover || !!emojiBoardAnchor) && (
|
||||||
|
<AddReactionButton onClick={handleInlineAddReaction} ghost />
|
||||||
|
)}
|
||||||
{messageLayout === MessageLayout.Compact && (
|
{messageLayout === MessageLayout.Compact && (
|
||||||
<CompactLayout before={headerJSX} onContextMenu={handleContextMenu}>
|
<CompactLayout before={headerJSX} onContextMenu={handleContextMenu}>
|
||||||
{msgContentJSX}
|
{msgContentJSX}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import * as css from './styles.css';
|
|||||||
import { ReactionViewer } from '../reaction-viewer';
|
import { ReactionViewer } from '../reaction-viewer';
|
||||||
import { stopPropagation } from '../../../utils/keyboard';
|
import { stopPropagation } from '../../../utils/keyboard';
|
||||||
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
|
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
|
||||||
|
import { AddReactionButton } from '../../../../owl/components/AddReactionButton';
|
||||||
|
|
||||||
export type ReactionsProps = {
|
export type ReactionsProps = {
|
||||||
room: Room;
|
room: Room;
|
||||||
@@ -30,9 +31,10 @@ export type ReactionsProps = {
|
|||||||
canSendReaction?: boolean;
|
canSendReaction?: boolean;
|
||||||
relations: Relations;
|
relations: Relations;
|
||||||
onReactionToggle: (targetEventId: string, key: string, shortcode?: string) => void;
|
onReactionToggle: (targetEventId: string, key: string, shortcode?: string) => void;
|
||||||
|
onAddReaction?: MouseEventHandler<HTMLButtonElement>;
|
||||||
};
|
};
|
||||||
export const Reactions = as<'div', ReactionsProps>(
|
export const Reactions = as<'div', ReactionsProps>(
|
||||||
({ className, room, relations, mEventId, canSendReaction, onReactionToggle, ...props }, ref) => {
|
({ className, room, relations, mEventId, canSendReaction, onReactionToggle, onAddReaction, ...props }, ref) => {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
const [viewer, setViewer] = useState<boolean | string>(false);
|
const [viewer, setViewer] = useState<boolean | string>(false);
|
||||||
@@ -41,6 +43,9 @@ export const Reactions = as<'div', ReactionsProps>(
|
|||||||
relations,
|
relations,
|
||||||
useCallback((rel) => [...(rel.getSortedAnnotationsByKey() ?? [])], [])
|
useCallback((rel) => [...(rel.getSortedAnnotationsByKey() ?? [])], [])
|
||||||
);
|
);
|
||||||
|
const visibleCount = reactions.filter(
|
||||||
|
([key, events]) => typeof key === 'string' && Array.from(events).length > 0
|
||||||
|
).length;
|
||||||
|
|
||||||
const handleViewReaction: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
const handleViewReaction: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
@@ -94,7 +99,10 @@ export const Reactions = as<'div', ReactionsProps>(
|
|||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{reactions.length > 0 && (
|
{visibleCount > 0 && canSendReaction && onAddReaction && (
|
||||||
|
<AddReactionButton onClick={onAddReaction} />
|
||||||
|
)}
|
||||||
|
{visibleCount > 0 && (
|
||||||
<Overlay
|
<Overlay
|
||||||
onContextMenu={(evt: any) => {
|
onContextMenu={(evt: any) => {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
|
|||||||
23
src/owl/components/AddReactionButton.tsx
Normal file
23
src/owl/components/AddReactionButton.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import React, { MouseEventHandler } from 'react';
|
||||||
|
import { Box, Icon, Icons } from 'folds';
|
||||||
|
import * as css from '../styles/reactions.css';
|
||||||
|
|
||||||
|
type AddReactionButtonProps = {
|
||||||
|
onClick: MouseEventHandler<HTMLButtonElement>;
|
||||||
|
ghost?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AddReactionButton({ onClick, ghost }: AddReactionButtonProps) {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
as="button"
|
||||||
|
className={ghost ? css.AddReactionGhost : css.AddReactionChip}
|
||||||
|
alignItems="Center"
|
||||||
|
justifyContent="Center"
|
||||||
|
shrink="No"
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
<Icon src={Icons.SmilePlus} size="50" />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
41
src/owl/styles/reactions.css.ts
Normal file
41
src/owl/styles/reactions.css.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { style } from '@vanilla-extract/css';
|
||||||
|
import { DefaultReset, FocusOutline, color, config, toRem } from 'folds';
|
||||||
|
|
||||||
|
const addReactionBase = {
|
||||||
|
padding: `${toRem(2)} ${config.space.S200}`,
|
||||||
|
backgroundColor: color.SurfaceVariant.Container,
|
||||||
|
border: `${config.borderWidth.B300} solid ${color.SurfaceVariant.ContainerLine}`,
|
||||||
|
borderRadius: config.radii.R300,
|
||||||
|
cursor: 'pointer',
|
||||||
|
selectors: {
|
||||||
|
'&:hover, &:focus-visible': {
|
||||||
|
backgroundColor: color.SurfaceVariant.ContainerHover,
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
'&:active': {
|
||||||
|
backgroundColor: color.SurfaceVariant.ContainerActive,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const AddReactionChip = style([
|
||||||
|
DefaultReset,
|
||||||
|
FocusOutline,
|
||||||
|
{
|
||||||
|
...addReactionBase,
|
||||||
|
opacity: 0.6,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const AddReactionGhost = style([
|
||||||
|
DefaultReset,
|
||||||
|
FocusOutline,
|
||||||
|
{
|
||||||
|
...addReactionBase,
|
||||||
|
position: 'absolute',
|
||||||
|
left: config.space.S400,
|
||||||
|
bottom: config.space.S100,
|
||||||
|
opacity: 0.5,
|
||||||
|
zIndex: 1,
|
||||||
|
},
|
||||||
|
]);
|
||||||
Reference in New Issue
Block a user