about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorClaire <claire.github-309c@sitedethib.com>2022-10-11 19:22:48 +0200
committerGitHub <noreply@github.com>2022-10-11 19:22:48 +0200
commitb01faa7375493ee91f7e9dfa32b0af3058c8d16f (patch)
tree42ef2359b2f85e5210172240b73ce735f1e92293 /app
parent94713940c7f28e9aff50071cf63d897c8e355ee6 (diff)
parente1db6cf320d5a1b3f7c87f4bd9e6f2f1a0c0585f (diff)
Merge pull request #1862 from ClearlyClaire/glitch-soc/refactor/upstream-discrepancies
Refactor glitch-soc front-end to limit discrepancies with upstream
Diffstat (limited to 'app')
-rw-r--r--app/javascript/flavours/glitch/actions/account_notes.js2
-rw-r--r--app/javascript/flavours/glitch/actions/accounts.js2
-rw-r--r--app/javascript/flavours/glitch/actions/announcements.js2
-rw-r--r--app/javascript/flavours/glitch/actions/blocks.js2
-rw-r--r--app/javascript/flavours/glitch/actions/bookmarks.js2
-rw-r--r--app/javascript/flavours/glitch/actions/compose.js10
-rw-r--r--app/javascript/flavours/glitch/actions/conversations.js2
-rw-r--r--app/javascript/flavours/glitch/actions/custom_emojis.js2
-rw-r--r--app/javascript/flavours/glitch/actions/directory.js2
-rw-r--r--app/javascript/flavours/glitch/actions/domain_blocks.js2
-rw-r--r--app/javascript/flavours/glitch/actions/favourites.js2
-rw-r--r--app/javascript/flavours/glitch/actions/filters.js2
-rw-r--r--app/javascript/flavours/glitch/actions/history.js2
-rw-r--r--app/javascript/flavours/glitch/actions/identity_proofs.js2
-rw-r--r--app/javascript/flavours/glitch/actions/importer/normalizer.js6
-rw-r--r--app/javascript/flavours/glitch/actions/interactions.js2
-rw-r--r--app/javascript/flavours/glitch/actions/lists.js2
-rw-r--r--app/javascript/flavours/glitch/actions/local_settings.js2
-rw-r--r--app/javascript/flavours/glitch/actions/markers.js4
-rw-r--r--app/javascript/flavours/glitch/actions/mutes.js2
-rw-r--r--app/javascript/flavours/glitch/actions/notifications.js10
-rw-r--r--app/javascript/flavours/glitch/actions/pin_statuses.js4
-rw-r--r--app/javascript/flavours/glitch/actions/polls.js2
-rw-r--r--app/javascript/flavours/glitch/actions/push_notifications/registerer.js4
-rw-r--r--app/javascript/flavours/glitch/actions/reports.js2
-rw-r--r--app/javascript/flavours/glitch/actions/search.js2
-rw-r--r--app/javascript/flavours/glitch/actions/server.js2
-rw-r--r--app/javascript/flavours/glitch/actions/settings.js2
-rw-r--r--app/javascript/flavours/glitch/actions/statuses.js2
-rw-r--r--app/javascript/flavours/glitch/actions/streaming.js2
-rw-r--r--app/javascript/flavours/glitch/actions/suggestions.js2
-rw-r--r--app/javascript/flavours/glitch/actions/tags.js2
-rw-r--r--app/javascript/flavours/glitch/actions/timelines.js8
-rw-r--r--app/javascript/flavours/glitch/actions/trends.js2
-rw-r--r--app/javascript/flavours/glitch/api.js (renamed from app/javascript/flavours/glitch/util/api.js)2
-rw-r--r--app/javascript/flavours/glitch/base_polyfills.js (renamed from app/javascript/flavours/glitch/util/base_polyfills.js)2
-rw-r--r--app/javascript/flavours/glitch/compare_id.js (renamed from app/javascript/flavours/glitch/util/compare_id.js)0
-rw-r--r--app/javascript/flavours/glitch/components/account.js2
-rw-r--r--app/javascript/flavours/glitch/components/admin/Counter.js2
-rw-r--r--app/javascript/flavours/glitch/components/admin/Dimension.js4
-rw-r--r--app/javascript/flavours/glitch/components/admin/ReportReasonSelector.js2
-rw-r--r--app/javascript/flavours/glitch/components/admin/Retention.js4
-rw-r--r--app/javascript/flavours/glitch/components/admin/Trends.js2
-rw-r--r--app/javascript/flavours/glitch/components/animated_number.js2
-rw-r--r--app/javascript/flavours/glitch/components/autosuggest_emoji.js4
-rw-r--r--app/javascript/flavours/glitch/components/avatar.js2
-rw-r--r--app/javascript/flavours/glitch/components/avatar_composite.js2
-rw-r--r--app/javascript/flavours/glitch/components/avatar_overlay.js2
-rw-r--r--app/javascript/flavours/glitch/components/column.js2
-rw-r--r--app/javascript/flavours/glitch/components/display_name.js2
-rw-r--r--app/javascript/flavours/glitch/components/dropdown_menu.js2
-rw-r--r--app/javascript/flavours/glitch/components/error_boundary.js4
-rw-r--r--app/javascript/flavours/glitch/components/icon_button.js2
-rw-r--r--app/javascript/flavours/glitch/components/intersection_observer_article.js4
-rw-r--r--app/javascript/flavours/glitch/components/link.js2
-rw-r--r--app/javascript/flavours/glitch/components/media_attachments.js2
-rw-r--r--app/javascript/flavours/glitch/components/media_gallery.js4
-rw-r--r--app/javascript/flavours/glitch/components/poll.js4
-rw-r--r--app/javascript/flavours/glitch/components/scrollable_list.js4
-rw-r--r--app/javascript/flavours/glitch/components/server_banner.js2
-rw-r--r--app/javascript/flavours/glitch/components/short_number.js4
-rw-r--r--app/javascript/flavours/glitch/components/status.js6
-rw-r--r--app/javascript/flavours/glitch/components/status_action_bar.js4
-rw-r--r--app/javascript/flavours/glitch/components/status_content.js4
-rw-r--r--app/javascript/flavours/glitch/components/status_icons.js2
-rw-r--r--app/javascript/flavours/glitch/components/status_prepend.js2
-rw-r--r--app/javascript/flavours/glitch/containers/account_container.js2
-rw-r--r--app/javascript/flavours/glitch/containers/compose_container.js2
-rw-r--r--app/javascript/flavours/glitch/containers/dropdown_menu_container.js2
-rw-r--r--app/javascript/flavours/glitch/containers/mastodon.js2
-rw-r--r--app/javascript/flavours/glitch/containers/media_container.js2
-rw-r--r--app/javascript/flavours/glitch/containers/status_container.js4
-rw-r--r--app/javascript/flavours/glitch/containers/timeline_container.js2
-rw-r--r--app/javascript/flavours/glitch/extra_polyfills.js (renamed from app/javascript/flavours/glitch/util/extra_polyfills.js)0
-rw-r--r--app/javascript/flavours/glitch/features/account/components/action_bar.js4
-rw-r--r--app/javascript/flavours/glitch/features/account/components/header.js4
-rw-r--r--app/javascript/flavours/glitch/features/account_gallery/components/media_item.js4
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js2
-rw-r--r--app/javascript/flavours/glitch/features/audio/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/community_timeline/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/compose_form.js14
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/dropdown.js4
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/dropdown_menu.js6
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js (renamed from app/javascript/flavours/glitch/features/emoji_picker/index.js)90
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/header.js4
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/language_dropdown.js6
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/navigation_bar.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/options.js4
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/poll_form.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/publisher.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/search.js6
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/search_results.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/upload.js4
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/upload_progress.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/warning.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/containers/emoji_picker_dropdown_container.js82
-rw-r--r--app/javascript/flavours/glitch/features/compose/containers/header_container.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/containers/navigation_container.js2
-rw-r--r--app/javascript/flavours/glitch/features/compose/containers/warning_container.js4
-rw-r--r--app/javascript/flavours/glitch/features/compose/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/compose/util/counter.js (renamed from app/javascript/flavours/glitch/util/counter.js)0
-rw-r--r--app/javascript/flavours/glitch/features/compose/util/url_regex.js (renamed from app/javascript/flavours/glitch/util/url_regex.js)0
-rw-r--r--app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js2
-rw-r--r--app/javascript/flavours/glitch/features/directory/components/account_card.js2
-rw-r--r--app/javascript/flavours/glitch/features/directory/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/emoji/emoji.js (renamed from app/javascript/flavours/glitch/util/emoji/index.js)4
-rw-r--r--app/javascript/flavours/glitch/features/emoji/emoji_compressed.js (renamed from app/javascript/flavours/glitch/util/emoji/emoji_compressed.js)0
-rw-r--r--app/javascript/flavours/glitch/features/emoji/emoji_map.json (renamed from app/javascript/flavours/glitch/util/emoji/emoji_map.json)0
-rw-r--r--app/javascript/flavours/glitch/features/emoji/emoji_mart_data_light.js (renamed from app/javascript/flavours/glitch/util/emoji/emoji_mart_data_light.js)0
-rw-r--r--app/javascript/flavours/glitch/features/emoji/emoji_mart_search_light.js (renamed from app/javascript/flavours/glitch/util/emoji/emoji_mart_search_light.js)0
-rw-r--r--app/javascript/flavours/glitch/features/emoji/emoji_picker.js (renamed from app/javascript/flavours/glitch/util/emoji/emoji_picker.js)0
-rw-r--r--app/javascript/flavours/glitch/features/emoji/emoji_unicode_mapping_light.js (renamed from app/javascript/flavours/glitch/util/emoji/emoji_unicode_mapping_light.js)0
-rw-r--r--app/javascript/flavours/glitch/features/emoji/emoji_utils.js (renamed from app/javascript/flavours/glitch/util/emoji/emoji_utils.js)0
-rw-r--r--app/javascript/flavours/glitch/features/emoji/unicode_to_filename.js (renamed from app/javascript/flavours/glitch/util/emoji/unicode_to_filename.js)0
-rw-r--r--app/javascript/flavours/glitch/features/emoji/unicode_to_unified_name.js (renamed from app/javascript/flavours/glitch/util/emoji/unicode_to_unified_name.js)0
-rw-r--r--app/javascript/flavours/glitch/features/explore/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/explore/results.js2
-rw-r--r--app/javascript/flavours/glitch/features/filters/added_to_filter.js2
-rw-r--r--app/javascript/flavours/glitch/features/filters/select_filter.js4
-rw-r--r--app/javascript/flavours/glitch/features/follow_requests/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/getting_started/components/announcements.js10
-rw-r--r--app/javascript/flavours/glitch/features/getting_started/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/hashtag_timeline/containers/column_settings_container.js2
-rw-r--r--app/javascript/flavours/glitch/features/hashtag_timeline/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/home_timeline/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/interaction_modal/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/list_editor/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/local_settings/navigation/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/local_settings/page/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/notifications/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/picture_in_picture/components/footer.js2
-rw-r--r--app/javascript/flavours/glitch/features/pinned_accounts_editor/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/public_timeline/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/status/components/action_bar.js4
-rw-r--r--app/javascript/flavours/glitch/features/status/components/card.js4
-rw-r--r--app/javascript/flavours/glitch/features/status/components/detailed_status.js2
-rw-r--r--app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js2
-rw-r--r--app/javascript/flavours/glitch/features/status/index.js6
-rw-r--r--app/javascript/flavours/glitch/features/subscribed_languages_modal/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/column.js4
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/columns_area.js6
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/compare_history_modal.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/deprecated_settings_modal.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/embed_modal.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js6
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/link_footer.js6
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/media_modal.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/modal_root.js4
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/navigation_panel.js4
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/tabs_bar.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/upload_area.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/containers/status_list_container.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/index.js8
-rw-r--r--app/javascript/flavours/glitch/features/ui/util/async-components.js (renamed from app/javascript/flavours/glitch/util/async-components.js)2
-rw-r--r--app/javascript/flavours/glitch/features/ui/util/fullscreen.js (renamed from app/javascript/flavours/glitch/util/fullscreen.js)0
-rw-r--r--app/javascript/flavours/glitch/features/ui/util/get_rect_from_entry.js (renamed from app/javascript/flavours/glitch/util/get_rect_from_entry.js)0
-rw-r--r--app/javascript/flavours/glitch/features/ui/util/intersection_observer_wrapper.js (renamed from app/javascript/flavours/glitch/util/intersection_observer_wrapper.js)0
-rw-r--r--app/javascript/flavours/glitch/features/ui/util/optional_motion.js (renamed from app/javascript/flavours/glitch/util/optional_motion.js)2
-rw-r--r--app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js (renamed from app/javascript/flavours/glitch/util/react_router_helpers.js)0
-rw-r--r--app/javascript/flavours/glitch/features/ui/util/reduced_motion.js (renamed from app/javascript/flavours/glitch/util/reduced_motion.js)0
-rw-r--r--app/javascript/flavours/glitch/features/ui/util/schedule_idle_task.js (renamed from app/javascript/flavours/glitch/util/schedule_idle_task.js)0
-rw-r--r--app/javascript/flavours/glitch/features/video/index.js4
-rw-r--r--app/javascript/flavours/glitch/initial_state.js (renamed from app/javascript/flavours/glitch/util/initial_state.js)29
-rw-r--r--app/javascript/flavours/glitch/is_mobile.js (renamed from app/javascript/flavours/glitch/util/is_mobile.js)2
-rw-r--r--app/javascript/flavours/glitch/load_keyboard_extensions.js (renamed from app/javascript/flavours/glitch/util/load_keyboard_extensions.js)0
-rw-r--r--app/javascript/flavours/glitch/load_polyfills.js (renamed from app/javascript/flavours/glitch/util/load_polyfills.js)0
-rw-r--r--app/javascript/flavours/glitch/main.js (renamed from app/javascript/flavours/glitch/util/main.js)4
-rw-r--r--app/javascript/flavours/glitch/packs/about.js4
-rw-r--r--app/javascript/flavours/glitch/packs/admin.js2
-rw-r--r--app/javascript/flavours/glitch/packs/error.js2
-rw-r--r--app/javascript/flavours/glitch/packs/home.js4
-rw-r--r--app/javascript/flavours/glitch/packs/public.js8
-rw-r--r--app/javascript/flavours/glitch/packs/settings.js6
-rw-r--r--app/javascript/flavours/glitch/packs/share.js4
-rw-r--r--app/javascript/flavours/glitch/performance.js (renamed from app/javascript/flavours/glitch/util/performance.js)0
-rw-r--r--app/javascript/flavours/glitch/ready.js (renamed from app/javascript/flavours/glitch/util/ready.js)0
-rw-r--r--app/javascript/flavours/glitch/reducers/compose.js12
-rw-r--r--app/javascript/flavours/glitch/reducers/contexts.js2
-rw-r--r--app/javascript/flavours/glitch/reducers/conversations.js2
-rw-r--r--app/javascript/flavours/glitch/reducers/custom_emojis.js4
-rw-r--r--app/javascript/flavours/glitch/reducers/meta.js2
-rw-r--r--app/javascript/flavours/glitch/reducers/notifications.js2
-rw-r--r--app/javascript/flavours/glitch/reducers/settings.js2
-rw-r--r--app/javascript/flavours/glitch/reducers/timelines.js2
-rw-r--r--app/javascript/flavours/glitch/scroll.js (renamed from app/javascript/flavours/glitch/util/scroll.js)0
-rw-r--r--app/javascript/flavours/glitch/selectors/index.js4
-rw-r--r--app/javascript/flavours/glitch/settings.js (renamed from app/javascript/flavours/glitch/util/settings.js)0
-rw-r--r--app/javascript/flavours/glitch/stream.js (renamed from app/javascript/flavours/glitch/util/stream.js)0
-rw-r--r--app/javascript/flavours/glitch/util/redux_helpers.js8
-rw-r--r--app/javascript/flavours/glitch/utils/backend_links.js (renamed from app/javascript/flavours/glitch/util/backend_links.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/base64.js (renamed from app/javascript/flavours/glitch/util/base64.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/config.js (renamed from app/javascript/flavours/glitch/util/config.js)2
-rw-r--r--app/javascript/flavours/glitch/utils/content_warning.js (renamed from app/javascript/flavours/glitch/util/content_warning.js)2
-rw-r--r--app/javascript/flavours/glitch/utils/dom_helpers.js (renamed from app/javascript/flavours/glitch/util/dom_helpers.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/filters.js (renamed from app/javascript/flavours/glitch/util/filters.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/hashtag.js (renamed from app/javascript/flavours/glitch/util/hashtag.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/html.js (renamed from app/javascript/flavours/glitch/util/html.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/icons.js (renamed from app/javascript/flavours/glitch/util/icons.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/idna.js (renamed from app/javascript/flavours/glitch/util/idna.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/js_helpers.js (renamed from app/javascript/flavours/glitch/util/js_helpers.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/log_out.js (renamed from app/javascript/flavours/glitch/util/log_out.js)2
-rw-r--r--app/javascript/flavours/glitch/utils/notifications.js (renamed from app/javascript/flavours/glitch/util/notifications.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/numbers.js (renamed from app/javascript/flavours/glitch/util/numbers.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/privacy_preference.js (renamed from app/javascript/flavours/glitch/util/privacy_preference.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/react_helpers.js (renamed from app/javascript/flavours/glitch/util/react_helpers.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/resize_image.js (renamed from app/javascript/flavours/glitch/util/resize_image.js)0
-rw-r--r--app/javascript/flavours/glitch/utils/scrollbar.js (renamed from app/javascript/flavours/glitch/util/scrollbar.js)0
-rw-r--r--app/javascript/flavours/glitch/uuid.js (renamed from app/javascript/flavours/glitch/util/uuid.js)0
211 files changed, 361 insertions, 366 deletions
diff --git a/app/javascript/flavours/glitch/actions/account_notes.js b/app/javascript/flavours/glitch/actions/account_notes.js
index c1cce3193..059ed9e80 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 750740879..dc670e50a 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 871409d43..1bdea909f 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 adae9d83c..fd9881302 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 83dbf5407..544ed2ff2 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 ab74fb303..02aa4f144 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 e5c85c65d..4ef654b1f 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 29ae72edb..7b7d0091b 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 9fbfb7f5b..4b2b6dd56 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 6d3f471fa..34a33a654 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 0d8bfb14d..9448b1efe 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 9aa31028a..76326802e 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 c47057261..c142aaf61 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 18e679aec..103983956 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 9950a720b..1c9f524e4 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 336c8fa90..225ee7eb2 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 c2309b8c2..5ab922436 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 856674eb3..a4a928611 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 6a0549f7f..3b6a76bc4 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 2bacfadb7..1ccf9592f 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 4581ebc36..158a5b7e4 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 77dfb9c7f..0926978ac 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 ca94a095f..8e8b82df5 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 8fdb239f7..762fe260c 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 333bc71f4..fbe5b3791 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 b4aee4525..776782693 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 215dfeffa..af8fef780 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 fb0bcc09c..5634a11ef 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 58c1d44a6..5930b7a16 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 375728cb5..ffac1b258 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 7070250e3..1f1116e75 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 4016cf96f..37e79d4cb 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 0d6f844b3..ef1e4dbbb 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 e9aa28dd3..edda0b5b5 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
index 90d8465ef..645ef6500 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
index 4b8123dba..12096d902 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
index 66cf51c4b..66cf51c4b 100644
--- a/app/javascript/flavours/glitch/util/compare_id.js
+++ b/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 24d3f65ef..8bfc8e9dc 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 a4d6cef41..5b6a19f8d 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 a924d093c..3dac8c6c2 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 0f2a4fe36..771dbb452 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 6d7e4b279..9cc39040b 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 60e367f00..4c17b69a0 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 3cc5173dd..4619aad58 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 d04c1eb68..83fafbd10 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 6d53a5298..ce91d401d 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 e30dfe68a..c0ce7761d 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 23db5182b..01dec587a 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 c9da7d329..cf0e6d5e4 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 7cb0c9133..1c2297578 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 e04af8074..036e0b909 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 4537bde1d..fd3659de7 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 c0664ec89..42f5d4bc3 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 88f29892e..90667d9f5 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 de99f7d42..bbec121a8 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 c8d133f09..a517fcf30 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 68195ea80..5414b4858 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 bcd9fe341..da65cd241 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 50bfacc6a..8eb2b66d4 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 e29876d4b..16360ec56 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 e4ba09634..535c17727 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 9b656b2b3..6cdc4b971 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 4e5e5121a..deb9cfc15 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 39891da4f..fe0d4c043 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 2226aaef2..71ffb2e56 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 d85009362..f82533062 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 bc84d299b..5b57d730f 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 74c411b7c..1e49b89a0 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 0c4a2b50f..b2dff63db 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 a6ec5845d..bc0311293 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 11c15d7c6..f1e8534aa 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 a1b4c57c6..c12b2e614 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 b61dc8dd7..838bcd390 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
index 3acc55abd..3acc55abd 100644
--- a/app/javascript/flavours/glitch/util/extra_polyfills.js
+++ b/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 23120d57e..ce0584124 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 fc80446b1..0f0e40268 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 7457980d2..a16ee4806 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 659dbc3fa..c1577e170 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 8fa64342e..014a0a213 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 b921e22e9..5ee46ca3b 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 b03bc34b8..0be14e495 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)}
         >
-          <EmojiPicker onPickEmoji={handleEmoji} />
+          <EmojiPickerDropdown onPickEmoji={handleEmojiPick} />
           <TextareaIcons advancedOptions={advancedOptions} />
           <div className='compose-form__modifiers'>
             <UploadFormContainer />
diff --git a/app/javascript/flavours/glitch/features/compose/components/dropdown.js b/app/javascript/flavours/glitch/features/compose/components/dropdown.js
index 9f70d6b79..829f6d00f 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 0649fe1ca..21835e628 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
index 5de9fe107..0e49a35c3 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 95add2027..7ecb573ab 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 035b0c0c3..31f1d4e73 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 595ca5512..ba73ed553 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 f005dbdd1..32a464011 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 e4b5104f3..d5edccff3 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 e2498bcad..50baad065 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 12d839637..a59418e46 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 e82ee2ca2..c2178702c 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 963b95c87..ade6f0437 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 493bb9ca5..8896bbffd 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 6ee3640bc..4009be8c6 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 a037bbbcc..d12c98c01 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 000000000..ba85edd87
--- /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 2f0da48c8..e1ce19fb0 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 eb630ffbb..0e1400261 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 5fccaa442..b2ed40b82 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 b9a8e0245..567bb3711 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
index 7aa9e87b1..7aa9e87b1 100644
--- a/app/javascript/flavours/glitch/util/counter.js
+++ b/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
index 9c2005c53..9c2005c53 100644
--- a/app/javascript/flavours/glitch/util/url_regex.js
+++ b/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 7107c9db3..00d9fdcd0 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 218208c10..b6785a5f9 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 1aa8a330d..dce8fa4e7 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
index 162946bbb..c4e2c26f2 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
index 74b53ce5c..74b53ce5c 100644
--- a/app/javascript/flavours/glitch/util/emoji/emoji_compressed.js
+++ b/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
index 121fea2a5..121fea2a5 100644
--- a/app/javascript/flavours/glitch/util/emoji/emoji_map.json
+++ b/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
index 45086fc4c..45086fc4c 100644
--- a/app/javascript/flavours/glitch/util/emoji/emoji_mart_data_light.js
+++ b/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
index 70694ab6d..70694ab6d 100644
--- a/app/javascript/flavours/glitch/util/emoji/emoji_mart_search_light.js
+++ b/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
index 044d38cb2..044d38cb2 100644
--- a/app/javascript/flavours/glitch/util/emoji/emoji_picker.js
+++ b/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
index 918684c31..918684c31 100644
--- a/app/javascript/flavours/glitch/util/emoji/emoji_unicode_mapping_light.js
+++ b/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
index dbf725c1f..dbf725c1f 100644
--- a/app/javascript/flavours/glitch/util/emoji/emoji_utils.js
+++ b/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
index c75c4cd7d..c75c4cd7d 100644
--- a/app/javascript/flavours/glitch/util/emoji/unicode_to_filename.js
+++ b/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
index d29550f12..d29550f12 100644
--- a/app/javascript/flavours/glitch/util/emoji/unicode_to_unified_name.js
+++ b/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 388123c38..f37793732 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 3f43b9ee1..e37379686 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 f777ca429..becb170cd 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 5321dbb96..5391766c9 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 36a57d1d6..47ca1e1bf 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 f7097e2ec..93f3c9428 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 8b6a617ff..f52b769a3 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 1cf527573..004856b04 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 38dda85b2..5e098514a 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 7ca28da35..86aaa0258 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 d2260c4f0..5623f8a06 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 75b0de3d3..c2ca07053 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 d085a606c..e618a981e 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 a21c90b4b..e154fe1c8 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 6cfafb61e..26eeba168 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 2a5adf71d..86e24e38f 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 5f03c7e93..43ae0ec2f 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 6e1fb8ced..aa70acf15 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 75ad462f0..9868621fe 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 0ca2508e7..2d2e49eb8 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 91dc5ba20..46770930f 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 40e186569..e5e065987 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 8e783af80..c967ef34d 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 3047b434c..fa69d82a4 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 916396931..e9c1e2f87 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 5f5018105..718b4a27f 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 8fd528da0..baf7f25be 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 9cb5a30b9..68f04cb21 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 b6f5e628d..624b68f7e 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 5a4baa5a1..de330b3a1 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 6f4a8c2de..39576f17b 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 baa5ff275..ec3af857d 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 92768caeb..cedfabe03 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 453276775..57fbfb285 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 e7be62ad8..97932ada1 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 e08a1ea67..a935d7422 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 = () => (
   <div className='sign-in-banner'>
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 0a7078a9c..9c82fc91d 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 11a10baf1..6958ba9df 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 53c3b8f39..3cd0707f2 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 735623e3d..c8cc905e7 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
index 1ecba2bcb..eef3a941d 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
index cf5d0cf98..cf5d0cf98 100644
--- a/app/javascript/flavours/glitch/util/fullscreen.js
+++ b/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
index c266cd7dc..c266cd7dc 100644
--- a/app/javascript/flavours/glitch/util/get_rect_from_entry.js
+++ b/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
index 2b24c6583..2b24c6583 100644
--- a/app/javascript/flavours/glitch/util/intersection_observer_wrapper.js
+++ b/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
index eecb6634e..a7fbe6310 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
index e36c512f3..e36c512f3 100644
--- a/app/javascript/flavours/glitch/util/react_router_helpers.js
+++ b/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
index 95519042b..95519042b 100644
--- a/app/javascript/flavours/glitch/util/reduced_motion.js
+++ b/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
index b04d4a8ee..b04d4a8ee 100644
--- a/app/javascript/flavours/glitch/util/schedule_idle_task.js
+++ b/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 25c94bb2c..cb4655f7f 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
index 99ee6bc69..0f2484ba3 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
index c8517f592..0d5663098 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
index 2dd0e45fa..2dd0e45fa 100644
--- a/app/javascript/flavours/glitch/util/load_keyboard_extensions.js
+++ b/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
index 73eedc9dc..73eedc9dc 100644
--- a/app/javascript/flavours/glitch/util/load_polyfills.js
+++ b/app/javascript/flavours/glitch/load_polyfills.js
diff --git a/app/javascript/flavours/glitch/util/main.js b/app/javascript/flavours/glitch/main.js
index b4e6bc151..04efcd43f 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<void>}
diff --git a/app/javascript/flavours/glitch/packs/about.js b/app/javascript/flavours/glitch/packs/about.js
index 2e2cce501..ef17fdea4 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 4c09ddb05..56cdfc30a 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 9f692ad37..f13e32149 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 7c87c515c..ace9dc3c4 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 84ec9fce7..ae1899638 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 de88d4f52..4c85f6556 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 f4a97e201..e5a79849a 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
index 450a90626..450a90626 100644
--- a/app/javascript/flavours/glitch/util/performance.js
+++ b/app/javascript/flavours/glitch/performance.js
diff --git a/app/javascript/flavours/glitch/util/ready.js b/app/javascript/flavours/glitch/ready.js
index e769cc756..e769cc756 100644
--- a/app/javascript/flavours/glitch/util/ready.js
+++ b/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 2ef08b2a6..035e9f564 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 73b25fe3f..a0fcc4158 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 fba0308bc..4407dcf04 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 90e3040a4..f490d0db1 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 0364ec289..b1482777a 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 51d7886d7..1b593b128 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 1d99441a1..82927f7cd 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 afd9d12cb..407293c62 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
index 84fe58269..84fe58269 100644
--- a/app/javascript/flavours/glitch/util/scroll.js
+++ b/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 377805f16..8e6e40d24 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
index 7643a508e..7643a508e 100644
--- a/app/javascript/flavours/glitch/util/settings.js
+++ b/app/javascript/flavours/glitch/settings.js
diff --git a/app/javascript/flavours/glitch/util/stream.js b/app/javascript/flavours/glitch/stream.js
index c6d12cd6f..c6d12cd6f 100644
--- a/app/javascript/flavours/glitch/util/stream.js
+++ b/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 8eb338da7..000000000
--- 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
index d0ae63419..d0ae63419 100644
--- a/app/javascript/flavours/glitch/util/backend_links.js
+++ b/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
index 8226e2c54..8226e2c54 100644
--- a/app/javascript/flavours/glitch/util/base64.js
+++ b/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
index c3e2b73ae..932cd0cbf 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
index 383a34226..91d452baa 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
index d94aeb9d4..d94aeb9d4 100644
--- a/app/javascript/flavours/glitch/util/dom_helpers.js
+++ b/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
index 97b433a99..97b433a99 100644
--- a/app/javascript/flavours/glitch/util/filters.js
+++ b/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
index 9b663487f..9b663487f 100644
--- a/app/javascript/flavours/glitch/util/hashtag.js
+++ b/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
index 5159df9db..5159df9db 100644
--- a/app/javascript/flavours/glitch/util/html.js
+++ b/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
index c3e362e39..c3e362e39 100644
--- a/app/javascript/flavours/glitch/util/icons.js
+++ b/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
index efab5bacf..efab5bacf 100644
--- a/app/javascript/flavours/glitch/util/idna.js
+++ b/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
index 2ebd5b6c5..2ebd5b6c5 100644
--- a/app/javascript/flavours/glitch/util/js_helpers.js
+++ b/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
index 42dcee03e..f82041150 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
index 7634cac21..7634cac21 100644
--- a/app/javascript/flavours/glitch/util/notifications.js
+++ b/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
index 6ef563ad8..6ef563ad8 100644
--- a/app/javascript/flavours/glitch/util/numbers.js
+++ b/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
index 7781ca7fa..7781ca7fa 100644
--- a/app/javascript/flavours/glitch/util/privacy_preference.js
+++ b/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
index 082a58e62..082a58e62 100644
--- a/app/javascript/flavours/glitch/util/react_helpers.js
+++ b/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
index fb8c3c11e..fb8c3c11e 100644
--- a/app/javascript/flavours/glitch/util/resize_image.js
+++ b/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
index 929b036d6..929b036d6 100644
--- a/app/javascript/flavours/glitch/util/scrollbar.js
+++ b/app/javascript/flavours/glitch/utils/scrollbar.js
diff --git a/app/javascript/flavours/glitch/util/uuid.js b/app/javascript/flavours/glitch/uuid.js
index be1899305..be1899305 100644
--- a/app/javascript/flavours/glitch/util/uuid.js
+++ b/app/javascript/flavours/glitch/uuid.js