More styling for statuses

pull/69/head
Eugen Rochko 2016-08-24 21:08:00 +02:00
parent bc0692d75b
commit a541e937ca
11 changed files with 135 additions and 379 deletions

View File

@ -0,0 +1,17 @@
const Avatar = React.createClass({
propTypes: {
src: React.PropTypes.string.isRequired
},
render () {
return (
<div style={{ width: '48px', height: '48px', flex: '0 0 auto' }}>
<img src={this.props.src} width={48} height={48} alt='' style={{ display: 'block', borderRadius: '4px' }} />
</div>
);
}
});
export default Avatar;

View File

@ -0,0 +1,22 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
const DisplayName = React.createClass({
propTypes: {
account: ImmutablePropTypes.map.isRequired
},
render () {
var displayName = this.props.account.get('display_name', this.props.account.get('username'));
var acct = this.props.account.get('acct');
var url = this.props.account.get('url');
return (
<a href={url} style={{ color: '#616b86', textDecoration: 'none' }}>
<strong style={{ fontWeight: 'bold', color: '#fff' }}>{displayName}</strong> <span>{acct}</span>
</a>
);
}
});
export default DisplayName;

View File

@ -0,0 +1,55 @@
import moment from 'moment';
moment.updateLocale('en', {
relativeTime : {
future: "in %s",
past: "%s ago",
s: "s",
m: "a minute",
mm: "%dm",
h: "an hour",
hh: "%dh",
d: "a day",
dd: "%dd",
M: "a month",
MM: "%dm",
y: "a year",
yy: "%dy"
}
});
const RelativeTimestamp = React.createClass({
getInitialState () {
return {
text: ''
};
},
propTypes: {
timestamp: React.PropTypes.string.isRequired
},
componentWillMount () {
this._updateMomentText();
this.interval = setInterval(this._updateMomentText, 6000);
},
componentWillUnmount () {
clearInterval(this.interval);
},
_updateMomentText () {
this.setState({ text: moment(this.props.timestamp).fromNow() });
},
render () {
return (
<span style={{ color: '#616b86' }}>
{this.state.text}
</span>
);
}
});
export default RelativeTimestamp;

View File

