Implement low-hanging-fruit feed card comment frontend tweaks (#19416)

This commit is contained in:
Ben Halpern 2023-05-04 08:29:32 -04:00 committed by GitHub
parent 5faae0bb6d
commit cb2c200404
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 204 additions and 37 deletions

View file

@ -2,7 +2,11 @@
.crayons-comment {
font-size: var(--fs-s);
padding: var(--su-2) var(--su-3);
padding-bottom: var(--su-3);
display: flex;
align-items: flex-start;
padding-left: var(--su-3);
margin-right: var(--su-3);
&__meta {
display: flex;
@ -14,11 +18,60 @@
}
}
&__metainner {
color: var(--base-80);
margin-bottom: var(--su-1);
}
&__body {
padding-left: var(--su-7);
max-height: 310px;
overflow: hidden;
position: relative;
width: 100%;
background: var(--card-tertiary-bg);
&:hover {
background: var(--card-tertiary-bg-hover);
}
border-radius: var(--radius);
padding: var(--su-4);
padding-bottom: var(--su-1);
.crayons-comment__inner {
.c-embed {
padding-top: var(--su-3);
padding-bottom: var(--su-1);
}
.c-embed__cover {
display: none;
}
.c-embed__body {
font-size: var(--fs-s);
}
div:not(.crayons-comment__readmore) {
margin-bottom: var(--su-3);
background: var(--card-secondary-bg);
}
.liquid-comment .body {
:not(:first-child) {
display: none;
}
}
}
.crayons-comment__readmore {
color: var(--base-80);
font-weight: var(--fw-medium);
margin-bottom: var(--su-1);
margin-top: -3px;
padding-bottom: var(--su-1);
}
img {
max-height: 130px;
border-radius: var(--radius);
max-width: 220px;
}
iframe {
max-height: 240px;
border-radius: var(--radius);
border: 0;
}
a:hover {
text-decoration: underline; //todo: default for all in-content links
@ -42,19 +95,6 @@
margin: var(--su-1) auto;
font-size: 90%; // little adjustment for feed comments since default monospace font looks really tiny there.
}
&::after {
content: '';
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background: linear-gradient(
var(--story-comments-bg-top) 250px,
var(--story-comments-bg-bottom)
);
}
}
& + & {

View file

@ -217,18 +217,19 @@
&__comments {
cursor: default;
background: var(--story-comments-bg);
border-radius: var(--radius);
position: relative;
bottom: var(--su-2);
margin: var(--su-2);
margin-bottom: 0;
margin-top: -3px;
padding: var(--su-2) 0;
@media (min-width: $breakpoint-s) {
bottom: var(--su-3);
margin: var(--su-3);
margin-bottom: 0;
margin-top: -5px;
}
&__headline {
@ -242,6 +243,9 @@
&__actions {
padding-left: calc(var(--su-6) + var(--su-4));
margin-top: var(--su-1);
a {
font-weight: var(--fw-medium);
}
}
}

View file

@ -53,6 +53,8 @@
--card-color-secondary: rgb(var(--grey-700));
--card-color-tertiary: rgb(var(--grey-600));
--card-secondary-bg: rgb(var(--grey-50));
--card-tertiary-bg: rgb(var(--grey-100));
--card-tertiary-bg-hover: rgba(var(--grey-200), 0.55);
--card-secondary-color: rgb(var(--grey-700));
--card-border: rgba(var(--grey-900), 0.1);
--card-secondary-border: rgba(var(--grey-900), 0.05);

View file

@ -54,6 +54,9 @@
text-align: right;
display: block;
width: 100px;
:not(:first-child) {
display: none;
}
a {
color: var(--card-color-tertiary);
}

View file

@ -51,6 +51,7 @@
padding: calc(0.6vw + 8px) calc(0.8vw + 8px);
padding-right: 8px;
box-sizing: border-box;
border-radius: var(--radius);
img {
width: calc(1.2vw + 40px);
height: calc(1.2vw + 40px);
@ -90,7 +91,7 @@
box-sizing: border-box;
max-width: 55px;
max-height: 55px;
}
}
.ltag__link__user__pic {
display: inline-block;
position: absolute;
@ -123,7 +124,7 @@
padding: 0;
font-weight: var(--fw-bold);
font-size: calc(1.45em + 0.2vw);
line-height: var(--lh-tight)
line-height: var(--lh-tight);
}
h3 {
margin: calc(0.3vw + 1px) 0;
@ -206,4 +207,4 @@
}
}
}
}
}

View file

@ -65,6 +65,8 @@
--card-color-tertiary: rgb(var(--grey-400));
--card-secondary-bg: rgb(var(--grey-900));
--card-secondary-color: rgb(var(--grey-200));
--card-tertiary-bg: rgb(var(--grey-100));
--card-tertiary-bg-hover: rgba(var(--grey-200), 0.55);
--card-border: rgba(var(--white), 0.15);
--card-secondary-border: rgba(var(--white), 0.1);

View file

