mirror of https://framagit.org/tykayn/mastodon.git
🎨 style on conversations stacks
Signed-off-by: Baptiste Lemoine <contact@cipherbliss.com>
This commit is contained in:
parent
cda3febaac
commit
8dde1abdd4
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { FormattedMessage } from 'react-intl';
|
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 {
|
export default class ErrorBoundary extends React.PureComponent {
|
||||||
|
|
||||||
|
@ -10,17 +10,17 @@ export default class ErrorBoundary extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
hasError: false,
|
hasError : false,
|
||||||
stackTrace: undefined,
|
stackTrace : undefined,
|
||||||
componentStack: undefined,
|
componentStack: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidCatch (error, info) {
|
componentDidCatch(error, info) {
|
||||||
this.setState({
|
this.setState({
|
||||||
hasError: true,
|
hasError : true,
|
||||||
stackTrace: error.stack,
|
stackTrace : error.stack,
|
||||||
componentStack: info && info.componentStack,
|
componentStack: info && info.componentStack,
|
||||||
copied: false,
|
copied : false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ export default class ErrorBoundary extends React.PureComponent {
|
||||||
const { stackTrace } = this.state;
|
const { stackTrace } = this.state;
|
||||||
const textarea = document.createElement('textarea');
|
const textarea = document.createElement('textarea');
|
||||||
|
|
||||||
textarea.textContent = stackTrace;
|
textarea.textContent = stackTrace;
|
||||||
textarea.style.position = 'fixed';
|
textarea.style.position = 'fixed';
|
||||||
|
|
||||||
document.body.appendChild(textarea);
|
document.body.appendChild(textarea);
|
||||||
|
@ -44,7 +44,7 @@ export default class ErrorBoundary extends React.PureComponent {
|
||||||
|
|
||||||
this.setState({ copied: true });
|
this.setState({ copied: true });
|
||||||
setTimeout(() => this.setState({ copied: false }), 700);
|
setTimeout(() => this.setState({ copied: false }), 700);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { hasError, copied } = this.state;
|
const { hasError, copied } = this.state;
|
||||||
|
@ -54,13 +54,32 @@ export default class ErrorBoundary extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='error-boundary'>
|
<div className='error-boundary hero text-center padded content'>
|
||||||
<div>
|
<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 className='error-boundary__error title content-heading'><FormattedMessage
|
||||||
<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>
|
id='error.unexpected_crash.explanation'
|
||||||
<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>
|
defaultMessage='Due to a bug in our code or a browser compatibility issue, this page could not be displayed correctly.'
|
||||||
</div>
|
/></p >
|
||||||
</div>
|
<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 >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,10 @@ class LinkFooter extends React.PureComponent {
|
||||||
var snowClasses = this.props.enableChristmasSnow ? 'snow-button active' : 'snow-button ';
|
var snowClasses = this.props.enableChristmasSnow ? 'snow-button active' : 'snow-button ';
|
||||||
const navToTags = HashTagNavlinks.map(element => {
|
const navToTags = HashTagNavlinks.map(element => {
|
||||||
return (
|
return (
|
||||||
<li className='tag-element btn-small btn'>
|
<li
|
||||||
|
className='tag-element btn-small btn'
|
||||||
|
key={element}
|
||||||
|
>
|
||||||
|
|
||||||
<NavLink
|
<NavLink
|
||||||
exact
|
exact
|
||||||
|
|
|
@ -1,21 +1,59 @@
|
||||||
import React from 'react';
|
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 {
|
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 = [];
|
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 = (
|
const list = (
|
||||||
<li className='conversations_item has-new-message'>
|
<li className={'conversation-item ' + hasNewClass + ' ' + isVisible}>
|
||||||
<div className='title'>
|
<div className='top-title'>
|
||||||
<i
|
<i
|
||||||
role='img'
|
role='img'
|
||||||
className='fa fa-envelope column-header__icon fa-fw'
|
className='fa fa-envelope column-header__icon fa-fw'
|
||||||
/>
|
/>
|
||||||
Un Gens
|
<Contact account={this.props.recipient} />
|
||||||
<span className='new-message-counter'>
|
{this.props.newMessages && (
|
||||||
(3)</span >
|
<span className='new-message-counter'>
|
||||||
|
({this.props.newMessages})
|
||||||
|
</span >
|
||||||
|
)}
|
||||||
<button className='btn-small'>
|
<button className='btn-small'>
|
||||||
<i
|
<i
|
||||||
role='img'
|
role='img'
|
||||||
|
@ -23,24 +61,11 @@ export default class ConversationItem extends React.PureComponent {
|
||||||
/>
|
/>
|
||||||
</button >
|
</button >
|
||||||
</div >
|
</div >
|
||||||
<div className='conversation_stream'>
|
<ConversationStream messages={this.props.messages} />
|
||||||
<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 >
|
|
||||||
<div className='conversation_input'>
|
<div className='conversation_input'>
|
||||||
<form
|
<form
|
||||||
action='#'
|
action='#'
|
||||||
onSubmit={this.submitCompose()}
|
onSubmit={this.submitCompose}
|
||||||
>
|
>
|
||||||
<textarea
|
<textarea
|
||||||
name='messager'
|
name='messager'
|
||||||
|
@ -49,6 +74,8 @@ export default class ConversationItem extends React.PureComponent {
|
||||||
rows='3'
|
rows='3'
|
||||||
className='messager-textarea'
|
className='messager-textarea'
|
||||||
placeholder='allez dis nous tout'
|
placeholder='allez dis nous tout'
|
||||||
|
value={this.state.composeMessage}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
|
|
|
@ -1,12 +1,35 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class ConversationStream extends React.PureComponent {
|
export default class ConversationStream extends React.PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
messages: PropTypes.array,
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
let messagesLists = (
|
||||||
<div class='conversation-stream'>
|
<div className='no_messages'>
|
||||||
ConversationStream todo
|
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 >
|
</div >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { mockContactList } from './mockContactList';
|
|
||||||
import Contact from './Contact';
|
|
||||||
import ConversationItem from './conversation-item';
|
import ConversationItem from './conversation-item';
|
||||||
|
import { mockRecipient, mockRecipient2 } from './mockConversation';
|
||||||
const following = mockContactList;
|
|
||||||
|
|
||||||
export default class ConversationStack extends React.Component {
|
export default class ConversationStack extends React.Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
following: PropTypes.array,
|
conversations: PropTypes.array,
|
||||||
// conversations: PropTypes.array,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
following: following,
|
conversations: [mockRecipient, mockRecipient2],
|
||||||
};
|
};
|
||||||
|
|
||||||
openConversationWith(account) {
|
openConversationWith(account) {
|
||||||
|
@ -23,20 +19,26 @@ export default class ConversationStack extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
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 >),
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
;
|
|
@ -384,6 +384,22 @@ hr.spacer {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
background: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr,
|
||||||
|
.select select,
|
||||||
|
.textarea,
|
||||||
|
.input {
|
||||||
|
background-color: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.batch-form-box {
|
.batch-form-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
$messagingBoxWidth: 20em;
|
$messagingBoxWidth: 20em;
|
||||||
$messagingBoxHeight: 100%;
|
$messagingBoxHeight: 100%;
|
||||||
|
$conversationBoxHeight: 20em;
|
||||||
|
|
||||||
.fixed-box {
|
.fixed-box {
|
||||||
border: solid 1px white;
|
border: solid 1px white;
|
||||||
|
@ -99,20 +100,22 @@ $messagingBoxHeight: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.conversations_list {
|
.conversations_list {
|
||||||
right: 1em;
|
@extend .fixed-box;
|
||||||
position: absolute;
|
right: $messagingBoxWidth + 2em;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
background: gray;
|
|
||||||
|
|
||||||
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.conversation-item {
|
.conversation-item {
|
||||||
@extend .fixed-box;
|
float: right;
|
||||||
width: $messagingBoxWidth;
|
width: 20em;
|
||||||
right: $messagingBoxWidth + 5em;
|
margin-left: 2em;
|
||||||
background: $ui-secondary-color;
|
padding: 1em;
|
||||||
|
border-radius: 15px;
|
||||||
|
background: $classic-base-color;
|
||||||
|
|
||||||
&.has-new-message {
|
&.has-new-message {
|
||||||
background: $ui-highlight-color;
|
background: $ui-highlight-color;
|
||||||
|
@ -126,7 +129,7 @@ $messagingBoxHeight: 100%;
|
||||||
|
|
||||||
.conversation_stream {
|
.conversation_stream {
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
height: $messagingBoxHeight;
|
height: $conversationBoxHeight;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
background: $ui-secondary-color;
|
background: $ui-secondary-color;
|
||||||
|
|
||||||
|
|
|
@ -229,3 +229,7 @@ button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.padded {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
|
@ -32,25 +32,27 @@
|
||||||
|
|
||||||
%hr.spacer/
|
%hr.spacer/
|
||||||
|
|
||||||
.fields-row
|
.custom-label-container
|
||||||
.fields-row__column.fields-group.fields-row__column-6
|
.fields-group.custom_labels_container
|
||||||
.input.with_block_label
|
.with_block_label
|
||||||
%label= t('simple_form.labels.defaults.fields')
|
%label= t('simple_form.labels.defaults.fields')
|
||||||
%span.hint= t('simple_form.hints.defaults.fields')
|
%span.hint= t('simple_form.hints.defaults.fields')
|
||||||
|
|
||||||
= f.simple_fields_for :fields do |fields_f|
|
= f.simple_fields_for :fields do |fields_f|
|
||||||
.row
|
.columns
|
||||||
= fields_f.input :name, placeholder: t('simple_form.labels.account.fields.name'), input_html: { maxlength: 255 }
|
.column.tag-side
|
||||||
= fields_f.input :value, placeholder: t('simple_form.labels.account.fields.value'), input_html: { maxlength: 255 }
|
= 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
|
.fields-group.verification-container
|
||||||
%h6= t('verification.verification')
|
%h6= t('verification.verification')
|
||||||
%p.hint= t('verification.explanation_html')
|
%p.hint= t('verification.explanation_html')
|
||||||
|
|
||||||
.input-copy
|
.input-copy
|
||||||
.input-copy__wrapper
|
.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 }
|
%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')
|
%button{ type: :button }= t('generic.copy')
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
= f.button :button, t('generic.save_changes'), type: :submit
|
= f.button :button, t('generic.save_changes'), type: :submit
|
||||||
|
|
Loading…
Reference in New Issue