diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js index 2af0fcf48d0..469fc2aa717 100644 --- a/app/javascript/flavours/glitch/features/getting_started/index.js +++ b/app/javascript/flavours/glitch/features/getting_started/index.js @@ -29,6 +29,7 @@ const messages = defineMessages({ info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' }, show_me_around: { id: 'getting_started.onboarding', defaultMessage: 'Show me around' }, pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' }, + lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' }, }); const mapStateToProps = state => ({ @@ -87,6 +88,7 @@ export default class GettingStarted extends ImmutablePureComponent { navItems = navItems.concat([ , , + , ]); if (myAccount.get('locked')) { @@ -96,6 +98,7 @@ export default class GettingStarted extends ImmutablePureComponent { navItems = navItems.concat([ , , + , ]); return ( 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 61b2392839d..679578b7599 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js @@ -15,6 +15,7 @@ import { ReportModal, SettingsModal, EmbedModal, + ListEditor, } from 'flavours/glitch/util/async-components'; const MODAL_COMPONENTS = { @@ -29,6 +30,7 @@ const MODAL_COMPONENTS = { 'SETTINGS': SettingsModal, 'ACTIONS': () => Promise.resolve({ default: ActionsModal }), 'EMBED': EmbedModal, + 'LIST_EDITOR': ListEditor, }; export default class ModalRoot extends React.PureComponent { diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 3dee7ca1969..698ae996c2e 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -39,6 +39,7 @@ import { Blocks, Mutes, PinnedStatuses, + Lists, } from 'flavours/glitch/util/async-components'; import { HotKeys } from 'react-hotkeys'; import { me } from 'flavours/glitch/util/initial_state'; @@ -426,6 +427,7 @@ export default class UI extends React.Component { + diff --git a/app/javascript/flavours/glitch/reducers/accounts.js b/app/javascript/flavours/glitch/reducers/accounts.js index 5113a281aa5..9ca05881a33 100644 --- a/app/javascript/flavours/glitch/reducers/accounts.js +++ b/app/javascript/flavours/glitch/reducers/accounts.js @@ -43,6 +43,10 @@ import { FAVOURITED_STATUSES_FETCH_SUCCESS, FAVOURITED_STATUSES_EXPAND_SUCCESS, } from 'flavours/glitch/actions/favourites'; +import { + LIST_ACCOUNTS_FETCH_SUCCESS, + LIST_EDITOR_SUGGESTIONS_READY, +} from 'flavours/glitch/actions/lists'; import { STORE_HYDRATE } from 'flavours/glitch/actions/store'; import emojify from 'flavours/glitch/util/emoji'; import { Map as ImmutableMap, fromJS } from 'immutable'; @@ -110,6 +114,8 @@ export default function accounts(state = initialState, action) { case BLOCKS_EXPAND_SUCCESS: case MUTES_FETCH_SUCCESS: case MUTES_EXPAND_SUCCESS: + case LIST_ACCOUNTS_FETCH_SUCCESS: + case LIST_EDITOR_SUGGESTIONS_READY: return action.accounts ? normalizeAccounts(state, action.accounts) : state; case NOTIFICATIONS_REFRESH_SUCCESS: case NOTIFICATIONS_EXPAND_SUCCESS: diff --git a/app/javascript/flavours/glitch/reducers/accounts_counters.js b/app/javascript/flavours/glitch/reducers/accounts_counters.js index a9aebd26fce..0fd985a081f 100644 --- a/app/javascript/flavours/glitch/reducers/accounts_counters.js +++ b/app/javascript/flavours/glitch/reducers/accounts_counters.js @@ -45,6 +45,10 @@ import { FAVOURITED_STATUSES_FETCH_SUCCESS, FAVOURITED_STATUSES_EXPAND_SUCCESS, } from 'flavours/glitch/actions/favourites'; +import { + LIST_ACCOUNTS_FETCH_SUCCESS, + LIST_EDITOR_SUGGESTIONS_READY, +} from 'flavours/glitch/actions/lists'; import { STORE_HYDRATE } from 'flavours/glitch/actions/store'; import { Map as ImmutableMap, fromJS } from 'immutable'; @@ -106,6 +110,8 @@ export default function accountsCounters(state = initialState, action) { case BLOCKS_EXPAND_SUCCESS: case MUTES_FETCH_SUCCESS: case MUTES_EXPAND_SUCCESS: + case LIST_ACCOUNTS_FETCH_SUCCESS: + case LIST_EDITOR_SUGGESTIONS_READY: return action.accounts ? normalizeAccounts(state, action.accounts) : state; case NOTIFICATIONS_REFRESH_SUCCESS: case NOTIFICATIONS_EXPAND_SUCCESS: diff --git a/app/javascript/flavours/glitch/reducers/index.js b/app/javascript/flavours/glitch/reducers/index.js index 25baaef71b5..e9c8d7c1df1 100644 --- a/app/javascript/flavours/glitch/reducers/index.js +++ b/app/javascript/flavours/glitch/reducers/index.js @@ -24,6 +24,7 @@ import notifications from './notifications'; import height_cache from './height_cache'; import custom_emojis from './custom_emojis'; import lists from './lists'; +import listEditor from './list_editor'; const reducers = { timelines, @@ -51,6 +52,7 @@ const reducers = { height_cache, custom_emojis, lists, + listEditor, }; export default combineReducers(reducers); diff --git a/app/javascript/flavours/glitch/reducers/settings.js b/app/javascript/flavours/glitch/reducers/settings.js index 6d5d71217c8..aaf7938df4d 100644 --- a/app/javascript/flavours/glitch/reducers/settings.js +++ b/app/javascript/flavours/glitch/reducers/settings.js @@ -2,6 +2,7 @@ import { SETTING_CHANGE, SETTING_SAVE } from 'flavours/glitch/actions/settings'; import { COLUMN_ADD, COLUMN_REMOVE, COLUMN_MOVE } from 'flavours/glitch/actions/columns'; import { STORE_HYDRATE } from 'flavours/glitch/actions/store'; import { EMOJI_USE } from 'flavours/glitch/actions/emojis'; +import { LIST_DELETE_SUCCESS, LIST_FETCH_FAIL } from '../actions/lists'; import { Map as ImmutableMap, fromJS } from 'immutable'; import uuid from 'flavours/glitch/util/uuid'; @@ -92,6 +93,8 @@ const moveColumn = (state, uuid, direction) => { const updateFrequentEmojis = (state, emoji) => state.update('frequentlyUsedEmojis', ImmutableMap(), map => map.update(emoji.id, 0, count => count + 1)).set('saved', false); +const filterDeadListColumns = (state, listId) => state.update('columns', columns => columns.filterNot(column => column.get('id') === 'LIST' && column.get('params').get('id') === listId)); + export default function settings(state = initialState, action) { switch(action.type) { case STORE_HYDRATE: @@ -114,6 +117,10 @@ export default function settings(state = initialState, action) { return updateFrequentEmojis(state, action.emoji); case SETTING_SAVE: return state.set('saved', true); + case LIST_FETCH_FAIL: + return action.error.response.status === 404 ? filterDeadListColumns(state, action.id) : state; + case LIST_DELETE_SUCCESS: + return filterDeadListColumns(state, action.id); default: return state; } diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 7aeab0a6af9..147690562bd 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -4827,6 +4827,90 @@ noscript { } } + +.column-inline-form { + padding: 7px 15px; + padding-right: 5px; + display: flex; + justify-content: flex-start; + align-items: center; + background: lighten($ui-base-color, 4%); + + label { + flex: 1 1 auto; + + input { + width: 100%; + margin-bottom: 6px; + } + } + + .icon-button { + flex: 0 0 auto; + margin-left: 5px; + } +} + +.drawer__backdrop { + cursor: pointer; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba($base-overlay-background, 0.5); +} + +.list-editor { + background: $ui-base-color; + flex-direction: column; + border-radius: 8px; + box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); + width: 40vh; + overflow: hidden; + + h4 { + padding: 15px 0; + background: lighten($ui-base-color, 13%); + font-weight: 500; + font-size: 16px; + text-align: center; + border-radius: 8px 8px 0 0; + } + + .drawer__pager { + height: 50vh; + } + + .drawer__inner { + border-radius: 0 0 8px 8px; + + &.backdrop { + width: calc(100% - 60px); + box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); + border-radius: 0 0 0 8px; + } + } + + &__accounts { + overflow-y: auto; + } + + .account__display-name { + &:hover strong { + text-decoration: none; + } + } + + .account__avatar { + cursor: default; + } + + .search { + margin-bottom: 0; + } +} + @import 'doodle'; @import 'emoji_picker'; @import 'local_settings'; diff --git a/app/javascript/flavours/glitch/util/async-components.js b/app/javascript/flavours/glitch/util/async-components.js index 3056deab2b7..e4c991f011c 100644 --- a/app/javascript/flavours/glitch/util/async-components.js +++ b/app/javascript/flavours/glitch/util/async-components.js @@ -30,6 +30,14 @@ export function ListTimeline () { return import(/* webpackChunkName: "features/list_timeline" */'flavours/glitch/features/list_timeline'); } +export function Lists () { + return import(/* webpackChunkName: "features/lists" */'flavours/glitch/features/lists'); +} + +export function ListEditor () { + return import(/* webpackChunkName: "features/list_editor" */'flavours/glitch/features/list_editor'); +} + export function DirectTimeline() { return import(/* webpackChunkName: "flavours/glitch/async/direct_timeline" */'flavours/glitch/features/direct_timeline'); }