diff --git a/app/javascript/flavours/glitch/actions/account_notes.js b/app/javascript/flavours/glitch/actions/account_notes.js
index c1cce31939..059ed9e803 100644
--- a/app/javascript/flavours/glitch/actions/account_notes.js
+++ b/app/javascript/flavours/glitch/actions/account_notes.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
export const ACCOUNT_NOTE_SUBMIT_REQUEST = 'ACCOUNT_NOTE_SUBMIT_REQUEST';
export const ACCOUNT_NOTE_SUBMIT_SUCCESS = 'ACCOUNT_NOTE_SUBMIT_SUCCESS';
diff --git a/app/javascript/flavours/glitch/actions/accounts.js b/app/javascript/flavours/glitch/actions/accounts.js
index 7507408798..dc670e50ac 100644
--- a/app/javascript/flavours/glitch/actions/accounts.js
+++ b/app/javascript/flavours/glitch/actions/accounts.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'flavours/glitch/util/api';
+import api, { getLinks } from '../api';
import { importAccount, importFetchedAccount, importFetchedAccounts } from './importer';
export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST';
diff --git a/app/javascript/flavours/glitch/actions/announcements.js b/app/javascript/flavours/glitch/actions/announcements.js
index 871409d437..1bdea909f7 100644
--- a/app/javascript/flavours/glitch/actions/announcements.js
+++ b/app/javascript/flavours/glitch/actions/announcements.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { normalizeAnnouncement } from './importer/normalizer';
export const ANNOUNCEMENTS_FETCH_REQUEST = 'ANNOUNCEMENTS_FETCH_REQUEST';
diff --git a/app/javascript/flavours/glitch/actions/blocks.js b/app/javascript/flavours/glitch/actions/blocks.js
index adae9d83c2..fd9881302a 100644
--- a/app/javascript/flavours/glitch/actions/blocks.js
+++ b/app/javascript/flavours/glitch/actions/blocks.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'flavours/glitch/util/api';
+import api, { getLinks } from '../api';
import { fetchRelationships } from './accounts';
import { importFetchedAccounts } from './importer';
import { openModal } from './modal';
diff --git a/app/javascript/flavours/glitch/actions/bookmarks.js b/app/javascript/flavours/glitch/actions/bookmarks.js
index 83dbf5407c..544ed2ff22 100644
--- a/app/javascript/flavours/glitch/actions/bookmarks.js
+++ b/app/javascript/flavours/glitch/actions/bookmarks.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'flavours/glitch/util/api';
+import api, { getLinks } from '../api';
import { importFetchedStatuses } from './importer';
export const BOOKMARKED_STATUSES_FETCH_REQUEST = 'BOOKMARKED_STATUSES_FETCH_REQUEST';
diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js
index ab74fb3036..02aa4f144c 100644
--- a/app/javascript/flavours/glitch/actions/compose.js
+++ b/app/javascript/flavours/glitch/actions/compose.js
@@ -1,11 +1,11 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { CancelToken, isCancel } from 'axios';
import { throttle } from 'lodash';
-import { search as emojiSearch } from 'flavours/glitch/util/emoji/emoji_mart_search_light';
+import { search as emojiSearch } from 'flavours/glitch/features/emoji/emoji_mart_search_light';
import { useEmoji } from './emojis';
-import { tagHistory } from 'flavours/glitch/util/settings';
-import { recoverHashtags } from 'flavours/glitch/util/hashtag';
-import resizeImage from 'flavours/glitch/util/resize_image';
+import { tagHistory } from '../settings';
+import { recoverHashtags } from 'flavours/glitch/utils/hashtag';
+import resizeImage from 'flavours/glitch/utils/resize_image';
import { importFetchedAccounts } from './importer';
import { updateTimeline } from './timelines';
import { showAlertForError } from './alerts';
diff --git a/app/javascript/flavours/glitch/actions/conversations.js b/app/javascript/flavours/glitch/actions/conversations.js
index e5c85c65d9..4ef654b1f9 100644
--- a/app/javascript/flavours/glitch/actions/conversations.js
+++ b/app/javascript/flavours/glitch/actions/conversations.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'flavours/glitch/util/api';
+import api, { getLinks } from '../api';
import {
importFetchedAccounts,
importFetchedStatuses,
diff --git a/app/javascript/flavours/glitch/actions/custom_emojis.js b/app/javascript/flavours/glitch/actions/custom_emojis.js
index 29ae72edbf..7b7d0091b5 100644
--- a/app/javascript/flavours/glitch/actions/custom_emojis.js
+++ b/app/javascript/flavours/glitch/actions/custom_emojis.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
export const CUSTOM_EMOJIS_FETCH_REQUEST = 'CUSTOM_EMOJIS_FETCH_REQUEST';
export const CUSTOM_EMOJIS_FETCH_SUCCESS = 'CUSTOM_EMOJIS_FETCH_SUCCESS';
diff --git a/app/javascript/flavours/glitch/actions/directory.js b/app/javascript/flavours/glitch/actions/directory.js
index 9fbfb7f5b7..4b2b6dd56d 100644
--- a/app/javascript/flavours/glitch/actions/directory.js
+++ b/app/javascript/flavours/glitch/actions/directory.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { importFetchedAccounts } from './importer';
import { fetchRelationships } from './accounts';
diff --git a/app/javascript/flavours/glitch/actions/domain_blocks.js b/app/javascript/flavours/glitch/actions/domain_blocks.js
index 6d3f471fa2..34a33a6546 100644
--- a/app/javascript/flavours/glitch/actions/domain_blocks.js
+++ b/app/javascript/flavours/glitch/actions/domain_blocks.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'flavours/glitch/util/api';
+import api, { getLinks } from '../api';
export const DOMAIN_BLOCK_REQUEST = 'DOMAIN_BLOCK_REQUEST';
export const DOMAIN_BLOCK_SUCCESS = 'DOMAIN_BLOCK_SUCCESS';
diff --git a/app/javascript/flavours/glitch/actions/favourites.js b/app/javascript/flavours/glitch/actions/favourites.js
index 0d8bfb14d6..9448b1efe7 100644
--- a/app/javascript/flavours/glitch/actions/favourites.js
+++ b/app/javascript/flavours/glitch/actions/favourites.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'flavours/glitch/util/api';
+import api, { getLinks } from '../api';
import { importFetchedStatuses } from './importer';
export const FAVOURITED_STATUSES_FETCH_REQUEST = 'FAVOURITED_STATUSES_FETCH_REQUEST';
diff --git a/app/javascript/flavours/glitch/actions/filters.js b/app/javascript/flavours/glitch/actions/filters.js
index 9aa31028ab..76326802ea 100644
--- a/app/javascript/flavours/glitch/actions/filters.js
+++ b/app/javascript/flavours/glitch/actions/filters.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { openModal } from './modal';
export const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST';
diff --git a/app/javascript/flavours/glitch/actions/history.js b/app/javascript/flavours/glitch/actions/history.js
index c47057261e..c142aaf617 100644
--- a/app/javascript/flavours/glitch/actions/history.js
+++ b/app/javascript/flavours/glitch/actions/history.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { importFetchedAccounts } from './importer';
export const HISTORY_FETCH_REQUEST = 'HISTORY_FETCH_REQUEST';
diff --git a/app/javascript/flavours/glitch/actions/identity_proofs.js b/app/javascript/flavours/glitch/actions/identity_proofs.js
index 18e679aec4..1039839566 100644
--- a/app/javascript/flavours/glitch/actions/identity_proofs.js
+++ b/app/javascript/flavours/glitch/actions/identity_proofs.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
export const IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST = 'IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST';
export const IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS = 'IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS';
diff --git a/app/javascript/flavours/glitch/actions/importer/normalizer.js b/app/javascript/flavours/glitch/actions/importer/normalizer.js
index 9950a720bd..1c9f524e43 100644
--- a/app/javascript/flavours/glitch/actions/importer/normalizer.js
+++ b/app/javascript/flavours/glitch/actions/importer/normalizer.js
@@ -1,7 +1,7 @@
import escapeTextContentForBrowser from 'escape-html';
-import emojify from 'flavours/glitch/util/emoji';
-import { unescapeHTML } from 'flavours/glitch/util/html';
-import { autoHideCW } from 'flavours/glitch/util/content_warning';
+import emojify from 'flavours/glitch/features/emoji/emoji';
+import { unescapeHTML } from 'flavours/glitch/utils/html';
+import { autoHideCW } from 'flavours/glitch/utils/content_warning';
const domParser = new DOMParser();
diff --git a/app/javascript/flavours/glitch/actions/interactions.js b/app/javascript/flavours/glitch/actions/interactions.js
index 336c8fa907..225ee7eb2a 100644
--- a/app/javascript/flavours/glitch/actions/interactions.js
+++ b/app/javascript/flavours/glitch/actions/interactions.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { importFetchedAccounts, importFetchedStatus } from './importer';
export const REBLOG_REQUEST = 'REBLOG_REQUEST';
diff --git a/app/javascript/flavours/glitch/actions/lists.js b/app/javascript/flavours/glitch/actions/lists.js
index c2309b8c26..5ab9224363 100644
--- a/app/javascript/flavours/glitch/actions/lists.js
+++ b/app/javascript/flavours/glitch/actions/lists.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { importFetchedAccounts } from './importer';
import { showAlertForError } from './alerts';
diff --git a/app/javascript/flavours/glitch/actions/local_settings.js b/app/javascript/flavours/glitch/actions/local_settings.js
index 856674eb3c..a4a928611d 100644
--- a/app/javascript/flavours/glitch/actions/local_settings.js
+++ b/app/javascript/flavours/glitch/actions/local_settings.js
@@ -1,4 +1,4 @@
-import { expandSpoilers, disableSwiping } from 'flavours/glitch/util/initial_state';
+import { expandSpoilers, disableSwiping } from 'flavours/glitch/initial_state';
import { openModal } from './modal';
export const LOCAL_SETTING_CHANGE = 'LOCAL_SETTING_CHANGE';
diff --git a/app/javascript/flavours/glitch/actions/markers.js b/app/javascript/flavours/glitch/actions/markers.js
index 6a0549f7f0..3b6a76bc43 100644
--- a/app/javascript/flavours/glitch/actions/markers.js
+++ b/app/javascript/flavours/glitch/actions/markers.js
@@ -1,6 +1,6 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { debounce } from 'lodash';
-import compareId from 'flavours/glitch/util/compare_id';
+import compareId from '../compare_id';
import { List as ImmutableList } from 'immutable';
export const MARKERS_FETCH_REQUEST = 'MARKERS_FETCH_REQUEST';
diff --git a/app/javascript/flavours/glitch/actions/mutes.js b/app/javascript/flavours/glitch/actions/mutes.js
index 2bacfadb70..1ccf9592f7 100644
--- a/app/javascript/flavours/glitch/actions/mutes.js
+++ b/app/javascript/flavours/glitch/actions/mutes.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'flavours/glitch/util/api';
+import api, { getLinks } from '../api';
import { fetchRelationships } from './accounts';
import { importFetchedAccounts } from './importer';
import { openModal } from 'flavours/glitch/actions/modal';
diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js
index 4581ebc36f..158a5b7e43 100644
--- a/app/javascript/flavours/glitch/actions/notifications.js
+++ b/app/javascript/flavours/glitch/actions/notifications.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'flavours/glitch/util/api';
+import api, { getLinks } from '../api';
import IntlMessageFormat from 'intl-messageformat';
import { fetchFollowRequests, fetchRelationships } from './accounts';
import {
@@ -11,10 +11,10 @@ import { submitMarkers } from './markers';
import { saveSettings } from './settings';
import { defineMessages } from 'react-intl';
import { List as ImmutableList } from 'immutable';
-import { unescapeHTML } from 'flavours/glitch/util/html';
-import { usePendingItems as preferPendingItems } from 'flavours/glitch/util/initial_state';
-import compareId from 'flavours/glitch/util/compare_id';
-import { requestNotificationPermission } from 'flavours/glitch/util/notifications';
+import { unescapeHTML } from 'flavours/glitch/utils/html';
+import { usePendingItems as preferPendingItems } from 'flavours/glitch/initial_state';
+import compareId from 'flavours/glitch/compare_id';
+import { requestNotificationPermission } from 'flavours/glitch/utils/notifications';
export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
export const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP';
diff --git a/app/javascript/flavours/glitch/actions/pin_statuses.js b/app/javascript/flavours/glitch/actions/pin_statuses.js
index 77dfb9c7ff..0926978ac8 100644
--- a/app/javascript/flavours/glitch/actions/pin_statuses.js
+++ b/app/javascript/flavours/glitch/actions/pin_statuses.js
@@ -1,11 +1,11 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { importFetchedStatuses } from './importer';
export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST';
export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS';
export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL';
-import { me } from 'flavours/glitch/util/initial_state';
+import { me } from 'flavours/glitch/initial_state';
export function fetchPinnedStatuses() {
return (dispatch, getState) => {
diff --git a/app/javascript/flavours/glitch/actions/polls.js b/app/javascript/flavours/glitch/actions/polls.js
index ca94a095fe..8e8b82df5d 100644
--- a/app/javascript/flavours/glitch/actions/polls.js
+++ b/app/javascript/flavours/glitch/actions/polls.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { importFetchedPoll } from './importer';
export const POLL_VOTE_REQUEST = 'POLL_VOTE_REQUEST';
diff --git a/app/javascript/flavours/glitch/actions/push_notifications/registerer.js b/app/javascript/flavours/glitch/actions/push_notifications/registerer.js
index 8fdb239f72..762fe260c7 100644
--- a/app/javascript/flavours/glitch/actions/push_notifications/registerer.js
+++ b/app/javascript/flavours/glitch/actions/push_notifications/registerer.js
@@ -1,5 +1,5 @@
-import api from 'flavours/glitch/util/api';
-import { pushNotificationsSetting } from 'flavours/glitch/util/settings';
+import api from '../../api';
+import { pushNotificationsSetting } from '../../settings';
import { setBrowserSupport, setSubscription, clearSubscription } from './setter';
// Taken from https://www.npmjs.com/package/web-push
diff --git a/app/javascript/flavours/glitch/actions/reports.js b/app/javascript/flavours/glitch/actions/reports.js
index 333bc71f4d..fbe5b3791b 100644
--- a/app/javascript/flavours/glitch/actions/reports.js
+++ b/app/javascript/flavours/glitch/actions/reports.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { openModal } from './modal';
export const REPORT_SUBMIT_REQUEST = 'REPORT_SUBMIT_REQUEST';
diff --git a/app/javascript/flavours/glitch/actions/search.js b/app/javascript/flavours/glitch/actions/search.js
index b4aee4525d..7767826933 100644
--- a/app/javascript/flavours/glitch/actions/search.js
+++ b/app/javascript/flavours/glitch/actions/search.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { fetchRelationships } from './accounts';
import { importFetchedAccounts, importFetchedStatuses } from './importer';
diff --git a/app/javascript/flavours/glitch/actions/server.js b/app/javascript/flavours/glitch/actions/server.js
index 215dfeffaa..af8fef780f 100644
--- a/app/javascript/flavours/glitch/actions/server.js
+++ b/app/javascript/flavours/glitch/actions/server.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { importFetchedAccount } from './importer';
export const SERVER_FETCH_REQUEST = 'Server_FETCH_REQUEST';
diff --git a/app/javascript/flavours/glitch/actions/settings.js b/app/javascript/flavours/glitch/actions/settings.js
index fb0bcc09ce..5634a11efb 100644
--- a/app/javascript/flavours/glitch/actions/settings.js
+++ b/app/javascript/flavours/glitch/actions/settings.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { debounce } from 'lodash';
import { showAlertForError } from './alerts';
diff --git a/app/javascript/flavours/glitch/actions/statuses.js b/app/javascript/flavours/glitch/actions/statuses.js
index 58c1d44a69..5930b7a160 100644
--- a/app/javascript/flavours/glitch/actions/statuses.js
+++ b/app/javascript/flavours/glitch/actions/statuses.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { deleteFromTimelines } from './timelines';
import { importFetchedStatus, importFetchedStatuses } from './importer';
diff --git a/app/javascript/flavours/glitch/actions/streaming.js b/app/javascript/flavours/glitch/actions/streaming.js
index 375728cb5a..ffac1b2582 100644
--- a/app/javascript/flavours/glitch/actions/streaming.js
+++ b/app/javascript/flavours/glitch/actions/streaming.js
@@ -1,6 +1,6 @@
// @ts-check
-import { connectStream } from 'flavours/glitch/util/stream';
+import { connectStream } from '../stream';
import {
updateTimeline,
deleteFromTimelines,
diff --git a/app/javascript/flavours/glitch/actions/suggestions.js b/app/javascript/flavours/glitch/actions/suggestions.js
index 7070250e3e..1f1116e75e 100644
--- a/app/javascript/flavours/glitch/actions/suggestions.js
+++ b/app/javascript/flavours/glitch/actions/suggestions.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
import { importFetchedAccounts } from './importer';
import { fetchRelationships } from './accounts';
diff --git a/app/javascript/flavours/glitch/actions/tags.js b/app/javascript/flavours/glitch/actions/tags.js
index 4016cf96fc..37e79d4cba 100644
--- a/app/javascript/flavours/glitch/actions/tags.js
+++ b/app/javascript/flavours/glitch/actions/tags.js
@@ -1,4 +1,4 @@
-import api from 'flavours/glitch/util/api';
+import api from '../api';
export const HASHTAG_FETCH_REQUEST = 'HASHTAG_FETCH_REQUEST';
export const HASHTAG_FETCH_SUCCESS = 'HASHTAG_FETCH_SUCCESS';
diff --git a/app/javascript/flavours/glitch/actions/timelines.js b/app/javascript/flavours/glitch/actions/timelines.js
index 0d6f844b3f..ef1e4dbbb9 100644
--- a/app/javascript/flavours/glitch/actions/timelines.js
+++ b/app/javascript/flavours/glitch/actions/timelines.js
@@ -1,10 +1,10 @@
import { importFetchedStatus, importFetchedStatuses } from './importer';
import { submitMarkers } from './markers';
-import api, { getLinks } from 'flavours/glitch/util/api';
+import api, { getLinks } from 'flavours/glitch/api';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
-import compareId from 'flavours/glitch/util/compare_id';
-import { me, usePendingItems as preferPendingItems } from 'flavours/glitch/util/initial_state';
-import { toServerSideType } from 'flavours/glitch/util/filters';
+import compareId from 'flavours/glitch/compare_id';
+import { me, usePendingItems as preferPendingItems } from 'flavours/glitch/initial_state';
+import { toServerSideType } from 'flavours/glitch/utils/filters';
export const TIMELINE_UPDATE = 'TIMELINE_UPDATE';
export const TIMELINE_DELETE = 'TIMELINE_DELETE';
diff --git a/app/javascript/flavours/glitch/actions/trends.js b/app/javascript/flavours/glitch/actions/trends.js
index e9aa28dd39..edda0b5b5d 100644
--- a/app/javascript/flavours/glitch/actions/trends.js
+++ b/app/javascript/flavours/glitch/actions/trends.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'flavours/glitch/util/api';
+import api, { getLinks } from '../api';
import { importFetchedStatuses } from './importer';
export const TRENDS_TAGS_FETCH_REQUEST = 'TRENDS_TAGS_FETCH_REQUEST';
diff --git a/app/javascript/flavours/glitch/util/api.js b/app/javascript/flavours/glitch/api.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/api.js
rename to app/javascript/flavours/glitch/api.js
index 90d8465efc..645ef65006 100644
--- a/app/javascript/flavours/glitch/util/api.js
+++ b/app/javascript/flavours/glitch/api.js
@@ -1,6 +1,6 @@
import axios from 'axios';
-import ready from './ready';
import LinkHeader from 'http-link-header';
+import ready from './ready';
export const getLinks = response => {
const value = response.headers.link;
diff --git a/app/javascript/flavours/glitch/util/base_polyfills.js b/app/javascript/flavours/glitch/base_polyfills.js
similarity index 94%
rename from app/javascript/flavours/glitch/util/base_polyfills.js
rename to app/javascript/flavours/glitch/base_polyfills.js
index 4b8123dba0..12096d9021 100644
--- a/app/javascript/flavours/glitch/util/base_polyfills.js
+++ b/app/javascript/flavours/glitch/base_polyfills.js
@@ -5,7 +5,7 @@ import includes from 'array-includes';
import assign from 'object-assign';
import values from 'object.values';
import isNaN from 'is-nan';
-import { decode as decodeBase64 } from './base64';
+import { decode as decodeBase64 } from './utils/base64';
import promiseFinally from 'promise.prototype.finally';
if (!Array.prototype.includes) {
diff --git a/app/javascript/flavours/glitch/util/compare_id.js b/app/javascript/flavours/glitch/compare_id.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/compare_id.js
rename to app/javascript/flavours/glitch/compare_id.js
diff --git a/app/javascript/flavours/glitch/components/account.js b/app/javascript/flavours/glitch/components/account.js
index 24d3f65efd..8bfc8e9dce 100644
--- a/app/javascript/flavours/glitch/components/account.js
+++ b/app/javascript/flavours/glitch/components/account.js
@@ -7,7 +7,7 @@ import Permalink from './permalink';
import IconButton from './icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { me } from 'flavours/glitch/util/initial_state';
+import { me } from 'flavours/glitch/initial_state';
import RelativeTimestamp from './relative_timestamp';
import Skeleton from 'flavours/glitch/components/skeleton';
diff --git a/app/javascript/flavours/glitch/components/admin/Counter.js b/app/javascript/flavours/glitch/components/admin/Counter.js
index a4d6cef412..5b6a19f8da 100644
--- a/app/javascript/flavours/glitch/components/admin/Counter.js
+++ b/app/javascript/flavours/glitch/components/admin/Counter.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import api from 'flavours/glitch/util/api';
+import api from 'flavours/glitch/api';
import { FormattedNumber } from 'react-intl';
import { Sparklines, SparklinesCurve } from 'react-sparklines';
import classNames from 'classnames';
diff --git a/app/javascript/flavours/glitch/components/admin/Dimension.js b/app/javascript/flavours/glitch/components/admin/Dimension.js
index a924d093c8..3dac8c6c24 100644
--- a/app/javascript/flavours/glitch/components/admin/Dimension.js
+++ b/app/javascript/flavours/glitch/components/admin/Dimension.js
@@ -1,8 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
-import api from 'flavours/glitch/util/api';
+import api from 'flavours/glitch/api';
import { FormattedNumber } from 'react-intl';
-import { roundTo10 } from 'flavours/glitch/util/numbers';
+import { roundTo10 } from 'flavours/glitch/utils/numbers';
import Skeleton from 'flavours/glitch/components/skeleton';
export default class Dimension extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/components/admin/ReportReasonSelector.js b/app/javascript/flavours/glitch/components/admin/ReportReasonSelector.js
index 0f2a4fe362..771dbb452d 100644
--- a/app/javascript/flavours/glitch/components/admin/ReportReasonSelector.js
+++ b/app/javascript/flavours/glitch/components/admin/ReportReasonSelector.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import api from 'flavours/glitch/util/api';
+import api from 'flavours/glitch/api';
import { injectIntl, defineMessages } from 'react-intl';
import classNames from 'classnames';
diff --git a/app/javascript/flavours/glitch/components/admin/Retention.js b/app/javascript/flavours/glitch/components/admin/Retention.js
index 6d7e4b2798..9cc39040b9 100644
--- a/app/javascript/flavours/glitch/components/admin/Retention.js
+++ b/app/javascript/flavours/glitch/components/admin/Retention.js
@@ -1,9 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
-import api from 'flavours/glitch/util/api';
+import api from 'flavours/glitch/api';
import { FormattedMessage, FormattedNumber, FormattedDate } from 'react-intl';
import classNames from 'classnames';
-import { roundTo10 } from 'flavours/glitch/util/numbers';
+import { roundTo10 } from 'flavours/glitch/utils/numbers';
const dateForCohort = cohort => {
switch(cohort.frequency) {
diff --git a/app/javascript/flavours/glitch/components/admin/Trends.js b/app/javascript/flavours/glitch/components/admin/Trends.js
index 60e367f001..4c17b69a08 100644
--- a/app/javascript/flavours/glitch/components/admin/Trends.js
+++ b/app/javascript/flavours/glitch/components/admin/Trends.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import api from 'flavours/glitch/util/api';
+import api from 'flavours/glitch/api';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import Hashtag from 'flavours/glitch/components/hashtag';
diff --git a/app/javascript/flavours/glitch/components/animated_number.js b/app/javascript/flavours/glitch/components/animated_number.js
index 3cc5173dd4..4619aad587 100644
--- a/app/javascript/flavours/glitch/components/animated_number.js
+++ b/app/javascript/flavours/glitch/components/animated_number.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { FormattedNumber } from 'react-intl';
import TransitionMotion from 'react-motion/lib/TransitionMotion';
import spring from 'react-motion/lib/spring';
-import { reduceMotion } from 'flavours/glitch/util/initial_state';
+import { reduceMotion } from 'flavours/glitch/initial_state';
const obfuscatedCount = count => {
if (count < 0) {
diff --git a/app/javascript/flavours/glitch/components/autosuggest_emoji.js b/app/javascript/flavours/glitch/components/autosuggest_emoji.js
index d04c1eb687..83fafbd10d 100644
--- a/app/javascript/flavours/glitch/components/autosuggest_emoji.js
+++ b/app/javascript/flavours/glitch/components/autosuggest_emoji.js
@@ -1,8 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
-import unicodeMapping from 'flavours/glitch/util/emoji/emoji_unicode_mapping_light';
+import unicodeMapping from 'flavours/glitch/features/emoji/emoji_unicode_mapping_light';
-import { assetHost } from 'flavours/glitch/util/config';
+import { assetHost } from 'flavours/glitch/utils/config';
export default class AutosuggestEmoji extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/components/avatar.js b/app/javascript/flavours/glitch/components/avatar.js
index 6d53a5298d..ce91d401d1 100644
--- a/app/javascript/flavours/glitch/components/avatar.js
+++ b/app/javascript/flavours/glitch/components/avatar.js
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import { autoPlayGif } from 'flavours/glitch/util/initial_state';
+import { autoPlayGif } from 'flavours/glitch/initial_state';
import classNames from 'classnames';
export default class Avatar extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/components/avatar_composite.js b/app/javascript/flavours/glitch/components/avatar_composite.js
index e30dfe68a8..c0ce7761dc 100644
--- a/app/javascript/flavours/glitch/components/avatar_composite.js
+++ b/app/javascript/flavours/glitch/components/avatar_composite.js
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import { autoPlayGif } from 'flavours/glitch/util/initial_state';
+import { autoPlayGif } from 'flavours/glitch/initial_state';
export default class AvatarComposite extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/components/avatar_overlay.js b/app/javascript/flavours/glitch/components/avatar_overlay.js
index 23db5182bc..01dec587a5 100644
--- a/app/javascript/flavours/glitch/components/avatar_overlay.js
+++ b/app/javascript/flavours/glitch/components/avatar_overlay.js
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import { autoPlayGif } from 'flavours/glitch/util/initial_state';
+import { autoPlayGif } from 'flavours/glitch/initial_state';
export default class AvatarOverlay extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/components/column.js b/app/javascript/flavours/glitch/components/column.js
index c9da7d329e..cf0e6d5e40 100644
--- a/app/javascript/flavours/glitch/components/column.js
+++ b/app/javascript/flavours/glitch/components/column.js
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { supportsPassiveEvents } from 'detect-passive-events';
-import { scrollTop } from 'flavours/glitch/util/scroll';
+import { scrollTop } from '../scroll';
export default class Column extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/components/display_name.js b/app/javascript/flavours/glitch/components/display_name.js
index 7cb0c9133d..1c22975785 100644
--- a/app/javascript/flavours/glitch/components/display_name.js
+++ b/app/javascript/flavours/glitch/components/display_name.js
@@ -2,7 +2,7 @@ import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import classNames from 'classnames';
-import { autoPlayGif } from 'flavours/glitch/util/initial_state';
+import { autoPlayGif } from 'flavours/glitch/initial_state';
import Skeleton from 'flavours/glitch/components/skeleton';
export default class DisplayName extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/components/dropdown_menu.js b/app/javascript/flavours/glitch/components/dropdown_menu.js
index e04af8074b..036e0b9090 100644
--- a/app/javascript/flavours/glitch/components/dropdown_menu.js
+++ b/app/javascript/flavours/glitch/components/dropdown_menu.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import IconButton from './icon_button';
import Overlay from 'react-overlays/lib/Overlay';
-import Motion from 'flavours/glitch/util/optional_motion';
+import Motion from '../features/ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import { supportsPassiveEvents } from 'detect-passive-events';
import classNames from 'classnames';
diff --git a/app/javascript/flavours/glitch/components/error_boundary.js b/app/javascript/flavours/glitch/components/error_boundary.js
index 4537bde1d4..fd3659de7a 100644
--- a/app/javascript/flavours/glitch/components/error_boundary.js
+++ b/app/javascript/flavours/glitch/components/error_boundary.js
@@ -1,8 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
-import { source_url } from 'flavours/glitch/util/initial_state';
-import { preferencesLink } from 'flavours/glitch/util/backend_links';
+import { source_url } from 'flavours/glitch/initial_state';
+import { preferencesLink } from 'flavours/glitch/utils/backend_links';
import StackTrace from 'stacktrace-js';
export default class ErrorBoundary extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/components/icon_button.js b/app/javascript/flavours/glitch/components/icon_button.js
index c0664ec890..42f5d4bc35 100644
--- a/app/javascript/flavours/glitch/components/icon_button.js
+++ b/app/javascript/flavours/glitch/components/icon_button.js
@@ -1,5 +1,5 @@
import React from 'react';
-import Motion from 'flavours/glitch/util/optional_motion';
+import Motion from '../features/ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import PropTypes from 'prop-types';
import classNames from 'classnames';
diff --git a/app/javascript/flavours/glitch/components/intersection_observer_article.js b/app/javascript/flavours/glitch/components/intersection_observer_article.js
index 88f29892e8..90667d9f5a 100644
--- a/app/javascript/flavours/glitch/components/intersection_observer_article.js
+++ b/app/javascript/flavours/glitch/components/intersection_observer_article.js
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
-import scheduleIdleTask from 'flavours/glitch/util/schedule_idle_task';
-import getRectFromEntry from 'flavours/glitch/util/get_rect_from_entry';
+import scheduleIdleTask from '../features/ui/util/schedule_idle_task';
+import getRectFromEntry from '../features/ui/util/get_rect_from_entry';
// Diff these props in the "unrendered" state
const updateOnPropsForUnrendered = ['id', 'index', 'listLength', 'cachedHeight'];
diff --git a/app/javascript/flavours/glitch/components/link.js b/app/javascript/flavours/glitch/components/link.js
index de99f7d42b..bbec121a86 100644
--- a/app/javascript/flavours/glitch/components/link.js
+++ b/app/javascript/flavours/glitch/components/link.js
@@ -7,7 +7,7 @@ import PropTypes from 'prop-types';
import React from 'react';
// Utils.
-import { assignHandlers } from 'flavours/glitch/util/react_helpers';
+import { assignHandlers } from 'flavours/glitch/utils/react_helpers';
// Handlers.
const handlers = {
diff --git a/app/javascript/flavours/glitch/components/media_attachments.js b/app/javascript/flavours/glitch/components/media_attachments.js
index c8d133f09d..a517fcf300 100644
--- a/app/javascript/flavours/glitch/components/media_attachments.js
+++ b/app/javascript/flavours/glitch/components/media_attachments.js
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { MediaGallery, Video, Audio } from 'flavours/glitch/util/async-components';
+import { MediaGallery, Video, Audio } from 'flavours/glitch/features/ui/util/async-components';
import Bundle from 'flavours/glitch/features/ui/components/bundle';
import noop from 'lodash/noop';
diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js
index 68195ea807..5414b48586 100644
--- a/app/javascript/flavours/glitch/components/media_gallery.js
+++ b/app/javascript/flavours/glitch/components/media_gallery.js
@@ -4,9 +4,9 @@ import PropTypes from 'prop-types';
import { is } from 'immutable';
import IconButton from './icon_button';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import { isIOS } from 'flavours/glitch/util/is_mobile';
+import { isIOS } from '../is_mobile';
import classNames from 'classnames';
-import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state';
+import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
import { debounce } from 'lodash';
import Blurhash from 'flavours/glitch/components/blurhash';
diff --git a/app/javascript/flavours/glitch/components/poll.js b/app/javascript/flavours/glitch/components/poll.js
index bcd9fe3418..da65cd2415 100644
--- a/app/javascript/flavours/glitch/components/poll.js
+++ b/app/javascript/flavours/glitch/components/poll.js
@@ -4,10 +4,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import classNames from 'classnames';
-import Motion from 'flavours/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/features/ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import escapeTextContentForBrowser from 'escape-html';
-import emojify from 'flavours/glitch/util/emoji';
+import emojify from 'flavours/glitch/features/emoji/emoji';
import RelativeTimestamp from './relative_timestamp';
import Icon from 'flavours/glitch/components/icon';
diff --git a/app/javascript/flavours/glitch/components/scrollable_list.js b/app/javascript/flavours/glitch/components/scrollable_list.js
index 50bfacc6ad..8eb2b66d43 100644
--- a/app/javascript/flavours/glitch/components/scrollable_list.js
+++ b/app/javascript/flavours/glitch/components/scrollable_list.js
@@ -4,11 +4,11 @@ import PropTypes from 'prop-types';
import IntersectionObserverArticleContainer from 'flavours/glitch/containers/intersection_observer_article_container';
import LoadMore from './load_more';
import LoadPending from './load_pending';
-import IntersectionObserverWrapper from 'flavours/glitch/util/intersection_observer_wrapper';
+import IntersectionObserverWrapper from 'flavours/glitch/features/ui/util/intersection_observer_wrapper';
import { throttle } from 'lodash';
import { List as ImmutableList } from 'immutable';
import classNames from 'classnames';
-import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'flavours/glitch/util/fullscreen';
+import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../features/ui/util/fullscreen';
import LoadingIndicator from './loading_indicator';
import { connect } from 'react-redux';
diff --git a/app/javascript/flavours/glitch/components/server_banner.js b/app/javascript/flavours/glitch/components/server_banner.js
index e29876d4b4..16360ec564 100644
--- a/app/javascript/flavours/glitch/components/server_banner.js
+++ b/app/javascript/flavours/glitch/components/server_banner.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { domain } from 'flavours/glitch/util/initial_state';
+import { domain } from 'flavours/glitch/initial_state';
import { fetchServer } from 'flavours/glitch/actions/server';
import { connect } from 'react-redux';
import Account from 'flavours/glitch/containers/account_container';
diff --git a/app/javascript/flavours/glitch/components/short_number.js b/app/javascript/flavours/glitch/components/short_number.js
index e4ba09634c..535c17727d 100644
--- a/app/javascript/flavours/glitch/components/short_number.js
+++ b/app/javascript/flavours/glitch/components/short_number.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { toShortNumber, pluralReady, DECIMAL_UNITS } from '../util/numbers';
+import { toShortNumber, pluralReady, DECIMAL_UNITS } from '../utils/numbers';
import { FormattedMessage, FormattedNumber } from 'react-intl';
// @ts-check
@@ -56,7 +56,7 @@ ShortNumber.propTypes = {
/**
* @typedef {object} ShortNumberCounterProps
- * @property {import('../util/number').ShortNumber} value Short number
+ * @property {import('../utils/number').ShortNumber} value Short number
*/
/**
diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js
index 9b656b2b3e..6cdc4b9719 100644
--- a/app/javascript/flavours/glitch/components/status.js
+++ b/app/javascript/flavours/glitch/components/status.js
@@ -10,13 +10,13 @@ import AttachmentList from './attachment_list';
import Card from '../features/status/components/card';
import { injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { MediaGallery, Video, Audio } from 'flavours/glitch/util/async-components';
+import { MediaGallery, Video, Audio } from '../features/ui/util/async-components';
import { HotKeys } from 'react-hotkeys';
import NotificationOverlayContainer from 'flavours/glitch/features/notifications/containers/overlay_container';
import classNames from 'classnames';
-import { autoUnfoldCW } from 'flavours/glitch/util/content_warning';
+import { autoUnfoldCW } from 'flavours/glitch/utils/content_warning';
import PollContainer from 'flavours/glitch/containers/poll_container';
-import { displayMedia } from 'flavours/glitch/util/initial_state';
+import { displayMedia } from 'flavours/glitch/initial_state';
import PictureInPicturePlaceholder from 'flavours/glitch/components/picture_in_picture_placeholder';
// We use the component (and not the container) since we do not want
diff --git a/app/javascript/flavours/glitch/components/status_action_bar.js b/app/javascript/flavours/glitch/components/status_action_bar.js
index 4e5e5121ae..deb9cfc150 100644
--- a/app/javascript/flavours/glitch/components/status_action_bar.js
+++ b/app/javascript/flavours/glitch/components/status_action_bar.js
@@ -5,9 +5,9 @@ import IconButton from './icon_button';
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { me } from 'flavours/glitch/util/initial_state';
+import { me } from 'flavours/glitch/initial_state';
import RelativeTimestamp from './relative_timestamp';
-import { accountAdminLink, statusAdminLink } from 'flavours/glitch/util/backend_links';
+import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links';
import classNames from 'classnames';
import { PERMISSION_MANAGE_USERS } from 'flavours/glitch/permissions';
diff --git a/app/javascript/flavours/glitch/components/status_content.js b/app/javascript/flavours/glitch/components/status_content.js
index 39891da4f4..fe0d4c0439 100644
--- a/app/javascript/flavours/glitch/components/status_content.js
+++ b/app/javascript/flavours/glitch/components/status_content.js
@@ -5,8 +5,8 @@ import { FormattedMessage } from 'react-intl';
import Permalink from './permalink';
import classnames from 'classnames';
import Icon from 'flavours/glitch/components/icon';
-import { autoPlayGif } from 'flavours/glitch/util/initial_state';
-import { decode as decodeIDNA } from 'flavours/glitch/util/idna';
+import { autoPlayGif } from 'flavours/glitch/initial_state';
+import { decode as decodeIDNA } from 'flavours/glitch/utils/idna';
const textMatchesTarget = (text, origin, host) => {
return (text === origin || text === host
diff --git a/app/javascript/flavours/glitch/components/status_icons.js b/app/javascript/flavours/glitch/components/status_icons.js
index 2226aaef2b..71ffb2e569 100644
--- a/app/javascript/flavours/glitch/components/status_icons.js
+++ b/app/javascript/flavours/glitch/components/status_icons.js
@@ -8,7 +8,7 @@ import { defineMessages, injectIntl } from 'react-intl';
import IconButton from './icon_button';
import VisibilityIcon from './status_visibility_icon';
import Icon from 'flavours/glitch/components/icon';
-import { languages } from 'flavours/glitch/util/initial_state';
+import { languages } from 'flavours/glitch/initial_state';
// Messages for use with internationalization stuff.
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/components/status_prepend.js b/app/javascript/flavours/glitch/components/status_prepend.js
index d850093623..f825330621 100644
--- a/app/javascript/flavours/glitch/components/status_prepend.js
+++ b/app/javascript/flavours/glitch/components/status_prepend.js
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { FormattedMessage } from 'react-intl';
import Icon from 'flavours/glitch/components/icon';
-import { me } from 'flavours/glitch/util/initial_state';
+import { me } from 'flavours/glitch/initial_state';
export default class StatusPrepend extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/containers/account_container.js b/app/javascript/flavours/glitch/containers/account_container.js
index bc84d299b4..5b57d730f0 100644
--- a/app/javascript/flavours/glitch/containers/account_container.js
+++ b/app/javascript/flavours/glitch/containers/account_container.js
@@ -13,7 +13,7 @@ import {
} from 'flavours/glitch/actions/accounts';
import { openModal } from 'flavours/glitch/actions/modal';
import { initMuteModal } from 'flavours/glitch/actions/mutes';
-import { unfollowModal } from 'flavours/glitch/util/initial_state';
+import { unfollowModal } from 'flavours/glitch/initial_state';
const messages = defineMessages({
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
diff --git a/app/javascript/flavours/glitch/containers/compose_container.js b/app/javascript/flavours/glitch/containers/compose_container.js
index 74c411b7c1..1e49b89a0b 100644
--- a/app/javascript/flavours/glitch/containers/compose_container.js
+++ b/app/javascript/flavours/glitch/containers/compose_container.js
@@ -6,7 +6,7 @@ import { hydrateStore } from 'flavours/glitch/actions/store';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from 'mastodon/locales';
import Compose from 'flavours/glitch/features/standalone/compose';
-import initialState from 'flavours/glitch/util/initial_state';
+import initialState from 'flavours/glitch/initial_state';
import { fetchCustomEmojis } from 'flavours/glitch/actions/custom_emojis';
const { localeData, messages } = getLocale();
diff --git a/app/javascript/flavours/glitch/containers/dropdown_menu_container.js b/app/javascript/flavours/glitch/containers/dropdown_menu_container.js
index 0c4a2b50ff..b2dff63db8 100644
--- a/app/javascript/flavours/glitch/containers/dropdown_menu_container.js
+++ b/app/javascript/flavours/glitch/containers/dropdown_menu_container.js
@@ -2,7 +2,7 @@ import { openDropdownMenu, closeDropdownMenu } from 'flavours/glitch/actions/dro
import { openModal, closeModal } from 'flavours/glitch/actions/modal';
import { connect } from 'react-redux';
import DropdownMenu from 'flavours/glitch/components/dropdown_menu';
-import { isUserTouching } from 'flavours/glitch/util/is_mobile';
+import { isUserTouching } from '../is_mobile';
const mapStateToProps = state => ({
dropdownPlacement: state.getIn(['dropdown_menu', 'placement']),
diff --git a/app/javascript/flavours/glitch/containers/mastodon.js b/app/javascript/flavours/glitch/containers/mastodon.js
index a6ec5845da..bc03112936 100644
--- a/app/javascript/flavours/glitch/containers/mastodon.js
+++ b/app/javascript/flavours/glitch/containers/mastodon.js
@@ -11,7 +11,7 @@ import { connectUserStream } from 'flavours/glitch/actions/streaming';
import { checkDeprecatedLocalSettings } from 'flavours/glitch/actions/local_settings';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from 'locales';
-import initialState from 'flavours/glitch/util/initial_state';
+import initialState from 'flavours/glitch/initial_state';
import ErrorBoundary from 'flavours/glitch/components/error_boundary';
const { localeData, messages } = getLocale();
diff --git a/app/javascript/flavours/glitch/containers/media_container.js b/app/javascript/flavours/glitch/containers/media_container.js
index 11c15d7c6f..f1e8534aad 100644
--- a/app/javascript/flavours/glitch/containers/media_container.js
+++ b/app/javascript/flavours/glitch/containers/media_container.js
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
import { IntlProvider, addLocaleData } from 'react-intl';
import { fromJS } from 'immutable';
import { getLocale } from 'mastodon/locales';
-import { getScrollbarWidth } from 'flavours/glitch/util/scrollbar';
+import { getScrollbarWidth } from 'flavours/glitch/utils/scrollbar';
import MediaGallery from 'flavours/glitch/components/media_gallery';
import Poll from 'flavours/glitch/components/poll';
import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag';
diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js
index a1b4c57c6e..c12b2e6143 100644
--- a/app/javascript/flavours/glitch/containers/status_container.js
+++ b/app/javascript/flavours/glitch/containers/status_container.js
@@ -36,8 +36,8 @@ import { openModal } from 'flavours/glitch/actions/modal';
import { deployPictureInPicture } from 'flavours/glitch/actions/picture_in_picture';
import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import { boostModal, favouriteModal, deleteModal } from 'flavours/glitch/util/initial_state';
-import { filterEditLink } from 'flavours/glitch/util/backend_links';
+import { boostModal, favouriteModal, deleteModal } from 'flavours/glitch/initial_state';
+import { filterEditLink } from 'flavours/glitch/utils/backend_links';
import { showAlertForError } from '../actions/alerts';
import AccountContainer from 'flavours/glitch/containers/account_container';
import Spoilers from '../components/spoilers';
diff --git a/app/javascript/flavours/glitch/containers/timeline_container.js b/app/javascript/flavours/glitch/containers/timeline_container.js
index b61dc8dd7d..838bcd390d 100644
--- a/app/javascript/flavours/glitch/containers/timeline_container.js
+++ b/app/javascript/flavours/glitch/containers/timeline_container.js
@@ -9,7 +9,7 @@ import { getLocale } from 'mastodon/locales';
import PublicTimeline from 'flavours/glitch/features/standalone/public_timeline';
import HashtagTimeline from 'flavours/glitch/features/standalone/hashtag_timeline';
import ModalContainer from 'flavours/glitch/features/ui/containers/modal_container';
-import initialState from 'flavours/glitch/util/initial_state';
+import initialState from 'flavours/glitch/initial_state';
const { localeData, messages } = getLocale();
addLocaleData(localeData);
diff --git a/app/javascript/flavours/glitch/util/extra_polyfills.js b/app/javascript/flavours/glitch/extra_polyfills.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/extra_polyfills.js
rename to app/javascript/flavours/glitch/extra_polyfills.js
diff --git a/app/javascript/flavours/glitch/features/account/components/action_bar.js b/app/javascript/flavours/glitch/features/account/components/action_bar.js
index 23120d57ea..ce05841241 100644
--- a/app/javascript/flavours/glitch/features/account/components/action_bar.js
+++ b/app/javascript/flavours/glitch/features/account/components/action_bar.js
@@ -4,8 +4,8 @@ import PropTypes from 'prop-types';
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
import { NavLink } from 'react-router-dom';
import { injectIntl, FormattedMessage, FormattedNumber } from 'react-intl';
-import { me, isStaff } from 'flavours/glitch/util/initial_state';
-import { profileLink, accountAdminLink } from 'flavours/glitch/util/backend_links';
+import { me, isStaff } from 'flavours/glitch/initial_state';
+import { profileLink, accountAdminLink } from 'flavours/glitch/utils/backend_links';
import Icon from 'flavours/glitch/components/icon';
export default @injectIntl
diff --git a/app/javascript/flavours/glitch/features/account/components/header.js b/app/javascript/flavours/glitch/features/account/components/header.js
index fc80446b11..0f0e40268f 100644
--- a/app/javascript/flavours/glitch/features/account/components/header.js
+++ b/app/javascript/flavours/glitch/features/account/components/header.js
@@ -3,8 +3,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { autoPlayGif, me, title, domain } from 'flavours/glitch/util/initial_state';
-import { preferencesLink, profileLink, accountAdminLink } from 'flavours/glitch/util/backend_links';
+import { autoPlayGif, me, title, domain } from 'flavours/glitch/initial_state';
+import { preferencesLink, profileLink, accountAdminLink } from 'flavours/glitch/utils/backend_links';
import classNames from 'classnames';
import Icon from 'flavours/glitch/components/icon';
import IconButton from 'flavours/glitch/components/icon_button';
diff --git a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
index 7457980d2a..a16ee48062 100644
--- a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
+++ b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
@@ -1,8 +1,8 @@
import Blurhash from 'flavours/glitch/components/blurhash';
import classNames from 'classnames';
import Icon from 'flavours/glitch/components/icon';
-import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state';
-import { isIOS } from 'flavours/glitch/util/is_mobile';
+import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
+import { isIOS } from 'flavours/glitch/is_mobile';
import PropTypes from 'prop-types';
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
diff --git a/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
index 659dbc3fa2..c1577e1700 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
@@ -21,7 +21,7 @@ import { openModal } from 'flavours/glitch/actions/modal';
import { blockDomain, unblockDomain } from 'flavours/glitch/actions/domain_blocks';
import { initEditAccountNote } from 'flavours/glitch/actions/account_notes';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import { unfollowModal } from 'flavours/glitch/util/initial_state';
+import { unfollowModal } from 'flavours/glitch/initial_state';
const messages = defineMessages({
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
diff --git a/app/javascript/flavours/glitch/features/audio/index.js b/app/javascript/flavours/glitch/features/audio/index.js
index 8fa64342e6..014a0a213d 100644
--- a/app/javascript/flavours/glitch/features/audio/index.js
+++ b/app/javascript/flavours/glitch/features/audio/index.js
@@ -8,7 +8,7 @@ import { throttle } from 'lodash';
import { getPointerPosition, fileNameFromURL } from 'flavours/glitch/features/video';
import { debounce } from 'lodash';
import Visualizer from './visualizer';
-import { displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state';
+import { displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
import Blurhash from 'flavours/glitch/components/blurhash';
import { is } from 'immutable';
diff --git a/app/javascript/flavours/glitch/features/community_timeline/index.js b/app/javascript/flavours/glitch/features/community_timeline/index.js
index b921e22e99..5ee46ca3bb 100644
--- a/app/javascript/flavours/glitch/features/community_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/community_timeline/index.js
@@ -10,7 +10,7 @@ import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/col
import ColumnSettingsContainer from './containers/column_settings_container';
import { connectCommunityStream } from 'flavours/glitch/actions/streaming';
import { Helmet } from 'react-helmet';
-import { title } from 'flavours/glitch/util/initial_state';
+import { title } from 'flavours/glitch/initial_state';
const messages = defineMessages({
title: { id: 'column.community', defaultMessage: 'Local timeline' },
diff --git a/app/javascript/flavours/glitch/features/compose/components/compose_form.js b/app/javascript/flavours/glitch/features/compose/components/compose_form.js
index b03bc34b84..0be14e495b 100644
--- a/app/javascript/flavours/glitch/features/compose/components/compose_form.js
+++ b/app/javascript/flavours/glitch/features/compose/components/compose_form.js
@@ -5,17 +5,17 @@ import ReplyIndicatorContainer from '../containers/reply_indicator_container';
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
import AutosuggestInput from '../../../components/autosuggest_input';
import { defineMessages, injectIntl } from 'react-intl';
-import EmojiPicker from 'flavours/glitch/features/emoji_picker';
+import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container';
import PollFormContainer from '../containers/poll_form_container';
import UploadFormContainer from '../containers/upload_form_container';
import WarningContainer from '../containers/warning_container';
-import { isMobile } from 'flavours/glitch/util/is_mobile';
+import { isMobile } from 'flavours/glitch/is_mobile';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { countableText } from 'flavours/glitch/util/counter';
+import { countableText } from '../util/counter';
import OptionsContainer from '../containers/options_container';
import Publisher from './publisher';
import TextareaIcons from './textarea_icons';
-import { maxChars } from 'flavours/glitch/util/initial_state';
+import { maxChars } from 'flavours/glitch/initial_state';
import CharacterCounter from './character_counter';
import { length } from 'stringz';
@@ -143,7 +143,7 @@ class ComposeForm extends ImmutablePureComponent {
};
// Inserts an emoji at the caret.
- handleEmoji = (data) => {
+ handleEmojiPick = (data) => {
const { textarea: { selectionStart } } = this;
const { onPickEmoji } = this.props;
if (onPickEmoji) {
@@ -275,7 +275,7 @@ class ComposeForm extends ImmutablePureComponent {
render () {
const {
- handleEmoji,
+ handleEmojiPick,
handleSecondarySubmit,
handleSelect,
handleSubmit,
@@ -344,7 +344,7 @@ class ComposeForm extends ImmutablePureComponent {
onPaste={onPaste}
autoFocus={!showSearch && !isMobile(window.innerWidth, layout)}
>
-
+
diff --git a/app/javascript/flavours/glitch/features/compose/components/dropdown.js b/app/javascript/flavours/glitch/features/compose/components/dropdown.js
index 9f70d6b794..829f6d00f2 100644
--- a/app/javascript/flavours/glitch/features/compose/components/dropdown.js
+++ b/app/javascript/flavours/glitch/features/compose/components/dropdown.js
@@ -9,8 +9,8 @@ import IconButton from 'flavours/glitch/components/icon_button';
import DropdownMenu from './dropdown_menu';
// Utils.
-import { isUserTouching } from 'flavours/glitch/util/is_mobile';
-import { assignHandlers } from 'flavours/glitch/util/react_helpers';
+import { isUserTouching } from 'flavours/glitch/is_mobile';
+import { assignHandlers } from 'flavours/glitch/utils/react_helpers';
// The component.
export default class ComposerOptionsDropdown extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js b/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js
index 0649fe1caa..21835e628a 100644
--- a/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js
+++ b/app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js
@@ -9,9 +9,9 @@ import classNames from 'classnames';
import Icon from 'flavours/glitch/components/icon';
// Utils.
-import { withPassive } from 'flavours/glitch/util/dom_helpers';
-import Motion from 'flavours/glitch/util/optional_motion';
-import { assignHandlers } from 'flavours/glitch/util/react_helpers';
+import { withPassive } from 'flavours/glitch/utils/dom_helpers';
+import Motion from '../../ui/util/optional_motion';
+import { assignHandlers } from 'flavours/glitch/utils/react_helpers';
// The spring to use with our motion.
const springMotion = spring(1, {
diff --git a/app/javascript/flavours/glitch/features/emoji_picker/index.js b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js
similarity index 84%
rename from app/javascript/flavours/glitch/features/emoji_picker/index.js
rename to app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js
index 5de9fe107f..0e49a35c3e 100644
--- a/app/javascript/flavours/glitch/features/emoji_picker/index.js
+++ b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js
@@ -1,19 +1,14 @@
-import { connect } from 'react-redux';
-import { changeSetting } from 'flavours/glitch/actions/settings';
-import { createSelector } from 'reselect';
-import { Map as ImmutableMap } from 'immutable';
-import { useEmoji } from 'flavours/glitch/actions/emojis';
import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import { EmojiPicker as EmojiPickerAsync } from 'flavours/glitch/util/async-components';
+import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components';
import Overlay from 'react-overlays/lib/Overlay';
import classNames from 'classnames';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { supportsPassiveEvents } from 'detect-passive-events';
-import { buildCustomEmojis, categoriesFromEmojis } from 'flavours/glitch/util/emoji';
-import { useSystemEmojiFont } from 'flavours/glitch/util/initial_state';
-import { assetHost } from 'flavours/glitch/util/config';
+import { buildCustomEmojis, categoriesFromEmojis } from '../../emoji/emoji';
+import { useSystemEmojiFont } from 'flavours/glitch/initial_state';
+import { assetHost } from 'flavours/glitch/utils/config';
const messages = defineMessages({
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
@@ -31,80 +26,6 @@ const messages = defineMessages({
flags: { id: 'emoji_button.flags', defaultMessage: 'Flags' },
});
-const perLine = 8;
-const lines = 2;
-
-const DEFAULTS = [
- '+1',
- 'grinning',
- 'kissing_heart',
- 'heart_eyes',
- 'laughing',
- 'stuck_out_tongue_winking_eye',
- 'sweat_smile',
- 'joy',
- 'yum',
- 'disappointed',
- 'thinking_face',
- 'weary',
- 'sob',
- 'sunglasses',
- 'heart',
- 'ok_hand',
-];
-
-const getFrequentlyUsedEmojis = createSelector([
- state => state.getIn(['settings', 'frequentlyUsedEmojis'], ImmutableMap()),
-], emojiCounters => {
- let emojis = emojiCounters
- .keySeq()
- .sort((a, b) => emojiCounters.get(a) - emojiCounters.get(b))
- .reverse()
- .slice(0, perLine * lines)
- .toArray();
-
- if (emojis.length < DEFAULTS.length) {
- emojis = emojis.concat(DEFAULTS.slice(0, DEFAULTS.length - emojis.length));
- }
-
- return emojis;
-});
-
-const getCustomEmojis = createSelector([
- state => state.get('custom_emojis'),
-], emojis => emojis.filter(e => e.get('visible_in_picker')).sort((a, b) => {
- const aShort = a.get('shortcode').toLowerCase();
- const bShort = b.get('shortcode').toLowerCase();
-
- if (aShort < bShort) {
- return -1;
- } else if (aShort > bShort ) {
- return 1;
- } else {
- return 0;
- }
-}));
-
-const mapStateToProps = state => ({
- custom_emojis: getCustomEmojis(state),
- skinTone: state.getIn(['settings', 'skinTone']),
- frequentlyUsedEmojis: getFrequentlyUsedEmojis(state),
-});
-
-const mapDispatchToProps = (dispatch, { onPickEmoji }) => ({
- onSkinTone: skinTone => {
- dispatch(changeSetting(['skinTone'], skinTone));
- },
-
- onPickEmoji: emoji => {
- dispatch(useEmoji(emoji));
-
- if (onPickEmoji) {
- onPickEmoji(emoji);
- }
- },
-});
-
let EmojiPicker, Emoji; // load asynchronously
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
@@ -389,8 +310,7 @@ class EmojiPickerMenu extends React.PureComponent {
}
-export default @connect(mapStateToProps, mapDispatchToProps)
-@injectIntl
+export default @injectIntl
class EmojiPickerDropdown extends React.PureComponent {
static propTypes = {
diff --git a/app/javascript/flavours/glitch/features/compose/components/header.js b/app/javascript/flavours/glitch/features/compose/components/header.js
index 95add2027d..7ecb573aba 100644
--- a/app/javascript/flavours/glitch/features/compose/components/header.js
+++ b/app/javascript/flavours/glitch/features/compose/components/header.js
@@ -10,8 +10,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import Icon from 'flavours/glitch/components/icon';
// Utils.
-import { conditionalRender } from 'flavours/glitch/util/react_helpers';
-import { signOutLink } from 'flavours/glitch/util/backend_links';
+import { conditionalRender } from 'flavours/glitch/utils/react_helpers';
+import { signOutLink } from 'flavours/glitch/utils/backend_links';
// Messages.
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js b/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js
index 035b0c0c3e..31f1d4e730 100644
--- a/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js
+++ b/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js
@@ -3,12 +3,12 @@ import PropTypes from 'prop-types';
import { injectIntl, defineMessages } from 'react-intl';
import TextIconButton from './text_icon_button';
import Overlay from 'react-overlays/lib/Overlay';
-import Motion from 'flavours/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/features/ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import { supportsPassiveEvents } from 'detect-passive-events';
import classNames from 'classnames';
-import { languages as preloadedLanguages } from 'flavours/glitch/util/initial_state';
-import { loupeIcon, deleteIcon } from 'flavours/glitch/util/icons';
+import { languages as preloadedLanguages } from 'flavours/glitch/initial_state';
+import { loupeIcon, deleteIcon } from 'flavours/glitch/utils/icons';
import fuzzysort from 'fuzzysort';
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/features/compose/components/navigation_bar.js b/app/javascript/flavours/glitch/features/compose/components/navigation_bar.js
index 595ca55122..ba73ed553a 100644
--- a/app/javascript/flavours/glitch/features/compose/components/navigation_bar.js
+++ b/app/javascript/flavours/glitch/features/compose/components/navigation_bar.js
@@ -4,7 +4,7 @@ import Avatar from 'flavours/glitch/components/avatar';
import Permalink from 'flavours/glitch/components/permalink';
import { FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { profileLink } from 'flavours/glitch/util/backend_links';
+import { profileLink } from 'flavours/glitch/utils/backend_links';
export default class NavigationBar extends ImmutablePureComponent {
diff --git a/app/javascript/flavours/glitch/features/compose/components/options.js b/app/javascript/flavours/glitch/features/compose/components/options.js
index f005dbdd18..32a464011f 100644
--- a/app/javascript/flavours/glitch/features/compose/components/options.js
+++ b/app/javascript/flavours/glitch/features/compose/components/options.js
@@ -16,8 +16,8 @@ import LanguageDropdown from '../containers/language_dropdown_container';
import ImmutablePureComponent from 'react-immutable-pure-component';
// Utils.
-import Motion from 'flavours/glitch/util/optional_motion';
-import { pollLimits } from 'flavours/glitch/util/initial_state';
+import Motion from '../../ui/util/optional_motion';
+import { pollLimits } from 'flavours/glitch/initial_state';
// Messages.
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/features/compose/components/poll_form.js b/app/javascript/flavours/glitch/features/compose/components/poll_form.js
index e4b5104f35..d5edccff33 100644
--- a/app/javascript/flavours/glitch/features/compose/components/poll_form.js
+++ b/app/javascript/flavours/glitch/features/compose/components/poll_form.js
@@ -7,7 +7,7 @@ import IconButton from 'flavours/glitch/components/icon_button';
import Icon from 'flavours/glitch/components/icon';
import AutosuggestInput from 'flavours/glitch/components/autosuggest_input';
import classNames from 'classnames';
-import { pollLimits } from 'flavours/glitch/util/initial_state';
+import { pollLimits } from 'flavours/glitch/initial_state';
const messages = defineMessages({
option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Choice {number}' },
diff --git a/app/javascript/flavours/glitch/features/compose/components/publisher.js b/app/javascript/flavours/glitch/features/compose/components/publisher.js
index e2498bcad5..50baad0658 100644
--- a/app/javascript/flavours/glitch/features/compose/components/publisher.js
+++ b/app/javascript/flavours/glitch/features/compose/components/publisher.js
@@ -11,7 +11,7 @@ import Button from 'flavours/glitch/components/button';
import Icon from 'flavours/glitch/components/icon';
// Utils.
-import { maxChars } from 'flavours/glitch/util/initial_state';
+import { maxChars } from 'flavours/glitch/initial_state';
// Messages.
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/features/compose/components/search.js b/app/javascript/flavours/glitch/features/compose/components/search.js
index 12d8396378..a59418e46c 100644
--- a/app/javascript/flavours/glitch/features/compose/components/search.js
+++ b/app/javascript/flavours/glitch/features/compose/components/search.js
@@ -15,9 +15,9 @@ import Overlay from 'react-overlays/lib/Overlay';
import Icon from 'flavours/glitch/components/icon';
// Utils.
-import { focusRoot } from 'flavours/glitch/util/dom_helpers';
-import { searchEnabled } from 'flavours/glitch/util/initial_state';
-import Motion from 'flavours/glitch/util/optional_motion';
+import { focusRoot } from 'flavours/glitch/utils/dom_helpers';
+import { searchEnabled } from 'flavours/glitch/initial_state';
+import Motion from '../../ui/util/optional_motion';
const messages = defineMessages({
placeholder: { id: 'search.placeholder', defaultMessage: 'Search' },
diff --git a/app/javascript/flavours/glitch/features/compose/components/search_results.js b/app/javascript/flavours/glitch/features/compose/components/search_results.js
index e82ee2ca2c..c2178702cb 100644
--- a/app/javascript/flavours/glitch/features/compose/components/search_results.js
+++ b/app/javascript/flavours/glitch/features/compose/components/search_results.js
@@ -7,7 +7,7 @@ import StatusContainer from 'flavours/glitch/containers/status_container';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag';
import Icon from 'flavours/glitch/components/icon';
-import { searchEnabled } from 'flavours/glitch/util/initial_state';
+import { searchEnabled } from 'flavours/glitch/initial_state';
import LoadMore from 'flavours/glitch/components/load_more';
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/features/compose/components/upload.js b/app/javascript/flavours/glitch/features/compose/components/upload.js
index 963b95c87b..ade6f0437a 100644
--- a/app/javascript/flavours/glitch/features/compose/components/upload.js
+++ b/app/javascript/flavours/glitch/features/compose/components/upload.js
@@ -1,12 +1,12 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import Motion from 'flavours/glitch/util/optional_motion';
+import Motion from '../../ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { FormattedMessage } from 'react-intl';
import Icon from 'flavours/glitch/components/icon';
-import { isUserTouching } from 'flavours/glitch/util/is_mobile';
+import { isUserTouching } from 'flavours/glitch/is_mobile';
export default class Upload extends ImmutablePureComponent {
diff --git a/app/javascript/flavours/glitch/features/compose/components/upload_progress.js b/app/javascript/flavours/glitch/features/compose/components/upload_progress.js
index 493bb9ca53..8896bbffd6 100644
--- a/app/javascript/flavours/glitch/features/compose/components/upload_progress.js
+++ b/app/javascript/flavours/glitch/features/compose/components/upload_progress.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import Motion from 'flavours/glitch/util/optional_motion';
+import Motion from '../../ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import Icon from 'flavours/glitch/components/icon';
diff --git a/app/javascript/flavours/glitch/features/compose/components/warning.js b/app/javascript/flavours/glitch/features/compose/components/warning.js
index 6ee3640bc5..4009be8c6b 100644
--- a/app/javascript/flavours/glitch/features/compose/components/warning.js
+++ b/app/javascript/flavours/glitch/features/compose/components/warning.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import Motion from 'flavours/glitch/util/optional_motion';
+import Motion from '../../ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
export default class Warning extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js b/app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js
index a037bbbcc9..d12c98c01d 100644
--- a/app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js
@@ -18,7 +18,7 @@ import {
} from 'flavours/glitch/actions/modal';
import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
-import { privacyPreference } from 'flavours/glitch/util/privacy_preference';
+import { privacyPreference } from 'flavours/glitch/utils/privacy_preference';
const messages = defineMessages({
missingDescriptionMessage: { id: 'confirmations.missing_media_description.message',
diff --git a/app/javascript/flavours/glitch/features/compose/containers/emoji_picker_dropdown_container.js b/app/javascript/flavours/glitch/features/compose/containers/emoji_picker_dropdown_container.js
new file mode 100644
index 0000000000..ba85edd873
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/compose/containers/emoji_picker_dropdown_container.js
@@ -0,0 +1,82 @@
+import { connect } from 'react-redux';
+import EmojiPickerDropdown from '../components/emoji_picker_dropdown';
+import { changeSetting } from 'flavours/glitch/actions/settings';
+import { createSelector } from 'reselect';
+import { Map as ImmutableMap } from 'immutable';
+import { useEmoji } from 'flavours/glitch/actions/emojis';
+
+const perLine = 8;
+const lines = 2;
+
+const DEFAULTS = [
+ '+1',
+ 'grinning',
+ 'kissing_heart',
+ 'heart_eyes',
+ 'laughing',
+ 'stuck_out_tongue_winking_eye',
+ 'sweat_smile',
+ 'joy',
+ 'yum',
+ 'disappointed',
+ 'thinking_face',
+ 'weary',
+ 'sob',
+ 'sunglasses',
+ 'heart',
+ 'ok_hand',
+];
+
+const getFrequentlyUsedEmojis = createSelector([
+ state => state.getIn(['settings', 'frequentlyUsedEmojis'], ImmutableMap()),
+], emojiCounters => {
+ let emojis = emojiCounters
+ .keySeq()
+ .sort((a, b) => emojiCounters.get(a) - emojiCounters.get(b))
+ .reverse()
+ .slice(0, perLine * lines)
+ .toArray();
+
+ if (emojis.length < DEFAULTS.length) {
+ emojis = emojis.concat(DEFAULTS.slice(0, DEFAULTS.length - emojis.length));
+ }
+
+ return emojis;
+});
+
+const getCustomEmojis = createSelector([
+ state => state.get('custom_emojis'),
+], emojis => emojis.filter(e => e.get('visible_in_picker')).sort((a, b) => {
+ const aShort = a.get('shortcode').toLowerCase();
+ const bShort = b.get('shortcode').toLowerCase();
+
+ if (aShort < bShort) {
+ return -1;
+ } else if (aShort > bShort ) {
+ return 1;
+ } else {
+ return 0;
+ }
+}));
+
+const mapStateToProps = state => ({
+ custom_emojis: getCustomEmojis(state),
+ skinTone: state.getIn(['settings', 'skinTone']),
+ frequentlyUsedEmojis: getFrequentlyUsedEmojis(state),
+});
+
+const mapDispatchToProps = (dispatch, { onPickEmoji }) => ({
+ onSkinTone: skinTone => {
+ dispatch(changeSetting(['skinTone'], skinTone));
+ },
+
+ onPickEmoji: emoji => {
+ dispatch(useEmoji(emoji));
+
+ if (onPickEmoji) {
+ onPickEmoji(emoji);
+ }
+ },
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(EmojiPickerDropdown);
diff --git a/app/javascript/flavours/glitch/features/compose/containers/header_container.js b/app/javascript/flavours/glitch/features/compose/containers/header_container.js
index 2f0da48c86..e1ce19fb08 100644
--- a/app/javascript/flavours/glitch/features/compose/containers/header_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/header_container.js
@@ -2,7 +2,7 @@ import { openModal } from 'flavours/glitch/actions/modal';
import { connect } from 'react-redux';
import { defineMessages, injectIntl } from 'react-intl';
import Header from '../components/header';
-import { logOut } from 'flavours/glitch/util/log_out';
+import { logOut } from 'flavours/glitch/utils/log_out';
const messages = defineMessages({
logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' },
diff --git a/app/javascript/flavours/glitch/features/compose/containers/navigation_container.js b/app/javascript/flavours/glitch/features/compose/containers/navigation_container.js
index eb630ffbb5..0e14002616 100644
--- a/app/javascript/flavours/glitch/features/compose/containers/navigation_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/navigation_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import NavigationBar from '../components/navigation_bar';
-import { me } from 'flavours/glitch/util/initial_state';
+import { me } from 'flavours/glitch/initial_state';
const mapStateToProps = state => {
return {
diff --git a/app/javascript/flavours/glitch/features/compose/containers/warning_container.js b/app/javascript/flavours/glitch/features/compose/containers/warning_container.js
index 5fccaa4425..b2ed40b82f 100644
--- a/app/javascript/flavours/glitch/features/compose/containers/warning_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/warning_container.js
@@ -3,8 +3,8 @@ import { connect } from 'react-redux';
import Warning from '../components/warning';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
-import { me } from 'flavours/glitch/util/initial_state';
-import { profileLink, termsLink } from 'flavours/glitch/util/backend_links';
+import { me } from 'flavours/glitch/initial_state';
+import { profileLink, termsLink } from 'flavours/glitch/utils/backend_links';
const buildHashtagRE = () => {
try {
diff --git a/app/javascript/flavours/glitch/features/compose/index.js b/app/javascript/flavours/glitch/features/compose/index.js
index b9a8e02451..567bb3711a 100644
--- a/app/javascript/flavours/glitch/features/compose/index.js
+++ b/app/javascript/flavours/glitch/features/compose/index.js
@@ -8,10 +8,10 @@ import { mountCompose, unmountCompose } from 'flavours/glitch/actions/compose';
import { injectIntl, defineMessages } from 'react-intl';
import classNames from 'classnames';
import SearchContainer from './containers/search_container';
-import Motion from 'flavours/glitch/util/optional_motion';
+import Motion from '../ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import SearchResultsContainer from './containers/search_results_container';
-import { me, mascot } from 'flavours/glitch/util/initial_state';
+import { me, mascot } from 'flavours/glitch/initial_state';
import { cycleElefriendCompose } from 'flavours/glitch/actions/compose';
import HeaderContainer from './containers/header_container';
diff --git a/app/javascript/flavours/glitch/util/counter.js b/app/javascript/flavours/glitch/features/compose/util/counter.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/counter.js
rename to app/javascript/flavours/glitch/features/compose/util/counter.js
diff --git a/app/javascript/flavours/glitch/util/url_regex.js b/app/javascript/flavours/glitch/features/compose/util/url_regex.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/url_regex.js
rename to app/javascript/flavours/glitch/features/compose/util/url_regex.js
diff --git a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js
index 7107c9db3b..00d9fdcd05 100644
--- a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js
+++ b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js
@@ -11,7 +11,7 @@ import Permalink from 'flavours/glitch/components/permalink';
import IconButton from 'flavours/glitch/components/icon_button';
import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
import { HotKeys } from 'react-hotkeys';
-import { autoPlayGif } from 'flavours/glitch/util/initial_state';
+import { autoPlayGif } from 'flavours/glitch/initial_state';
import classNames from 'classnames';
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/features/directory/components/account_card.js b/app/javascript/flavours/glitch/features/directory/components/account_card.js
index 218208c101..b6785a5f95 100644
--- a/app/javascript/flavours/glitch/features/directory/components/account_card.js
+++ b/app/javascript/flavours/glitch/features/directory/components/account_card.js
@@ -10,7 +10,7 @@ import Permalink from 'flavours/glitch/components/permalink';
import IconButton from 'flavours/glitch/components/icon_button';
import Button from 'flavours/glitch/components/button';
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
-import { autoPlayGif, me, unfollowModal } from 'flavours/glitch/util/initial_state';
+import { autoPlayGif, me, unfollowModal } from 'flavours/glitch/initial_state';
import ShortNumber from 'flavours/glitch/components/short_number';
import {
followAccount,
diff --git a/app/javascript/flavours/glitch/features/directory/index.js b/app/javascript/flavours/glitch/features/directory/index.js
index 1aa8a330d3..dce8fa4e76 100644
--- a/app/javascript/flavours/glitch/features/directory/index.js
+++ b/app/javascript/flavours/glitch/features/directory/index.js
@@ -13,7 +13,7 @@ import RadioButton from 'flavours/glitch/components/radio_button';
import LoadMore from 'flavours/glitch/components/load_more';
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
-import { title } from 'flavours/glitch/util/initial_state';
+import { title } from 'flavours/glitch/initial_state';
import { Helmet } from 'react-helmet';
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/util/emoji/index.js b/app/javascript/flavours/glitch/features/emoji/emoji.js
similarity index 98%
rename from app/javascript/flavours/glitch/util/emoji/index.js
rename to app/javascript/flavours/glitch/features/emoji/emoji.js
index 162946bbb6..c4e2c26f28 100644
--- a/app/javascript/flavours/glitch/util/emoji/index.js
+++ b/app/javascript/flavours/glitch/features/emoji/emoji.js
@@ -1,6 +1,6 @@
-import { autoPlayGif, useSystemEmojiFont } from 'flavours/glitch/util/initial_state';
+import { autoPlayGif, useSystemEmojiFont } from 'flavours/glitch/initial_state';
import unicodeMapping from './emoji_unicode_mapping_light';
-import { assetHost } from 'flavours/glitch/util/config';
+import { assetHost } from 'flavours/glitch/utils/config';
import Trie from 'substring-trie';
const trie = new Trie(Object.keys(unicodeMapping));
diff --git a/app/javascript/flavours/glitch/util/emoji/emoji_compressed.js b/app/javascript/flavours/glitch/features/emoji/emoji_compressed.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/emoji/emoji_compressed.js
rename to app/javascript/flavours/glitch/features/emoji/emoji_compressed.js
diff --git a/app/javascript/flavours/glitch/util/emoji/emoji_map.json b/app/javascript/flavours/glitch/features/emoji/emoji_map.json
similarity index 100%
rename from app/javascript/flavours/glitch/util/emoji/emoji_map.json
rename to app/javascript/flavours/glitch/features/emoji/emoji_map.json
diff --git a/app/javascript/flavours/glitch/util/emoji/emoji_mart_data_light.js b/app/javascript/flavours/glitch/features/emoji/emoji_mart_data_light.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/emoji/emoji_mart_data_light.js
rename to app/javascript/flavours/glitch/features/emoji/emoji_mart_data_light.js
diff --git a/app/javascript/flavours/glitch/util/emoji/emoji_mart_search_light.js b/app/javascript/flavours/glitch/features/emoji/emoji_mart_search_light.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/emoji/emoji_mart_search_light.js
rename to app/javascript/flavours/glitch/features/emoji/emoji_mart_search_light.js
diff --git a/app/javascript/flavours/glitch/util/emoji/emoji_picker.js b/app/javascript/flavours/glitch/features/emoji/emoji_picker.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/emoji/emoji_picker.js
rename to app/javascript/flavours/glitch/features/emoji/emoji_picker.js
diff --git a/app/javascript/flavours/glitch/util/emoji/emoji_unicode_mapping_light.js b/app/javascript/flavours/glitch/features/emoji/emoji_unicode_mapping_light.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/emoji/emoji_unicode_mapping_light.js
rename to app/javascript/flavours/glitch/features/emoji/emoji_unicode_mapping_light.js
diff --git a/app/javascript/flavours/glitch/util/emoji/emoji_utils.js b/app/javascript/flavours/glitch/features/emoji/emoji_utils.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/emoji/emoji_utils.js
rename to app/javascript/flavours/glitch/features/emoji/emoji_utils.js
diff --git a/app/javascript/flavours/glitch/util/emoji/unicode_to_filename.js b/app/javascript/flavours/glitch/features/emoji/unicode_to_filename.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/emoji/unicode_to_filename.js
rename to app/javascript/flavours/glitch/features/emoji/unicode_to_filename.js
diff --git a/app/javascript/flavours/glitch/util/emoji/unicode_to_unified_name.js b/app/javascript/flavours/glitch/features/emoji/unicode_to_unified_name.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/emoji/unicode_to_unified_name.js
rename to app/javascript/flavours/glitch/features/emoji/unicode_to_unified_name.js
diff --git a/app/javascript/flavours/glitch/features/explore/index.js b/app/javascript/flavours/glitch/features/explore/index.js
index 388123c386..f377937328 100644
--- a/app/javascript/flavours/glitch/features/explore/index.js
+++ b/app/javascript/flavours/glitch/features/explore/index.js
@@ -11,9 +11,9 @@ import Statuses from './statuses';
import Suggestions from './suggestions';
import Search from 'flavours/glitch/features/compose/containers/search_container';
import SearchResults from './results';
-import { showTrends } from 'flavours/glitch/util/initial_state';
+import { showTrends } from 'flavours/glitch/initial_state';
import { Helmet } from 'react-helmet';
-import { title } from 'flavours/glitch/util/initial_state';
+import { title } from 'flavours/glitch/initial_state';
const messages = defineMessages({
title: { id: 'explore.title', defaultMessage: 'Explore' },
diff --git a/app/javascript/flavours/glitch/features/explore/results.js b/app/javascript/flavours/glitch/features/explore/results.js
index 3f43b9ee1f..e373796861 100644
--- a/app/javascript/flavours/glitch/features/explore/results.js
+++ b/app/javascript/flavours/glitch/features/explore/results.js
@@ -10,7 +10,7 @@ import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag'
import { List as ImmutableList } from 'immutable';
import LoadMore from 'flavours/glitch/components/load_more';
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
-import { title } from 'flavours/glitch/util/initial_state';
+import { title } from 'flavours/glitch/initial_state';
import { Helmet } from 'react-helmet';
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/features/filters/added_to_filter.js b/app/javascript/flavours/glitch/features/filters/added_to_filter.js
index f777ca429e..becb170cd2 100644
--- a/app/javascript/flavours/glitch/features/filters/added_to_filter.js
+++ b/app/javascript/flavours/glitch/features/filters/added_to_filter.js
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { FormattedMessage } from 'react-intl';
-import { toServerSideType } from 'flavours/glitch/util/filters';
+import { toServerSideType } from 'flavours/glitch/utils/filters';
import Button from 'flavours/glitch/components/button';
import { connect } from 'react-redux';
diff --git a/app/javascript/flavours/glitch/features/filters/select_filter.js b/app/javascript/flavours/glitch/features/filters/select_filter.js
index 5321dbb960..5391766c91 100644
--- a/app/javascript/flavours/glitch/features/filters/select_filter.js
+++ b/app/javascript/flavours/glitch/features/filters/select_filter.js
@@ -2,8 +2,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import { toServerSideType } from 'flavours/glitch/util/filters';
-import { loupeIcon, deleteIcon } from 'flavours/glitch/util/icons';
+import { toServerSideType } from 'flavours/glitch/utils/filters';
+import { loupeIcon, deleteIcon } from 'flavours/glitch/utils/icons';
import Icon from 'flavours/glitch/components/icon';
import fuzzysort from 'fuzzysort';
diff --git a/app/javascript/flavours/glitch/features/follow_requests/index.js b/app/javascript/flavours/glitch/features/follow_requests/index.js
index 36a57d1d68..47ca1e1bf7 100644
--- a/app/javascript/flavours/glitch/features/follow_requests/index.js
+++ b/app/javascript/flavours/glitch/features/follow_requests/index.js
@@ -11,7 +11,7 @@ import { fetchFollowRequests, expandFollowRequests } from 'flavours/glitch/actio
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ScrollableList from 'flavours/glitch/components/scrollable_list';
-import { me } from 'flavours/glitch/util/initial_state';
+import { me } from 'flavours/glitch/initial_state';
const messages = defineMessages({
heading: { id: 'column.follow_requests', defaultMessage: 'Follow requests' },
diff --git a/app/javascript/flavours/glitch/features/getting_started/components/announcements.js b/app/javascript/flavours/glitch/features/getting_started/components/announcements.js
index f7097e2ec1..93f3c9428f 100644
--- a/app/javascript/flavours/glitch/features/getting_started/components/announcements.js
+++ b/app/javascript/flavours/glitch/features/getting_started/components/announcements.js
@@ -6,16 +6,16 @@ import PropTypes from 'prop-types';
import IconButton from 'flavours/glitch/components/icon_button';
import Icon from 'flavours/glitch/components/icon';
import { defineMessages, injectIntl, FormattedMessage, FormattedDate } from 'react-intl';
-import { autoPlayGif, reduceMotion, disableSwiping } from 'flavours/glitch/util/initial_state';
+import { autoPlayGif, reduceMotion, disableSwiping } from 'flavours/glitch/initial_state';
import elephantUIPlane from 'mastodon/../images/elephant_ui_plane.svg';
-import { mascot } from 'flavours/glitch/util/initial_state';
-import unicodeMapping from 'flavours/glitch/util/emoji/emoji_unicode_mapping_light';
+import { mascot } from 'flavours/glitch/initial_state';
+import unicodeMapping from 'flavours/glitch/features/emoji/emoji_unicode_mapping_light';
import classNames from 'classnames';
-import EmojiPickerDropdown from 'flavours/glitch/features/emoji_picker';
+import EmojiPickerDropdown from 'flavours/glitch/features/compose/containers/emoji_picker_dropdown_container';
import AnimatedNumber from 'flavours/glitch/components/animated_number';
import TransitionMotion from 'react-motion/lib/TransitionMotion';
import spring from 'react-motion/lib/spring';
-import { assetHost } from 'flavours/glitch/util/config';
+import { assetHost } from 'flavours/glitch/utils/config';
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js
index 8b6a617ff4..f52b769a33 100644
--- a/app/javascript/flavours/glitch/features/getting_started/index.js
+++ b/app/javascript/flavours/glitch/features/getting_started/index.js
@@ -8,12 +8,12 @@ import { openModal } from 'flavours/glitch/actions/modal';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { me, showTrends } from 'flavours/glitch/util/initial_state';
+import { me, showTrends } from 'flavours/glitch/initial_state';
import { fetchFollowRequests } from 'flavours/glitch/actions/accounts';
import { List as ImmutableList } from 'immutable';
import { createSelector } from 'reselect';
import { fetchLists } from 'flavours/glitch/actions/lists';
-import { preferencesLink } from 'flavours/glitch/util/backend_links';
+import { preferencesLink } from 'flavours/glitch/utils/backend_links';
import NavigationBar from '../compose/components/navigation_bar';
import LinkFooter from 'flavours/glitch/features/ui/components/link_footer';
import TrendsContainer from './containers/trends_container';
diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/hashtag_timeline/containers/column_settings_container.js
index 1cf5275731..004856b048 100644
--- a/app/javascript/flavours/glitch/features/hashtag_timeline/containers/column_settings_container.js
+++ b/app/javascript/flavours/glitch/features/hashtag_timeline/containers/column_settings_container.js
@@ -1,7 +1,7 @@
import { connect } from 'react-redux';
import ColumnSettings from '../components/column_settings';
import { changeColumnParams } from 'flavours/glitch/actions/columns';
-import api from 'flavours/glitch/util/api';
+import api from 'flavours/glitch/api';
const mapStateToProps = (state, { columnId }) => {
const columns = state.getIn(['settings', 'columns']);
diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js
index 38dda85b2b..5e098514aa 100644
--- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js
@@ -14,7 +14,7 @@ import { isEqual } from 'lodash';
import { fetchHashtag, followHashtag, unfollowHashtag } from 'flavours/glitch/actions/tags';
import Icon from 'flavours/glitch/components/icon';
import classNames from 'classnames';
-import { title } from 'flavours/glitch/util/initial_state';
+import { title } from 'flavours/glitch/initial_state';
import { Helmet } from 'react-helmet';
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/features/home_timeline/index.js b/app/javascript/flavours/glitch/features/home_timeline/index.js
index 7ca28da35a..86aaa0258e 100644
--- a/app/javascript/flavours/glitch/features/home_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/home_timeline/index.js
@@ -15,7 +15,7 @@ import classNames from 'classnames';
import IconWithBadge from 'flavours/glitch/components/icon_with_badge';
import NotSignedInIndicator from 'flavours/glitch/components/not_signed_in_indicator';
import { Helmet } from 'react-helmet';
-import { title } from 'flavours/glitch/util/initial_state';
+import { title } from 'flavours/glitch/initial_state';
const messages = defineMessages({
title: { id: 'column.home', defaultMessage: 'Home' },
diff --git a/app/javascript/flavours/glitch/features/interaction_modal/index.js b/app/javascript/flavours/glitch/features/interaction_modal/index.js
index d2260c4f0d..5623f8a068 100644
--- a/app/javascript/flavours/glitch/features/interaction_modal/index.js
+++ b/app/javascript/flavours/glitch/features/interaction_modal/index.js
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
-import { registrationsOpen } from 'flavours/glitch/util/initial_state';
+import { registrationsOpen } from 'flavours/glitch/initial_state';
import { connect } from 'react-redux';
import Icon from 'flavours/glitch/components/icon';
import classNames from 'classnames';
diff --git a/app/javascript/flavours/glitch/features/list_editor/index.js b/app/javascript/flavours/glitch/features/list_editor/index.js
index 75b0de3d37..c2ca070532 100644
--- a/app/javascript/flavours/glitch/features/list_editor/index.js
+++ b/app/javascript/flavours/glitch/features/list_editor/index.js
@@ -8,7 +8,7 @@ import { setupListEditor, clearListSuggestions, resetListEditor } from 'flavours
import AccountContainer from './containers/account_container';
import SearchContainer from './containers/search_container';
import EditListForm from './components/edit_list_form';
-import Motion from 'flavours/glitch/util/optional_motion';
+import Motion from '../ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
const mapStateToProps = state => ({
diff --git a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js
index d085a606c3..e618a981e8 100644
--- a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js
@@ -5,7 +5,7 @@ import { injectIntl, defineMessages } from 'react-intl';
// Our imports
import LocalSettingsNavigationItem from './item';
-import { preferencesLink } from 'flavours/glitch/util/backend_links';
+import { preferencesLink } from 'flavours/glitch/utils/backend_links';
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js
index a21c90b4bd..e154fe1c81 100644
--- a/app/javascript/flavours/glitch/features/local_settings/page/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js
@@ -5,8 +5,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
// Our imports
-import { expandSpoilers, disableSwiping } from 'flavours/glitch/util/initial_state';
-import { preferenceLink } from 'flavours/glitch/util/backend_links';
+import { expandSpoilers, disableSwiping } from 'flavours/glitch/initial_state';
+import { preferenceLink } from 'flavours/glitch/utils/backend_links';
import LocalSettingsPageItem from './item';
import DeprecatedLocalSettingsPageItem from './deprecated_item';
diff --git a/app/javascript/flavours/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js
index 6cfafb61e3..26eeba1685 100644
--- a/app/javascript/flavours/glitch/features/notifications/index.js
+++ b/app/javascript/flavours/glitch/features/notifications/index.js
@@ -26,11 +26,11 @@ import { debounce } from 'lodash';
import ScrollableList from 'flavours/glitch/components/scrollable_list';
import LoadGap from 'flavours/glitch/components/load_gap';
import Icon from 'flavours/glitch/components/icon';
-import compareId from 'flavours/glitch/util/compare_id';
+import compareId from 'flavours/glitch/compare_id';
import NotificationsPermissionBanner from './components/notifications_permission_banner';
import NotSignedInIndicator from 'flavours/glitch/components/not_signed_in_indicator';
import { Helmet } from 'react-helmet';
-import { title } from 'flavours/glitch/util/initial_state';
+import { title } from 'flavours/glitch/initial_state';
import NotificationPurgeButtonsContainer from 'flavours/glitch/containers/notification_purge_buttons_container';
diff --git a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.js b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.js
index 2a5adf71d3..86e24e38f5 100644
--- a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.js
+++ b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.js
@@ -5,7 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import IconButton from 'flavours/glitch/components/icon_button';
import classNames from 'classnames';
-import { me, boostModal } from 'flavours/glitch/util/initial_state';
+import { me, boostModal } from 'flavours/glitch/initial_state';
import { defineMessages, injectIntl } from 'react-intl';
import { replyCompose } from 'flavours/glitch/actions/compose';
import { reblog, favourite, unreblog, unfavourite } from 'flavours/glitch/actions/interactions';
diff --git a/app/javascript/flavours/glitch/features/pinned_accounts_editor/index.js b/app/javascript/flavours/glitch/features/pinned_accounts_editor/index.js
index 5f03c7e93c..43ae0ec2fe 100644
--- a/app/javascript/flavours/glitch/features/pinned_accounts_editor/index.js
+++ b/app/javascript/flavours/glitch/features/pinned_accounts_editor/index.js
@@ -7,7 +7,7 @@ import { injectIntl, FormattedMessage } from 'react-intl';
import { fetchPinnedAccounts, clearPinnedAccountsSuggestions, resetPinnedAccountsEditor } from 'flavours/glitch/actions/accounts';
import AccountContainer from './containers/account_container';
import SearchContainer from './containers/search_container';
-import Motion from 'flavours/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/features/ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
const mapStateToProps = state => ({
diff --git a/app/javascript/flavours/glitch/features/public_timeline/index.js b/app/javascript/flavours/glitch/features/public_timeline/index.js
index 6e1fb8ced8..aa70acf158 100644
--- a/app/javascript/flavours/glitch/features/public_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/public_timeline/index.js
@@ -10,7 +10,7 @@ import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/col
import ColumnSettingsContainer from './containers/column_settings_container';
import { connectPublicStream } from 'flavours/glitch/actions/streaming';
import { Helmet } from 'react-helmet';
-import { title } from 'flavours/glitch/util/initial_state';
+import { title } from 'flavours/glitch/initial_state';
const messages = defineMessages({
title: { id: 'column.public', defaultMessage: 'Federated timeline' },
diff --git a/app/javascript/flavours/glitch/features/status/components/action_bar.js b/app/javascript/flavours/glitch/features/status/components/action_bar.js
index 75ad462f06..9868621fe5 100644
--- a/app/javascript/flavours/glitch/features/status/components/action_bar.js
+++ b/app/javascript/flavours/glitch/features/status/components/action_bar.js
@@ -4,8 +4,8 @@ import IconButton from 'flavours/glitch/components/icon_button';
import ImmutablePropTypes from 'react-immutable-proptypes';
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
import { defineMessages, injectIntl } from 'react-intl';
-import { me } from 'flavours/glitch/util/initial_state';
-import { accountAdminLink, statusAdminLink } from 'flavours/glitch/util/backend_links';
+import { me } from 'flavours/glitch/initial_state';
+import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links';
import classNames from 'classnames';
import { PERMISSION_MANAGE_USERS } from 'flavours/glitch/permissions';
diff --git a/app/javascript/flavours/glitch/features/status/components/card.js b/app/javascript/flavours/glitch/features/status/components/card.js
index 0ca2508e71..2d2e49eb8e 100644
--- a/app/javascript/flavours/glitch/features/status/components/card.js
+++ b/app/javascript/flavours/glitch/features/status/components/card.js
@@ -5,9 +5,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { FormattedMessage } from 'react-intl';
import punycode from 'punycode';
import classnames from 'classnames';
-import { decode as decodeIDNA } from 'flavours/glitch/util/idna';
+import { decode as decodeIDNA } from 'flavours/glitch/utils/idna';
import Icon from 'flavours/glitch/components/icon';
-import { useBlurhash } from 'flavours/glitch/util/initial_state';
+import { useBlurhash } from 'flavours/glitch/initial_state';
import Blurhash from 'flavours/glitch/components/blurhash';
import { debounce } from 'lodash';
diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js
index 91dc5ba208..46770930f5 100644
--- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js
+++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js
@@ -13,7 +13,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import Video from 'flavours/glitch/features/video';
import Audio from 'flavours/glitch/features/audio';
import VisibilityIcon from 'flavours/glitch/components/status_visibility_icon';
-import scheduleIdleTask from 'flavours/glitch/util/schedule_idle_task';
+import scheduleIdleTask from '../../ui/util/schedule_idle_task';
import classNames from 'classnames';
import PollContainer from 'flavours/glitch/containers/poll_container';
import Icon from 'flavours/glitch/components/icon';
diff --git a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js
index 40e186569e..e5e0659876 100644
--- a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js
+++ b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js
@@ -27,7 +27,7 @@ import { initReport } from 'flavours/glitch/actions/reports';
import { initBoostModal } from 'flavours/glitch/actions/boosts';
import { openModal } from 'flavours/glitch/actions/modal';
import { defineMessages, injectIntl } from 'react-intl';
-import { boostModal, deleteModal } from 'flavours/glitch/util/initial_state';
+import { boostModal, deleteModal } from 'flavours/glitch/initial_state';
import { showAlertForError } from 'flavours/glitch/actions/alerts';
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js
index 8e783af80f..c967ef34d2 100644
--- a/app/javascript/flavours/glitch/features/status/index.js
+++ b/app/javascript/flavours/glitch/features/status/index.js
@@ -47,9 +47,9 @@ import { openModal } from 'flavours/glitch/actions/modal';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { HotKeys } from 'react-hotkeys';
-import { boostModal, favouriteModal, deleteModal, title } from 'flavours/glitch/util/initial_state';
-import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'flavours/glitch/util/fullscreen';
-import { autoUnfoldCW } from 'flavours/glitch/util/content_warning';
+import { boostModal, favouriteModal, deleteModal, title } from 'flavours/glitch/initial_state';
+import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
+import { autoUnfoldCW } from 'flavours/glitch/utils/content_warning';
import { textForScreenReader, defaultMediaVisibility } from 'flavours/glitch/components/status';
import Icon from 'flavours/glitch/components/icon';
import { Helmet } from 'react-helmet';
diff --git a/app/javascript/flavours/glitch/features/subscribed_languages_modal/index.js b/app/javascript/flavours/glitch/features/subscribed_languages_modal/index.js
index 3047b434c8..fa69d82a4e 100644
--- a/app/javascript/flavours/glitch/features/subscribed_languages_modal/index.js
+++ b/app/javascript/flavours/glitch/features/subscribed_languages_modal/index.js
@@ -5,7 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { is, List as ImmutableList, Set as ImmutableSet } from 'immutable';
-import { languages as preloadedLanguages } from 'flavours/glitch/util/initial_state';
+import { languages as preloadedLanguages } from 'flavours/glitch/initial_state';
import Option from 'flavours/glitch/features/report/components/option';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import IconButton from 'flavours/glitch/components/icon_button';
diff --git a/app/javascript/flavours/glitch/features/ui/components/column.js b/app/javascript/flavours/glitch/features/ui/components/column.js
index 9163969315..e9c1e2f87e 100644
--- a/app/javascript/flavours/glitch/features/ui/components/column.js
+++ b/app/javascript/flavours/glitch/features/ui/components/column.js
@@ -2,8 +2,8 @@ import React from 'react';
import ColumnHeader from './column_header';
import PropTypes from 'prop-types';
import { debounce } from 'lodash';
-import { scrollTop } from 'flavours/glitch/util/scroll';
-import { isMobile } from 'flavours/glitch/util/is_mobile';
+import { scrollTop } from 'flavours/glitch/scroll';
+import { isMobile } from 'flavours/glitch/is_mobile';
export default class Column extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/features/ui/components/columns_area.js b/app/javascript/flavours/glitch/features/ui/components/columns_area.js
index 5f50181050..718b4a27f6 100644
--- a/app/javascript/flavours/glitch/features/ui/components/columns_area.js
+++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.js
@@ -8,7 +8,7 @@ import ReactSwipeableViews from 'react-swipeable-views';
import TabsBar, { links, getIndex, getLink } from './tabs_bar';
import { Link } from 'react-router-dom';
-import { disableSwiping } from 'flavours/glitch/util/initial_state';
+import { disableSwiping } from 'flavours/glitch/initial_state';
import BundleContainer from '../containers/bundle_container';
import ColumnLoading from './column_loading';
@@ -26,13 +26,13 @@ import {
BookmarkedStatuses,
ListTimeline,
Directory,
-} from 'flavours/glitch/util/async-components';
+} from '../../ui/util/async-components';
import Icon from 'flavours/glitch/components/icon';
import ComposePanel from './compose_panel';
import NavigationPanel from './navigation_panel';
import { supportsPassiveEvents } from 'detect-passive-events';
-import { scrollRight } from 'flavours/glitch/util/scroll';
+import { scrollRight } from 'flavours/glitch/scroll';
const componentMap = {
'COMPOSE': Compose,
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
index 8fd528da0c..baf7f25bec 100644
--- a/app/javascript/flavours/glitch/features/ui/components/compare_history_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/compare_history_modal.js
@@ -4,7 +4,7 @@ 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 emojify from 'flavours/glitch/features/emoji/emoji';
import escapeTextContentForBrowser from 'escape-html';
import InlineAccount from 'flavours/glitch/components/inline_account';
import IconButton from 'flavours/glitch/components/icon_button';
diff --git a/app/javascript/flavours/glitch/features/ui/components/deprecated_settings_modal.js b/app/javascript/flavours/glitch/features/ui/components/deprecated_settings_modal.js
index 9cb5a30b91..68f04cb21c 100644
--- a/app/javascript/flavours/glitch/features/ui/components/deprecated_settings_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/deprecated_settings_modal.js
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import { preferenceLink } from 'flavours/glitch/util/backend_links';
+import { preferenceLink } from 'flavours/glitch/utils/backend_links';
import Button from 'flavours/glitch/components/button';
import Icon from 'flavours/glitch/components/icon';
import illustration from 'flavours/glitch/images/logo_warn_glitch.svg';
diff --git a/app/javascript/flavours/glitch/features/ui/components/embed_modal.js b/app/javascript/flavours/glitch/features/ui/components/embed_modal.js
index b6f5e628d6..624b68f7ec 100644
--- a/app/javascript/flavours/glitch/features/ui/components/embed_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/embed_modal.js
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
-import api from 'flavours/glitch/util/api';
+import api from 'flavours/glitch/api';
import IconButton from 'flavours/glitch/components/icon_button';
const messages = defineMessages({
diff --git a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js
index 5a4baa5a14..de330b3a15 100644
--- a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js
@@ -15,14 +15,14 @@ import Textarea from 'react-textarea-autosize';
import UploadProgress from 'flavours/glitch/features/compose/components/upload_progress';
import CharacterCounter from 'flavours/glitch/features/compose/components/character_counter';
import { length } from 'stringz';
-import { Tesseract as fetchTesseract } from 'flavours/glitch/util/async-components';
+import { Tesseract as fetchTesseract } from 'flavours/glitch/features/ui/util/async-components';
import GIFV from 'flavours/glitch/components/gifv';
-import { me } from 'flavours/glitch/util/initial_state';
+import { me } from 'flavours/glitch/initial_state';
// eslint-disable-next-line import/no-extraneous-dependencies
import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js';
// eslint-disable-next-line import/extensions
import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js';
-import { assetHost } from 'flavours/glitch/util/config';
+import { assetHost } from 'flavours/glitch/utils/config';
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
diff --git a/app/javascript/flavours/glitch/features/ui/components/link_footer.js b/app/javascript/flavours/glitch/features/ui/components/link_footer.js
index 6f4a8c2dec..39576f17b4 100644
--- a/app/javascript/flavours/glitch/features/ui/components/link_footer.js
+++ b/app/javascript/flavours/glitch/features/ui/components/link_footer.js
@@ -3,9 +3,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import { Link } from 'react-router-dom';
-import { limitedFederationMode, version, repository, source_url, profile_directory as profileDirectory } from 'flavours/glitch/util/initial_state';
-import { signOutLink, securityLink, privacyPolicyLink } from 'flavours/glitch/util/backend_links';
-import { logOut } from 'flavours/glitch/util/log_out';
+import { limitedFederationMode, version, repository, source_url, profile_directory as profileDirectory } from 'flavours/glitch/initial_state';
+import { signOutLink, securityLink, privacyPolicyLink } from 'flavours/glitch/utils/backend_links';
+import { logOut } from 'flavours/glitch/utils/log_out';
import { openModal } from 'flavours/glitch/actions/modal';
import { PERMISSION_INVITE_USERS } from 'flavours/glitch/permissions';
diff --git a/app/javascript/flavours/glitch/features/ui/components/media_modal.js b/app/javascript/flavours/glitch/features/ui/components/media_modal.js
index baa5ff2756..ec3af857da 100644
--- a/app/javascript/flavours/glitch/features/ui/components/media_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/media_modal.js
@@ -12,7 +12,7 @@ import Icon from 'flavours/glitch/components/icon';
import GIFV from 'flavours/glitch/components/gifv';
import Footer from 'flavours/glitch/features/picture_in_picture/components/footer';
import { getAverageFromBlurhash } from 'flavours/glitch/blurhash';
-import { disableSwiping } from 'flavours/glitch/util/initial_state';
+import { disableSwiping } from 'flavours/glitch/initial_state';
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
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 92768caebd..cedfabe03d 100644
--- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js
+++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { getScrollbarWidth } from 'flavours/glitch/util/scrollbar';
+import { getScrollbarWidth } from 'flavours/glitch/utils/scrollbar';
import Base from 'flavours/glitch/components/modal_root';
import BundleContainer from '../containers/bundle_container';
import BundleModalError from './bundle_modal_error';
@@ -29,7 +29,7 @@ import {
PinnedAccountsEditor,
CompareHistoryModal,
FilterModal,
-} from 'flavours/glitch/util/async-components';
+} from 'flavours/glitch/features/ui/util/async-components';
const MODAL_COMPONENTS = {
'MEDIA': () => Promise.resolve({ default: MediaModal }),
diff --git a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js
index 4532767757..57fbfb285a 100644
--- a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js
+++ b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.js
@@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
import { NavLink, Link } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import Icon from 'flavours/glitch/components/icon';
-import { showTrends } from 'flavours/glitch/util/initial_state';
-import { preferencesLink, relationshipsLink } from 'flavours/glitch/util/backend_links';
+import { showTrends } from 'flavours/glitch/initial_state';
+import { preferencesLink, relationshipsLink } from 'flavours/glitch/utils/backend_links';
import NotificationsCounterIcon from './notifications_counter_icon';
import FollowRequestsNavLink from './follow_requests_nav_link';
import ListPanel from './list_panel';
diff --git a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
index e7be62ad89..97932ada18 100644
--- a/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
@@ -10,7 +10,7 @@ import ComposeForm from 'flavours/glitch/features/compose/components/compose_for
import DrawerAccount from 'flavours/glitch/features/compose/components/navigation_bar';
import Search from 'flavours/glitch/features/compose/components/search';
import ColumnHeader from './column_header';
-import { me, source_url } from 'flavours/glitch/util/initial_state';
+import { me, source_url } from 'flavours/glitch/initial_state';
const noop = () => { };
diff --git a/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js b/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js
index e08a1ea675..a935d7422e 100644
--- a/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js
+++ b/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js
@@ -1,6 +1,6 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
-import { registrationsOpen } from 'flavours/glitch/util/initial_state';
+import { registrationsOpen } from 'flavours/glitch/initial_state';
const SignInBanner = () => (
diff --git a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
index 0a7078a9c6..9c82fc91d3 100644
--- a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
+++ b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { NavLink, withRouter } from 'react-router-dom';
import { FormattedMessage, injectIntl } from 'react-intl';
import { debounce } from 'lodash';
-import { isUserTouching } from 'flavours/glitch/util/is_mobile';
+import { isUserTouching } from 'flavours/glitch/is_mobile';
import Icon from 'flavours/glitch/components/icon';
import NotificationsCounterIcon from './notifications_counter_icon';
diff --git a/app/javascript/flavours/glitch/features/ui/components/upload_area.js b/app/javascript/flavours/glitch/features/ui/components/upload_area.js
index 11a10baf1d..6958ba9df0 100644
--- a/app/javascript/flavours/glitch/features/ui/components/upload_area.js
+++ b/app/javascript/flavours/glitch/features/ui/components/upload_area.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import Motion from 'flavours/glitch/util/optional_motion';
+import Motion from '../../ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import { FormattedMessage } from 'react-intl';
diff --git a/app/javascript/flavours/glitch/features/ui/containers/status_list_container.js b/app/javascript/flavours/glitch/features/ui/containers/status_list_container.js
index 53c3b8f392..3cd0707f2d 100644
--- a/app/javascript/flavours/glitch/features/ui/containers/status_list_container.js
+++ b/app/javascript/flavours/glitch/features/ui/containers/status_list_container.js
@@ -4,7 +4,7 @@ import { scrollTopTimeline, loadPending } from 'flavours/glitch/actions/timeline
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import { createSelector } from 'reselect';
import { debounce } from 'lodash';
-import { me } from 'flavours/glitch/util/initial_state';
+import { me } from 'flavours/glitch/initial_state';
const getRegex = createSelector([
(state, { regex }) => regex,
diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js
index 735623e3dc..c8cc905e7b 100644
--- a/app/javascript/flavours/glitch/features/ui/index.js
+++ b/app/javascript/flavours/glitch/features/ui/index.js
@@ -5,7 +5,7 @@ import LoadingBarContainer from './containers/loading_bar_container';
import ModalContainer from './containers/modal_container';
import { connect } from 'react-redux';
import { Redirect, withRouter } from 'react-router-dom';
-import { layoutFromWindow } from 'flavours/glitch/util/is_mobile';
+import { layoutFromWindow } from 'flavours/glitch/is_mobile';
import { debounce } from 'lodash';
import { uploadCompose, resetCompose, changeComposeSpoilerness } from 'flavours/glitch/actions/compose';
import { expandHomeTimeline } from 'flavours/glitch/actions/timelines';
@@ -14,7 +14,7 @@ import { fetchServer } from 'flavours/glitch/actions/server';
import { clearHeight } from 'flavours/glitch/actions/height_cache';
import { changeLayout } from 'flavours/glitch/actions/app';
import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'flavours/glitch/actions/markers';
-import { WrappedSwitch, WrappedRoute } from 'flavours/glitch/util/react_router_helpers';
+import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers';
import UploadArea from './components/upload_area';
import PermaLink from 'flavours/glitch/components/permalink';
import ColumnsAreaContainer from './containers/columns_area_container';
@@ -52,9 +52,9 @@ import {
Directory,
Explore,
FollowRecommendations,
-} from 'flavours/glitch/util/async-components';
+} from './util/async-components';
import { HotKeys } from 'react-hotkeys';
-import { me, title } from 'flavours/glitch/util/initial_state';
+import { me, title } from 'flavours/glitch/initial_state';
import { closeOnboarding, INTRODUCTION_VERSION } from 'flavours/glitch/actions/onboarding';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import { Helmet } from 'react-helmet';
diff --git a/app/javascript/flavours/glitch/util/async-components.js b/app/javascript/flavours/glitch/features/ui/util/async-components.js
similarity index 99%
rename from app/javascript/flavours/glitch/util/async-components.js
rename to app/javascript/flavours/glitch/features/ui/util/async-components.js
index 1ecba2bcbb..eef3a941d2 100644
--- a/app/javascript/flavours/glitch/util/async-components.js
+++ b/app/javascript/flavours/glitch/features/ui/util/async-components.js
@@ -1,5 +1,5 @@
export function EmojiPicker () {
- return import(/* webpackChunkName: "flavours/glitch/async/emoji_picker" */'flavours/glitch/util/emoji/emoji_picker');
+ return import(/* webpackChunkName: "flavours/glitch/async/emoji_picker" */'flavours/glitch/features/emoji/emoji_picker');
}
export function Compose () {
diff --git a/app/javascript/flavours/glitch/util/fullscreen.js b/app/javascript/flavours/glitch/features/ui/util/fullscreen.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/fullscreen.js
rename to app/javascript/flavours/glitch/features/ui/util/fullscreen.js
diff --git a/app/javascript/flavours/glitch/util/get_rect_from_entry.js b/app/javascript/flavours/glitch/features/ui/util/get_rect_from_entry.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/get_rect_from_entry.js
rename to app/javascript/flavours/glitch/features/ui/util/get_rect_from_entry.js
diff --git a/app/javascript/flavours/glitch/util/intersection_observer_wrapper.js b/app/javascript/flavours/glitch/features/ui/util/intersection_observer_wrapper.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/intersection_observer_wrapper.js
rename to app/javascript/flavours/glitch/features/ui/util/intersection_observer_wrapper.js
diff --git a/app/javascript/flavours/glitch/util/optional_motion.js b/app/javascript/flavours/glitch/features/ui/util/optional_motion.js
similarity index 68%
rename from app/javascript/flavours/glitch/util/optional_motion.js
rename to app/javascript/flavours/glitch/features/ui/util/optional_motion.js
index eecb6634e9..a7fbe6310c 100644
--- a/app/javascript/flavours/glitch/util/optional_motion.js
+++ b/app/javascript/flavours/glitch/features/ui/util/optional_motion.js
@@ -1,4 +1,4 @@
-import { reduceMotion } from 'flavours/glitch/util/initial_state';
+import { reduceMotion } from 'flavours/glitch/initial_state';
import ReducedMotion from './reduced_motion';
import Motion from 'react-motion/lib/Motion';
diff --git a/app/javascript/flavours/glitch/util/react_router_helpers.js b/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/react_router_helpers.js
rename to app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js
diff --git a/app/javascript/flavours/glitch/util/reduced_motion.js b/app/javascript/flavours/glitch/features/ui/util/reduced_motion.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/reduced_motion.js
rename to app/javascript/flavours/glitch/features/ui/util/reduced_motion.js
diff --git a/app/javascript/flavours/glitch/util/schedule_idle_task.js b/app/javascript/flavours/glitch/features/ui/util/schedule_idle_task.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/schedule_idle_task.js
rename to app/javascript/flavours/glitch/features/ui/util/schedule_idle_task.js
diff --git a/app/javascript/flavours/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js
index 25c94bb2c5..cb4655f7f2 100644
--- a/app/javascript/flavours/glitch/features/video/index.js
+++ b/app/javascript/flavours/glitch/features/video/index.js
@@ -4,8 +4,8 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { is } from 'immutable';
import { throttle, debounce } from 'lodash';
import classNames from 'classnames';
-import { isFullscreen, requestFullscreen, exitFullscreen } from 'flavours/glitch/util/fullscreen';
-import { displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state';
+import { isFullscreen, requestFullscreen, exitFullscreen } from '../ui/util/fullscreen';
+import { displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
import Icon from 'flavours/glitch/components/icon';
import Blurhash from 'flavours/glitch/components/blurhash';
diff --git a/app/javascript/flavours/glitch/util/initial_state.js b/app/javascript/flavours/glitch/initial_state.js
similarity index 82%
rename from app/javascript/flavours/glitch/util/initial_state.js
rename to app/javascript/flavours/glitch/initial_state.js
index 99ee6bc69b..0f2484ba33 100644
--- a/app/javascript/flavours/glitch/util/initial_state.js
+++ b/app/javascript/flavours/glitch/initial_state.js
@@ -1,29 +1,26 @@
const element = document.getElementById('initial-state');
-const initialState = element && function () {
- const result = JSON.parse(element.textContent);
- try {
- result.local_settings = JSON.parse(localStorage.getItem('mastodon-settings'));
- } catch (e) {
- result.local_settings = {};
- }
- return result;
-}();
+const initialState = element && JSON.parse(element.textContent);
+
+// Glitch-soc-specific “local settings”
+try {
+ initialState.local_settings = JSON.parse(localStorage.getItem('mastodon-settings'));
+} catch (e) {
+ initialState.local_settings = {};
+}
const getMeta = (prop) => initialState && initialState.meta && initialState.meta[prop];
export const domain = getMeta('domain');
export const reduceMotion = getMeta('reduce_motion');
export const autoPlayGif = getMeta('auto_play_gif');
-export const displayMedia = getMeta('display_media') || (getMeta('display_sensitive_media') ? 'show_all' : 'default');
+export const displayMedia = getMeta('display_media');
export const expandSpoilers = getMeta('expand_spoilers');
export const unfollowModal = getMeta('unfollow_modal');
export const boostModal = getMeta('boost_modal');
-export const favouriteModal = getMeta('favourite_modal');
export const deleteModal = getMeta('delete_modal');
export const me = getMeta('me');
export const searchEnabled = getMeta('search_enabled');
export const maxChars = (initialState && initialState.max_toot_chars) || 500;
-export const pollLimits = (initialState && initialState.poll_limits);
export const limitedFederationMode = getMeta('limited_federation_mode');
export const registrationsOpen = getMeta('registrations_open');
export const repository = getMeta('repository');
@@ -31,14 +28,18 @@ export const source_url = getMeta('source_url');
export const version = getMeta('version');
export const mascot = getMeta('mascot');
export const profile_directory = getMeta('profile_directory');
-export const defaultContentType = getMeta('default_content_type');
export const forceSingleColumn = !getMeta('advanced_layout');
export const useBlurhash = getMeta('use_blurhash');
export const usePendingItems = getMeta('use_pending_items');
-export const useSystemEmojiFont = getMeta('system_emoji_font');
export const showTrends = getMeta('trends');
export const title = getMeta('title');
export const disableSwiping = getMeta('disable_swiping');
export const languages = initialState && initialState.languages;
+// Glitch-soc-specific settings
+export const favouriteModal = getMeta('favourite_modal');
+export const pollLimits = (initialState && initialState.poll_limits);
+export const defaultContentType = getMeta('default_content_type');
+export const useSystemEmojiFont = getMeta('system_emoji_font');
+
export default initialState;
diff --git a/app/javascript/flavours/glitch/util/is_mobile.js b/app/javascript/flavours/glitch/is_mobile.js
similarity index 93%
rename from app/javascript/flavours/glitch/util/is_mobile.js
rename to app/javascript/flavours/glitch/is_mobile.js
index c8517f592a..0d56630983 100644
--- a/app/javascript/flavours/glitch/util/is_mobile.js
+++ b/app/javascript/flavours/glitch/is_mobile.js
@@ -1,5 +1,5 @@
import { supportsPassiveEvents } from 'detect-passive-events';
-import { forceSingleColumn } from 'flavours/glitch/util/initial_state';
+import { forceSingleColumn } from 'flavours/glitch/initial_state';
const LAYOUT_BREAKPOINT = 630;
diff --git a/app/javascript/flavours/glitch/util/load_keyboard_extensions.js b/app/javascript/flavours/glitch/load_keyboard_extensions.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/load_keyboard_extensions.js
rename to app/javascript/flavours/glitch/load_keyboard_extensions.js
diff --git a/app/javascript/flavours/glitch/util/load_polyfills.js b/app/javascript/flavours/glitch/load_polyfills.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/load_polyfills.js
rename to app/javascript/flavours/glitch/load_polyfills.js
diff --git a/app/javascript/flavours/glitch/util/main.js b/app/javascript/flavours/glitch/main.js
similarity index 93%
rename from app/javascript/flavours/glitch/util/main.js
rename to app/javascript/flavours/glitch/main.js
index b4e6bc1512..04efcd43fd 100644
--- a/app/javascript/flavours/glitch/util/main.js
+++ b/app/javascript/flavours/glitch/main.js
@@ -2,9 +2,9 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { setupBrowserNotifications } from 'flavours/glitch/actions/notifications';
import Mastodon, { store } from 'flavours/glitch/containers/mastodon';
-import ready from 'flavours/glitch/util/ready';
+import ready from 'flavours/glitch/ready';
-const perf = require('flavours/glitch/util/performance');
+const perf = require('flavours/glitch/performance');
/**
* @returns {Promise}
diff --git a/app/javascript/flavours/glitch/packs/about.js b/app/javascript/flavours/glitch/packs/about.js
index 2e2cce501c..ef17fdea40 100644
--- a/app/javascript/flavours/glitch/packs/about.js
+++ b/app/javascript/flavours/glitch/packs/about.js
@@ -1,5 +1,5 @@
import 'packs/public-path';
-import loadPolyfills from 'flavours/glitch/util/load_polyfills';
+import loadPolyfills from 'flavours/glitch/load_polyfills';
function loaded() {
const TimelineContainer = require('flavours/glitch/containers/timeline_container').default;
@@ -14,7 +14,7 @@ function loaded() {
}
function main() {
- const ready = require('flavours/glitch/util/ready').default;
+ const ready = require('flavours/glitch/ready').default;
ready(loaded);
}
diff --git a/app/javascript/flavours/glitch/packs/admin.js b/app/javascript/flavours/glitch/packs/admin.js
index 4c09ddb05c..56cdfc30a3 100644
--- a/app/javascript/flavours/glitch/packs/admin.js
+++ b/app/javascript/flavours/glitch/packs/admin.js
@@ -1,5 +1,5 @@
import 'packs/public-path';
-import ready from 'flavours/glitch/util/ready';
+import ready from 'flavours/glitch/ready';
ready(() => {
const React = require('react');
diff --git a/app/javascript/flavours/glitch/packs/error.js b/app/javascript/flavours/glitch/packs/error.js
index 9f692ad379..f13e321498 100644
--- a/app/javascript/flavours/glitch/packs/error.js
+++ b/app/javascript/flavours/glitch/packs/error.js
@@ -1,5 +1,5 @@
import 'packs/public-path';
-import ready from 'flavours/glitch/util/ready';
+import ready from 'flavours/glitch/ready';
ready(() => {
const image = document.querySelector('img');
diff --git a/app/javascript/flavours/glitch/packs/home.js b/app/javascript/flavours/glitch/packs/home.js
index 7c87c515c5..ace9dc3c4f 100644
--- a/app/javascript/flavours/glitch/packs/home.js
+++ b/app/javascript/flavours/glitch/packs/home.js
@@ -1,8 +1,8 @@
import 'packs/public-path';
-import loadPolyfills from 'flavours/glitch/util/load_polyfills';
+import loadPolyfills from 'flavours/glitch/load_polyfills';
loadPolyfills().then(async () => {
- const { default: main } = await import('flavours/glitch/util/main');
+ const { default: main } = await import('flavours/glitch/main');
return main();
}).catch(e => {
diff --git a/app/javascript/flavours/glitch/packs/public.js b/app/javascript/flavours/glitch/packs/public.js
index 84ec9fce74..ae1899638a 100644
--- a/app/javascript/flavours/glitch/packs/public.js
+++ b/app/javascript/flavours/glitch/packs/public.js
@@ -1,13 +1,13 @@
import 'packs/public-path';
-import loadPolyfills from 'flavours/glitch/util/load_polyfills';
-import ready from 'flavours/glitch/util/ready';
-import loadKeyboardExtensions from 'flavours/glitch/util/load_keyboard_extensions';
+import loadPolyfills from 'flavours/glitch/load_polyfills';
+import ready from 'flavours/glitch/ready';
+import loadKeyboardExtensions from 'flavours/glitch/load_keyboard_extensions';
function main() {
const IntlMessageFormat = require('intl-messageformat').default;
const { timeAgoString } = require('flavours/glitch/components/relative_timestamp');
const { delegate } = require('@rails/ujs');
- const emojify = require('flavours/glitch/util/emoji').default;
+ const emojify = require('flavours/glitch/features/emoji/emoji').default;
const { getLocale } = require('locales');
const { messages } = getLocale();
const React = require('react');
diff --git a/app/javascript/flavours/glitch/packs/settings.js b/app/javascript/flavours/glitch/packs/settings.js
index de88d4f523..4c85f65561 100644
--- a/app/javascript/flavours/glitch/packs/settings.js
+++ b/app/javascript/flavours/glitch/packs/settings.js
@@ -1,7 +1,7 @@
import 'packs/public-path';
-import loadPolyfills from 'flavours/glitch/util/load_polyfills';
-import ready from 'flavours/glitch/util/ready';
-import loadKeyboardExtensions from 'flavours/glitch/util/load_keyboard_extensions';
+import loadPolyfills from 'flavours/glitch/load_polyfills';
+import ready from 'flavours/glitch/ready';
+import loadKeyboardExtensions from 'flavours/glitch/load_keyboard_extensions';
import 'cocoon-js-vanilla';
function main() {
diff --git a/app/javascript/flavours/glitch/packs/share.js b/app/javascript/flavours/glitch/packs/share.js
index f4a97e2015..e5a79849aa 100644
--- a/app/javascript/flavours/glitch/packs/share.js
+++ b/app/javascript/flavours/glitch/packs/share.js
@@ -1,5 +1,5 @@
import 'packs/public-path';
-import loadPolyfills from 'flavours/glitch/util/load_polyfills';
+import loadPolyfills from 'flavours/glitch/load_polyfills';
function loaded() {
const ComposeContainer = require('flavours/glitch/containers/compose_container').default;
@@ -14,7 +14,7 @@ function loaded() {
}
function main() {
- const ready = require('flavours/glitch/util/ready').default;
+ const ready = require('flavours/glitch/ready').default;
ready(loaded);
}
diff --git a/app/javascript/flavours/glitch/util/performance.js b/app/javascript/flavours/glitch/performance.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/performance.js
rename to app/javascript/flavours/glitch/performance.js
diff --git a/app/javascript/flavours/glitch/util/ready.js b/app/javascript/flavours/glitch/ready.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/ready.js
rename to app/javascript/flavours/glitch/ready.js
diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js
index 2ef08b2a6b..035e9f5643 100644
--- a/app/javascript/flavours/glitch/reducers/compose.js
+++ b/app/javascript/flavours/glitch/reducers/compose.js
@@ -53,12 +53,12 @@ import { TIMELINE_DELETE } from 'flavours/glitch/actions/timelines';
import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
import { REDRAFT } from 'flavours/glitch/actions/statuses';
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
-import uuid from 'flavours/glitch/util/uuid';
-import { privacyPreference } from 'flavours/glitch/util/privacy_preference';
-import { me, defaultContentType } from 'flavours/glitch/util/initial_state';
-import { overwrite } from 'flavours/glitch/util/js_helpers';
-import { unescapeHTML } from 'flavours/glitch/util/html';
-import { recoverHashtags } from 'flavours/glitch/util/hashtag';
+import uuid from '../uuid';
+import { privacyPreference } from 'flavours/glitch/utils/privacy_preference';
+import { me, defaultContentType } from 'flavours/glitch/initial_state';
+import { overwrite } from 'flavours/glitch/utils/js_helpers';
+import { unescapeHTML } from 'flavours/glitch/utils/html';
+import { recoverHashtags } from 'flavours/glitch/utils/hashtag';
const totalElefriends = 3;
diff --git a/app/javascript/flavours/glitch/reducers/contexts.js b/app/javascript/flavours/glitch/reducers/contexts.js
index 73b25fe3f9..a0fcc41587 100644
--- a/app/javascript/flavours/glitch/reducers/contexts.js
+++ b/app/javascript/flavours/glitch/reducers/contexts.js
@@ -5,7 +5,7 @@ import {
import { CONTEXT_FETCH_SUCCESS } from 'flavours/glitch/actions/statuses';
import { TIMELINE_DELETE, TIMELINE_UPDATE } from 'flavours/glitch/actions/timelines';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
-import compareId from 'flavours/glitch/util/compare_id';
+import compareId from '../compare_id';
const initialState = ImmutableMap({
inReplyTos: ImmutableMap(),
diff --git a/app/javascript/flavours/glitch/reducers/conversations.js b/app/javascript/flavours/glitch/reducers/conversations.js
index fba0308bc4..4407dcf040 100644
--- a/app/javascript/flavours/glitch/reducers/conversations.js
+++ b/app/javascript/flavours/glitch/reducers/conversations.js
@@ -11,7 +11,7 @@ import {
} from '../actions/conversations';
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS } from 'flavours/glitch/actions/accounts';
import { DOMAIN_BLOCK_SUCCESS } from 'flavours/glitch/actions/domain_blocks';
-import compareId from 'flavours/glitch/util/compare_id';
+import compareId from '../compare_id';
const initialState = ImmutableMap({
items: ImmutableList(),
diff --git a/app/javascript/flavours/glitch/reducers/custom_emojis.js b/app/javascript/flavours/glitch/reducers/custom_emojis.js
index 90e3040a43..f490d0db1e 100644
--- a/app/javascript/flavours/glitch/reducers/custom_emojis.js
+++ b/app/javascript/flavours/glitch/reducers/custom_emojis.js
@@ -1,7 +1,7 @@
import { List as ImmutableList, fromJS as ConvertToImmutable } from 'immutable';
import { CUSTOM_EMOJIS_FETCH_SUCCESS } from 'flavours/glitch/actions/custom_emojis';
-import { search as emojiSearch } from 'flavours/glitch/util/emoji/emoji_mart_search_light';
-import { buildCustomEmojis } from 'flavours/glitch/util/emoji';
+import { search as emojiSearch } from 'flavours/glitch/features/emoji/emoji_mart_search_light';
+import { buildCustomEmojis } from 'flavours/glitch/features/emoji/emoji';
const initialState = ImmutableList([]);
diff --git a/app/javascript/flavours/glitch/reducers/meta.js b/app/javascript/flavours/glitch/reducers/meta.js
index 0364ec2890..b1482777a9 100644
--- a/app/javascript/flavours/glitch/reducers/meta.js
+++ b/app/javascript/flavours/glitch/reducers/meta.js
@@ -1,7 +1,7 @@
import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
import { APP_LAYOUT_CHANGE } from 'flavours/glitch/actions/app';
import { Map as ImmutableMap } from 'immutable';
-import { layoutFromWindow } from 'flavours/glitch/util/is_mobile';
+import { layoutFromWindow } from 'flavours/glitch/is_mobile';
const initialState = ImmutableMap({
streaming_api_base_url: null,
diff --git a/app/javascript/flavours/glitch/reducers/notifications.js b/app/javascript/flavours/glitch/reducers/notifications.js
index 51d7886d7a..1b593b1281 100644
--- a/app/javascript/flavours/glitch/reducers/notifications.js
+++ b/app/javascript/flavours/glitch/reducers/notifications.js
@@ -32,7 +32,7 @@ import {
import { DOMAIN_BLOCK_SUCCESS } from 'flavours/glitch/actions/domain_blocks';
import { TIMELINE_DELETE, TIMELINE_DISCONNECT } from 'flavours/glitch/actions/timelines';
import { fromJS, Map as ImmutableMap, List as ImmutableList } from 'immutable';
-import compareId from 'flavours/glitch/util/compare_id';
+import compareId from '../compare_id';
const initialState = ImmutableMap({
pendingItems: ImmutableList(),
diff --git a/app/javascript/flavours/glitch/reducers/settings.js b/app/javascript/flavours/glitch/reducers/settings.js
index 1d99441a19..82927f7cd7 100644
--- a/app/javascript/flavours/glitch/reducers/settings.js
+++ b/app/javascript/flavours/glitch/reducers/settings.js
@@ -6,7 +6,7 @@ import { EMOJI_USE } from 'flavours/glitch/actions/emojis';
import { LANGUAGE_USE } from 'flavours/glitch/actions/languages';
import { LIST_DELETE_SUCCESS, LIST_FETCH_FAIL } from '../actions/lists';
import { Map as ImmutableMap, fromJS } from 'immutable';
-import uuid from 'flavours/glitch/util/uuid';
+import uuid from '../uuid';
const initialState = ImmutableMap({
saved: true,
diff --git a/app/javascript/flavours/glitch/reducers/timelines.js b/app/javascript/flavours/glitch/reducers/timelines.js
index afd9d12cb9..407293c62e 100644
--- a/app/javascript/flavours/glitch/reducers/timelines.js
+++ b/app/javascript/flavours/glitch/reducers/timelines.js
@@ -17,7 +17,7 @@ import {
ACCOUNT_UNFOLLOW_SUCCESS,
} from 'flavours/glitch/actions/accounts';
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
-import compareId from 'flavours/glitch/util/compare_id';
+import compareId from '../compare_id';
const initialState = ImmutableMap();
diff --git a/app/javascript/flavours/glitch/util/scroll.js b/app/javascript/flavours/glitch/scroll.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/scroll.js
rename to app/javascript/flavours/glitch/scroll.js
diff --git a/app/javascript/flavours/glitch/selectors/index.js b/app/javascript/flavours/glitch/selectors/index.js
index 377805f16c..8e6e40d246 100644
--- a/app/javascript/flavours/glitch/selectors/index.js
+++ b/app/javascript/flavours/glitch/selectors/index.js
@@ -1,8 +1,8 @@
import escapeTextContentForBrowser from 'escape-html';
import { createSelector } from 'reselect';
import { List as ImmutableList } from 'immutable';
-import { toServerSideType } from 'flavours/glitch/util/filters';
-import { me } from 'flavours/glitch/util/initial_state';
+import { toServerSideType } from 'flavours/glitch/utils/filters';
+import { me } from 'flavours/glitch/initial_state';
const getAccountBase = (state, id) => state.getIn(['accounts', id], null);
const getAccountCounters = (state, id) => state.getIn(['accounts_counters', id], null);
diff --git a/app/javascript/flavours/glitch/util/settings.js b/app/javascript/flavours/glitch/settings.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/settings.js
rename to app/javascript/flavours/glitch/settings.js
diff --git a/app/javascript/flavours/glitch/util/stream.js b/app/javascript/flavours/glitch/stream.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/stream.js
rename to app/javascript/flavours/glitch/stream.js
diff --git a/app/javascript/flavours/glitch/util/redux_helpers.js b/app/javascript/flavours/glitch/util/redux_helpers.js
deleted file mode 100644
index 8eb338da70..0000000000
--- a/app/javascript/flavours/glitch/util/redux_helpers.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { injectIntl } from 'react-intl';
-import { connect } from 'react-redux';
-
-// Connects a component.
-export function wrap (Component, mapStateToProps, mapDispatchToProps, options) {
- const withIntl = typeof options === 'object' ? options.withIntl : !!options;
- return (withIntl ? injectIntl : i => i)(connect(mapStateToProps, mapDispatchToProps)(Component));
-}
diff --git a/app/javascript/flavours/glitch/util/backend_links.js b/app/javascript/flavours/glitch/utils/backend_links.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/backend_links.js
rename to app/javascript/flavours/glitch/utils/backend_links.js
diff --git a/app/javascript/flavours/glitch/util/base64.js b/app/javascript/flavours/glitch/utils/base64.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/base64.js
rename to app/javascript/flavours/glitch/utils/base64.js
diff --git a/app/javascript/flavours/glitch/util/config.js b/app/javascript/flavours/glitch/utils/config.js
similarity index 85%
rename from app/javascript/flavours/glitch/util/config.js
rename to app/javascript/flavours/glitch/utils/config.js
index c3e2b73aea..932cd0cbf5 100644
--- a/app/javascript/flavours/glitch/util/config.js
+++ b/app/javascript/flavours/glitch/utils/config.js
@@ -1,4 +1,4 @@
-import ready from './ready';
+import ready from '../ready';
export let assetHost = '';
diff --git a/app/javascript/flavours/glitch/util/content_warning.js b/app/javascript/flavours/glitch/utils/content_warning.js
similarity index 90%
rename from app/javascript/flavours/glitch/util/content_warning.js
rename to app/javascript/flavours/glitch/utils/content_warning.js
index 383a342264..91d452baac 100644
--- a/app/javascript/flavours/glitch/util/content_warning.js
+++ b/app/javascript/flavours/glitch/utils/content_warning.js
@@ -1,4 +1,4 @@
-import { expandSpoilers } from 'flavours/glitch/util/initial_state';
+import { expandSpoilers } from 'flavours/glitch/initial_state';
function _autoUnfoldCW(spoiler_text, skip_unfold_regex) {
if (!expandSpoilers)
diff --git a/app/javascript/flavours/glitch/util/dom_helpers.js b/app/javascript/flavours/glitch/utils/dom_helpers.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/dom_helpers.js
rename to app/javascript/flavours/glitch/utils/dom_helpers.js
diff --git a/app/javascript/flavours/glitch/util/filters.js b/app/javascript/flavours/glitch/utils/filters.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/filters.js
rename to app/javascript/flavours/glitch/utils/filters.js
diff --git a/app/javascript/flavours/glitch/util/hashtag.js b/app/javascript/flavours/glitch/utils/hashtag.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/hashtag.js
rename to app/javascript/flavours/glitch/utils/hashtag.js
diff --git a/app/javascript/flavours/glitch/util/html.js b/app/javascript/flavours/glitch/utils/html.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/html.js
rename to app/javascript/flavours/glitch/utils/html.js
diff --git a/app/javascript/flavours/glitch/util/icons.js b/app/javascript/flavours/glitch/utils/icons.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/icons.js
rename to app/javascript/flavours/glitch/utils/icons.js
diff --git a/app/javascript/flavours/glitch/util/idna.js b/app/javascript/flavours/glitch/utils/idna.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/idna.js
rename to app/javascript/flavours/glitch/utils/idna.js
diff --git a/app/javascript/flavours/glitch/util/js_helpers.js b/app/javascript/flavours/glitch/utils/js_helpers.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/js_helpers.js
rename to app/javascript/flavours/glitch/utils/js_helpers.js
diff --git a/app/javascript/flavours/glitch/util/log_out.js b/app/javascript/flavours/glitch/utils/log_out.js
similarity index 93%
rename from app/javascript/flavours/glitch/util/log_out.js
rename to app/javascript/flavours/glitch/utils/log_out.js
index 42dcee03ec..f820411500 100644
--- a/app/javascript/flavours/glitch/util/log_out.js
+++ b/app/javascript/flavours/glitch/utils/log_out.js
@@ -1,5 +1,5 @@
import Rails from '@rails/ujs';
-import { signOutLink } from 'flavours/glitch/util/backend_links';
+import { signOutLink } from 'flavours/glitch/utils/backend_links';
export const logOut = () => {
const form = document.createElement('form');
diff --git a/app/javascript/flavours/glitch/util/notifications.js b/app/javascript/flavours/glitch/utils/notifications.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/notifications.js
rename to app/javascript/flavours/glitch/utils/notifications.js
diff --git a/app/javascript/flavours/glitch/util/numbers.js b/app/javascript/flavours/glitch/utils/numbers.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/numbers.js
rename to app/javascript/flavours/glitch/utils/numbers.js
diff --git a/app/javascript/flavours/glitch/util/privacy_preference.js b/app/javascript/flavours/glitch/utils/privacy_preference.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/privacy_preference.js
rename to app/javascript/flavours/glitch/utils/privacy_preference.js
diff --git a/app/javascript/flavours/glitch/util/react_helpers.js b/app/javascript/flavours/glitch/utils/react_helpers.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/react_helpers.js
rename to app/javascript/flavours/glitch/utils/react_helpers.js
diff --git a/app/javascript/flavours/glitch/util/resize_image.js b/app/javascript/flavours/glitch/utils/resize_image.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/resize_image.js
rename to app/javascript/flavours/glitch/utils/resize_image.js
diff --git a/app/javascript/flavours/glitch/util/scrollbar.js b/app/javascript/flavours/glitch/utils/scrollbar.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/scrollbar.js
rename to app/javascript/flavours/glitch/utils/scrollbar.js
diff --git a/app/javascript/flavours/glitch/util/uuid.js b/app/javascript/flavours/glitch/uuid.js
similarity index 100%
rename from app/javascript/flavours/glitch/util/uuid.js
rename to app/javascript/flavours/glitch/uuid.js