add style for comments with is_pinned=true

This commit is contained in:
Sean Yesmunt 2020-10-08 11:31:36 -04:00
parent d808d91e72
commit 761b93d811
7 changed files with 66 additions and 6 deletions

View file

@ -11,6 +11,7 @@ declare type Comment = {
signing_ts?: string, // timestamp used when signing this comment signing_ts?: string, // timestamp used when signing this comment
is_channel_signature_valid?: boolean, // whether or not the signature could be validated is_channel_signature_valid?: boolean, // whether or not the signature could be validated
parent_id?: number, // comment_id of comment this is in reply to parent_id?: number, // comment_id of comment this is in reply to
is_pinned: boolean,
}; };
// todo: relate individual comments to their commentId // todo: relate individual comments to their commentId

View file

@ -4,6 +4,7 @@ import * as PAGES from 'constants/pages';
import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field'; import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field';
import { SITE_NAME, SIMPLE_SITE, ENABLE_COMMENT_REACTIONS } from 'config'; import { SITE_NAME, SIMPLE_SITE, ENABLE_COMMENT_REACTIONS } from 'config';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { parseURI } from 'lbry-redux';
import { isEmpty } from 'util/object'; import { isEmpty } from 'util/object';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import Button from 'component/button'; import Button from 'component/button';
@ -43,6 +44,7 @@ type Props = {
doToast: ({ message: string }) => void, doToast: ({ message: string }) => void,
isTopLevel?: boolean, isTopLevel?: boolean,
threadDepth: number, threadDepth: number,
isPinned: boolean,
}; };
const LENGTH_TO_COLLAPSE = 300; const LENGTH_TO_COLLAPSE = 300;
@ -71,10 +73,12 @@ function Comment(props: Props) {
doToast, doToast,
isTopLevel, isTopLevel,
threadDepth, threadDepth,
isPinned,
} = props; } = props;
const { const {
push, push,
location: { pathname }, replace,
location: { pathname, search },
} = useHistory(); } = useHistory();
const [isReplying, setReplying] = React.useState(false); const [isReplying, setReplying] = React.useState(false);
const [isEditing, setEditing] = useState(false); const [isEditing, setEditing] = useState(false);
@ -84,11 +88,17 @@ function Comment(props: Props) {
const [mouseIsHovering, setMouseHover] = useState(false); const [mouseIsHovering, setMouseHover] = useState(false);
const [advancedEditor] = usePersistedState('comment-editor-mode', false); const [advancedEditor] = usePersistedState('comment-editor-mode', false);
const hasChannels = myChannels && myChannels.length > 0; const hasChannels = myChannels && myChannels.length > 0;
// to debounce subsequent requests // to debounce subsequent requests
const shouldFetch = const shouldFetch =
channel === undefined || channel === undefined ||
(channel !== null && channel.value_type === 'channel' && isEmpty(channel.meta) && !pending); (channel !== null && channel.value_type === 'channel' && isEmpty(channel.meta) && !pending);
let channelOwnerOfContent;
try {
const { channelName } = parseURI(uri);
if (channelName) {
channelOwnerOfContent = channelName;
}
} catch (e) {}
useEffect(() => { useEffect(() => {
// If author was extracted from the URI, then it must be valid. // If author was extracted from the URI, then it must be valid.
@ -133,18 +143,28 @@ function Comment(props: Props) {
} }
} }
function handleTimeClick() {
const urlParams = new URLSearchParams(search);
urlParams.delete('lc');
urlParams.append('lc', commentId);
replace(`${pathname}?${urlParams.toString()}`);
}
return ( return (
<li <li
className={classnames('comment', { className={classnames('comment', {
'comment--top-level': isTopLevel, 'comment--top-level': isTopLevel,
'comment--reply': !isTopLevel, 'comment--reply': !isTopLevel,
'comment--highlighted': linkedComment && linkedComment.comment_id === commentId,
})} })}
id={commentId} id={commentId}
onMouseOver={() => setMouseHover(true)} onMouseOver={() => setMouseHover(true)}
onMouseOut={() => setMouseHover(false)} onMouseOut={() => setMouseHover(false)}
> >
<div className="comment__content"> <div
className={classnames('comment__content', {
'comment--highlighted': linkedComment && linkedComment.comment_id === commentId,
})}
>
<div className="comment__author-thumbnail"> <div className="comment__author-thumbnail">
{authorUri ? ( {authorUri ? (
<ChannelThumbnail uri={authorUri} obscure={channelIsBlocked} small /> <ChannelThumbnail uri={authorUri} obscure={channelIsBlocked} small />
@ -167,9 +187,18 @@ function Comment(props: Props) {
)} )}
<Button <Button
className="comment__time" className="comment__time"
navigate={`${uri}?lc=${commentId}`} onClick={handleTimeClick}
label={<DateTime date={timePosted} timeAgo />} label={<DateTime date={timePosted} timeAgo />}
/> />
{isPinned && (
<span className="comment__pin">
<Icon icon={ICONS.PIN} />
{channelOwnerOfContent
? __('Pinned by @%channel%', { channel: channelOwnerOfContent })
: __('Pinned by creator')}
</span>
)}
</div> </div>
<div className="comment__menu"> <div className="comment__menu">
<Menu> <Menu>

View file

@ -216,6 +216,7 @@ function CommentList(props: Props) {
claimIsMine={claimIsMine} claimIsMine={claimIsMine}
commentIsMine={comment.channel_id && isMyComment(comment.channel_id)} commentIsMine={comment.channel_id && isMyComment(comment.channel_id)}
linkedComment={linkedComment} linkedComment={linkedComment}
isPinned={comment.is_pinned}
/> />
); );
})} })}

