mirror of
https://github.com/astuto/astuto.git
synced 2025-12-16 11:47:56 +01:00
Refactor CSS pt. 3 (semantically @extend Bootstrap)
This commit is contained in:
@@ -74,7 +74,7 @@ class BoardP extends React.Component<Props> {
|
|||||||
const { filters } = posts;
|
const { filters } = posts;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="boardContainer d-flex justify-content-between align-items-start">
|
<div className="boardContainer">
|
||||||
<div className="sidebar">
|
<div className="sidebar">
|
||||||
<NewPost
|
<NewPost
|
||||||
board={board}
|
board={board}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
DangerText,
|
DangerText,
|
||||||
SuccessText,
|
SuccessText,
|
||||||
} from '../shared/CustomTexts';
|
} from '../shared/CustomTexts';
|
||||||
|
import Button from '../shared/Button';
|
||||||
|
|
||||||
import IBoard from '../../interfaces/IBoard';
|
import IBoard from '../../interfaces/IBoard';
|
||||||
|
|
||||||
@@ -145,11 +146,12 @@ class NewPost extends React.Component<Props, State> {
|
|||||||
<MutedText>{board.description}</MutedText>
|
<MutedText>{board.description}</MutedText>
|
||||||
{
|
{
|
||||||
isLoggedIn ?
|
isLoggedIn ?
|
||||||
<button
|
<Button
|
||||||
onClick={this.toggleForm}
|
onClick={this.toggleForm}
|
||||||
className={`submitBtn btn btn-${showForm ? 'outline-' : ''}dark my-2`}>
|
className="submitBtn"
|
||||||
|
outline={showForm}>
|
||||||
{ showForm ? 'Cancel' : 'Submit feedback' }
|
{ showForm ? 'Cancel' : 'Submit feedback' }
|
||||||
</button>
|
</Button>
|
||||||
:
|
:
|
||||||
<a href="/users/sign_in" className="btn btn-dark">
|
<a href="/users/sign_in" className="btn btn-dark">
|
||||||
Log in / Sign up
|
Log in / Sign up
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import Button from '../shared/Button';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
@@ -41,11 +43,9 @@ const NewPostForm = ({
|
|||||||
id="postDescription"
|
id="postDescription"
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<Button onClick={e => handleSubmit(e)} className="submitBtn d-block mx-auto">
|
||||||
onClick={e => handleSubmit(e)}
|
|
||||||
className="submitBtn btn btn-dark d-block mx-auto">
|
|
||||||
Submit feedback
|
Submit feedback
|
||||||
</button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const PostList = ({
|
|||||||
page,
|
page,
|
||||||
hasMore
|
hasMore
|
||||||
}: Props) => (
|
}: Props) => (
|
||||||
<div className="postList d-flex flex-column flex-grow-1">
|
<div className="postList">
|
||||||
{ error ? <DangerText>{error}</DangerText> : null }
|
{ error ? <DangerText>{error}</DangerText> : null }
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
initialLoad={false}
|
initialLoad={false}
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ interface Props {
|
|||||||
|
|
||||||
const PostListItem = ({ id, title, description, postStatus}: Props) => (
|
const PostListItem = ({ id, title, description, postStatus}: Props) => (
|
||||||
<a href={`/posts/${id}`} className="postLink">
|
<a href={`/posts/${id}`} className="postLink">
|
||||||
<div className="postListItem d-flex flex-column justify-content-between m-0 px-2 py-1">
|
<div className="postListItem">
|
||||||
<TitleText>{title}</TitleText>
|
<TitleText>{title}</TitleText>
|
||||||
<DescriptionText limit={120}>{description}</DescriptionText>
|
<DescriptionText limit={120}>{description}</DescriptionText>
|
||||||
|
|
||||||
<div className="postDetails d-flex justify-content-between text-uppercase">
|
<div className="postDetails">
|
||||||
<CommentsNumber number={0} />
|
<CommentsNumber number={0} />
|
||||||
{ postStatus ? <PostStatusLabel {...postStatus} /> : null }
|
{ postStatus ? <PostStatusLabel {...postStatus} /> : null }
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import PostStatusLabel from '../shared/PostStatusLabel';
|
import PostStatusLabel from '../shared/PostStatusLabel';
|
||||||
|
import Button from '../shared/Button';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -19,17 +20,18 @@ const PostStatusListItem = ({
|
|||||||
handleResetFilter,
|
handleResetFilter,
|
||||||
}: Props) => (
|
}: Props) => (
|
||||||
<div className={
|
<div className={
|
||||||
"postStatusListItemContainer " + `postStatus${name.replace(/ /g, '')} d-flex align-self-stretch`
|
"postStatusListItemContainer " + `postStatus${name.replace(/ /g, '')}`
|
||||||
}>
|
}>
|
||||||
<a onClick={handleClick} className="postStatusListItemLink flex-grow-1">
|
<a onClick={handleClick} className="postStatusListItemLink">
|
||||||
<div className="postStatusListItem p-1">
|
<div className="postStatusListItem">
|
||||||
<PostStatusLabel id={undefined} name={name} color={color} />
|
<PostStatusLabel id={undefined} name={name} color={color} />
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
{
|
{
|
||||||
isCurrentFilter ?
|
isCurrentFilter ?
|
||||||
<button onClick={handleResetFilter}
|
<Button onClick={handleResetFilter} className="resetFilter" outline>
|
||||||
className="resetFilter btn btn-outline-dark">X</button>
|
X
|
||||||
|
</Button>
|
||||||
:
|
:
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import { Provider } from 'react-redux';
|
|||||||
import Board from '../../containers/Board';
|
import Board from '../../containers/Board';
|
||||||
import createStoreHelper from '../../helpers/createStore';
|
import createStoreHelper from '../../helpers/createStore';
|
||||||
|
|
||||||
import '../../stylesheets/components/Board.scss';
|
|
||||||
|
|
||||||
import IBoard from '../../interfaces/IBoard';
|
import IBoard from '../../interfaces/IBoard';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PostListByPostStatus = ({ postStatus, posts, boards }: Props) => (
|
const PostListByPostStatus = ({ postStatus, posts, boards }: Props) => (
|
||||||
<div className="roadmapColumn card my-2 px-2" style={{borderColor: postStatus.color}}>
|
<div className="roadmapColumn" style={{borderColor: postStatus.color}}>
|
||||||
<div className="columnHeader card-header d-flex bg-transparent"
|
<div className="columnHeader"
|
||||||
style={{borderBottomColor: postStatus.color}}>
|
style={{borderBottomColor: postStatus.color}}>
|
||||||
<div className="dot" style={{backgroundColor: postStatus.color}}></div>
|
<div className="dot" style={{backgroundColor: postStatus.color}}></div>
|
||||||
<div className="columnTitle"><TitleText>{postStatus.name}</TitleText></div>
|
<div className="columnTitle"><TitleText>{postStatus.name}</TitleText></div>
|
||||||
</div>
|
</div>
|
||||||
<div className="scrollContainer card-body">
|
<div className="scrollContainer">
|
||||||
<PostList
|
<PostList
|
||||||
posts={posts}
|
posts={posts}
|
||||||
boards={boards}
|
boards={boards}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ interface Props {
|
|||||||
|
|
||||||
const PostListItem = ({id, title, boardName}: Props) => (
|
const PostListItem = ({id, title, boardName}: Props) => (
|
||||||
<a href={`/posts/${id}`} className="postLink">
|
<a href={`/posts/${id}`} className="postLink">
|
||||||
<div className="postListItem d-flex flex-column my-1 py-2">
|
<div className="postListItem">
|
||||||
<TitleText>{title}</TitleText>
|
<TitleText>{title}</TitleText>
|
||||||
<UppercaseText>{boardName}</UppercaseText>
|
<UppercaseText>{boardName}</UppercaseText>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import IPostStatus from '../../interfaces/IPostStatus';
|
|||||||
import IPostJSON from '../../interfaces/json/IPost';
|
import IPostJSON from '../../interfaces/json/IPost';
|
||||||
import IBoard from '../../interfaces/IBoard';
|
import IBoard from '../../interfaces/IBoard';
|
||||||
|
|
||||||
import '../../stylesheets/components/Roadmap.scss';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
postStatuses: Array<IPostStatus>;
|
postStatuses: Array<IPostStatus>;
|
||||||
posts: Array<IPostJSON>;
|
posts: Array<IPostJSON>;
|
||||||
@@ -19,7 +17,7 @@ class Roadmap extends React.Component<Props> {
|
|||||||
const { postStatuses, posts, boards } = this.props;
|
const { postStatuses, posts, boards } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="roadmapColumns d-flex justify-content-between flex-wrap">
|
<div className="roadmapColumns">
|
||||||
{postStatuses.map((postStatus, i) => (
|
{postStatuses.map((postStatus, i) => (
|
||||||
<PostListByPostStatus
|
<PostListByPostStatus
|
||||||
postStatus={postStatus}
|
postStatus={postStatus}
|
||||||
|
|||||||
20
app/javascript/components/shared/Button.tsx
Normal file
20
app/javascript/components/shared/Button.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { FormEvent } from 'react';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: string;
|
||||||
|
onClick(e: FormEvent): void;
|
||||||
|
className?: string;
|
||||||
|
outline?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Button = ({ children, onClick, className = '', outline = false}: Props) => (
|
||||||
|
<button
|
||||||
|
onClick={onClick}
|
||||||
|
className={`${className} btn btn-${outline ? 'outline-' : ''}dark my-2`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Button;
|
||||||
@@ -10,27 +10,27 @@ interface DescriptionTextProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const TitleText = ({ children }: Props) => (
|
export const TitleText = ({ children }: Props) => (
|
||||||
<span className="text-dark font-weight-bolder">{children}</span>
|
<span className="titleText">{children}</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const MutedText = ({ children }: Props) => (
|
export const MutedText = ({ children }: Props) => (
|
||||||
<span className="text-muted text-center">{children}</span>
|
<span className="mutedText">{children}</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const UppercaseText = ({ children }: Props) => (
|
export const UppercaseText = ({ children }: Props) => (
|
||||||
<span className="text-secondary text-uppercase font-weight-lighter">{children}</span>
|
<span className="uppercaseText">{children}</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const SuccessText = ({ children }: Props) => (
|
export const SuccessText = ({ children }: Props) => (
|
||||||
<span className="text-success text-center">{children}</span>
|
<span className="successText">{children}</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const DangerText = ({ children }: Props) => (
|
export const DangerText = ({ children }: Props) => (
|
||||||
<span className="text-danger text-center">{children}</span>
|
<span className="dangerText">{children}</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const DescriptionText = ({ children, limit = 90}: DescriptionTextProps) => (
|
export const DescriptionText = ({ children, limit = 90}: DescriptionTextProps) => (
|
||||||
<span className="text-muted">
|
<span className="descriptionText">
|
||||||
{
|
{
|
||||||
children && children.length > limit ?
|
children && children.length > limit ?
|
||||||
children.slice(0, limit-1) + '...'
|
children.slice(0, limit-1) + '...'
|
||||||
|
|||||||
@@ -1,4 +1,20 @@
|
|||||||
.boardContainer {
|
.boardContainer {
|
||||||
|
@extend
|
||||||
|
.d-flex,
|
||||||
|
.justify-content-between,
|
||||||
|
.align-items-start;
|
||||||
|
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
position: sticky;
|
||||||
|
top: 20px;
|
||||||
|
|
||||||
|
.sidebarBox {
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 800px) {
|
@media (max-width: 800px) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
@@ -13,26 +29,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 801px) {
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
position: sticky;
|
|
||||||
top: 20px;
|
|
||||||
|
|
||||||
.sidebarBox {
|
.sidebarBox {
|
||||||
width: 250px;
|
@extend
|
||||||
}
|
.d-flex,
|
||||||
}
|
.flex-column,
|
||||||
}
|
.justify-content-start,
|
||||||
|
.align-items-center,
|
||||||
.sidebarBox {
|
.flex-grow-0,
|
||||||
flex: 0 0 auto;
|
.flex-shrink-0;
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
border: thin solid black;
|
border: thin solid black;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -41,7 +45,21 @@
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.postStatusListItemContainer {
|
||||||
|
@extend
|
||||||
|
.d-flex,
|
||||||
|
.align-self-stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postStatusListItemLink {
|
||||||
|
@extend
|
||||||
|
.flex-grow-1;
|
||||||
|
}
|
||||||
|
|
||||||
.postStatusListItem {
|
.postStatusListItem {
|
||||||
|
@extend
|
||||||
|
.p-1;
|
||||||
|
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@@ -53,13 +71,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.resetFilter {
|
.resetFilter {
|
||||||
flex: 0 0 auto;
|
@extend
|
||||||
|
.flex-grow-0,
|
||||||
|
.flex-shrink-0,
|
||||||
|
.align-self-center,
|
||||||
|
.p-0;
|
||||||
|
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
padding: 0;
|
.postList {
|
||||||
|
@extend
|
||||||
align-self: center;
|
.d-flex,
|
||||||
|
.flex-column,
|
||||||
|
.flex-grow-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.postLink {
|
.postLink {
|
||||||
@@ -67,14 +93,29 @@
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin: 8px 0;
|
margin: 8px 0;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
|
||||||
|
|
||||||
.postLink:hover {
|
&:hover {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.postListItem {
|
.postListItem {
|
||||||
|
@extend
|
||||||
|
.d-flex,
|
||||||
|
.flex-column,
|
||||||
|
.justify-content-between,
|
||||||
|
.m-0,
|
||||||
|
.px-2,
|
||||||
|
.py-1;
|
||||||
|
|
||||||
height: 114px;
|
height: 114px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.postDetails {
|
||||||
|
@extend
|
||||||
|
.d-flex,
|
||||||
|
.justify-content-between,
|
||||||
|
.text-uppercase;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,33 @@
|
|||||||
.roadmapColumns {
|
.roadmapColumns {
|
||||||
@media (max-width: 800px) {
|
@extend
|
||||||
|
.d-flex,
|
||||||
|
.justify-content-between,
|
||||||
|
.flex-wrap;
|
||||||
|
|
||||||
.roadmapColumn {
|
.roadmapColumn {
|
||||||
|
@extend
|
||||||
|
.card,
|
||||||
|
.my-2,
|
||||||
|
.px-2;
|
||||||
|
|
||||||
|
width: 32%;
|
||||||
|
|
||||||
|
@media (max-width: 800px) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 801px) {
|
.columnHeader {
|
||||||
.roadmapColumn {
|
@extend
|
||||||
width: 32%;
|
.card-header,
|
||||||
}
|
.d-flex,
|
||||||
|
.bg-transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scrollContainer {
|
.scrollContainer {
|
||||||
|
@extend
|
||||||
|
.card-body;
|
||||||
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
max-height: 350px;
|
max-height: 350px;
|
||||||
}
|
}
|
||||||
@@ -19,4 +35,12 @@
|
|||||||
.postLink:hover {
|
.postLink:hover {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.postListItem {
|
||||||
|
@extend
|
||||||
|
.d-flex,
|
||||||
|
.flex-column,
|
||||||
|
.my-1,
|
||||||
|
.py-2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
40
app/javascript/stylesheets/general/_custom_texts.scss
Normal file
40
app/javascript/stylesheets/general/_custom_texts.scss
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
This styles apply to custom texts defined in
|
||||||
|
/app/javascript/components/shared/CustomTexts.tsx
|
||||||
|
*/
|
||||||
|
|
||||||
|
.titleText {
|
||||||
|
@extend
|
||||||
|
.text-dark,
|
||||||
|
.font-weight-bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mutedText {
|
||||||
|
@extend
|
||||||
|
.text-muted,
|
||||||
|
.text-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uppercaseText {
|
||||||
|
@extend
|
||||||
|
.text-secondary,
|
||||||
|
.text-uppercase,
|
||||||
|
.font-weight-lighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
.successText {
|
||||||
|
@extend
|
||||||
|
.text-success,
|
||||||
|
.text-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dangerText {
|
||||||
|
@extend
|
||||||
|
.text-danger,
|
||||||
|
.text-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.descriptionText {
|
||||||
|
@extend
|
||||||
|
.text-muted;
|
||||||
|
}
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
@import 'vendors/bootstrap_custom';
|
@import 'vendors/bootstrap_custom';
|
||||||
|
|
||||||
@import 'general/index';
|
@import 'general/custom_texts';
|
||||||
@import 'general/navbar';
|
|
||||||
@import 'general/form';
|
@import 'general/form';
|
||||||
@import 'general/icons';
|
@import 'general/icons';
|
||||||
|
@import 'general/index';
|
||||||
|
@import 'general/navbar';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Components stylesheets are not imported here. Instead,
|
Components stylesheets are not imported here. Instead,
|
||||||
they are imported in the specific React components
|
they are imported in the specific React components
|
||||||
that use them
|
that use them
|
||||||
*/
|
*/
|
||||||
|
@import 'components/Board';
|
||||||
|
@import 'components/Post';
|
||||||
|
@import 'components/Roadmap';
|
||||||
Reference in New Issue
Block a user