@ -14,15 +14,10 @@ import {
ColorWithPicker ,
FileChooserLogo ,
} from 'soapbox/features/forms' ;
import StillImage from 'soapbox/components/still_image' ;
import {
Map as ImmutableMap ,
List as ImmutableList ,
getIn ,
} from 'immutable' ;
import { Map as ImmutableMap , List as ImmutableList } from 'immutable' ;
import { updateAdminConfig } from 'soapbox/actions/admin' ;
import Icon from 'soapbox/components/icon' ;
import { getSoapbox Config } from 'soapbox/actions/soapbox' ;
import { defaultConfig } from 'soapbox/actions/soapbox' ;
const messages = defineMessages ( {
heading : { id : 'column.soapbox_config' , defaultMessage : 'Soapbox config' } ,
@ -35,8 +30,13 @@ const messages = defineMessages({
customCssLabel : { id : 'soapbox_config.custom_css.meta_fields.url_placeholder' , defaultMessage : 'URL' } ,
} ) ;
const templates = {
promoPanelItem : ImmutableMap ( { icon : '' , text : '' , url : '' } ) ,
footerItem : ImmutableMap ( { title : '' , url : '' } ) ,
} ;
const mapStateToProps = state => ( {
soapbox : getSoapboxConfig ( state ) ,
soapbox : state. get ( 'soapbox' ) ,
} ) ;
export default @ connect ( mapStateToProps )
@ -44,103 +44,33 @@ export default @connect(mapStateToProps)
class SoapboxConfig extends ImmutablePureComponent {
static propTypes = {
soapbox : ImmutablePropTypes . map ,
soapbox : ImmutablePropTypes . map .isRequired ,
dispatch : PropTypes . func . isRequired ,
intl : PropTypes . object . isRequired ,
} ;
state = {
isLoading : false ,
soapbox : this . props . soapbox ,
}
constructor ( props ) {
super ( props ) ;
var promoPanelItems = getIn ( this . props . soapbox , [ 'promoPanel' ] , [ 'items' ] , [ ] ) . get ( 'items' ) ;
if ( promoPanelItems . size === 0 ) {
this . state . promoPanelItems = ImmutableList ( [
ImmutableMap ( {
icon : '' ,
text : '' ,
url : '' ,
} ) ,
] ) ;
} else {
this . state . promoPanelItems = promoPanelItems ;
} ;
var homeFooterItems = getIn ( this . props . soapbox , [ 'navlinks' ] , [ 'homefooter' ] , [ ] ) . get ( 'homeFooter' ) ;
if ( homeFooterItems . size === 0 ) {
this . state . homeFooterItems = ImmutableList ( [
ImmutableMap ( {
title : '' ,
url : '' ,
} ) ,
] ) ;
} else {
this . state . homeFooterItems = homeFooterItems ;
} ;
var customCssItems = getIn ( this . props . soapbox , [ 'customCss' ] , [ ] ) ;
if ( customCssItems . size === 0 ) {
this . state . customCssItems = ImmutableList ( [ '' ] ) ;
} else {
this . state . customCssItems = customCssItems ;
} ;
this . state . patron = getIn ( this . props . soapbox , [ 'extensions' , 'patron' ] , false ) ;
this . state . autoPlayGif = getIn ( this . props . soapbox , [ 'defaultSettings' , 'autoPlayGif' ] , false ) ;
this . handlecustomCSSChange = this . handleCustomCSSChange . bind ( this ) ;
this . handleAutoPlayGifCheckboxChange = this . handleAutoPlayGifCheckboxChange . bind ( this ) ;
this . handlePatronCheckboxChange = this . handlePatronCheckboxChange . bind ( this ) ;
}
setConfig = ( path , value ) => {
const { soapbox } = this . state ;
const config = soapbox . setIn ( path , value ) ;
this . setState ( { soapbox : config } ) ;
} ;
getParams = ( ) => {
const { s tate } = this ;
var obj = {
const { soapbox } = this . state ;
return {
configs : [ {
group : ':pleroma' ,
key : ':frontend_configurations' ,
value : [ {
tuple : [ ':soapbox_fe' ,
{
logo : '' ,
banner : '' ,
brandColor : '' ,
customCss : [ ] ,
promoPanel : {
items : [ ] ,
} ,
extensions : {
patron : false ,
} ,
defaultSettings : {
autoPlayGif : false ,
} ,
copyright : '' ,
navlinks : {
homeFooter : [ ] ,
} ,
} ,
] ,
tuple : [ ':soapbox_fe' , soapbox . toJSON ( ) ] ,
} ] ,
} ] ,
} ;
obj . configs [ 0 ] . value [ 0 ] . tuple [ 1 ] . logo = ( state . logo ? state . logo : getIn ( this . props . soapbox , [ 'logo' ] , '' ) ) ;
obj . configs [ 0 ] . value [ 0 ] . tuple [ 1 ] . banner = ( state . banner ? state . banner : getIn ( this . props . soapbox , [ 'banner' ] , '' ) ) ;
obj . configs [ 0 ] . value [ 0 ] . tuple [ 1 ] . brandColor = ( state . brandColor ? state . brandColor : getIn ( this . props . soapbox , [ 'brandColor' ] , '' ) ) ;
obj . configs [ 0 ] . value [ 0 ] . tuple [ 1 ] . extensions . patron = ( state . patron !== undefined ? state . patron : getIn ( this . props . soapbox , [ 'extensions' , 'patron' ] , false ) ) ;
obj . configs [ 0 ] . value [ 0 ] . tuple [ 1 ] . defaultSettings . autoPlayGif = ( state . autoPlayGif !== undefined ? state . autoPlayGif : getIn ( this . props . soapbox , [ 'defaultSettings' , 'autoPlayGif' ] , false ) ) ;
obj . configs [ 0 ] . value [ 0 ] . tuple [ 1 ] . copyright = ( state . copyright ? state . copyright : getIn ( this . props . soapbox , [ 'copyright' ] , '' ) ) ;
var homeFooterItems = ( state . homeFooterItems ? state . homeFooterItems : getIn ( this . props . soapbox , [ 'navlinks' ] , [ 'homeFooter' ] , [ ] ) ) ;
homeFooterItems . forEach ( ( f ) =>
obj . configs [ 0 ] . value [ 0 ] . tuple [ 1 ] . navlinks . homeFooter . push ( { title : f . get ( 'title' ) , url : f . get ( 'url' ) } )
) ;
var promoPanelItems = ( state . promoPanelItems ? state . promoPanelItems : getIn ( this . props . soapbox , [ 'promoPanel' ] , [ 'items' ] , [ ] ) ) ;
promoPanelItems . forEach ( ( f ) =>
obj . configs [ 0 ] . value [ 0 ] . tuple [ 1 ] . promoPanel . items . push ( { icon : f . get ( 'icon' ) , text : f . get ( 'text' ) , url : f . get ( 'url' ) } )
) ;
var customCssItems = ( state . customCssItems ? state . customCssItems : getIn ( this . props . soapbox , [ 'customCss' ] , [ ] ) ) ;
customCssItems . forEach ( ( f ) =>
obj . configs [ 0 ] . value [ 0 ] . tuple [ 1 ] . customCss . push ( f )
) ;
return obj ;
}
handleSubmit = ( event ) => {
@ -154,102 +84,55 @@ class SoapboxConfig extends ImmutablePureComponent {
event . preventDefault ( ) ;
}
handlePatronCheckboxChange = e => {
this . setState ( { patron : ! this . state . patron } ) ;
}
handleAutoPlayGifCheckboxChange = e => {
this . setState ( { autoPlayGif : ! this . state . autoPlayGif } ) ;
}
handleBrandColorChange = e => {
this . setState ( {
brandColor : e . hex ,
} ) ;
}
handleTextChange = e => {
this . setState ( {
[ e . target . name ] : e . target . value ,
} ) ;
}
handlePromoItemsChange = ( i , key ) => {
return ( e ) => {
this . setState ( {
promoPanelItems : this . state . promoPanelItems . setIn ( [ i , key ] , e . target . value ) ,
} ) ;
} ;
}
handleHomeFooterItemsChange = ( i , key ) => {
return ( e ) => {
this . setState ( {
homeFooterItems : this . state . homeFooterItems . setIn ( [ i , key ] , e . target . value ) ,
} ) ;
handleChange = ( path , getValue ) => {
return e => {
this . setConfig ( path , getValue ( e ) ) ;
} ;
}
} ;
handleCustomCSSChange = i => {
return ( e ) => {
this . setState ( {
customCssItems : this . state . customCssItems . setIn ( [ i ] , e . target . value ) ,
} ) ;
handleAddItem = ( path , template ) => {
return e => {
this . setConfig (
path ,
this . getSoapboxConfig ( ) . getIn ( path , ImmutableList ( ) ) . push ( template ) ,
) ;
} ;
}
handleFileChange = e => {
const { name } = e . target ;
const [ file ] = e . target . files || [ ] ;
const url = file ? URL . createObjectURL ( file ) : this . state [ name ] ;
} ;
this . setState ( {
[ name ] : url ,
[ ` ${ name } _file ` ] : file ,
} ) ;
}
handleItemChange = ( path , key , field , template ) => {
return this . handleChange (
path , ( e ) =>
template
. merge ( field )
. set ( key , e . target . value )
) ;
} ;
handleAddPromoPanelItem = ( ) => {
handlePromoItemChange = ( index , key , field ) => {
return this . handleItemChange (
[ 'promoPanel' , 'items' , index ] , key , field , templates . promoPanelItem
) ;
} ;
this . setState ( {
promoPanelItems : this . state . promoPanelItems . concat ( [
ImmutableMap ( {
icon : '' ,
text : '' ,
url : '' ,
} ) ,
] ) ,
} ) ;
}
handleHomeFooterItemChange = ( index , key , field ) => {
return this . handleItemChange (
[ 'navlinks' , 'homeFooter' , index ] , key , field , templates . footerItem
) ;
} ;
handleAddHomeFooterItem = ( ) => {
this . setState ( {
homeFooterItems : this . state . homeFooterItems . concat ( [
ImmutableMap ( {
title : '' ,
url : '' ,
} ) ,
] ) ,
} ) ;
getSoapboxConfig = ( ) => {
return defaultConfig . mergeDeep ( this . state . soapbox ) ;
}
handleAddCssItem = ( ) => {
this. setState ( {
customCssItems : this . state . customCssItems . concat ( [ '' ] ) ,
} ) ;
componentDidUpdate ( prevProps , prevState ) {
if ( prevProps . soapbox !== this . props . soapbox ) {
this . setState ( { soapbox : this . props . soapbox } ) ;
}
}
render ( ) {
const { intl } = this . props ;
const logo = ( this . state . logo ? this . state . logo : getIn ( this . props . soapbox , [ 'logo' ] , '' ) ) ;
const banner = ( this . state . banner ? this . state . banner : getIn ( this . props . soapbox , [ 'banner' ] , '' ) ) ;
const brandColor = ( this . state . brandColor ? this . state . brandColor : getIn ( this . props . soapbox , [ 'brandColor' ] , '' ) ) ;
const patron = ( this . state . patron !== undefined ? this . state . patron : getIn ( this . props . soapbox , [ 'extensions' , 'patron' ] , false ) ) ;
const autoPlayGif = ( this . state . autoPlayGif !== undefined ? this . state . autoPlayGif : getIn ( this . props . soapbox , [ 'defaultSettings' , 'autoPlayGif' ] , false ) ) ;
const promoPanelItems = ( this . state . promoPanelItems ? this . state . promoPanelItems : getIn ( this . props . soapbox , [ 'promoPanel' ] , [ 'items' ] , [ ] ) . get ( 'items' ) ) ;
const homeFooterItems = ( this . state . homeFooterItems ? this . state . homeFooterItems : getIn ( this . props . soapbox , [ 'navlinks' ] , [ 'homeFooter' ] , [ ] ) . get ( 'homeFooter' ) ) ;
const customCssItems = ( this . state . customCssItems ? this . state . customCssItems : getIn ( this . props . soapbox , [ 'customCss' ] , [ ] ) ) ;
const copyright = ( this . state . copyright ? this . state . copyright : getIn ( this . props . soapbox , [ 'copyright' ] , '' ) ) ;
const soapbox = this . getSoapboxConfig ( ) ;
return (
< Column icon = 'shield' heading = { intl . formatMessage ( messages . heading ) } backBtnSlim >
@ -258,27 +141,27 @@ class SoapboxConfig extends ImmutablePureComponent {
< FieldsGroup >
< div className = 'fields-row' >
< div className = 'fields-row__column fields-row__column-6' >
< St illI ma ge src = { logo} / >
< img src = { soapbox. get ( ' logo') } / >
< / d i v >
< div className = 'fields-row__column fields-group fields-row__column-6' >
< FileChooserLogo
label = { < FormattedMessage id = 'soapbox_config.fields.logo_label' defaultMessage = 'Logo' / > }
name = 'logo'
hint = { < FormattedMessage id = 'soapbox_config.hints.logo' defaultMessage = 'SVG. At most 2 MB. Will be downscaled to 50px height, maintaining aspect ratio' / > }
onChange = { this . handleFileChange }
// onChange={this.handleFileChange}
/ >
< / d i v >
< / d i v >
< div className = 'fields-row' >
< div className = 'fields-row__column fields-row__column-6' >
{ this . state . banner ? ( < StillImage src = { this . state . banner } / > ) : ( < StillImage src = { banner || '' } / > ) }
< img src = { soapbox . get ( 'banner' ) } / >
< / d i v >
< div className = 'fields-row__column fields-group fields-row__column-6' >
< FileChooser
label = { < FormattedMessage id = 'soapbox_config.fields.banner_label' defaultMessage = 'Banner' / > }
name = 'banner'
hint = { < FormattedMessage id = 'soapbox_config.hints.banner' defaultMessage = 'PNG, GIF or JPG. At most 2 MB. Will be downscaled to 400x400px' / > }
onChange = { this . handleFileChange }
// onChange={this.handleFileChange}
/ >
< / d i v >
< / d i v >
@ -288,8 +171,8 @@ class SoapboxConfig extends ImmutablePureComponent {
< ColorWithPicker
buttonId = 'brand_color'
label = { < FormattedMessage id = 'soapbox_config.fields.brand_color_label' defaultMessage = 'Brand color' / > }
value = { brandColor}
onChange = { this . handle BrandColorChange }
value = { soapbox. get ( ' brandColor') }
onChange = { this . handle Change( [ 'brandColor' ] , ( e ) => e . hex ) }
/ >
< / d i v >
< / F i e l d s G r o u p >
@ -298,15 +181,10 @@ class SoapboxConfig extends ImmutablePureComponent {
label = { < FormattedMessage id = 'soapbox_config.fields.patron_enabled_label' defaultMessage = 'Patron module' / > }
hint = { < FormattedMessage id = 'soapbox_config.hints.patron_enabled' defaultMessage = 'Enables display of Patron module. Requires installation of Patron module.' / > }
name = 'patron'
checked = { patron }
onChange = { this . handlePatronCheckboxChange }
/ >
< Checkbox
label = { < FormattedMessage id = 'soapbox_config.fields.auto_play_gif_label' defaultMessage = 'Auto-play GIFs' / > }
hint = { < FormattedMessage id = 'soapbox_config.hints.auto_play_gif' defaultMessage = 'Enable auto-playing of GIF files in timeline' / > }
name = 'autoPlayGif'
checked = { autoPlayGif }
onChange = { this . handleAutoPlayGifCheckboxChange }
checked = { soapbox . getIn ( [ 'extensions' , 'patron' , 'enabled' ] ) }
onChange = { this . handleChange (
[ 'extensions' , 'patron' , 'enabled' ] , ( e ) => e . checked ,
) }
/ >
< / F i e l d s G r o u p >
< FieldsGroup >
@ -314,8 +192,8 @@ class SoapboxConfig extends ImmutablePureComponent {
name = 'copyright'
label = { intl . formatMessage ( messages . copyrightFooterLabel ) }
placeholder = { intl . formatMessage ( messages . copyrightFooterLabel ) }
value = { copyright}
onChange = { this . handle Text Change}
value = { soapbox. get ( ' copyright') }
onChange = { this . handle Change( [ 'copyright' ] , ( e ) => e . target . value ) }
/ >
< / F i e l d s G r o u p >
< FieldsGroup >
@ -329,31 +207,31 @@ class SoapboxConfig extends ImmutablePureComponent {
< FormattedMessage id = 'soapbox_config.hints.promo_panel_icons' defaultMessage = '{ link }' values = { { link : < a target = '_blank' href = 'https://forkaweso.me/Fork-Awesome/icons/' > Soapbox Icons List < /a> }} / >
< / s p a n >
{
promoPanelItems. valueSeq ( ) . map ( ( field , i ) => (
soapbox. getIn ( [ 'promoPanel' , 'items' ] ) . map ( ( field , i ) => (
< div className = 'row' key = { i } >
< TextInput
label = { intl . formatMessage ( messages . promoItemIcon ) }
placeholder = { intl . formatMessage ( messages . promoItemIcon ) }
value = { field . get ( 'icon' ) }
onChange = { this . handlePromoItem s Change( i , 'icon' ) }
onChange = { this . handlePromoItem Change( i , 'icon' , field ) }
/ >
< TextInput
label = { intl . formatMessage ( messages . promoItemLabel ) }
placeholder = { intl . formatMessage ( messages . promoItemLabel ) }
value = { field . get ( 'text' ) }
onChange = { this . handlePromoItem s Change( i , 'text' ) }
onChange = { this . handlePromoItem Change( i , 'text' , field ) }
/ >
< TextInput
label = { intl . formatMessage ( messages . promoItemURL ) }
placeholder = { intl . formatMessage ( messages . promoItemURL ) }
value = { field . get ( 'url' ) }
onChange = { this . handlePromoItem s Change( i , 'url' ) }
onChange = { this . handlePromoItem Change( i , 'url' , field ) }
/ >
< / d i v >
) )
}
< div className = 'actions' >
< div name = 'button' type = 'button' role = 'presentation' className = 'btn button button-secondary' onClick = { this . handleAdd PromoPanelItem} >
< div name = 'button' type = 'button' role = 'presentation' className = 'btn button button-secondary' onClick = { this . handleAdd Item( [ 'promo Panel', 'items' ] , templates . p romoPanelItem) } >
< Icon id = 'plus-circle' / >
< FormattedMessage id = 'soapbox_config.fields.promo_panel.add' defaultMessage = 'Add new Promo panel item' / >
< / d i v >
@ -365,25 +243,25 @@ class SoapboxConfig extends ImmutablePureComponent {
< FormattedMessage id = 'soapbox_config.hints.home_footer_fields' defaultMessage = 'You can have custom defined links displayed on the footer of your static pages' / >
< / s p a n >
{
homeFooterItems. valueSeq ( ) . map ( ( field , i ) => (
soapbox. getIn ( [ 'navlinks' , 'homeFooter' ] ) . map ( ( field , i ) => (
< div className = 'row' key = { i } >
< TextInput
label = { intl . formatMessage ( messages . homeFooterItemLabel ) }
placeholder = { intl . formatMessage ( messages . homeFooterItemLabel ) }
value = { field . get ( 'title' ) }
onChange = { this . handleHomeFooterItem s Change( i , 'title' ) }
onChange = { this . handleHomeFooterItem Change( i , 'title' , field ) }
/ >
< TextInput
label = { intl . formatMessage ( messages . homeFooterItemURL ) }
placeholder = { intl . formatMessage ( messages . homeFooterItemURL ) }
value = { field . get ( 'url' ) }
onChange = { this . handleHomeFooterItem s Change( i , 'url' ) }
onChange = { this . handleHomeFooterItem Change( i , 'url' , field ) }
/ >
< / d i v >
) )
}
< div className = 'actions' >
< div name = 'button' type = 'button' role = 'presentation' className = 'btn button button-secondary' onClick = { this . handleAdd HomeFooterItem } >
< div name = 'button' type = 'button' role = 'presentation' className = 'btn button button-secondary' onClick = { this . handleAdd Item( [ 'navlinks' , 'homeFooter' ] , templates . footerItem ) } >
< Icon id = 'plus-circle' / >
< FormattedMessage id = 'soapbox_config.fields.home_footer.add' defaultMessage = 'Add new Home Footer Item' / >
< / d i v >
@ -396,19 +274,19 @@ class SoapboxConfig extends ImmutablePureComponent {
< FormattedMessage id = 'soapbox_config.hints.custom_css_fields' defaultMessage = 'Insert a URL to a CSS file like `https://mysite.com/instance/custom.css`, or simply `/instance/custom.css`' / >
< / s p a n >
{
customCssItems. valueSeq ( ) . map ( ( field , i ) => (
soapbox. get ( 'customCss' ) . map ( ( field , i ) => (
< div className = 'row' key = { i } >
< TextInput
label = { intl . formatMessage ( messages . customCssLabel ) }
placeholder = { intl . formatMessage ( messages . customCssLabel ) }
value = { field }
onChange = { this . handle customCSSChange( i ) }
onChange = { this . handle Change( [ 'customCss' , i ] , ( e ) => e . target . value ) }
/ >
< / d i v >
) )
}
< div className = 'actions' >
< div name = 'button' type = 'button' role = 'presentation' className = 'btn button button-secondary' onClick = { this . handleAdd Css Item} >
< div name = 'button' type = 'button' role = 'presentation' className = 'btn button button-secondary' onClick = { this . handleAdd Item( [ 'customCss' ] , '' ) } >
< Icon id = 'plus-circle' / >
< FormattedMessage id = 'soapbox_config.fields.custom_css.add' defaultMessage = 'Add another custom CSS URL' / >
< / d i v >