Implement adding a user to a list from their profile (#9062)
* Add add user to list from thier profile * Fix listAdderCss
This commit is contained in:
		
					parent
					
						
							
								a7e3bd0300
							
						
					
				
			
			
				commit
				
					
						bb5558de62
					
				
			
		
					 62 changed files with 414 additions and 0 deletions
				
			
		|  | @ -42,6 +42,13 @@ export const LIST_EDITOR_REMOVE_REQUEST = 'LIST_EDITOR_REMOVE_REQUEST'; | |||
| export const LIST_EDITOR_REMOVE_SUCCESS = 'LIST_EDITOR_REMOVE_SUCCESS'; | ||||
| export const LIST_EDITOR_REMOVE_FAIL    = 'LIST_EDITOR_REMOVE_FAIL'; | ||||
| 
 | ||||
| export const LIST_ADDER_RESET = 'LIST_ADDER_RESET'; | ||||
| export const LIST_ADDER_SETUP = 'LIST_ADDER_SETUP'; | ||||
| 
 | ||||
| export const LIST_ADDER_LISTS_FETCH_REQUEST = 'LIST_ADDER_LISTS_FETCH_REQUEST'; | ||||
| export const LIST_ADDER_LISTS_FETCH_SUCCESS = 'LIST_ADDER_LISTS_FETCH_SUCCESS'; | ||||
| export const LIST_ADDER_LISTS_FETCH_FAIL    = 'LIST_ADDER_LISTS_FETCH_FAIL'; | ||||
| 
 | ||||
| export const fetchList = id => (dispatch, getState) => { | ||||
|   if (getState().getIn(['lists', id])) { | ||||
|     return; | ||||
|  | @ -316,3 +323,50 @@ export const removeFromListFail = (listId, accountId, error) => ({ | |||
|   accountId, | ||||
|   error, | ||||
| }); | ||||
| 
 | ||||
| export const resetListAdder = () => ({ | ||||
|   type: LIST_ADDER_RESET, | ||||
| }); | ||||
| 
 | ||||
| export const setupListAdder = accountId => (dispatch, getState) => { | ||||
|   dispatch({ | ||||
|     type: LIST_ADDER_SETUP, | ||||
|     account: getState().getIn(['accounts', accountId]), | ||||
|   }); | ||||
|   dispatch(fetchLists()); | ||||
|   dispatch(fetchAccountLists(accountId)); | ||||
| }; | ||||
| 
 | ||||
| export const fetchAccountLists = accountId => (dispatch, getState) => { | ||||
|   dispatch(fetchAccountListsRequest(accountId)); | ||||
| 
 | ||||
|   api(getState).get(`/api/v1/accounts/${accountId}/lists`) | ||||
|     .then(({ data }) => dispatch(fetchAccountListsSuccess(accountId, data))) | ||||
|     .catch(err => dispatch(fetchAccountListsFail(accountId, err))); | ||||
| }; | ||||
| 
 | ||||
| export const fetchAccountListsRequest = id => ({ | ||||
|   type:LIST_ADDER_LISTS_FETCH_REQUEST, | ||||
|   id, | ||||
| }); | ||||
| 
 | ||||
| export const fetchAccountListsSuccess = (id, lists) => ({ | ||||
|   type: LIST_ADDER_LISTS_FETCH_SUCCESS, | ||||
|   id, | ||||
|   lists, | ||||
| }); | ||||
| 
 | ||||
| export const fetchAccountListsFail = (id, err) => ({ | ||||
|   type: LIST_ADDER_LISTS_FETCH_FAIL, | ||||
|   id, | ||||
|   err, | ||||
| }); | ||||
| 
 | ||||
| export const addToListAdder = listId => (dispatch, getState) => { | ||||
|   dispatch(addToList(listId, getState().getIn(['listAdder', 'accountId']))); | ||||
| }; | ||||
| 
 | ||||
| export const removeFromListAdder = listId => (dispatch, getState) => { | ||||
|   dispatch(removeFromList(listId, getState().getIn(['listAdder', 'accountId']))); | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -34,6 +34,7 @@ const messages = defineMessages({ | |||
|   mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' }, | ||||
|   endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' }, | ||||
|   unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' }, | ||||
|   add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' }, | ||||
| }); | ||||
| 
 | ||||
| export default @injectIntl | ||||
|  | @ -51,6 +52,7 @@ class ActionBar extends React.PureComponent { | |||
|     onBlockDomain: PropTypes.func.isRequired, | ||||
|     onUnblockDomain: PropTypes.func.isRequired, | ||||
|     onEndorseToggle: PropTypes.func.isRequired, | ||||
|     onAddToList: PropTypes.func.isRequired, | ||||
|     intl: PropTypes.object.isRequired, | ||||
|   }; | ||||
| 
 | ||||
|  | @ -105,6 +107,7 @@ class ActionBar extends React.PureComponent { | |||
|         } | ||||
| 
 | ||||
|         menu.push({ text: intl.formatMessage(account.getIn(['relationship', 'endorsed']) ? messages.unendorse : messages.endorse), action: this.props.onEndorseToggle }); | ||||
|         menu.push({ text: intl.formatMessage(messages.add_or_remove_from_list), action: this.props.onAddToList }); | ||||
|         menu.push(null); | ||||
|       } | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ export default class Header extends ImmutablePureComponent { | |||
|     onBlockDomain: PropTypes.func.isRequired, | ||||
|     onUnblockDomain: PropTypes.func.isRequired, | ||||
|     onEndorseToggle: PropTypes.func.isRequired, | ||||
|     onAddToList: PropTypes.func.isRequired, | ||||
|     hideTabs: PropTypes.bool, | ||||
|   }; | ||||
| 
 | ||||
|  | @ -78,6 +79,10 @@ export default class Header extends ImmutablePureComponent { | |||
|     this.props.onEndorseToggle(this.props.account); | ||||
|   } | ||||
| 
 | ||||
|   handleAddToList = () => { | ||||
|     this.props.onAddToList(this.props.account); | ||||
|   } | ||||
| 
 | ||||
|   render () { | ||||
|     const { account, hideTabs } = this.props; | ||||
| 
 | ||||
|  | @ -106,6 +111,7 @@ export default class Header extends ImmutablePureComponent { | |||
|           onBlockDomain={this.handleBlockDomain} | ||||
|           onUnblockDomain={this.handleUnblockDomain} | ||||
|           onEndorseToggle={this.handleEndorseToggle} | ||||
|           onAddToList={this.handleAddToList} | ||||
|         /> | ||||
| 
 | ||||
|         {!hideTabs && ( | ||||
|  |  | |||
|  | @ -116,6 +116,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ | |||
|     dispatch(unblockDomain(domain)); | ||||
|   }, | ||||
| 
 | ||||
|   onAddToList(account){ | ||||
|     dispatch(openModal('LIST_ADDER', { | ||||
|       accountId: account.get('id'), | ||||
|     })); | ||||
|   }, | ||||
| 
 | ||||
| }); | ||||
| 
 | ||||
| export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Header)); | ||||
|  |  | |||
|  | @ -0,0 +1,43 @@ | |||
| import React from 'react'; | ||||
| import { connect } from 'react-redux'; | ||||
| import { makeGetAccount } from '../../../selectors'; | ||||
| import ImmutablePureComponent from 'react-immutable-pure-component'; | ||||
| import ImmutablePropTypes from 'react-immutable-proptypes'; | ||||
| import Avatar from '../../../components/avatar'; | ||||
| import DisplayName from '../../../components/display_name'; | ||||
| import { injectIntl } from 'react-intl'; | ||||
| 
 | ||||
| const makeMapStateToProps = () => { | ||||
|   const getAccount = makeGetAccount(); | ||||
| 
 | ||||
|   const mapStateToProps = (state, { accountId }) => ({ | ||||
|     account: getAccount(state, accountId), | ||||
|   }); | ||||
| 
 | ||||
|   return mapStateToProps; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| export default @connect(makeMapStateToProps) | ||||
| @injectIntl | ||||
| class Account extends ImmutablePureComponent { | ||||
| 
 | ||||
|   static propTypes = { | ||||
|     account: ImmutablePropTypes.map.isRequired, | ||||
|   }; | ||||
| 
 | ||||
|   render () { | ||||
|     const { account } = this.props; | ||||
|     return ( | ||||
|       <div className='account'> | ||||
|         <div className='account__wrapper'> | ||||
|           <div className='account__display-name'> | ||||
|             <div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div> | ||||
|             <DisplayName account={account} /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,68 @@ | |||
| import React from 'react'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import { connect } from 'react-redux'; | ||||
| import ImmutablePureComponent from 'react-immutable-pure-component'; | ||||
| import ImmutablePropTypes from 'react-immutable-proptypes'; | ||||
| import IconButton from '../../../components/icon_button'; | ||||
| import { defineMessages, injectIntl } from 'react-intl'; | ||||
| import { removeFromListAdder, addToListAdder } from '../../../actions/lists'; | ||||
| 
 | ||||
| const messages = defineMessages({ | ||||
|   remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' }, | ||||
|   add: { id: 'lists.account.add', defaultMessage: 'Add to list' }, | ||||
| }); | ||||
| 
 | ||||
| const MapStateToProps = (state, { listId, added }) => ({ | ||||
|   list: state.get('lists').get(listId), | ||||
|   added: typeof added === 'undefined' ? state.getIn(['listAdder', 'lists', 'items']).includes(listId) : added, | ||||
| }); | ||||
| 
 | ||||
| const mapDispatchToProps = (dispatch, { listId }) => ({ | ||||
|   onRemove: () => dispatch(removeFromListAdder(listId)), | ||||
|   onAdd: () => dispatch(addToListAdder(listId)), | ||||
| }); | ||||
| 
 | ||||
| export default @connect(MapStateToProps, mapDispatchToProps) | ||||
| @injectIntl | ||||
| class List extends ImmutablePureComponent { | ||||
| 
 | ||||
|   static propTypes = { | ||||
|     list: ImmutablePropTypes.map.isRequired, | ||||
|     intl: PropTypes.object.isRequired, | ||||
|     onRemove: PropTypes.func.isRequired, | ||||
|     onAdd: PropTypes.func.isRequired, | ||||
|     added: PropTypes.bool, | ||||
|   }; | ||||
| 
 | ||||
|   static defaultProps = { | ||||
|     added: false, | ||||
|   }; | ||||
| 
 | ||||
|   render () { | ||||
|     const { list, intl, onRemove, onAdd, added } = this.props; | ||||
| 
 | ||||
|     let button; | ||||
| 
 | ||||
|     if (added) { | ||||
|       button = <IconButton icon='times' title={intl.formatMessage(messages.remove)} onClick={onRemove} />; | ||||
|     } else { | ||||
|       button = <IconButton icon='plus' title={intl.formatMessage(messages.add)} onClick={onAdd} />; | ||||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <div className='list'> | ||||
|         <div className='list__wrapper'> | ||||
|           <div className='list__display-name'> | ||||
|             <i className='fa fa-fw fa-list-ul column-link__icon' /> | ||||
|             {list.get('title')} | ||||
|           </div> | ||||
| 
 | ||||
|           <div className='account__relationship'> | ||||
|             {button} | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										73
									
								
								app/javascript/mastodon/features/list_adder/index.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								app/javascript/mastodon/features/list_adder/index.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | |||
| 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 { setupListAdder, resetListAdder } from '../../actions/lists'; | ||||
| import { createSelector } from 'reselect'; | ||||
| import List from './components/list'; | ||||
| import Account from './components/account'; | ||||
| import NewListForm from '../lists/components/new_list_form'; | ||||
| // hack
 | ||||
| 
 | ||||
| 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 => ({ | ||||
|   listIds: getOrderedLists(state).map(list=>list.get('id')), | ||||
| }); | ||||
| 
 | ||||
| const mapDispatchToProps = dispatch => ({ | ||||
|   onInitialize: accountId => dispatch(setupListAdder(accountId)), | ||||
|   onReset: () => dispatch(resetListAdder()), | ||||
| }); | ||||
| 
 | ||||
| export default @connect(mapStateToProps, mapDispatchToProps) | ||||
| @injectIntl | ||||
| class ListAdder extends ImmutablePureComponent { | ||||
| 
 | ||||
|   static propTypes = { | ||||
|     accountId: PropTypes.string.isRequired, | ||||
|     onClose: PropTypes.func.isRequired, | ||||
|     intl: PropTypes.object.isRequired, | ||||
|     onInitialize: PropTypes.func.isRequired, | ||||
|     onReset: PropTypes.func.isRequired, | ||||
|     listIds: ImmutablePropTypes.list.isRequired, | ||||
|   }; | ||||
| 
 | ||||
|   componentDidMount () { | ||||
|     const { onInitialize, accountId } = this.props; | ||||
|     onInitialize(accountId); | ||||
|   } | ||||
| 
 | ||||
|   componentWillUnmount () { | ||||
|     const { onReset } = this.props; | ||||
|     onReset(); | ||||
|   } | ||||
| 
 | ||||
|   render () { | ||||
|     const { accountId, listIds } = this.props; | ||||
| 
 | ||||
|     return ( | ||||
|       <div className='modal-root__modal list-adder'> | ||||
|         <div className='list-adder__account'> | ||||
|           <Account accountId={accountId} /> | ||||
|         </div> | ||||
| 
 | ||||
|         <NewListForm /> | ||||
| 
 | ||||
| 
 | ||||
|         <div className='list-adder__lists'> | ||||
|           {listIds.map(ListId => <List key={ListId} listId={ListId} />)} | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
| } | ||||
|  | @ -16,6 +16,7 @@ import { | |||
|   ReportModal, | ||||
|   EmbedModal, | ||||
|   ListEditor, | ||||
|   ListAdder, | ||||
| } from '../../../features/ui/util/async-components'; | ||||
| 
 | ||||
| const MODAL_COMPONENTS = { | ||||
|  | @ -30,6 +31,7 @@ const MODAL_COMPONENTS = { | |||
|   'EMBED': EmbedModal, | ||||
|   'LIST_EDITOR': ListEditor, | ||||
|   'FOCAL_POINT': () => Promise.resolve({ default: FocalPointModal }), | ||||
|   'LIST_ADDER':ListAdder, | ||||
| }; | ||||
| 
 | ||||
| export default class ModalRoot extends React.PureComponent { | ||||
|  |  | |||
|  | @ -129,3 +129,7 @@ export function EmbedModal () { | |||
| export function ListEditor () { | ||||
|   return import(/* webpackChunkName: "features/list_editor" */'../../list_editor'); | ||||
| } | ||||
| 
 | ||||
| export function ListAdder () { | ||||
|   return import(/*webpackChunkName: "features/list_adder" */'../../list_adder'); | ||||
| } | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "روبوت", | ||||
|   "account.block": "حظر @{name}", | ||||
|   "account.block_domain": "إخفاء كل شيئ قادم من إسم النطاق {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Robó", | ||||
|   "account.block": "Bloquiar a @{name}", | ||||
|   "account.block_domain": "Hide everything from {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Блокирай", | ||||
|   "account.block_domain": "Hide everything from {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Bloca @{name}", | ||||
|   "account.block_domain": "Amaga-ho tot de {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Bluccà @{name}", | ||||
|   "account.block_domain": "Piattà tuttu da {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Robot", | ||||
|   "account.block": "Zablokovat uživatele @{name}", | ||||
|   "account.block_domain": "Skrýt vše z {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blocio @{name}", | ||||
|   "account.block_domain": "Cuddio popeth rhag {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Robot", | ||||
|   "account.block": "Bloker @{name}", | ||||
|   "account.block_domain": "Skjul alt fra {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "@{name} blockieren", | ||||
|   "account.block_domain": "Alles von {domain} verstecken", | ||||
|  |  | |||
|  | @ -577,6 +577,9 @@ | |||
|         "defaultMessage": "Don't feature on profile", | ||||
|         "id": "account.unendorse" | ||||
|       }, | ||||
|       { | ||||
|         "id": "account.add_or_remove_from_list" | ||||
|       }, | ||||
|       { | ||||
|         "defaultMessage": "Information below may reflect the user's profile incompletely.", | ||||
|         "id": "account.disclaimer_full" | ||||
|  | @ -1444,6 +1447,19 @@ | |||
|     ], | ||||
|     "path": "app/javascript/mastodon/features/keyboard_shortcuts/index.json" | ||||
|   }, | ||||
|   { | ||||
|     "descriptors": [ | ||||
|       { | ||||
|         "defaultMessage": "Remove from list", | ||||
|         "id": "lists.account.remove" | ||||
|       }, | ||||
|       { | ||||
|         "defaultMessage": "Add to list", | ||||
|         "id": "lists.account.add" | ||||
|       } | ||||
|     ], | ||||
|     "path": "app/javascript/mastodon/features/list_adder/components/list.json" | ||||
|   }, | ||||
|   { | ||||
|     "descriptors": [ | ||||
|       { | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Μποτ", | ||||
|   "account.block": "Απόκλεισε τον/την @{name}", | ||||
|   "account.block_domain": "Απόκρυψε τα πάντα από το {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Block @{name}", | ||||
|   "account.block_domain": "Hide everything from {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Roboto", | ||||
|   "account.block": "Bloki @{name}", | ||||
|   "account.block_domain": "Kaŝi ĉion de {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Bloquear", | ||||
|   "account.block_domain": "Ocultar todo de {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blokeatu @{name}", | ||||
|   "account.block_domain": "Ezkutatu {domain} domeinuko guztia", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "ربات", | ||||
|   "account.block": "مسدودسازی @{name}", | ||||
|   "account.block_domain": "پنهانسازی همه چیز از سرور {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Botti", | ||||
|   "account.block": "Estä @{name}", | ||||
|   "account.block_domain": "Piilota kaikki sisältö verkkotunnuksesta {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Bloquer @{name}", | ||||
|   "account.block_domain": "Tout masquer venant de {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Bloquear @{name}", | ||||
|   "account.block_domain": "Ocultar calquer contido de {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "חסימת @{name}", | ||||
|   "account.block_domain": "להסתיר הכל מהקהילה {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blokiraj @{name}", | ||||
|   "account.block_domain": "Sakrij sve sa {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "@{name} letiltása", | ||||
|   "account.block_domain": "Minden elrejtése innen: {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Արգելափակել @{name}֊ին", | ||||
|   "account.block_domain": "Թաքցնել ամենը հետեւյալ տիրույթից՝ {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blokir @{name}", | ||||
|   "account.block_domain": "Sembunyikan segalanya dari {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blokusar @{name}", | ||||
|   "account.block_domain": "Hide everything from {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blocca @{name}", | ||||
|   "account.block_domain": "Nascondi tutto da {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "@{name}さんをブロック", | ||||
|   "account.block_domain": "{domain}全体を非表示", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "ბოტი", | ||||
|   "account.block": "დაბლოკე @{name}", | ||||
|   "account.block_domain": "დაიმალოს ყველაფერი დომენიდან {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "봇", | ||||
|   "account.block": "@{name}을 차단", | ||||
|   "account.block_domain": "{domain} 전체를 숨김", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blokkeer @{name}", | ||||
|   "account.block_domain": "Verberg alles van {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blokkér @{name}", | ||||
|   "account.block_domain": "Skjul alt fra {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Robòt", | ||||
|   "account.block": "Blocar @{name}", | ||||
|   "account.block_domain": "Tot amagar del domeni {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blokuj @{name}", | ||||
|   "account.block_domain": "Blokuj wszystko z {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Robô", | ||||
|   "account.block": "Bloquear @{name}", | ||||
|   "account.block_domain": "Esconder tudo de {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Bloquear @{name}", | ||||
|   "account.block_domain": "Esconder tudo do domínio {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blochează @{name}", | ||||
|   "account.block_domain": "Ascunde tot de la {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Бот", | ||||
|   "account.block": "Блокировать", | ||||
|   "account.block_domain": "Блокировать все с {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blokuj @{name}", | ||||
|   "account.block_domain": "Ukry všetko z {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Robot", | ||||
|   "account.block": "Blokiraj @{name}", | ||||
|   "account.block_domain": "Skrij vse iz {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Blokiraj korisnika @{name}", | ||||
|   "account.block_domain": "Sakrij sve sa domena {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Бот", | ||||
|   "account.block": "Блокирај @{name}", | ||||
|   "account.block_domain": "Сакриј све са домена {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Robot", | ||||
|   "account.block": "Blockera @{name}", | ||||
|   "account.block_domain": "Dölj allt från {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Block @{name}", | ||||
|   "account.block_domain": "Hide everything from {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "బాట్", | ||||
|   "account.block": "@{name} ను బ్లాక్ చేయి", | ||||
|   "account.block_domain": "{domain} నుంచి అన్నీ దాచిపెట్టు", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Block @{name}", | ||||
|   "account.block_domain": "Hide everything from {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Bot", | ||||
|   "account.block": "Engelle @{name}", | ||||
|   "account.block_domain": "Hide everything from {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "Бот", | ||||
|   "account.block": "Заблокувати @{name}", | ||||
|   "account.block_domain": "Заглушити {domain}", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "机器人", | ||||
|   "account.block": "屏蔽 @{name}", | ||||
|   "account.block_domain": "隐藏来自 {domain} 的内容", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "機械人", | ||||
|   "account.block": "封鎖 @{name}", | ||||
|   "account.block_domain": "隱藏來自 {domain} 的一切文章", | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| { | ||||
|   "account.add_or_remove_from_list": "Add or Remove from lists", | ||||
|   "account.badges.bot": "機器人", | ||||
|   "account.block": "封鎖 @{name}", | ||||
|   "account.block_domain": "隱藏來自 {domain} 的一切嘟文", | ||||
|  |  | |||
|  | @ -25,6 +25,7 @@ import height_cache from './height_cache'; | |||
| import custom_emojis from './custom_emojis'; | ||||
| import lists from './lists'; | ||||
| import listEditor from './list_editor'; | ||||
| import listAdder from './list_adder'; | ||||
| import filters from './filters'; | ||||
| import conversations from './conversations'; | ||||
| import suggestions from './suggestions'; | ||||
|  | @ -56,6 +57,7 @@ const reducers = { | |||
|   custom_emojis, | ||||
|   lists, | ||||
|   listEditor, | ||||
|   listAdder, | ||||
|   filters, | ||||
|   conversations, | ||||
|   suggestions, | ||||
|  |  | |||
							
								
								
									
										47
									
								
								app/javascript/mastodon/reducers/list_adder.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/javascript/mastodon/reducers/list_adder.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; | ||||
| import { | ||||
|   LIST_ADDER_RESET, | ||||
|   LIST_ADDER_SETUP, | ||||
|   LIST_ADDER_LISTS_FETCH_REQUEST, | ||||
|   LIST_ADDER_LISTS_FETCH_SUCCESS, | ||||
|   LIST_ADDER_LISTS_FETCH_FAIL, | ||||
|   LIST_EDITOR_ADD_SUCCESS, | ||||
|   LIST_EDITOR_REMOVE_SUCCESS, | ||||
| } from '../actions/lists'; | ||||
| 
 | ||||
| const initialState = ImmutableMap({ | ||||
|   accountId: null, | ||||
| 
 | ||||
|   lists: ImmutableMap({ | ||||
|     items: ImmutableList(), | ||||
|     loaded: false, | ||||
|     isLoading: false, | ||||
|   }), | ||||
| }); | ||||
| 
 | ||||
| export default function listAdderReducer(state = initialState, action) { | ||||
|   switch(action.type) { | ||||
|   case LIST_ADDER_RESET: | ||||
|     return initialState; | ||||
|   case LIST_ADDER_SETUP: | ||||
|     return state.withMutations(map => { | ||||
|       map.set('accountId', action.account.get('id')); | ||||
|     }); | ||||
|   case LIST_ADDER_LISTS_FETCH_REQUEST: | ||||
|     return state.setIn(['lists', 'isLoading'], true); | ||||
|   case LIST_ADDER_LISTS_FETCH_FAIL: | ||||
|     return state.setIn(['lists', 'isLoading'], false); | ||||
|   case LIST_ADDER_LISTS_FETCH_SUCCESS: | ||||
|     return state.update('lists', lists => lists.withMutations(map => { | ||||
|       map.set('isLoading', false); | ||||
|       map.set('loaded', true); | ||||
|       map.set('items', ImmutableList(action.lists.map(item => item.id))); | ||||
|     })); | ||||
|   case LIST_EDITOR_ADD_SUCCESS: | ||||
|     return state.updateIn(['lists', 'items'], list => list.unshift(action.listId)); | ||||
|   case LIST_EDITOR_REMOVE_SUCCESS: | ||||
|     return state.updateIn(['lists', 'items'], list => list.filterNot(item => item === action.listId)); | ||||
|   default: | ||||
|     return state; | ||||
|   } | ||||
| }; | ||||
|  | @ -5344,6 +5344,47 @@ noscript { | |||
|   } | ||||
| } | ||||
| 
 | ||||
| .list-adder { | ||||
|   background: $ui-base-color; | ||||
|   flex-direction: column; | ||||
|   border-radius: 8px; | ||||
|   box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); | ||||
|   width: 380px; | ||||
|   overflow: hidden; | ||||
| 
 | ||||
|   @media screen and (max-width: 420px) { | ||||
|     width: 90%; | ||||
|   } | ||||
| 
 | ||||
|   &__account { | ||||
|     background: lighten($ui-base-color, 13%); | ||||
|   } | ||||
| 
 | ||||
|   &__lists { | ||||
|     background: lighten($ui-base-color, 13%); | ||||
|     height: 50vh; | ||||
|     border-radius: 0 0 8px 8px; | ||||
|     overflow-y: auto; | ||||
|   } | ||||
| 
 | ||||
|   .list { | ||||
|     padding: 10px; | ||||
|     border-bottom: 1px solid lighten($ui-base-color, 8%); | ||||
|   } | ||||
| 
 | ||||
|   .list__wrapper { | ||||
|     display: flex; | ||||
|   } | ||||
| 
 | ||||
|   .list__display-name { | ||||
|     flex: 1 1 auto; | ||||
|     overflow: hidden; | ||||
|     text-decoration: none; | ||||
|     font-size: 16px; | ||||
|     padding: 10px; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .focal-point-modal { | ||||
|   max-width: 80vw; | ||||
|   max-height: 80vh; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue