about summary refs log tree commit diff
path: root/app/javascript/flavours/glitch/features/composer/textarea/suggestions
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/flavours/glitch/features/composer/textarea/suggestions')
-rw-r--r--app/javascript/flavours/glitch/features/composer/textarea/suggestions/index.js43
-rw-r--r--app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js101
2 files changed, 144 insertions, 0 deletions
diff --git a/app/javascript/flavours/glitch/features/composer/textarea/suggestions/index.js b/app/javascript/flavours/glitch/features/composer/textarea/suggestions/index.js
new file mode 100644
index 000000000..dc72585f2
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/composer/textarea/suggestions/index.js
@@ -0,0 +1,43 @@
+//  Package imports.
+import PropTypes from 'prop-types';
+import React from 'react';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+
+//  Components.
+import ComposerTextareaSuggestionsItem from './item';
+
+//  The component.
+export default function ComposerTextareaSuggestions ({
+  hidden,
+  onSuggestionClick,
+  suggestions,
+  value,
+}) {
+
+  //  The result.
+  return (
+    <div
+      className='composer--textarea--suggestions'
+      hidden={hidden || !suggestions || suggestions.isEmpty()}
+    >
+      {!hidden && suggestions ? suggestions.map(
+        (suggestion, index) => (
+          <ComposerTextareaSuggestionsItem
+            index={index}
+            key={typeof suggestion === 'object' ? suggestion.id : suggestion}
+            onClick={onSuggestionClick}
+            selected={index === value}
+            suggestion={suggestion}
+          />
+        )
+      ) : null}
+    </div>
+  );
+}
+
+ComposerTextareaSuggestions.propTypes = {
+  hidden: PropTypes.bool,
+  onSuggestionClick: PropTypes.func,
+  suggestions: ImmutablePropTypes.list,
+  value: PropTypes.number,
+};
diff --git a/app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js b/app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js
new file mode 100644
index 000000000..d2c794ae9
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/composer/textarea/suggestions/item/index.js
@@ -0,0 +1,101 @@
+//  Package imports.
+import classNames from 'classnames';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+//  Components.
+import AccountContainer from 'flavours/glitch/containers/account_container';
+
+//  Utils.
+import { unicodeMapping } from 'flavours/glitch/util/emoji';
+import { assignHandlers } from 'flavours/glitch/util/react_helpers';
+
+//  Gets our asset host from the environment, if available.
+const assetHost = ((process || {}).env || {}).CDN_HOST || '';
+
+//  Handlers.
+const handlers = {
+
+  //  Handles a click on a suggestion.
+  handleClick (e) {
+    const {
+      index,
+      onClick,
+    } = this.props;
+    if (onClick) {
+      e.preventDefault();
+      onClick(index);
+    }
+  },
+};
+
+//  The component.
+export default class ComposerTextareaSuggestionsItem extends React.Component {
+
+  //  Constructor.
+  constructor (props) {
+    super(props);
+    assignHandlers(this, handlers);
+  }
+
+  //  Rendering.
+  render () {
+    const { handleClick } = this.handlers;
+    const {
+      selected,
+      suggestion,
+    } = this.props;
+    const computedClass = classNames('composer--textarea--suggestions--item', { selected });
+
+    //  The result.
+    return (
+      <div
+        className={computedClass}
+        onMouseDown={handleClick}
+        role='button'
+        tabIndex='0'
+      >
+        { //  If the suggestion is an object, then we render an emoji.
+          //  Otherwise, we render an account.
+          typeof suggestion === 'object' ? function () {
+            const url = function () {
+              if (suggestion.custom) {
+                return suggestion.imageUrl;
+              } else {
+                const mapping = unicodeMapping[suggestion.native] || unicodeMapping[suggestion.native.replace(/\uFE0F$/, '')];
+                if (!mapping) {
+                  return null;
+                }
+                return `${assetHost}/emoji/${mapping.filename}.svg`;
+              }
+            }();
+            return url ? (
+              <div className='emoji'>
+                <img
+                  alt={suggestion.native || suggestion.colons}
+                  className='emojione'
+                  src={url}
+                />
+                {suggestion.colons}
+              </div>
+            ) : null;
+          }() : (
+            <AccountContainer
+              id={suggestion}
+              small
+            />
+          )
+        }
+      </div>
+    );
+  }
+
+}
+
+//  Props.
+ComposerTextareaSuggestionsItem.propTypes = {
+  index: PropTypes.number,
+  onClick: PropTypes.func,
+  selected: PropTypes.bool,
+  suggestion: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
+};