🎨 style on conversations stacks

Signed-off-by: Baptiste Lemoine <contact@cipherbliss.com>
This commit is contained in:
Baptiste Lemoine 2020-01-07 16:44:50 +01:00
parent cda3febaac
commit 8dde1abdd4
10 changed files with 214 additions and 82 deletions

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { version, source_url } from 'mastodon/initial_state';
import { source_url, version } from 'mastodon/initial_state';
export default class ErrorBoundary extends React.PureComponent {
@ -10,17 +10,17 @@ export default class ErrorBoundary extends React.PureComponent {
};
state = {
hasError: false,
stackTrace: undefined,
hasError : false,
stackTrace : undefined,
componentStack: undefined,
};
componentDidCatch (error, info) {
componentDidCatch(error, info) {
this.setState({
hasError: true,
stackTrace: error.stack,
hasError : true,
stackTrace : error.stack,
componentStack: info && info.componentStack,
copied: false,
copied : false,
});
}
@ -28,7 +28,7 @@ export default class ErrorBoundary extends React.PureComponent {
const { stackTrace } = this.state;
const textarea = document.createElement('textarea');
textarea.textContent = stackTrace;
textarea.textContent = stackTrace;
textarea.style.position = 'fixed';
document.body.appendChild(textarea);
@ -44,7 +44,7 @@ export default class ErrorBoundary extends React.PureComponent {
this.setState({ copied: true });
setTimeout(() => this.setState({ copied: false }), 700);
}
};
render() {
const { hasError, copied } = this.state;
@ -54,13 +54,32 @@ export default class ErrorBoundary extends React.PureComponent {
}
return (
<div className='error-boundary'>
<div>
<p className='error-boundary__error'><FormattedMessage id='error.unexpected_crash.explanation' defaultMessage='Due to a bug in our code or a browser compatibility issue, this page could not be displayed correctly.' /></p>
<p><FormattedMessage id='error.unexpected_crash.next_steps' defaultMessage='Try refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.' /></p>
<p className='error-boundary__footer'>Mastodon v{version} · <a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='errors.unexpected_crash.report_issue' defaultMessage='Report issue' /></a> · <button onClick={this.handleCopyStackTrace} className={copied && 'copied'}><FormattedMessage id='errors.unexpected_crash.copy_stacktrace' defaultMessage='Copy stacktrace to clipboard' /></button></p>
</div>
</div>
<div className='error-boundary hero text-center padded content'>
<div >
<p className='error-boundary__error title content-heading'><FormattedMessage
id='error.unexpected_crash.explanation'
defaultMessage='Due to a bug in our code or a browser compatibility issue, this page could not be displayed correctly.'
/></p >
<p className='content'><FormattedMessage
id='error.unexpected_crash.next_steps'
defaultMessage='Try refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.'
/></p >
<p className='error-boundary__footer'>Mastodon v{version} · <a
href={source_url}
rel='noopener noreferrer'
target='_blank'
><FormattedMessage
id='errors.unexpected_crash.report_issue'
defaultMessage='Report issue'
/></a > · <button
onClick={this.handleCopyStackTrace}
className={copied && 'copied'}
><FormattedMessage
id='errors.unexpected_crash.copy_stacktrace'
defaultMessage='Copy stacktrace to clipboard'
/></button ></p >
</div >
</div >
);
}

View File

@ -106,7 +106,10 @@ class LinkFooter extends React.PureComponent {
var snowClasses = this.props.enableChristmasSnow ? 'snow-button active' : 'snow-button ';
const navToTags = HashTagNavlinks.map(element => {
return (
<li className='tag-element btn-small btn'>
<li
className='tag-element btn-small btn'
key={element}
>
<NavLink
exact

View File

@ -1,21 +1,59 @@
import React from 'react';
import Contact from './Contact';
import PropTypes from 'prop-types';
import ConversationStream from './conversation-stream';
/**
* a conversation between the current logged in user and one recipient
*/
export default class ConversationItem extends React.PureComponent {
static propTypes = {
messages : PropTypes.array, // our and their message sorted chronologically
recipient : PropTypes.any, // account of the person we talk to, not current logged in account
newMessages: PropTypes.number,
displayed : PropTypes.bool,
};
following = [];
render() {
static defaultProps = {
newMessages: 0,
displayed : true,
};
constructor(props) {
super(props);
this.state = {
composeMessage: '',
displayed : this.props.displayed,
};
}
submitCompose() {
console.log('submit');
}
handleChange(e) {
// e.preventDefault();
console.log('e', e);
}
render() {
const hasNewClass = this.props.newMessages ? 'has-new-message' : 'nothing-new';
const isVisible = this.props.displayed ? 'displayed' : 'hidden';
const list = (
<li className='conversations_item has-new-message'>
<div className='title'>
<li className={'conversation-item ' + hasNewClass + ' ' + isVisible}>
<div className='top-title'>
<i
role='img'
className='fa fa-envelope column-header__icon fa-fw'
/>
Un Gens
<span className='new-message-counter'>
(3)</span >
<Contact account={this.props.recipient} />
{this.props.newMessages && (
<span className='new-message-counter'>
({this.props.newMessages})
</span >
)}
<button className='btn-small'>
<i
role='img'
@ -23,24 +61,11 @@ export default class ConversationItem extends React.PureComponent {
/>
</button >
</div >
<div className='conversation_stream'>
<div className='message theirs'>
<p >oh hello there! 😋 </p >
<div className='arrow-down' />
</div >
<div className='message mine'>
<p >General Emoji</p >
<div className='arrow-down' />
</div >
<div className='message theirs'>
<p >we just achieved comedy</p >
<div className='arrow-down' />
</div >
</div >
<ConversationStream messages={this.props.messages} />
<div className='conversation_input'>
<form
action='#'
onSubmit={this.submitCompose()}
onSubmit={this.submitCompose}
>
<textarea
name='messager'
@ -49,6 +74,8 @@ export default class ConversationItem extends React.PureComponent {
rows='3'
className='messager-textarea'
placeholder='allez dis nous tout'
value={this.state.composeMessage}
onChange={this.handleChange}
/>
<input

View File

@ -1,12 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
export default class ConversationStream extends React.PureComponent {
static propTypes = {
messages: PropTypes.array,
};
render() {
return (
<div class='conversation-stream'>
ConversationStream todo
let messagesLists = (
<div className='no_messages'>
no messages
</div >
);
if (this.props.messages) {
messagesLists = this.props.messages.map(message => {
return (
<li className={'message ' + message.text}>
<p >{message.text}</p >
<div className='arrow-down' />
</li >
);
});
}
return (
<div className='conversation-stream'>
<ul className='messages'>
{messagesLists}
</ul >
</div >
);
}

View File

@ -1,21 +1,17 @@
import React from 'react';
import PropTypes from 'prop-types';
import { mockContactList } from './mockContactList';
import Contact from './Contact';
import ConversationItem from './conversation-item';
const following = mockContactList;
import { mockRecipient, mockRecipient2 } from './mockConversation';
export default class ConversationStack extends React.Component {
static propTypes = {
following: PropTypes.array,
// conversations: PropTypes.array,
conversations: PropTypes.array,
};
static defaultProps = {
following: following,
conversations: [mockRecipient, mockRecipient2],
};
openConversationWith(account) {
@ -23,20 +19,26 @@ export default class ConversationStack extends React.Component {
}
render() {
let list = this.props.conversations.map(conversations =>
(
<li
className='conversation-item-wrapper'
key={conversations.id}
>
<ConversationItem
recipient={mockRecipient}
messages={mockRecipient.messages}
key={conversations.id}
onClick={this.openConversationWith}
/>
</li >
),
);
return (
<ul className='stack conversations_list'>
{list}
</ul >
return this.props.following.map(elem =>
(<li className='user-item'>
<div className='conversation-box'>
<div
className='conversation-header'
onClick={this.openConversationWith(elem)}
>
<Contact account={elem} />
</div >
<ConversationItem />
</div >
</li >),
);
};

View File

@ -0,0 +1,33 @@
export const mockMessages = [
{ text: 'oh hello there! 😋 ', who: 'theirs' },
{ text: 'General Emoji', who: 'ours' },
{ text: 'we just achieved comedy', who: 'theirs' },
]
;
export const mockMessages2 = [
{ text: 'oh oh oh ', who: 'theirs' },
{ text: 'General Emoji', who: 'ours' },
{ text: 'DANGER!!', who: 'theirs' },
{ text: 'JUST KIDDING WILL ROBINSON.', who: 'theirs' },
]
;
export const mockRecipient = [
{
id : 3,
username : 'chuck norris',
newMessages: 5,
messages : mockMessages,
},
]
;
export const mockRecipient2 = [
{
id : 4,
username : 'the Bo botte',
newMessages: 0,
messages : mockMessages2,
},
]
;

View File

@ -384,6 +384,22 @@ hr.spacer {
max-width: 100%;
}
input {
background: auto;
}
hr,
.select select,
.textarea,
.input {
background-color: transparent;
border-color: transparent;
&:hover {
border: transparent;
}
}
.batch-form-box {
display: flex;
flex-wrap: wrap;

View File

@ -1,5 +1,6 @@
$messagingBoxWidth: 20em;
$messagingBoxHeight: 100%;
$conversationBoxHeight: 20em;
.fixed-box {
border: solid 1px white;
@ -99,20 +100,22 @@ $messagingBoxHeight: 100%;
}
.conversations_list {
right: 1em;
position: absolute;
@extend .fixed-box;
right: $messagingBoxWidth + 2em;
bottom: 0;
width: 100%;
padding: 0.5em;
background: gray;
overflow-x: auto;
}
.conversation-item {
@extend .fixed-box;
width: $messagingBoxWidth;
right: $messagingBoxWidth + 5em;
background: $ui-secondary-color;
float: right;
width: 20em;
margin-left: 2em;
padding: 1em;
border-radius: 15px;
background: $classic-base-color;
&.has-new-message {
background: $ui-highlight-color;
@ -126,7 +129,7 @@ $messagingBoxHeight: 100%;
.conversation_stream {
padding-top: 1em;
height: $messagingBoxHeight;
height: $conversationBoxHeight;
overflow: auto;
background: $ui-secondary-color;

View File

@ -229,3 +229,7 @@ button {
}
}
}
.padded {
padding: 1em;
}

View File

@ -32,25 +32,27 @@
%hr.spacer/
.fields-row
.fields-row__column.fields-group.fields-row__column-6
.input.with_block_label
.custom-label-container
.fields-group.custom_labels_container
.with_block_label
%label= t('simple_form.labels.defaults.fields')
%span.hint= t('simple_form.hints.defaults.fields')
= f.simple_fields_for :fields do |fields_f|
.row
= fields_f.input :name, placeholder: t('simple_form.labels.account.fields.name'), input_html: { maxlength: 255 }
= fields_f.input :value, placeholder: t('simple_form.labels.account.fields.value'), input_html: { maxlength: 255 }
.columns
.column.tag-side
= fields_f.input :name, placeholder: t('simple_form.labels.account.fields.name'), input_html: { maxlength: 255 }
.column.value-side
= fields_f.input :value, placeholder: t('simple_form.labels.account.fields.value'), input_html: { maxlength: 255 }
.fields-row__column.fields-group.fields-row__column-6
%h6= t('verification.verification')
%p.hint= t('verification.explanation_html')
.fields-group.verification-container
%h6= t('verification.verification')
%p.hint= t('verification.explanation_html')
.input-copy
.input-copy__wrapper
%input{ type: :text, maxlength: '999', spellcheck: 'false', readonly: 'true', value: link_to('Mastodon', ActivityPub::TagManager.instance.url_for(@account), rel: 'me').to_str }
%button{ type: :button }= t('generic.copy')
.input-copy
.input-copy__wrapper
%input{ type: :text, maxlength: '999', spellcheck: 'false', readonly: 'true', value: link_to('Mastodon', ActivityPub::TagManager.instance.url_for(@account), rel: 'me').to_str }
%button{ type: :button }= t('generic.copy')
.actions
= f.button :button, t('generic.save_changes'), type: :submit