Another large update for all components

reorganization, linting, updating file imports, consolidation
warning: there will be errors in this commit
todo: update webpack, add missing styles, scss files, consolidate group page components.
This commit is contained in:
mgabdev
2019-08-09 12:06:27 -04:00
parent 280dc51d85
commit 3d509c84a2
183 changed files with 4802 additions and 2361 deletions

View File

@@ -28,12 +28,13 @@ class Account extends ImmutablePureComponent {
onFollow: PropTypes.func.isRequired,
onBlock: PropTypes.func.isRequired,
onMute: PropTypes.func.isRequired,
onMuteNotifications: PropTypes.func.isRequired,
onMuteNotifications: PropTypes.func,
intl: PropTypes.object.isRequired,
hidden: PropTypes.bool,
actionIcon: PropTypes.string,
actionTitle: PropTypes.string,
onActionClick: PropTypes.func,
displayOnly: PropTypes.bool,
};
handleFollow = () => {
@@ -61,7 +62,7 @@ class Account extends ImmutablePureComponent {
}
render() {
const { account, intl, hidden, onActionClick, actionIcon, actionTitle } = this.props;
const { account, intl, hidden, onActionClick, actionIcon, actionTitle, displayOnly } = this.props;
if (!account) {
return <div />;
@@ -109,6 +110,21 @@ class Account extends ImmutablePureComponent {
}
}
if (displayOnly) {
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>
);
}
return (
<div className='account'>
<div className='account__wrapper'>

View File

@@ -17,7 +17,7 @@
display: block;
color: $primary-text-color;
@include text-overflow(nowrap);
@include text-overflow;
}
}

View File

@@ -0,0 +1,39 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Avatar from '../avatar';
import DisplayName from '../display_name';
import { makeGetAccount } from '../../selectors';
import './autosuggest_account.scss';
const makeMapStateToProps = () => {
const getAccount = makeGetAccount();
const mapStateToProps = (state, { id }) => ({
account: getAccount(state, id),
});
return mapStateToProps;
};
export default @connect(makeMapStateToProps)
class AutosuggestAccount extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map.isRequired,
};
render () {
const { account } = this.props;
return (
<div className='autosuggest-account' title={account.get('acct')}>
<div className='autosuggest-account__icon'>
<Avatar account={account} size={18} />
</div>
<DisplayName account={account} />
</div>
);
}
}

View File

@@ -0,0 +1,15 @@
.autosuggest-account {
@include flex(flex-start, center, row);
@include text-sizing(14px, 400, 18px);
&__icon {
display: block;
margin-right: 8px;
@include size(16px);
}
.display-name__account {
color: $lighter-text-color;
}
}

View File

@@ -0,0 +1 @@
export { default } from './autosuggest_account';

View File

@@ -2,7 +2,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import classNames from 'classnames';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Textarea from 'react-textarea-autosize';
import AutosuggestAccount from '../../features/compose/components/autosuggest_account';
import AutosuggestAccount from '../autosuggest_account';
import AutosuggestEmoji from '../autosuggest_emoji';
import { isRtl } from '../../utils/rtl';
import { textAtCursorMatchesToken } from '../../utils/cursor_token_match';

View File

@@ -12,7 +12,7 @@
@include border-design(transparent, 10px, 4px);
@include text-sizing(14px, 500, 36px, center);
@include size(auto, 36px);
@include text-overflow(nowrap);
@include text-overflow;
&:active,
&:focus,

View File

