Skip to content
30 changes: 18 additions & 12 deletions web/libs/editor/src/components/Comments/Comment/CommentForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { LINK_COMMENT_MODE } from "../../../stores/Annotation/LinkingModes";
import { CommentBase } from "../../../stores/Comment/Comment";
import { TextArea } from "../../../common/TextArea/TextArea";
import type { ActionRefValue } from "../../../common/TextArea/TextArea";
import { Block, Elem } from "../../../utils/bem";
import { cn } from "../../../utils/bem";
import { FF_DEV_3873, isFF } from "../../../utils/feature-flags";

import { LinkState } from "./LinkState";
Expand Down Expand Up @@ -148,8 +148,12 @@ export const CommentForm: FC<CommentFormProps> = observer(({ commentStore, annot
);

return (
<Block ref={formRef} tag="form" name="comment-form-new" mod={{ inline, linked: !!region }} onSubmit={onSubmit}>
<Elem name="text-row">
<form
ref={formRef as any}
className={cn("comment-form-new").mod({ inline, linked: !!region }).toClassName()}
onSubmit={onSubmit}
>
<div className={cn("comment-form-new").elem("text-row").toClassName()}>
<TextArea
actionRef={actionRef}
name="comment"
Expand All @@ -164,27 +168,29 @@ export const CommentForm: FC<CommentFormProps> = observer(({ commentStore, annot
{classificationsItems.length === 0 && (
<CommentFormButtons region={region} linking={linking} onLinkTo={linkToHandler} />
)}
</Elem>
</div>
{classificationsItems.length > 0 && (
<Elem name="classifications-row">
<Elem name="category-selector">
<div className={cn("comment-form-new").elem("classifications-row").toClassName()}>
<div className={cn("comment-form-new").elem("category-selector").toClassName()}>
<Taxonomy
selected={selections}
items={classificationsItems}
onChange={taxonomyOnChange}
options={COMMENT_TAXONOMY_OPTIONS}
defaultSearch={false}
/>
</Elem>
</div>
<CommentFormButtons region={region} linking={linking} onLinkTo={linkToHandler} />
</Elem>
</div>
)}
{hasLinkState && (
<Elem name="link-state">
<div className={cn("comment-form-new").elem("link-state").toClassName()}>
<LinkState linking={linking} region={region} result={result} onUnlink={currentComment?.unsetLink} />
</Elem>
</div>
)}
{commentStore.tooltipMessage && <Elem name="tooltipMessage">{commentStore.tooltipMessage}</Elem>}
</Block>
{commentStore.tooltipMessage && (
<div className={cn("comment-form-new").elem("tooltipMessage").toClassName()}>{commentStore.tooltipMessage}</div>
)}
</form>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,30 @@ import type { MouseEventHandler } from "react";

import { IconCommentLinkTo, IconSend } from "@humansignal/icons";
import { Tooltip } from "@humansignal/ui";
import { Block, Elem } from "../../../utils/bem";
import { cn } from "../../../utils/bem";
import "./CommentFormButtons.scss";

export const CommentFormButtons = ({
region,
linking,
onLinkTo,
}: { region: any; linking: boolean; onLinkTo?: MouseEventHandler<HTMLElement> }) => (
<Block name="comment-form-buttons">
<Elem name="buttons">
<div className={cn("comment-form-buttons").toClassName()}>
<div className={cn("comment-form-buttons").elem("buttons").toClassName()}>
{onLinkTo && !region && (
<Tooltip title="Link to...">
<Elem name="action" tag="button" mod={{ highlight: linking }} onClick={onLinkTo}>
<button
type="button"
className={cn("comment-form-buttons").elem("action").mod({ highlight: linking }).toClassName()}
onClick={onLinkTo}
>
<IconCommentLinkTo />
</Elem>
</button>
</Tooltip>
)}
<Elem name="action" tag="button" type="submit">
<button type="submit" className={cn("comment-form-buttons").elem("action").toClassName()}>
<IconSend />
</Elem>
</Elem>
</Block>
</button>
</div>
</div>
);
70 changes: 34 additions & 36 deletions web/libs/editor/src/components/Comments/Comment/CommentItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Button } from "@humansignal/ui";
import { Dropdown } from "../../../common/Dropdown/Dropdown";
import { Menu } from "../../../common/Menu/Menu";
import { Space } from "../../../common/Space/Space";
import { Block, Elem } from "../../../utils/bem";
import { cn } from "../../../utils/bem";
import { humanDateDiff, userDisplayName } from "../../../utils/utilities";
import { CommentFormBase } from "../CommentFormBase";
import { CommentsContext } from "./CommentsList";
Expand Down Expand Up @@ -144,71 +144,69 @@ export const CommentItem: FC<CommentItemProps> = observer(

if (isPersisted && time)
return (
<Elem name="date">
<div className={cn("comment-item").elem("date").toClassName()}>
<Tooltip alignment="top-right" title={new Date(time).toLocaleString()}>
<span>{`${isEdited ? "updated" : ""} ${humanDateDiff(time)}`}</span>
</Tooltip>
</Elem>
</div>
);
return null;
};

return (
<Block
name="comment-item"
mod={{ resolved, highlighted: isHighlighted }}
<div
className={cn("comment-item").mod({ resolved, highlighted: isHighlighted }).toClassName()}
onMouseEnter={() => {
setHighlighted(true);
}}
onMouseLeave={() => {
setHighlighted(false);
}}
ref={_commentRef}
ref={_commentRef as any}
>
<Space spread size="medium" truncated>
<Space size="small" truncated>
<Elem
tag={Userpic}
<Userpic
className={cn("comment-item").elem("userpic").toClassName()}
user={hiddenUser ?? createdBy}
name="userpic"
showUsernameTooltip
showUsername
username={createdBy}
/>
<Elem name="name" tag="span">
<span className={cn("comment-item").elem("name").toClassName()}>
{userDisplayName(hiddenUser ?? createdBy)}
</Elem>
</span>
</Space>

<Space size="small">
<Elem name="resolved" component={IconCheck} />
<Elem name="saving" mod={{ hide: isPersisted }}>
<Elem name="dot" />
</Elem>
<IconCheck className={cn("comment-item").elem("resolved").toClassName()} />
<div className={cn("comment-item").elem("saving").mod({ hide: isPersisted }).toClassName()}>
<div className={cn("comment-item").elem("dot").toClassName()} />
</div>
{!infoIsHidden && <TimeTracker />}
</Space>
</Space>

<Elem name="content">
<Elem name="text">
<div className={cn("comment-item").elem("content").toClassName()}>
<div className={cn("comment-item").elem("text").toClassName()}>
{isEditMode ? (
<>
<CommentFormBase value={text} onSubmit={commentFormBaseOnSubmit} classifications={classifications} />
{classificationsItems.length > 0 && (
<Elem name="classifications-row">
<div className={cn("comment-item").elem("classifications-row").toClassName()}>
<Taxonomy
selected={taxonomySelectedItems}
items={classificationsItems}
onChange={taxonomyOnChange}
options={COMMENT_TAXONOMY_OPTIONS}
defaultSearch={false}
/>
</Elem>
</div>
)}
</>
) : isConfirmDelete ? (
<Elem name="confirmForm">
<Elem name="question">Are you sure?</Elem>
<Elem name="controls">
<div className={cn("comment-item").elem("confirmForm").toClassName()}>
<div className={cn("comment-item").elem("question").toClassName()}>Are you sure?</div>
<div className={cn("comment-item").elem("controls").toClassName()}>
<Button
onClick={() => deleteComment()}
size="small"
Expand All @@ -221,29 +219,29 @@ export const CommentItem: FC<CommentItemProps> = observer(
<Button onClick={() => setConfirmMode(false)} size="small" aria-label="Cancel delete">
No
</Button>
</Elem>
</Elem>
</div>
</div>
) : (
<>
{classifications?.default?.values?.length > 0 && (
<Elem name="classifications" tag="ul">
<ul className={cn("comment-item").elem("classifications").toClassName()}>
{classifications?.default?.values?.map((valueArray: string[], index: number) => (
<li key={index}>{valueArray.join("/")}</li>
))}
</Elem>
</ul>
)}
{text}
{hasLinkState && (
<Elem name="linkState">
<div className={cn("comment-item").elem("linkState").toClassName()}>
<LinkState linking={linking} region={region} result={result} interactive />
</Elem>
</div>
)}
</>
)}
</Elem>
</div>

<Elem
name="actions"
<div
className={cn("comment-item").elem("actions").toClassName()}
onClick={(e: any) => {
e.stopPropagation();
e.preventDefault();
Expand Down Expand Up @@ -286,9 +284,9 @@ export const CommentItem: FC<CommentItemProps> = observer(
<Button size="small" look="string" icon={<IconEllipsis />} aria-label="Comment options" />
</Dropdown.Trigger>
)}
</Elem>
</Elem>
</Block>
</div>
</div>
</div>
);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createContext, type FC, useCallback, useMemo } from "react";
import { observer } from "mobx-react";

import { LINK_COMMENT_MODE } from "../../../stores/Annotation/LinkingModes";
import { Block } from "../../../utils/bem";
import { cn } from "../../../utils/bem";
import { CommentItem } from "./CommentItem";

export type CommentContextType = {
Expand Down Expand Up @@ -39,7 +39,7 @@ export const CommentsList: FC<{ commentStore: any }> = observer(({ commentStore

export const CommentsListInner: FC<{ commentStore: any }> = observer(({ commentStore }) => {
return (
<Block name="comments-list">
<div className={cn("comments-list").toClassName()}>
{commentStore.comments.map((comment: any) => (
<CommentItem
key={comment.id}
Expand All @@ -48,6 +48,6 @@ export const CommentsListInner: FC<{ commentStore: any }> = observer(({ commentS
classificationsItems={commentStore.commentClassificationsItems}
/>
))}
</Block>
</div>
);
});
47 changes: 25 additions & 22 deletions web/libs/editor/src/components/Comments/Comment/LinkState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import chroma from "chroma-js";
import { Button } from "@humansignal/ui";
import { IconCommentLinkTo, IconClose } from "@humansignal/icons";
import { Block, Elem } from "../../../utils/bem";
import { cn } from "../../../utils/bem";
import { NodeIcon } from "../../Node/Node";
import { RegionLabel } from "../../SidePanels/OutlinerPanel/RegionLabel";

Expand All @@ -26,13 +26,13 @@ export const LinkState: FC<LinkStateProps> = ({ linking, region, result, onUnlin
}, [linking, region]);
if (!isVisible) return null;
return (
<Block tag="div" name="link-state" mod={mod}>
<Elem tag="div" name="prefix">
<div className={cn("link-state").mod(mod).toClassName()}>
<div className={cn("link-state").elem("prefix").toClassName()}>
<IconCommentLinkTo />
</Elem>
</div>
{mod?.action && "Select an object to link it to this comment."}
{mod?.display && <LinkedRegion region={region} result={result} onUnlink={onUnlink} interactive={interactive} />}
</Block>
</div>
);
};

Expand Down Expand Up @@ -72,36 +72,39 @@ const LinkedRegion: FC<LinkedRegionProps> = observer(({ region, result, interact
}, [itemColor]);

return (
<Block
name="link-state-region"
mod={{ interactive }}
style={style}
<div
className={cn("link-state-region").mod({ interactive }).toClassName()}
style={style as any}
onMouseEnter={mouseEnterHandler}
onMouseLeave={mouseLeaveHandler}
onClick={clickHandler}
>
{!isClassification && (
<>
<Elem name="icon">
<div className={cn("link-state-region").elem("icon").toClassName()}>
<NodeIcon node={region} />
</Elem>
<Elem name="index">{region.region_index}</Elem>
</div>
<div className={cn("link-state-region").elem("index").toClassName()}>{region.region_index}</div>
</>
)}
{result ? (
<Elem name="title">
<div className={cn("link-state-region").elem("title").toClassName()}>
<ResultText result={result} />
</Elem>
</div>
) : (
<Elem name="title">
<Elem name="label">
<div className={cn("link-state-region").elem("title").toClassName()}>
<div className={cn("link-state-region").elem("label").toClassName()}>
<RegionLabel item={region} />
</Elem>
{region?.text && <Elem name="text">{region.text.replace(/\\n/g, "\n")}</Elem>}
</Elem>
</div>
{region?.text && (
<div className={cn("link-state-region").elem("text").toClassName()}>
{region.text.replace(/\\n/g, "\n")}
</div>
)}
</div>
)}
{onUnlink && (
<Elem name="close">
<div className={cn("link-state-region").elem("close").toClassName()}>
<Button
size="small"
variant="neutral"
Expand All @@ -110,9 +113,9 @@ const LinkedRegion: FC<LinkedRegionProps> = observer(({ region, result, interact
onClick={onUnlink}
aria-label="Unlink comment"
/>
</Elem>
</div>
)}
</Block>
</div>
);
});

Expand Down
Loading
Loading