about summary refs log tree commit diff
path: root/app/javascript/flavours/glitch
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/flavours/glitch')
-rw-r--r--app/javascript/flavours/glitch/actions/importer/normalizer.js4
-rw-r--r--app/javascript/flavours/glitch/actions/notifications.js2
-rw-r--r--app/javascript/flavours/glitch/components/poll.js13
-rw-r--r--app/javascript/flavours/glitch/features/composer/poll_form/components/poll_form.js2
-rw-r--r--app/javascript/flavours/glitch/features/emoji_picker/index.js51
-rw-r--r--app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js9
-rw-r--r--app/javascript/flavours/glitch/features/standalone/public_timeline/index.js13
-rw-r--r--app/javascript/flavours/glitch/styles/about.scss2
-rw-r--r--app/javascript/flavours/glitch/styles/components/composer.scss5
-rw-r--r--app/javascript/flavours/glitch/styles/components/emoji.scss4
-rw-r--r--app/javascript/flavours/glitch/styles/components/emoji_picker.scss25
-rw-r--r--app/javascript/flavours/glitch/styles/forms.scss55
-rw-r--r--app/javascript/flavours/glitch/styles/tables.scss43
-rw-r--r--app/javascript/flavours/glitch/theme.yml6
-rw-r--r--app/javascript/flavours/glitch/util/emoji/emoji_picker.js4
15 files changed, 189 insertions, 49 deletions
diff --git a/app/javascript/flavours/glitch/actions/importer/normalizer.js b/app/javascript/flavours/glitch/actions/importer/normalizer.js
index ccd84364e..a8c3fe16a 100644
--- a/app/javascript/flavours/glitch/actions/importer/normalizer.js
+++ b/app/javascript/flavours/glitch/actions/importer/normalizer.js
@@ -69,9 +69,11 @@ export function normalizeStatus(status, normalOldStatus) {
 export function normalizePoll(poll) {
   const normalPoll = { ...poll };
 
+  const emojiMap = makeEmojiMap(normalPoll);
+
   normalPoll.options = poll.options.map(option => ({
     ...option,
-    title_emojified: emojify(escapeTextContentForBrowser(option.title)),
+    title_emojified: emojify(escapeTextContentForBrowser(option.title), emojiMap),
   }));
 
   return normalPoll;
diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js
index dd4f5fd44..57fecf63d 100644
--- a/app/javascript/flavours/glitch/actions/notifications.js
+++ b/app/javascript/flavours/glitch/actions/notifications.js
@@ -7,6 +7,7 @@ import {
   importFetchedStatus,
   importFetchedStatuses,
 } from './importer';
+import { saveSettings } from './settings';
 import { defineMessages } from 'react-intl';
 import { List as ImmutableList } from 'immutable';
 import { unescapeHTML } from 'flavours/glitch/util/html';
@@ -286,5 +287,6 @@ export function setFilter (filterType) {
       value: filterType,
     });
     dispatch(expandNotifications());
+    dispatch(saveSettings());
   };
 };
diff --git a/app/javascript/flavours/glitch/components/poll.js b/app/javascript/flavours/glitch/components/poll.js
index a1b297ce7..56331cb29 100644
--- a/app/javascript/flavours/glitch/components/poll.js
+++ b/app/javascript/flavours/glitch/components/poll.js
@@ -44,6 +44,11 @@ const timeRemainingString = (intl, date, now) => {
   return relativeTime;
 };
 
+const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
+  obj[`:${emoji.get('shortcode')}:`] = emoji.toJS();
+  return obj;
+}, {});
+
 export default @injectIntl
 class Poll extends ImmutablePureComponent {
 
@@ -99,6 +104,12 @@ class Poll extends ImmutablePureComponent {
     const active             = !!this.state.selected[`${optionIndex}`];
     const showResults        = poll.get('voted') || poll.get('expired');
 
+    let titleEmojified = option.get('title_emojified');
+    if (!titleEmojified) {
+      const emojiMap = makeEmojiMap(poll);
+      titleEmojified = emojify(escapeTextContentForBrowser(option.get('title')), emojiMap);
+    }
+
     return (
       <li key={option.get('title')}>
         {showResults && (
@@ -122,7 +133,7 @@ class Poll extends ImmutablePureComponent {
           {!showResults && <span className={classNames('poll__input', { checkbox: poll.get('multiple'), active })} />}
           {showResults && <span className='poll__number'>{Math.round(percent)}%</span>}
 
-          <span dangerouslySetInnerHTML={{ __html: option.get('title_emojified', emojify(escapeTextContentForBrowser(option.get('title')))) }} />
+          <span dangerouslySetInnerHTML={{ __html: titleEmojified }} />
         </label>
       </li>
     );
diff --git a/app/javascript/flavours/glitch/features/composer/poll_form/components/poll_form.js b/app/javascript/flavours/glitch/features/composer/poll_form/components/poll_form.js
index 7ee28e304..1915b62d5 100644
--- a/app/javascript/flavours/glitch/features/composer/poll_form/components/poll_form.js
+++ b/app/javascript/flavours/glitch/features/composer/poll_form/components/poll_form.js
@@ -51,7 +51,7 @@ class Option extends React.PureComponent {
           <input
             type='text'
             placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
-            maxlength={pollLimits.max_option_chars}
+            maxLength={pollLimits.max_option_chars}
             value={title}
             onChange={this.handleOptionTitleChange}
           />
diff --git a/app/javascript/flavours/glitch/features/emoji_picker/index.js b/app/javascript/flavours/glitch/features/emoji_picker/index.js
index a78117971..d963039dc 100644
--- a/app/javascript/flavours/glitch/features/emoji_picker/index.js
+++ b/app/javascript/flavours/glitch/features/emoji_picker/index.js
@@ -129,6 +129,7 @@ class ModifierPickerMenu extends React.PureComponent {
     active: PropTypes.bool,
     onSelect: PropTypes.func.isRequired,
     onClose: PropTypes.func.isRequired,
+    modifier: PropTypes.number,
   };
 
   handleClick = e => {
@@ -165,20 +166,36 @@ class ModifierPickerMenu extends React.PureComponent {
 
   setRef = c => {
     this.node = c;
+    if (this.node) {
+      this.node.querySelector('li:first-child button').focus(); // focus the first element when opened
+    }
   }
 
   render () {
-    const { active } = this.props;
+    const { active, modifier } = this.props;
 
     return (
-      <div className='emoji-picker-dropdown__modifiers__menu' style={{ display: active ? 'block' : 'none' }} ref={this.setRef}>
-        <button onClick={this.handleClick} data-index={1}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={1} backgroundImageFn={backgroundImageFn} /></button>
-        <button onClick={this.handleClick} data-index={2}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={2} backgroundImageFn={backgroundImageFn} /></button>
-        <button onClick={this.handleClick} data-index={3}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={3} backgroundImageFn={backgroundImageFn} /></button>
-        <button onClick={this.handleClick} data-index={4}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={4} backgroundImageFn={backgroundImageFn} /></button>
-        <button onClick={this.handleClick} data-index={5}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={5} backgroundImageFn={backgroundImageFn} /></button>
-        <button onClick={this.handleClick} data-index={6}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={6} backgroundImageFn={backgroundImageFn} /></button>
-      </div>
+      <ul
+        className='emoji-picker-dropdown__modifiers__menu'
+        style={{ display: active ? 'block' : 'none' }}
+        role='menuitem'
+        ref={this.setRef}
+      >
+        {[1, 2, 3, 4, 5, 6].map(i => (
+          <li
+            onClick={this.handleClick}
+            role='menuitemradio'
+            aria-checked={i === (modifier || 1)}
+            data-index={i}
+            key={i}
+          >
+            <Emoji
+              emoji='fist' set='twitter' size={22} sheetSize={32} skin={i}
+              backgroundImageFn={backgroundImageFn}
+            />
+          </li>
+        ))}
+      </ul>
     );
   }
 
@@ -210,10 +227,22 @@ class ModifierPicker extends React.PureComponent {
   render () {
     const { active, modifier } = this.props;
 
+    function setRef(ref) {
+      if (!ref) {
+        return;
+      }
+      // TODO: It would be nice if we could pass props directly to emoji-mart's buttons.
+      const button = ref.querySelector('button');
+      button.setAttribute('aria-haspopup', 'true');
+      button.setAttribute('aria-expanded', active);
+    }
+
     return (
       <div className='emoji-picker-dropdown__modifiers'>
-        <Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={modifier} onClick={this.handleClick} backgroundImageFn={backgroundImageFn} />
-        <ModifierPickerMenu active={active} onSelect={this.handleSelect} onClose={this.props.onClose} />
+        <div ref={setRef}>
+          <Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={modifier} onClick={this.handleClick} backgroundImageFn={backgroundImageFn} />
+        </div>
+        <ModifierPickerMenu active={active} modifier={modifier} onSelect={this.handleSelect} onClose={this.props.onClose} />
       </div>
     );
   }
diff --git a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js
index 17f064713..4fbd504ef 100644
--- a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js
@@ -3,7 +3,6 @@ import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { expandHashtagTimeline } from 'flavours/glitch/actions/timelines';
-import { connectHashtagStream } from 'flavours/glitch/actions/streaming';
 import Masonry from 'react-masonry-infinite';
 import { List as ImmutableList } from 'immutable';
 import DetailedStatusContainer from 'flavours/glitch/features/status/containers/detailed_status_container';
@@ -31,14 +30,6 @@ class HashtagTimeline extends React.PureComponent {
     const { dispatch, hashtag } = this.props;
 
     dispatch(expandHashtagTimeline(hashtag));
-    this.disconnect = dispatch(connectHashtagStream(hashtag, hashtag));
-  }
-
-  componentWillUnmount () {
-    if (this.disconnect) {
-      this.disconnect();
-      this.disconnect = null;
-    }
   }
 
   handleLoadMore = () => {
diff --git a/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js
index 5e2b3fc6d..5f8a369ff 100644
--- a/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js
@@ -3,7 +3,6 @@ import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { expandPublicTimeline, expandCommunityTimeline } from 'flavours/glitch/actions/timelines';
-import { connectPublicStream, connectCommunityStream } from 'flavours/glitch/actions/streaming';
 import Masonry from 'react-masonry-infinite';
 import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
 import DetailedStatusContainer from 'flavours/glitch/features/status/containers/detailed_status_container';
@@ -42,24 +41,12 @@ class PublicTimeline extends React.PureComponent {
     }
   }
 
-  componentWillUnmount () {
-    this._disconnect();
-  }
-
   _connect () {
     const { dispatch, local } = this.props;
 
     dispatch(local ? expandCommunityTimeline() : expandPublicTimeline());
-    this.disconnect = dispatch(local ? connectCommunityStream() : connectPublicStream());
   }
  
-  _disconnect () {
-    if (this.disconnect) {
-      this.disconnect();
-      this.disconnect = null;
-    }
-  }
-
   handleLoadMore = () => {
     const { dispatch, statusIds, local } = this.props;
     const maxId = statusIds.last();
diff --git a/app/javascript/flavours/glitch/styles/about.scss b/app/javascript/flavours/glitch/styles/about.scss
index 7a457600e..d4ead07a1 100644
--- a/app/javascript/flavours/glitch/styles/about.scss
+++ b/app/javascript/flavours/glitch/styles/about.scss
@@ -660,7 +660,7 @@ $small-breakpoint: 960px;
     display: flex;
     justify-content: center;
     align-items: center;
-    padding: 100px;
+    padding: 50px;
 
     img {
       height: 52px;
diff --git a/app/javascript/flavours/glitch/styles/components/composer.scss b/app/javascript/flavours/glitch/styles/components/composer.scss
index e14775e44..f0729bedc 100644
--- a/app/javascript/flavours/glitch/styles/components/composer.scss
+++ b/app/javascript/flavours/glitch/styles/components/composer.scss
@@ -147,6 +147,11 @@
       font-size: 14px;
       font-family: inherit;
       resize: none;
+      scrollbar-color: initial;
+
+      &::-webkit-scrollbar {
+        all: unset;
+      }
 
       &:disabled { background: $ui-secondary-color }
       &:focus { outline: 0 }
diff --git a/app/javascript/flavours/glitch/styles/components/emoji.scss b/app/javascript/flavours/glitch/styles/components/emoji.scss
index dd386d698..ccfd42f28 100644
--- a/app/javascript/flavours/glitch/styles/components/emoji.scss
+++ b/app/javascript/flavours/glitch/styles/components/emoji.scss
@@ -44,11 +44,11 @@
   box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
   overflow: hidden;
 
-  button {
+  li {
     display: block;
     cursor: pointer;
     border: 0;
-    padding: 4px 8px;
+    padding: 3px 8px;
     background: transparent;
 
     &:hover,
diff --git a/app/javascript/flavours/glitch/styles/components/emoji_picker.scss b/app/javascript/flavours/glitch/styles/components/emoji_picker.scss
index dcc551c5b..171623352 100644
--- a/app/javascript/flavours/glitch/styles/components/emoji_picker.scss
+++ b/app/javascript/flavours/glitch/styles/components/emoji_picker.scss
@@ -1,3 +1,5 @@
+@import '~emoji-mart/css/emoji-mart.css';
+
 .emoji-mart {
   &,
   * {
@@ -51,6 +53,14 @@
 
   &:hover {
     color: darken($lighter-text-color, 4%);
+
+    svg {
+      fill: darken($lighter-text-color, 4%);
+    }
+  }
+
+  svg {
+    fill: $lighter-text-color;
   }
 }
 
@@ -59,11 +69,19 @@
 
   &:hover {
     color: darken($highlight-text-color, 4%);
+
+    svg {
+      fill: darken($highlight-text-color, 4%);
+    }
   }
 
   .emoji-mart-anchor-bar {
     bottom: 0;
   }
+
+  svg {
+    fill: $highlight-text-color;
+  }
 }
 
 .emoji-mart-anchor-bar {
@@ -83,7 +101,6 @@
   }
 
   svg {
-    fill: currentColor;
     max-height: 18px;
   }
 }
@@ -103,15 +120,14 @@
 }
 
 .emoji-mart-search {
-  padding: 10px;
-  padding-right: 45px;
+  margin: 10px 40px 10px 5px;
   background: $simple-background-color;
 
   input {
     font-size: 14px;
     font-weight: 400;
     padding: 7px 9px;
-    font-family: inherit;
+    font-family: $font-sans-serif;
     display: block;
     width: 100%;
     background: rgba($ui-secondary-color, 0.3);
@@ -166,6 +182,7 @@
     font-weight: 500;
     padding: 5px 6px;
     background: $simple-background-color;
+    font-family: $font-sans-serif;
   }
 }
 
diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss
index 6051c1d00..9ef45e425 100644
--- a/app/javascript/flavours/glitch/styles/forms.scss
+++ b/app/javascript/flavours/glitch/styles/forms.scss
@@ -801,3 +801,58 @@ code {
     }
   }
 }
+
+.connection-prompt {
+  margin-bottom: 25px;
+
+  .fa-link {
+    background-color: darken($ui-base-color, 4%);
+    border-radius: 100%;
+    font-size: 24px;
+    padding: 10px;
+  }
+
+  &__column {
+    align-items: center;
+    display: flex;
+    flex: 1;
+    flex-direction: column;
+    flex-shrink: 1;
+
+    &-sep {
+      flex-grow: 0;
+      overflow: visible;
+      position: relative;
+      z-index: 1;
+    }
+  }
+
+  .account__avatar {
+    margin-bottom: 20px;
+  }
+
+  &__connection {
+    background-color: lighten($ui-base-color, 8%);
+    box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
+    border-radius: 4px;
+    padding: 25px 10px;
+    position: relative;
+    text-align: center;
+
+    &::after {
+      background-color: darken($ui-base-color, 4%);
+      content: '';
+      display: block;
+      height: 100%;
+      left: 50%;
+      position: absolute;
+      width: 1px;
+    }
+  }
+
+  &__row {
+    align-items: center;
+    display: flex;
+    flex-direction: row;
+  }
+}
diff --git a/app/javascript/flavours/glitch/styles/tables.scss b/app/javascript/flavours/glitch/styles/tables.scss
index 296182ff5..154844665 100644
--- a/app/javascript/flavours/glitch/styles/tables.scss
+++ b/app/javascript/flavours/glitch/styles/tables.scss
@@ -140,6 +140,19 @@ a.table-action-link {
       input {
         margin-top: 8px;
       }
+
+      &--aligned {
+        display: flex;
+        align-items: center;
+
+        input {
+          margin-top: 0;
+        }
+      }
+
+      @media screen and (max-width: $no-gap-breakpoint) {
+        display: none;
+      }
     }
 
     &__actions,
@@ -161,6 +174,10 @@ a.table-action-link {
       text-align: right;
       padding-right: 16px - 5px;
     }
+
+    @media screen and (max-width: $no-gap-breakpoint) {
+      display: none;
+    }
   }
 
   &__row {
@@ -168,6 +185,12 @@ a.table-action-link {
     border-top: 0;
     background: darken($ui-base-color, 4%);
 
+    @media screen and (max-width: $no-gap-breakpoint) {
+      &:first-child {
+        border-top: 1px solid darken($ui-base-color, 8%);
+      }
+    }
+
     &:hover {
       background: darken($ui-base-color, 2%);
     }
@@ -183,6 +206,10 @@ a.table-action-link {
     &__content {
       padding-top: 12px;
       padding-bottom: 16px;
+
+      &--unpadded {
+        padding: 0;
+      }
     }
   }
 
@@ -193,4 +220,20 @@ a.table-action-link {
       font-weight: 700;
     }
   }
+
+  .nothing-here {
+    border: 1px solid darken($ui-base-color, 8%);
+    border-top: 0;
+    box-shadow: none;
+
+    @media screen and (max-width: $no-gap-breakpoint) {
+      border-top: 1px solid darken($ui-base-color, 8%);
+    }
+  }
+
+  @media screen and (max-width: 870px) {
+    .accounts-table tbody td.optional {
+      display: none;
+    }
+  }
 }
diff --git a/app/javascript/flavours/glitch/theme.yml b/app/javascript/flavours/glitch/theme.yml
index d8f313381..587cc0f1e 100644
--- a/app/javascript/flavours/glitch/theme.yml
+++ b/app/javascript/flavours/glitch/theme.yml
@@ -28,10 +28,8 @@ pack:
 locales: locales
 
 #  (OPTIONAL) A file to use as the preview screenshot for the flavour,
-#  or an array thereof. These filenames must be unique across all
-#  images (regardless of path), so it's a good idea to namespace them
-#  to your theme. It's up to you to let webpack know to compile them.
-screenshot: glitch-preview.jpg
+#  or an array thereof. These are the full path from `app/javascript/`.
+screenshot: flavours/glitch/images/glitch-preview.jpg
 
 #  (OPTIONAL) The directory which contains the pack files.
 #  Defaults to the theme directory (`app/javascript/themes/[theme]`),
diff --git a/app/javascript/flavours/glitch/util/emoji/emoji_picker.js b/app/javascript/flavours/glitch/util/emoji/emoji_picker.js
index 044d38cb2..73fcaa8c8 100644
--- a/app/javascript/flavours/glitch/util/emoji/emoji_picker.js
+++ b/app/javascript/flavours/glitch/util/emoji/emoji_picker.js
@@ -1,5 +1,5 @@
-import Picker from 'emoji-mart/dist-es/components/picker/picker';
-import Emoji from 'emoji-mart/dist-es/components/emoji/emoji';
+import Picker from 'emoji-mart/dist-modern/components/picker/picker';
+import Emoji from 'emoji-mart/dist-modern/components/emoji/emoji';
 
 export {
   Picker,