@@ -63,33 +63,6 @@
}
}
&__links {
.text-btn {
margin-right: 10px;
}
}
&__setting-btn {
padding: 0 10px;
&:last-child {
padding-right: 0;
}
&:hover {
color: $darker-text-color;
text-decoration: underline;
}
&--link {
text-decoration: none;
.fa {
margin-left: 10px;
}
}
}
&__button {
margin-left: auto;
cursor: pointer;

View File

@@ -0,0 +1,40 @@
import { Link } from 'react-router-dom';
import classNames from 'classnames';
import Icon from '../icon';
import './column_header_setting_button.scss';
export default class ColumnHeaderSettingButton extends PureComponent {
static propTypes = {
title: PropTypes.node.isRequired,
icon: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired,
to: PropTypes.string,
};
render () {
const { title, icon, to } = this.props;
const classes = classNames('column-header-setting-btn', {
'column-header-setting-btn--link': !!to
});
if (to) {
return (
<Link to={to} className={classes}>
{title}
<Icon id={icon} />
</Link>
)
}
return (
<button className={classes} tabIndex='0' onClick={this.props.onClick}>
<Icon id={icon} />
{title}
</button>
);
}
}

View File

@@ -0,0 +1,28 @@
.column-header-setting-btn {
display: inline-block;
padding: 0;
font-family: inherit;
font-size: inherit;
color: inherit;
border: 0;
background: transparent;
cursor: pointer;
padding: 0 10px;
&:last-child {
padding-right: 0;
}
&:hover {
color: $darker-text-color;
text-decoration: underline;
}
&--link {
text-decoration: none;
.fa {
margin-left: 10px;
}
}
}

View File

@@ -0,0 +1 @@
export { default } from './column_header_setting_button';

View File

@@ -0,0 +1,56 @@
import Button from '../button';
import './column_inline_form.scss';
export default class ColumnInlineForm extends PureComponent {
static propTypes = {
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
label: PropTypes.string.isRequired,
btnTitle: PropTypes.string.isRequired,
disabled: PropTypes.bool,
};
handleChange = e => {
this.props.onChange(e.target.value);
}
handleSubmit = e => {
e.preventDefault();
this.props.onSubmit();
}
handleClick = () => {
this.props.onSubmit();
}
render() {
const { value, label, btnTitle, disabled } = this.props;
return (
<form className='column-inline-form' onSubmit={this.handleSubmit}>
<label className='column-inline-form__block'>
<span className='column-inline-form__title'>{label}</span>
<input
className='column-inline-form__input'
value={value}
disabled={disabled}
onChange={this.handleChange}
placeholder={label}
/>
</label>
<Button
className='column-inline-form__btn'
disabled={disabled}
onClick={this.handleClick}
>
{btnTitle}
</Button>
</form>
);
}
}

View File

@@ -0,0 +1,28 @@
.column-inline-form {
padding: 7px 5px 7px 15px;
background: lighten($ui-base-color, 4%);
@include flex(flex-start, center);
&__block {
flex: 1 1 auto;
}
&__title {
}
&__input {
width: 100%;
margin-bottom: 6px;
&:focus {
outline: 0;
}
}
&__btn {
flex: 0 0 auto;
margin: 0 5px;
}
}

View File

@@ -0,0 +1 @@
export { default } from './column_inline_form';

View File

@@ -1,6 +1,8 @@
import { Link } from 'react-router-dom';
import Icon from '../../components/icon';
import './column_link.scss';
export default class ColumnLink extends PureComponent {
static propTypes = {

View File

@@ -0,0 +1,16 @@
import './column_settings_heading.scss';
export default class ColumnSettingsHeading extends PureComponent {
static propTypes = {
heading: PropTypes.object.isRequired,
id: PropTypes.string,
};
render() {
const { heading } = this.props;
return (
<span id={id} className='column-settings-heading'>{heading}</span>
)
}
}

View File

@@ -0,0 +1,7 @@
.column-settings-heading {
display: block;
color: $darker-text-color;
cursor: default;
font-weight: 500;
margin-bottom: 10px;
}

View File

@@ -0,0 +1 @@
export { default } from './column_settings_heading';

View File

@@ -11,6 +11,8 @@ export default class ColumnsArea extends PureComponent {
const { children } = this.props;
const layout = this.props.layout || {LEFT:null,RIGHT:null};
console.log("layout:", layout);
return (
<div className='page'>
<div className='page__columns'>

View File

@@ -71,7 +71,7 @@
text-transform: capitalize;
color: $gab-secondary-text;
@include text-overflow(nowrap);
@include text-overflow;
@include text-sizing(13px, 400, 26px);
&:focus,

View File

@@ -22,6 +22,7 @@ export default class IconButton extends PureComponent {
animate: PropTypes.bool,
overlay: PropTypes.bool,
tabIndex: PropTypes.string,
text: PropTypes.string,
};
static defaultProps = {
@@ -62,6 +63,7 @@ export default class IconButton extends PureComponent {
pressed,
tabIndex,
title,
text,
} = this.props;
const classes = classNames(className, 'icon-button', {
@@ -86,6 +88,7 @@ export default class IconButton extends PureComponent {
disabled={disabled}
>
<Icon id={icon} fixedWidth aria-hidden='true' />
{!!text && text}
</button>
);
}
@@ -105,6 +108,7 @@ export default class IconButton extends PureComponent {
disabled={disabled}
>
<Icon id={icon} style={{ transform: `rotate(${rotate}deg)` }} fixedWidth aria-hidden='true' />
{!!text && text}
</button>
)}
</Motion>

View File

@@ -1,6 +1,6 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import { is } from 'immutable';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { defineMessages, injectIntl } from 'react-intl';
import classNames from 'classnames';
import { decode } from 'blurhash';
import IconButton from '../icon_button';
@@ -11,6 +11,8 @@ import './media_gallery.scss';
const messages = defineMessages({
toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' },
warning: { id: 'status.sensitive_warning', defaultMessage: 'Sensitive content' },
hidden: { id: 'status.media_hidden', defaultMessage: 'Media hidden' },
});
class Item extends PureComponent {
@@ -308,11 +310,7 @@ class MediaGallery extends PureComponent {
spoilerButton = (
<button type='button' onClick={this.handleOpen} className='spoiler-button__overlay'>
<span className='spoiler-button__overlay__label'>
{
sensitive
? <FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' />
: <FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' />
}
{intl.formatMessage(sensitive ? messages.warning : messages.hidden)}
</span>
</button>
);

View File

@@ -1,7 +1,13 @@
import ImmutablePureComponent from 'react-immutable-pure-component';
import { FormattedMessage, injectIntl } from 'react-intl';
import { defineMessages, injectIntl } from 'react-intl';
import api from '../../../api'
const messages = defineMessages({
embed: { id: 'status.embed', defaultMessage: 'Embed' },
instructions: { id: 'embed.instructions', defaultMessage: 'Embed this status on your website by copying the code below.' },
preview: { id: 'embed.preview', defaultMessage: 'Here is what it will look like:' },
});
export default @injectIntl
class EmbedModal extends ImmutablePureComponent {
@@ -48,15 +54,15 @@ class EmbedModal extends ImmutablePureComponent {
}
render () {
const { oembed } = this.state;
const { oembed, intl } = this.state;
return (
<div className='modal-root__modal embed-modal'>
<h4><FormattedMessage id='status.embed' defaultMessage='Embed' /></h4>
<h4>{intl.formatMessage(messages.embed)}</h4>
<div className='embed-modal__container'>
<p className='hint'>
<FormattedMessage id='embed.instructions' defaultMessage='Embed this status on your website by copying the code below.' />
{intl.formatMessage(messages.instructions)}
</p>
<input
@@ -68,7 +74,7 @@ class EmbedModal extends ImmutablePureComponent {
/>
<p className='hint'>
<FormattedMessage id='embed.preview' defaultMessage='Here is what it will look like:' />
{intl.formatMessage(messages.preview)}
</p>
<iframe

View File

@@ -0,0 +1,59 @@
.embed-modal {
max-width: 80vw;
max-height: 80vh;
h4 {
padding: 30px;
font-weight: 500;
font-size: 16px;
text-align: center;
}
.embed-modal__container {
padding: 10px;
.hint {
margin-bottom: 15px;
}
.embed-modal__html {
outline: 0;
box-sizing: border-box;
display: block;
width: 100%;
border: none;
padding: 10px;
font-family: $font-monospace, monospace;
background: $ui-base-color;
color: $primary-text-color;
font-size: 14px;
margin: 0;
margin-bottom: 15px;
&::-moz-focus-inner {
border: 0;
}
&::-moz-focus-inner,
&:focus,
&:active {
outline: 0 !important;
}
&:focus {
background: lighten($ui-base-color, 4%);
}
@media screen and (max-width: 600px) {
font-size: 16px;
}
}
.embed-modal__iframe {
width: 400px;
max-width: 100%;
overflow: hidden;
border: 0;
}
}
}

View File

@@ -5,6 +5,8 @@ import { changeUploadCompose } from '../../../actions/compose';
import { getPointerPosition } from '../../../utils/element_position';
import ImageLoader from '../../image_loader';
import './focal_point_modal.scss';
const mapStateToProps = (state, { id }) => ({
media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id),
});
@@ -101,7 +103,7 @@ class FocalPointModal extends ImmutablePureComponent {
const height = media.getIn(['meta', 'original', 'height']) || null;
return (
<div className='modal-root__modal video-modal focal-point-modal'>
<div className='modal-root__modal focal-point-modal'>
<div className={classNames('focal-point', { dragging })} ref={this.setRef}>
<ImageLoader
previewSrc={media.get('preview_url')}

View File

@@ -0,0 +1,36 @@
.focal-point-modal {
position: relative;
@include max-size(80vw, 80vh);
}
.focal-point {
position: relative;
cursor: pointer;
overflow: hidden;
&.dragging {
cursor: move;
}
img {
margin: auto;
@include max-size(80vw, 80vh);
@include size(auto);
}
&__reticle {
position: absolute;
transform: translate(-50%, -50%);
background: url('/assets/images/reticle.png') no-repeat 0 0;
box-shadow: 0 0 0 9999em rgba($base-shadow-color, 0.35);
@include circle(100px);
}
&__overlay {
@include size(100%);
@include abs-position(0, auto, auto, 0);
}
}

View File

@@ -9,6 +9,8 @@ import IconButton from '../../icon_button';
import ImageLoader from '../../image_loader';
import Icon from '../../icon';
import './media_modal.scss';
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
previous: { id: 'lightbox.previous', defaultMessage: 'Previous' },

View File

@@ -0,0 +1,103 @@
.media-modal {
position: relative;
@include size(100%);
&__closer {
@include abs-position(0, 0, 0, 0);
}
&__navigation {
pointer-events: none;
transition: opacity 0.3s linear;
will-change: opacity;
@include abs-position(0, 0, 0, 0);
* {
pointer-events: auto;
}
&.media-modal__navigation--hidden {
opacity: 0;
* {
pointer-events: none;
}
}
}
&__nav {
background: rgba($base-overlay-background, 0.5);
box-sizing: border-box;
border: 0;
color: $primary-text-color;
cursor: pointer;
display: flex;
align-items: center;
font-size: 24px;
height: 20vmax;
margin: auto 0;
padding: 30px 15px;
@include abs-position(0, auto, 0, auto);
&--left {
left: 0;
}
&--right {
right: 0;
}
}
&__meta,
&__pagination {
width: 100%;
text-align: center;
pointer-events: none;
@include abs-position(auto, auto, 20px, 0);
}
&__meta {
&--shifted {
bottom: 62px;
}
a {
text-decoration: none;
font-weight: 500;
color: $ui-secondary-color;
&:hover,
&:focus,
&:active {
text-decoration: underline;
}
}
}
&__page-dot {
display: inline-block;
}
&__button {
background-color: $primary-text-color;
border-radius: 6px;
margin: 10px;
padding: 0;
border: 0;
font-size: 0;
@include size(12px);
&--active {
background-color: $highlight-text-color;
}
}
&__close {
@include abs-position(8px, 8px);
}
}

View File

@@ -1,5 +1,5 @@
import { injectIntl, FormattedMessage } from 'react-intl';
import Toggle from 'react-toggle';
import ToggleSwitch from '../../toggle_switch';
import Button from '../../button';
import { closeModal } from '../../../actions/modal';
import { muteAccount } from '../../../actions/accounts';
@@ -82,7 +82,7 @@ class MuteModal extends PureComponent {
<label htmlFor='mute-modal__hide-notifications-checkbox'>
<FormattedMessage id='mute_modal.hide_notifications' defaultMessage='Hide notifications from this user?' />
{' '}
<Toggle id='mute-modal__hide-notifications-checkbox' checked={notifications} onChange={this.toggleNotifications} />
<ToggleSwitch id='mute-modal__hide-notifications-checkbox' checked={notifications} onChange={this.toggleNotifications} />
</label>
</div>
</div>

View File

@@ -2,7 +2,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import { OrderedSet } from 'immutable';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Toggle from 'react-toggle';
import ToggleSwitch from '../../toggle_switch';
import { changeReportComment, changeReportForward, submitReport } from '../../../actions/reports';
import { expandAccountTimeline } from '../../../actions/timelines';
import { makeGetAccount } from '../../../selectors';
@@ -111,7 +111,7 @@ class ReportModal extends ImmutablePureComponent {
<p><FormattedMessage id='report.forward_hint' defaultMessage='The account is from another server. Send an anonymized copy of the report there as well?' /></p>
<div className='setting-toggle'>
<Toggle id='report-forward' checked={forward} disabled={isSubmitting} onChange={this.handleForwardChange} />
<ToggleSwitch id='report-forward' checked={forward} disabled={isSubmitting} onChange={this.handleForwardChange} />
<label htmlFor='report-forward' className='setting-toggle__label'><FormattedMessage id='report.forward' defaultMessage='Forward to {target}' values={{ target: domain }} /></label>
</div>
</div>

View File

@@ -26,7 +26,7 @@
cursor: default;
color: #fff;
@include text-overflow(nowrap);
@include text-overflow;
body.theme-gabsocial-light & {
color: $gab-default-text-light;

View File

@@ -0,0 +1,92 @@
import Overlay from 'react-overlays/lib/Overlay';
import Icon from '../icon';
import SearchPopout from '../search_popout';
export default class Search extends PureComponent {
static contextTypes = {
router: PropTypes.object.isRequired,
};
static propTypes = {
value: PropTypes.string.isRequired,
submitted: PropTypes.bool,
onChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
onClear: PropTypes.func.isRequired,
onShow: PropTypes.func.isRequired,
openInRoute: PropTypes.bool,
intl: PropTypes.object.isRequired,
};
state = {
expanded: false,
};
handleChange = (e) => {
this.props.onChange(e.target.value);
}
handleClear = (e) => {
e.preventDefault();
if (this.props.value.length > 0 || this.props.submitted) {
this.props.onClear();
}
}
handleKeyUp = (e) => {
if (e.key === 'Enter') {
e.preventDefault();
this.props.onSubmit();
if (this.props.openInRoute) {
this.context.router.history.push('/search');
}
} else if (e.key === 'Escape') {
document.querySelector('.ui').parentElement.focus();
}
}
handleFocus = () => {
this.setState({ expanded: true });
this.props.onShow();
}
handleBlur = () => {
this.setState({ expanded: false });
}
render() {
const { intl, value, submitted } = this.props;
const { expanded } = this.state;
const hasValue = value.length > 0 || submitted;
return (
<div className='search'>
<label>
<span style={{ display: 'none' }}>{intl.formatMessage(messages.placeholder)}</span>
<input
className='search__input'
type='text'
placeholder={intl.formatMessage(messages.placeholder)}
value={value}
onChange={this.handleChange}
onKeyUp={this.handleKeyUp}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
/>
</label>
<div role='button' tabIndex='0' className='search__icon' onClick={this.handleClear}>
<Icon id='search' className={hasValue ? '' : 'active'} />
<Icon id='times-circle' className={hasValue ? 'active' : ''} aria-label={intl.formatMessage(messages.placeholder)} />
</div>
<Overlay show={expanded && !hasValue} placement='bottom' target={this}>
<SearchPopout />
</Overlay>
</div>
);
}
}

View File

@@ -0,0 +1 @@
export { default } from './search_popout';

View File

@@ -0,0 +1,55 @@
import { FormattedMessage } from 'react-intl';
import spring from 'react-motion/lib/spring';
import Motion from '../../features/ui/util/optional_motion';
import { searchEnabled } from '../../initial_state';
import './search_popout.scss';
export default class SearchPopout extends PureComponent {
static propTypes = {
style: PropTypes.object,
};
render() {
const { style } = this.props;
return (
<div className='search-popout-container' style={{ ...style, position: 'absolute', zIndex: 1000 }}>
<Motion defaultStyle={{ opacity: 0, scaleX: 1, scaleY: 1 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
{({ opacity, scaleX, scaleY }) => (
<div className='search-popout' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
<h4>
<FormattedMessage id='search_popout.search_format' defaultMessage='Advanced search format' />
</h4>
<ul>
<li>
<em>#example</em>
<FormattedMessage id='search_popout.tips.hashtag' defaultMessage='hashtag' />
</li>
<li>
<em>@username</em>
<FormattedMessage id='search_popout.tips.user' defaultMessage='user' />
</li>
<li>
<em>URL</em>
<FormattedMessage id='search_popout.tips.user' defaultMessage='user' />
</li>
<li>
<em>URL</em>
<FormattedMessage id='search_popout.tips.status' defaultMessage='status' />
</li>
</ul>
{
searchEnabled
? <FormattedMessage id='search_popout.tips.full_text' defaultMessage='Simple text returns statuses you have written, favorited, reposted, or have been mentioned in, as well as matching usernames, display names, and hashtags.' />
: <FormattedMessage id='search_popout.tips.text' defaultMessage='Simple text returns matching display names, usernames and hashtags' />
}
</div>
)}
</Motion>
</div>
);
}
}

View File

@@ -0,0 +1,36 @@
.search-popout-container {
width: 251px;
@media screen and (max-width: $nav-breakpoint-2) {
width: 100%;
}
}
.search-popout {
background: $gab-background-container;
padding: 8px 10px 17px 10px;
margin: 4px 0 0 0;
color: $gab-secondary-text;
box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.5);
@include text-sizing(12px, 400, 14px);
@include border-design($gab-placeholder-accent, 1px, 4px);
h4 {
color: #fff;
@include text-sizing(14px, 600, 16px);
}
ul {
margin: 6px 0 6px;
li {
margin: 0 0 2px 0;
em {
color: $gab-text-highlight;
}
}
}
}

View File

@@ -0,0 +1 @@
export { default } from './section_headline_bar';

View File

@@ -0,0 +1,52 @@
import { NavLink } from 'react-router-dom';
import classNames from 'classnames';
import Icon from '../icon';
class SectionHeadlineBarItem extends PureComponent {
static propTypes = {
to: PropTypes.string,
icon: PropTypes.string,
className: PropTypes.string,
onClick: PropTypes.func,
title: PropTypes.oneOf([
PropTypes.string,
PropTypes.node,
]),
};
render() {
const { to, title, icon, className, onClick } = this.props;
const classes = classNames('section-header-bar__item', className);
if (to) {
return (<NavLink className={classes} to={to}>{title}</NavLink>);
} else if (icon) {
<button className={classes} onClick={onClick} title={title}>
<Icon id={icon} fixedWidth />
</button>
}
return (<button className={classes} onClick={onClick}>{title}</button>)
}
};
export default class SectionHeadlineBar extends PureComponent {
static propTypes = {
items: PropTypes.array,
};
render() {
const { items } = this.props;
return (
<div className='section-headline-bar'>
{
items.forEach(item, i => (
<SectionHeadlineBarItem key={`shbi-{i}`} {...item} />
))
}
</div>
)
}
}

View File

@@ -0,0 +1,50 @@
.section-headline-bar {
background: darken($ui-base-color, 4%);
border-bottom: 1px solid lighten($ui-base-color, 8%);
cursor: default;
display: flex;
flex-shrink: 0;
button {
background: darken($ui-base-color, 4%);
border: 0;
margin: 0;
}
button,
a {
display: block;
flex: 1 1 auto;
color: $secondary-text-color;
padding: 15px 0;
font-size: 14px;
font-weight: 500;
text-align: center;
text-decoration: none;
position: relative;
&.active {
color: $primary-text-color;
&::before,
&::after {
display: block;
content: "";
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 0;
transform: translateX(-50%);
border-style: solid;
border-width: 0 10px 10px;
border-color: transparent transparent lighten($ui-base-color, 8%);
}
&::after {
bottom: -1px;
border-color: transparent transparent $ui-base-color;
}
}
}
}

View File

@@ -1,5 +1,5 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import Toggle from 'react-toggle';
import ToggleSwitch from '../toggle_switch';
import './setting_toggle.scss';
@@ -23,7 +23,7 @@ export default class SettingToggle extends PureComponent {
return (
<div className='setting-toggle'>
<Toggle id={id} checked={settings.getIn(settingPath)} onChange={this.onChange} onKeyDown={this.onKeyDown} />
<ToggleSwitch id={id} checked={settings.getIn(settingPath)} onChange={this.onChange} onKeyDown={this.onKeyDown} />
<label htmlFor={id} className='setting-toggle__label'>{label}</label>
</div>
);

View File

@@ -115,4 +115,87 @@
margin-top: 10px;
}
}
}
.status__wrapper--filtered {
color: $dark-text-color;
border: 0;
font-size: inherit;
text-align: center;
line-height: inherit;
margin: 0;
padding: 15px;
box-sizing: border-box;
width: 100%;
clear: both;
border-bottom: 1px solid lighten($ui-base-color, 8%);
}
.status__prepend-icon-wrapper {
left: -26px;
position: absolute;
}
.status__relative-time {
color: $dark-text-color;
float: right;
font-size: 14px;
}
.status__display-name {
color: $dark-text-color;
}
.status__info .status__display-name {
display: block;
max-width: 100%;
padding-right: 25px;
}
.status__info {
font-size: 15px;
z-index: 4;
}
.status__prepend {
margin-left: 68px;
color: $dark-text-color;
padding: 8px 0;
padding-bottom: 2px;
font-size: 14px;
position: relative;
.status__display-name strong {
color: $dark-text-color;
}
>span {
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
}
.status__display-name {
strong {
color: $primary-text-color;
}
}
.status__avatar {
height: 48px;
left: 10px;
position: absolute;
top: 10px;
width: 48px;
}
.status__expand {
width: 68px;
position: absolute;
left: 0;
top: 0;
height: 100%;
cursor: pointer;
}

View File

@@ -1,11 +1,11 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import Toggle from 'react-toggle';
import { Set as ImmutableSet } from 'immutable';
import noop from 'lodash/noop';
import StatusContent from '../status_content';
import { MediaGallery, Video } from '../../features/ui/util/async-components';
import Bundle from '../../features/ui/util/bundle';
import { toggleStatusReport } from '../../actions/reports';
import ToggleSwitch from '../toggle_switch';
import './status_check_box.scss';
@@ -78,7 +78,7 @@ class StatusCheckBox extends PureComponent {
</div>
<div className='status-check-box-toggle'>
<Toggle checked={checked} onChange={onToggle} disabled={disabled} />
<ToggleSwitch checked={checked} onChange={onToggle} disabled={disabled} />
</div>
</div>
);

View File

@@ -0,0 +1 @@
export { default } from './toggle_switch';

View File

@@ -0,0 +1,9 @@
import Toggle from 'react-toggle';
import './toggle_switch.scss';
export default class ToggleSwitch extends PureComponent {
render() {
return <Toggle {...this.props} />
};
}

View File

@@ -0,0 +1,98 @@
.react-toggle {
display: inline-block;
position: relative;
cursor: pointer;
background-color: transparent;
border: 0;
padding: 0;
user-select: none;
-webkit-tap-highlight-color: rgba($base-overlay-background, 0);
-webkit-tap-highlight-color: transparent;
&--disabled {
cursor: not-allowed;
opacity: 0.5;
transition: opacity 0.25s;
}
}
.react-toggle-screenreader-only {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.react-toggle-track {
width: 50px;
height: 24px;
padding: 0;
border-radius: 30px;
background-color: $ui-base-color;
transition: background-color 0.2s ease;
@include size(50px, 24px);
}
.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track {
background-color: darken($ui-base-color, 10%);
}
.react-toggle--checked .react-toggle-track {
background-color: $gab-brand-default;
}
.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track {
background-color: lighten($gab-brand-default, 10%);
}
.react-toggle-track-check {
margin-top: auto;
margin-bottom: auto;
line-height: 0;
opacity: 0;
transition: opacity 0.25s ease;
@include abs-position(0, auto, 0, 8px);
@include size(14px, 10px);
}
.react-toggle--checked .react-toggle-track-check {
opacity: 1;
transition: opacity 0.25s ease;
}
.react-toggle-track-x {
margin-top: auto;
margin-bottom: auto;
line-height: 0;
opacity: 1;
transition: opacity 0.25s ease;
@include abs-position(0, 10px, 0);
@include size(10px);
}
.react-toggle--checked .react-toggle-track-x {
opacity: 0;
}
.react-toggle-thumb {
border: 1px solid $ui-base-color;
background-color: darken($simple-background-color, 2%);
box-sizing: border-box;
transition: all 0.25s ease;
transition-property: border-color, left;
@include abs-position(1, auto, auto, 1px);
@include circle(22px);
}
.react-toggle--checked .react-toggle-thumb {
left: 27px;
border-color: $gab-brand-default;
}

View File

@@ -12,7 +12,7 @@
flex: 1 1 auto;
color: $dark-text-color;
@include text-overflow(nowrap);
@include text-overflow;
strong {
font-weight: 500;
@@ -24,7 +24,7 @@
text-decoration: none;
@include text-sizing(14px, 500);
@include text-overflow(nowrap);
@include text-overflow;
&:hover,
&:focus,

View File

@@ -5,7 +5,7 @@ export default class VerifiedIcon extends PureComponent {
render() {
return (
<span className='verified-icon'>
<span className='visuallyhidden'>Verified Account</span>
<span className='invisible'>Verified Account</span>
</span>
);
}