add and remove muted words, filters
This commit is contained in:
parent
bdd9204b3c
commit
69184ef97c
5 changed files with 199 additions and 42 deletions
|
@ -1,4 +1,5 @@
|
||||||
import api from '../api';
|
import api from '../api';
|
||||||
|
import { showAlert } from 'soapbox/actions/alerts';
|
||||||
|
|
||||||
export const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST';
|
export const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST';
|
||||||
export const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS';
|
export const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS';
|
||||||
|
@ -8,6 +9,10 @@ export const FILTERS_CREATE_REQUEST = 'FILTERS_CREATE_REQUEST';
|
||||||
export const FILTERS_CREATE_SUCCESS = 'FILTERS_CREATE_SUCCESS';
|
export const FILTERS_CREATE_SUCCESS = 'FILTERS_CREATE_SUCCESS';
|
||||||
export const FILTERS_CREATE_FAIL = 'FILTERS_CREATE_FAIL';
|
export const FILTERS_CREATE_FAIL = 'FILTERS_CREATE_FAIL';
|
||||||
|
|
||||||
|
export const FILTERS_DELETE_REQUEST = 'FILTERS_DELETE_REQUEST';
|
||||||
|
export const FILTERS_DELETE_SUCCESS = 'FILTERS_DELETE_SUCCESS';
|
||||||
|
export const FILTERS_DELETE_FAIL = 'FILTERS_DELETE_FAIL';
|
||||||
|
|
||||||
export const fetchFilters = () => (dispatch, getState) => {
|
export const fetchFilters = () => (dispatch, getState) => {
|
||||||
if (!getState().get('me')) return;
|
if (!getState().get('me')) return;
|
||||||
|
|
||||||
|
@ -31,13 +36,33 @@ export const fetchFilters = () => (dispatch, getState) => {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createFilter(params) {
|
export function createFilter(phrase, expires_at, context, whole_word, irreversible) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch({ type: FILTERS_CREATE_REQUEST });
|
dispatch({ type: FILTERS_CREATE_REQUEST });
|
||||||
return api(getState).post('/api/v1/filters', params).then(response => {
|
return api(getState).post('/api/v1/filters', {
|
||||||
|
phrase,
|
||||||
|
context,
|
||||||
|
irreversible,
|
||||||
|
whole_word,
|
||||||
|
expires_at,
|
||||||
|
}).then(response => {
|
||||||
dispatch({ type: FILTERS_CREATE_SUCCESS, filter: response.data });
|
dispatch({ type: FILTERS_CREATE_SUCCESS, filter: response.data });
|
||||||
|
dispatch(showAlert('', 'Filter added'));
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch({ type: FILTERS_CREATE_FAIL, error });
|
dispatch({ type: FILTERS_CREATE_FAIL, error });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function deleteFilter(id) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
dispatch({ type: FILTERS_DELETE_REQUEST });
|
||||||
|
return api(getState).delete('/api/v1/filters/'+id).then(response => {
|
||||||
|
dispatch({ type: FILTERS_DELETE_SUCCESS, filter: response.data });
|
||||||
|
dispatch(showAlert('', 'Filter deleted'));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({ type: FILTERS_DELETE_FAIL, error });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -4,23 +4,26 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
import { fetchFilters, createFilter } from '../../actions/filters';
|
import { fetchFilters, createFilter, deleteFilter } from '../../actions/filters';
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
import ScrollableList from '../../components/scrollable_list';
|
||||||
import Button from 'soapbox/components/button';
|
import Button from 'soapbox/components/button';
|
||||||
import {
|
import {
|
||||||
SimpleForm,
|
SimpleForm,
|
||||||
SimpleInput,
|
SimpleInput,
|
||||||
FieldsGroup,
|
FieldsGroup,
|
||||||
TextInput,
|
|
||||||
SelectDropdown,
|
SelectDropdown,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
} from 'soapbox/features/forms';
|
} from 'soapbox/features/forms';
|
||||||
import { showAlert } from 'soapbox/actions/alerts';
|
import { showAlert } from 'soapbox/actions/alerts';
|
||||||
|
import Icon from 'soapbox/components/icon';
|
||||||
|
import ColumnSubheading from '../ui/components/column_subheading';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.filters', defaultMessage: 'Muted words' },
|
heading: { id: 'column.filters', defaultMessage: 'Muted words' },
|
||||||
|
subheading_add_new: { id: 'column.filters.subheading_add_new', defaultMessage: 'Add New Filter' },
|
||||||
keyword: { id: 'column.filters.keyword', defaultMessage: 'Keyword or phrase' },
|
keyword: { id: 'column.filters.keyword', defaultMessage: 'Keyword or phrase' },
|
||||||
expires: { id: 'column.filters.expires', defaultMessage: 'Expire after' },
|
expires: { id: 'column.filters.expires', defaultMessage: 'Expire after' },
|
||||||
|
expires_hint: { id: 'column.filters.expires_hint', defaultMessage: 'Expiration dates are not currently supported' },
|
||||||
home_timeline: { id: 'column.filters.home_timeline', defaultMessage: 'Home timeline' },
|
home_timeline: { id: 'column.filters.home_timeline', defaultMessage: 'Home timeline' },
|
||||||
public_timeline: { id: 'column.filters.public_timeline', defaultMessage: 'Public timeline' },
|
public_timeline: { id: 'column.filters.public_timeline', defaultMessage: 'Public timeline' },
|
||||||
notifications: { id: 'column.filters.notifications', defaultMessage: 'Notifications' },
|
notifications: { id: 'column.filters.notifications', defaultMessage: 'Notifications' },
|
||||||
|
@ -29,17 +32,20 @@ const messages = defineMessages({
|
||||||
drop_hint: { id: 'column.filters.drop_hint', defaultMessage: 'Filtered posts will disappear irreversibly, even if filter is later removed' },
|
drop_hint: { id: 'column.filters.drop_hint', defaultMessage: 'Filtered posts will disappear irreversibly, even if filter is later removed' },
|
||||||
whole_word_header: { id: 'column.filters.whole_word_header', defaultMessage: 'Whole word' },
|
whole_word_header: { id: 'column.filters.whole_word_header', defaultMessage: 'Whole word' },
|
||||||
whole_word_hint: { id: 'column.filters.whole_word_hint', defaultMessage: 'When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word' },
|
whole_word_hint: { id: 'column.filters.whole_word_hint', defaultMessage: 'When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word' },
|
||||||
add_new: { id: 'column.filters.add_new', defaultMessage: 'Add New Muted Word' },
|
add_new: { id: 'column.filters.add_new', defaultMessage: 'Add New Filter' },
|
||||||
error: { id: 'column.filters.error', defaultMessage: 'Error adding filter' },
|
create_error: { id: 'column.filters.create_error', defaultMessage: 'Error adding filter' },
|
||||||
|
delete_error: { id: 'column.filters.delete_error', defaultMessage: 'Error deleting filter' },
|
||||||
|
subheading_filters: { id: 'column.filters.subheading_filters', defaultMessage: 'Current Filters' },
|
||||||
|
delete: { id: 'column.filters.delete', defaultMessage: 'Delete' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const expirations = {
|
const expirations = {
|
||||||
1800: 'Never',
|
null: 'Never',
|
||||||
3600: '30 minutes',
|
// 3600: '30 minutes',
|
||||||
21600: '1 hour',
|
// 21600: '1 hour',
|
||||||
43200: '12 hours',
|
// 43200: '12 hours',
|
||||||
86400 : '1 day',
|
// 86400 : '1 day',
|
||||||
604800: '1 week',
|
// 604800: '1 week',
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
@ -60,12 +66,10 @@ class Filters extends ImmutablePureComponent {
|
||||||
state = {
|
state = {
|
||||||
phrase: '',
|
phrase: '',
|
||||||
expires_at: '',
|
expires_at: '',
|
||||||
context: {
|
home_timeline: true,
|
||||||
home_timeline: false,
|
public_timeline: false,
|
||||||
public_timeline: false,
|
notifications: false,
|
||||||
notifications: false,
|
conversations: false,
|
||||||
conversations: false,
|
|
||||||
},
|
|
||||||
irreversible: false,
|
irreversible: false,
|
||||||
whole_word: true,
|
whole_word: true,
|
||||||
}
|
}
|
||||||
|
@ -89,12 +93,37 @@ class Filters extends ImmutablePureComponent {
|
||||||
|
|
||||||
handleAddNew = e => {
|
handleAddNew = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const { intl, dispatch } = this.state;
|
const { intl, dispatch } = this.props;
|
||||||
const { phrase, context, whole_word, expires_at } = this.state;
|
const { phrase, whole_word, expires_at, irreversible } = this.state;
|
||||||
dispatch(createFilter(phrase, context, whole_word, expires_at)).then(response => {
|
const { home_timeline, public_timeline, notifications, conversations } = this.state;
|
||||||
dispatch(fetchFilters());
|
let context = [];
|
||||||
|
|
||||||
|
if (home_timeline) {
|
||||||
|
context.push('home');
|
||||||
|
};
|
||||||
|
if (public_timeline) {
|
||||||
|
context.push('public');
|
||||||
|
};
|
||||||
|
if (notifications) {
|
||||||
|
context.push('notifications');
|
||||||
|
};
|
||||||
|
if (conversations) {
|
||||||
|
context.push('thread');
|
||||||
|
};
|
||||||
|
|
||||||
|
dispatch(createFilter(phrase, expires_at, context, whole_word, irreversible)).then(response => {
|
||||||
|
return dispatch(fetchFilters());
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch(showAlert('', intl.formatMessage(messages.error)));
|
dispatch(showAlert('', intl.formatMessage(messages.create_error)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFilterDelete = e => {
|
||||||
|
const { intl, dispatch } = this.props;
|
||||||
|
dispatch(deleteFilter(e.currentTarget.dataset.value)).then(response => {
|
||||||
|
return dispatch(fetchFilters());
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(showAlert('', intl.formatMessage(messages.delete_error)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,14 +133,10 @@ class Filters extends ImmutablePureComponent {
|
||||||
const emptyMessage = <FormattedMessage id='empty_column.filters' defaultMessage="You haven't created any muted words yet." />;
|
const emptyMessage = <FormattedMessage id='empty_column.filters' defaultMessage="You haven't created any muted words yet." />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column icon='filter' heading={intl.formatMessage(messages.heading)} backBtnSlim>
|
<Column className='filter-settings-panel' icon='filter' heading={intl.formatMessage(messages.heading)} backBtnSlim>
|
||||||
|
<ColumnSubheading text={intl.formatMessage(messages.subheading_add_new)} />
|
||||||
<SimpleForm>
|
<SimpleForm>
|
||||||
<div className='filter-settings-panel'>
|
<div className='filter-settings-panel'>
|
||||||
<h1 className='filter-settings-panel__add-new'>
|
|
||||||
<FormattedMessage id='filters.add_new_title' defaultMessage='Add New Filter' />
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<fieldset disabled={false}>
|
<fieldset disabled={false}>
|
||||||
<FieldsGroup>
|
<FieldsGroup>
|
||||||
|
|
||||||
|
@ -119,12 +144,13 @@ class Filters extends ImmutablePureComponent {
|
||||||
label={intl.formatMessage(messages.keyword)}
|
label={intl.formatMessage(messages.keyword)}
|
||||||
required
|
required
|
||||||
type='text'
|
type='text'
|
||||||
name='custom_filter_phrase'
|
name='phrase'
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SelectDropdown
|
<SelectDropdown
|
||||||
label={intl.formatMessage(messages.expires)}
|
label={intl.formatMessage(messages.expires)}
|
||||||
|
hint={intl.formatMessage(messages.expires_hint)}
|
||||||
items={expirations}
|
items={expirations}
|
||||||
defaultValue={expirations.never}
|
defaultValue={expirations.never}
|
||||||
onChange={this.handleSelectChange}
|
onChange={this.handleSelectChange}
|
||||||
|
@ -141,25 +167,25 @@ class Filters extends ImmutablePureComponent {
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={intl.formatMessage(messages.home_timeline)}
|
label={intl.formatMessage(messages.home_timeline)}
|
||||||
name='home_timeline'
|
name='home_timeline'
|
||||||
checked={this.state.context.home_timeline}
|
checked={this.state.home_timeline}
|
||||||
onChange={this.handleCheckboxChange}
|
onChange={this.handleCheckboxChange}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={intl.formatMessage(messages.public_timeline)}
|
label={intl.formatMessage(messages.public_timeline)}
|
||||||
name='public_timeline'
|
name='public_timeline'
|
||||||
checked={this.state.context.public_timeline}
|
checked={this.state.public_timeline}
|
||||||
onChange={this.handleCheckboxChange}
|
onChange={this.handleCheckboxChange}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={intl.formatMessage(messages.notifications)}
|
label={intl.formatMessage(messages.notifications)}
|
||||||
name='notifications'
|
name='notifications'
|
||||||
checked={this.state.context.notifications}
|
checked={this.state.notifications}
|
||||||
onChange={this.handleCheckboxChange}
|
onChange={this.handleCheckboxChange}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={intl.formatMessage(messages.conversations)}
|
label={intl.formatMessage(messages.conversations)}
|
||||||
name='conversations'
|
name='conversations'
|
||||||
checked={this.state.context.conversations}
|
checked={this.state.conversations}
|
||||||
onChange={this.handleCheckboxChange}
|
onChange={this.handleCheckboxChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -183,16 +209,46 @@ class Filters extends ImmutablePureComponent {
|
||||||
</FieldsGroup>
|
</FieldsGroup>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<Button className='button button-primary setup' text={intl.formatMessage(messages.add_new)} onClick={this.props.handleAddNew} />
|
<Button className='button button-primary setup' text={intl.formatMessage(messages.add_new)} onClick={this.handleAddNew} />
|
||||||
|
|
||||||
|
<ColumnSubheading text={intl.formatMessage(messages.subheading_filters)} />
|
||||||
|
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='mutes'
|
scrollKey='filters'
|
||||||
onLoadMore={this.handleLoadMore}
|
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
>
|
>
|
||||||
{filters.map((filter, i) => (
|
{filters.map((filter, i) => (
|
||||||
<div key={i} className='backup_code'>
|
<div key={i} className='filter__container'>
|
||||||
<div className='backup_code'>{filter}</div>
|
<div className='filter__details'>
|
||||||
|
<div className='filter__phrase'>
|
||||||
|
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_phrase_label' defaultMessage='Keyword or phrase:' /></span>
|
||||||
|
<span className='filter__list-value'>{filter.get('phrase')}</span>
|
||||||
|
</div>
|
||||||
|
<div className='filter__contexts'>
|
||||||
|
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_context_label' defaultMessage='Filter contexts:' /></span>
|
||||||
|
<span className='filter__list-value'>
|
||||||
|
{filter.get('context').map((context, i) => (
|
||||||
|
<span key={i} className='context'>{context}</span>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className='filter__details'>
|
||||||
|
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_details_label' defaultMessage='Filter settings:' /></span>
|
||||||
|
<span className='filter__list-value'>
|
||||||
|
{filter.get('irreversible') ?
|
||||||
|
<span><FormattedMessage id='filters.filters_list_drop' defaultMessage='Drop' /></span> :
|
||||||
|
<span><FormattedMessage id='filters.filters_list_hide' defaultMessage='Hide' /></span>
|
||||||
|
}
|
||||||
|
{filter.get('whole_word') &&
|
||||||
|
<span><FormattedMessage id='filters.filters_list_whole-word' defaultMessage='Whole word' /></span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='filter__delete' role='button' tabIndex='0' onClick={this.handleFilterDelete} data-value={filter.get('id')} aria-label={intl.formatMessage(messages.delete)}>
|
||||||
|
<Icon className='filter__delete-icon' id='times' size={40} />
|
||||||
|
<span className='filter__delete-label'><FormattedMessage id='filters.filters_list_delete' defaultMessage='Delete' /></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
|
|
|
@ -36,7 +36,7 @@ InputContainer.propTypes = {
|
||||||
extraClass: PropTypes.string,
|
extraClass: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LabelInputContainer = ({ label, children, ...props }) => {
|
export const LabelInputContainer = ({ label, hint, children, ...props }) => {
|
||||||
const [id] = useState(uuidv4());
|
const [id] = useState(uuidv4());
|
||||||
const childrenWithProps = React.Children.map(children, child => (
|
const childrenWithProps = React.Children.map(children, child => (
|
||||||
React.cloneElement(child, { id: id, key: id })
|
React.cloneElement(child, { id: id, key: id })
|
||||||
|
@ -48,12 +48,14 @@ export const LabelInputContainer = ({ label, children, ...props }) => {
|
||||||
<div className='label_input__wrapper'>
|
<div className='label_input__wrapper'>
|
||||||
{childrenWithProps}
|
{childrenWithProps}
|
||||||
</div>
|
</div>
|
||||||
|
{hint && <span className='hint'>{hint}</span>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
LabelInputContainer.propTypes = {
|
LabelInputContainer.propTypes = {
|
||||||
label: FormPropTypes.label.isRequired,
|
label: FormPropTypes.label.isRequired,
|
||||||
|
hint: PropTypes.node,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -223,11 +225,12 @@ export class SelectDropdown extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
label: FormPropTypes.label,
|
label: FormPropTypes.label,
|
||||||
|
hint: PropTypes.node,
|
||||||
items: PropTypes.object.isRequired,
|
items: PropTypes.object.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { label, items, ...props } = this.props;
|
const { label, hint, items, ...props } = this.props;
|
||||||
|
|
||||||
const optionElems = Object.keys(items).map(item => (
|
const optionElems = Object.keys(items).map(item => (
|
||||||
<option key={item} value={item}>{items[item]}</option>
|
<option key={item} value={item}>{items[item]}</option>
|
||||||
|
@ -236,7 +239,7 @@ export class SelectDropdown extends ImmutablePureComponent {
|
||||||
const selectElem = <select {...props}>{optionElems}</select>;
|
const selectElem = <select {...props}>{optionElems}</select>;
|
||||||
|
|
||||||
return label ? (
|
return label ? (
|
||||||
<LabelInputContainer label={label}>{selectElem}</LabelInputContainer>
|
<LabelInputContainer label={label} hint={hint}>{selectElem}</LabelInputContainer>
|
||||||
) : selectElem;
|
) : selectElem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,3 +72,4 @@
|
||||||
@import 'components/video-player';
|
@import 'components/video-player';
|
||||||
@import 'components/audio-player';
|
@import 'components/audio-player';
|
||||||
@import 'components/profile_hover_card';
|
@import 'components/profile_hover_card';
|
||||||
|
@import 'components/filters';
|
||||||
|
|
72
app/styles/components/filters.scss
Normal file
72
app/styles/components/filters.scss
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
.filter-settings-panel {
|
||||||
|
h1 {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1.25;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
font-weight: 400;
|
||||||
|
margin: 20px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list article {
|
||||||
|
border-bottom: 1px solid var(--primary-text-color--faint);
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter__container {
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
.filter__phrase, .filter__contexts, .filter__details {
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.filter__list-label {
|
||||||
|
padding-right: 5px;
|
||||||
|
color: var(--primary-text-color--faint);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.filter__list-value span {
|
||||||
|
padding-right: 5px;
|
||||||
|
text-transform: capitalize;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: ',';
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter__delete {
|
||||||
|
display: flex;
|
||||||
|
margin: 10px;
|
||||||
|
align-items: baseline;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 20px;
|
||||||
|
|
||||||
|
span.filter__delete-label {
|
||||||
|
color: var(--primary-text-color--faint);
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter__delete-icon {
|
||||||
|
background: none;
|
||||||
|
color: var(--primary-text-color--faint);
|
||||||
|
padding: 0 5px;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue