about summary refs log tree commit diff
path: root/app/javascript/flavours
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/flavours')
-rw-r--r--app/javascript/flavours/glitch/actions/compose.js5
-rw-r--r--app/javascript/flavours/glitch/components/display_name.js2
-rw-r--r--app/javascript/flavours/glitch/components/media_gallery.js10
-rw-r--r--app/javascript/flavours/glitch/components/status.js1
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js2
-rw-r--r--app/javascript/flavours/glitch/features/composer/index.js1
-rw-r--r--app/javascript/flavours/glitch/features/composer/options/dropdown/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/composer/spoiler/index.js19
-rw-r--r--app/javascript/flavours/glitch/features/composer/upload_form/item/index.js3
-rw-r--r--app/javascript/flavours/glitch/features/notifications/components/follow.js4
-rw-r--r--app/javascript/flavours/glitch/features/status/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/video/index.js5
-rw-r--r--app/javascript/flavours/glitch/styles/forms.scss17
-rw-r--r--app/javascript/flavours/glitch/styles/rtl.scss77
-rw-r--r--app/javascript/flavours/glitch/styles/stream_entries.scss1
-rw-r--r--app/javascript/flavours/glitch/util/emoji/emoji_mart_search_light.js22
16 files changed, 148 insertions, 27 deletions
diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js
index fb311fc0a..58f2b3786 100644
--- a/app/javascript/flavours/glitch/actions/compose.js
+++ b/app/javascript/flavours/glitch/actions/compose.js
@@ -120,6 +120,7 @@ export function submitCompose() {
   return function (dispatch, getState) {
     let status = getState().getIn(['compose', 'text'], '');
     let media  = getState().getIn(['compose', 'media_attachments']);
+    let spoilerText = getState().getIn(['compose', 'spoiler_text'], '');
 
     if ((!status || !status.length) && media.size === 0) {
       return;
@@ -133,8 +134,8 @@ export function submitCompose() {
       status,
       in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
       media_ids: media.map(item => item.get('id')),
-      sensitive: getState().getIn(['compose', 'sensitive']),
-      spoiler_text: getState().getIn(['compose', 'spoiler_text'], ''),
+      sensitive: getState().getIn(['compose', 'sensitive']) || spoilerText.length > 0,
+      spoiler_text: spoilerText,
       visibility: getState().getIn(['compose', 'privacy']),
     }, {
       headers: {
diff --git a/app/javascript/flavours/glitch/components/display_name.js b/app/javascript/flavours/glitch/components/display_name.js
index 4c65aaefa..d6ac4907d 100644
--- a/app/javascript/flavours/glitch/components/display_name.js
+++ b/app/javascript/flavours/glitch/components/display_name.js
@@ -15,7 +15,7 @@ export default function DisplayName ({
   //  The result.
   return account ? (
     <span className={computedClass}>
-      <strong className='display-name__html' dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} />
+      <bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /></bdi>
       {inline ? ' ' : null}
       <span className='display-name__account'>@{account.get('acct')}</span>
     </span>
diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js
index 613318102..e8dfd6f8e 100644
--- a/app/javascript/flavours/glitch/components/media_gallery.js
+++ b/app/javascript/flavours/glitch/components/media_gallery.js
@@ -215,6 +215,7 @@ export default class MediaGallery extends React.PureComponent {
     standalone: PropTypes.bool,
     letterbox: PropTypes.bool,
     fullwidth: PropTypes.bool,
+    hidden: PropTypes.bool,
     media: ImmutablePropTypes.list.isRequired,
     size: PropTypes.object,
     onOpenMedia: PropTypes.func.isRequired,
@@ -235,6 +236,14 @@ export default class MediaGallery extends React.PureComponent {
     }
   }
 
+  componentDidUpdate (prevProps) {
+    if (this.node && this.node.offsetWidth) {
+      this.setState({
+        width: this.node.offsetWidth,
+      });
+    }
+  }
+
   handleOpen = () => {
     this.setState({ visible: !this.state.visible });
   }
@@ -244,6 +253,7 @@ export default class MediaGallery extends React.PureComponent {
   }
 
   handleRef = (node) => {
+    this.node = node;
     if (node /*&& this.isStandaloneEligible()*/) {
       // offsetWidth triggers a layout, so only calculate when we need to
       this.setState({
diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js
index 665aa457a..449532ea4 100644
--- a/app/javascript/flavours/glitch/components/status.js
+++ b/app/javascript/flavours/glitch/components/status.js
@@ -465,6 +465,7 @@ export default class Status extends ImmutablePureComponent {
                 sensitive={status.get('sensitive')}
                 letterbox={settings.getIn(['media', 'letterbox'])}
                 fullwidth={settings.getIn(['media', 'fullwidth'])}
+                hidden={isCollapsed || !isExpanded}
                 onOpenMedia={this.props.onOpenMedia}
               />
             )}
diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js b/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js
index 1c0e081cc..280389bba 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js
@@ -34,7 +34,7 @@ export default class MovedNote extends ImmutablePureComponent {
       <div className='account__moved-note'>
         <div className='account__moved-note__message'>
           <div className='account__moved-note__icon-wrapper'><i className='fa fa-fw fa-suitcase account__moved-note__icon' /></div>
-          <FormattedMessage id='account.moved_to' defaultMessage='{name} has moved to:' values={{ name: <strong dangerouslySetInnerHTML={displayNameHtml} /> }} />
+          <FormattedMessage id='account.moved_to' defaultMessage='{name} has moved to:' values={{ name: <bdi><strong dangerouslySetInnerHTML={displayNameHtml} /></bdi> }} />
         </div>
 
         <a href={to.get('url')} onClick={this.handleAccountClick} className='detailed-status__display-name'>
diff --git a/app/javascript/flavours/glitch/features/composer/index.js b/app/javascript/flavours/glitch/features/composer/index.js
index 257797047..029b11a36 100644
--- a/app/javascript/flavours/glitch/features/composer/index.js
+++ b/app/javascript/flavours/glitch/features/composer/index.js
@@ -437,6 +437,7 @@ class Composer extends React.Component {
           intl={intl}
           onChange={handleChangeSpoiler}
           onSubmit={handleSubmit}
+          onSecondarySubmit={handleSecondarySubmit}
           text={spoilerText}
           ref={handleRefSpoilerText}
         />
diff --git a/app/javascript/flavours/glitch/features/composer/options/dropdown/index.js b/app/javascript/flavours/glitch/features/composer/options/dropdown/index.js
index 8cfbac1bb..7817cc964 100644
--- a/app/javascript/flavours/glitch/features/composer/options/dropdown/index.js
+++ b/app/javascript/flavours/glitch/features/composer/options/dropdown/index.js
@@ -131,7 +131,7 @@ export default class ComposerOptionsDropdown extends React.PureComponent {
     this.state = {
       needsModalUpdate: false,
       open: false,
-      placement: null,
+      placement: 'bottom',
     };
   }
 
diff --git a/app/javascript/flavours/glitch/features/composer/spoiler/index.js b/app/javascript/flavours/glitch/features/composer/spoiler/index.js
index a7fecbcf5..1c3c962f0 100644
--- a/app/javascript/flavours/glitch/features/composer/spoiler/index.js
+++ b/app/javascript/flavours/glitch/features/composer/spoiler/index.js
@@ -25,18 +25,31 @@ const handlers = {
     ctrlKey,
     keyCode,
     metaKey,
+    altKey,
   }) {
-    const { onSubmit } = this.props;
+    const { onSubmit, onSecondarySubmit } = this.props;
 
     //  We submit the status on control/meta + enter.
     if (onSubmit && keyCode === 13 && (ctrlKey || metaKey)) {
       onSubmit();
     }
+
+    // Submit the status with secondary visibility on alt + enter.
+    if (onSecondarySubmit && keyCode === 13 && altKey) {
+      onSecondarySubmit();
+    }
   },
 
   handleRefSpoilerText (spoilerText) {
     this.spoilerText = spoilerText;
   },
+
+  //  When the escape key is released, we focus the UI.
+  handleKeyUp ({ key }) {
+    if (key === 'Escape') {
+      document.querySelector('.ui').parentElement.focus();
+    }
+  },
 };
 
 //  The component.
@@ -50,7 +63,7 @@ export default class ComposerSpoiler extends React.PureComponent {
 
   //  Rendering.
   render () {
-    const { handleKeyDown, handleRefSpoilerText } = this.handlers;
+    const { handleKeyDown, handleKeyUp, handleRefSpoilerText } = this.handlers;
     const {
       hidden,
       intl,
@@ -69,6 +82,7 @@ export default class ComposerSpoiler extends React.PureComponent {
             id='glitch.composer.spoiler.input'
             onChange={onChange}
             onKeyDown={handleKeyDown}
+            onKeyUp={handleKeyUp}
             placeholder={intl.formatMessage(messages.placeholder)}
             type='text'
             value={text}
@@ -87,5 +101,6 @@ ComposerSpoiler.propTypes = {
   intl: PropTypes.object.isRequired,
   onChange: PropTypes.func,
   onSubmit: PropTypes.func,
+  onSecondarySubmit: PropTypes.func,
   text: PropTypes.string,
 };
diff --git a/app/javascript/flavours/glitch/features/composer/upload_form/item/index.js b/app/javascript/flavours/glitch/features/composer/upload_form/item/index.js
index 5addccfb1..93fa4e39e 100644
--- a/app/javascript/flavours/glitch/features/composer/upload_form/item/index.js
+++ b/app/javascript/flavours/glitch/features/composer/upload_form/item/index.js
@@ -14,6 +14,7 @@ import IconButton from 'flavours/glitch/components/icon_button';
 //  Utils.
 import Motion from 'flavours/glitch/util/optional_motion';
 import { assignHandlers } from 'flavours/glitch/util/react_helpers';
+import { isUserTouching } from 'flavours/glitch/util/is_mobile';
 
 //  Messages.
 const messages = defineMessages({
@@ -130,7 +131,7 @@ export default class ComposerUploadFormItem extends React.PureComponent {
       hovered,
       dirtyDescription,
     } = this.state;
-    const active = hovered || focused;
+    const active = hovered || focused || isUserTouching();
     const computedClass = classNames('composer--upload_form--item', { active });
     const x = ((focusX /  2) + .5) * 100;
     const y = ((focusY / -2) + .5) * 100;
diff --git a/app/javascript/flavours/glitch/features/notifications/components/follow.js b/app/javascript/flavours/glitch/features/notifications/components/follow.js
index 54506f67c..ea81d9ab4 100644
--- a/app/javascript/flavours/glitch/features/notifications/components/follow.js
+++ b/app/javascript/flavours/glitch/features/notifications/components/follow.js
@@ -63,13 +63,13 @@ export default class NotificationFollow extends ImmutablePureComponent {
     //  Links to the display name.
     const displayName = account.get('display_name_html') || account.get('username');
     const link = (
-      <Permalink
+      <bdi><Permalink
         className='notification__display-name'
         href={account.get('url')}
         title={account.get('acct')}
         to={`/accounts/${account.get('id')}`}
         dangerouslySetInnerHTML={{ __html: displayName }}
-      />
+      /></bdi>
     );
 
     //  Renders.
diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js
index 4382748d5..cfa1450f6 100644
--- a/app/javascript/flavours/glitch/features/status/index.js
+++ b/app/javascript/flavours/glitch/features/status/index.js
@@ -127,7 +127,7 @@ export default class Status extends ImmutablePureComponent {
     if (status.get('favourited')) {
       this.props.dispatch(unfavourite(status));
     } else {
-      if (e.shiftKey || !favouriteModal) {
+      if ((e && e.shiftKey) || !favouriteModal) {
         this.handleModalFavourite(status);
       } else {
         this.props.dispatch(openModal('FAVOURITE', { status, onFavourite: this.handleModalFavourite }));
@@ -164,7 +164,7 @@ export default class Status extends ImmutablePureComponent {
     if (status.get('reblogged')) {
       this.props.dispatch(unreblog(status));
     } else {
-      if (e.shiftKey || !boostModal) {
+      if ((e && e.shiftKey) || !boostModal) {
         this.handleModalReblog(status);
       } else {
         this.props.dispatch(openModal('BOOST', { status, onReblog: this.handleModalReblog }));
diff --git a/app/javascript/flavours/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js
index 227f298e4..4f95aea96 100644
--- a/app/javascript/flavours/glitch/features/video/index.js
+++ b/app/javascript/flavours/glitch/features/video/index.js
@@ -220,6 +220,11 @@ export default class Video extends React.PureComponent {
   }
 
   componentDidUpdate (prevProps) {
+    if (this.player && this.player.offsetWidth && !this.state.fullscreen) {
+      this.setState({
+        containerWidth: this.player.offsetWidth,
+      });
+    }
     if (this.video && this.state.revealed && this.props.preventPlayback && !prevProps.preventPlayback) {
       this.video.pause();
     }
diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss
index be2bf7cea..8c4c934ea 100644
--- a/app/javascript/flavours/glitch/styles/forms.scss
+++ b/app/javascript/flavours/glitch/styles/forms.scss
@@ -427,7 +427,7 @@ code {
 
     &__append {
       position: absolute;
-      right: 1px;
+      right: 3px;
       top: 1px;
       padding: 10px;
       padding-bottom: 9px;
@@ -460,9 +460,20 @@ code {
   border-radius: 4px;
   padding: 15px 10px;
   margin-bottom: 30px;
-  box-shadow: 0 0 5px rgba($base-shadow-color, 0.2);
   text-align: center;
 
+  &.notice {
+    border: 1px solid rgba($valid-value-color, 0.5);
+    background: rgba($valid-value-color, 0.25);
+    color: $valid-value-color;
+  }
+
+  &.alert {
+    border: 1px solid rgba($error-value-color, 0.5);
+    background: rgba($error-value-color, 0.25);
+    color: $error-value-color;
+  }
+
   p {
     margin-bottom: 15px;
   }
@@ -551,12 +562,12 @@ code {
 .oauth-prompt,
 .follow-prompt {
   margin-bottom: 30px;
-  text-align: center;
   color: $darker-text-color;
 
   h2 {
     font-size: 16px;
     margin-bottom: 30px;
+    text-align: center;
   }
 
   strong {
diff --git a/app/javascript/flavours/glitch/styles/rtl.scss b/app/javascript/flavours/glitch/styles/rtl.scss
index 70aaa5bb1..d4618440d 100644
--- a/app/javascript/flavours/glitch/styles/rtl.scss
+++ b/app/javascript/flavours/glitch/styles/rtl.scss
@@ -73,7 +73,7 @@ body.rtl {
     float: left;
   }
 
-  .setting-toggle {
+  .setting-toggle__label {
     margin-left: 0;
     margin-right: 8px;
   }
@@ -200,6 +200,10 @@ body.rtl {
     right: -2.14285714em;
   }
 
+  .admin-wrapper {
+    direction: rtl;
+  }
+
   .admin-wrapper .sidebar ul a i.fa,
   a.table-action-link i.fa {
     margin-right: 0;
@@ -218,22 +222,47 @@ body.rtl {
     right: 0;
   }
 
+  .simple_form .input.radio_buttons .radio {
+    left: auto;
+    right: 0;
+  }
+
+  .simple_form .input.radio_buttons .radio > label {
+    padding-right: 28px;
+    padding-left: 0;
+  }
+
   .simple_form .input-with-append .input input {
     padding-left: 142px;
     padding-right: 0;
   }
 
-  .simple_form .input-with-append .append {
+  .simple_form .input.boolean label.checkbox {
+    left: auto;
+    right: 0;
+  }
+
+  .simple_form .input.boolean .label_input,
+  .simple_form .input.boolean .hint {
+    padding-left: 0;
+    padding-right: 28px;
+  }
+
+  .simple_form .label_input__append {
     right: auto;
-    left: 0;
+    left: 3px;
 
     &::after {
       right: auto;
       left: 0;
-      background-image: linear-gradient(to left, rgba($ui-base-color, 0), $ui-base-color);
+      background-image: linear-gradient(to left, rgba(darken($ui-base-color, 10%), 0), darken($ui-base-color, 10%));
     }
   }
 
+  .simple_form select {
+    background: darken($ui-base-color, 10%) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>") no-repeat left 8px center / auto 16px;
+  }
+
   .table th,
   .table td {
     text-align: right;
@@ -249,6 +278,10 @@ body.rtl {
     left: auto;
   }
 
+  .landing-page__call-to-action .row__information-board {
+    direction: rtl;
+  }
+
   .landing-page .header .hero .floats .float-1 {
     left: -120px;
     right: auto;
@@ -312,4 +345,40 @@ body.rtl {
       margin-right: 20px;
     }
   }
+
+  .landing-page__information {
+    .account__display-name {
+      margin-right: 0;
+      margin-left: 5px;
+    }
+
+    .account__avatar-wrapper {
+      margin-left: 12px;
+      margin-right: 0;
+    }
+  }
+
+  .card__bar .display-name {
+    margin-left: 0;
+    margin-right: 15px;
+    text-align: right;
+  }
+
+  .fa-chevron-left::before {
+    content: "\F054";
+  }
+
+  .fa-chevron-right::before {
+    content: "\F053";
+  }
+
+  .column-back-button__icon {
+    margin-right: 0;
+    margin-left: 5px;
+  }
+
+  .column-header__setting-arrows .column-header__setting-btn:last-child {
+    padding-left: 0;
+    padding-right: 10px;
+  }
 }
diff --git a/app/javascript/flavours/glitch/styles/stream_entries.scss b/app/javascript/flavours/glitch/styles/stream_entries.scss
index c458fcb79..80e2d0ca0 100644
--- a/app/javascript/flavours/glitch/styles/stream_entries.scss
+++ b/app/javascript/flavours/glitch/styles/stream_entries.scss
@@ -3,7 +3,6 @@
   border-radius: 4px;
   overflow: hidden;
   margin-bottom: 10px;
-  text-align: left;
 
   @media screen and (max-width: $no-gap-breakpoint) {
     margin-bottom: 0;
diff --git a/app/javascript/flavours/glitch/util/emoji/emoji_mart_search_light.js b/app/javascript/flavours/glitch/util/emoji/emoji_mart_search_light.js
index 36351ec02..164fdcc0b 100644
--- a/app/javascript/flavours/glitch/util/emoji/emoji_mart_search_light.js
+++ b/app/javascript/flavours/glitch/util/emoji/emoji_mart_search_light.js
@@ -2,7 +2,7 @@
 // https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/emoji-index.js
 
 import data from './emoji_mart_data_light';
-import { getData, getSanitizedData, intersect } from './emoji_utils';
+import { getData, getSanitizedData, uniq, intersect } from './emoji_utils';
 
 let originalPool = {};
 let index = {};
@@ -103,7 +103,7 @@ function search(value, { emojisToShowFilter, maxResults, include, exclude, custo
       }
     }
 
-    allResults = values.map((value) => {
+    const searchValue = (value) => {
       let aPool = pool,
         aIndex = index,
         length = 0;
@@ -150,15 +150,23 @@ function search(value, { emojisToShowFilter, maxResults, include, exclude, custo
       }
 
       return aIndex.results;
-    }).filter(a => a);
+    };
 
-    if (allResults.length > 1) {
-      results = intersect.apply(null, allResults);
-    } else if (allResults.length) {
-      results = allResults[0];
+    if (values.length > 1) {
+      results = searchValue(value);
     } else {
       results = [];
     }
+
+    allResults = values.map(searchValue).filter(a => a);
+
+    if (allResults.length > 1) {
+      allResults = intersect.apply(null, allResults);
+    } else if (allResults.length) {
+      allResults = allResults[0];
+    }
+
+    results = uniq(results.concat(allResults));
   }
 
   if (results) {