From 0b88d580942cd7df144193fd6c4b574189bbb8aa Mon Sep 17 00:00:00 2001 From: riggraz Date: Fri, 20 Sep 2019 17:56:01 +0200 Subject: [PATCH] Improve style pt. 4 (post and comments) --- app/javascript/components/Board/NewPost.tsx | 2 +- .../components/Board/PostStatusFilter.tsx | 2 +- .../components/Board/SearchFilter.tsx | 2 +- .../components/Comments/Comment.tsx | 9 ++- .../components/Comments/CommentsP.tsx | 10 +-- .../components/Comments/NewComment.tsx | 7 ++- app/javascript/components/Post/PostP.tsx | 55 +++++++++------- app/javascript/components/Post/index.tsx | 2 - app/javascript/helpers/friendlyDate.js | 33 ++++++++++ .../stylesheets/components/Board.scss | 31 ---------- .../stylesheets/components/Comments.scss | 62 ++++++++++++++++--- .../stylesheets/components/Post.scss | 28 +++++++++ .../stylesheets/general/_components.scss | 31 ++++++++++ 13 files changed, 202 insertions(+), 72 deletions(-) create mode 100644 app/javascript/helpers/friendlyDate.js diff --git a/app/javascript/components/Board/NewPost.tsx b/app/javascript/components/Board/NewPost.tsx index fb484488..7a688e7f 100644 --- a/app/javascript/components/Board/NewPost.tsx +++ b/app/javascript/components/Board/NewPost.tsx @@ -141,7 +141,7 @@ class NewPost extends React.Component { } = this.state; return ( -
+
{board.name}

{board.description}

{ diff --git a/app/javascript/components/Board/PostStatusFilter.tsx b/app/javascript/components/Board/PostStatusFilter.tsx index 1850f855..68c90a56 100644 --- a/app/javascript/components/Board/PostStatusFilter.tsx +++ b/app/javascript/components/Board/PostStatusFilter.tsx @@ -23,7 +23,7 @@ const PostStatusFilter = ({ handleFilterClick, currentFilter, }: Props) => ( -
+
Filter by post status: { postStatuses.map((postStatus, i) => ( diff --git a/app/javascript/components/Board/SearchFilter.tsx b/app/javascript/components/Board/SearchFilter.tsx index 8d05759c..d48a79e7 100644 --- a/app/javascript/components/Board/SearchFilter.tsx +++ b/app/javascript/components/Board/SearchFilter.tsx @@ -8,7 +8,7 @@ interface Props { } const SearchFilter = ({ searchQuery, handleChange }: Props) => ( -
+
Search:

{body}

- Reply - {updatedAt} + + { reply.isOpen ? 'Cancel' : 'Reply' } + +  •  + {friendlyDate(updatedAt)}
{ reply.isOpen ? diff --git a/app/javascript/components/Comments/CommentsP.tsx b/app/javascript/components/Comments/CommentsP.tsx index a5ea8aa1..4efd3c5f 100644 --- a/app/javascript/components/Comments/CommentsP.tsx +++ b/app/javascript/components/Comments/CommentsP.tsx @@ -4,7 +4,7 @@ import { FormEvent } from 'react'; import NewComment from './NewComment'; import CommentList from './CommentList'; import Spinner from '../shared/Spinner'; -import { DangerText } from '../shared/CustomTexts'; +import { DangerText, UppercaseText } from '../shared/CustomTexts'; import IComment from '../../interfaces/IComment'; import { CommentRepliesState } from '../../reducers/commentRepliesReducer'; @@ -56,9 +56,7 @@ class CommentsP extends React.Component { } = this.props; return ( -
-

Comments

- +
reply.commentId === -1) && replies.find(reply => reply.commentId === -1).body} parentId={null} @@ -73,6 +71,10 @@ class CommentsP extends React.Component { { areLoading ? : null } { error ? {error} : null } + + activity • {comments.length} comments + + - +
); diff --git a/app/javascript/components/Post/PostP.tsx b/app/javascript/components/Post/PostP.tsx index 5b58100e..ada2766e 100644 --- a/app/javascript/components/Post/PostP.tsx +++ b/app/javascript/components/Post/PostP.tsx @@ -6,6 +6,9 @@ import IPostStatus from '../../interfaces/IPostStatus'; import PostStatusSelect from './PostStatusSelect'; import PostStatusLabel from '../shared/PostStatusLabel'; import Comments from '../../containers/Comments'; +import { MutedText } from '../shared/CustomTexts'; + +import friendlyDate from '../../helpers/friendlyDate'; interface Props { postId: number; @@ -40,29 +43,39 @@ class PostP extends React.Component { } = this.props; return ( -
-

{post.title}

- { - isPowerUser && post ? - changePostStatus(post.id, newPostStatusId, authenticityToken) - } - /> - : - postStatus.id === post.postStatusId)} - /> - } +
+
+
+
+
+
-

{post.description}

+
+
+

{post.title}

+ { + isPowerUser && post ? + changePostStatus(post.id, newPostStatusId, authenticityToken) + } + /> + : + postStatus.id === post.postStatusId)} + /> + } +

{post.description}

+ {friendlyDate(post.createdAt)} +
- + +
); } diff --git a/app/javascript/components/Post/index.tsx b/app/javascript/components/Post/index.tsx index ff9cfdd9..bf91ec0d 100644 --- a/app/javascript/components/Post/index.tsx +++ b/app/javascript/components/Post/index.tsx @@ -7,8 +7,6 @@ import Post from '../../containers/Post'; import IPostStatus from '../../interfaces/IPostStatus'; -import '../../stylesheets/components/Post.scss'; - interface Props { postId: number; postStatuses: Array; diff --git a/app/javascript/helpers/friendlyDate.js b/app/javascript/helpers/friendlyDate.js new file mode 100644 index 00000000..ab4995d1 --- /dev/null +++ b/app/javascript/helpers/friendlyDate.js @@ -0,0 +1,33 @@ +const friendlyDate = date => { + var now = new Date(); + var timeStamp = fromRailsStringToJavascriptDate(date); + + var secondsPast = (now.getTime() - timeStamp.getTime()) / 1000; + + if (secondsPast < 60) { + secondsPast = parseInt(secondsPast); + return secondsPast + ' ' + (secondsPast === 1 ? 'second' : 'seconds') + ' ago'; + } else if (secondsPast < 3600) { + let minutesPast = parseInt(secondsPast / 60); + return minutesPast + ' ' + (minutesPast === 1 ? 'minute' : 'minutes') + ' ago'; + } else if (secondsPast <= 86400) { + let hoursPast = parseInt(secondsPast / 3600); + return hoursPast + ' ' + (hoursPast === 1 ? 'hour' : 'hours') + ' ago'; + } else { + let daysPast = parseInt(secondsPast / 86400); + return daysPast + ' ' + (daysPast === 1 ? 'day' : 'days') + ' ago'; + } +} + +export default friendlyDate; + +/* + Converts the default Rails datetime string + format to a JavaScript Date object. +*/ +const fromRailsStringToJavascriptDate = date => { + let dateOnly = date.slice(0, 10); + let timeOnly = date.slice(11, 19); + + return new Date(`${dateOnly}T${timeOnly}Z`); +} \ No newline at end of file diff --git a/app/javascript/stylesheets/components/Board.scss b/app/javascript/stylesheets/components/Board.scss index 579be62b..720c5826 100644 --- a/app/javascript/stylesheets/components/Board.scss +++ b/app/javascript/stylesheets/components/Board.scss @@ -6,27 +6,9 @@ flex-direction: row; - .sidebar { - position: sticky; - top: 60px; - - .sidebarBox { - width: 250px; - margin-right: 16px; - } - } - @include media-breakpoint-down(sm) { flex-direction: column; - .sidebar { - position: relative; - width: 100%; - top: 0; - - .sidebarBox { width: 100%; } - } - .postStatusFilterContainer { flex-direction: row !important; flex-wrap: wrap; @@ -45,19 +27,6 @@ } } - .sidebarBox { - @extend - .card, - .d-flex, - .flex-column, - .justify-content-start, - .align-items-center, - .flex-grow-0, - .flex-shrink-0, - .my-3, - .p-2; - } - .postStatusListItemContainer { @extend .d-flex, diff --git a/app/javascript/stylesheets/components/Comments.scss b/app/javascript/stylesheets/components/Comments.scss index f44c567f..c3bf8e4b 100644 --- a/app/javascript/stylesheets/components/Comments.scss +++ b/app/javascript/stylesheets/components/Comments.scss @@ -1,21 +1,67 @@ -.comments { +.commentsContainer { + .newCommentForm { + @extend + .d-flex, + .my-3; + + .newCommentBody { + @extend + .form-control, + .w-100, + .p-2, + .mr-2; + + height: 80px; + + border: thin solid grey; + border-radius: 4px; + + resize: none; + } + + .submitCommentButton { + @extend + .align-self-end; + + height: 40px; + } + } + + .commentsTitle { + @extend + .text-secondary, + .text-uppercase, + .font-weight-lighter, + .my-2; + } + .commentList > .commentList { padding-left: 32px; } .comment { - margin-bottom: 32px; + @extend + .my-3; .commentHeader { - @extend - .font-weight-bolder; - - font-size: 17px; + @extend .titleText; } .commentBody { - @extend - .my-2; + @extend .my-1; + } + + .commentFooter { + font-size: 14px; + + .commentReplyButton { + color: #333; + + &:hover { + text-decoration: underline; + cursor: pointer; + } + } } } } \ No newline at end of file diff --git a/app/javascript/stylesheets/components/Post.scss b/app/javascript/stylesheets/components/Post.scss index e69de29b..69e76893 100644 --- a/app/javascript/stylesheets/components/Post.scss +++ b/app/javascript/stylesheets/components/Post.scss @@ -0,0 +1,28 @@ +.pageContainer { + @extend + .d-flex, + .justify-content-between, + .align-items-start; + + flex-direction: row; + + @include media-breakpoint-down(sm) { + flex-direction: column; + + .postAndCommentsContainer { width: 100%; } + } + + .postAndCommentsContainer { + @extend + .card, + .flex-grow-1, + .p-3; + + .postDescription { + @extend + .my-3; + + color: #333; + } + } +} \ No newline at end of file diff --git a/app/javascript/stylesheets/general/_components.scss b/app/javascript/stylesheets/general/_components.scss index 35de4c6d..e361eb40 100644 --- a/app/javascript/stylesheets/general/_components.scss +++ b/app/javascript/stylesheets/general/_components.scss @@ -21,6 +21,37 @@ } } +.sidebar { + position: sticky; + top: 60px; + + .sidebarCard { + @extend + .card, + .d-flex, + .flex-column, + .justify-content-start, + .align-items-center, + .flex-grow-0, + .flex-shrink-0, + .my-3, + .p-2; + + width: 250px; + margin-right: 16px; + } +} + +@include media-breakpoint-down(sm) { + .sidebar { + position: relative; + width: 100%; + top: 0; + + .sidebarCard { width: 100%; } + } +} + .badge { @extend .badge,