Large update for all components

reorganization, linting, updating file imports, consolidation
warning: there will be errors in this commit
todo: update webpack, add missing styles, scss files, consolidate the rest of components within features/*
This commit is contained in:
mgabdev
2019-08-07 01:02:36 -04:00
parent 5505f60119
commit 280dc51d85
341 changed files with 8876 additions and 8321 deletions

View File

@@ -1,167 +1 @@
import ReactSwipeableViews from 'react-swipeable-views';
import classNames from 'classnames';
import { FormattedMessage } from 'react-intl';
import { closeOnboarding } from '../../actions/onboarding';
const FrameWelcome = ({ domain, onNext }) => (
<div className='introduction__frame'>
<div className='introduction__text introduction__text--centered'>
<h3><FormattedMessage id='introduction.welcome.headline' defaultMessage='First steps' /></h3>
<p><FormattedMessage id='introduction.welcome.text' defaultMessage="Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name." values={{ domain: <code>{domain}</code> }} /></p>
</div>
<div className='introduction__action'>
<button className='button' onClick={onNext}><FormattedMessage id='introduction.welcome.action' defaultMessage="Let's go!" /></button>
</div>
</div>
);
FrameWelcome.propTypes = {
domain: PropTypes.string.isRequired,
onNext: PropTypes.func.isRequired,
};
const FrameFederation = ({ onNext }) => (
<div className='introduction__frame'>
<div className='introduction__text introduction__text--columnized'>
<div>
<h3><FormattedMessage id='introduction.federation.home.headline' defaultMessage='Home' /></h3>
<p><FormattedMessage id='introduction.federation.home.text' defaultMessage='Posts from people you follow will appear in your home feed. You can follow anyone on any server!' /></p>
</div>
</div>
<div className='introduction__action'>
<button className='button' onClick={onNext}><FormattedMessage id='introduction.federation.action' defaultMessage='Next' /></button>
</div>
</div>
);
FrameFederation.propTypes = {
onNext: PropTypes.func.isRequired,
};
const FrameInteractions = ({ onNext }) => (
<div className='introduction__frame'>
<div className='introduction__text introduction__text--columnized'>
<div>
<h3><FormattedMessage id='introduction.interactions.reply.headline' defaultMessage='Reply' /></h3>
<p><FormattedMessage id='introduction.interactions.reply.text' defaultMessage="You can reply to other people's and your own gabs, which will chain them together in a conversation." /></p>
</div>
<div>
<h3><FormattedMessage id='introduction.interactions.reblog.headline' defaultMessage='Repost' /></h3>
<p><FormattedMessage id='introduction.interactions.reblog.text' defaultMessage="You can share other people's gabs with your followers by reposting them." /></p>
</div>
<div>
<h3><FormattedMessage id='introduction.interactions.favourite.headline' defaultMessage='Favorite' /></h3>
<p><FormattedMessage id='introduction.interactions.favourite.text' defaultMessage='You can save a gab for later, and let the author know that you liked it, by favouriting it.' /></p>
</div>
</div>
<div className='introduction__action'>
<button className='button' onClick={onNext}><FormattedMessage id='introduction.interactions.action' defaultMessage='Finish tutorial!' /></button>
</div>
</div>
);
FrameInteractions.propTypes = {
onNext: PropTypes.func.isRequired,
};
export default @connect(state => ({ domain: state.getIn(['meta', 'domain']) }))
class Introduction extends PureComponent {
static propTypes = {
domain: PropTypes.string.isRequired,
dispatch: PropTypes.func.isRequired,
};
state = {
currentIndex: 0,
};
componentWillMount () {
this.pages = [
<FrameWelcome domain={this.props.domain} onNext={this.handleNext} />,
<FrameFederation onNext={this.handleNext} />,
<FrameInteractions onNext={this.handleFinish} />,
];
}
componentDidMount() {
window.addEventListener('keyup', this.handleKeyUp);
}
componentWillUnmount() {
window.addEventListener('keyup', this.handleKeyUp);
}
handleDot = (e) => {
const i = Number(e.currentTarget.getAttribute('data-index'));
e.preventDefault();
this.setState({ currentIndex: i });
}
handlePrev = () => {
this.setState(({ currentIndex }) => ({
currentIndex: Math.max(0, currentIndex - 1),
}));
}
handleNext = () => {
const { pages } = this;
this.setState(({ currentIndex }) => ({
currentIndex: Math.min(currentIndex + 1, pages.length - 1),
}));
}
handleSwipe = (index) => {
this.setState({ currentIndex: index });
}
handleFinish = () => {
this.props.dispatch(closeOnboarding());
}
handleKeyUp = ({ key }) => {
switch (key) {
case 'ArrowLeft':
this.handlePrev();
break;
case 'ArrowRight':
this.handleNext();
break;
}
}
render () {
const { currentIndex } = this.state;
const { pages } = this;
return (
<div className='introduction'>
<ReactSwipeableViews index={currentIndex} onChangeIndex={this.handleSwipe} className='introduction__pager'>
{pages.map((page, i) => (
<div key={i} className={classNames('introduction__frame-wrapper', { 'active': i === currentIndex })}>{page}</div>
))}
</ReactSwipeableViews>
<div className='introduction__dots'>
{pages.map((_, i) => (
<div
key={`dot-${i}`}
role='button'
tabIndex='0'
data-index={i}
onClick={this.handleDot}
className={classNames('introduction__dot', { active: i === currentIndex })}
/>
))}
</div>
</div>
);
}
}
export { default } from './introduction';

View File

@@ -0,0 +1,237 @@
import ReactSwipeableViews from 'react-swipeable-views';
import classNames from 'classnames';
import { FormattedMessage } from 'react-intl';
import { closeOnboarding } from '../../actions/onboarding';
import './introduction.scss';
class FrameWelcome extends Component {
static propTypes = {
domain: PropTypes.string.isRequired,
onNext: PropTypes.func.isRequired,
};
shouldComponentUpdate(nextProps) {
if (nextProps.domain !== this.props.domain) {
return true;
}
return false;
}
render() {
const { domain, onNext } = this.props;
return (
<div className='introduction__frame'>
<div className='introduction__text introduction__text--centered'>
<h3>
<FormattedMessage id='introduction.welcome.headline' defaultMessage='First steps' />
</h3>
<p>
<FormattedMessage
id='introduction.welcome.text'
defaultMessage="Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name."
values={{
domain: <code>{domain}</code>
}}
/>
</p>
</div>
<div className='introduction__action'>
<button className='button' onClick={onNext}>
<FormattedMessage id='introduction.welcome.action' defaultMessage="Let's go!" />
</button>
</div>
</div>
);
}
}
class FrameFederation extends Component {
static propTypes = {
onNext: PropTypes.func.isRequired,
}
shouldComponentUpdate() {
return false;
}
render() {
return (
<div className='introduction__frame'>
<div className='introduction__text introduction__text--columnized'>
<div>
<h3>
<FormattedMessage id='introduction.federation.home.headline' defaultMessage='Home' />
</h3>
<p>
<FormattedMessage
id='introduction.federation.home.text'
defaultMessage='Posts from people you follow will appear in your home feed. You can follow anyone on any server!'
/>
</p>
</div>
</div>
<div className='introduction__action'>
<button className='button' onClick={onNext}>
<FormattedMessage id='introduction.federation.action' defaultMessage='Next' />
</button>
</div>
</div>
)
}
};
class FrameInteractions extends Component {
static propTypes = {
onNext: PropTypes.func.isRequired,
};
shouldComponentUpdate() {
return false;
}
render() {
return (
<div className='introduction__frame'>
<div className='introduction__text introduction__text--columnized'>
<div>
<h3>
<FormattedMessage id='introduction.interactions.reply.headline' defaultMessage='Reply' />
</h3>
<p>
<FormattedMessage
id='introduction.interactions.reply.text'
defaultMessage="You can reply to other people's and your own gabs, which will chain them together in a conversation."
/>
</p>
</div>
<div>
<h3>
<FormattedMessage id='introduction.interactions.reblog.headline' defaultMessage='Repost' />
</h3>
<p>
<FormattedMessage id='introduction.interactions.reblog.text' defaultMessage="You can share other people's gabs with your followers by reposting them." />
</p>
</div>
<div>
<h3>
<FormattedMessage id='introduction.interactions.favourite.headline' defaultMessage='Favorite' />
</h3>
<p>
<FormattedMessage id='introduction.interactions.favourite.text' defaultMessage='You can save a gab for later, and let the author know that you liked it, by favouriting it.' />
</p>
</div>
</div>
<div className='introduction__action'>
<button className='button' onClick={onNext}>
<FormattedMessage id='introduction.interactions.action' defaultMessage='Finish tutorial!' />
</button>
</div>
</div>
);
}
}
export default @connect(state => ({ domain: state.getIn(['meta', 'domain']) }))
class Introduction extends PureComponent {
static propTypes = {
domain: PropTypes.string.isRequired,
dispatch: PropTypes.func.isRequired,
};
state = {
currentIndex: 0,
};
componentWillMount () {
this.pages = [
<FrameWelcome domain={this.props.domain} onNext={this.handleNext} />,
<FrameFederation onNext={this.handleNext} />,
<FrameInteractions onNext={this.handleFinish} />,
];
}
componentDidMount() {
window.addEventListener('keyup', this.handleKeyUp);
}
componentWillUnmount() {
window.addEventListener('keyup', this.handleKeyUp);
}
handleDot = (e) => {
const i = Number(e.currentTarget.getAttribute('data-index'));
e.preventDefault();
this.setState({ currentIndex: i });
}
handlePrev = () => {
this.setState(({ currentIndex }) => ({
currentIndex: Math.max(0, currentIndex - 1),
}));
}
handleNext = () => {
const { pages } = this;
this.setState(({ currentIndex }) => ({
currentIndex: Math.min(currentIndex + 1, pages.length - 1),
}));
}
handleSwipe = (index) => {
this.setState({ currentIndex: index });
}
handleFinish = () => {
this.props.dispatch(closeOnboarding());
}
handleKeyUp = ({ key }) => {
switch (key) {
case 'ArrowLeft':
this.handlePrev();
break;
case 'ArrowRight':
this.handleNext();
break;
}
}
render () {
const { currentIndex } = this.state;
const { pages } = this;
return (
<div className='introduction'>
<ReactSwipeableViews index={currentIndex} onChangeIndex={this.handleSwipe} className='introduction__pager'>
{pages.map((page, i) => (
<div key={i} className={classNames('introduction__frame-wrapper', { 'active': i === currentIndex })}>{page}</div>
))}
</ReactSwipeableViews>
<div className='introduction__dots'>
{pages.map((_, i) => (
<div
key={`dot-${i}`}
role='button'
tabIndex='0'
data-index={i}
onClick={this.handleDot}
className={classNames('introduction__dot', { active: i === currentIndex })}
/>
))}
</div>
</div>
);
}
}

View File

@@ -0,0 +1,143 @@
.introduction {
@include flex(center, center, column);
@media screen and (max-width: 920px) {
background: darken($ui-base-color, 8%);
display: block !important;
}
&__pager {
background: darken($ui-base-color, 8%);
box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
overflow: hidden;
}
&__pager,
&__frame {
border-radius: 10px;
width: 50vw;
min-width: 920px;
@media screen and (max-width: 920px) {
min-width: 0;
width: 100%;
border-radius: 0;
box-shadow: none;
}
}
&__frame-wrapper {
opacity: 0;
transition: opacity 500ms linear;
&.active {
opacity: 1;
transition: opacity 50ms linear;
}
}
&__frame {
overflow: hidden;
}
&__illustration {
height: 50vh;
@media screen and (max-width: 630px) {
height: auto;
}
img {
object-fit: cover;
display: block;
margin: 0;
@include size(100%);
}
}
&__text {
&--columnized {
display: flex;
&>div {
flex: 1 1 33.33%;
text-align: center;
padding: 25px;
padding-bottom: 30px;
}
@media screen and (max-width: 630px) {
display: block;
padding: 15px 0;
padding-bottom: 20px;
&>div {
padding: 10px 25px;
}
}
}
h3 {
margin-bottom: 10px;
@include text-sizing(24px, 700, 1.5);
}
p {
color: $darker-text-color;
@include text-sizing(16px, 400, 24px);
code {
display: inline-block;
background: darken($ui-base-color, 8%);
font-size: 15px;
padding: 1px 3px;
@include border-design(lighten($ui-base-color, 8%), 1px, 2px);
}
}
&--centered {
padding: 25px;
padding-bottom: 30px;
text-align: center;
}
}
&__dots {
padding: 25px;
@include flex(center, center);
@media screen and (max-width: 630px) {
display: none;
}
}
&__dot {
background: transparent;
margin: 0 3px;
cursor: pointer;
@include size(14px);
@include border-design($ui-highlight-color, 1px, 14px);
&:hover {
background: lighten($ui-base-color, 8%);
}
&.active {
cursor: default;
background: $ui-highlight-color;
}
}
&__action {
padding: 25px;
padding-top: 0;
@include flex(center, center);
}
}