Progress
This commit is contained in:
parent
389b189d64
commit
cdde454915
@ -132,8 +132,8 @@ class Account extends ImmutablePureComponent {
|
||||
</div>
|
||||
|
||||
<div className={[styles.default, styles.marginLeftAuto].join(' ')}>
|
||||
<button className={[styles.default, styles.circle, styles.backgroundSubtle2, styles.paddingVertical5PX, styles.paddingHorizontal5PX, styles.cursorPointer].join(' ')}>
|
||||
<Icon id='close' width='8px' height='8px' />
|
||||
<button className={[styles.default, styles.circle, styles.backgroundTransparent, styles.paddingVertical5PX, styles.paddingHorizontal5PX, styles.cursorPointer].join(' ')}>
|
||||
<Icon className={styles.fillColorSubtle} id='close' width='8px' height='8px' />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
@ -1,33 +1,20 @@
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import classNames from 'classnames/bind'
|
||||
|
||||
export default class Button extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
text: PropTypes.node,
|
||||
to: PropTypes.string,
|
||||
href: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
block: PropTypes.bool,
|
||||
secondary: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
className: PropTypes.string,
|
||||
}
|
||||
|
||||
state = {
|
||||
hovering: false,
|
||||
}
|
||||
|
||||
handleOnMouseEnter = () => {
|
||||
this.setState({
|
||||
hovering: true,
|
||||
})
|
||||
}
|
||||
|
||||
handleOnMouseLeave = () => {
|
||||
this.setState({
|
||||
hovering: false,
|
||||
})
|
||||
}
|
||||
|
||||
handleClick = (e) => {
|
||||
if (!this.props.disabled && this.props.onClick) {
|
||||
@ -44,8 +31,7 @@ export default class Button extends PureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { secondary, block, className, disabled, text, children, href } = this.props
|
||||
const { hovering } = this.state
|
||||
const { block, className, disabled, text, to, children, href } = this.props
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
@ -60,21 +46,22 @@ export default class Button extends PureComponent {
|
||||
paddingVertical10PX: 1,
|
||||
paddingHorizontal15PX: 1,
|
||||
width100PC: block,
|
||||
backgroundColorBrand: !hovering,
|
||||
backgroundColorBrandDark: hovering,
|
||||
backgroundColorBrand: 1,
|
||||
backgroundColorBrandDark_onHover: 1,
|
||||
})
|
||||
|
||||
if (href) {
|
||||
return (
|
||||
<a
|
||||
className={classes}
|
||||
href={href}
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
>
|
||||
<a className={classes} href={href}>
|
||||
{text || children}
|
||||
</a>
|
||||
)
|
||||
} else if (to) {
|
||||
return (
|
||||
<NavLink className={classes} to={to}>
|
||||
{text || children}
|
||||
</NavLink>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
@ -83,8 +70,6 @@ export default class Button extends PureComponent {
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
className={classes}
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
>
|
||||
{text || children}
|
||||
</button>
|
||||
|
@ -26,7 +26,7 @@ export default class Column extends PureComponent {
|
||||
);
|
||||
|
||||
return (
|
||||
<div role='region' aria-labelledby={columnHeaderId} className='column'>
|
||||
<div role='region' aria-labelledby={columnHeaderId} className={[styles.default].join(' ')}>
|
||||
{ backBtn && <ColumnBackButton slim={backBtn === 'slim'} />}
|
||||
{children}
|
||||
</div>
|
||||
|
145
app/javascript/gabsocial/components/column_header.js
Normal file
145
app/javascript/gabsocial/components/column_header.js
Normal file
@ -0,0 +1,145 @@
|
||||
import { injectIntl, defineMessages } from 'react-intl'
|
||||
import Icon from './icon'
|
||||
|
||||
const messages = defineMessages({
|
||||
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
|
||||
hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },
|
||||
})
|
||||
|
||||
export default @injectIntl
|
||||
class ColumnHeader extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
title: PropTypes.node,
|
||||
icon: PropTypes.string,
|
||||
active: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
}
|
||||
|
||||
state = {
|
||||
collapsed: true,
|
||||
}
|
||||
|
||||
historyBack = () => {
|
||||
if (window.history && window.history.length === 1) {
|
||||
this.context.router.history.push('/home') // homehack
|
||||
} else {
|
||||
this.context.router.history.goBack()
|
||||
}
|
||||
}
|
||||
|
||||
handleToggleClick = (e) => {
|
||||
e.stopPropagation()
|
||||
this.setState({
|
||||
collapsed: !this.state.collapsed,
|
||||
})
|
||||
}
|
||||
|
||||
handleBackClick = () => {
|
||||
this.historyBack()
|
||||
}
|
||||
|
||||
render () {
|
||||
const { title, icon, active, children, intl: { formatMessage } } = this.props
|
||||
const { collapsed } = this.state
|
||||
|
||||
return (
|
||||
<div className={[styles.default, styles.height100PC, styles.flexRow].join(' ')}>
|
||||
{ /* <button className={[styles.default, styles.cursorPointer, styles.backgroundTransparent, styles.alignItemsCenter, styles.marginRight10PX, styles.justifyContentCenter].join(' ')}>
|
||||
<Icon className={[styles.marginRight5PX, styles.fillColorBrand].join(' ')} id='back' width='24px' height='24px' />
|
||||
</button> */ }
|
||||
<h1 className={[styles.default, styles.height100PC, styles.justifyContentCenter].join(' ')}>
|
||||
<span className={[styles.default, styles.text, styles.fontSize24PX, styles.fontWeight500, styles.colorBlack].join(' ')}>
|
||||
{title}
|
||||
</span>
|
||||
</h1>
|
||||
<div className={[styles.default, styles.backgroundTransparent, styles.flexRow, styles.alignItemsCenter, styles.justifyContentCenter, styles.marginLeftAuto].join(' ')}>
|
||||
<button className={[styles.default, styles.marginLeft5PX, styles.cursorPointer, styles.backgroundSubtle2, styles.paddingHorizontal10PX, styles.paddingVertical5PX, styles.radiusSmall].join(' ')}>
|
||||
<Icon className={styles.fillColorSubtle} id='ellipsis' width='24px' height='24px' />
|
||||
</button>
|
||||
<button className={[styles.default, styles.marginLeft5PX, styles.cursorPointer, styles.backgroundSubtle2, styles.paddingHorizontal10PX, styles.paddingVertical5PX, styles.radiusSmall].join(' ')}>
|
||||
<Icon className={styles.fillColorSubtle} id='ellipsis' width='24px' height='24px' />
|
||||
</button>
|
||||
<button className={[styles.default, styles.marginLeft5PX, styles.cursorPointer, styles.backgroundSubtle2, styles.paddingHorizontal10PX, styles.paddingVertical5PX, styles.radiusSmall].join(' ')}>
|
||||
<Icon className={styles.fillColorSubtle} id='ellipsis' width='24px' height='24px' />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
// const wrapperClassName = classNames('column-header__wrapper', {
|
||||
// 'column-header__wrapper--active': active,
|
||||
// })
|
||||
|
||||
// const buttonClassName = classNames('column-header', {
|
||||
// 'column-header--active': active,
|
||||
// })
|
||||
|
||||
// const btnTitle = formatMessage(collapsed ? messages.show : messages.hide)
|
||||
// const hasTitle = icon && title
|
||||
// const hasChildren = !!children
|
||||
|
||||
// if (!hasChildren && !hasTitle) {
|
||||
// return null
|
||||
// } else if (!hasChildren && hasTitle) {
|
||||
// return (
|
||||
// <div className={wrapperClassName}>
|
||||
// <h1 className={buttonClassName}>
|
||||
// <Icon id={icon} fixedWidth className='column-header__icon' />
|
||||
// {title}
|
||||
// </h1>
|
||||
// </div>
|
||||
// )
|
||||
// }
|
||||
|
||||
// const collapsibleClassName = classNames('column-header__collapsible', {
|
||||
// 'column-header__collapsible--collapsed': collapsed,
|
||||
// })
|
||||
|
||||
// const collapsibleButtonClassName = classNames('column-header__button', {
|
||||
// 'column-header__button--active': !collapsed,
|
||||
// })
|
||||
|
||||
// return (
|
||||
// <div className={wrapperClassName}>
|
||||
// <h1 className={buttonClassName}>
|
||||
// {
|
||||
// hasTitle && (
|
||||
// <Fragment>
|
||||
// <Icon id={icon} fixedWidth className='column-header__icon' />
|
||||
// {title}
|
||||
// </Fragment>
|
||||
// )
|
||||
// }
|
||||
|
||||
// <button
|
||||
// className={collapsibleButtonClassName}
|
||||
// title={btnTitle}
|
||||
// aria-label={btnTitle}
|
||||
// aria-pressed={!collapsed}
|
||||
// onClick={this.handleToggleClick}
|
||||
// >
|
||||
// <Icon id='sliders' />
|
||||
// </button>
|
||||
// </h1>
|
||||
|
||||
// <div className={collapsibleClassName} tabIndex={collapsed ? -1 : null}>
|
||||
// <div className='column-header__collapsible-inner'>
|
||||
// {
|
||||
// !collapsed &&
|
||||
// <div key='extra-content' className='column-header__collapsible__extra'>
|
||||
// {children}
|
||||
// </div>
|
||||
// }
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// )
|
||||
}
|
||||
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
import { Fragment } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import Icon from '../icon';
|
||||
|
||||
const messages = defineMessages({
|
||||
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
|
||||
hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },
|
||||
});
|
||||
|
||||
export default @injectIntl
|
||||
class ColumnHeader extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
title: PropTypes.node,
|
||||
icon: PropTypes.string,
|
||||
active: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
state = {
|
||||
collapsed: true,
|
||||
};
|
||||
|
||||
historyBack = () => {
|
||||
if (window.history && window.history.length === 1) {
|
||||
this.context.router.history.push('/home'); // homehack
|
||||
} else {
|
||||
this.context.router.history.goBack();
|
||||
}
|
||||
}
|
||||
|
||||
handleToggleClick = (e) => {
|
||||
e.stopPropagation();
|
||||
this.setState({
|
||||
collapsed: !this.state.collapsed,
|
||||
});
|
||||
}
|
||||
|
||||
handleBackClick = () => {
|
||||
this.historyBack();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { title, icon, active, children, intl: { formatMessage } } = this.props;
|
||||
const { collapsed } = this.state;
|
||||
|
||||
const wrapperClassName = classNames('column-header__wrapper', {
|
||||
'column-header__wrapper--active': active,
|
||||
});
|
||||
|
||||
const buttonClassName = classNames('column-header', {
|
||||
'column-header--active': active,
|
||||
});
|
||||
|
||||
const btnTitle = formatMessage(collapsed ? messages.show : messages.hide);
|
||||
const hasTitle = icon && title;
|
||||
const hasChildren = !!children;
|
||||
|
||||
if (!hasChildren && !hasTitle) {
|
||||
return null;
|
||||
} else if (!hasChildren && hasTitle) {
|
||||
return (
|
||||
<div className={wrapperClassName}>
|
||||
<h1 className={buttonClassName}>
|
||||
<Icon id={icon} fixedWidth className='column-header__icon' />
|
||||
{title}
|
||||
</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const collapsibleClassName = classNames('column-header__collapsible', {
|
||||
'column-header__collapsible--collapsed': collapsed,
|
||||
});
|
||||
|
||||
const collapsibleButtonClassName = classNames('column-header__button', {
|
||||
'column-header__button--active': !collapsed,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={wrapperClassName}>
|
||||
<h1 className={buttonClassName}>
|
||||
{
|
||||
hasTitle && (
|
||||
<Fragment>
|
||||
<Icon id={icon} fixedWidth className='column-header__icon' />
|
||||
{title}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
<button
|
||||
className={collapsibleButtonClassName}
|
||||
title={btnTitle}
|
||||
aria-label={btnTitle}
|
||||
aria-pressed={!collapsed}
|
||||
onClick={this.handleToggleClick}
|
||||
>
|
||||
<Icon id='sliders' />
|
||||
</button>
|
||||
</h1>
|
||||
|
||||
<div className={collapsibleClassName} tabIndex={collapsed ? -1 : null}>
|
||||
<div className='column-header__collapsible-inner'>
|
||||
{
|
||||
!collapsed &&
|
||||
<div key='extra-content' className='column-header__collapsible__extra'>
|
||||
{children}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
.column-header {
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
flex: 0 0 auto;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
outline: 0;
|
||||
overflow: hidden;
|
||||
background: $gab-background-container;
|
||||
|
||||
body.theme-gabsocial-light & {
|
||||
background: $gab-background-container-light;
|
||||
color: $gab-default-text-light;
|
||||
}
|
||||
|
||||
&--active {
|
||||
box-shadow: 0 1px 0 rgba($highlight-text-color, 0.3);
|
||||
|
||||
.column-header__icon {
|
||||
color: $highlight-text-color;
|
||||
text-shadow: 0 0 10px rgba($highlight-text-color, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:active {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&__wrapper {
|
||||
position: relative;
|
||||
flex: 0 0 auto;
|
||||
overflow: hidden;
|
||||
|
||||
&--active {
|
||||
&::before {
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
background: radial-gradient(ellipse, rgba($ui-highlight-color, 0.23) 0%, rgba($ui-highlight-color, 0) 60%);
|
||||
|
||||
@include pseudo;
|
||||
@include size(60%, 28px);
|
||||
@include abs-position(35px, 0, auto, 0, false);
|
||||
@include margin-center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&__expansion {
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
white-space: nowrap;
|
||||
max-height: 0px;
|
||||
|
||||
&--open {
|
||||
max-height: 55px;
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
margin-left: auto;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
padding: 0 15px;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
background: $gab-background-container;
|
||||
|
||||
body.theme-gabsocial-light & {
|
||||
color: $gab-default-text-light;
|
||||
background: $gab-background-container-light;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: lighten($darker-text-color, 7%);
|
||||
}
|
||||
|
||||
&--active {
|
||||
color: $primary-text-color;
|
||||
background: lighten($ui-base-color, 8%);
|
||||
|
||||
&:hover {
|
||||
color: $primary-text-color;
|
||||
background: lighten($ui-base-color, 8%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__collapsible-inner {
|
||||
background: #3f3f3f;
|
||||
padding: 15px;
|
||||
|
||||
body.theme-gabsocial-light & {
|
||||
background: #e6e6e6;
|
||||
}
|
||||
}
|
||||
|
||||
&__collapsible {
|
||||
max-height: 70vh;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
color: $darker-text-color;
|
||||
transition: max-height 150ms linear;
|
||||
|
||||
&--collapsed {
|
||||
max-height: 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 0;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-top: 1px solid lighten($ui-base-color, 12%);
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.column-header-btn {
|
||||
padding: 15px;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
|
||||
&--sub {
|
||||
font-size: 14px;
|
||||
padding: 6px s10px;
|
||||
}
|
||||
|
||||
&--grouped {
|
||||
margin: 6px;
|
||||
}
|
||||
|
||||
&--active {
|
||||
color: $primary-text-color;
|
||||
border-radius: 10px;
|
||||
background-color: rgba($highlight-text-color, .1);
|
||||
}
|
||||
}
|
@ -1,168 +0,0 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import classNames from 'classnames';
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { createSelector } from 'reselect';
|
||||
import { fetchLists } from '../../actions/lists';
|
||||
import Icon from '../icon';
|
||||
|
||||
const messages = defineMessages({
|
||||
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
|
||||
hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },
|
||||
homeTitle: { id: 'home_column_header.home', defaultMessage: 'Home' },
|
||||
allTitle: { id: 'home_column_header.all', defaultMessage: 'All' },
|
||||
listTitle: { id: 'home_column.lists', defaultMessage: '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 => {
|
||||
return {
|
||||
lists: getOrderedLists(state),
|
||||
};
|
||||
};
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class HomeColumnHeader extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
active: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
activeItem: PropTypes.string,
|
||||
activeSubItem: PropTypes.string,
|
||||
lists: ImmutablePropTypes.list,
|
||||
};
|
||||
|
||||
state = {
|
||||
collapsed: true,
|
||||
listsExpanded: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatch(fetchLists());
|
||||
}
|
||||
|
||||
handleToggleClick = (e) => {
|
||||
e.stopPropagation();
|
||||
this.setState({ collapsed: !this.state.collapsed });
|
||||
}
|
||||
|
||||
expandLists = () => {
|
||||
this.setState({ listsExpanded: !this.state.listsExpanded });
|
||||
}
|
||||
|
||||
render () {
|
||||
const { active, children, intl: { formatMessage }, activeItem, activeSubItem, lists } = this.props;
|
||||
const { collapsed, listsExpanded } = this.state;
|
||||
|
||||
const wrapperClassName = classNames('column-header__wrapper', {
|
||||
'column-header__wrapper--active': active,
|
||||
});
|
||||
|
||||
const buttonClassName = classNames('column-header', {
|
||||
'column-header--active': active,
|
||||
});
|
||||
|
||||
const collapsibleClassName = classNames('column-header__collapsible', {
|
||||
'column-header__collapsible--collapsed': collapsed,
|
||||
});
|
||||
|
||||
const collapsibleButtonClassName = classNames('column-header__button', {
|
||||
'column-header__button--active': !collapsed,
|
||||
});
|
||||
|
||||
const expansionClassName = classNames('column-header column-header__expansion', {
|
||||
'column-header__expansion--open': listsExpanded,
|
||||
});
|
||||
|
||||
const btnTitle = formatMessage(collapsed ? messages.show : messages.hide);
|
||||
|
||||
let expandedContent = null;
|
||||
if ((listsExpanded || activeItem === 'lists') && lists) {
|
||||
expandedContent = lists.map((list) => {
|
||||
const listId = list.get('id');
|
||||
const linkUrl = `/list/${listId}`;
|
||||
const classes = classNames('column-header-btn column-header-btn--sub column-header-btn--grouped', {
|
||||
'column-header-btn--active': listId === activeSubItem,
|
||||
});
|
||||
|
||||
return (
|
||||
<Link key={listId} to={linkUrl} className={classes}>
|
||||
{list.get('title')}
|
||||
</Link>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={wrapperClassName}>
|
||||
<h1 className={buttonClassName}>
|
||||
<Link to='/home' className={classNames('column-header-btn column-header-btn--grouped', { 'column-header-btn--active': 'home' === activeItem })}>
|
||||
<Icon id='home' fixedWidth className='column-header__icon' />
|
||||
{formatMessage(messages.homeTitle)}
|
||||
</Link>
|
||||
|
||||
<Link to='/timeline/all' className={classNames('column-header-btn column-header-btn--grouped', { 'column-header-btn--active': 'all' === activeItem })}>
|
||||
<Icon id='globe' fixedWidth className='column-header__icon' />
|
||||
{formatMessage(messages.allTitle)}
|
||||
</Link>
|
||||
|
||||
{ lists.size > 0 &&
|
||||
<a onClick={this.expandLists} className={classNames('column-header-btn column-header-btn--grouped', { 'column-header-btn--active': 'lists' === activeItem })}>
|
||||
<Icon id='list' fixedWidth className='column-header__icon' />
|
||||
{formatMessage(messages.listTitle)}
|
||||
</a>
|
||||
}
|
||||
{ lists.size == 0 &&
|
||||
<Link to='/lists' className='column-header-btn column-header-btn--grouped'>
|
||||
<Icon id='list' fixedWidth className='column-header__icon' />
|
||||
{formatMessage(messages.listTitle)}
|
||||
</Link>
|
||||
}
|
||||
|
||||
<div className='column-header__buttons'>
|
||||
<button
|
||||
className={collapsibleButtonClassName}
|
||||
title={btnTitle}
|
||||
aria-label={btnTitle}
|
||||
aria-pressed={collapsed ? 'false' : 'true'}
|
||||
onClick={this.handleToggleClick}
|
||||
>
|
||||
<Icon id='sliders' />
|
||||
</button>
|
||||
</div>
|
||||
</h1>
|
||||
|
||||
<h1 className={expansionClassName}>
|
||||
{expandedContent}
|
||||
</h1>
|
||||
|
||||
<div className={collapsibleClassName} tabIndex={collapsed ? -1 : null}>
|
||||
<div className='column-header__collapsible-inner'>
|
||||
{
|
||||
!collapsed &&
|
||||
<div key='extra-content' className='column-header__collapsible__extra'>
|
||||
{children}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import ColumnHeader from './column_header';
|
||||
import HomeColumnHeader from './home_column_header';
|
||||
|
||||
export {
|
||||
ColumnHeader,
|
||||
HomeColumnHeader,
|
||||
}
|
43
app/javascript/gabsocial/components/column_indicator.js
Normal file
43
app/javascript/gabsocial/components/column_indicator.js
Normal file
@ -0,0 +1,43 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import Icon from './icon'
|
||||
|
||||
const messages = defineMessages({
|
||||
loading: { id: 'loading_indicator.label', defaultMessage: 'Loading..' },
|
||||
missing: { id: 'missing_indicator.sublabel', defaultMessage: 'This resource could not be found.' },
|
||||
})
|
||||
|
||||
export default @injectIntl
|
||||
class ColumnIndicator extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
type: PropTypes.oneOf([
|
||||
'loading',
|
||||
'missing',
|
||||
'error',
|
||||
]),
|
||||
message: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.object,
|
||||
]),
|
||||
}
|
||||
|
||||
render() {
|
||||
const { type, message, intl } = this.props
|
||||
|
||||
const title = type !== 'error' ? intl.formatMessage(messages[type]) : message
|
||||
|
||||
return (
|
||||
<div className={[styles.default, styles.width100PC, styles.justifyContentCenter, styles.alignItemsCenter, styles.paddingVertical15PX].join(' ')}>
|
||||
<Icon id={type} width='52px' height='52px' />
|
||||
{
|
||||
type !== 'loading' &&
|
||||
<span className={[styles.default, styles.marginTop10PX, styles.text, styles.displayFlex, styles.colorBrand, styles.fontWeightNormal, styles.fontSize14PX].join(' ')}>
|
||||
{title}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import Column from '../column';
|
||||
|
||||
const messages = defineMessages({
|
||||
loading: { id: 'loading_indicator.label', defaultMessage: 'Loading...' },
|
||||
missing: { id: 'missing_indicator.sublabel', defaultMessage: 'This resource could not be found.' },
|
||||
});
|
||||
|
||||
export default @injectIntl
|
||||
class ColumnIndicator extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
type: PropTypes.oneOf([
|
||||
'loading',
|
||||
'missing',
|
||||
'error',
|
||||
]),
|
||||
message: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.object,
|
||||
]),
|
||||
};
|
||||
|
||||
render() {
|
||||
const { type, message, intl } = this.props;
|
||||
|
||||
const title = type !== 'error' ? intl.formatMessage(messages[type]) : message;
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<div className={`column-indicator column-indicator--${type}`}>
|
||||
<div className='column-indicator__figure' />
|
||||
<span className='column-indicator__title'>{title}</span>
|
||||
</div>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
};
|
@ -1,93 +0,0 @@
|
||||
.column-indicator {
|
||||
overflow: visible;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
@include abs-position(50%, auto, auto, 50%);
|
||||
|
||||
&--loading & {
|
||||
&__figure {
|
||||
border: 6px solid lighten($ui-base-color, 26%);
|
||||
}
|
||||
}
|
||||
|
||||
&--missing & {
|
||||
&__figure {
|
||||
&:before {
|
||||
@include pseudo('!');
|
||||
@include text-sizing(40px, 600, 1, center);
|
||||
@include abs-position(0, 0, 0, 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__figure {
|
||||
transform: translate(-50%, -50%);
|
||||
box-sizing: border-box;
|
||||
background-color: transparent;
|
||||
|
||||
@include circle(42px);
|
||||
@include abs-position(50%, auto, auto, 50%);
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-left: 50%;
|
||||
transform: translateX(-50%);
|
||||
margin: 82px 0 0 50%;
|
||||
white-space: nowrap;
|
||||
color: $dark-text-color;
|
||||
|
||||
@include text-sizing(14px, 400);
|
||||
}
|
||||
}
|
||||
|
||||
.no-reduce-motion .column-indicator--loading span {
|
||||
animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
}
|
||||
|
||||
.no-reduce-motion .column-indicator--loading .column-indicator__figure {
|
||||
animation: loader-figure 1.15s infinite cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
}
|
||||
|
||||
@keyframes loader-label {
|
||||
0% {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0.25;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes loader-figure {
|
||||
0% {
|
||||
background-color: lighten($ui-base-color, 26%);
|
||||
|
||||
@include size(0);
|
||||
}
|
||||
|
||||
29% {
|
||||
background-color: lighten($ui-base-color, 26%);
|
||||
}
|
||||
|
||||
30% {
|
||||
background-color: transparent;
|
||||
border-width: 21px;
|
||||
opacity: 1;
|
||||
|
||||
@include size(42px);
|
||||
}
|
||||
|
||||
100% {
|
||||
border-width: 0;
|
||||
opacity: 0;
|
||||
background-color: transparent;
|
||||
|
||||
@include size(42px);
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export { default } from './column_indicator';
|
@ -105,32 +105,39 @@ class Header extends ImmutablePureComponent {
|
||||
const menuItems = [
|
||||
{
|
||||
title: 'Home',
|
||||
icon: <Icon id='home' />,
|
||||
icon: 'home',
|
||||
to: '/',
|
||||
count: 0,
|
||||
},
|
||||
{
|
||||
title: 'Notifications',
|
||||
icon: <Icon id='notifications' />,
|
||||
icon: 'notifications',
|
||||
to: '/notifications',
|
||||
count: 40,
|
||||
},
|
||||
{
|
||||
title: 'Groups',
|
||||
icon: <Icon id='groups' />,
|
||||
icon: 'group',
|
||||
to: '/groups',
|
||||
},
|
||||
{
|
||||
title: 'Lists',
|
||||
icon: <Icon id='lists' />,
|
||||
icon: 'lists',
|
||||
to: '/lists',
|
||||
},
|
||||
{
|
||||
title: 'Chat',
|
||||
icon: <Icon id='chat' />,
|
||||
icon: 'chat',
|
||||
to: '/',
|
||||
},
|
||||
{
|
||||
title: 'Profile',
|
||||
icon: <Icon id='profile' />,
|
||||
icon: 'profile',
|
||||
to: '/',
|
||||
},
|
||||
{
|
||||
title: 'More',
|
||||
icon: 'plus',
|
||||
to: '/',
|
||||
},
|
||||
]
|
||||
@ -138,70 +145,88 @@ class Header extends ImmutablePureComponent {
|
||||
const shortcutItems = [
|
||||
{
|
||||
title: 'Meme Group',
|
||||
icon: <Icon id='group' />,
|
||||
icon: 'group',
|
||||
to: '/',
|
||||
count: 0,
|
||||
},
|
||||
{
|
||||
title: 'Andrew',
|
||||
icon: <Icon id='user' />,
|
||||
icon: 'user',
|
||||
to: '/',
|
||||
count: 3,
|
||||
},
|
||||
]
|
||||
|
||||
const exploreItems = [
|
||||
{
|
||||
title: 'Trends',
|
||||
icon: <Icon id='trends' />,
|
||||
icon: 'trends',
|
||||
to: '/',
|
||||
},
|
||||
{
|
||||
title: 'Dissenter',
|
||||
icon: <Icon id='dissenter' />,
|
||||
icon: 'dissenter',
|
||||
to: '/',
|
||||
},
|
||||
{
|
||||
title: 'Apps',
|
||||
icon: <Icon id='apps' />,
|
||||
icon: 'apps',
|
||||
to: '/',
|
||||
},
|
||||
{
|
||||
title: 'Shop',
|
||||
icon: <Icon id='shop' />,
|
||||
icon: 'shop',
|
||||
to: '/',
|
||||
},
|
||||
]
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
const titleClasses = cx({
|
||||
default: 1,
|
||||
text: 1,
|
||||
colorSubtle: 1,
|
||||
displayBlock: 1,
|
||||
fontSize13PX: 1,
|
||||
paddingVertical5PX: 1,
|
||||
marginTop10PX: 1,
|
||||
paddingHorizontal10PX: 1,
|
||||
fontWeightBold: 1,
|
||||
})
|
||||
|
||||
return (
|
||||
<header role='banner' className={[styles.default, styles.flexGrow1, styles.z3, styles.alignItemsEnd].join(' ')}>
|
||||
<div className={[styles.default, styles.width250PX].join(' ')}>
|
||||
<div className={[styles.default, styles.positionFixed, styles.top0, styles.height100PC].join(' ')}>
|
||||
<div className={[styles.default, styles.height100PC, styles.width250PX, styles.paddingHorizontal20PX, styles.marginVertical10PX].join(' ')}>
|
||||
<div className={[styles.default, styles.height100PC, styles.width250PX, styles.paddingHorizontal15PX, styles.marginVertical10PX].join(' ')}>
|
||||
<h1 className={[styles.default].join(' ')}>
|
||||
<NavLink to='/' aria-label='Gab' className={[styles.default, styles.noSelect, styles.noUnderline, styles.height50PX, styles.justifyContentCenter, styles.cursorPointer, styles.paddingHorizontal10PX].join(' ')}>
|
||||
<GabLogo />
|
||||
</NavLink>
|
||||
</h1>
|
||||
<nav aria-label='Primary' role='navigation' className={[styles.default, styles.width100PC, styles.marginBottom15PX].join(' ')}>
|
||||
<span className={[styles.default, styles.text, styles.colorSubtle, styles.displayBlock, styles.fontSize13PX, styles.paddingVertical5PX, styles.marginTop10PX, styles.paddingHorizontal10PX, styles.fontWeight500].join(' ')}>Menu</span>
|
||||
<span className={titleClasses}>Menu</span>
|
||||
{
|
||||
menuItems.map((menuItem, i) => (
|
||||
<HeaderMenuItem {...menuItem} key={`header-item-menu-${i}`} />
|
||||
))
|
||||
}
|
||||
<span className={[styles.default, styles.text, styles.colorSubtle, styles.displayBlock, styles.fontSize13PX, styles.paddingVertical5PX, styles.marginTop10PX, styles.paddingHorizontal10PX, styles.fontWeight500].join(' ')}>Shortcuts</span>
|
||||
<span className={titleClasses}>Shortcuts</span>
|
||||
{
|
||||
shortcutItems.map((shortcutItem, i) => (
|
||||
<HeaderMenuItem {...shortcutItem} key={`header-item-shortcut-${i}`} />
|
||||
))
|
||||
}
|
||||
<span className={[styles.default, styles.text, styles.colorSubtle, styles.displayBlock, styles.fontSize13PX, styles.paddingVertical5PX, styles.marginTop10PX, styles.paddingHorizontal10PX, styles.fontWeight500].join(' ')}>Explore</span>
|
||||
<span className={titleClasses}>Explore</span>
|
||||
{
|
||||
exploreItems.map((exploreItem, i) => (
|
||||
<HeaderMenuItem {...exploreItem} key={`header-item-explore-${i}`} />
|
||||
))
|
||||
}
|
||||
</nav>
|
||||
<Button className={[styles.paddingVertical15PX, styles.fontSize15PX, styles.fontWeightBold].join(' ')}>Gab</Button>
|
||||
<Button block className={[styles.paddingVertical15PX, styles.fontSize15PX, styles.fontWeightBold].join(' ')}>
|
||||
Gab
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -215,7 +240,7 @@ class HeaderMenuItem extends PureComponent {
|
||||
static propTypes = {
|
||||
to: PropTypes.string,
|
||||
active: PropTypes.bool,
|
||||
icon: PropTypes.node,
|
||||
icon: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
}
|
||||
|
||||
@ -247,9 +272,10 @@ class HeaderMenuItem extends PureComponent {
|
||||
paddingVertical5PX: 1,
|
||||
paddingHorizontal10PX: 1,
|
||||
alignItemsCenter: 1,
|
||||
radiusSmall: 1,
|
||||
// border1PX: shouldShowActive,
|
||||
// borderColorSubtle: shouldShowActive,
|
||||
backgroundWhite: shouldShowActive,
|
||||
backgroundColorBrandLightOpaque: shouldShowActive,
|
||||
})
|
||||
|
||||
const textClasses = cx({
|
||||
@ -257,6 +283,7 @@ class HeaderMenuItem extends PureComponent {
|
||||
fontWeightNormal: 1,
|
||||
fontSize15PX: 1,
|
||||
text: 1,
|
||||
fontWeight500: shouldShowActive,
|
||||
colorBrand: shouldShowActive,
|
||||
colorBlack: !hovering && !active,
|
||||
})
|
||||
@ -275,7 +302,7 @@ class HeaderMenuItem extends PureComponent {
|
||||
>
|
||||
<div className={containerClasses}>
|
||||
<div className={[styles.default]}>
|
||||
<Icon className={iconClasses} width='16px' height='16px' />
|
||||
<Icon id={icon} className={iconClasses} width='15px' height='15px' />
|
||||
</div>
|
||||
<div className={[styles.default, styles.paddingHorizontal10PX, styles.textOverflowEllipsis, styles.overflowWrapBreakWord, styles.displayInline].join(' ')}>
|
||||
<span className={textClasses}>{title}</span>
|
||||
|
@ -1,3 +1,5 @@
|
||||
import BackIcon from './svgs/back_icon'
|
||||
import CalendarIcon from './svgs/calendar_icon'
|
||||
import CloseIcon from './svgs/close_icon'
|
||||
import CommentIcon from './svgs/comment_icon'
|
||||
import EllipsisIcon from './svgs/ellipsis_icon'
|
||||
@ -5,11 +7,15 @@ import GlobeIcon from './svgs/globe_icon'
|
||||
import GroupIcon from './svgs/group_icon'
|
||||
import HomeIcon from './svgs/home_icon'
|
||||
import LikeIcon from './svgs/like_icon'
|
||||
import LoadingIcon from './svgs/loading_icon'
|
||||
import MediaIcon from './svgs/media_icon'
|
||||
import NotificationsIcon from './svgs/notifications_icon'
|
||||
import PollIcon from './svgs/poll_icon'
|
||||
import RepostIcon from './svgs/repost_icon'
|
||||
import SearchIcon from './svgs/search_icon'
|
||||
import ShareIcon from './svgs/share_icon'
|
||||
import VerifiedIcon from './svgs/verified_icon'
|
||||
import WarningIcon from './svgs/warning_icon'
|
||||
|
||||
export default class Icon extends PureComponent {
|
||||
|
||||
@ -23,9 +29,11 @@ export default class Icon extends PureComponent {
|
||||
render() {
|
||||
const { id, ...options } = this.props
|
||||
|
||||
console.log("id:", id)
|
||||
|
||||
switch (id) {
|
||||
case 'back':
|
||||
return <BackIcon {...options} />
|
||||
case 'calendar':
|
||||
return <CalendarIcon {...options} />
|
||||
case 'close':
|
||||
return <CloseIcon {...options} />
|
||||
case 'comment':
|
||||
@ -40,8 +48,14 @@ export default class Icon extends PureComponent {
|
||||
return <HomeIcon {...options} />
|
||||
case 'like':
|
||||
return <LikeIcon {...options} />
|
||||
case 'loading':
|
||||
return <LoadingIcon {...options} />
|
||||
case 'media':
|
||||
return <MediaIcon {...options} />
|
||||
case 'notifications':
|
||||
return <NotificationsIcon {...options} />
|
||||
case 'poll':
|
||||
return <PollIcon {...options} />
|
||||
case 'repost':
|
||||
return <RepostIcon {...options} />
|
||||
case 'search':
|
||||
@ -50,7 +64,8 @@ export default class Icon extends PureComponent {
|
||||
return <ShareIcon {...options} />
|
||||
case 'verified':
|
||||
return <VerifiedIcon {...options} />
|
||||
|
||||
case 'warning':
|
||||
return <WarningIcon {...options} />
|
||||
default:
|
||||
return <NotificationsIcon {...options} />
|
||||
}
|
||||
|
26
app/javascript/gabsocial/components/icon/svgs/back_icon.js
Normal file
26
app/javascript/gabsocial/components/icon/svgs/back_icon.js
Normal file
@ -0,0 +1,26 @@
|
||||
const BackIcon = ({
|
||||
className = '',
|
||||
width = '16px',
|
||||
height = '16px',
|
||||
viewBox = '0 0 60 60',
|
||||
title = 'Back',
|
||||
}) => (
|
||||
<svg
|
||||
className={className}
|
||||
version='1.1'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
x='0px'
|
||||
y='0px'
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox={viewBox}
|
||||
xmlSpace='preserve'
|
||||
aria-label={title}
|
||||
>
|
||||
<g>
|
||||
<path d="M 19.570312 9.542969 C 20.417969 8.695312 21.75 8.695312 22.59375 9.542969 C 23.410156 10.359375 23.410156 11.71875 22.59375 12.535156 L 7.265625 27.867188 L 57.851562 27.867188 C 59.03125 27.867188 60 28.804688 60 29.984375 C 60 31.164062 59.03125 32.128906 57.851562 32.128906 L 7.265625 32.128906 L 22.59375 47.433594 C 23.410156 48.277344 23.410156 49.640625 22.59375 50.457031 C 21.75 51.300781 20.417969 51.300781 19.570312 50.457031 L 0.613281 31.496094 C -0.207031 30.679688 -0.207031 29.316406 0.613281 28.503906 Z M 19.570312 9.542969" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default BackIcon
|
@ -0,0 +1,26 @@
|
||||
const CalendarIcon = ({
|
||||
className = '',
|
||||
width = '26px',
|
||||
height = '26px',
|
||||
viewBox = '0 0 48 48',
|
||||
title = 'Calendar',
|
||||
}) => (
|
||||
<svg
|
||||
className={className}
|
||||
version='1.1'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
x='0px'
|
||||
y='0px'
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox={viewBox}
|
||||
xmlSpace='preserve'
|
||||
aria-label={title}
|
||||
>
|
||||
<g>
|
||||
<path d="M 45.234375 7.871094 C 44.558594 7.191406 43.753906 6.851562 42.828125 6.851562 L 39.402344 6.851562 L 39.402344 4.28125 C 39.402344 3.105469 38.980469 2.097656 38.144531 1.257812 C 37.304688 0.417969 36.296875 0 35.117188 0 L 33.40625 0 C 32.226562 0 31.21875 0.417969 30.378906 1.257812 C 29.542969 2.097656 29.121094 3.105469 29.121094 4.28125 L 29.121094 6.851562 L 18.84375 6.851562 L 18.84375 4.28125 C 18.84375 3.105469 18.425781 2.097656 17.585938 1.257812 C 16.746094 0.417969 15.738281 0 14.5625 0 L 12.847656 0 C 11.671875 0 10.664062 0.417969 9.824219 1.257812 C 8.984375 2.097656 8.566406 3.105469 8.566406 4.28125 L 8.566406 6.851562 L 5.140625 6.851562 C 4.210938 6.851562 3.410156 7.191406 2.730469 7.871094 C 2.050781 8.546875 1.714844 9.351562 1.714844 10.277344 L 1.714844 44.539062 C 1.714844 45.46875 2.050781 46.269531 2.730469 46.949219 C 3.410156 47.625 4.210938 47.964844 5.140625 47.964844 L 42.824219 47.964844 C 43.753906 47.964844 44.558594 47.625 45.234375 46.949219 C 45.914062 46.269531 46.253906 45.46875 46.253906 44.539062 L 46.253906 10.277344 C 46.253906 9.351562 45.914062 8.546875 45.234375 7.871094 Z M 12.847656 44.539062 L 5.140625 44.539062 L 5.140625 36.832031 L 12.847656 36.832031 Z M 12.847656 35.117188 L 5.140625 35.117188 L 5.140625 26.554688 L 12.847656 26.554688 Z M 12.847656 24.839844 L 5.140625 24.839844 L 5.140625 17.128906 L 12.847656 17.128906 Z M 12.246094 12.59375 C 12.078125 12.425781 11.992188 12.222656 11.992188 11.992188 L 11.992188 4.28125 C 11.992188 4.050781 12.078125 3.851562 12.246094 3.679688 C 12.414062 3.511719 12.617188 3.425781 12.847656 3.425781 L 14.5625 3.425781 C 14.792969 3.425781 14.996094 3.511719 15.164062 3.679688 C 15.332031 3.851562 15.417969 4.050781 15.417969 4.28125 L 15.417969 11.992188 C 15.417969 12.222656 15.332031 12.425781 15.164062 12.59375 C 14.992188 12.761719 14.792969 12.847656 14.5625 12.847656 L 12.847656 12.847656 C 12.617188 12.847656 12.414062 12.761719 12.246094 12.59375 Z M 23.125 44.539062 L 14.5625 44.539062 L 14.5625 36.832031 L 23.125 36.832031 Z M 23.125 35.117188 L 14.5625 35.117188 L 14.5625 26.554688 L 23.125 26.554688 Z M 23.125 24.839844 L 14.5625 24.839844 L 14.5625 17.128906 L 23.125 17.128906 Z M 33.40625 44.539062 L 24.839844 44.539062 L 24.839844 36.832031 L 33.40625 36.832031 Z M 33.40625 35.117188 L 24.839844 35.117188 L 24.839844 26.554688 L 33.40625 26.554688 Z M 33.40625 24.839844 L 24.839844 24.839844 L 24.839844 17.128906 L 33.40625 17.128906 Z M 32.804688 12.59375 C 32.632812 12.425781 32.550781 12.222656 32.550781 11.992188 L 32.550781 4.28125 C 32.550781 4.050781 32.632812 3.851562 32.804688 3.679688 C 32.972656 3.511719 33.171875 3.425781 33.40625 3.425781 L 35.117188 3.425781 C 35.351562 3.425781 35.550781 3.511719 35.71875 3.679688 C 35.890625 3.851562 35.972656 4.050781 35.972656 4.28125 L 35.972656 11.992188 C 35.972656 12.222656 35.890625 12.425781 35.71875 12.59375 C 35.550781 12.761719 35.351562 12.847656 35.117188 12.847656 L 33.40625 12.847656 C 33.171875 12.847656 32.972656 12.761719 32.804688 12.59375 Z M 42.824219 44.539062 L 35.117188 44.539062 L 35.117188 36.832031 L 42.824219 36.832031 Z M 42.824219 35.117188 L 35.117188 35.117188 L 35.117188 26.554688 L 42.824219 26.554688 Z M 42.824219 24.839844 L 35.117188 24.839844 L 35.117188 17.128906 L 42.824219 17.128906 Z M 42.824219 24.839844" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default CalendarIcon
|
@ -18,7 +18,7 @@ const GlobeIcon = ({
|
||||
aria-label={title}
|
||||
>
|
||||
<g>
|
||||
<circle fill='none' stroke='#616770' stroke-width='1px' cx='14' cy='14' r='13.5' />
|
||||
<circle fill='none' stroke='#616770' strokeWidth='1px' cx='14' cy='14' r='13.5' />
|
||||
<path fill='#616770' d='M 16 5 L 18 4 L 20 5 L 22 5 L 23 4 C 24 5 25 6 25 7 L 25 7 L 22 8 L 20 7 L 19 6 L 16 6 L 14 7 L 15 11 L 18 12 L 20 12 L 21 13 L 21 14 L 22 16 L 23 18 L 23 20 L 26.4 21 C 20 27 12 29 6 25 C 1 21 0 14 1 8 L 2 11 L 3 12 L 5 13 L 4 14 L 4 15 L 5 17 L 7 17 L 7 22 L 8 24 L 9 25 L 9 22 L 11 21 L 11 20 L 13 18 L 14 15 L 12 15 L 10 13 L 7 13 L 6 11 L 5 13 L 5 11 L 4 10 L 4 8 L 7 8 L 9 7 L 11 4 L 12 4 L 13 2 L 10 2 L 10 1 C 12 0 16 0 18 1 L 18 2 L 16 2 L 15 4 Z M 16 5' />
|
||||
{/*<path fill='#616770' d='M 14 27 C 21 28 28 21 28 14 C 28 6 21 0 14 0 C 8 0 3 3 1 8 L 0 8 L 1 8 C -1 15 1 24 8 26 C 10 27 12 28 14 27 Z M 24 21 L 24 20 L 24 18 C 24 18 24 18 24 18 L 22 14 L 22 13 C 22 12 22 12 22 12 L 20 11 C 20 11 20 11 20 11 L 18 12 L 15 10 L 15 8 L 16 7 L 18 7 L 19 8 C 19 8 19 8 19 8 L 22 8 C 22 8 22 8 23 8 L 25 7 C 27 12 27 17 24 21 Z M 23 4 L 22 5 L 20 4 L 18 4 C 18 4 18 4 18 4 L 16 4 L 16 4 L 16 3 L 18 3 C 18 3 18 3 18 3 L 20 2 C 21 2 22 3 23 4 Z M 8 1 L 10 2 C 10 2 10 2 10 2 L 12 3 L 12 3 L 11 4 C 10 4 10 4 10 4 L 9 6 L 7 7 L 4 8 C 3 8 3 8 3 8 L 3 10 C 3 10 3 10 3 10 L 4 11 L 4 12 L 2 10 L 2 8 C 3 5 5 3 8 1 Z M 7 17 L 5 16 L 4 15 L 4 14 L 6 12 L 7 13 C 7 13 7 14 7 14 L 10 14 L 11 16 C 11 16 11 16 12 16 L 13 16 L 13 17 L 11 19 C 11 19 11 19 11 20 L 11 21 L 9 22 C 9 22 9 22 9 22 L 9 24 L 8 24 L 7 22 L 7 17 C 7 17 7 17 7 17 Z M 1 10 L 1 11 C 1 11 1 11 2 11 L 4 13 L 3 13 C 3 13 3 13 3 14 L 3 15 C 3 15 3 15 3 15 L 4 17 C 4 17 4 17 5 17 L 7 18 L 7 22 C 7 22 7 22 7 22 L 7 24 C 8 25 8 25 8 25 L 9 25 C 9 25 9 25 9 25 C 10 25 10 25 10 25 L 10 23 L 11 21 C 12 21 12 21 12 21 L 12 20 L 13 18 C 13 18 13 18 13 18 L 14 15 C 14 15 14 15 14 15 C 14 15 14 15 14 15 L 12 15 L 11 13 C 11 13 10 13 10 13 L 7 13 L 6 11 C 6 11 6 11 6 11 C 6 11 6 11 6 11 L 5 11 L 5 11 C 5 11 5 10 5 10 L 4 10 L 4 9 L 7 8 C 7 8 7 8 7 8 L 10 7 C 10 7 10 7 10 7 L 11 5 L 12 4 C 12 4 12 4 13 4 L 13 2 C 13 2 13 2 13 2 C 13 2 13 2 13 2 L 10 1 L 9 1 C 12 0 16 0 18 1 L 18 2 L 16 2 C 16 2 15 2 15 2 L 14 4 C 14 4 14 4 15 5 C 15 5 15 5 15 5 L 16 5 C 16 5 16 5 16 5 L 18 5 L 19 5 C 19 5 19 5 19 5 L 22 6 C 22 6 22 6 22 5 L 23 5 C 24 5 24 6 25 7 L 22 7 L 20 7 L 19 6 C 19 6 19 6 19 6 L 16 6 C 16 6 16 6 16 6 L 14 7 C 14 7 14 7 14 8 L 14 11 C 14 11 15 11 15 11 L 18 13 C 18 13 18 13 18 13 L 20 12 L 21 13 L 21 14 C 21 15 21 15 21 15 L 23 18 L 23 20 C 23 20 23 20 23 20 L 24 21 C 20 27 11 28 6 24 C 1 21 0 15 1 10 Z M 1 10' /> */}
|
||||
</g>
|
||||
|
@ -0,0 +1,83 @@
|
||||
const LoadingIcon = ({
|
||||
className = '',
|
||||
width = '24px',
|
||||
height = '24px',
|
||||
viewBox = '0 0 100 100',
|
||||
}) => (
|
||||
<svg
|
||||
className={className}
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
style={{shapeRendering: 'auto'}}
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox={viewBox}
|
||||
preserveAspectRatio='xMidYMid'
|
||||
>
|
||||
<g transform='translate(82,50)'>
|
||||
<g transform='rotate(0)'>
|
||||
<circle cx='0' cy='0' r='6' fill='#30ce7d' fill-opacity='1' transform='scale(1.03405 1.03405)'>
|
||||
<animateTransform attributeName='transform' type='scale' begin='-1.0294117647058822s' values='1.5 1.5;1 1' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite'></animateTransform>
|
||||
<animate attributeName='fill-opacity' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite' values='1;0' begin='-1.0294117647058822s'></animate>
|
||||
</circle>
|
||||
</g>
|
||||
</g>
|
||||
<g transform='translate(72.62741699796952,72.62741699796952)'>
|
||||
<g transform='rotate(45)'>
|
||||
<circle cx='0' cy='0' r='6' fill='#30ce7d' fill-opacity='0.875' transform='scale(1.09655 1.09655)'>
|
||||
<animateTransform attributeName='transform' type='scale' begin='-0.8823529411764705s' values='1.5 1.5;1 1' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite'></animateTransform>
|
||||
<animate attributeName='fill-opacity' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite' values='1;0' begin='-0.8823529411764705s'></animate>
|
||||
</circle>
|
||||
</g>
|
||||
</g>
|
||||
<g transform='translate(50,82)'>
|
||||
<g transform='rotate(90)'>
|
||||
<circle cx='0' cy='0' r='6' fill='#30ce7d' fill-opacity='0.75' transform='scale(1.15905 1.15905)'>
|
||||
<animateTransform attributeName='transform' type='scale' begin='-0.7352941176470588s' values='1.5 1.5;1 1' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite'></animateTransform>
|
||||
<animate attributeName='fill-opacity' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite' values='1;0' begin='-0.7352941176470588s'></animate>
|
||||
</circle>
|
||||
</g>
|
||||
</g>
|
||||
<g transform='translate(27.37258300203048,72.62741699796952)'>
|
||||
<g transform='rotate(135)'>
|
||||
<circle cx='0' cy='0' r='6' fill='#30ce7d' fill-opacity='0.625' transform='scale(1.22155 1.22155)'>
|
||||
<animateTransform attributeName='transform' type='scale' begin='-0.588235294117647s' values='1.5 1.5;1 1' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite'></animateTransform>
|
||||
<animate attributeName='fill-opacity' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite' values='1;0' begin='-0.588235294117647s'></animate>
|
||||
</circle>
|
||||
</g>
|
||||
</g>
|
||||
<g transform='translate(18,50)'>
|
||||
<g transform='rotate(180)'>
|
||||
<circle cx='0' cy='0' r='6' fill='#30ce7d' fill-opacity='0.5' transform='scale(1.28405 1.28405)'>
|
||||
<animateTransform attributeName='transform' type='scale' begin='-0.4411764705882352s' values='1.5 1.5;1 1' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite'></animateTransform>
|
||||
<animate attributeName='fill-opacity' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite' values='1;0' begin='-0.4411764705882352s'></animate>
|
||||
</circle>
|
||||
</g>
|
||||
</g>
|
||||
<g transform='translate(27.372583002030474,27.37258300203048)'>
|
||||
<g transform='rotate(225)'>
|
||||
<circle cx='0' cy='0' r='6' fill='#30ce7d' fill-opacity='0.375' transform='scale(1.34655 1.34655)'>
|
||||
<animateTransform attributeName='transform' type='scale' begin='-0.2941176470588235s' values='1.5 1.5;1 1' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite'></animateTransform>
|
||||
<animate attributeName='fill-opacity' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite' values='1;0' begin='-0.2941176470588235s'></animate>
|
||||
</circle>
|
||||
</g>
|
||||
</g>
|
||||
<g transform='translate(50,18)'>
|
||||
<g transform='rotate(270)'>
|
||||
<circle cx='0' cy='0' r='6' fill='#30ce7d' fill-opacity='0.25' transform='scale(1.40905 1.40905)'>
|
||||
<animateTransform attributeName='transform' type='scale' begin='-0.14705882352941174s' values='1.5 1.5;1 1' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite'></animateTransform>
|
||||
<animate attributeName='fill-opacity' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite' values='1;0' begin='-0.14705882352941174s'></animate>
|
||||
</circle>
|
||||
</g>
|
||||
</g>
|
||||
<g transform='translate(72.62741699796952,27.372583002030474)'>
|
||||
<g transform='rotate(315)'>
|
||||
<circle cx='0' cy='0' r='6' fill='#30ce7d' fill-opacity='0.125' transform='scale(1.47155 1.47155)'>
|
||||
<animateTransform attributeName='transform' type='scale' begin='0s' values='1.5 1.5;1 1' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite'></animateTransform>
|
||||
<animate attributeName='fill-opacity' keyTimes='0;1' dur='1.176470588235294s' repeatCount='indefinite' values='1;0' begin='0s'></animate>
|
||||
</circle>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default LoadingIcon
|
29
app/javascript/gabsocial/components/icon/svgs/media_icon.js
Normal file
29
app/javascript/gabsocial/components/icon/svgs/media_icon.js
Normal file
@ -0,0 +1,29 @@
|
||||
const MediaIcon = ({
|
||||
className = '',
|
||||
width = '16px',
|
||||
height = '16px',
|
||||
viewBox = '0 0 48 48',
|
||||
title = 'Media',
|
||||
}) => (
|
||||
<svg
|
||||
className={className}
|
||||
version='1.1'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
x='0px'
|
||||
y='0px'
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox={viewBox}
|
||||
xmlSpace='preserve'
|
||||
aria-label={title}
|
||||
>
|
||||
<g>
|
||||
<path d="M 24.867188 37.953125 C 23.472656 37.933594 22.125 37.429688 21.058594 36.535156 L 14.019531 30.332031 C 12.910156 29.296875 11.214844 29.214844 10.015625 30.140625 L 0.00390625 37.503906 L 0.00390625 42.28125 C -0.0664062 43.5625 0.914062 44.660156 2.195312 44.734375 C 2.261719 44.738281 2.328125 44.738281 2.394531 44.734375 L 37.847656 44.734375 C 39.269531 44.734375 40.691406 43.703125 40.691406 42.28125 L 40.691406 29.753906 L 27.96875 37.113281 C 27.03125 37.675781 25.957031 37.96875 24.867188 37.953125 Z M 24.867188 37.953125" />
|
||||
<path d="M 27.191406 22.582031 C 27.191406 24.152344 25.921875 25.425781 24.351562 25.425781 C 22.78125 25.425781 21.507812 24.152344 21.507812 22.582031 C 21.507812 21.015625 22.78125 19.742188 24.351562 19.742188 C 25.921875 19.742188 27.191406 21.015625 27.191406 22.582031 Z M 27.191406 22.582031" />
|
||||
<path d="M 47.40625 8.3125 C 46.996094 7.75 46.359375 7.394531 45.664062 7.34375 L 10.464844 3.273438 C 9.78125 3.214844 9.09375 3.398438 8.527344 3.789062 C 8.027344 4.226562 7.6875 4.816406 7.558594 5.46875 L 6.980469 10.507812 L 37.847656 10.507812 C 40.792969 10.574219 43.171875 12.925781 43.273438 15.867188 L 43.273438 38.664062 C 43.273438 38.535156 43.855469 38.40625 44.113281 38.148438 C 44.648438 37.726562 44.957031 37.085938 44.953125 36.40625 L 47.988281 10.183594 C 48.054688 9.507812 47.84375 8.832031 47.40625 8.3125 Z M 47.40625 8.3125" />
|
||||
<path d="M 37.847656 13.089844 L 2.394531 13.089844 C 0.972656 13.089844 0.00390625 14.445312 0.00390625 15.867188 L 0.00390625 34.273438 L 8.527344 28.074219 C 10.691406 26.46875 13.6875 26.601562 15.695312 28.394531 L 22.800781 34.597656 C 23.871094 35.503906 25.402344 35.636719 26.609375 34.917969 L 40.691406 26.71875 L 40.691406 15.867188 C 40.59375 14.351562 39.367188 13.152344 37.847656 13.089844 Z M 24.351562 28.007812 C 21.355469 28.007812 18.925781 25.578125 18.925781 22.582031 C 18.925781 19.585938 21.355469 17.160156 24.351562 17.160156 C 27.347656 17.160156 29.777344 19.585938 29.777344 22.582031 C 29.777344 25.578125 27.347656 28.007812 24.351562 28.007812 Z M 24.351562 28.007812" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default MediaIcon
|
26
app/javascript/gabsocial/components/icon/svgs/poll_icon.js
Normal file
26
app/javascript/gabsocial/components/icon/svgs/poll_icon.js
Normal file
@ -0,0 +1,26 @@
|
||||
const PollIcon = ({
|
||||
className = '',
|
||||
width = '16px',
|
||||
height = '16px',
|
||||
viewBox = '0 0 48 48',
|
||||
title = 'Poll',
|
||||
}) => (
|
||||
<svg
|
||||
className={className}
|
||||
version='1.1'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
x='0px'
|
||||
y='0px'
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox={viewBox}
|
||||
xmlSpace='preserve'
|
||||
aria-label={title}
|
||||
>
|
||||
<g>
|
||||
<path d="M 42.667969 0 L 5.332031 0 C 2.386719 0 0 2.386719 0 5.332031 L 0 42.667969 C 0 45.613281 2.386719 48 5.332031 48 L 42.667969 48 C 45.613281 48 48 45.613281 48 42.667969 L 48 5.332031 C 48 2.386719 45.613281 0 42.667969 0 Z M 16 37.332031 L 10.667969 37.332031 L 10.667969 18.667969 L 16 18.667969 Z M 26.667969 37.332031 L 21.332031 37.332031 L 21.332031 10.667969 L 26.667969 10.667969 Z M 37.332031 37.332031 L 32 37.332031 L 32 26.667969 L 37.332031 26.667969 Z M 37.332031 37.332031" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default PollIcon
|
@ -21,8 +21,8 @@ const ShareIcon = ({
|
||||
<circle cx="18" cy="5" r="3"/>
|
||||
<circle cx="6" cy="12" r="3"/>
|
||||
<circle cx="18" cy="19" r="3"/>
|
||||
<line stroke='#666' stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8.59" x2="15.42" y1="13.51" y2="17.49" />
|
||||
<line stroke='#666' stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="15.41" x2="8.59" y1="6.51" y2="10.49" />
|
||||
<line stroke='#666' strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" x1="8.59" x2="15.42" y1="13.51" y2="17.49" />
|
||||
<line stroke='#666' strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" x1="15.41" x2="8.59" y1="6.51" y2="10.49" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
@ -0,0 +1,26 @@
|
||||
const WarningIcon = ({
|
||||
className = '',
|
||||
width = '16px',
|
||||
height = '16px',
|
||||
viewBox = '0 0 48 48',
|
||||
title = 'Warning',
|
||||
}) => (
|
||||
<svg
|
||||
className={className}
|
||||
version='1.1'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
x='0px'
|
||||
y='0px'
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox={viewBox}
|
||||
xmlSpace='preserve'
|
||||
aria-label={title}
|
||||
>
|
||||
<g>
|
||||
<path d="M 47.003906 35.996094 L 30.046875 4.824219 C 27.324219 0.238281 20.679688 0.234375 17.953125 4.824219 L 1 35.996094 C -1.785156 40.683594 1.585938 46.617188 7.042969 46.617188 L 40.957031 46.617188 C 46.410156 46.617188 49.789062 40.6875 47.003906 35.996094 Z M 24 40.992188 C 22.449219 40.992188 21.1875 39.730469 21.1875 38.179688 C 21.1875 36.628906 22.449219 35.367188 24 35.367188 C 25.550781 35.367188 26.8125 36.628906 26.8125 38.179688 C 26.8125 39.730469 25.550781 40.992188 24 40.992188 Z M 26.8125 29.742188 C 26.8125 31.292969 25.550781 32.554688 24 32.554688 C 22.449219 32.554688 21.1875 31.292969 21.1875 29.742188 L 21.1875 15.679688 C 21.1875 14.128906 22.449219 12.867188 24 12.867188 C 25.550781 12.867188 26.8125 14.128906 26.8125 15.679688 Z M 26.8125 29.742188" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default WarningIcon
|
@ -164,7 +164,7 @@ class Item extends ImmutablePureComponent {
|
||||
|
||||
thumbnail = (
|
||||
<a
|
||||
className='media-item__thumbnail'
|
||||
className={[styles.default, styles.overflowHidden].join(' ')}
|
||||
href={attachment.get('remote_url') || originalUrl}
|
||||
onClick={this.handleClick}
|
||||
target='_blank'
|
||||
@ -184,9 +184,9 @@ class Item extends ImmutablePureComponent {
|
||||
const autoPlay = !isIOS() && autoPlayGif !== false;
|
||||
|
||||
thumbnail = (
|
||||
<div className={classNames('media-gallery__gifv', { autoplay: autoPlay })}>
|
||||
<div className={[styles.default, styles.overflowHidden, styles.heigh100PC, styles.width100PC].join(' ')}>
|
||||
<video
|
||||
className='media-item__gifv'
|
||||
className={[styles.default, styles.cursorPointer, styles.objectFitCover, styles.width100PC, styles.height100PC, styles.z1].join(' ')}
|
||||
aria-label={attachment.get('description')}
|
||||
title={attachment.get('description')}
|
||||
role='application'
|
||||
@ -208,8 +208,8 @@ class Item extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames('media-gallery__item', { standalone })} key={attachment.get('id')} style={{ position, float, left, top, right, bottom, height, width: `${width}%` }}>
|
||||
<canvas width={32} height={32} ref={this.setCanvasRef} className={classNames('media-gallery__preview', { 'media-gallery__preview--hidden': visible && this.state.loaded })} />
|
||||
<div className={[styles.defeault, styles.positionAbsolute].join(' ')} key={attachment.get('id')} style={{ position, float, left, top, right, bottom, height, width: `${width}%` }}>
|
||||
<canvas width={0} height={0} ref={this.setCanvasRef} className={styles.displayNone} />
|
||||
{visible && thumbnail}
|
||||
</div>
|
||||
);
|
||||
@ -512,10 +512,15 @@ class MediaGallery extends PureComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='media-gallery' style={style} ref={this.handleRef}>
|
||||
<div
|
||||
className={[styles.default, styles.overflowHidden, styles.borderColorSubtle, styles.borderTop1PX, styles.borderBottom1PX].join(' ')}
|
||||
style={style}
|
||||
ref={this.handleRef}
|
||||
>
|
||||
{ /*
|
||||
<div className={classNames('spoiler-button', { 'spoiler-button--minified': visible })}>
|
||||
{spoilerButton}
|
||||
</div>
|
||||
</div> */ }
|
||||
|
||||
{children}
|
||||
</div>
|
||||
|
@ -1,43 +1,55 @@
|
||||
import ColumnHeader from './column_header'
|
||||
import Header from './header'
|
||||
|
||||
export default class PageLayout extends PureComponent {
|
||||
static propTypes = {
|
||||
layout: PropTypes.object,
|
||||
title: PropTypes.string,
|
||||
showBackBtn: PropTypes.boolean,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, layout } = this.props
|
||||
const { children, title, showBackBtn, layout } = this.props
|
||||
|
||||
const right = layout.RIGHT || null
|
||||
const headerRight = layout.HEADER_RIGHT || null
|
||||
|
||||
return (
|
||||
<div className={[styles.default, styles.flexRow, styles.width100PC, styles.backgroundColorSubtle3].join(' ')}>
|
||||
|
||||
<Header />
|
||||
|
||||
<main role='main' className={[styles.default, styles.flexShrink1, styles.flexGrow1, styles.borderColorSubtle2, styles.borderLeft1PX].join(' ')}>
|
||||
<div className={[styles.default, styles.height53PX, styles.borderBottom1PX, styles.borderColorSubtle2, styles.backgroundColorSubtle3].join(' ')}>
|
||||
|
||||
<div className={[styles.default, styles.height53PX, styles.borderBottom1PX, styles.borderColorSubtle2, styles.backgroundColorSubtle3, styles.z3, styles.top0, styles.positionFixed].join(' ')}>
|
||||
<div className={[styles.default, styles.height53PX, styles.paddingLeft15PX, styles.width1015PX, styles.flexRow, styles.justifyContentSpaceBetween].join(' ')}>
|
||||
<div className={[styles.default, styles.width660PX].join(' ')}>
|
||||
test
|
||||
<ColumnHeader title={title} />
|
||||
</div>
|
||||
<div className={[styles.default, styles.width325PX].join(' ')}>
|
||||
{ headerRight }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={[styles.default, styles.height53PX].join(' ')}></div>
|
||||
|
||||
<div className={[styles.default, styles.width1015PX, styles.flexRow, styles.justifyContentSpaceBetween, styles.paddingLeft15PX, styles.paddingVertical15PX].join(' ')}>
|
||||
<div className={[styles.default, styles.width660PX, styles.z1].join(' ')}>
|
||||
<div className={styles.default}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={[styles.default, styles.width325PX].join(' ')}>
|
||||
<div className={styles.default}>
|
||||
{right}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import classNames from 'classnames';
|
||||
import classNames from 'classnames/bind';
|
||||
import Overlay from 'react-overlays/lib/Overlay';
|
||||
import Icon from '../icon';
|
||||
import SearchPopout from '../search_popout';
|
||||
@ -41,7 +41,19 @@ export default class Search extends PureComponent {
|
||||
const { expanded } = this.state;
|
||||
|
||||
const hasValue = value ? value.length > 0 || submitted : 0;
|
||||
const iconClass = hasValue ? 'active' : '';
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
const btnClasses = cx({
|
||||
default: 1,
|
||||
cursorPointer: 1,
|
||||
marginRight5PX: 1,
|
||||
paddingHorizontal10PX: 1,
|
||||
paddingVertical10PX: 1,
|
||||
circle: 1,
|
||||
backgroundColorBrandLight: 1,
|
||||
displayNone: !hasValue,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={[styles.default, styles.justifyContentCenter, styles.height53PX].join(' ')}>
|
||||
@ -57,7 +69,7 @@ export default class Search extends PureComponent {
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
/>
|
||||
<div role='button' tabIndex='0' className={[styles.default, styles.cursorPointer, styles.marginRight5PX, styles.paddingHorizontal10PX, styles.paddingVertical10PX, styles.circle, styles.backgroundColorBrandLight].join(' ')} onClick={handleClear}>
|
||||
<div role='button' tabIndex='0' className={btnClasses} onClick={handleClear}>
|
||||
<Icon id='close' width='10px' height='10px' className={styles.fillColorWhite} aria-label={placeholder} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -265,6 +265,8 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
const { intl, hidden, featured, otherAccounts, unread, showThread, group, promoted } = this.props;
|
||||
|
||||
// console.log("replies:", this.props.replies)
|
||||
|
||||
let { status, account, ...other } = this.props;
|
||||
|
||||
if (status === null) return null;
|
||||
@ -391,6 +393,7 @@ class Status extends ImmutablePureComponent {
|
||||
);
|
||||
}
|
||||
} else if (status.get('spoiler_text').length === 0 && status.get('card')) {
|
||||
console.log("card:", status.get('card'))
|
||||
media = (
|
||||
<Card
|
||||
onOpenMedia={this.props.onOpenMedia}
|
||||
@ -424,8 +427,6 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
const statusUrl = `/${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`;
|
||||
|
||||
console.log("const replies = state.getIn(['contexts', 'replies', id]);", state.getIn(['contexts', 'replies', id]))
|
||||
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
<div
|
||||
@ -472,7 +473,7 @@ class Status extends ImmutablePureComponent {
|
||||
<Icon id='globe' width='12px' height='12px' className={[styles.default, styles.displayInline, styles.marginLeft5PX, styles.fillColorSubtle].join(' ')}/>
|
||||
|
||||
{
|
||||
status.get('group') &&
|
||||
!!status.get('group') &&
|
||||
<Fragment>
|
||||
<span className={[styles.default, styles.text, styles.fontSize12PX, styles.marginLeft5PX, styles.colorSubtle].join(' ')}>•</span>
|
||||
<NavLink
|
||||
@ -502,7 +503,7 @@ class Status extends ImmutablePureComponent {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={[styles.default, styles.paddingHorizontal15PX, styles.marginBottom15PX].join(' ')}>
|
||||
<div className={styles.default}>
|
||||
<StatusContent
|
||||
status={status}
|
||||
reblogContent={reblogContent}
|
||||
@ -513,7 +514,7 @@ class Status extends ImmutablePureComponent {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{ /* media */ }
|
||||
{ media }
|
||||
|
||||
{ /* status.get('quote') && <StatusQuote
|
||||
id={status.get('quote')}
|
||||
|
@ -57,21 +57,8 @@ class StatusActionBarItem extends PureComponent {
|
||||
disabled: PropTypes.bool,
|
||||
}
|
||||
|
||||
state = {
|
||||
hovering: false,
|
||||
}
|
||||
|
||||
handleOnMouseEnter = () => {
|
||||
this.setState({ hovering: true })
|
||||
}
|
||||
|
||||
handleOnMouseLeave = () => {
|
||||
this.setState({ hovering: false })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { title, onClick, icon, active, disabled } = this.props
|
||||
const { hovering } = this.state
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
@ -90,11 +77,9 @@ class StatusActionBarItem extends PureComponent {
|
||||
width100PC: 1,
|
||||
radiusSmall: 1,
|
||||
outlineFocusBrand: 1,
|
||||
backgroundTransparent: !hovering,
|
||||
backgroundSubtle: hovering,
|
||||
backgroundTransparent: 1,
|
||||
backgroundSubtle_onHover: 1,
|
||||
colorSubtle: 1,
|
||||
// colorSubtle: !hovering,
|
||||
// colorBrand: hovering,
|
||||
})
|
||||
|
||||
return (
|
||||
@ -104,8 +89,6 @@ class StatusActionBarItem extends PureComponent {
|
||||
onClick={onClick}
|
||||
active={active}
|
||||
disabled={disabled}
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
>
|
||||
<Icon width='16px' height='16px' id={icon} className={[styles.default, styles.marginRight10PX, styles.fillColorSubtle].join(' ')} />
|
||||
{title}
|
||||
@ -358,9 +341,66 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
},
|
||||
]
|
||||
|
||||
const hasInteractions = favoriteCount > 0 || replyCount > 0 || reblogCount > 0
|
||||
const shouldCondense = (!!status.get('card') || status.get('media_attachments').size > 0) && !hasInteractions
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
const containerClasses = cx({
|
||||
default: 1,
|
||||
paddingHorizontal10PX: 1,
|
||||
marginTop10PX: !shouldCondense,
|
||||
marginTop5PX: shouldCondense,
|
||||
})
|
||||
|
||||
const innerContainerClasses = cx({
|
||||
default: 1,
|
||||
paddingVertical2PX: 1,
|
||||
flexRow: 1,
|
||||
width100PC: 1,
|
||||
borderTop1PX: !shouldCondense,
|
||||
borderColorSubtle: !shouldCondense,
|
||||
marginTop5PX: hasInteractions,
|
||||
})
|
||||
|
||||
const interactionBtnClasses = cx({
|
||||
default: 1,
|
||||
text: 1,
|
||||
colorSubtle: 1,
|
||||
cursorPointer: 1,
|
||||
fontSize15PX: 1,
|
||||
fontWeightNormal: 1,
|
||||
marginRight10PX: 1,
|
||||
paddingVertical5PX: 1,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={[styles.default, styles.marginTop10PX, styles.paddingHorizontal10PX].join(' ')}>
|
||||
<div className={[styles.default, styles.paddingVertical2PX, styles.flexRow, styles.borderTop1PX, styles.borderColorSubtle].join(' ')}>
|
||||
<div className={containerClasses}>
|
||||
{
|
||||
hasInteractions &&
|
||||
<div className={[styles.default, styles.flexRow, styles.paddingHorizontal5PX].join(' ')}>
|
||||
{ favoriteCount > 0 &&
|
||||
<button className={interactionBtnClasses}>
|
||||
{favoriteCount}
|
||||
Likes
|
||||
</button>
|
||||
}
|
||||
{ replyCount > 0 &&
|
||||
<button className={interactionBtnClasses}>
|
||||
{replyCount}
|
||||
Comments
|
||||
</button>
|
||||
}
|
||||
{ reblogCount > 0 &&
|
||||
<button className={interactionBtnClasses}>
|
||||
{reblogCount}
|
||||
Reposts
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div className={innerContainerClasses}>
|
||||
<div className={[styles.default, styles.flexRow, styles.paddingVertical2PX, styles.width100PC].join(' ')}>
|
||||
{
|
||||
items.map((item, i) => (
|
||||
<StatusActionBarItem key={`status-action-bar-item-${i}`} {...item} />
|
||||
@ -378,6 +418,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
/>
|
||||
</div>*/}
|
||||
</div>
|
||||
</div>
|
||||
<div className='status-action-bar__comment'>
|
||||
{/*<ComposeFormContainer shouldCondense statusId={status.get('id')} />*/}
|
||||
</div>
|
||||
|
@ -2,7 +2,7 @@ import { Fragment } from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
||||
import classnames from 'classnames';
|
||||
import classNames from 'classnames/bind'
|
||||
import { isRtl } from '../../utils/rtl';
|
||||
import Permalink from '../permalink/permalink';
|
||||
import Icon from '../icon';
|
||||
@ -12,6 +12,7 @@ const MAX_HEIGHT = 200;
|
||||
const messages = defineMessages({
|
||||
showMore: { id: 'status.show_more', defaultMessage: 'Show more' },
|
||||
showLess: { id: 'status.show_less', defaultMessage: 'Show less' },
|
||||
readMore: { id: 'status.read_more', defaultMessage: 'Read more' },
|
||||
})
|
||||
|
||||
export default
|
||||
@ -161,16 +162,20 @@ class StatusContent extends ImmutablePureComponent {
|
||||
const content = { __html: this.getHtmlContent() };
|
||||
const spoilerContent = { __html: status.get('spoilerHtml') };
|
||||
const directionStyle = { direction: 'ltr' };
|
||||
const classNames = classnames('status__content', {
|
||||
'status__content--with-action': this.props.onClick && this.context.router,
|
||||
'status__content--with-spoiler': status.get('spoiler_text').length > 0,
|
||||
'status__content--collapsed': this.state.collapsed === true,
|
||||
});
|
||||
// const classNames = '';
|
||||
// classnames('status__content', {
|
||||
// 'status__content--with-action': this.props.onClick && this.context.router,
|
||||
// 'status__content--with-spoiler': status.get('spoiler_text').length > 0,
|
||||
// 'status__content--collapsed': this.state.collapsed === true,
|
||||
// // styles.paddingHorizontal15PX, styles.marginBottom15PX
|
||||
// });
|
||||
|
||||
if (isRtl(status.get('search_index'))) {
|
||||
directionStyle.direction = 'rtl';
|
||||
}
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
if (status.get('spoiler_text').length > 0) {
|
||||
let mentionsPlaceholder = '';
|
||||
|
||||
@ -187,7 +192,7 @@ class StatusContent extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames} ref={this.setRef} tabIndex='0' style={directionStyle} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}>
|
||||
<div className={[].join(' ')} ref={this.setRef} tabIndex='0' style={directionStyle} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}>
|
||||
<p style={{ marginBottom: hidden && status.get('mentions').isEmpty() ? '0px' : null }}>
|
||||
<span dangerouslySetInnerHTML={spoilerContent} lang={status.get('language')} />
|
||||
{' '}
|
||||
@ -200,8 +205,15 @@ class StatusContent extends ImmutablePureComponent {
|
||||
</div>
|
||||
);
|
||||
} else if (this.props.onClick) {
|
||||
const hasMarginBottom = !!status.get('card') || !!status.get('poll') || status.get('media_attachments').size > 0
|
||||
|
||||
const containerClasses = cx({
|
||||
paddingHorizontal15PX: 1,
|
||||
marginBottom15PX: hasMarginBottom,
|
||||
})
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={containerClasses}>
|
||||
<div
|
||||
ref={this.setRef}
|
||||
tabIndex='0'
|
||||
@ -212,17 +224,16 @@ class StatusContent extends ImmutablePureComponent {
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onMouseUp={this.handleMouseUp}
|
||||
/>
|
||||
|
||||
{
|
||||
this.state.collapsed &&
|
||||
<button
|
||||
className={[styles.default].join(' ')}
|
||||
className={[styles.default, styles.displayFlex, styles.cursorPointer, styles.paddingVertical2PX, styles.text, styles.colorBlack, styles.fontWeightBold, styles.fontSize15PX].join(' ')}
|
||||
onClick={this.props.onClick}
|
||||
>
|
||||
<FormattedMessage id='status.read_more' defaultMessage='Read more' />
|
||||
{intl.formatMessage(messages.readMore)}
|
||||
</button>
|
||||
}
|
||||
</Fragment>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -230,7 +241,7 @@ class StatusContent extends ImmutablePureComponent {
|
||||
<div
|
||||
tabIndex='0'
|
||||
ref={this.setRef}
|
||||
className={[styles.statusContent].join(' ')}
|
||||
className={[styles.paddingHorizontal15PX, styles.marginBottom15PX, styles.statusContent].join(' ')}
|
||||
style={directionStyle}
|
||||
dangerouslySetInnerHTML={content}
|
||||
lang={status.get('language')}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { me } from '../../initial_state';
|
||||
import ComposeFormContainer from '../../features/compose/containers/compose_form_container';
|
||||
import Avatar from '../avatar';
|
||||
import { me } from '../initial_state';
|
||||
import ComposeFormContainer from '../features/compose/containers/compose_form_container';
|
||||
import Avatar from './avatar';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
@ -26,7 +26,7 @@ class TimelineComposeBlock extends ImmutablePureComponent {
|
||||
const { account, size, ...rest } = this.props;
|
||||
|
||||
return (
|
||||
<section className={[styles.default, styles.radiusSmall, styles.border1PX, styles.borderColorSubtle, styles.backgroundWhite, styles.marginBottom15PX].join(' ')}>
|
||||
<section className={[styles.default, styles.overflowHidden, styles.radiusSmall, styles.border1PX, styles.borderColorSubtle, styles.backgroundWhite, styles.marginBottom15PX].join(' ')}>
|
||||
<div className={[styles.default, styles.backgroundSubtle, styles.borderBottom1PX, styles.borderColorSubtle, styles.paddingHorizontal15PX, styles.paddingVertical2PX].join(' ')}>
|
||||
<h1 className={[styles.default, styles.text, styles.colorSubtle, styles.fontSize12PX, styles.fontWeight500, styles.lineHeight2, styles.paddingVertical2PX].join(' ')}>
|
||||
Create Post
|
@ -1 +0,0 @@
|
||||
export { default } from './timeline_compose_block';
|
@ -1,19 +0,0 @@
|
||||
.timeline-compose-block {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
@include gab-container-standards();
|
||||
|
||||
.emoji-picker-wrapper {
|
||||
.emoji-picker-dropdown {
|
||||
top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.compose-form {
|
||||
flex: 1 1;
|
||||
padding: 0 0 0 20px !important;
|
||||
position: relative;
|
||||
}
|
||||
}
|
@ -50,6 +50,7 @@ const makeMapStateToProps = () => {
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
status: getStatus(state, props),
|
||||
replies: state.getIn(['contexts', 'replies', props.id]),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
|
@ -7,7 +7,7 @@ import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../acti
|
||||
import { fetchAccountIdentityProofs } from '../../actions/identity_proofs';
|
||||
import { me } from '../../initial_state';
|
||||
import StatusList from '../../components/status_list/status_list';
|
||||
import ColumnIndicator from '../../components/column_indicator/column_indicator';
|
||||
import ColumnIndicator from '../../components/column_indicator';
|
||||
import Column from '../../components/column';
|
||||
import SectionHeadlineBar from '../../components/section_headline_bar' ;
|
||||
|
||||
|
@ -1,23 +1,36 @@
|
||||
import { length } from 'stringz';
|
||||
import classNames from 'classnames';
|
||||
import { length } from 'stringz'
|
||||
|
||||
export default class CharacterCounter extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
text: PropTypes.string.isRequired,
|
||||
max: PropTypes.number.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const diff = this.props.max - length(this.props.text);
|
||||
|
||||
const classes = classNames('character-counter', {
|
||||
'character-counter--over': (diff < 0),
|
||||
});
|
||||
const radius = 12
|
||||
const circumference = 2 * Math.PI * radius
|
||||
const diff = length(this.props.text) / this.props.max
|
||||
const dashoffset = circumference * (1 - diff)
|
||||
|
||||
return (
|
||||
<div className='character-counter__wrapper'>
|
||||
<span className={classes}>{diff}</span>
|
||||
<div className={[styles.default, styles.marginRight10PX, styles.justifyContentCenter, styles.alignItemsCenter].join(' ')}>
|
||||
<svg width="32" height="32" viewBox="0 0 32 32">
|
||||
<circle fill='none' cx="16" cy="16" r="12" fill="none" stroke="#e6e6e6" stroke-width="2" />
|
||||
<circle style={{
|
||||
// transform: 'rotate(-90deg)',
|
||||
strokeDashoffset: dashoffset,
|
||||
strokeDasharray: circumference,
|
||||
}}
|
||||
fill='none'
|
||||
cx="16"
|
||||
cy="16"
|
||||
r="12"
|
||||
strokeWidth="2"
|
||||
strokeLinecap='round'
|
||||
stroke='#21cf7a'
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ export default class ComposeExtraButton extends PureComponent {
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
>
|
||||
<Icon icon={icon} width='18px' height='18px' />
|
||||
<Icon id={icon} width='18px' height='18px' className={styles.fillColorSubtle} />
|
||||
<span className={titleClasses}>
|
||||
{title}
|
||||
</span>
|
||||
|
@ -299,6 +299,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
</div>
|
||||
<CharacterCounter max={maxPostCharacterCount} text={text} />
|
||||
<Button
|
||||
className={[styles.fontSize15PX, styles.paddingHorizontal15PX].join(' ')}
|
||||
text={intl.formatMessage(scheduledAt ? messages.schedulePost : messages.publish)}
|
||||
onClick={this.handleSubmit}
|
||||
disabled={disabledButton}
|
||||
|
@ -54,7 +54,7 @@ class PollButton extends PureComponent {
|
||||
title={intl.formatMessage(active ? messages.remove_poll : messages.title)}
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
icon='tasks'
|
||||
icon='poll'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ class UploadButton extends ImmutablePureComponent {
|
||||
title={intl.formatMessage(messages.title)}
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
icon='upload'
|
||||
icon='media'
|
||||
>
|
||||
<label>
|
||||
<span className={styles.displayNone}>{intl.formatMessage(messages.upload)}</span>
|
||||
|
@ -5,7 +5,7 @@ import { fetchPinnedStatuses } from '../../actions/pin_statuses';
|
||||
import { meUsername } from '../../initial_state';
|
||||
import Column from '../../components/column';
|
||||
import StatusList from '../../components/status_list/status_list';
|
||||
import ColumnIndicator from '../../components/column_indicator/column_indicator';
|
||||
import ColumnIndicator from '../../components/column_indicator';
|
||||
|
||||
const mapStateToProps = (state, { params: { username } }) => {
|
||||
return {
|
||||
|
@ -115,113 +115,131 @@ export default class Card extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
renderVideo () {
|
||||
const { card } = this.props;
|
||||
const content = { __html: addAutoPlay(card.get('html')) };
|
||||
const { width } = this.state;
|
||||
const ratio = card.get('width') / card.get('height');
|
||||
const height = width / ratio;
|
||||
const { card } = this.props
|
||||
const content = { __html: addAutoPlay(card.get('html')) }
|
||||
const { width } = this.state
|
||||
const ratio = card.get('width') / card.get('height')
|
||||
const height = width / ratio
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={this.setRef}
|
||||
className='status-card__image status-card-video'
|
||||
className={[styles.default, styles.backgroundColorSubtle3, styles.positionAbsolute, styles.top0, styles.right0, styles.bottom0, styles.left0, styles.statusCardVideo].join(' ')}
|
||||
dangerouslySetInnerHTML={content}
|
||||
style={{
|
||||
height,
|
||||
paddingBottom: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { card } = this.props;
|
||||
const { width, embedded } = this.state;
|
||||
const { card } = this.props
|
||||
const { width, embedded } = this.state
|
||||
|
||||
if (card === null) {
|
||||
return null;
|
||||
}
|
||||
if (card === null) return null
|
||||
|
||||
const maxDescription = 160
|
||||
const cardImg = card.get('image')
|
||||
const provider = card.get('provider_name').length === 0 ? decodeIDNA(getHostname(card.get('url'))) : card.get('provider_name')
|
||||
const horizontal = (card.get('width') > card.get('height') && (card.get('width') + 100 >= width)) || card.get('type') !== 'link' || embedded
|
||||
const interactive = card.get('type') !== 'link'
|
||||
|
||||
const maxDescription = 150;
|
||||
const cardImg = card.get('image');
|
||||
const provider = card.get('provider_name').length === 0 ? decodeIDNA(getHostname(card.get('url'))) : card.get('provider_name');
|
||||
const horizontal = (card.get('width') > card.get('height') && (card.get('width') + 100 >= width)) || card.get('type') !== 'link' || embedded;
|
||||
const interactive = card.get('type') !== 'link';
|
||||
const className = classnames('status-card', {
|
||||
horizontal,
|
||||
interactive,
|
||||
compact: !cardImg && !interactive,
|
||||
});
|
||||
const title = interactive ?
|
||||
<a className='status-card__title' href={card.get('url')} title={card.get('title')} rel='noopener' target='_blank'>
|
||||
<strong>{card.get('title')}</strong>
|
||||
(
|
||||
<a
|
||||
className={[styles.default, styles.displayFlex, styles.text, styles.noUnderline, styles.overflowWrapBreakWord, styles.colorBlack, styles.fontSize15PX, styles.fontWeight500].join(' ')}
|
||||
href={card.get('url')}
|
||||
title={card.get('title')}
|
||||
rel='noopener'
|
||||
target='_blank'
|
||||
>
|
||||
{card.get('title')}
|
||||
</a>
|
||||
: <strong className='status-card__title' title={card.get('title')}>{card.get('title')}</strong>;
|
||||
)
|
||||
: (
|
||||
<span className={[styles.default, styles.displayFlex, styles.text, styles.overflowWrapBreakWord, styles.colorBlack, styles.fontSize15PX, styles.fontWeight500].join(' ')}>
|
||||
{card.get('title')}
|
||||
</span>
|
||||
)
|
||||
|
||||
const description = (
|
||||
<div className='status-card__content'>
|
||||
<div className={[styles.default, styles.flexNormal, styles.paddingHorizontal10PX, styles.paddingVertical10PX, styles.borderColorSubtle, styles.borderLeft1PX].join(' ')}>
|
||||
{title}
|
||||
{!horizontal && <p className='status-card__description'>{trim(card.get('description') || '', maxDescription)}</p>}
|
||||
<span className='status-card__host'>
|
||||
<Icon id='link' fixedWidth />
|
||||
{' '}
|
||||
<p className={[styles.default, styles.displayFlex, styles.text, styles.marginVertical5PX, styles.overflowWrapBreakWord, styles.colorSubtle, styles.fontSize13PX, styles.fontWeightNormal].join(' ')}>
|
||||
{trim(card.get('description') || '', maxDescription)}
|
||||
</p>
|
||||
<span className={[styles.default, styles.marginTopAuto, styles.flexRow, styles.alignItemsCenter, styles.colorSubtle, styles.text, styles.displayFlex, styles.textOverflowEllipsis, styles.fontSize13PX].join(' ')}>
|
||||
<Icon id='link' width='12px' height='12px' className={[styles.fillColorSubtle, styles.marginRight5PX].join(' ')} fixedWidth />
|
||||
{provider}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
||||
let embed = '';
|
||||
let thumbnail = card ? <div style={{ backgroundImage: `url(${cardImg})` }} className='status-card__image-image' /> : thumbnail = <div className='status-card__image-image' />;
|
||||
let embed = ''
|
||||
let thumbnail = interactive ?
|
||||
<img src={cardImg} className={[styles.default, styles.objectFitCover, styles.positionAbsolute, styles.width100PC, styles.height100PC, styles.top0, styles.right0, styles.bottom0, styles.left0].join(' ')} />
|
||||
:
|
||||
<img src={cardImg} className={[styles.default, styles.objectFitCover, styles.width400PX, styles.height260PX].join(' ')} />
|
||||
|
||||
if (interactive) {
|
||||
if (embedded) {
|
||||
embed = this.renderVideo();
|
||||
} else {
|
||||
let iconVariant = 'play';
|
||||
embed = this.renderVideo()
|
||||
}
|
||||
|
||||
let iconVariant = 'play'
|
||||
|
||||
if (card.get('type') === 'photo') {
|
||||
iconVariant = 'search-plus';
|
||||
}
|
||||
|
||||
embed = (
|
||||
<div className='status-card__image'>
|
||||
{thumbnail}
|
||||
<div className='status-card__actions'>
|
||||
<div>
|
||||
<button onClick={this.handleEmbedClick}><Icon id={iconVariant} /></button>
|
||||
{horizontal && <a href={card.get('url')} target='_blank' rel='noopener'><Icon id='external-link' /></a>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
iconVariant = 'search-plus'
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className} ref={this.setRef}>
|
||||
{embed}
|
||||
<div className={[styles.default, styles.width100PC, styles.paddingHorizontal10PX].join(' ')}>
|
||||
<div className={[styles.default, styles.overflowHidden, styles.width100PC, styles.borderColorSubtle2, styles.border1PX, styles.radiusSmall].join(' ')}>
|
||||
<div className={[styles.default, styles.width100PC].join(' ')}>
|
||||
<div className={[styles.default, styles.width100PC, styles.paddingTop5625PC].join(' ')}>
|
||||
{ !!embed && embed}
|
||||
{ !embed && thumbnail}
|
||||
{ !embed &&
|
||||
<div className={[styles.default, styles.positionAbsolute, styles.top0, styles.right0, styles.left0, styles.bottom0, styles.alignItemsCenter, styles.justifyContentCenter].join(' ')}>
|
||||
<button
|
||||
className={[styles.default, styles.cursorPointer, styles.backgroundColorOpaque, styles.radiusSmall, styles.paddingVertical15PX, styles.paddingHorizontal15PX].join(' ')}
|
||||
onClick={this.handleEmbedClick}
|
||||
>
|
||||
<Icon id={iconVariant} className={[styles.fillColorWhite].join(' ')}/>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{description}
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
)
|
||||
} else if (cardImg) {
|
||||
embed = (
|
||||
<div className='status-card__image'>
|
||||
<div className={[styles.default].join(' ')}>
|
||||
{thumbnail}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
} else {
|
||||
embed = (
|
||||
<div className='status-card__image'>
|
||||
<Icon id='file-text' />
|
||||
<div className={[styles.default, styles.paddingVertical15PX, styles.paddingHorizontal15PX, styles.width72PX, styles.alignItemsCenter, styles.justifyContentCenter].join(' ')}>
|
||||
<Icon id='file-text' width='22px' height='22px' className={styles.fillColorSubtle} />
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<a href={card.get('url')} className={className} target='_blank' rel='noopener' ref={this.setRef}>
|
||||
<div className={[styles.default, styles.width100PC, styles.paddingHorizontal10PX].join(' ')}>
|
||||
<a
|
||||
href={card.get('url')}
|
||||
className={[styles.default, styles.cursorPointer, styles.flexRow, styles.overflowHidden, styles.noUnderline, styles.width100PC, styles.borderColorSubtle2, styles.border1PX, styles.radiusSmall].join(' ')}
|
||||
rel='noopener'
|
||||
ref={this.setRef}
|
||||
>
|
||||
{embed}
|
||||
{description}
|
||||
</a>
|
||||
);
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ import HomePage from '../../pages/home_page';
|
||||
// import GroupSidebarPanel from '../groups/sidebar_panel';
|
||||
|
||||
import {
|
||||
// Status,
|
||||
Status,
|
||||
// GettingStarted,
|
||||
// CommunityTimeline,
|
||||
// AccountTimeline,
|
||||
@ -230,10 +230,10 @@ class SwitchingColumnsArea extends PureComponent {
|
||||
|
||||
<Redirect from='/@:username/pins' to='/:username/pins' />
|
||||
<WrappedRoute path='/:username/pins' component={PinnedStatuses} page={ProfilePage} content={children} />
|
||||
|
||||
*/ }
|
||||
<Redirect from='/@:username/posts/:statusId' to='/:username/posts/:statusId' exact />
|
||||
<WrappedRoute path='/:username/posts/:statusId' publicRoute exact layout={LAYOUT.STATUS} component={Status} content={children} />
|
||||
|
||||
{ /*
|
||||
<Redirect from='/@:username/posts/:statusId/reblogs' to='/:username/posts/:statusId/reblogs' />
|
||||
<WrappedRoute path='/:username/posts/:statusId/reblogs' layout={LAYOUT.STATUS} component={Reblogs} content={children} />
|
||||
|
||||
|
@ -54,7 +54,7 @@ export default class WrappedRoute extends Component {
|
||||
}
|
||||
|
||||
renderLoading = () => {
|
||||
return <ColumnIndicator type='loading' />;
|
||||
return <div />
|
||||
}
|
||||
|
||||
renderError = (props) => {
|
||||
|
@ -16,8 +16,8 @@ export default class HomePage extends PureComponent {
|
||||
|
||||
return (
|
||||
<PageLayout
|
||||
title='Home'
|
||||
layout={{
|
||||
HEADER: <span>hello</span>,
|
||||
HEADER_RIGHT: <Search />,
|
||||
RIGHT: (
|
||||
<Fragment>
|
||||
|
@ -16,6 +16,11 @@ body {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
.statusCardVideo iframe {
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.default {
|
||||
display: flex;
|
||||
flex-basis: auto;
|
||||
@ -93,7 +98,7 @@ body {
|
||||
.resizeNone { resize: none; }
|
||||
|
||||
.circle { border-radius: 9999px; }
|
||||
.radiusSmall { border-radius: 4px; }
|
||||
.radiusSmall { border-radius: 8px; }
|
||||
|
||||
.borderColorSubtle2 { border-color: #e5e9ed; }
|
||||
.borderColorSubtle { border-color: #ECECED; }
|
||||
@ -122,13 +127,16 @@ body {
|
||||
.backgroundTransparent { background-color: transparent; }
|
||||
.backgroundPanel { background-color: #aaa; }
|
||||
.backgroundSubtle { background-color: #F5F8FA; }
|
||||
.backgroundSubtle_onHover:hover { background-color: #F5F8FA; }
|
||||
.backgroundSubtle2 { background-color: #e8ecef; }
|
||||
.backgroundColorSubtle3 { background-color: #F6F6F9; }
|
||||
.backgroundWhite { background-color: #fff; }
|
||||
.backgroundColorBrandLightOpaque { background-color: rgba(54, 233, 145, 0.1); }
|
||||
.backgroundColorOpaque { background-color: rgba(0,0,0, 0.4); }
|
||||
.backgroundColorBrandLight { background-color: #36e991; }
|
||||
.backgroundColorBrand { background-color: #21cf7a; }
|
||||
.backgroundColorBrandDark { background-color: #38A16B; }
|
||||
.backgroundColorBrandDark_onHover:hover { background-color: #38A16B; }
|
||||
.colorBlack { color: #000; }
|
||||
.colorWhite { color: #fff; }
|
||||
.colorSubtle { color: #666; }
|
||||
@ -161,9 +169,11 @@ body {
|
||||
.height53PX { height: 53px; }
|
||||
.height72PX { height: 72px; }
|
||||
.height122PX { height: 122px; }
|
||||
.height260PX { height: 260px; }
|
||||
|
||||
.width1015PX { width: 1015px; }
|
||||
.width660PX { width: 660px; }
|
||||
.width400PX { width: 400px; }
|
||||
.width325PX { width: 325px; }
|
||||
.width250PX { width: 250px; }
|
||||
.width100PC { width: 100%; }
|
||||
@ -175,6 +185,7 @@ body {
|
||||
|
||||
.textAlignCenter { text-align: center; }
|
||||
|
||||
.fontSize24PX { font-size: 24px; }
|
||||
.fontSize19PX { font-size: 19px; }
|
||||
.fontSize16PX { font-size: 16px; }
|
||||
.fontSize15PX { font-size: 15px; }
|
||||
@ -189,6 +200,7 @@ body {
|
||||
|
||||
.noUnderline { text-decoration: none; }
|
||||
.underline { text-decoration: underline; }
|
||||
.underline_onHover:hover { text-decoration: underline; }
|
||||
|
||||
.objectFitCover { object-fit: cover; }
|
||||
|
||||
@ -218,8 +230,11 @@ body {
|
||||
.marginBottom10PX { margin-bottom: 10px; }
|
||||
.marginTop10PX { margin-top: 10px; }
|
||||
.marginTop5PX { margin-top: 5px; }
|
||||
.marginTopAuto { margin-top: auto; }
|
||||
.marginTopNeg30PX { margin-top: -30px; }
|
||||
|
||||
.paddingTop5625PC { padding-top: 56.25%; }
|
||||
|
||||
.paddingHorizontal15PX {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
|
Loading…
x
Reference in New Issue
Block a user