View file

@ -892,4 +892,22 @@ export const icons = {
</g> </g>
</svg> </svg>
), ),
[ICONS.PIN]: (props: CustomProps) => (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
viewBox="-6 -5 26 24"
width={props.size || '18'}
height={props.size || '18'}
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M11.3333333,6 C11.3333333,8.94666667 8.94666667,11.3333333 6,11.3333333 C3.056,11.3333333 0.666666667,8.94666667 0.666666667,6 C0.666666667,3.05466667 3.056,0.666666667 6,0.666666667 C8.94666667,0.666666667 11.3333333,3.05466667 11.3333333,6 L11.3333333,6 Z" />
<line x1="6" y1="11.3333333" x2="6" y2="23.3333333" />
<path d="M6,3.33333333 C7.47333333,3.33333333 8.66666667,4.528 8.66666667,6" />
</svg>
),
}; };

View file

@ -124,3 +124,4 @@ export const FIRE_ACTIVE = 'FireActive';
export const SLIME_ACTIVE = 'SlimeActive'; export const SLIME_ACTIVE = 'SlimeActive';
export const FIRE = 'Fire'; export const FIRE = 'Fire';
export const SLIME = 'Slime'; export const SLIME = 'Slime';
export const PIN = 'Pin';

View file

@ -127,7 +127,7 @@ $thumbnailWidthSmall: 0rem;
.comment--highlighted { .comment--highlighted {
background: var(--color-comment-highlighted); background: var(--color-comment-highlighted);
box-shadow: 0 0 0 var(--spacing-xs) var(--color-comment-highlighted); box-shadow: 0 0 0 5px var(--color-comment-highlighted);
border-radius: 4px; border-radius: 4px;
} }
@ -151,6 +151,10 @@ $thumbnailWidthSmall: 0rem;
height: 100%; height: 100%;
} }
.comment__pin {
margin-left: var(--spacing-s);
}
.comment__message { .comment__message {
word-break: break-word; word-break: break-word;
max-width: 35rem; max-width: 35rem;

View file

@ -20,6 +20,12 @@ export function sortComments(sortProps: SortProps): Array<Comment> {
} }
return comments.slice().sort((a: Comment, b: Comment) => { return comments.slice().sort((a: Comment, b: Comment) => {
if (a.is_pinned) {
return -1;
} else if (b.is_pinned) {
return 1;
}
if (sort === SORT_COMMENTS_NEW) { if (sort === SORT_COMMENTS_NEW) {
return 0; return 0;
} }