Refactor CSS (#116)

Refactor CSS files and structure. Also refactors some html and React components for a smarter use of CSS classes.
This commit is contained in:
Riccardo Graziosi
2022-06-08 10:20:36 +02:00
committed by GitHub
parent 35c427d9f6
commit 8e75a85873
61 changed files with 329 additions and 262 deletions

View File

@@ -4,6 +4,7 @@ import NewPost from './NewPost';
import SearchFilter from './SearchFilter'; import SearchFilter from './SearchFilter';
import PostStatusFilter from './PostStatusFilter'; import PostStatusFilter from './PostStatusFilter';
import PostList from './PostList'; import PostList from './PostList';
import Sidebar from '../common/Sidebar';
import IBoard from '../../interfaces/IBoard'; import IBoard from '../../interfaces/IBoard';
@@ -74,7 +75,7 @@ class BoardP extends React.Component<Props> {
return ( return (
<div className="boardContainer"> <div className="boardContainer">
<div className="sidebar"> <Sidebar>
<NewPost <NewPost
board={board} board={board}
isLoggedIn={isLoggedIn} isLoggedIn={isLoggedIn}
@@ -92,7 +93,7 @@ class BoardP extends React.Component<Props> {
currentFilter={filters.postStatusId} currentFilter={filters.postStatusId}
handleFilterClick={handlePostStatusFilterChange} handleFilterClick={handlePostStatusFilterChange}
/> />
</div> </Sidebar>
<PostList <PostList
posts={posts.items} posts={posts.items}

View File

@@ -3,12 +3,12 @@ import ReactMarkdown from 'react-markdown';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import NewPostForm from './NewPostForm'; import NewPostForm from './NewPostForm';
import Spinner from '../shared/Spinner'; import Spinner from '../common/Spinner';
import { import {
DangerText, DangerText,
SuccessText, SuccessText,
} from '../shared/CustomTexts'; } from '../common/CustomTexts';
import Button from '../shared/Button'; import Button from '../common/Button';
import IBoard from '../../interfaces/IBoard'; import IBoard from '../../interfaces/IBoard';
import buildRequestHeaders from '../../helpers/buildRequestHeaders'; import buildRequestHeaders from '../../helpers/buildRequestHeaders';
@@ -143,7 +143,7 @@ class NewPost extends React.Component<Props, State> {
} = this.state; } = this.state;
return ( return (
<div className="newPostContainer sidebarCard"> <div className="newPostContainer sidebarBox">
<span className="boardTitle">{board.name}</span> <span className="boardTitle">{board.name}</span>
<ReactMarkdown <ReactMarkdown

View File

@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import Button from '../shared/Button'; import Button from '../common/Button';
interface Props { interface Props {
title: string; title: string;

View File

@@ -3,11 +3,11 @@ import I18n from 'i18n-js';
import InfiniteScroll from 'react-infinite-scroller'; import InfiniteScroll from 'react-infinite-scroller';
import PostListItem from './PostListItem'; import PostListItem from './PostListItem';
import Spinner from '../shared/Spinner'; import Spinner from '../common/Spinner';
import { import {
DangerText, DangerText,
CenteredMutedText, CenteredMutedText,
} from '../shared/CustomTexts'; } from '../common/CustomTexts';
import IPost from '../../interfaces/IPost'; import IPost from '../../interfaces/IPost';
import IPostStatus from '../../interfaces/IPostStatus'; import IPostStatus from '../../interfaces/IPostStatus';

View File

@@ -2,8 +2,8 @@ import * as React from 'react';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import LikeButton from '../../containers/LikeButton'; import LikeButton from '../../containers/LikeButton';
import CommentsNumber from '../shared/CommentsNumber'; import CommentsNumber from '../common/CommentsNumber';
import PostStatusLabel from '../shared/PostStatusLabel'; import PostStatusLabel from '../common/PostStatusLabel';
import IPostStatus from '../../interfaces/IPostStatus'; import IPostStatus from '../../interfaces/IPostStatus';

View File

@@ -2,10 +2,11 @@ import * as React from 'react';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import PostStatusListItem from './PostStatusListItem'; import PostStatusListItem from './PostStatusListItem';
import Spinner from '../shared/Spinner'; import Spinner from '../common/Spinner';
import { BoxTitleText, DangerText } from '../shared/CustomTexts'; import { DangerText } from '../common/CustomTexts';
import IPostStatus from '../../interfaces/IPostStatus'; import IPostStatus from '../../interfaces/IPostStatus';
import SidebarBox from '../common/SidebarBox';
interface Props { interface Props {
postStatuses: Array<IPostStatus>; postStatuses: Array<IPostStatus>;
@@ -24,8 +25,7 @@ const PostStatusFilter = ({
handleFilterClick, handleFilterClick,
currentFilter, currentFilter,
}: Props) => ( }: Props) => (
<div className="postStatusFilterContainer sidebarCard"> <SidebarBox title={I18n.t('board.filter_box.title')} customClass="postStatusFilterContainer">
<BoxTitleText>{I18n.t('board.filter_box.title')}</BoxTitleText>
{ {
postStatuses.map((postStatus, i) => ( postStatuses.map((postStatus, i) => (
<PostStatusListItem <PostStatusListItem
@@ -42,7 +42,7 @@ const PostStatusFilter = ({
} }
{ areLoading ? <Spinner /> : null } { areLoading ? <Spinner /> : null }
{ error ? <DangerText>{error}</DangerText> : null } { error ? <DangerText>{error}</DangerText> : null }
</div> </SidebarBox>
); );
export default PostStatusFilter; export default PostStatusFilter;

View File

@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import PostStatusLabel from '../shared/PostStatusLabel'; import PostStatusLabel from '../common/PostStatusLabel';
import Button from '../shared/Button'; import Button from '../common/Button';
interface Props { interface Props {
name: string; name: string;

View File

@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import { BoxTitleText } from '../shared/CustomTexts'; import SidebarBox from '../common/SidebarBox';
interface Props { interface Props {
searchQuery: string; searchQuery: string;
@@ -9,9 +9,7 @@ interface Props {
} }
const SearchFilter = ({ searchQuery, handleChange }: Props) => ( const SearchFilter = ({ searchQuery, handleChange }: Props) => (
<div className="sidebarCard"> <SidebarBox title={I18n.t('board.search_box.title')}>
<BoxTitleText>{I18n.t('board.search_box.title')}</BoxTitleText>
<input <input
type="search" type="search"
value={searchQuery} value={searchQuery}
@@ -19,7 +17,7 @@ const SearchFilter = ({ searchQuery, handleChange }: Props) => (
id="searchPostInput" id="searchPostInput"
className="form-control" className="form-control"
/> />
</div> </SidebarBox>
); );
export default SearchFilter; export default SearchFilter;

View File

@@ -4,8 +4,8 @@ import Gravatar from 'react-gravatar';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import NewComment from './NewComment'; import NewComment from './NewComment';
import Separator from '../shared/Separator'; import Separator from '../common/Separator';
import { MutedText } from '../shared/CustomTexts'; import { MutedText } from '../common/CustomTexts';
import { ReplyFormState } from '../../reducers/replyFormReducer'; import { ReplyFormState } from '../../reducers/replyFormReducer';

View File

@@ -3,12 +3,12 @@ import I18n from 'i18n-js';
import NewComment from './NewComment'; import NewComment from './NewComment';
import CommentList from './CommentList'; import CommentList from './CommentList';
import Spinner from '../shared/Spinner'; import Spinner from '../common/Spinner';
import { DangerText } from '../shared/CustomTexts'; import { DangerText } from '../common/CustomTexts';
import IComment from '../../interfaces/IComment'; import IComment from '../../interfaces/IComment';
import { ReplyFormState } from '../../reducers/replyFormReducer'; import { ReplyFormState } from '../../reducers/replyFormReducer';
import Separator from '../shared/Separator'; import Separator from '../common/Separator';
interface Props { interface Props {
postId: number; postId: number;

View File

@@ -4,9 +4,9 @@ import Gravatar from 'react-gravatar';
import NewCommentUpdateSection from './NewCommentUpdateSection'; import NewCommentUpdateSection from './NewCommentUpdateSection';
import Button from '../shared/Button'; import Button from '../common/Button';
import Spinner from '../shared/Spinner'; import Spinner from '../common/Spinner';
import { DangerText } from '../shared/CustomTexts'; import { DangerText } from '../common/CustomTexts';
interface Props { interface Props {
body: string; body: string;

View File

@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import { MutedText } from '../shared/CustomTexts'; import { MutedText } from '../common/CustomTexts';
interface Props { interface Props {
postUpdateFlagValue: boolean; postUpdateFlagValue: boolean;

View File

@@ -1,8 +1,9 @@
import * as React from 'react'; import * as React from 'react';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import Button from '../shared/Button'; import { SmallMutedText } from '../common/CustomTexts';
import { BoxTitleText, SmallMutedText } from '../shared/CustomTexts'; import SidebarBox from '../common/SidebarBox';
import Switch from '../common/Switch';
interface Props { interface Props {
followed: boolean; followed: boolean;
@@ -12,14 +13,14 @@ interface Props {
} }
const ActionBox = ({followed, submitFollow, isLoggedIn}: Props) => ( const ActionBox = ({followed, submitFollow, isLoggedIn}: Props) => (
<div className="actionBoxContainer"> <SidebarBox title={I18n.t('post.action_box.title')} customClass="actionBoxContainer">
<div className="actionBoxFollow"> <Switch
<BoxTitleText>{I18n.t('post.action_box.title')}</BoxTitleText> onClick={isLoggedIn ? submitFollow : () => location.href = '/users/sign_in'}
<br /> label={I18n.t('post.action_box.follow_button')}
<Button onClick={isLoggedIn ? submitFollow : () => location.href = '/users/sign_in'} outline> checked={followed}
{ followed ? I18n.t('post.action_box.unfollow_button') : I18n.t('post.action_box.follow_button') } htmlId="followSwitch"
</Button> />
<br />
<SmallMutedText> <SmallMutedText>
{ followed ? { followed ?
I18n.t('post.action_box.following_description') I18n.t('post.action_box.following_description')
@@ -27,8 +28,7 @@ const ActionBox = ({followed, submitFollow, isLoggedIn}: Props) => (
I18n.t('post.action_box.not_following_description') I18n.t('post.action_box.not_following_description')
} }
</SmallMutedText> </SmallMutedText>
</div> </SidebarBox>
</div>
); );
export default ActionBox; export default ActionBox;

View File

@@ -3,12 +3,12 @@ import I18n from 'i18n-js';
import Gravatar from 'react-gravatar'; import Gravatar from 'react-gravatar';
import ILike from '../../interfaces/ILike'; import ILike from '../../interfaces/ILike';
import Spinner from '../shared/Spinner'; import Spinner from '../common/Spinner';
import SidebarBox from '../common/SidebarBox';
import { import {
BoxTitleText,
DangerText, DangerText,
CenteredMutedText CenteredMutedText
} from '../shared/CustomTexts'; } from '../common/CustomTexts';
interface Props { interface Props {
likes: Array<ILike>; likes: Array<ILike>;
@@ -17,9 +17,7 @@ interface Props {
} }
const LikeList = ({ likes, areLoading, error}: Props) => ( const LikeList = ({ likes, areLoading, error}: Props) => (
<div className="likeListContainer"> <SidebarBox title={I18n.t('post.likes_box.title')} customClass="likeListContainer">
<BoxTitleText>{I18n.t('post.likes_box.title')}</BoxTitleText>
{ areLoading ? <Spinner /> : null } { areLoading ? <Spinner /> : null }
{ error ? <DangerText>{error}</DangerText> : null } { error ? <DangerText>{error}</DangerText> : null }
@@ -34,7 +32,7 @@ const LikeList = ({ likes, areLoading, error}: Props) => (
)) ))
} }
</div> </div>
</div> </SidebarBox>
); );
export default LikeList; export default LikeList;

View File

@@ -12,10 +12,11 @@ import ActionBox from './ActionBox';
import LikeButton from '../../containers/LikeButton'; import LikeButton from '../../containers/LikeButton';
import PostBoardSelect from './PostBoardSelect'; import PostBoardSelect from './PostBoardSelect';
import PostStatusSelect from './PostStatusSelect'; import PostStatusSelect from './PostStatusSelect';
import PostBoardLabel from '../shared/PostBoardLabel'; import PostBoardLabel from '../common/PostBoardLabel';
import PostStatusLabel from '../shared/PostStatusLabel'; import PostStatusLabel from '../common/PostStatusLabel';
import Comments from '../../containers/Comments'; import Comments from '../../containers/Comments';
import { MutedText } from '../shared/CustomTexts'; import { MutedText } from '../common/CustomTexts';
import Sidebar from '../common/Sidebar';
import { LikesState } from '../../reducers/likesReducer'; import { LikesState } from '../../reducers/likesReducer';
import { CommentsState } from '../../reducers/commentsReducer'; import { CommentsState } from '../../reducers/commentsReducer';
@@ -101,8 +102,8 @@ class PostP extends React.Component<Props> {
); );
return ( return (
<div className="pageContainer"> <div className="postContainer">
<div className="sidebar"> <Sidebar>
<PostUpdateList <PostUpdateList
postUpdates={postUpdates} postUpdates={postUpdates}
postStatuses={postStatuses} postStatuses={postStatuses}
@@ -122,10 +123,10 @@ class PostP extends React.Component<Props> {
isLoggedIn={isLoggedIn} isLoggedIn={isLoggedIn}
/> />
</div> </Sidebar>
<div className="postAndCommentsContainer"> <div className="postAndCommentsContainer">
<div className="postContainer"> <>
<div className="postHeader"> <div className="postHeader">
<LikeButton <LikeButton
postId={post.id} postId={post.id}
@@ -183,7 +184,7 @@ class PostP extends React.Component<Props> {
</ReactMarkdown> </ReactMarkdown>
<MutedText>{friendlyDate(post.createdAt)}</MutedText> <MutedText>{friendlyDate(post.createdAt)}</MutedText>
</div> </>
<Comments <Comments
postId={this.props.postId} postId={this.props.postId}

View File

@@ -3,15 +3,16 @@ import ReactMarkdown from 'react-markdown';
import Gravatar from 'react-gravatar'; import Gravatar from 'react-gravatar';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import { BoxTitleText, DangerText, CenteredMutedText, MutedText } from '../shared/CustomTexts'; import { DangerText, CenteredMutedText, MutedText } from '../common/CustomTexts';
import Spinner from '../shared/Spinner'; import Spinner from '../common/Spinner';
import IComment from '../../interfaces/IComment'; import IComment from '../../interfaces/IComment';
import IPostStatusChange from '../../interfaces/IPostStatusChange'; import IPostStatusChange from '../../interfaces/IPostStatusChange';
import IPostStatus from '../../interfaces/IPostStatus'; import IPostStatus from '../../interfaces/IPostStatus';
import friendlyDate from '../../helpers/datetime'; import friendlyDate from '../../helpers/datetime';
import PostStatusLabel from '../shared/PostStatusLabel'; import PostStatusLabel from '../common/PostStatusLabel';
import SidebarBox from '../common/SidebarBox';
interface Props { interface Props {
postUpdates: Array<IComment | IPostStatusChange>; postUpdates: Array<IComment | IPostStatusChange>;
@@ -26,9 +27,7 @@ const PostUpdateList = ({
areLoading, areLoading,
error, error,
}: Props) => ( }: Props) => (
<div className="postUpdateListContainer"> <SidebarBox title={I18n.t('post.updates_box.title')} customClass="postUpdateListContainer">
<BoxTitleText>{I18n.t('post.updates_box.title')}</BoxTitleText>
{ areLoading ? <Spinner /> : null } { areLoading ? <Spinner /> : null }
{ error ? <DangerText>{error}</DangerText> : null } { error ? <DangerText>{error}</DangerText> : null }
@@ -71,7 +70,7 @@ const PostUpdateList = ({
)) ))
} }
</div> </div>
</div> </SidebarBox>
); );
export default PostUpdateList; export default PostUpdateList;

View File

@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import PostListItem from './PostListItem'; import PostListItem from './PostListItem';
import { CenteredMutedText } from '../shared/CustomTexts'; import { CenteredMutedText } from '../common/CustomTexts';
import IPostJSON from '../../interfaces/json/IPost'; import IPostJSON from '../../interfaces/json/IPost';
import IBoard from '../../interfaces/IBoard'; import IBoard from '../../interfaces/IBoard';

View File

@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import PostList from './PostList'; import PostList from './PostList';
import { TitleText } from '../shared/CustomTexts'; import { TitleText } from '../common/CustomTexts';
import IPostStatus from '../../interfaces/IPostStatus'; import IPostStatus from '../../interfaces/IPostStatus';
import IPostJSON from '../../interfaces/json/IPost'; import IPostJSON from '../../interfaces/json/IPost';

View File

@@ -1,6 +1,6 @@
import * as React from 'react'; import * as React from 'react';
import { TitleText, UppercaseText } from '../shared/CustomTexts'; import { TitleText, UppercaseText } from '../common/CustomTexts';
interface Props { interface Props {
id: number; id: number;

View File

@@ -2,11 +2,11 @@ import * as React from 'react';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import { Draggable } from 'react-beautiful-dnd'; import { Draggable } from 'react-beautiful-dnd';
import { DescriptionText } from '../../shared/CustomTexts'; import { DescriptionText } from '../../common/CustomTexts';
import DragZone from '../../shared/DragZone'; import DragZone from '../../common/DragZone';
import PostBoardLabel from '../../shared/PostBoardLabel'; import PostBoardLabel from '../../common/PostBoardLabel';
import Separator from '../../shared/Separator'; import Separator from '../../common/Separator';
import BoardForm from './BoardForm'; import BoardForm from './BoardForm';
interface Props { interface Props {

View File

@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import Button from '../../shared/Button'; import Button from '../../common/Button';
interface Props { interface Props {
mode: 'create' | 'update'; mode: 'create' | 'update';

View File

@@ -1,14 +1,15 @@
import * as React from 'react'; import * as React from 'react';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import { DragDropContext, Droppable } from 'react-beautiful-dnd'; import { DragDropContext, Droppable } from 'react-beautiful-dnd';
import BoardEditable from './BoardEditable'; import BoardEditable from './BoardEditable';
import BoardForm from './BoardForm'; import BoardForm from './BoardForm';
import SiteSettingsInfoBox from '../../shared/SiteSettingsInfoBox'; import SiteSettingsInfoBox from '../../common/SiteSettingsInfoBox';
import Spinner from '../../shared/Spinner'; import Spinner from '../../common/Spinner';
import Box from '../../common/Box';
import { CenteredMutedText } from '../../common/CustomTexts';
import { BoardsState } from '../../../reducers/boardsReducer'; import { BoardsState } from '../../../reducers/boardsReducer';
import { CenteredMutedText } from '../../shared/CustomTexts';
import IBoard from '../../../interfaces/IBoard'; import IBoard from '../../../interfaces/IBoard';
interface Props { interface Props {
@@ -89,8 +90,8 @@ class BoardsSiteSettingsP extends React.Component<Props> {
} = this.props; } = this.props;
return ( return (
<React.Fragment> <>
<div className="content"> <Box>
<h2>{I18n.t('site_settings.boards.title')}</h2> <h2>{I18n.t('site_settings.boards.title')}</h2>
{ {
@@ -124,16 +125,16 @@ class BoardsSiteSettingsP extends React.Component<Props> {
: :
<CenteredMutedText>{I18n.t('site_settings.boards.empty')}</CenteredMutedText> <CenteredMutedText>{I18n.t('site_settings.boards.empty')}</CenteredMutedText>
} }
</div> </Box>
<div className="content"> <Box>
<h2>{I18n.t('site_settings.boards.new')}</h2> <h2>{I18n.t('site_settings.boards.new')}</h2>
<BoardForm mode='create' handleSubmit={this.handleSubmit} /> <BoardForm mode='create' handleSubmit={this.handleSubmit} />
</div> </Box>
<SiteSettingsInfoBox areUpdating={settingsAreUpdating || boards.areLoading} error={settingsError} /> <SiteSettingsInfoBox areUpdating={settingsAreUpdating || boards.areLoading} error={settingsError} />
</React.Fragment> </>
); );
} }
} }

View File

@@ -3,9 +3,9 @@ import I18n from 'i18n-js';
import { Draggable } from 'react-beautiful-dnd'; import { Draggable } from 'react-beautiful-dnd';
import PostStatusLabel from "../../shared/PostStatusLabel"; import PostStatusLabel from "../../common/PostStatusLabel";
import DragZone from '../../shared/DragZone'; import DragZone from '../../common/DragZone';
import Separator from '../../shared/Separator'; import Separator from '../../common/Separator';
import PostStatusForm from './PostStatusForm'; import PostStatusForm from './PostStatusForm';
interface Props { interface Props {

View File

@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import Button from '../../shared/Button'; import Button from '../../common/Button';
import padStart from '../../../helpers/padStart'; import padStart from '../../../helpers/padStart';

View File

@@ -5,11 +5,12 @@ import { DragDropContext, Droppable } from 'react-beautiful-dnd';
import IPostStatus from '../../../interfaces/IPostStatus'; import IPostStatus from '../../../interfaces/IPostStatus';
import { PostStatusesState } from "../../../reducers/postStatusesReducer"; import { PostStatusesState } from "../../../reducers/postStatusesReducer";
import { CenteredMutedText } from '../../shared/CustomTexts'; import { CenteredMutedText } from '../../common/CustomTexts';
import SiteSettingsInfoBox from '../../shared/SiteSettingsInfoBox'; import SiteSettingsInfoBox from '../../common/SiteSettingsInfoBox';
import PostStatusForm from './PostStatusForm'; import PostStatusForm from './PostStatusForm';
import PostStatusEditable from './PostStatusEditable'; import PostStatusEditable from './PostStatusEditable';
import Spinner from '../../shared/Spinner'; import Spinner from '../../common/Spinner';
import Box from '../../common/Box';
interface Props { interface Props {
authenticityToken: string; authenticityToken: string;
@@ -84,8 +85,8 @@ class PostStatusesSiteSettingsP extends React.Component<Props> {
const { postStatuses, settingsAreUpdating, settingsError } = this.props; const { postStatuses, settingsAreUpdating, settingsError } = this.props;
return ( return (
<React.Fragment> <>
<div className="content"> <Box>
<h2>{I18n.t('site_settings.post_statuses.title')}</h2> <h2>{I18n.t('site_settings.post_statuses.title')}</h2>
{ {
@@ -119,16 +120,16 @@ class PostStatusesSiteSettingsP extends React.Component<Props> {
: :
<CenteredMutedText>{I18n.t('site_settings.post_statuses.empty')}</CenteredMutedText> <CenteredMutedText>{I18n.t('site_settings.post_statuses.empty')}</CenteredMutedText>
} }
</div> </Box>
<div className="content"> <Box>
<h2>{I18n.t('site_settings.post_statuses.new')}</h2> <h2>{I18n.t('site_settings.post_statuses.new')}</h2>
<PostStatusForm mode='create' handleSubmit={this.handleSubmit} /> <PostStatusForm mode='create' handleSubmit={this.handleSubmit} />
</div> </Box>
<SiteSettingsInfoBox areUpdating={settingsAreUpdating || postStatuses.areLoading} error={settingsError} /> <SiteSettingsInfoBox areUpdating={settingsAreUpdating || postStatuses.areLoading} error={settingsError} />
</React.Fragment> </>
); );
} }
} }

View File

@@ -0,0 +1,14 @@
import * as React from 'react';
interface Props {
customClass?: string;
children: React.ReactNode;
}
const Box = ({ customClass, children }: Props) => (
<div className={`box ${customClass}`}>
{children}
</div>
);
export default Box;

View File

@@ -0,0 +1,13 @@
import * as React from 'react';
interface Props {
children: React.ReactNode;
}
const Sidebar = ({ children }: Props) => (
<div className="sidebar">
{children}
</div>
);
export default Sidebar;

View File

@@ -0,0 +1,18 @@
import * as React from 'react';
import { BoxTitleText } from './CustomTexts';
interface Props {
title: string;
customClass?: string;
children: React.ReactNode;
}
const SidebarBox = ({ title, customClass, children }: Props) => (
<div className={`sidebarBox ${customClass}`}>
<BoxTitleText>{title}</BoxTitleText>
{children}
</div>
);
export default SidebarBox;

View File

@@ -2,6 +2,7 @@ import * as React from 'react';
import I18n from 'i18n-js'; import I18n from 'i18n-js';
import Spinner from './Spinner'; import Spinner from './Spinner';
import Box from './Box';
interface Props { interface Props {
areUpdating: boolean; areUpdating: boolean;
@@ -9,7 +10,7 @@ interface Props {
} }
const SiteSettingsInfoBox = ({ areUpdating, error }: Props) => ( const SiteSettingsInfoBox = ({ areUpdating, error }: Props) => (
<div className="content siteSettingsInfo"> <Box customClass="siteSettingsInfo">
{ {
areUpdating ? areUpdating ?
<Spinner /> <Spinner />
@@ -21,7 +22,7 @@ const SiteSettingsInfoBox = ({ areUpdating, error }: Props) => (
: :
<span>{I18n.t('site_settings.info_box.up_to_date')}</span> <span>{I18n.t('site_settings.info_box.up_to_date')}</span>
} }
</div> </Box>
); );
export default SiteSettingsInfoBox; export default SiteSettingsInfoBox;

View File

@@ -0,0 +1,17 @@
import * as React from 'react';
interface Props {
label?: string;
onClick: React.MouseEventHandler;
checked?: boolean;
htmlId?: string;
}
const Switch = ({ label, onClick, checked, htmlId }: Props) => (
<div className="checkboxSwitch">
<input type="checkbox" id={htmlId} onClick={onClick} checked={checked} />
<label htmlFor={htmlId}>{label}</label>
</div>
);
export default Switch;

View File

@@ -1,13 +1,5 @@
import 'bootstrap/js/dist/alert' import 'bootstrap/js/dist/alert'
import 'bootstrap/js/dist/button' import 'bootstrap/js/dist/button'
import 'bootstrap/js/dist/carousel'
import 'bootstrap/js/dist/collapse' import 'bootstrap/js/dist/collapse'
import 'bootstrap/js/dist/dropdown' import 'bootstrap/js/dist/dropdown'
import 'bootstrap/js/dist/index'
import 'bootstrap/js/dist/modal'
import 'bootstrap/js/dist/popover'
import 'bootstrap/js/dist/scrollspy'
import 'bootstrap/js/dist/tab'
import 'bootstrap/js/dist/toast'
import 'bootstrap/js/dist/tooltip'
import 'bootstrap/js/dist/util' import 'bootstrap/js/dist/util'

View File

@@ -1,3 +0,0 @@
<% name = 'Erb' %>
console.log('Hello world from <%= name %>')

View File

@@ -24,7 +24,7 @@
} }
.mutedText { .mutedText {
color: $muted-text-color; color: $astuto-grey;
} }
.smallMutedText { .smallMutedText {

View File

@@ -9,7 +9,7 @@
} }
.form-control:focus { .form-control:focus {
border-color: $astuto-grey; border-color: $astuto-light-grey;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 4px rgba(0, 0, 0, 0.6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 4px rgba(0, 0, 0, 0.6);
} }
@@ -33,7 +33,7 @@
margin-top: 24px; margin-top: 24px;
a { color: $astuto-black; } a { color: $primary-color; }
} }
.switch { .switch {

View File

@@ -1,4 +1,9 @@
.navbar { .header {
@extend
.navbar,
.navbar-expand-md,
.navbar-light;
position: sticky; position: sticky;
z-index: 1; z-index: 1;
top: 0px; top: 0px;
@@ -13,7 +18,9 @@
margin-bottom: 1em; margin-bottom: 1em;
.navbar-brand { .brand {
@extend .navbar-brand;
font-size: 18pt; font-size: 18pt;
font-weight: 700; font-weight: 700;
@@ -27,7 +34,19 @@
} }
} }
.navbarToggler {
@extend .navbar-toggler;
&:focus {
outline: none;
}
}
.boardsNav { .boardsNav {
@extend
.navbar-nav,
.mr-auto;
.nav-item { .nav-item {
@extend @extend
.badge, .badge,
@@ -42,25 +61,26 @@
} }
} }
.profileNav {
@extend
.navbar-nav,
.ml-auto;
.profileToggle {
@extend
.nav-link,
.dropdown-toggle;
&::after { vertical-align: middle; }
}
.fullname { .fullname {
vertical-align: middle;
color: $astuto-black; color: $astuto-black;
}
.dropdown-toggle::after {
vertical-align: middle; vertical-align: middle;
} }
.navbar-toggler:focus {
outline: none;
}
.navbar-toggler[aria-expanded="true"] {
background-color: $astuto-grey;
} }
.dropdown-item:active { .dropdown-item:active {
background-color: $astuto-black; background-color: $primary-color;
} }
} }

View File

@@ -1,16 +1,10 @@
a {
color: $astuto-black;
&:hover { color: inherit; }
}
.card { .card {
@extend .card; @extend .card;
box-shadow: 0 1px 1px rgba(0,0,0,0.15), 0 1px 1px rgba(0,0,0,0.15); box-shadow: 0 1px 1px rgba(0,0,0,0.15), 0 1px 1px rgba(0,0,0,0.15);
transition: all 0.3s cubic-bezier(.25,.8,.25,1); transition: all 0.3s cubic-bezier(.25,.8,.25,1);
color: $astuto-black; color: $primary-color;
padding: 8px; padding: 8px;
} }
@@ -27,7 +21,8 @@ a {
} }
} }
.multiColumnContainer { // General container for pages with siderbar + main content
.twoColumnsContainer {
@extend @extend
.d-flex, .d-flex,
.justify-content-between, .justify-content-between,
@@ -37,18 +32,17 @@ a {
@include media-breakpoint-down(sm) { @include media-breakpoint-down(sm) {
flex-direction: column; flex-direction: column;
.postAndCommentsContainer { width: 100%; }
} }
}
.multiRowContent { // Make the main content full width
& > div:nth-child(2) {
@extend @extend
.flex-grow-1, .flex-grow-1,
.w-100; .w-100;
}
} }
.content { .box {
@extend @extend
.card, .card,
.flex-grow-1, .flex-grow-1,
@@ -60,7 +54,13 @@ a {
position: sticky; position: sticky;
top: 79px; top: 79px;
.sidebarCard { @include media-breakpoint-down(sm) {
position: relative;
width: 100%;
top: 0;
}
.sidebarBox {
@extend @extend
.card, .card,
.d-flex, .d-flex,
@@ -74,6 +74,10 @@ a {
width: 280px; width: 280px;
margin-right: 16px; margin-right: 16px;
@include media-breakpoint-down(sm) {
width: 100%;
}
} }
} }
@@ -85,8 +89,18 @@ a {
.text-center, .text-center,
.align-self-stretch; .align-self-stretch;
a {
color: $astuto-grey;
font-weight: 500;
&:hover {
color: $astuto-black;
}
}
.nav-link.active { .nav-link.active {
background-color: $astuto-black; color: $astuto-black;
background-color: $astuto-light-grey;
} }
} }
@@ -109,17 +123,6 @@ a {
&:active { cursor: grabbing; } &:active { cursor: grabbing; }
} }
@include media-breakpoint-down(sm) {
.sidebar {
position: relative;
width: 100%;
top: 0;
.sidebarCard { width: 100%; }
}
}
.badge { .badge {
@extend @extend
.badge, .badge,
@@ -132,5 +135,41 @@ a {
.badgeLight { .badgeLight {
@extend .badge-light; @extend .badge-light;
background-color: $astuto-grey; background-color: $astuto-light-grey;
}
.container {
max-width: 960px;
}
.turbolinks-progress-bar {
background-color: $primary-color;
height: 2px;
}
.gravatar {
border-radius: 100%;
}
.checkboxSwitch {
@extend
.custom-control,
.custom-switch;
& > input[type="checkbox"] {
@extend .custom-control-input;
}
& > label {
@extend .custom-control-label;
&::before {
transform: scale(1.2);
}
}
& > input:checked ~ label::before {
background-color: $primary-color !important;
border-color: $primary-color !important;
}
} }

View File

@@ -1,41 +1,3 @@
/*
This stylesheet contains styles that are general and
could not be grouped in a file of their own
*/
.container {
max-width: 960px;
}
.turbolinks-progress-bar {
background-color: $astuto-black;
height: 2px;
}
.gravatar {
border-radius: 100%;
}
.dot {
width: 16px;
height: 16px;
border-radius: 100%;
margin-top: auto;
margin-bottom: auto;
margin-right: 4px;
}
.loginInfo {
text-decoration: underline;
}
.btn {
color: #fff;
background-color: #343a40;
border-color: #343a40;
}
// Credits: https://codepen.io/chriscoyier/pen/YzXBYvL // Credits: https://codepen.io/chriscoyier/pen/YzXBYvL
.scroll-shadows { .scroll-shadows {
max-height: 200px; max-height: 200px;

View File

@@ -1,14 +1,7 @@
.boardContainer { .boardContainer {
@extend @extend .twoColumnsContainer;
.d-flex,
.justify-content-between,
.align-items-start;
flex-direction: row;
@include media-breakpoint-down(sm) { @include media-breakpoint-down(sm) {
flex-direction: column;
.postStatusFilterContainer { .postStatusFilterContainer {
flex-direction: row !important; flex-direction: row !important;
flex-wrap: wrap; flex-wrap: wrap;
@@ -18,7 +11,7 @@
} }
.newPostContainer { .newPostContainer {
background-color: $astuto-grey; background-color: $astuto-light-grey;
text-align: center; text-align: center;
.boardTitle { .boardTitle {
@@ -91,7 +84,7 @@
.p-3; .p-3;
height: 140px; height: 140px;
color: $astuto-black; color: $primary-color;
@include media-breakpoint-down(sm) { @include media-breakpoint-down(sm) {
height: auto; height: auto;

View File

@@ -95,7 +95,7 @@
font-size: 14px; font-size: 14px;
.commentLink { .commentLink {
color: $astuto-black; color: $primary-color;
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;

View File

@@ -15,13 +15,13 @@
border-bottom: $like_button_size solid rgba(35,35,35,.2); border-bottom: $like_button_size solid rgba(35,35,35,.2);
&:hover { &:hover {
border-bottom-color: $astuto-black; border-bottom-color: $primary-color;
cursor: pointer; cursor: pointer;
} }
} }
.likeButton.liked { .likeButton.liked {
border-bottom-color: $astuto-black; border-bottom-color: $primary-color;
} }
.likesCountLabel { .likesCountLabel {

View File

@@ -1,10 +1,5 @@
.pageContainer { .postContainer {
@extend @extend .twoColumnsContainer;
.d-flex,
.justify-content-between,
.align-items-start;
flex-direction: row;
@include media-breakpoint-down(sm) { @include media-breakpoint-down(sm) {
flex-direction: column; flex-direction: column;
@@ -14,8 +9,6 @@
.sidebar { .sidebar {
.postUpdateListContainer { .postUpdateListContainer {
@extend .sidebarCard;
.postUpdateList { .postUpdateList {
@extend @extend
.scroll-shadows, .scroll-shadows,
@@ -63,8 +56,6 @@
} }
.likeListContainer { .likeListContainer {
@extend .sidebarCard;
.likeList { .likeList {
@extend @extend
.scroll-shadows, .scroll-shadows,
@@ -86,14 +77,12 @@
} }
.actionBoxContainer { .actionBoxContainer {
@extend @extend .text-center;
.sidebarCard,
.text-center;
.btn { .checkboxSwitch {
@extend @extend
.mt-3, .mt-1,
.mb-1; .mb-2;
} }
} }
} }
@@ -141,7 +130,7 @@
@extend @extend
.my-3; .my-3;
color: $astuto-black; color: $primary-color;
} }
} }
} }

View File

@@ -11,7 +11,7 @@
.p-0; .p-0;
width: 32%; width: 32%;
background-color: $astuto-grey; background-color: $astuto-light-grey;
@include media-breakpoint-down(sm) { @include media-breakpoint-down(sm) {
width: 100%; width: 100%;

View File

@@ -1,3 +1,5 @@
$primary-color: #333;
$astuto-black: #333; $astuto-black: #333;
$astuto-grey: rgba(178, 178, 178, 0.15); $astuto-grey: rgba(0, 0, 0, 0.5);
$muted-text-color: #6c757d; $astuto-light-grey: rgba(178, 178, 178, 0.2);

View File

@@ -2,11 +2,11 @@
@import 'constants/colors'; @import 'constants/colors';
@import 'general/components'; @import 'common/index';
@import 'general/custom_texts'; @import 'common/custom_texts';
@import 'general/form'; @import 'common/form';
@import 'general/header'; @import 'common/header';
@import 'general/index'; @import 'common/scroll_shadows';
/* Components */ /* Components */
@import 'components/Board'; @import 'components/Board';

View File

@@ -1,26 +1,35 @@
<nav class="navbar navbar-expand-md navbar-light"> <nav class="header">
<div class="container"> <div class="container">
<%= <%=
link_to root_path, class: 'navbar-brand' do link_to root_path, class: 'brand' do
app_name = content_tag :span, Rails.application.name app_name = content_tag :span, Rails.application.name
logo = image_tag(asset_pack_path('media/images/logo.png'), class: 'logo') logo = image_tag(asset_pack_path('media/images/logo.png'), class: 'logo')
Rails.application.show_logo? ? logo + app_name : app_name Rails.application.show_logo? ? logo + app_name : app_name
end end
%> %>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<button
class="navbarToggler"
type="button"
data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse" id="navbarSupportedContent"> <div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="boardsNav navbar-nav mr-auto"> <ul class="boardsNav">
<%= render 'layouts/boards_menu_section', boards: @boards unless @boards.nil? %> <%= render 'layouts/boards_nav_section', boards: @boards unless @boards.nil? %>
</ul> </ul>
<ul class="navbar-nav ml-auto">
<% if user_signed_in? %>
<ul class="profileNav">
<% if user_signed_in? %>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a class="profileToggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= image_tag(current_user.gravatar_url, class: 'gravatar', alt: current_user.full_name, size: 24) %> <%= image_tag(current_user.gravatar_url, class: 'gravatar', alt: current_user.full_name, size: 24) %>
<span class="fullname"><%= current_user.full_name %></span> <span class="fullname"><%= current_user.full_name %></span>
</a> </a>
@@ -30,8 +39,11 @@
<%= link_to t('header.menu.admin_panel'), admin_root_path, class: 'dropdown-item', 'data-turbolinks': 'false' %> <%= link_to t('header.menu.admin_panel'), admin_root_path, class: 'dropdown-item', 'data-turbolinks': 'false' %>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<% end %> <% end %>
<%= link_to t('header.menu.profile_settings'), edit_user_registration_path, class: 'dropdown-item' %> <%= link_to t('header.menu.profile_settings'), edit_user_registration_path, class: 'dropdown-item' %>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<%= link_to t('header.menu.sign_out'), destroy_user_session_path, method: :delete, class: 'dropdown-item' %> <%= link_to t('header.menu.sign_out'), destroy_user_session_path, method: :delete, class: 'dropdown-item' %>
</div> </div>
</li> </li>

View File

@@ -1,6 +1,7 @@
<div class="sidebar"> <div class="sidebar">
<div class="sidebarCard"> <div class="sidebarBox">
<span class="boxTitleText"><%= t('site_settings.menu.title') %></span> <span class="boxTitleText"><%= t('site_settings.menu.title') %></span>
<div class="verticalNavigation" role="tablist" aria-orientation="vertical"> <div class="verticalNavigation" role="tablist" aria-orientation="vertical">
<%= render 'menu_link', label: t('site_settings.menu.boards'), path: site_settings_boards_path %> <%= render 'menu_link', label: t('site_settings.menu.boards'), path: site_settings_boards_path %>
<%= render 'menu_link', label: t('site_settings.menu.post_statuses'), path: site_settings_post_statuses_path %> <%= render 'menu_link', label: t('site_settings.menu.post_statuses'), path: site_settings_post_statuses_path %>

View File

@@ -1,6 +1,6 @@
<div class="multiColumnContainer"> <div class="twoColumnsContainer">
<%= render 'menu' %> <%= render 'menu' %>
<div class="multiRowContent"> <div>
<%= <%=
react_component( react_component(
'SiteSettings/Boards', 'SiteSettings/Boards',

View File

@@ -1,4 +1,4 @@
<div class="multiColumnContainer"> <div class="twoColumnsContainer">
<%= render 'menu' %> <%= render 'menu' %>
<div class="content"> <div class="content">

View File

@@ -1,6 +1,6 @@
<div class="multiColumnContainer"> <div class="twoColumnsContainer">
<%= render 'menu' %> <%= render 'menu' %>
<div class="multiRowContent"> <div>
<%= <%=
react_component( react_component(
'SiteSettings/PostStatuses', 'SiteSettings/PostStatuses',

View File

@@ -85,8 +85,7 @@ en:
empty: 'There are no likes yet' empty: 'There are no likes yet'
action_box: action_box:
title: 'Actions' title: 'Actions'
follow_button: 'Follow' follow_button: 'Follow post'
unfollow_button: 'Unfollow'
following_description: "you're receiving notifications about new updates on this post" following_description: "you're receiving notifications about new updates on this post"
not_following_description: "you won't receive notifications about this post" not_following_description: "you won't receive notifications about this post"
comments: comments:

View File

@@ -85,8 +85,7 @@ it:
empty: 'Non ci sono mi piace per ora' empty: 'Non ci sono mi piace per ora'
action_box: action_box:
title: 'Azioni' title: 'Azioni'
follow_button: 'Segui' follow_button: 'Segui post'
unfollow_button: 'Non seguire più'
following_description: 'riceverai notifiche sugli aggiornamenti di questo post' following_description: 'riceverai notifiche sugli aggiornamenti di questo post'
not_following_description: 'non riceverai alcuna notifica riguardo questo post' not_following_description: 'non riceverai alcuna notifica riguardo questo post'
comments: comments:

View File

@@ -11,7 +11,7 @@ RSpec.describe 'header', type: :view do
it 'renders a logo' do it 'renders a logo' do
render_header render_header
expect(rendered).to have_selector('.navbar-brand') expect(rendered).to have_selector('.brand')
end end
it 'renders a link for each board' do it 'renders a link for each board' do