fix: Bring UI closer to mockups

This makes many tweaks to get the UI closer to
the mockup and using Paragon components as much as possible.

Related tickets:
* [TNL-8427](https://openedx.atlassian.net/browse/TNL-8427)
* [BB-4417](https://tasks.opencraft.com/browse/BB-4417)
This commit is contained in:
João Cabrita
2021-07-20 16:39:49 +01:00
committed by Mehak Nasir
parent 80ad9f1dc2
commit 7138e63cf0
15 changed files with 313 additions and 293 deletions

View File

@@ -1,11 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import { faSort } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useDispatch, useSelector } from 'react-redux';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Icon } from '@edx/paragon';
import { ArrowDropUpDown } from '@edx/paragon/icons';
import { SelectableDropdown } from '../../../components';
import {
@@ -71,7 +71,7 @@ function PostFilterBar({
options={postOrderingOptions}
onChange={(sortBy) => dispatch(setSortedBy(sortBy.value))}
label={
<FontAwesomeIcon icon={faSort} aria-label="Sort" title="Sort" />
<Icon src={ArrowDropUpDown} aria-label="Sort" title="Sort" />
}
/>
</div>

View File

@@ -0,0 +1,61 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import {
Icon, IconButton, OverlayTrigger, Tooltip,
} from '@edx/paragon';
import { ThumbUpFilled, ThumbUpOutline } from '@edx/paragon/icons';
import messages from './messages';
function LikeButton(
{
count,
intl,
onClick,
voted,
},
) {
const handleClick = (e) => {
e.preventDefault();
if (onClick) {
onClick();
}
return false;
};
return (
<div className="d-flex align-items-center mx-2.5">
<OverlayTrigger
overlay={(
<Tooltip>
{intl.formatMessage(voted ? messages.removeLike : messages.like)}
</Tooltip>
)}
>
<IconButton
onClick={handleClick}
alt="Like"
iconAs={Icon}
size="inline"
src={voted ? ThumbUpFilled : ThumbUpOutline}
/>
</OverlayTrigger>
{count}
</div>
);
}
LikeButton.propTypes = {
count: PropTypes.number.isRequired,
intl: intlShape.isRequired,
onClick: PropTypes.func,
voted: PropTypes.bool,
};
LikeButton.defaultProps = {
voted: false,
onClick: undefined,
};
export default injectIntl(LikeButton);

View File

@@ -1,28 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
faQuestionCircle,
faStar as faEmptyStar,
faThumbsUp as faEmptyThumb,
} from '@fortawesome/free-regular-svg-icons';
import {
faComments,
faStar as faSolidStar,
faThumbsUp as faSolidThumb,
faThumbtack,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useDispatch } from 'react-redux';
import * as timeago from 'timeago.js';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import {
Avatar, IconButton, OverlayTrigger, Tooltip,
Avatar, Icon, IconButton, OverlayTrigger, Tooltip,
} from '@edx/paragon';
import {
Pin,
QuestionAnswer,
StarFilled,
StarOutline,
} from '@edx/paragon/icons';
import { updateExistingThread } from '../data/thunks';
import messages from './messages';
import LikeButton from './LikeButton';
export const postShape = PropTypes.shape({
abuseFlagged: PropTypes.bool,
@@ -43,18 +38,11 @@ export const postShape = PropTypes.shape({
function PostTypeIcon(props) {
return (
<div className="m-1">
{props.type === 'question' && <FontAwesomeIcon icon={faQuestionCircle} size="lg" />}
{props.type === 'discussion' && <FontAwesomeIcon icon={faComments} size="lg" />}
{props.type === 'question' && <Icon src={QuestionAnswer} size="lg" />}
{props.type === 'discussion' && <Icon src={QuestionAnswer} size="lg" />}
{props.pinned && (
<FontAwesomeIcon
icon={faThumbtack}
size="sm"
className="position-relative bg-white rounded"
style={{
left: '-0.25rem',
bottom: '-0.75rem',
padding: '0.125rem',
}}
<Icon
src={Pin}
/>
)}
</div>
@@ -71,27 +59,32 @@ function PostHeader({
post,
}) {
return (
<div className="d-flex flex-fill">
<Avatar className="my-1" alt={post.author} src={post.authorAvatars.imageUrlSmall} />
<div className="d-flex flex-row flex-fill">
<PostTypeIcon type={post.type} pinned={post.pinned} />
<div className="d-flex flex-fill justify-content-between">
<Avatar className="m-2" alt={post.author} src={post.authorAvatars.imageUrlSmall} />
<PostTypeIcon type={post.type} pinned={post.pinned} />
<div className="align-items-center d-flex flex-row flex-fill">
<div className="d-flex flex-column flex-fill">
<span className="d-flex font-weight-bold text-gray">
<span className="d-flex font-weight-bold">
{post.title}
</span>
<span className="d-flex small text-gray-300">
{post.author}{' | '}
<span className="d-flex text-gray-500 x-small">
<span title={post.createdAt}>
{intl.formatMessage(messages.postedOn, { time: timeago.format(post.createdAt, intl.locale) })}
{intl.formatMessage(
messages.postedOn,
{
author: post.author,
time: timeago.format(post.createdAt, intl.locale),
},
)}
</span>
</span>
</div>
<div className="d-flex align-items-center mr-3">
<FontAwesomeIcon icon={faComments} className="mr-2" />
<span style={{ minWidth: '2rem' }}>
{post.commentCount}
</span>
</div>
</div>
<div className="d-flex mr-3">
<Icon src={QuestionAnswer} />
<span style={{ minWidth: '2rem' }}>
{post.commentCount}
</span>
</div>
</div>
);
@@ -109,35 +102,22 @@ function Post({
const dispatch = useDispatch();
return (
<div className="d-flex flex-column mt-2">
<div className="d-flex flex-column p-2.5 w-100">
<PostHeader post={post} intl={intl} />
<div className="d-flex mt-2 mb-0 p-0" dangerouslySetInnerHTML={{ __html: post.renderedBody }} />
<div className="d-flex align-items-center">
<div className="d-flex align-items-center">
<OverlayTrigger overlay={(
<LikeButton
count={post.voteCount}
onClick={() => dispatch(updateExistingThread(post.id, { voted: !post.voted }))}
voted={post.voted}
/>
<OverlayTrigger
className="mx-2.5"
overlay={(
<Tooltip>
{intl.formatMessage(post.voted ? messages.removeLike : messages.like)}
{intl.formatMessage(post.following ? messages.unfollow : messages.follow)}
</Tooltip>
)}
>
<IconButton
onClick={(e) => {
e.preventDefault();
dispatch(updateExistingThread(post.id, { voted: !post.voted }));
return false;
}}
alt="Like"
size="inline"
icon={post.voted ? faSolidThumb : faEmptyThumb}
/>
</OverlayTrigger>
{post.voteCount}
</div>
<OverlayTrigger overlay={(
<Tooltip>
{intl.formatMessage(post.following ? messages.unfollow : messages.follow)}
</Tooltip>
)}
>
<IconButton
onClick={() => {
@@ -145,8 +125,9 @@ function Post({
return true;
}}
alt="Follow"
iconAs={Icon}
size="inline"
icon={post.following ? faSolidStar : faEmptyStar}
src={post.following ? StarFilled : StarOutline}
/>
</OverlayTrigger>
</div>

View File

@@ -1,10 +1,10 @@
import React from 'react';
import { faCircle, faFlag } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Link } from 'react-router-dom';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Icon } from '@edx/paragon';
import { Flag, Unread } from '@edx/paragon/icons';
import { Routes } from '../../../data/constants';
import messages from './messages';
@@ -24,13 +24,13 @@ function PostLink({
}
>
{post.abuseFlagged && (
<div className="bg-gray-100 flex-fill">
<FontAwesomeIcon icon={faFlag} className="mx-1" />
{intl.formatMessage(messages.contentReported)}
<div className="align-items-center bg-danger-100 d-flex flex-fill p-1">
<Icon className="text-danger-700" src={Flag} />
<span className="text-gray-700 x-small">{intl.formatMessage(messages.contentReported)}</span>
</div>
)}
<div className="d-flex flex-row mb-2">
<FontAwesomeIcon icon={faCircle} className={`my-1 text-accent-a ${post.read && 'invisible'}`} size="xs" />
<div className="d-flex flex-row p-2">
{!post.read && <Icon className="text-brand-500" src={Unread} />}
<Post post={post} />
</div>
</Link>

View File

@@ -7,7 +7,7 @@ const messages = defineMessages({
},
postedOn: {
id: 'discussions.post.posted-on',
defaultMessage: 'Posted {time}',
defaultMessage: 'Posted {time} by {author}',
},
contentReported: {
id: 'discussions.post.content-reported',