diff --git a/web/chat/chat-message-list.react.js b/web/chat/chat-message-list.react.js
--- a/web/chat/chat-message-list.react.js
+++ b/web/chat/chat-message-list.react.js
@@ -32,6 +32,7 @@
import { useSelector } from '../redux/redux-utils';
import css from './chat-message-list.css';
import { MessageListContext } from './message-list-types';
+import MessageTimestampTooltip from './message-timestamp-tooltip.react';
import Message from './message.react';
import type {
OnMessagePositionWithContainerInfo,
@@ -237,6 +238,17 @@
invariant(inputState, 'InputState should be set');
const messages = messageListData.map(this.renderItem);
+ let tooltip;
+ if (this.state.mouseOverMessagePosition) {
+ const messagePositionInfo = this.state.mouseOverMessagePosition;
+ tooltip = (
+
+ );
+ }
+
let relationshipPrompt;
if (threadInfo) {
relationshipPrompt = ;
@@ -252,6 +264,7 @@
{messages}
+ {tooltip}
);
}
diff --git a/web/chat/message-timestamp-tooltip.css b/web/chat/message-timestamp-tooltip.css
new file mode 100644
--- /dev/null
+++ b/web/chat/message-timestamp-tooltip.css
@@ -0,0 +1,53 @@
+div.messageLeftTooltip:after {
+ top: 7px;
+ right: -14px;
+ border-color: transparent transparent transparent var(--tool-tip-bg);
+}
+div.messageRightTooltip:after {
+ top: 7px;
+ left: -14px;
+ border-color: transparent var(--tool-tip-bg) transparent transparent;
+}
+div.messageTopLeftTooltip:after {
+ bottom: -14px;
+ left: 4px;
+ border-color: var(--tool-tip-bg) transparent transparent transparent;
+}
+div.messageTopRightTooltip:after {
+ bottom: -14px;
+ right: 4px;
+ border-color: var(--tool-tip-bg) transparent transparent transparent;
+}
+div.messageBottomLeftTooltip:after {
+ top: -14px;
+ left: 4px;
+ border-color: transparent transparent var(--tool-tip-bg) transparent;
+}
+div.messageBottomRightTooltip:after {
+ top: -14px;
+ right: 4px;
+ border-color: transparent transparent var(--tool-tip-bg) transparent;
+}
+
+div.messageActionActiveArea {
+ position: absolute;
+ display: flex;
+ top: 0;
+ bottom: 0;
+ align-items: center;
+ padding: 0 12px;
+}
+
+div.viewerMessageActionActiveArea {
+ right: 100%;
+}
+div.nonViewerMessageActiveArea {
+ left: 100%;
+}
+div.messageActionActiveArea > div + div {
+ margin-left: 4px;
+}
+
+div.messageActionLinkIcon:hover {
+ cursor: pointer;
+}
diff --git a/web/chat/message-timestamp-tooltip.react.js b/web/chat/message-timestamp-tooltip.react.js
new file mode 100644
--- /dev/null
+++ b/web/chat/message-timestamp-tooltip.react.js
@@ -0,0 +1,148 @@
+// @flow
+
+import invariant from 'invariant';
+import * as React from 'react';
+
+import { isComposableMessageType } from 'lib/types/message-types';
+import { longAbsoluteDate } from 'lib/utils/date-utils';
+
+import css from './message-timestamp-tooltip.css';
+import type { OnMessagePositionWithContainerInfo } from './position-types';
+import {
+ type TooltipPosition,
+ tooltipPositions,
+ sizeOfTooltipArrow,
+} from './tooltip-utils';
+import {
+ TooltipMenu,
+ type TooltipStyle,
+ TooltipTextItem,
+} from './tooltip.react';
+
+const availablePositionsForComposedViewerMessage = [
+ tooltipPositions.BOTTOM_RIGHT,
+];
+const availablePositionsForNonComposedOrNonViewerMessage = [
+ tooltipPositions.LEFT,
+];
+
+type Props = {
+ +messagePositionInfo: OnMessagePositionWithContainerInfo,
+ +timeZone: ?string,
+};
+function MessageTimestampTooltip(props: Props): React.Node {
+ const { messagePositionInfo, timeZone } = props;
+ const { time, creator, type } = messagePositionInfo.item.messageInfo;
+ console.log(messagePositionInfo);
+
+ const text = React.useMemo(() => longAbsoluteDate(time, timeZone), [
+ time,
+ timeZone,
+ ]);
+ const availableTooltipPositions = React.useMemo(() => {
+ const { isViewer } = creator;
+ const isComposed = isComposableMessageType(type);
+ return isComposed && isViewer
+ ? availablePositionsForComposedViewerMessage
+ : availablePositionsForNonComposedOrNonViewerMessage;
+ }, [creator, type]);
+
+ const { messagePosition, containerPosition } = messagePositionInfo;
+ const pointingToInfo = React.useMemo(() => {
+ return {
+ containerPosition,
+ itemPosition: messagePosition,
+ };
+ }, [messagePosition, containerPosition]);
+
+ const getTooltipStyle = React.useCallback(
+ (tooltipPosition: TooltipPosition) =>
+ getTimestampTooltipStyle(messagePositionInfo, tooltipPosition),
+ [messagePositionInfo],
+ );
+ return (
+
+
+
+ );
+}
+
+function getTimestampTooltipStyle(
+ messagePositionInfo: OnMessagePositionWithContainerInfo,
+ tooltipPosition: TooltipPosition,
+): TooltipStyle {
+ const { messagePosition, containerPosition } = messagePositionInfo;
+ const { height: containerHeight, width: containerWidth } = containerPosition;
+
+ let style, className;
+ if (tooltipPosition === tooltipPositions.LEFT) {
+ const centerOfMessage = messagePosition.top + messagePosition.height / 2;
+ const tooltipPointing = Math.max(
+ Math.min(centerOfMessage, containerHeight),
+ 0,
+ );
+ style = {
+ right: containerWidth - messagePosition.left + sizeOfTooltipArrow,
+ top: tooltipPointing,
+ };
+ className = css.messageLeftTooltip;
+ } else if (tooltipPosition === tooltipPositions.RIGHT) {
+ const centerOfMessage = messagePosition.top + messagePosition.height / 2;
+ const tooltipPointing = Math.max(
+ Math.min(centerOfMessage, containerHeight),
+ 0,
+ );
+ style = {
+ left: messagePosition.right + sizeOfTooltipArrow,
+ top: tooltipPointing,
+ };
+ className = css.messageRightTooltip;
+ } else if (tooltipPosition === tooltipPositions.TOP_LEFT) {
+ const tooltipPointing = Math.min(
+ containerHeight - messagePosition.top,
+ containerHeight,
+ );
+ style = {
+ left: messagePosition.left,
+ bottom: tooltipPointing + sizeOfTooltipArrow,
+ };
+ className = css.messageTopLeftTooltip;
+ } else if (tooltipPosition === tooltipPositions.TOP_RIGHT) {
+ const tooltipPointing = Math.min(
+ containerHeight - messagePosition.top,
+ containerHeight,
+ );
+ style = {
+ right: containerWidth - messagePosition.right,
+ bottom: tooltipPointing + sizeOfTooltipArrow,
+ };
+ className = css.messageTopRightTooltip;
+ } else if (tooltipPosition === tooltipPositions.BOTTOM_LEFT) {
+ const tooltipPointing = Math.min(messagePosition.bottom, containerHeight);
+ style = {
+ left: messagePosition.left,
+ top: tooltipPointing + sizeOfTooltipArrow,
+ };
+ className = css.messageBottomLeftTooltip;
+ } else if (tooltipPosition === tooltipPositions.BOTTOM_RIGHT) {
+ const tooltipPointing = Math.min(messagePosition.bottom, containerHeight);
+ style = {
+ right: containerWidth - messagePosition.right,
+ top: tooltipPointing + sizeOfTooltipArrow,
+ };
+ className = css.messageBottomRightTooltip;
+ console.log(`container height:${containerHeight}`);
+ }
+ invariant(
+ className && style,
+ `${tooltipPosition} is not valid for timestamp tooltip`,
+ );
+ return { className, style };
+}
+
+export default MessageTimestampTooltip;
diff --git a/web/chat/message-tooltip.css b/web/chat/message-tooltip.css
--- a/web/chat/message-tooltip.css
+++ b/web/chat/message-tooltip.css
@@ -9,24 +9,6 @@
width: fit-content;
}
-div.timestampContainer {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: center;
- padding: 0 6px;
- margin-top: 6px;
- background-color: var(--message-action-tooltip-bg);
- border-radius: 8px;
- color: var(--tool-tip-color);
-}
-
-div.timestampContainer p {
- white-space: nowrap;
- padding: 5px;
- font-size: var(--s-font-14);
-}
-
div.messageActionButtons {
display: flex;
font-size: 16px;
diff --git a/web/chat/message-tooltip.react.js b/web/chat/message-tooltip.react.js
--- a/web/chat/message-tooltip.react.js
+++ b/web/chat/message-tooltip.react.js
@@ -7,10 +7,8 @@
import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors';
import { useSidebarExistsOrCanBeCreated } from 'lib/shared/thread-utils';
import type { ThreadInfo } from 'lib/types/thread-types';
-import { longAbsoluteDate } from 'lib/utils/date-utils';
import type { InputState } from '../input/input-state';
-import { useSelector } from '../redux/redux-utils';
import {
useOnClickThread,
useOnClickPendingSidebar,
@@ -190,12 +188,6 @@
);
}
- const timezone = useSelector(state => state.timeZone);
- const timestampText = React.useMemo(
- () => longAbsoluteDate(messageInfo.time, timezone),
- [messageInfo.time, timezone],
- );
-
const { isViewer } = messageInfo.creator;
const messageActionButtonsContainerClassName = classNames({
[css.messageActionContainer]: true,
@@ -209,9 +201,6 @@
{sidebarButton}
{replyButton}
-
);
}