Documentation and cleanup
This commit is contained in:
		
							parent
							
								
									32ef49a033
								
							
						
					
					
						commit
						fea6120855
					
				
					 11 changed files with 705 additions and 189 deletions
				
			
		| 
						 | 
					@ -21,12 +21,12 @@ consists of the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            /* * * * */
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Constants
 | 
					Constants:
 | 
				
			||||||
---------
 | 
					----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
We provide the following constants:
 | 
					We provide the following constants:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,12 +39,12 @@ We provide the following constants:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const LOCAL_SETTING_CHANGE = 'LOCAL_SETTING_CHANGE';
 | 
					export const LOCAL_SETTING_CHANGE = 'LOCAL_SETTING_CHANGE';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            /* * * * */
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`changeLocalSetting(key, value)`
 | 
					`changeLocalSetting(key, value)`:
 | 
				
			||||||
--------------------------------
 | 
					---------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Changes the local setting with the given `key` to the given `value`.
 | 
					Changes the local setting with the given `key` to the given `value`.
 | 
				
			||||||
`key` **MUST** be an array of strings, as required by
 | 
					`key` **MUST** be an array of strings, as required by
 | 
				
			||||||
| 
						 | 
					@ -67,12 +67,12 @@ export function changeLocalSetting(key, value) {
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            /* * * * */
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`saveLocalSettings()`
 | 
					`saveLocalSettings()`:
 | 
				
			||||||
---------------------
 | 
					----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Saves the local settings to `localStorage` as a JSON object.
 | 
					Saves the local settings to `localStorage` as a JSON object.
 | 
				
			||||||
`changeLocalSetting()` calls this whenever it changes a setting. We
 | 
					`changeLocalSetting()` calls this whenever it changes a setting. We
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,45 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`<AccountHeader>`
 | 
				
			||||||
 | 
					=================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					>   For more information on the contents of this file, please contact:
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
 | 
					>   - kibigo! [@kibi@glitch.social]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Original file by @gargron@mastodon.social et al as part of
 | 
				
			||||||
 | 
					tootsuite/mastodon. We've expanded it in order to handle user bio
 | 
				
			||||||
 | 
					frontmatter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `<AccountHeader>` component provides the header for account
 | 
				
			||||||
 | 
					timelines. It is a fairly simple component which mostly just consists
 | 
				
			||||||
 | 
					of a `render()` method.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__Props:__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`account` (`ImmutablePropTypes.map`) :__
 | 
				
			||||||
 | 
					    The account to render a header for.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`me` (`PropTypes.number.isRequired`) :__
 | 
				
			||||||
 | 
					    The id of the currently-signed-in account.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`onFollow` (`PropTypes.func.isRequired`) :__
 | 
				
			||||||
 | 
					    The function to call when the user clicks the "follow" button.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`intl` (`PropTypes.object.isRequired`) :__
 | 
				
			||||||
 | 
					    Our internationalization object, inserted by `@injectIntl`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Imports:
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//  Package imports  //
 | 
					//  Package imports  //
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
| 
						 | 
					@ -14,25 +56,63 @@ import Avatar from '../../../mastodon/components/avatar';
 | 
				
			||||||
//  Our imports  //
 | 
					//  Our imports  //
 | 
				
			||||||
import { processBio } from '../../util/bio_metadata';
 | 
					import { processBio } from '../../util/bio_metadata';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Inital setup:
 | 
				
			||||||
 | 
					-------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `messages` constant is used to define any messages that we need
 | 
				
			||||||
 | 
					from inside props. In our case, these are the `unfollow`, `follow`, and
 | 
				
			||||||
 | 
					`requested` messages used in the `title` of our buttons.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
  unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
 | 
					  unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
 | 
				
			||||||
  follow: { id: 'account.follow', defaultMessage: 'Follow' },
 | 
					  follow: { id: 'account.follow', defaultMessage: 'Follow' },
 | 
				
			||||||
  requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' },
 | 
					  requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Implementation:
 | 
				
			||||||
 | 
					---------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@injectIntl
 | 
					@injectIntl
 | 
				
			||||||
export default class Header extends ImmutablePureComponent {
 | 
					export default class AccountHeader extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
    account: ImmutablePropTypes.map,
 | 
					    account  : ImmutablePropTypes.map,
 | 
				
			||||||
    me: PropTypes.number.isRequired,
 | 
					    me       : PropTypes.number.isRequired,
 | 
				
			||||||
    onFollow: PropTypes.func.isRequired,
 | 
					    onFollow : PropTypes.func.isRequired,
 | 
				
			||||||
    intl: PropTypes.object.isRequired,
 | 
					    intl     : PropTypes.object.isRequired,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###  `render()`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `render()` function is used to render our component.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { account, me, intl } = this.props;
 | 
					    const { account, me, intl } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If no `account` is provided, then we can't render a header. Otherwise,
 | 
				
			||||||
 | 
					we get the `displayName` for the account, if available. If it's blank,
 | 
				
			||||||
 | 
					then we set the `displayName` to just be the `username` of the account.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!account) {
 | 
					    if (!account) {
 | 
				
			||||||
      return null;
 | 
					      return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -40,17 +120,30 @@ export default class Header extends ImmutablePureComponent {
 | 
				
			||||||
    let displayName = account.get('display_name');
 | 
					    let displayName = account.get('display_name');
 | 
				
			||||||
    let info        = '';
 | 
					    let info        = '';
 | 
				
			||||||
    let actionBtn   = '';
 | 
					    let actionBtn   = '';
 | 
				
			||||||
    let lockedIcon  = '';
 | 
					    let following   = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (displayName.length === 0) {
 | 
					    if (displayName.length === 0) {
 | 
				
			||||||
      displayName = account.get('username');
 | 
					      displayName = account.get('username');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) {
 | 
					/*
 | 
				
			||||||
      info = <span className='account--follows-info'><FormattedMessage id='account.follows_you' defaultMessage='Follows you' /></span>;
 | 
					
 | 
				
			||||||
    }
 | 
					Next, we handle the account relationships. If the account follows the
 | 
				
			||||||
 | 
					user, then we add an `info` message. If the user has requested a
 | 
				
			||||||
 | 
					follow, then we disable the `actionBtn` and display an hourglass.
 | 
				
			||||||
 | 
					Otherwise, if the account isn't blocked, we set the `actionBtn` to the
 | 
				
			||||||
 | 
					appropriate icon.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (me !== account.get('id')) {
 | 
					    if (me !== account.get('id')) {
 | 
				
			||||||
 | 
					      if (account.getIn(['relationship', 'followed_by'])) {
 | 
				
			||||||
 | 
					        info = (
 | 
				
			||||||
 | 
					          <span className='account--follows-info'>
 | 
				
			||||||
 | 
					            <FormattedMessage id='account.follows_you' defaultMessage='Follows you' />
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      if (account.getIn(['relationship', 'requested'])) {
 | 
					      if (account.getIn(['relationship', 'requested'])) {
 | 
				
			||||||
        actionBtn = (
 | 
					        actionBtn = (
 | 
				
			||||||
          <div className='account--action-button'>
 | 
					          <div className='account--action-button'>
 | 
				
			||||||
| 
						 | 
					@ -58,30 +151,64 @@ export default class Header extends ImmutablePureComponent {
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else if (!account.getIn(['relationship', 'blocking'])) {
 | 
					      } else if (!account.getIn(['relationship', 'blocking'])) {
 | 
				
			||||||
 | 
					        following = account.getIn(['relationship', 'following']);
 | 
				
			||||||
        actionBtn = (
 | 
					        actionBtn = (
 | 
				
			||||||
          <div className='account--action-button'>
 | 
					          <div className='account--action-button'>
 | 
				
			||||||
            <IconButton size={26} icon={account.getIn(['relationship', 'following']) ? 'user-times' : 'user-plus'} active={account.getIn(['relationship', 'following'])} title={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={this.props.onFollow} />
 | 
					            <IconButton
 | 
				
			||||||
 | 
					              size={26}
 | 
				
			||||||
 | 
					              icon={following ? 'user-times' : 'user-plus'}
 | 
				
			||||||
 | 
					              active={following}
 | 
				
			||||||
 | 
					              title={intl.formatMessage(following ? messages.unfollow : messages.follow)}
 | 
				
			||||||
 | 
					              onClick={this.props.onFollow}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (account.get('locked')) {
 | 
					/*
 | 
				
			||||||
      lockedIcon = <i className='fa fa-lock' />;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const displayNameHTML    = { __html: emojify(escapeTextContentForBrowser(displayName)) };
 | 
					`displayNameHTML` processes the `displayName` and prepares it for
 | 
				
			||||||
 | 
					insertion into the document. Meanwhile, we extract the `text` and
 | 
				
			||||||
 | 
					`metadata` from our account's `note` using `processBio()`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const displayNameHTML    = {
 | 
				
			||||||
 | 
					      __html : emojify(escapeTextContentForBrowser(displayName)),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    const { text, metadata } = processBio(account.get('note'));
 | 
					    const { text, metadata } = processBio(account.get('note'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here, we render our component using all the things we've defined above.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className='account__header__wrapper'>
 | 
					      <div className='account__header__wrapper'>
 | 
				
			||||||
        <div className='account__header' style={{ backgroundImage: `url(${account.get('header')})` }}>
 | 
					        <div
 | 
				
			||||||
 | 
					          className='account__header'
 | 
				
			||||||
 | 
					          style={{ backgroundImage: `url(${account.get('header')})` }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
          <div>
 | 
					          <div>
 | 
				
			||||||
            <a href={account.get('url')} target='_blank' rel='noopener'>
 | 
					            <a href={account.get('url')} target='_blank' rel='noopener'>
 | 
				
			||||||
              <span className='account__header__avatar'><Avatar src={account.get('avatar')} staticSrc={account.get('avatar_static')} size={90} /></span>
 | 
					              <span className='account__header__avatar'>
 | 
				
			||||||
              <span className='account__header__display-name' dangerouslySetInnerHTML={displayNameHTML} />
 | 
					                <Avatar
 | 
				
			||||||
 | 
					                  src={account.get('avatar')}
 | 
				
			||||||
 | 
					                  staticSrc={account.get('avatar_static')}
 | 
				
			||||||
 | 
					                  size={90}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					              <span
 | 
				
			||||||
 | 
					                className='account__header__display-name'
 | 
				
			||||||
 | 
					                dangerouslySetInnerHTML={displayNameHTML}
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
            </a>
 | 
					            </a>
 | 
				
			||||||
            <span className='account__header__username'>@{account.get('acct')} {lockedIcon}</span>
 | 
					            <span className='account__header__username'>
 | 
				
			||||||
 | 
					              @{account.get('acct')}
 | 
				
			||||||
 | 
					              {account.get('locked') ? <i className='fa fa-lock' /> : null}
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
            <div className='account__header__content' dangerouslySetInnerHTML={{ __html: emojify(text) }} />
 | 
					            <div className='account__header__content' dangerouslySetInnerHTML={{ __html: emojify(text) }} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            {info}
 | 
					            {info}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,21 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`<ComposeAdvancedOptionsContainer>`
 | 
				
			||||||
 | 
					===================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This container connects `<ComposeAdvancedOptions>` to the Redux store.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Imports:
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//  Package imports  //
 | 
					//  Package imports  //
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,10 +25,36 @@ import { toggleComposeAdvancedOption } from '../../../../mastodon/actions/compos
 | 
				
			||||||
//  Our imports  //
 | 
					//  Our imports  //
 | 
				
			||||||
import ComposeAdvancedOptions from '.';
 | 
					import ComposeAdvancedOptions from '.';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					State mapping:
 | 
				
			||||||
 | 
					--------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `mapStateToProps()` function maps various state properties to the
 | 
				
			||||||
 | 
					props of our component. The only property we care about is
 | 
				
			||||||
 | 
					`compose.advanced_options`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapStateToProps = state => ({
 | 
					const mapStateToProps = state => ({
 | 
				
			||||||
  values: state.getIn(['compose', 'advanced_options']),
 | 
					  values: state.getIn(['compose', 'advanced_options']),
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Dispatch mapping:
 | 
				
			||||||
 | 
					-----------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `mapDispatchToProps()` function maps dispatches to our store to the
 | 
				
			||||||
 | 
					various props of our component. We just need to provide a dispatch for
 | 
				
			||||||
 | 
					when an advanced option toggle changes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapDispatchToProps = dispatch => ({
 | 
					const mapDispatchToProps = dispatch => ({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onChange (option) {
 | 
					  onChange (option) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,137 +1,241 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`<ComposeAdvancedOptions>`
 | 
				
			||||||
 | 
					==========================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					>   For more information on the contents of this file, please contact:
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
 | 
					>   - surinna [@srn@dev.glitch.social]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This adds an advanced options dropdown to the toot compose box, for
 | 
				
			||||||
 | 
					toggles that don't necessarily fit elsewhere.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__Props:__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`values` (`ImmutablePropTypes.contains(…).isRequired`) :__
 | 
				
			||||||
 | 
					    An Immutable map with the following values:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     -  __`do_not_federate` (`PropTypes.bool.isRequired`) :__
 | 
				
			||||||
 | 
					        Specifies whether or not to federate the status.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`onChange` (`PropTypes.func.isRequired`) :__
 | 
				
			||||||
 | 
					    The function to call when a toggle is changed. We pass this from
 | 
				
			||||||
 | 
					    our container to the toggle.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`intl` (`PropTypes.object.isRequired`) :__
 | 
				
			||||||
 | 
					    Our internationalization object, inserted by `@injectIntl`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__State:__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`open` :__
 | 
				
			||||||
 | 
					    This tells whether the dropdown is currently open or closed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Imports:
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//  Package imports  //
 | 
					//  Package imports  //
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import Toggle from 'react-toggle';
 | 
					 | 
				
			||||||
import { injectIntl, defineMessages } from 'react-intl';
 | 
					import { injectIntl, defineMessages } from 'react-intl';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//  Mastodon imports  //
 | 
					//  Mastodon imports  //
 | 
				
			||||||
import IconButton from '../../../../mastodon/components/icon_button';
 | 
					import IconButton from '../../../../mastodon/components/icon_button';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  Our imports  //
 | 
				
			||||||
 | 
					import ComposeAdvancedOptionsToggle from './toggle';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Inital setup:
 | 
				
			||||||
 | 
					-------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `messages` constant is used to define any messages that we need
 | 
				
			||||||
 | 
					from inside props. These are the various titles and labels on our
 | 
				
			||||||
 | 
					toggles.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`iconStyle` styles the icon used for the dropdown button.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
  local_only_short: { id: 'advanced-options.local-only.short', defaultMessage: 'Local-only' },
 | 
					  local_only_short            :
 | 
				
			||||||
  local_only_long: { id: 'advanced-options.local-only.long', defaultMessage: 'Do not post to other instances' },
 | 
					    { id: 'advanced-options.local-only.short', defaultMessage: 'Local-only' },
 | 
				
			||||||
  advanced_options_icon_title: { id: 'advanced_options.icon_title', defaultMessage: 'Advanced options' },
 | 
					  local_only_long             :
 | 
				
			||||||
 | 
					    { id: 'advanced-options.local-only.long', defaultMessage: 'Do not post to other instances' },
 | 
				
			||||||
 | 
					  advanced_options_icon_title :
 | 
				
			||||||
 | 
					    { id: 'advanced_options.icon_title', defaultMessage: 'Advanced options' },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const iconStyle = {
 | 
					const iconStyle = {
 | 
				
			||||||
  height: null,
 | 
					  height     : null,
 | 
				
			||||||
  lineHeight: '27px',
 | 
					  lineHeight : '27px',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AdvancedOptionToggle extends React.PureComponent {
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					Implementation:
 | 
				
			||||||
    onChange: PropTypes.func.isRequired,
 | 
					---------------
 | 
				
			||||||
    active: PropTypes.bool.isRequired,
 | 
					 | 
				
			||||||
    name: PropTypes.string.isRequired,
 | 
					 | 
				
			||||||
    shortText: PropTypes.string.isRequired,
 | 
					 | 
				
			||||||
    longText: PropTypes.string.isRequired,
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onToggle = () => {
 | 
					*/
 | 
				
			||||||
    this.props.onChange(this.props.name);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  render() {
 | 
					 | 
				
			||||||
    const { active, shortText, longText } = this.props;
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <div role='button' tabIndex='0' className='advanced-options-dropdown__option' onClick={this.onToggle}>
 | 
					 | 
				
			||||||
        <div className='advanced-options-dropdown__option__toggle'>
 | 
					 | 
				
			||||||
          <Toggle checked={active} onChange={this.onToggle} />
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div className='advanced-options-dropdown__option__content'>
 | 
					 | 
				
			||||||
          <strong>{shortText}</strong>
 | 
					 | 
				
			||||||
          {longText}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@injectIntl
 | 
					@injectIntl
 | 
				
			||||||
export default class ComposeAdvancedOptions extends React.PureComponent {
 | 
					export default class ComposeAdvancedOptions extends React.PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
    values: ImmutablePropTypes.contains({
 | 
					    values   : ImmutablePropTypes.contains({
 | 
				
			||||||
      do_not_federate: PropTypes.bool.isRequired,
 | 
					      do_not_federate : PropTypes.bool.isRequired,
 | 
				
			||||||
    }).isRequired,
 | 
					    }).isRequired,
 | 
				
			||||||
    onChange: PropTypes.func.isRequired,
 | 
					    onChange : PropTypes.func.isRequired,
 | 
				
			||||||
    intl: PropTypes.object.isRequired,
 | 
					    intl     : PropTypes.object.isRequired,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  state = {
 | 
				
			||||||
 | 
					    open: false,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###  `onToggleDropdown()`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This function toggles the opening and closing of the advanced options
 | 
				
			||||||
 | 
					dropdown.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onToggleDropdown = () => {
 | 
					  onToggleDropdown = () => {
 | 
				
			||||||
    this.setState({ open: !this.state.open });
 | 
					    this.setState({ open: !this.state.open });
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###  `onGlobalClick(e)`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This function closes the advanced options dropdown if you click
 | 
				
			||||||
 | 
					anywhere else on the screen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onGlobalClick = (e) => {
 | 
					  onGlobalClick = (e) => {
 | 
				
			||||||
    if (e.target !== this.node && !this.node.contains(e.target) && this.state.open) {
 | 
					    if (e.target !== this.node && !this.node.contains(e.target) && this.state.open) {
 | 
				
			||||||
      this.setState({ open: false });
 | 
					      this.setState({ open: false });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###  `componentDidMount()`, `componentWillUnmount()`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This function closes the advanced options dropdown if you click
 | 
				
			||||||
 | 
					anywhere else on the screen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentDidMount () {
 | 
					  componentDidMount () {
 | 
				
			||||||
    window.addEventListener('click', this.onGlobalClick);
 | 
					    window.addEventListener('click', this.onGlobalClick);
 | 
				
			||||||
    window.addEventListener('touchstart', this.onGlobalClick);
 | 
					    window.addEventListener('touchstart', this.onGlobalClick);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  componentWillUnmount () {
 | 
					  componentWillUnmount () {
 | 
				
			||||||
    window.removeEventListener('click', this.onGlobalClick);
 | 
					    window.removeEventListener('click', this.onGlobalClick);
 | 
				
			||||||
    window.removeEventListener('touchstart', this.onGlobalClick);
 | 
					    window.removeEventListener('touchstart', this.onGlobalClick);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  state = {
 | 
					/*
 | 
				
			||||||
    open: false,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleClick = (e) => {
 | 
					###  `setRef(c)`
 | 
				
			||||||
    const option = e.currentTarget.getAttribute('data-index');
 | 
					
 | 
				
			||||||
    e.preventDefault();
 | 
					`setRef()` stores a reference to the dropdown's `<div> in `this.node`.
 | 
				
			||||||
    this.props.onChange(option);
 | 
					
 | 
				
			||||||
  }
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setRef = (c) => {
 | 
					  setRef = (c) => {
 | 
				
			||||||
    this.node = c;
 | 
					    this.node = c;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###  `render()`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`render()` actually puts our component on the screen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { open } = this.state;
 | 
					    const { open } = this.state;
 | 
				
			||||||
    const { intl, values } = this.props;
 | 
					    const { intl, values } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `options` array provides all of the available advanced options
 | 
				
			||||||
 | 
					alongside their icon, text, and name.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
    const options = [
 | 
					    const options = [
 | 
				
			||||||
      { icon: 'wifi', shortText: messages.local_only_short, longText: messages.local_only_long, key: 'do_not_federate' },
 | 
					      { icon: 'wifi', shortText: messages.local_only_short, longText: messages.local_only_long, name: 'do_not_federate' },
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`anyEnabled` tells us if any of our advanced options have been enabled.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const anyEnabled = values.some((enabled) => enabled);
 | 
					    const anyEnabled = values.some((enabled) => enabled);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`optionElems` takes our `options` and creates
 | 
				
			||||||
 | 
					`<ComposeAdvancedOptionsToggle>`s out of them. We use the `name` of the
 | 
				
			||||||
 | 
					toggle as its `key` so that React can keep track of it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const optionElems = options.map((option) => {
 | 
					    const optionElems = options.map((option) => {
 | 
				
			||||||
      return (
 | 
					      return (
 | 
				
			||||||
        <AdvancedOptionToggle
 | 
					        <ComposeAdvancedOptionsToggle
 | 
				
			||||||
          onChange={this.props.onChange}
 | 
					          onChange={this.props.onChange}
 | 
				
			||||||
          active={values.get(option.key)}
 | 
					          active={values.get(option.name)}
 | 
				
			||||||
          key={option.key}
 | 
					          key={option.name}
 | 
				
			||||||
          name={option.key}
 | 
					          name={option.name}
 | 
				
			||||||
          shortText={intl.formatMessage(option.shortText)}
 | 
					          shortText={intl.formatMessage(option.shortText)}
 | 
				
			||||||
          longText={intl.formatMessage(option.longText)}
 | 
					          longText={intl.formatMessage(option.longText)}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (<div ref={this.setRef} className={`advanced-options-dropdown ${open ?  'open' : ''} ${anyEnabled ? 'active' : ''} `}>
 | 
					/*
 | 
				
			||||||
      <div className='advanced-options-dropdown__value'>
 | 
					
 | 
				
			||||||
        <IconButton
 | 
					Finally, we can render our component.
 | 
				
			||||||
          className='advanced-options-dropdown__value'
 | 
					
 | 
				
			||||||
          title={intl.formatMessage(messages.advanced_options_icon_title)}
 | 
					*/
 | 
				
			||||||
          icon='ellipsis-h' active={open || anyEnabled}
 | 
					
 | 
				
			||||||
          size={18}
 | 
					    return (
 | 
				
			||||||
          style={iconStyle}
 | 
					      <div ref={this.setRef} className={`advanced-options-dropdown ${open ?  'open' : ''} ${anyEnabled ? 'active' : ''} `}>
 | 
				
			||||||
          onClick={this.onToggleDropdown}
 | 
					        <div className='advanced-options-dropdown__value'>
 | 
				
			||||||
        />
 | 
					          <IconButton
 | 
				
			||||||
 | 
					            className='advanced-options-dropdown__value'
 | 
				
			||||||
 | 
					            title={intl.formatMessage(messages.advanced_options_icon_title)}
 | 
				
			||||||
 | 
					            icon='ellipsis-h' active={open || anyEnabled}
 | 
				
			||||||
 | 
					            size={18}
 | 
				
			||||||
 | 
					            style={iconStyle}
 | 
				
			||||||
 | 
					            onClick={this.onToggleDropdown}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div className='advanced-options-dropdown__dropdown'>
 | 
				
			||||||
 | 
					          {optionElems}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div className='advanced-options-dropdown__dropdown'>
 | 
					    );
 | 
				
			||||||
        {optionElems}
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,103 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`<ComposeAdvancedOptionsToggle>`
 | 
				
			||||||
 | 
					================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					>   For more information on the contents of this file, please contact:
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
 | 
					>   - surinna [@srn@dev.glitch.social]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This creates the toggle used by `<ComposeAdvancedOptions>`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__Props:__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`onChange` (`PropTypes.func`) :__
 | 
				
			||||||
 | 
					    This provides the function to call when the toggle is
 | 
				
			||||||
 | 
					    (de-?)activated.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`active` (`PropTypes.bool`) :__
 | 
				
			||||||
 | 
					    This prop controls whether the toggle is currently active or not.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`name` (`PropTypes.string`) :__
 | 
				
			||||||
 | 
					    This identifies the toggle, and is sent to `onChange()` when it is
 | 
				
			||||||
 | 
					    called.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`shortText` (`PropTypes.string`) :__
 | 
				
			||||||
 | 
					    This is a short string used as the title of the toggle.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`longText` (`PropTypes.string`) :__
 | 
				
			||||||
 | 
					    This is a longer string used as a subtitle for the toggle.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Imports:
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  Package imports  //
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
 | 
					import Toggle from 'react-toggle';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Implementation:
 | 
				
			||||||
 | 
					---------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class ComposeAdvancedOptionsToggle extends React.PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static propTypes = {
 | 
				
			||||||
 | 
					    onChange: PropTypes.func.isRequired,
 | 
				
			||||||
 | 
					    active: PropTypes.bool.isRequired,
 | 
				
			||||||
 | 
					    name: PropTypes.string.isRequired,
 | 
				
			||||||
 | 
					    shortText: PropTypes.string.isRequired,
 | 
				
			||||||
 | 
					    longText: PropTypes.string.isRequired,
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###  `onToggle()`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `onToggle()` function simply calls the `onChange()` prop with the
 | 
				
			||||||
 | 
					toggle's `name`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onToggle = () => {
 | 
				
			||||||
 | 
					    this.props.onChange(this.props.name);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###  `render()`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `render()` function is used to render our component. We just render
 | 
				
			||||||
 | 
					a `<Toggle>` and place next to it our text.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  render() {
 | 
				
			||||||
 | 
					    const { active, shortText, longText } = this.props;
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <div role='button' tabIndex='0' className='advanced-options-dropdown__option' onClick={this.onToggle}>
 | 
				
			||||||
 | 
					        <div className='advanced-options-dropdown__option__toggle'>
 | 
				
			||||||
 | 
					          <Toggle checked={active} onChange={this.onToggle} />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div className='advanced-options-dropdown__option__content'>
 | 
				
			||||||
 | 
					          <strong>{shortText}</strong>
 | 
				
			||||||
 | 
					          {longText}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,21 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`<NotificationContainer>`
 | 
				
			||||||
 | 
					=========================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This container connects `<Notification>`s to the Redux store.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Imports:
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//  Package imports  //
 | 
					//  Package imports  //
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +26,20 @@ import { makeGetNotification } from '../../../mastodon/selectors';
 | 
				
			||||||
import Notification from '.';
 | 
					import Notification from '.';
 | 
				
			||||||
import { deleteNotification } from '../../../mastodon/actions/notifications';
 | 
					import { deleteNotification } from '../../../mastodon/actions/notifications';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					State mapping:
 | 
				
			||||||
 | 
					--------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `mapStateToProps()` function maps various state properties to the
 | 
				
			||||||
 | 
					props of our component. We wrap this in `makeMapStateToProps()` so that
 | 
				
			||||||
 | 
					we only have to call `makeGetNotification()` once instead of every
 | 
				
			||||||
 | 
					time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const makeMapStateToProps = () => {
 | 
					const makeMapStateToProps = () => {
 | 
				
			||||||
  const getNotification = makeGetNotification();
 | 
					  const getNotification = makeGetNotification();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,7 +51,20 @@ const makeMapStateToProps = () => {
 | 
				
			||||||
  return mapStateToProps;
 | 
					  return mapStateToProps;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapDispatchToProps = (dispatch) => ({
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Dispatch mapping:
 | 
				
			||||||
 | 
					-----------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `mapDispatchToProps()` function maps dispatches to our store to the
 | 
				
			||||||
 | 
					various props of our component. We only need to provide a dispatch for
 | 
				
			||||||
 | 
					deleting notifications.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const mapDispatchToProps = dispatch => ({
 | 
				
			||||||
  onDeleteNotification (id) {
 | 
					  onDeleteNotification (id) {
 | 
				
			||||||
    dispatch(deleteNotification(id));
 | 
					    dispatch(deleteNotification(id));
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										171
									
								
								app/javascript/glitch/components/notification/follow.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								app/javascript/glitch/components/notification/follow.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,171 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`<NotificationFollow>`
 | 
				
			||||||
 | 
					======================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This component renders a follow notification.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__Props:__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`id` (`PropTypes.number.isRequired`) :__
 | 
				
			||||||
 | 
					    This is the id of the notification.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`onDeleteNotification` (`PropTypes.func.isRequired`) :__
 | 
				
			||||||
 | 
					    The function to call when a notification should be
 | 
				
			||||||
 | 
					    dismissed/deleted.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`account` (`PropTypes.object.isRequired`) :__
 | 
				
			||||||
 | 
					    The account associated with the follow notification, ie the account
 | 
				
			||||||
 | 
					    which followed the user.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -  __`intl` (`PropTypes.object.isRequired`) :__
 | 
				
			||||||
 | 
					    Our internationalization object, inserted by `@injectIntl`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Imports:
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  Package imports  //
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
 | 
					import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
 | 
				
			||||||
 | 
					import escapeTextContentForBrowser from 'escape-html';
 | 
				
			||||||
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  Mastodon imports  //
 | 
				
			||||||
 | 
					import emojify from '../../../mastodon/emoji';
 | 
				
			||||||
 | 
					import Permalink from '../../../mastodon/components/permalink';
 | 
				
			||||||
 | 
					import AccountContainer from '../../../mastodon/containers/account_container';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Inital setup:
 | 
				
			||||||
 | 
					-------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `messages` constant is used to define any messages that we need
 | 
				
			||||||
 | 
					from inside props.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const messages = defineMessages({
 | 
				
			||||||
 | 
					  deleteNotification :
 | 
				
			||||||
 | 
					    { id: 'status.dismiss_notification', defaultMessage: 'Dismiss notification' },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Implementation:
 | 
				
			||||||
 | 
					---------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@injectIntl
 | 
				
			||||||
 | 
					export default class NotificationFollow extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static propTypes = {
 | 
				
			||||||
 | 
					    id                   : PropTypes.number.isRequired,
 | 
				
			||||||
 | 
					    onDeleteNotification : PropTypes.func.isRequired,
 | 
				
			||||||
 | 
					    account              : ImmutablePropTypes.map.isRequired,
 | 
				
			||||||
 | 
					    intl                 : PropTypes.object.isRequired,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###  `handleNotificationDeleteClick()`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This function just calls our `onDeleteNotification()` prop with the
 | 
				
			||||||
 | 
					notification's `id`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleNotificationDeleteClick = () => {
 | 
				
			||||||
 | 
					    this.props.onDeleteNotification(this.props.id);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###  `render()`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This actually renders the component.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  render () {
 | 
				
			||||||
 | 
					    const { account, intl } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`dismiss` creates the notification dismissal button. Its title is given
 | 
				
			||||||
 | 
					by `dismissTitle`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const dismissTitle = intl.formatMessage(messages.deleteNotification);
 | 
				
			||||||
 | 
					    const dismiss = (
 | 
				
			||||||
 | 
					      <button
 | 
				
			||||||
 | 
					        aria-label={dismissTitle}
 | 
				
			||||||
 | 
					        title={dismissTitle}
 | 
				
			||||||
 | 
					        onClick={this.handleNotificationDeleteClick}
 | 
				
			||||||
 | 
					        className='status__prepend-dismiss-button'
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <i className='fa fa-eraser' />
 | 
				
			||||||
 | 
					      </button>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`link` is a container for the account's `displayName`, which links to
 | 
				
			||||||
 | 
					the account timeline using a `<Permalink>`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const displayName = account.get('display_name') || account.get('username');
 | 
				
			||||||
 | 
					    const displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) };
 | 
				
			||||||
 | 
					    const link = (
 | 
				
			||||||
 | 
					      <Permalink
 | 
				
			||||||
 | 
					        className='notification__display-name'
 | 
				
			||||||
 | 
					        href={account.get('url')}
 | 
				
			||||||
 | 
					        title={account.get('acct')}
 | 
				
			||||||
 | 
					        to={`/accounts/${account.get('id')}`}
 | 
				
			||||||
 | 
					        dangerouslySetInnerHTML={displayNameHTML}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We can now render our component.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <div className='notification notification-follow'>
 | 
				
			||||||
 | 
					        <div className='notification__message'>
 | 
				
			||||||
 | 
					          <div className='notification__favourite-icon-wrapper'>
 | 
				
			||||||
 | 
					            <i className='fa fa-fw fa-user-plus' />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <FormattedMessage
 | 
				
			||||||
 | 
					            id='notification.follow'
 | 
				
			||||||
 | 
					            defaultMessage='{name} followed you'
 | 
				
			||||||
 | 
					            values={{ name: link }}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          {dismiss}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <AccountContainer id={account.get('id')} withNote={false} />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,78 +0,0 @@
 | 
				
			||||||
//  Package imports  //
 | 
					 | 
				
			||||||
import React from 'react';
 | 
					 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
 | 
					 | 
				
			||||||
import escapeTextContentForBrowser from 'escape-html';
 | 
					 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//  Mastodon imports  //
 | 
					 | 
				
			||||||
import emojify from '../../../mastodon/emoji';
 | 
					 | 
				
			||||||
import Permalink from '../../../mastodon/components/permalink';
 | 
					 | 
				
			||||||
import AccountContainer from '../../../mastodon/containers/account_container';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const messages = defineMessages({
 | 
					 | 
				
			||||||
  deleteNotification: { id: 'status.dismiss_notification', defaultMessage: 'Dismiss notification' },
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@injectIntl
 | 
					 | 
				
			||||||
export default class FollowNotification extends ImmutablePureComponent {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static contextTypes = {
 | 
					 | 
				
			||||||
    router: PropTypes.object,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static propTypes = {
 | 
					 | 
				
			||||||
    notificationId: PropTypes.number.isRequired,
 | 
					 | 
				
			||||||
    onDeleteNotification: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
    account: ImmutablePropTypes.map.isRequired,
 | 
					 | 
				
			||||||
    intl: PropTypes.object.isRequired,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Avoid checking props that are functions (and whose equality will always
 | 
					 | 
				
			||||||
  // evaluate to false. See react-immutable-pure-component for usage.
 | 
					 | 
				
			||||||
  updateOnProps = [
 | 
					 | 
				
			||||||
    'account',
 | 
					 | 
				
			||||||
  ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  handleNotificationDeleteClick = () => {
 | 
					 | 
				
			||||||
    this.props.onDeleteNotification(this.props.notificationId);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  render () {
 | 
					 | 
				
			||||||
    const { account, intl } = this.props;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const dismissTitle = intl.formatMessage(messages.deleteNotification);
 | 
					 | 
				
			||||||
    const dismiss = (
 | 
					 | 
				
			||||||
      <button
 | 
					 | 
				
			||||||
        aria-label={dismissTitle}
 | 
					 | 
				
			||||||
        title={dismissTitle}
 | 
					 | 
				
			||||||
        onClick={this.handleNotificationDeleteClick}
 | 
					 | 
				
			||||||
        className='status__prepend-dismiss-button'
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <i className='fa fa-eraser' />
 | 
					 | 
				
			||||||
      </button>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const displayName      = account.get('display_name').length > 0 ? account.get('display_name') : account.get('username');
 | 
					 | 
				
			||||||
    const displayNameHTML  = { __html: emojify(escapeTextContentForBrowser(displayName)) };
 | 
					 | 
				
			||||||
    const link             = <Permalink className='notification__display-name' href={account.get('url')} title={account.get('acct')} to={`/accounts/${account.get('id')}`} dangerouslySetInnerHTML={displayNameHTML} />;
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <div className='notification notification-follow'>
 | 
					 | 
				
			||||||
        <div className='notification__message'>
 | 
					 | 
				
			||||||
          <div className='notification__favourite-icon-wrapper'>
 | 
					 | 
				
			||||||
            <i className='fa fa-fw fa-user-plus' />
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          <FormattedMessage id='notification.follow' defaultMessage='{name} followed you' values={{ name: link }} />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          {dismiss}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <AccountContainer id={account.get('id')} withNote={false} />
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ import PropTypes from 'prop-types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//  Our imports  //
 | 
					//  Our imports  //
 | 
				
			||||||
import StatusContainer from '../status/container';
 | 
					import StatusContainer from '../status/container';
 | 
				
			||||||
import FollowNotification from './follow_notification';
 | 
					import NotificationFollow from './follow';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class Notification extends ImmutablePureComponent {
 | 
					export default class Notification extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,8 +20,8 @@ export default class Notification extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  renderFollow (notification) {
 | 
					  renderFollow (notification) {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <FollowNotification
 | 
					      <NotificationFollow
 | 
				
			||||||
        notificationId={notification.get('id')}
 | 
					        id={notification.get('id')}
 | 
				
			||||||
        account={notification.get('account')}
 | 
					        account={notification.get('account')}
 | 
				
			||||||
        onDeleteNotification={this.props.onDeleteNotification}
 | 
					        onDeleteNotification={this.props.onDeleteNotification}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,12 +18,12 @@ associated actions are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            /* * * * */
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Imports
 | 
					Imports:
 | 
				
			||||||
-------
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,12 +36,12 @@ import { STORE_HYDRATE } from '../../mastodon/actions/store';
 | 
				
			||||||
//  Our imports  //
 | 
					//  Our imports  //
 | 
				
			||||||
import { LOCAL_SETTING_CHANGE } from '../actions/local_settings';
 | 
					import { LOCAL_SETTING_CHANGE } from '../actions/local_settings';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            /* * * * */
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
initialState
 | 
					initialState:
 | 
				
			||||||
------------
 | 
					-------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can see the default values for all of our local settings here.
 | 
					You can see the default values for all of our local settings here.
 | 
				
			||||||
These are only used if no previously-saved values exist.
 | 
					These are only used if no previously-saved values exist.
 | 
				
			||||||
| 
						 | 
					@ -71,12 +71,12 @@ const initialState = ImmutableMap({
 | 
				
			||||||
  }),
 | 
					  }),
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            /* * * * */
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Helper functions
 | 
					Helper functions:
 | 
				
			||||||
----------------
 | 
					-----------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###  `hydrate(state, localSettings)`
 | 
					###  `hydrate(state, localSettings)`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,12 +89,12 @@ from `localStorage`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const hydrate = (state, localSettings) => state.mergeDeep(localSettings);
 | 
					const hydrate = (state, localSettings) => state.mergeDeep(localSettings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            /* * * * */
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`localSettings(state = initialState, action)`
 | 
					`localSettings(state = initialState, action)`:
 | 
				
			||||||
---------------------------------------------
 | 
					----------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This function holds our actual reducer.
 | 
					This function holds our actual reducer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`util/bio_metadata`
 | 
					`util/bio_metadata`
 | 
				
			||||||
========================
 | 
					===================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
>   For more information on the contents of this file, please contact:
 | 
					>   For more information on the contents of this file, please contact:
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,7 @@ functions are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            /* * * * */
 | 
					//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*********************************************************************\
 | 
					/*********************************************************************\
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue