From f44c8fd130e51b5d8f707be8fd53ccc81211eb73 Mon Sep 17 00:00:00 2001 From: cwm Date: Fri, 8 Dec 2017 19:40:49 -0600 Subject: merged tootsuite pr #5750 into glitch flavour --- .../features/list_editor/components/account.js | 77 ++++++++++ .../features/list_editor/components/search.js | 75 +++++++++ .../flavours/glitch/features/list_editor/index.js | 80 ++++++++++ .../glitch/features/list_timeline/index.js | 170 +++++++++++++++++++++ .../features/lists/components/new_list_form.js | 78 ++++++++++ .../flavours/glitch/features/lists/index.js | 76 +++++++++ .../glitch/features/ui/components/columns_area.js | 3 +- .../flavours/glitch/features/ui/index.js | 3 +- 8 files changed, 560 insertions(+), 2 deletions(-) create mode 100644 app/javascript/flavours/glitch/features/list_editor/components/account.js create mode 100644 app/javascript/flavours/glitch/features/list_editor/components/search.js create mode 100644 app/javascript/flavours/glitch/features/list_editor/index.js create mode 100644 app/javascript/flavours/glitch/features/list_timeline/index.js create mode 100644 app/javascript/flavours/glitch/features/lists/components/new_list_form.js create mode 100644 app/javascript/flavours/glitch/features/lists/index.js (limited to 'app/javascript/flavours/glitch/features') diff --git a/app/javascript/flavours/glitch/features/list_editor/components/account.js b/app/javascript/flavours/glitch/features/list_editor/components/account.js new file mode 100644 index 000000000..f48df759d --- /dev/null +++ b/app/javascript/flavours/glitch/features/list_editor/components/account.js @@ -0,0 +1,77 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { makeGetAccount } from 'flavours/glitch/selectors'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import Avatar from 'flavours/glitch/components/avatar'; +import DisplayName from 'flavours/glitch/components/display_name'; +import IconButton from 'flavours/glitch/components/icon_button'; +import { defineMessages, injectIntl } from 'react-intl'; +import { removeFromListEditor, addToListEditor } from 'flavours/glitch/actions/lists'; + +const messages = defineMessages({ + remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' }, + add: { id: 'lists.account.add', defaultMessage: 'Add to list' }, +}); + +const makeMapStateToProps = () => { + const getAccount = makeGetAccount(); + + const mapStateToProps = (state, { accountId, added }) => ({ + account: getAccount(state, accountId), + added: typeof added === 'undefined' ? state.getIn(['listEditor', 'accounts', 'items']).includes(accountId) : added, + }); + + return mapStateToProps; +}; + +const mapDispatchToProps = (dispatch, { accountId }) => ({ + onRemove: () => dispatch(removeFromListEditor(accountId)), + onAdd: () => dispatch(addToListEditor(accountId)), +}); + +@connect(makeMapStateToProps, mapDispatchToProps) +@injectIntl +export default class Account extends ImmutablePureComponent { + + static propTypes = { + account: ImmutablePropTypes.map.isRequired, + intl: PropTypes.object.isRequired, + onRemove: PropTypes.func.isRequired, + onAdd: PropTypes.func.isRequired, + added: PropTypes.bool, + }; + + static defaultProps = { + added: false, + }; + + render () { + const { account, intl, onRemove, onAdd, added } = this.props; + + let button; + + if (added) { + button = ; + } else { + button = ; + } + + return ( +
+
+
+
+ +
+ +
+ {button} +
+
+
+ ); + } + +} diff --git a/app/javascript/flavours/glitch/features/list_editor/components/search.js b/app/javascript/flavours/glitch/features/list_editor/components/search.js new file mode 100644 index 000000000..45c4d0f2e --- /dev/null +++ b/app/javascript/flavours/glitch/features/list_editor/components/search.js @@ -0,0 +1,75 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { defineMessages, injectIntl } from 'react-intl'; +import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from '../../../actions/lists'; +import classNames from 'classnames'; + +const messages = defineMessages({ + search: { id: 'lists.search', defaultMessage: 'Search among people you follow' }, +}); + +const mapStateToProps = state => ({ + value: state.getIn(['listEditor', 'suggestions', 'value']), +}); + +const mapDispatchToProps = dispatch => ({ + onSubmit: value => dispatch(fetchListSuggestions(value)), + onClear: () => dispatch(clearListSuggestions()), + onChange: value => dispatch(changeListSuggestions(value)), +}); + +@connect(mapStateToProps, mapDispatchToProps) +@injectIntl +export default class Search extends React.PureComponent { + + static propTypes = { + intl: PropTypes.object.isRequired, + value: PropTypes.string.isRequired, + onChange: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onClear: PropTypes.func.isRequired, + }; + + handleChange = e => { + this.props.onChange(e.target.value); + } + + handleKeyUp = e => { + if (e.keyCode === 13) { + this.props.onSubmit(this.props.value); + } + } + + handleClear = () => { + this.props.onClear(); + } + + render () { + const { value, intl } = this.props; + const hasValue = value.length > 0; + + return ( +
+ + +
+ + +
+
+ ); + } + +} diff --git a/app/javascript/flavours/glitch/features/list_editor/index.js b/app/javascript/flavours/glitch/features/list_editor/index.js new file mode 100644 index 000000000..7f9c6b0e9 --- /dev/null +++ b/app/javascript/flavours/glitch/features/list_editor/index.js @@ -0,0 +1,80 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import { connect } from 'react-redux'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { injectIntl } from 'react-intl'; +import { setupListEditor, clearListSuggestions, resetListEditor } from 'flavours/glitch/actions/lists'; +import Account from './components/account'; +import Search from './components/search'; +import Motion from 'flavours/glitch/util/optional_motion'; +import spring from 'react-motion/lib/spring'; + +const mapStateToProps = state => ({ + title: state.getIn(['listEditor', 'title']), + accountIds: state.getIn(['listEditor', 'accounts', 'items']), + searchAccountIds: state.getIn(['listEditor', 'suggestions', 'items']), +}); + +const mapDispatchToProps = dispatch => ({ + onInitialize: listId => dispatch(setupListEditor(listId)), + onClear: () => dispatch(clearListSuggestions()), + onReset: () => dispatch(resetListEditor()), +}); + +@connect(mapStateToProps, mapDispatchToProps) +@injectIntl +export default class ListEditor extends ImmutablePureComponent { + + static propTypes = { + listId: PropTypes.string.isRequired, + onClose: PropTypes.func.isRequired, + intl: PropTypes.object.isRequired, + onInitialize: PropTypes.func.isRequired, + onClear: PropTypes.func.isRequired, + onReset: PropTypes.func.isRequired, + title: PropTypes.string.isRequired, + accountIds: ImmutablePropTypes.list.isRequired, + searchAccountIds: ImmutablePropTypes.list.isRequired, + }; + + componentDidMount () { + const { onInitialize, listId } = this.props; + onInitialize(listId); + } + + componentWillUnmount () { + const { onReset } = this.props; + onReset(); + } + + render () { + const { title, accountIds, searchAccountIds, onClear } = this.props; + const showSearch = searchAccountIds.size > 0; + + return ( +
+

{title}

+ + + +
+
+ {accountIds.map(accountId => )} +
+ + {showSearch &&
} + + + {({ x }) => +
+ {searchAccountIds.map(accountId => )} +
+ } +
+
+
+ ); + } + +} diff --git a/app/javascript/flavours/glitch/features/list_timeline/index.js b/app/javascript/flavours/glitch/features/list_timeline/index.js new file mode 100644 index 000000000..bcc752d34 --- /dev/null +++ b/app/javascript/flavours/glitch/features/list_timeline/index.js @@ -0,0 +1,170 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container'; +import Column from 'flavours/glitch/components/column'; +import ColumnHeader from 'flavours/glitch/components/column_header'; +import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; +import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; +import { connectListStream } from 'flavours/glitch/actions/streaming'; +import { refreshListTimeline, expandListTimeline } from 'flavours/glitch/actions/timelines'; +import { fetchList, deleteList } from 'flavours/glitch/actions/lists'; +import { openModal } from 'flavours/glitch/actions/modal'; +import MissingIndicator from 'flavours/glitch/components/missing_indicator'; +import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; + +const messages = defineMessages({ + deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' }, + deleteConfirm: { id: 'confirmations.delete_list.confirm', defaultMessage: 'Delete' }, +}); + +const mapStateToProps = (state, props) => ({ + list: state.getIn(['lists', props.params.id]), + hasUnread: state.getIn(['timelines', `list:${props.params.id}`, 'unread']) > 0, +}); + +@connect(mapStateToProps) +@injectIntl +export default class ListTimeline extends React.PureComponent { + + static contextTypes = { + router: PropTypes.object, + }; + + static propTypes = { + params: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + columnId: PropTypes.string, + hasUnread: PropTypes.bool, + multiColumn: PropTypes.bool, + list: PropTypes.oneOfType([ImmutablePropTypes.map, PropTypes.bool]), + intl: PropTypes.object.isRequired, + }; + + handlePin = () => { + const { columnId, dispatch } = this.props; + + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('LIST', { id: this.props.params.id })); + this.context.router.history.push('/'); + } + } + + handleMove = (dir) => { + const { columnId, dispatch } = this.props; + dispatch(moveColumn(columnId, dir)); + } + + handleHeaderClick = () => { + this.column.scrollTop(); + } + + componentDidMount () { + const { dispatch } = this.props; + const { id } = this.props.params; + + dispatch(fetchList(id)); + dispatch(refreshListTimeline(id)); + + this.disconnect = dispatch(connectListStream(id)); + } + + componentWillUnmount () { + if (this.disconnect) { + this.disconnect(); + this.disconnect = null; + } + } + + setRef = c => { + this.column = c; + } + + handleLoadMore = () => { + const { id } = this.props.params; + this.props.dispatch(expandListTimeline(id)); + } + + handleEditClick = () => { + this.props.dispatch(openModal('LIST_EDITOR', { listId: this.props.params.id })); + } + + handleDeleteClick = () => { + const { dispatch, columnId, intl } = this.props; + const { id } = this.props.params; + + dispatch(openModal('CONFIRM', { + message: intl.formatMessage(messages.deleteMessage), + confirm: intl.formatMessage(messages.deleteConfirm), + onConfirm: () => { + dispatch(deleteList(id)); + + if (!!columnId) { + dispatch(removeColumn(columnId)); + } else { + this.context.router.history.push('/lists'); + } + }, + })); + } + + render () { + const { hasUnread, columnId, multiColumn, list } = this.props; + const { id } = this.props.params; + const pinned = !!columnId; + const title = list ? list.get('title') : id; + + if (typeof list === 'undefined') { + return ( + + + + ); + } else if (list === false) { + return ( + + + + ); + } + + return ( + + +
+ + + +
+ +
+
+ + } + /> +
+ ); + } + +} diff --git a/app/javascript/flavours/glitch/features/lists/components/new_list_form.js b/app/javascript/flavours/glitch/features/lists/components/new_list_form.js new file mode 100644 index 000000000..61fcbeaf9 --- /dev/null +++ b/app/javascript/flavours/glitch/features/lists/components/new_list_form.js @@ -0,0 +1,78 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import { changeListEditorTitle, submitListEditor } from 'flavours/glitch/actions/lists'; +import IconButton from 'flavours/glitch/components/icon_button'; +import { defineMessages, injectIntl } from 'react-intl'; + +const messages = defineMessages({ + label: { id: 'lists.new.title_placeholder', defaultMessage: 'New list title' }, + title: { id: 'lists.new.create', defaultMessage: 'Add list' }, +}); + +const mapStateToProps = state => ({ + value: state.getIn(['listEditor', 'title']), + disabled: state.getIn(['listEditor', 'isSubmitting']), +}); + +const mapDispatchToProps = dispatch => ({ + onChange: value => dispatch(changeListEditorTitle(value)), + onSubmit: () => dispatch(submitListEditor(true)), +}); + +@connect(mapStateToProps, mapDispatchToProps) +@injectIntl +export default class NewListForm extends React.PureComponent { + + static propTypes = { + value: PropTypes.string.isRequired, + disabled: PropTypes.bool, + intl: PropTypes.object.isRequired, + onChange: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + }; + + handleChange = e => { + this.props.onChange(e.target.value); + } + + handleSubmit = e => { + e.preventDefault(); + this.props.onSubmit(); + } + + handleClick = () => { + this.props.onSubmit(); + } + + render () { + const { value, disabled, intl } = this.props; + + const label = intl.formatMessage(messages.label); + const title = intl.formatMessage(messages.title); + + return ( +
+ + + + + ); + } + +} diff --git a/app/javascript/flavours/glitch/features/lists/index.js b/app/javascript/flavours/glitch/features/lists/index.js new file mode 100644 index 000000000..c82b370bc --- /dev/null +++ b/app/javascript/flavours/glitch/features/lists/index.js @@ -0,0 +1,76 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; +import Column from 'flavours/glitch/features/ui/components/column'; +import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim'; +import { fetchLists } from 'flavours/glitch/actions/lists'; +import { defineMessages, injectIntl } from 'react-intl'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import ColumnLink from 'flavours/glitch/features/ui/components/column_link'; +import ColumnSubheading from 'flavours/glitch/features/ui/components/column_subheading'; +import NewListForm from './components/new_list_form'; +import { createSelector } from 'reselect'; + +const messages = defineMessages({ + heading: { id: 'column.lists', defaultMessage: 'Lists' }, + subheading: { id: 'lists.subheading', defaultMessage: 'Your lists' }, +}); + +const getOrderedLists = createSelector([state => state.get('lists')], lists => { + if (!lists) { + return lists; + } + + return lists.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title'))); +}); + +const mapStateToProps = state => ({ + lists: getOrderedLists(state), +}); + +@connect(mapStateToProps) +@injectIntl +export default class Lists extends ImmutablePureComponent { + + static propTypes = { + params: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + lists: ImmutablePropTypes.list, + intl: PropTypes.object.isRequired, + }; + + componentWillMount () { + this.props.dispatch(fetchLists()); + } + + render () { + const { intl, lists } = this.props; + + if (!lists) { + return ( + + + + ); + } + + return ( + + + + + +
+ + + {lists.map(list => + + )} +
+
+ ); + } + +} 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 264f60724..4167ff693 100644 --- a/app/javascript/flavours/glitch/features/ui/components/columns_area.js +++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.js @@ -11,7 +11,7 @@ import BundleContainer from '../containers/bundle_container'; import ColumnLoading from './column_loading'; import DrawerLoading from './drawer_loading'; import BundleColumnError from './bundle_column_error'; -import { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, DirectTimeline, FavouritedStatuses } from 'flavours/glitch/util/async-components'; +import { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, DirectTimeline, FavouritedStatuses, ListTimeline } from 'flavours/glitch/util/async-components'; import detectPassiveEvents from 'detect-passive-events'; import { scrollRight } from 'flavours/glitch/util/scroll'; @@ -25,6 +25,7 @@ const componentMap = { 'HASHTAG': HashtagTimeline, 'DIRECT': DirectTimeline, 'FAVOURITES': FavouritedStatuses, + 'LIST': ListTimeline, }; @component => injectIntl(component, { withRef: true }) diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 4a1982916..3dee7ca19 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -35,6 +35,7 @@ import { FollowRequests, GenericNotFound, FavouritedStatuses, + ListTimeline, Blocks, Mutes, PinnedStatuses, @@ -407,7 +408,7 @@ export default class UI extends React.Component { - + -- cgit From 47157e07b25f80aa9d2f90591bb59cf32cf593be Mon Sep 17 00:00:00 2001 From: cwm Date: Fri, 8 Dec 2017 20:13:08 -0600 Subject: merged tootsuite pr #5811 into glitch flavour --- .../glitch/features/getting_started/index.js | 3 + .../glitch/features/ui/components/modal_root.js | 2 + .../flavours/glitch/features/ui/index.js | 2 + .../flavours/glitch/reducers/accounts.js | 6 ++ .../flavours/glitch/reducers/accounts_counters.js | 6 ++ app/javascript/flavours/glitch/reducers/index.js | 2 + .../flavours/glitch/reducers/settings.js | 7 ++ .../flavours/glitch/styles/components/index.scss | 84 ++++++++++++++++++++++ .../flavours/glitch/util/async-components.js | 8 +++ 9 files changed, 120 insertions(+) (limited to 'app/javascript/flavours/glitch/features') diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js index 2af0fcf48..469fc2aa7 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 61b239283..679578b75 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 3dee7ca19..698ae996c 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 5113a281a..9ca05881a 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 a9aebd26f..0fd985a08 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 25baaef71..e9c8d7c1d 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 6d5d71217..aaf7938df 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 7aeab0a6a..147690562 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 3056deab2..e4c991f01 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'); } -- cgit From b165950ca76f45bc04a730d61853063c0100914c Mon Sep 17 00:00:00 2001 From: cwm Date: Fri, 8 Dec 2017 20:30:45 -0600 Subject: add keyboard shortcut to getting started, add missing list style --- .../flavours/glitch/features/getting_started/index.js | 3 ++- app/javascript/flavours/glitch/styles/components/index.scss | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch/features') diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js index 469fc2aa7..5307e583f 100644 --- a/app/javascript/flavours/glitch/features/getting_started/index.js +++ b/app/javascript/flavours/glitch/features/getting_started/index.js @@ -30,6 +30,7 @@ const messages = defineMessages({ 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' }, + keyboard_shortcuts: { id: 'navigation_bar.keyboard_shortcuts', defaultMessage: 'Keyboard shortcuts' }, }); const mapStateToProps = state => ({ @@ -88,7 +89,7 @@ export default class GettingStarted extends ImmutablePureComponent { navItems = navItems.concat([ , , - , + , ]); if (myAccount.get('locked')) { diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 147690562..db51b164d 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -2542,6 +2542,10 @@ button.icon-button.active i.fa-retweet { margin-left: 0; } +.column-header__links .text-btn { + margin-right: 10px; +} + .column-header__button { background: lighten($ui-base-color, 4%); border: 0; @@ -2664,6 +2668,14 @@ button.icon-button.active i.fa-retweet { overflow-y: hidden; } + hr { + height: 0; + background: transparent; + border: 0; + border-top: 1px solid lighten($ui-base-color, 12%); + margin: 10px 0; + } + // notif cleaning drawer &.ncd { transition: none; -- cgit From baf9ea80180afbd905397d67085b174a0921b7e8 Mon Sep 17 00:00:00 2001 From: cwm Date: Sat, 9 Dec 2017 10:32:46 -0600 Subject: remove keyboard shortcuts from getting started because thats a different thing --- app/javascript/flavours/glitch/features/getting_started/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'app/javascript/flavours/glitch/features') diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js index 5307e583f..47142fdd1 100644 --- a/app/javascript/flavours/glitch/features/getting_started/index.js +++ b/app/javascript/flavours/glitch/features/getting_started/index.js @@ -89,7 +89,7 @@ export default class GettingStarted extends ImmutablePureComponent { navItems = navItems.concat([ , , - , + , ]); if (myAccount.get('locked')) { @@ -99,7 +99,6 @@ export default class GettingStarted extends ImmutablePureComponent { navItems = navItems.concat([ , , - , ]); return ( -- cgit