about summary refs log tree commit diff
path: root/app/javascript/flavours/glitch/features/ui
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/flavours/glitch/features/ui')
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/actions_modal.js79
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/compare_history_modal.js79
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/modal_root.js4
3 files changed, 105 insertions, 57 deletions
diff --git a/app/javascript/flavours/glitch/features/ui/components/actions_modal.js b/app/javascript/flavours/glitch/features/ui/components/actions_modal.js
index 24169036c..aae2e4426 100644
--- a/app/javascript/flavours/glitch/features/ui/components/actions_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/actions_modal.js
@@ -7,24 +7,22 @@ import Avatar from 'flavours/glitch/components/avatar';
 import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
 import DisplayName from 'flavours/glitch/components/display_name';
 import classNames from 'classnames';
-import Icon from 'flavours/glitch/components/icon';
-import Link from 'flavours/glitch/components/link';
-import Toggle from 'react-toggle';
+import IconButton from 'flavours/glitch/components/icon_button';
 
 export default class ActionsModal extends ImmutablePureComponent {
 
   static propTypes = {
     status: ImmutablePropTypes.map,
+    onClick: PropTypes.func,
     actions: PropTypes.arrayOf(PropTypes.shape({
       active: PropTypes.bool,
       href: PropTypes.string,
       icon: PropTypes.string,
-      meta: PropTypes.node,
+      meta: PropTypes.string,
       name: PropTypes.string,
-      on: PropTypes.bool,
-      onPassiveClick: PropTypes.func,
-      text: PropTypes.node,
+      text: PropTypes.string,
     })),
+    renderItemContents: PropTypes.func,
   };
 
   renderAction = (action, i) => {
@@ -32,57 +30,26 @@ export default class ActionsModal extends ImmutablePureComponent {
       return <li key={`sep-${i}`} className='dropdown-menu__separator' />;
     }
 
-    const {
-      active,
-      href,
-      icon,
-      meta,
-      name,
-      on,
-      onClick,
-      onPassiveClick,
-      text,
-    } = action;
+    const { icon = null, text, meta = null, active = false, href = '#' } = action;
+    let contents = this.props.renderItemContents && this.props.renderItemContents(action, i);
 
-    return (
-      <li key={name || i}>
-        <Link
-          className={classNames('link', { active })}
-          href={href}
-          onClick={on !== null && typeof on !== 'undefined' && onPassiveClick || onClick}
-          role={onClick ? 'button' : null}
-        >
-          {function () {
+    if (!contents) {
+      contents = (
+        <React.Fragment>
+          {icon && <IconButton title={text} icon={icon} role='presentation' tabIndex='-1' inverted />}
+          <div>
+            <div className={classNames({ 'actions-modal__item-label': !!meta })}>{text}</div>
+            <div>{meta}</div>
+          </div>
+        </React.Fragment>
+      );
+    }
 
-            //  We render a `<Toggle>` if we were provided an `on`
-            //  property, and otherwise show an `<Icon>` if available.
-            switch (true) {
-            case on !== null && typeof on !== 'undefined':
-              return (
-                <Toggle
-                  checked={on}
-                  onChange={onPassiveClick || onClick}
-                />
-              );
-            case !!icon:
-              return (
-                <Icon
-                  className='icon'
-                  fixedWidth
-                  id={icon}
-                />
-              );
-            default:
-              return null;
-            }
-          }()}
-          {meta ? (
-            <div>
-              <strong>{text}</strong>
-              {meta}
-            </div>
-          ) : <div>{text}</div>}
-        </Link>
+    return (
+      <li key={`${text}-${i}`}>
+        <a href={href} target='_blank' rel='noopener noreferrer' onClick={this.props.onClick} data-index={i} className={classNames('link', { active })}>
+          {contents}
+        </a>
       </li>
     );
   }
diff --git a/app/javascript/flavours/glitch/features/ui/components/compare_history_modal.js b/app/javascript/flavours/glitch/features/ui/components/compare_history_modal.js
new file mode 100644
index 000000000..198443221
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/ui/components/compare_history_modal.js
@@ -0,0 +1,79 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import { connect } from 'react-redux';
+import { FormattedMessage } from 'react-intl';
+import { closeModal } from 'flavours/glitch/actions/modal';
+import emojify from 'flavours/glitch/util/emoji';
+import escapeTextContentForBrowser from 'escape-html';
+import InlineAccount from 'flavours/glitch/components/inline_account';
+import IconButton from 'flavours/glitch/components/icon_button';
+import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
+
+const mapStateToProps = (state, { statusId }) => ({
+  versions: state.getIn(['history', statusId, 'items']),
+});
+
+const mapDispatchToProps = dispatch => ({
+
+  onClose() {
+    dispatch(closeModal());
+  },
+
+});
+
+export default @connect(mapStateToProps, mapDispatchToProps)
+class CompareHistoryModal extends React.PureComponent {
+
+  static propTypes = {
+    onClose: PropTypes.func.isRequired,
+    index: PropTypes.number.isRequired,
+    statusId: PropTypes.string.isRequired,
+    versions: ImmutablePropTypes.list.isRequired,
+  };
+
+  render () {
+    const { index, versions, onClose } = this.props;
+    const currentVersion = versions.get(index);
+
+    const emojiMap = currentVersion.get('emojis').reduce((obj, emoji) => {
+      obj[`:${emoji.get('shortcode')}:`] = emoji.toJS();
+      return obj;
+    }, {});
+
+    const content = { __html: emojify(currentVersion.get('content'), emojiMap) };
+    const spoilerContent = { __html: emojify(escapeTextContentForBrowser(currentVersion.get('spoiler_text')), emojiMap) };
+
+    const formattedDate = <RelativeTimestamp timestamp={currentVersion.get('created_at')} short={false} />;
+    const formattedName = <InlineAccount accountId={currentVersion.get('account')} />;
+
+    const label = currentVersion.get('original') ? (
+      <FormattedMessage id='status.history.created' defaultMessage='{name} created {date}' values={{ name: formattedName, date: formattedDate }} />
+    ) : (
+      <FormattedMessage id='status.history.edited' defaultMessage='{name} edited {date}' values={{ name: formattedName, date: formattedDate }} />
+    );
+
+    return (
+      <div className='modal-root__modal compare-history-modal'>
+        <div className='report-modal__target'>
+          <IconButton className='report-modal__close' icon='times' onClick={onClose} size={20} />
+          {label}
+        </div>
+
+        <div className='compare-history-modal__container'>
+          <div className='status__content'>
+            {currentVersion.get('spoiler_text').length > 0 && (
+              <React.Fragment>
+                <div className='translate' dangerouslySetInnerHTML={spoilerContent} />
+                <hr />
+              </React.Fragment>
+            )}
+
+            <div className='status__content__text status__content__text--visible translate' dangerouslySetInnerHTML={content} />
+          </div>
+        </div>
+      </div>
+    );
+  }
+
+}
diff --git a/app/javascript/flavours/glitch/features/ui/components/modal_root.js b/app/javascript/flavours/glitch/features/ui/components/modal_root.js
index 62bb167a0..1e065c171 100644
--- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js
+++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js
@@ -24,6 +24,7 @@ import {
   ListEditor,
   ListAdder,
   PinnedAccountsEditor,
+  CompareHistoryModal,
 } from 'flavours/glitch/util/async-components';
 
 const MODAL_COMPONENTS = {
@@ -42,9 +43,10 @@ const MODAL_COMPONENTS = {
   'ACTIONS': () => Promise.resolve({ default: ActionsModal }),
   'EMBED': EmbedModal,
   'LIST_EDITOR': ListEditor,
-  'LIST_ADDER':ListAdder,
   'FOCAL_POINT': () => Promise.resolve({ default: FocalPointModal }),
+  'LIST_ADDER': ListAdder,
   'PINNED_ACCOUNTS_EDITOR': PinnedAccountsEditor,
+  'COMPARE_HISTORY': CompareHistoryModal,
 };
 
 export default class ModalRoot extends React.PureComponent {