2018-12-17 11:07:17 +01:00
import React from 'react' ;
import PropTypes from 'prop-types' ;
import ReactSwipeableViews from 'react-swipeable-views' ;
import classNames from 'classnames' ;
import { connect } from 'react-redux' ;
import { FormattedMessage } from 'react-intl' ;
import { closeOnboarding } from '../../actions/onboarding' ;
import screenHello from '../../../images/screen_hello.svg' ;
import screenFederation from '../../../images/screen_federation.svg' ;
import screenInteractions from '../../../images/screen_interactions.svg' ;
import logoTransparent from '../../../images/logo_transparent.svg' ;
2020-09-30 19:31:03 +02:00
import { disableSwiping } from 'mastodon/initial_state' ;
2018-12-17 11:07:17 +01:00
const FrameWelcome = ( { domain , onNext } ) => (
< div className = 'introduction__frame' >
< div className = 'introduction__illustration' style = { { background : ` url( ${ logoTransparent } ) no-repeat center center / auto 80% ` } } >
< img src = { screenHello } alt = '' / >
< / d i v >
< div className = 'introduction__text introduction__text--centered' >
< h3 > < FormattedMessage id = 'introduction.welcome.headline' defaultMessage = 'First steps' / > < / h 3 >
< 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 >
< / d i v >
< div className = 'introduction__action' >
< button className = 'button' onClick = { onNext } > < FormattedMessage id = 'introduction.welcome.action' defaultMessage = "Let's go!" / > < / b u t t o n >
< / d i v >
< / d i v >
) ;
FrameWelcome . propTypes = {
domain : PropTypes . string . isRequired ,
onNext : PropTypes . func . isRequired ,
} ;
const FrameFederation = ( { onNext } ) => (
< div className = 'introduction__frame' >
< div className = 'introduction__illustration' >
< img src = { screenFederation } alt = '' / >
< / d i v >
< div className = 'introduction__text introduction__text--columnized' >
< div >
< h3 > < FormattedMessage id = 'introduction.federation.home.headline' defaultMessage = 'Home' / > < / h 3 >
< 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 >
< / d i v >
< div >
< h3 > < FormattedMessage id = 'introduction.federation.local.headline' defaultMessage = 'Local' / > < / h 3 >
< p > < FormattedMessage id = 'introduction.federation.local.text' defaultMessage = 'Public posts from people on the same server as you will appear in the local timeline.' / > < / p >
< / d i v >
< div >
< h3 > < FormattedMessage id = 'introduction.federation.federated.headline' defaultMessage = 'Federated' / > < / h 3 >
< p > < FormattedMessage id = 'introduction.federation.federated.text' defaultMessage = 'Public posts from other servers of the fediverse will appear in the federated timeline.' / > < / p >
< / d i v >
< / d i v >
< div className = 'introduction__action' >
< button className = 'button' onClick = { onNext } > < FormattedMessage id = 'introduction.federation.action' defaultMessage = 'Next' / > < / b u t t o n >
< / d i v >
< / d i v >
) ;
FrameFederation . propTypes = {
onNext : PropTypes . func . isRequired ,
} ;
const FrameInteractions = ( { onNext } ) => (
< div className = 'introduction__frame' >
< div className = 'introduction__illustration' >
< img src = { screenInteractions } alt = '' / >
< / d i v >
< div className = 'introduction__text introduction__text--columnized' >
< div >
< h3 > < FormattedMessage id = 'introduction.interactions.reply.headline' defaultMessage = 'Reply' / > < / h 3 >
< p > < FormattedMessage id = 'introduction.interactions.reply.text' defaultMessage = "You can reply to other people's and your own toots, which will chain them together in a conversation." / > < / p >
< / d i v >
< div >
< h3 > < FormattedMessage id = 'introduction.interactions.reblog.headline' defaultMessage = 'Boost' / > < / h 3 >
< p > < FormattedMessage id = 'introduction.interactions.reblog.text' defaultMessage = "You can share other people's toots with your followers by boosting them." / > < / p >
< / d i v >
< div >
< h3 > < FormattedMessage id = 'introduction.interactions.favourite.headline' defaultMessage = 'Favourite' / > < / h 3 >
< p > < FormattedMessage id = 'introduction.interactions.favourite.text' defaultMessage = 'You can save a toot for later, and let the author know that you liked it, by favouriting it.' / > < / p >
< / d i v >
< / d i v >
< div className = 'introduction__action' >
2019-02-04 04:45:29 +01:00
< button className = 'button' onClick = { onNext } > < FormattedMessage id = 'introduction.interactions.action' defaultMessage = 'Finish toot-orial!' / > < / b u t t o n >
2018-12-17 11:07:17 +01:00
< / d i v >
< / d i v >
) ;
FrameInteractions . propTypes = {
onNext : PropTypes . func . isRequired ,
} ;
2018-12-31 18:11:48 +01:00
export default @ connect ( state => ( { domain : state . getIn ( [ 'meta' , 'domain' ] ) } ) )
class Introduction extends React . PureComponent {
2018-12-17 11:07:17 +01:00
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' >
2020-09-30 19:31:03 +02:00
< ReactSwipeableViews index = { currentIndex } onChangeIndex = { this . handleSwipe } disabled = { disableSwiping } className = 'introduction__pager' >
2018-12-17 11:07:17 +01:00
{ pages . map ( ( page , i ) => (
< div key = { i } className = { classNames ( 'introduction__frame-wrapper' , { 'active' : i === currentIndex } ) } > { page } < / d i v >
) ) }
< / R e a c t S w i p e a b l e V i e w s >
< 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 } ) }
/ >
) ) }
< / d i v >
< / d i v >
) ;
}
}