@ -1,17 +1,32 @@
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import Avatar from './avatar';
import DisplayName from './display_name';
import RelativeTimestamp from './relative_timestamp';
const Status = React.createClass({ const Status = React.createClass({
propTypes: { propTypes: {
status: ImmutablePropTypes.map.isRequired status: ImmutablePropTypes.map.isRequired
}, },
render: function() { render () {
var content = { __html: this.props.status.get('content') }; var content = { __html: this.props.status.get('content') };
var status = this.props.status;
return ( return (
<div style={{ padding: '5px' }}> <div style={{ padding: '8px 10px', display: 'flex', flexDirection: 'row', borderBottom: '1px solid #363c4b' }}>
<div><strong>{this.props.status.getIn(['account', 'username'])}</strong></div> <Avatar src={status.getIn(['account', 'avatar'])} />
<div dangerouslySetInnerHTML={content} />
<div style={{ flex: '1 1 auto', marginLeft: '10px' }}>
<div style={{ overflow: 'hidden' }}>
<div style={{ float: 'right' }}>
<a href={status.get('url')} style={{ textDecoration: 'none' }}><RelativeTimestamp timestamp={status.get('created_at')} /></a>
</div>
<DisplayName account={status.get('account')} />
</div>
<div className='status__content' dangerouslySetInnerHTML={content} style={{ fontSize: '14px' }} />
</div>
</div> </div>
); );
} }

View File

@ -357,7 +357,6 @@ body {
} }
} }
@import 'home';
@import 'accounts'; @import 'accounts';
@import 'stream_entries'; @import 'stream_entries';
@import 'dashboard' @import 'components'

View File

@ -0,0 +1,20 @@
.status__content {
a {
color: #2b90d9;
text-decoration: none;
&:hover {
text-decoration: underline;
}
&.mention {
&:hover {
text-decoration: none;
span {
text-decoration: underline;
}
}
}
}
}

View File

@ -1,356 +0,0 @@
.dashboard-wrapper {
background: #282c37;
border-radius: 4px;
margin: 20px auto;
width: 940px;
display: flex;
overflow: hidden;
.dashboard__sidebar {
width: 240px;
border-radius: 4px 0 0 4px;
flex-shrink: 0;
.dashboard__top-bar {
border-radius: 4px 0 0 0;
}
ul {
padding: 20px 0;
a {
display: block;
padding: 7px 20px;
color: #d9e1e8;
text-decoration: none;
font-size: 14px;
font-weight: 400;
.fa {
display: inline-block;
width: 18px;
text-align: center;
margin-right: 5px;
}
&:hover {
color: #fff;
background: darken(#282c37, 1%);
}
}
.active {
a {
background: darken(#282c37, 5%);
border-left: 2px solid #2b90d9;
padding-left: 18px;
}
}
}
}
.dashboard__current-user {
padding: 20px;
a {
text-decoration: none;
color: inherit;
outline: 0;
}
.dashboard__current-user__avatar {
display: block;
width: 50px;
height: 50px;
border-radius: 50px;
float: left;
margin-right: 15px;
}
.dashboard__current-user__display-name {
font-weight: 500;
font-size: 13px;
color: #d9e1e8;
display: block;
margin-top: 5px;
}
.dashboard__current-user__username {
font-size: 12px;
display: block;
color: #2b90d9;
}
}
.dashboard__logo {
color: #2b90d9;
span {
font-weight: 500;
}
}
.dashboard__top-bar {
background: #fff;
padding: 20px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
color: #282c37;
font-size: 16px;
overflow: hidden;
&.alternate {
background: lighten(#282c37, 10%);
text-align: center;
}
ul {
float: right;
list-style: none;
display: block;
li {
display: inline-block;
margin-left: 7px;
}
}
a {
color: #9baec8;
text-decoration: none;
}
}
.dashboard__content {
flex: 1;
background: #d9e1e8;
border-radius: 0 4px 4px 0;
.dashboard__top-bar {
border-radius: 0 4px 0 0;
}
}
}
.dashboard__content__content {
padding: 20px;
color: #282c37;
line-height: 18px;
h3 {
font-size: 14px;
font-weight: 500;
margin-bottom: 15px;
}
p {
margin-bottom: 15px;
}
samp {
font-family: 'Roboto Mono', monospace;
}
ul {
list-style: circle;
padding-left: 15px;
margin-bottom: 15px;
}
.table {
width: 100%;
th {
font-weight: 500;
text-align: left;
border-bottom: 1px solid lighten(#282c37, 55%);
}
th, td {
padding: 5px 0;
line-height: 18px;
}
}
a {
color: #2b90d9;
text-decoration: underline;
&:hover {
text-decoration: none;
}
}
.btn {
display: inline-block;
border: 0;
background: #2b90d9;
border-radius: 16px;
padding: 6px 16px;
font-size: 12px;
font-weight: 500;
color: #fff;
cursor: pointer;
font-family: 'Roboto', sans-serif;
text-decoration: none;
&:hover {
background: lighten(#2b90d9, 5%);
}
&.btn-iconized {
font-size: 16px;
font-weight: 400;
width: 24px;
text-align: center;
padding: 10px 7px;
border-radius: 100px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
}
}
hr {
clear: both;
border: 0;
padding: 0;
width: 100%;
height: 0;
margin: 30px 0;
}
}
.simple_form {
.form-actions {
padding-top: 20px;
text-align: center;
}
.error_notification {
color: #df405a;
font-weight: 500;
margin-bottom: 15px;
}
.input {
margin-bottom: 15px;
label {
display: block;
text-transform: uppercase;
font-size: 11px;
font-weight: 500;
margin-bottom: 10px;
}
input[type=text], input[type=email], input[type=password], textarea {
display: block;
box-sizing: border-box;
width: 100%;
border: 0;
background: transparent;
border-bottom: 1px solid lighten(#282c37, 55%);
padding: 5px 0;
outline: 0;
padding-bottom: 6px;
font-size: 14px;
font-family: 'Roboto', sans-serif;
color: #282c37;
&:focus, &:active {
border-bottom: 2px solid #2b90d9;
padding-bottom: 5px;
}
}
input[type=file] {
display: block;
}
.hint {
display: block;
margin-top: 5px;
color: lighten(#282c37, 25%);
}
&.field_with_errors {
input[type=text], input[type=email], input[type=password], textarea {
border-bottom: 2px solid #df405a;
padding-bottom: 5px;
&:focus, &:active {
border-bottom: 2px solid #2b90d9;
padding-bottom: 5px;
}
}
.error {
display: block;
margin-top: 5px;
color: #df405a;
}
}
}
}
.panel {
box-sizing: border-box;
padding: 10px 15px;
background: lighten(#d9e1e8, 5%);
margin-bottom: 20px;
border-radius: 4px;
.panel-heading {
font-size: 13px;
text-transform: uppercase;
color: lighten(#282c37, 25%);
margin-bottom: 10px;
}
&.panel-full {
width: 100%;
}
.panel-row {
display: flex;
dt {
color: #282c37;
width: 100px;
}
dd {
flex: 1;
color: lighten(#282c37, 25%);
}
&.panel-row-wider {
dt {
width: auto;
flex: 1;
}
}
}
}
.row {
overflow: hidden;
clear: both;
.panel {
float: left;
width: 320px;
margin-right: 20px;
&:last-child {
margin-right: 0;
}
}
}
.page-actions {
margin-top: 20px;
text-align: right;
.btn {
margin-left: 5px;
}
}

View File

@ -1,11 +0,0 @@
.api-descriptions {
.address {
samp {
font-weight: 400;
&.method {
font-weight: 500;
}
}
}
}

View File

@ -1,3 +0,0 @@
// Place all the styles related to the settings controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,3 +0,0 @@
// Place all the styles related to the statuses controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -12,6 +12,7 @@
}, },
"dependencies": { "dependencies": {
"immutable": "^3.8.1", "immutable": "^3.8.1",
"moment": "^2.14.1",
"react-immutable-proptypes": "^2.1.0", "react-immutable-proptypes": "^2.1.0",
"react-redux": "^4.4.5", "react-redux": "^4.4.5",
"redux": "^3.5.2", "redux": "^3.5.2",