@ -12,6 +12,7 @@ import {
articleWithReactions,
videoArticle,
articleWithComments,
articleWithCommentWithLongParagraph,
podcastArticle,
podcastEpisodeArticle,
userArticle,
@ -200,6 +201,36 @@ describe('<Article /> component', () => {
expect(comments.textContent).toEqual(`213 ${locale('core.comment')}s`);
});
it('should render second paragraph, but not third', () => {
const { queryByTestId } = render(
<Article
{...commonProps}
isBookmarked={false}
article={articleWithComments}
/>,
);
const comments = queryByTestId('comment-content');
expect(comments.textContent).toContain('Kitsch hoodie artisan');
expect(comments.classList).not.toContain('Third paragraph');
});
it('should render the first part of a long paragraph', () => {
const { queryByTestId } = render(
<Article
{...commonProps}
isBookmarked={false}
article={articleWithCommentWithLongParagraph}
/>,
);
const comments = queryByTestId('comment-content');
expect(comments.textContent).toContain('Start of paragraph');
expect(comments.classList).not.toContain('End of paragraph');
});
it('should render with an add comment button when there are no comments', () => {
const { queryByTestId } = render(
<Article {...commonProps} isBookmarked={false} article={article} />,

View file

@ -198,7 +198,53 @@ export const articleWithComments = {
user_id: 6,
published_timestamp: '2020-04-21T19:41:40Z',
published_at_int: new Date(),
safe_processed_html: '<p>Kitsch hoodie artisan.</p>\n\n',
safe_processed_html:
'<p>Kitsch hoodie artisan.</p><p>Second paragraph.</p><p>Third paragraph.</p>\n\n',
path: '/naoma_dr_rice/comment/n',
username: 'naoma_dr_rice',
name: 'Dr. Naoma Rice',
profile_image_90: '/images/7.png',
},
],
public_reactions_count: 428,
comments_count: 213,
};
export const articleWithCommentWithLongParagraph = {
id: 62407,
title: 'Unbranded Home Loan Account',
path: '/some-post/path',
type_of: '',
class_name: 'Article',
flare_tag: {
id: 35682,
name: 'javascript',
hotness_score: 99,
points: 23,
bg_color_hex: '#000000',
text_color_hex: '#ffffff',
},
tag_list: ['javascript', 'ruby', 'go'],
cached_tag_list_array: [],
user_id: 23289,
user: {
username: 'Emil99',
name: 'Stella Macejkovic',
profile_image_90: '/images/10.png',
},
published_at_int: 1582037964819,
published_timestamp: 'Tue, 18 Feb 2020 14:59:24 GMT',
published_at: '2020-03-19T10:04:15-05:00',
readable_publish_date: 'February 18',
top_comments: [
{
comment_id: 23,
user_id: 6,
published_timestamp: '2020-04-21T19:41:40Z',
published_at_int: new Date(),
safe_processed_html:
`<p>Start of paragraph. This is a long test paragraph. This is a long test paragraph. This is a long test paragraph. This is a long test paragraph. This is a long test paragraph.
This is a long test paragraph. This is a long test paragraph. Yes it is really really really really really long. For real, like really real. Okay, this is long enough. End of paragraph</p>\n\n`,
path: '/naoma_dr_rice/comment/n',
username: 'naoma_dr_rice',
name: 'Dr. Naoma Rice',

View file

@ -8,11 +8,43 @@ function userProfilePage(username) {
return str;
}
function contentAwareComments(comment) {
const parser = new DOMParser();
const htmlDoc = parser.parseFromString(
comment.safe_processed_html,
'text/html',
);
const nodes = htmlDoc.body.childNodes;
let text = '';
let nodesSelected = 0;
nodes.forEach((node) => {
if (
node.outerHTML &&
node.tagName === 'P' &&
nodesSelected < 2 &&
node.outerHTML.length > 250
) {
text = `${text} ${node.outerHTML.substring(0, 230)} ...`;
nodesSelected = 2;
} else if (node.outerHTML && nodesSelected < 2) {
text = text + node.outerHTML;
nodesSelected++;
} else if (node.outerHTML && nodesSelected < 3) {
text = `${text} <div class="crayons-comment__readmore">See more</div>`;
nodesSelected++;
}
});
return text;
}
export const CommentListItem = ({ comment }) => (
<div
className="crayons-comment cursor-pointer"
role="presentation"
onClick={(_event) => {
if (_event.target.closest('a')) {
return;
}
if (_event.which > 1 || _event.metaKey || _event.ctrlKey) {
// Indicates should open in _blank
window.open(comment.path, '_blank');
@ -35,23 +67,28 @@ export const CommentListItem = ({ comment }) => (
alt="{comment.username} avatar"
/>
</span>
{comment.name}
</a>
<a href={comment.path} className="crayons-story__tertiary ml-1">
<time>
{timeAgo({
oldTimeInSeconds: comment.published_at_int,
formatter: (x) => x,
maxDisplayedAge: NaN,
})}
</time>
</a>
</div>
<div
className="crayons-comment__body"
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: comment.safe_processed_html }}
/>
<div className="crayons-comment__body">
<div class="crayons-comment__metainner">
<span class="fw-medium">{comment.name}</span>
<a href={comment.path} className="crayons-story__tertiary ml-1">
<time>
{timeAgo({
oldTimeInSeconds: comment.published_at_int,
formatter: (x) => x,
maxDisplayedAge: NaN,
})}
</time>
</a>
</div>
<div
data-testid="comment-content"
className="crayons-comment__inner"
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: contentAwareComments(comment) }}
/>
</div>
</div>
);

View file

@ -25,6 +25,7 @@ export const CommentsCount = ({ count, articlePath, articleTitle }) => {
url={`${articlePath}#comments`}
icon={commentsSVG}
tagName="a"
className="flex items-center"
aria-label={commentsAriaLabelText}
>
<span title="Number of comments">