about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js45
-rw-r--r--app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js10
-rw-r--r--app/javascript/mastodon/reducers/settings.js2
-rw-r--r--app/javascript/styles/components.scss31
4 files changed, 66 insertions, 22 deletions
diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
index 210721d9c..9be8909d8 100644
--- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
+++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
@@ -31,6 +31,19 @@ let EmojiPicker, Emoji; // load asynchronously
 const backgroundImageFn = () => `${assetHost}/emoji/sheet.png`;
 const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;
 
+const categoriesSort = [
+  'recent',
+  'custom',
+  'people',
+  'nature',
+  'foods',
+  'activity',
+  'places',
+  'objects',
+  'symbols',
+  'flags',
+];
+
 class ModifierPickerMenu extends React.PureComponent {
 
   static propTypes = {
@@ -141,6 +154,9 @@ class EmojiPickerMenu extends React.PureComponent {
     arrowOffsetLeft: PropTypes.string,
     arrowOffsetTop: PropTypes.string,
     intl: PropTypes.object.isRequired,
+    skinTone: PropTypes.number.isRequired,
+    onSkinTone: PropTypes.func.isRequired,
+    autoPlay: PropTypes.bool,
   };
 
   static defaultProps = {
@@ -151,7 +167,6 @@ class EmojiPickerMenu extends React.PureComponent {
 
   state = {
     modifierOpen: false,
-    modifier: 1,
   };
 
   handleDocumentClick = e => {
@@ -214,20 +229,18 @@ class EmojiPickerMenu extends React.PureComponent {
   }
 
   handleModifierChange = modifier => {
-    if (modifier !== this.state.modifier) {
-      this.setState({ modifier });
-    }
+    this.props.onSkinTone(modifier);
   }
 
   render () {
-    const { loading, style, intl } = this.props;
+    const { loading, style, intl, custom_emojis, autoPlay, skinTone } = this.props;
 
     if (loading) {
       return <div style={{ width: 299 }} />;
     }
 
     const title = intl.formatMessage(messages.emoji);
-    const { modifierOpen, modifier } = this.state;
+    const { modifierOpen } = this.state;
 
     return (
       <div className={classNames('emoji-picker-dropdown__menu', { selecting: modifierOpen })} style={style} ref={this.setRef}>
@@ -235,20 +248,22 @@ class EmojiPickerMenu extends React.PureComponent {
           perLine={8}
           emojiSize={22}
           sheetSize={32}
+          custom={buildCustomEmojis(custom_emojis, autoPlay)}
           color=''
           emoji=''
           set='twitter'
           title={title}
           i18n={this.getI18n()}
           onClick={this.handleClick}
-          skin={modifier}
+          include={categoriesSort}
+          skin={skinTone}
           showPreview={false}
           backgroundImageFn={backgroundImageFn}
         />
 
         <ModifierPicker
           active={modifierOpen}
-          modifier={modifier}
+          modifier={skinTone}
           onOpen={this.handleModifierOpen}
           onClose={this.handleModifierClose}
           onChange={this.handleModifierChange}
@@ -267,6 +282,8 @@ export default class EmojiPickerDropdown extends React.PureComponent {
     autoPlay: PropTypes.bool,
     intl: PropTypes.object.isRequired,
     onPickEmoji: PropTypes.func.isRequired,
+    onSkinTone: PropTypes.func.isRequired,
+    skinTone: PropTypes.number.isRequired,
   };
 
   state = {
@@ -279,8 +296,6 @@ export default class EmojiPickerDropdown extends React.PureComponent {
   }
 
   onShowDropdown = () => {
-    const { autoPlay } = this.props;
-
     this.setState({ active: true });
 
     if (!EmojiPicker) {
@@ -288,9 +303,8 @@ export default class EmojiPickerDropdown extends React.PureComponent {
 
       EmojiPickerAsync().then(EmojiMart => {
         EmojiPicker = EmojiMart.Picker;
-        Emoji = EmojiMart.Emoji;
-        // populate custom emoji in search
-        EmojiMart.emojiIndex.search('', { custom: buildCustomEmojis(this.props.custom_emojis, autoPlay) });
+        Emoji       = EmojiMart.Emoji;
+
         this.setState({ loading: false });
       }).catch(() => {
         this.setState({ loading: false });
@@ -327,7 +341,7 @@ export default class EmojiPickerDropdown extends React.PureComponent {
   }
 
   render () {
-    const { intl, onPickEmoji } = this.props;
+    const { intl, onPickEmoji, autoPlay, onSkinTone, skinTone } = this.props;
     const title = intl.formatMessage(messages.emoji);
     const { active, loading } = this.state;
 
@@ -347,6 +361,9 @@ export default class EmojiPickerDropdown extends React.PureComponent {
             loading={loading}
             onClose={this.onHideDropdown}
             onPick={onPickEmoji}
+            autoPlay={autoPlay}
+            onSkinTone={onSkinTone}
+            skinTone={skinTone}
           />
         </Overlay>
       </div>
diff --git a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js
index cecc46320..56cc6c3b1 100644
--- a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js
+++ b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js
@@ -1,9 +1,17 @@
 import { connect } from 'react-redux';
 import EmojiPickerDropdown from '../components/emoji_picker_dropdown';
+import { changeSetting } from '../../../actions/settings';
 
 const mapStateToProps = state => ({
   custom_emojis: state.get('custom_emojis'),
   autoPlay: state.getIn(['meta', 'auto_play_gif']),
+  skinTone: state.getIn(['settings', 'skinTone']),
 });
 
-export default connect(mapStateToProps)(EmojiPickerDropdown);
+const mapDispatchToProps = dispatch => ({
+  onSkinTone: skinTone => {
+    dispatch(changeSetting(['skinTone'], skinTone));
+  },
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(EmojiPickerDropdown);
diff --git a/app/javascript/mastodon/reducers/settings.js b/app/javascript/mastodon/reducers/settings.js
index dd2d76ec0..3063ddadd 100644
--- a/app/javascript/mastodon/reducers/settings.js
+++ b/app/javascript/mastodon/reducers/settings.js
@@ -7,6 +7,8 @@ import uuid from '../uuid';
 const initialState = ImmutableMap({
   onboarded: false,
 
+  skinTone: 1,
+
   home: ImmutableMap({
     shows: ImmutableMap({
       reblog: true,
diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss
index aecc98e76..6c64528d6 100644
--- a/app/javascript/styles/components.scss
+++ b/app/javascript/styles/components.scss
@@ -2653,19 +2653,36 @@ button.icon-button.active i.fa-retweet {
   flex-direction: column;
 }
 
-@keyframes pulse {
-  0% {
-    opacity: 1;
+@keyframes heartbeat {
+  from {
+    transform: scale(1);
+    transform-origin: center center;
+    animation-timing-function: ease-out;
   }
 
-  100% {
-    opacity: 0.5;
+  10% {
+    transform: scale(0.91);
+    animation-timing-function: ease-in;
+  }
+
+  17% {
+    transform: scale(0.98);
+    animation-timing-function: ease-out;
+  }
+
+  33% {
+    transform: scale(0.87);
+    animation-timing-function: ease-in;
+  }
+
+  45% {
+    transform: scale(1);
+    animation-timing-function: ease-out;
   }
 }
 
 .pulse-loading {
-  animation: pulse 1s ease-in-out infinite;
-  animation-direction: alternate;
+  animation: heartbeat 1.5s ease-in-out infinite both;
 }
 
 .emoji-picker-dropdown__menu {