Progress
This commit is contained in:
parent
e37500c0cf
commit
bebc39f150
@ -8,6 +8,8 @@ import Avatar from '../avatar'
|
||||
import DisplayName from '../display_name'
|
||||
import IconButton from '../icon_button'
|
||||
import Icon from '../icon'
|
||||
import Button from '../button'
|
||||
import Text from '../text'
|
||||
|
||||
const messages = defineMessages({
|
||||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||
@ -126,9 +128,17 @@ class Account extends ImmutablePureComponent {
|
||||
>
|
||||
<DisplayName account={account} />
|
||||
</NavLink>
|
||||
<button className={[_s.default, _s.marginTop5PX, _s.colorBrand, _s.text, _s.cursorPointer, _s.fontSize14PX, _s.circle, _s.border1PX, _s.borderColorBrand, _s.paddingHorizontal20PX, _s.paddingVertical5PX].join(' ')}>
|
||||
{intl.formatMessage(messages.follow)}
|
||||
</button>
|
||||
<Button
|
||||
outline
|
||||
narrow
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={_s.marginTop5PX}
|
||||
>
|
||||
<Text color='inherit'>
|
||||
{intl.formatMessage(messages.follow)}
|
||||
</Text>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.marginLeftAuto].join(' ')}>
|
||||
|
@ -203,7 +203,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
<div className={[_s.default, _s.marginLeft5PX].join(' ')}>
|
||||
<Textarea
|
||||
inputRef={this.setTextbox}
|
||||
className={[_s.default, _s.backgroundWhite, _s.lineHeight125, _s.resizeNone, _s.paddingVertical15PX, _s.outlineFocusBrand, _s.fontSize16PX, _s.text, _s.displayBlock].join(' ')}
|
||||
className={[_s.default, _s.backgroundColorPrimary, _s.lineHeight125, _s.resizeNone, _s.paddingVertical15PX, _s.outlineFocusBrand, _s.fontSize16PX, _s.text, _s.displayBlock].join(' ')}
|
||||
disabled={disabled}
|
||||
placeholder={placeholder}
|
||||
autoFocus={autoFocus}
|
||||
|
@ -3,7 +3,7 @@ import Text from './text'
|
||||
export default class Badge extends PureComponent {
|
||||
static propTypes = {
|
||||
children: PropTypes.string,
|
||||
popover: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
}
|
||||
|
||||
state = {
|
||||
@ -19,15 +19,17 @@ export default class Badge extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, popover } = this.props
|
||||
const { children, description } = this.props
|
||||
const { hovering } = this.state
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Text color='secondary' size='small' className={_s.marginVertical5PX}>
|
||||
{children}
|
||||
</Text>
|
||||
</div>
|
||||
<Text
|
||||
color='white'
|
||||
size='extraSmall'
|
||||
className={[_s.backgroundColorBrand, _s.paddingHorizontal5PX, _s.lineHeight125, _s.radiusSmall].join(' ')}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
import { Fragment } from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import classNames from 'classnames/bind'
|
||||
import Icon from './icon'
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
@ -7,6 +9,7 @@ const COLORS = {
|
||||
primary: 'primary',
|
||||
secondary: 'secondary',
|
||||
tertiary: 'tertiary',
|
||||
white: 'white',
|
||||
brand: 'brand',
|
||||
error: 'error',
|
||||
none: 'none',
|
||||
@ -21,15 +24,22 @@ export default class Button extends PureComponent {
|
||||
onClick: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
icon: PropTypes.string,
|
||||
iconWidth: PropTypes.string,
|
||||
iconHeight: PropTypes.string,
|
||||
iconClassName: PropTypes.string,
|
||||
color: PropTypes.string,
|
||||
backgroundColor: PropTypes.string,
|
||||
block: PropTypes.bool,
|
||||
text: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
outline: PropTypes.bool,
|
||||
narrow: PropTypes.bool,
|
||||
underlineOnHover: PropTypes.bool,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
color: COLORS.brand,
|
||||
color: COLORS.white,
|
||||
backgroundColor: COLORS.brand,
|
||||
}
|
||||
|
||||
handleClick = (e) => {
|
||||
@ -47,7 +57,27 @@ export default class Button extends PureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { block, className, disabled, text, to, children, href, outline, color } = this.props
|
||||
const {
|
||||
block,
|
||||
className,
|
||||
disabled,
|
||||
text,
|
||||
to,
|
||||
icon,
|
||||
iconWidth,
|
||||
iconHeight,
|
||||
iconClassName,
|
||||
children,
|
||||
href,
|
||||
outline,
|
||||
color,
|
||||
backgroundColor,
|
||||
underlineOnHover,
|
||||
narrow,
|
||||
...otherProps
|
||||
} = this.props
|
||||
|
||||
const theIcon = !!icon ? <Icon id={icon} width={iconWidth} height={iconWidth} className={iconClassName} /> : undefined
|
||||
|
||||
// : todo :
|
||||
const classes = cx(className, {
|
||||
@ -57,26 +87,43 @@ export default class Button extends PureComponent {
|
||||
cursorPointer: 1,
|
||||
textAlignCenter: 1,
|
||||
|
||||
backgroundColorBrand: !text && !outline,
|
||||
backgroundColorPrimary: backgroundColor === COLORS.white,
|
||||
backgroundColorBrand: backgroundColor === COLORS.brand,
|
||||
backgroundTransparent: backgroundColor === COLORS.none,
|
||||
|
||||
// colorPrimary: 1,
|
||||
// colorSecondary: 1,
|
||||
colorWhite: [].indexOf(color) > -1,
|
||||
colorBrand: text || [].indexOf(color) > -1,
|
||||
colorPrimary: color === COLORS.primary,
|
||||
colorSecondary: color === COLORS.secondary,
|
||||
colorWhite: color === COLORS.white,
|
||||
colorBrand: color === COLORS.brand,
|
||||
|
||||
// borderColorBrand: 1,
|
||||
// border1PX: 1,
|
||||
borderColorBrand: color === COLORS.brand && outline,
|
||||
border1PX: outline,
|
||||
|
||||
circle: !text,
|
||||
|
||||
paddingVertical10PX: !text,
|
||||
paddingVertical5PX: narrow,
|
||||
paddingVertical10PX: !text && !narrow,
|
||||
paddingHorizontal15PX: !text,
|
||||
|
||||
width100PC: block,
|
||||
|
||||
underline_onHover: underlineOnHover,
|
||||
|
||||
backgroundColorBrandDark_onHover: backgroundColor === COLORS.brand,
|
||||
|
||||
backgroundColorBrand_onHover: color === COLORS.brand && outline,
|
||||
colorWhite_onHover: color === COLORS.brand && outline,
|
||||
})
|
||||
|
||||
const tagName = !!href ? 'a' : !!to ? 'NavLink' : 'button'
|
||||
|
||||
const theChildren = !!icon ? (
|
||||
<Fragment>
|
||||
{theIcon}
|
||||
{children}
|
||||
</Fragment>
|
||||
) : children
|
||||
|
||||
return React.createElement(
|
||||
tagName,
|
||||
{
|
||||
@ -86,8 +133,9 @@ export default class Button extends PureComponent {
|
||||
to: to || undefined,
|
||||
to: href || undefined,
|
||||
onClick: this.handleClick || undefined,
|
||||
...otherProps
|
||||
},
|
||||
children,
|
||||
theChildren,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { injectIntl, defineMessages } from 'react-intl'
|
||||
import Icon from './icon'
|
||||
import Button from './button'
|
||||
import Heading from './heading'
|
||||
|
||||
const messages = defineMessages({
|
||||
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
|
||||
@ -46,7 +48,7 @@ class ColumnHeader extends PureComponent {
|
||||
this.historyBack()
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { title, showBackBtn, icon, active, children, actions, intl: { formatMessage } } = this.props
|
||||
const { collapsed } = this.state
|
||||
|
||||
@ -58,11 +60,13 @@ class ColumnHeader extends PureComponent {
|
||||
<Icon className={[_s.marginRight5PX, _s.fillColorBrand].join(' ')} id='back' width='20px' height='20px' />
|
||||
</button>
|
||||
}
|
||||
<h1 role='heading' className={[_s.default, _s.height100PC, _s.justifyContentCenter].join(' ')}>
|
||||
<span className={[_s.default, _s.text, _s.fontSize24PX, _s.fontWeightMedium, _s.colorPrimary].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.height100PC, _s.justifyContentCenter].join(' ')}>
|
||||
<Heading size='h1'>
|
||||
{title}
|
||||
</span>
|
||||
</h1>
|
||||
</Heading>
|
||||
</div>
|
||||
|
||||
{
|
||||
!!actions &&
|
||||
<div className={[_s.default, _s.backgroundTransparent, _s.flexRow, _s.alignItemsCenter, _s.justifyContentCenter, _s.marginLeftAuto].join(' ')}>
|
||||
@ -81,75 +85,6 @@ class ColumnHeader extends PureComponent {
|
||||
}
|
||||
</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,17 +1,19 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import Icon from './icon';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import Badge from './badge'
|
||||
import Icon from './icon'
|
||||
|
||||
export default class DisplayName extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
multiline: PropTypes.bool,
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const { account } = this.props;
|
||||
const { account, multiline } = this.props
|
||||
|
||||
// : todo :
|
||||
return (
|
||||
<span className={[_s.default, _s.flexRow, _s.maxWidth100PC, _s.alignItemsCenter].join(' ')}>
|
||||
<bdi className={[_s.text, _s.whiteSpaceNoWrap, _s.textOverflowEllipsis].join(' ')}>
|
||||
@ -23,15 +25,24 @@ export default class DisplayName extends ImmutablePureComponent {
|
||||
{
|
||||
account.get('is_verified') &&
|
||||
<Icon id='verified' width='16px' height='16px' className={_s.default} title='Verified Account' />
|
||||
/*<Icon id='verified' width='15px' height='15px' className={[_s.default]} title='PRO' />
|
||||
<Icon id='verified' width='15px' height='15px' className={[_s.default]} title='Donor' />
|
||||
<Icon id='verified' width='15px' height='15px' className={[_s.default]} title='Investor' />*/
|
||||
}
|
||||
{ /*
|
||||
account.get('is_pro') &&
|
||||
<Icon id='verified' width='16px' height='16px' className={_s.default} title='Gab PRO' />
|
||||
*/ }
|
||||
{ /*
|
||||
account.get('is_donor') &&
|
||||
<Icon id='verified' width='16px' height='16px' className={_s.default} title='Gab Donor' />
|
||||
*/ }
|
||||
{ /*
|
||||
account.get('is_investor') &&
|
||||
<Icon id='verified' width='16px' height='16px' className={_s.default} title='Gab Investor' />
|
||||
*/ }
|
||||
<span className={[_s.text, _s.displayFlex, _s.flexNormal, _s.flexShrink1, _s.fontSize15PX, _s.overflowWrapBreakWord, _s.textOverflowEllipsis, _s.marginLeft5PX, _s.colorSecondary, _s.fontWeightNormal, _s.lineHeight125].join(' ')}>
|
||||
@{account.get('acct')}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
export default class Divider extends PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div className={[_s.default, _s.borderBottom1PX, _s.bordercolorSecondary2, _s.marginBottom15PX, _s.width100PC].join(' ')} />
|
||||
<div className={[_s.default, _s.borderBottom1PX, _s.borderColorSecondary2, _s.marginBottom15PX, _s.width100PC].join(' ')} />
|
||||
)
|
||||
}
|
||||
}
|
11
app/javascript/gabsocial/components/dot_text_seperator.js
Normal file
11
app/javascript/gabsocial/components/dot_text_seperator.js
Normal file
@ -0,0 +1,11 @@
|
||||
import Text from './text'
|
||||
|
||||
export default class DotTextSeperator extends PureComponent {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Text size='small' color='secondary' className={_s.marginLeft5PX}>•</Text>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -45,7 +45,7 @@ class GroupListItem extends ImmutablePureComponent {
|
||||
if (!relationships) return null
|
||||
|
||||
const unreadCount = relationships.get('unread_count')
|
||||
|
||||
|
||||
const subtitle = unreadCount > 0 ? (
|
||||
<Fragment>
|
||||
{shortNumberFormat(unreadCount)}
|
||||
@ -57,7 +57,7 @@ class GroupListItem extends ImmutablePureComponent {
|
||||
return (
|
||||
<NavLink
|
||||
to={`/groups/${group.get('id')}`}
|
||||
className={[_s.default, _s.noUnderline, _s.marginTop5PX, _s.overflowHidden, _s.radiusSmall, _s.marginBottom10PX, _s.border1PX, _s.bordercolorSecondary, _s.backgroundSubtle_onHover].join(' ')}
|
||||
className={[_s.default, _s.noUnderline, _s.marginTop5PX, _s.overflowHidden, _s.radiusSmall, _s.marginBottom10PX, _s.border1PX, _s.borderColorSecondary, _s.backgroundSubtle_onHover].join(' ')}
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
>
|
||||
|
@ -4,6 +4,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { shortNumberFormat } from '../utils/numbers'
|
||||
import Text from './text'
|
||||
import Button from './button'
|
||||
|
||||
export default class HashtagItem extends ImmutablePureComponent {
|
||||
|
||||
@ -29,15 +30,29 @@ export default class HashtagItem extends ImmutablePureComponent {
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
to='/test'
|
||||
to='/tags/test'
|
||||
className={[_s.default, _s.noUnderline, _s.backgroundSubtle_onHover, _s.paddingHorizontal15PX, _s.paddingVertical5PX].join(' ')}
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
>
|
||||
<Text color='brand' size='medium' weight='bold' className={_s.paddingVertical2PX}>
|
||||
#randomhashtag
|
||||
</Text>
|
||||
<Text color='secondary' size='small' underline={hovering} className={_s.paddingVertical2PX}>
|
||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
||||
<div>
|
||||
<Text color='brand' size='medium' weight='bold' className={[_s.paddingVertical2PX, _s.lineHeight15].join(' ')}>
|
||||
#randomhashtag
|
||||
</Text>
|
||||
</div>
|
||||
<Button
|
||||
text
|
||||
backgroundColor='none'
|
||||
color='none'
|
||||
icon='caret-down'
|
||||
iconWidth='8px'
|
||||
iconHeight='8px'
|
||||
iconClassName={_s.fillcolorSecondary}
|
||||
className={_s.marginLeftAuto}
|
||||
/>
|
||||
</div>
|
||||
<Text color='secondary' size='small' className={_s.paddingVertical2PX}>
|
||||
10,240 Gabs
|
||||
</Text>
|
||||
</NavLink>
|
||||
|
@ -13,7 +13,6 @@ const SIZES = {
|
||||
|
||||
export default class Heading extends PureComponent {
|
||||
static propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.any,
|
||||
size: PropTypes.oneOf(Object.keys(SIZES)),
|
||||
}
|
||||
@ -23,31 +22,36 @@ export default class Heading extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, children, size } = this.props
|
||||
const { children, size } = this.props
|
||||
|
||||
const classes = cx({
|
||||
default: 1,
|
||||
text: 1,
|
||||
|
||||
colorPrimary: [SIZES.h1, SIZES.h3].indexOf(size) > -1,
|
||||
colorSecondary: [SIZES.h2, SIZES.h4].indexOf(size) > -1,
|
||||
colorSecondary: [SIZES.h2, SIZES.h4, SIZES.h5].indexOf(size) > -1,
|
||||
|
||||
fontSize24PX: size === SIZES.h1,
|
||||
fontSize19PX: size === SIZES.h2,
|
||||
fontSize16PX: size === SIZES.h3,
|
||||
fontSize13PX: size === SIZES.h4,
|
||||
fontSize12PX: size === SIZES.h5,
|
||||
|
||||
marginTop5PX: [SIZES.h2, SIZES.h4].indexOf(size) > -1,
|
||||
|
||||
lineHeight2: size === SIZES.h5,
|
||||
paddingVertical2PX: size === SIZES.h5,
|
||||
|
||||
// fontWeightNormal: weight === WEIGHTS.normal,
|
||||
// fontWeightMedium: weight === WEIGHTS.medium,
|
||||
fontWeightBold: [SIZES.h3, SIZES.h4].indexOf(size) > -1
|
||||
fontWeightMedium: [SIZES.h1, SIZES.h5].indexOf(size) > -1,
|
||||
fontWeightBold: [SIZES.h3, SIZES.h4].indexOf(size) > -1,
|
||||
})
|
||||
|
||||
return React.createElement(
|
||||
size,
|
||||
{
|
||||
className: classes,
|
||||
role: 'heading',
|
||||
},
|
||||
children,
|
||||
)
|
||||
|
@ -1,9 +1,65 @@
|
||||
import classNames from 'classnames/bind'
|
||||
import Button from './button'
|
||||
import Icon from './icon'
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
export default class Input extends PureComponent {
|
||||
static propTypes = {
|
||||
placeholder: PropTypes.string,
|
||||
prependIcon: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
hasClear: PropTypes.bool,
|
||||
onChange: PropTypes.func,
|
||||
onKeyUp: PropTypes.func,
|
||||
onFocus: PropTypes.func,
|
||||
onBlur: PropTypes.func,
|
||||
onClear: PropTypes.func,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children } = this.props
|
||||
const { placeholder, prependIcon, value, hasClear, onChange, onKeyUp, onFocus, onBlur, onClear } = this.props
|
||||
|
||||
const inputClasses = cx({
|
||||
default: 1,
|
||||
text: 1,
|
||||
outlineNone: 1,
|
||||
lineHeight125: 1,
|
||||
displayBlock: 1,
|
||||
paddingVertical10PX: 1,
|
||||
backgroundTransparent: 1,
|
||||
fontSize15PX: 1,
|
||||
flexGrow1: 1,
|
||||
paddingHorizontal5PX: !!prependIcon,
|
||||
paddingLeft15PX: !prependIcon,
|
||||
paddingRight15PX: !hasClear,
|
||||
})
|
||||
|
||||
return (
|
||||
<input />
|
||||
<div className={[_s.default, _s.backgroundColorPrimary, _s.border1PX, _s.borderColorSecondary, _s.flexRow, _s.circle, _s.alignItemsCenter].join(' ')}>
|
||||
{
|
||||
!!prependIcon &&
|
||||
<Icon id={prependIcon} width='16px' height='16px' className={[_s.marginLeft15PX, _s.marginRight5PX].join(' ')} />
|
||||
}
|
||||
|
||||
<input
|
||||
className={inputClasses}
|
||||
type='text'
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onKeyUp={onKeyUp}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
|
||||
{
|
||||
hasClear &&
|
||||
<div role='button' tabIndex='0' className={'btnClasses'} onClick={onClear}>
|
||||
<Icon id='close' width='10px' height='10px' className={_s.fillColorWhite} aria-label='Clear' />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -19,14 +19,14 @@ export default class DefaultLayout extends PureComponent {
|
||||
|
||||
<Sidebar />
|
||||
|
||||
<main role='main' className={[_s.default, _s.flexShrink1, _s.flexGrow1, _s.bordercolorSecondary2, _s.borderLeft1PX].join(' ')}>
|
||||
<main role='main' className={[_s.default, _s.flexShrink1, _s.flexGrow1, _s.borderColorSecondary2, _s.borderLeft1PX].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.height53PX, _s.borderBottom1PX, _s.bordercolorSecondary2, _s.backgroundcolorSecondary3, _s.z3, _s.top0, _s.positionFixed].join(' ')}>
|
||||
<div className={[_s.default, _s.height53PX, _s.borderBottom1PX, _s.borderColorSecondary2, _s.backgroundcolorSecondary3, _s.z3, _s.top0, _s.positionFixed].join(' ')}>
|
||||
<div className={[_s.default, _s.height53PX, _s.paddingLeft15PX, _s.width1015PX, _s.flexRow, _s.justifyContentSpaceBetween].join(' ')}>
|
||||
<div className={[_s.default, _s.width660PX].join(' ')}>
|
||||
<div className={[_s.default, _s.width645PX].join(' ')}>
|
||||
<ColumnHeader title={title} showBackBtn={showBackBtn} actions={actions} />
|
||||
</div>
|
||||
<div className={[_s.default, _s.width325PX].join(' ')}>
|
||||
<div className={[_s.default, _s.width340PX].join(' ')}>
|
||||
<Search />
|
||||
</div>
|
||||
</div>
|
||||
@ -35,15 +35,15 @@ export default class DefaultLayout extends PureComponent {
|
||||
<div className={[_s.default, _s.height53PX].join(' ')}></div>
|
||||
|
||||
<div className={[_s.default, _s.width1015PX, _s.flexRow, _s.justifyContentSpaceBetween, _s.paddingLeft15PX, _s.paddingVertical15PX].join(' ')}>
|
||||
<div className={[_s.default, _s.width660PX, _s.z1].join(' ')}>
|
||||
<div className={[_s.default, _s.width645PX, _s.z1].join(' ')}>
|
||||
<div className={_s.default}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.width325PX].join(' ')}>
|
||||
<div className={[_s.default, _s.width340PX].join(' ')}>
|
||||
<Sticky top={73} enabled>
|
||||
<div className={[_s.default, _s.width325PX].join(' ')}>
|
||||
<div className={[_s.default, _s.width340PX].join(' ')}>
|
||||
{layout}
|
||||
</div>
|
||||
</Sticky>
|
||||
|
@ -16,7 +16,7 @@ export default class ProfileLayout extends PureComponent {
|
||||
|
||||
<Sidebar />
|
||||
|
||||
<main role='main' className={[_s.default, _s.flexShrink1, _s.flexGrow1, _s.bordercolorSecondary2, _s.borderLeft1PX].join(' ')}>
|
||||
<main role='main' className={[_s.default, _s.flexShrink1, _s.flexGrow1, _s.borderColorSecondary2, _s.borderLeft1PX].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.height350PX, _s.width100PC].join(' ')}>
|
||||
<img
|
||||
|
@ -1,5 +1,4 @@
|
||||
import moment from 'moment'
|
||||
import classNames from 'classnames/bind'
|
||||
import {
|
||||
FormattedMessage,
|
||||
defineMessages,
|
||||
@ -11,8 +10,11 @@ import {
|
||||
source_url,
|
||||
me,
|
||||
} from '../initial_state'
|
||||
import Text from './text'
|
||||
import Button from './button'
|
||||
|
||||
const messages = defineMessages({
|
||||
help: { id: 'getting_started.help', defaultMessage: 'Help' },
|
||||
invite: { id: 'getting_started.invite', defaultMessage: 'Invite people' },
|
||||
hotkeys: { id: 'navigation_bar.keyboard_shortcuts', defaultMessage: 'Hotkeys' },
|
||||
security: { id: 'getting_started.security', defaultMessage: 'Security' },
|
||||
@ -20,7 +22,7 @@ const messages = defineMessages({
|
||||
developers: { id: 'getting_started.developers', defaultMessage: 'Developers' },
|
||||
terms: { id: 'getting_started.terms', defaultMessage: 'Terms of Service' },
|
||||
dmca: { id: 'getting_started.dmca', defaultMessage: 'DMCA' },
|
||||
terms: { id: 'getting_started.terms_of_sale', defaultMessage: 'Terms of Sale' },
|
||||
salesTerms: { id: 'getting_started.terms_of_sale', defaultMessage: 'Terms of Sale' },
|
||||
privacy: { id: 'getting_started.privacy', defaultMessage: 'Privacy Policy' },
|
||||
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
|
||||
})
|
||||
@ -31,9 +33,6 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
},
|
||||
})
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
const currentYear = moment().format('YYYY')
|
||||
|
||||
export default @connect(null, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class LinkFooter extends PureComponent {
|
||||
@ -43,29 +42,18 @@ class LinkFooter extends PureComponent {
|
||||
onOpenHotkeys: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
state = {
|
||||
hoveringItemIndex: null,
|
||||
}
|
||||
|
||||
onMouseEnterLinkFooterItem = (i) => {
|
||||
this.setState({
|
||||
hoveringItemIndex: i,
|
||||
})
|
||||
}
|
||||
|
||||
onMouseLeaveLinkFooterItem = () => {
|
||||
this.setState({
|
||||
hoveringItemIndex: null,
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { onOpenHotkeys, intl } = this.props
|
||||
const { hoveringItemIndex } = this.state
|
||||
|
||||
const currentYear = moment().format('YYYY')
|
||||
|
||||
const linkFooterItems = [
|
||||
{
|
||||
to: '#',
|
||||
to: '/help',
|
||||
text: intl.formatMessage(messages.help),
|
||||
requiresUser: true,
|
||||
},
|
||||
{
|
||||
onClick: onOpenHotkeys,
|
||||
text: intl.formatMessage(messages.hotkeys),
|
||||
requiresUser: true,
|
||||
@ -93,7 +81,7 @@ class LinkFooter extends PureComponent {
|
||||
},
|
||||
{
|
||||
to: '/about/sales',
|
||||
text: intl.formatMessage(messages.terms),
|
||||
text: intl.formatMessage(messages.salesTerms),
|
||||
},
|
||||
{
|
||||
to: '/about/privacy',
|
||||
@ -108,64 +96,50 @@ class LinkFooter extends PureComponent {
|
||||
]
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.paddingHorizontal10PX].join(' ')}>
|
||||
<div className={[_s.default, _s.paddingHorizontal10PX, _s.marginBottom15PX].join(' ')}>
|
||||
<nav aria-label='Footer' role='navigation' className={[_s.default, _s.flexWrap, _s.flexRow].join(' ')}>
|
||||
{
|
||||
linkFooterItems.map((linkFooterItem, i) => {
|
||||
if (linkFooterItem.requiresUser && !me) return null
|
||||
const classes = cx({
|
||||
default: 1,
|
||||
fontSize13PX: 1,
|
||||
text: 1,
|
||||
marginVertical5PX: 1,
|
||||
paddingRight15PX: 1,
|
||||
cursorPointer: 1,
|
||||
backgroundTransparent: 1,
|
||||
colorSecondary: i !== hoveringItemIndex,
|
||||
noUnderline: i !== hoveringItemIndex,
|
||||
colorPrimary: i === hoveringItemIndex,
|
||||
underline: i === hoveringItemIndex,
|
||||
})
|
||||
|
||||
if (linkFooterItem.onClick) {
|
||||
return (
|
||||
<button
|
||||
key={`link-footer-item-${i}`}
|
||||
data-method={linkFooterItem.logout ? 'delete' : null}
|
||||
onClick={linkFooterItem.onClick || null}
|
||||
onMouseEnter={() => this.onMouseEnterLinkFooterItem(i)}
|
||||
onMouseLeave={() => this.onMouseLeaveLinkFooterItem(i)}
|
||||
className={classes}
|
||||
>
|
||||
{linkFooterItem.text}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
<Button
|
||||
text
|
||||
underlineOnHover
|
||||
color='none'
|
||||
backgroundColor='none'
|
||||
key={`link-footer-item-${i}`}
|
||||
href={linkFooterItem.to}
|
||||
data-method={linkFooterItem.logout ? 'delete' : null}
|
||||
onMouseEnter={() => this.onMouseEnterLinkFooterItem(i)}
|
||||
onMouseLeave={() => this.onMouseLeaveLinkFooterItem(i)}
|
||||
className={classes}
|
||||
onClick={linkFooterItem.onClick || null}
|
||||
className={[_s.marginVertical5PX, _s.paddingRight15PX].join(' ')}
|
||||
>
|
||||
{linkFooterItem.text}
|
||||
</a>
|
||||
<Text size='small' color='secondary'>
|
||||
{linkFooterItem.text}
|
||||
</Text>
|
||||
</Button>
|
||||
)
|
||||
})
|
||||
}
|
||||
<span className={[_s.default, _s.text, _s.fontSize13PX, _s.colorSecondary, _s.marginVertical5PX].join(' ')}>© {currentYear} Gab AI, Inc.</span>
|
||||
</nav>
|
||||
|
||||
<p className={[_s.default, _s.text, _s.fontSize13PX, _s.colorSecondary, _s.marginTop10PX, _s.marginBottom15PX].join(' ')}>
|
||||
<Text size='small' color='secondary' className={_s.marginTop10PX}>
|
||||
© {currentYear} Gab AI, Inc.
|
||||
</Text>
|
||||
|
||||
<Text size='small' color='secondary' tagName='p' className={_s.marginTop10PX}>
|
||||
<FormattedMessage
|
||||
id='getting_started.open_source_notice'
|
||||
defaultMessage='Gab Social is open source software. You can contribute or report issues on our self-hosted GitLab at {gitlab}.'
|
||||
values={{ gitlab: <a href={source_url} className={[_s.inherit].join(' ')} rel='noopener' target='_blank'>{repository}</a> }}
|
||||
values={{
|
||||
gitlab: (
|
||||
<a href={source_url} className={_s.inherit} rel='noopener' target='_blank'>
|
||||
{repository}
|
||||
</a>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</Text>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
38
app/javascript/gabsocial/components/list.js
Normal file
38
app/javascript/gabsocial/components/list.js
Normal file
@ -0,0 +1,38 @@
|
||||
import ScrollableList from './scrollable_list'
|
||||
import ListItem from './list_item'
|
||||
|
||||
export default class List extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
items: PropTypes.array,
|
||||
scrollKey: PropTypes.string,
|
||||
emptyMessage: PropTypes.any,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { items, scrollKey, emptyMessage } = this.props
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.backgroundColorPrimary, _s.radiusSmall, _s.overflowHidden, _s.border1PX, _s.borderColorSecondary].join(' ')}>
|
||||
<ScrollableList
|
||||
scrollKey={scrollKey}
|
||||
emptyMessage={emptyMessage}
|
||||
>
|
||||
{
|
||||
items.map((item, i) => {
|
||||
return (
|
||||
<ListItem
|
||||
key={`list-item-${i}`}
|
||||
to={item.to}
|
||||
title={item.title}
|
||||
isLast={items.length - 1 === i}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ScrollableList>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
44
app/javascript/gabsocial/components/list_item.js
Normal file
44
app/javascript/gabsocial/components/list_item.js
Normal file
@ -0,0 +1,44 @@
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import classNames from 'classnames/bind'
|
||||
import Icon from './icon'
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
export default class ListItem extends PureComponent {
|
||||
static propTypes = {
|
||||
isLast: PropTypes.bool,
|
||||
to: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { to, title, isLast } = this.props
|
||||
|
||||
const containerClasses = cx({
|
||||
default: 1,
|
||||
cursorPointer: 1,
|
||||
noUnderline: 1,
|
||||
paddingHorizontal15PX: 1,
|
||||
paddingVertical15PX: 1,
|
||||
flexRow: 1,
|
||||
alignItemsCenter: 1,
|
||||
backgroundSubtle_onHover: 1,
|
||||
borderColorSecondary: !isLast,
|
||||
borderBottom1PX: !isLast,
|
||||
})
|
||||
|
||||
return (
|
||||
<NavLink to={to} className={containerClasses} >
|
||||
<span className={[_s.default, _s.text, _s.colorPrimary, _s.fontSize14PX].join(' ')}>
|
||||
{title}
|
||||
</span>
|
||||
<Icon
|
||||
id='angle-right'
|
||||
width='10px'
|
||||
height='10px'
|
||||
className={[_s.marginLeftAuto, _s.fillColorBlack].join(' ')}
|
||||
/>
|
||||
</NavLink>
|
||||
)
|
||||
}
|
||||
}
|
@ -517,7 +517,7 @@ class MediaGallery extends PureComponent {
|
||||
default: 1,
|
||||
displayBlock: 1,
|
||||
overflowHidden: 1,
|
||||
bordercolorSecondary: size === 1,
|
||||
borderColorSecondary: size === 1,
|
||||
borderTop1PX: size === 1,
|
||||
borderBottom1PX: size === 1,
|
||||
paddingHorizontal5PX: size > 1,
|
||||
|
@ -31,24 +31,17 @@ class GroupSidebarPanel extends ImmutablePureComponent {
|
||||
return (
|
||||
<PanelLayout
|
||||
title={intl.formatMessage(messages.title)}
|
||||
buttonTitle={intl.formatMessage(messages.all)}
|
||||
buttonTo='/groups/browse/member'
|
||||
headerButtonTitle={intl.formatMessage(messages.all)}
|
||||
headerButtonTo='/groups/browse/member'
|
||||
footerButtonTitle={count > 6 ? intl.formatMessage(messages.show_all) : undefined}
|
||||
footerButtonTo={count > 6 ? '/groups/browse/member' : undefined}
|
||||
>
|
||||
<div className={_s.default}>
|
||||
{
|
||||
groupIds.slice(0, 6).map(groupId => (
|
||||
<GroupListItem
|
||||
key={`group-panel-item-${groupId}`}
|
||||
id={groupId}
|
||||
/>
|
||||
<GroupListItem key={`group-panel-item-${groupId}`} id={groupId} />
|
||||
))
|
||||
}
|
||||
{
|
||||
count > 6 &&
|
||||
<Button to='/groups/browse/member' block text>
|
||||
{intl.formatMessage(messages.show_all)}
|
||||
</Button>
|
||||
}
|
||||
</div>
|
||||
</PanelLayout>
|
||||
)
|
||||
|
@ -44,7 +44,12 @@ class HashtagsPanel extends ImmutablePureComponent {
|
||||
// }
|
||||
|
||||
return (
|
||||
<PanelLayout title={intl.formatMessage(messages.title)} noPadding>
|
||||
<PanelLayout
|
||||
noPadding
|
||||
title={intl.formatMessage(messages.title)}
|
||||
footerButtonTitle={intl.formatMessage(messages.show_all)}
|
||||
footerButtonTo='/explore'
|
||||
>
|
||||
<div className={_s.default}>
|
||||
{ /* hashtags && hashtags.map(hashtag => (
|
||||
<HashtagingItem key={hashtag.get('name')} hashtag={hashtag} />
|
||||
@ -55,9 +60,6 @@ class HashtagsPanel extends ImmutablePureComponent {
|
||||
<HashtagItem />
|
||||
<HashtagItem />
|
||||
</div>
|
||||
<Button to='/groups/browse/member' block text>
|
||||
{intl.formatMessage(messages.show_all)}
|
||||
</Button>
|
||||
</PanelLayout>
|
||||
)
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ class ListDetailsPanel extends ImmutablePureComponent {
|
||||
return (
|
||||
<PanelLayout
|
||||
title={intl.formatMessage(messages.title, { count })}
|
||||
buttonTitle={intl.formatMessage(messages.show_all)}
|
||||
buttonAction={this.handleShowAllLists}
|
||||
headerButtonTitle={intl.formatMessage(messages.show_all)}
|
||||
headerButtonAction={this.handleShowAllLists}
|
||||
>
|
||||
<div className={_s.default}>
|
||||
|
||||
|
@ -1,39 +1,57 @@
|
||||
import Heading from '../heading'
|
||||
import Button from '../button'
|
||||
import Text from '../text'
|
||||
|
||||
export default class PanelLayout extends PureComponent {
|
||||
static propTypes = {
|
||||
title: PropTypes.string,
|
||||
subtitle: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
buttonTitle: PropTypes.string,
|
||||
buttonAction: PropTypes.func,
|
||||
buttonTo: PropTypes.func,
|
||||
headerButtonTitle: PropTypes.string,
|
||||
headerButtonAction: PropTypes.func,
|
||||
headerButtonTo: PropTypes.func,
|
||||
footerButtonTitle: PropTypes.string,
|
||||
footerButtonAction: PropTypes.func,
|
||||
footerButtonTo: PropTypes.func,
|
||||
noPadding: PropTypes.bool,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { title, subtitle, buttonTitle, buttonAction, buttonTo, noPadding, children } = this.props
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
headerButtonTitle,
|
||||
headerButtonAction,
|
||||
headerButtonTo,
|
||||
footerButtonTitle,
|
||||
footerButtonAction,
|
||||
footerButtonTo,
|
||||
noPadding,
|
||||
children,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<aside className={[_s.default, _s.backgroundWhite, _s.overflowHidden, _s.radiusSmall, _s.marginBottom15PX, _s.bordercolorSecondary, _s.border1PX].join(' ')}>
|
||||
<aside className={[_s.default, _s.backgroundColorPrimary, _s.overflowHidden, _s.radiusSmall, _s.marginBottom15PX, _s.borderColorSecondary, _s.border1PX].join(' ')}>
|
||||
{
|
||||
(title || subtitle) &&
|
||||
<div className={[_s.default, _s.paddingHorizontal15PX, _s.paddingVertical10PX, _s.bordercolorSecondary, _s.borderBottom1PX].join(' ')}>
|
||||
<div className={[_s.default, _s.paddingHorizontal15PX, _s.paddingVertical10PX, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')}>
|
||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
||||
<Heading size='h3'>
|
||||
{title}
|
||||
</Heading>
|
||||
{
|
||||
(!!buttonTitle && (!!buttonAction || !!buttonTo)) &&
|
||||
(!!headerButtonTitle && (!!headerButtonAction || !!headerButtonTo)) &&
|
||||
<div className={[_s.default, _s.marginLeftAuto].join(' ')}>
|
||||
<Button
|
||||
text
|
||||
to={buttonTo}
|
||||
onClick={buttonAction}
|
||||
className={[_s.default, _s.cursorPointer, _s.fontWeightBold, _s.text, _s.colorBrand, _s.fontSize13PX, _s.noUnderline].join(' ')}
|
||||
backgroundColor='none'
|
||||
color='brand'
|
||||
to={headerButtonTo}
|
||||
onClick={headerButtonAction}
|
||||
>
|
||||
{buttonTitle}
|
||||
<Text size='small' color='inherit' weight='bold'>
|
||||
{headerButtonTitle}
|
||||
</Text>
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
@ -57,6 +75,24 @@ export default class PanelLayout extends PureComponent {
|
||||
{
|
||||
noPadding && children
|
||||
}
|
||||
|
||||
{
|
||||
(!!footerButtonTitle && (!!footerButtonAction || !!footerButtonTo)) &&
|
||||
<div className={[_s.default, _s.borderColorSecondary, _s.borderTop1PX].join(' ')}>
|
||||
<Button
|
||||
text
|
||||
color='none'
|
||||
backgroundColor='none'
|
||||
to={footerButtonTo}
|
||||
onClick={footerButtonAction}
|
||||
className={[_s.paddingHorizontal15PX, _s.paddingVertical15PX, _s.backgroundSubtle_onHover].join(' ')}
|
||||
>
|
||||
<Text color='brand' align='left' size='medium'>
|
||||
{footerButtonTitle}
|
||||
</Text>
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
|
@ -2,11 +2,12 @@ import { injectIntl, defineMessages } from 'react-intl'
|
||||
// import { fetchTrends } from '../../actions/trends'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import TrendingItem from '../../components/trending_item'
|
||||
import TrendingItem from '../trends_panel_item'
|
||||
import PanelLayout from './panel_layout'
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id:'trends.title', defaultMessage: 'Trending right now' },
|
||||
show_all: { id: 'groups.sidebar-panel.show_all', defaultMessage: 'Show all' },
|
||||
})
|
||||
|
||||
// const mapStateToProps = state => ({
|
||||
@ -43,7 +44,12 @@ class TrendsPanel extends ImmutablePureComponent {
|
||||
// }
|
||||
|
||||
return (
|
||||
<PanelLayout title={intl.formatMessage(messages.title)}>
|
||||
<PanelLayout
|
||||
noPadding
|
||||
title={intl.formatMessage(messages.title)}
|
||||
footerButtonTitle={intl.formatMessage(messages.show_all)}
|
||||
footerButtonTo='/explore'
|
||||
>
|
||||
<div className={_s.default}>
|
||||
{ /* trends && trends.map(hashtag => (
|
||||
<TrendingItem key={hashtag.get('name')} hashtag={hashtag} />
|
||||
@ -52,7 +58,6 @@ class TrendsPanel extends ImmutablePureComponent {
|
||||
<TrendingItem />
|
||||
<TrendingItem />
|
||||
<TrendingItem />
|
||||
<TrendingItem />
|
||||
</div>
|
||||
</PanelLayout>
|
||||
)
|
||||
|
@ -8,6 +8,7 @@ import PanelLayout from './panel_layout';
|
||||
const messages = defineMessages({
|
||||
dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
|
||||
title: { id: 'who_to_follow.title', defaultMessage: 'Who to Follow' },
|
||||
show_more: { id: 'who_to_follow.more', defaultMessage: 'Show more' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
@ -47,7 +48,11 @@ class WhoToFollowPanel extends ImmutablePureComponent {
|
||||
// }
|
||||
|
||||
return (
|
||||
<PanelLayout title={intl.formatMessage(messages.title)}>
|
||||
<PanelLayout
|
||||
title={intl.formatMessage(messages.title)}
|
||||
footerButtonTitle={intl.formatMessage(messages.show_more)}
|
||||
footerButtonTo='/explore'
|
||||
>
|
||||
<div className={_s.default}>
|
||||
{suggestions && suggestions.map(accountId => (
|
||||
<AccountContainer
|
||||
|
105
app/javascript/gabsocial/components/search.js
Normal file
105
app/javascript/gabsocial/components/search.js
Normal file
@ -0,0 +1,105 @@
|
||||
import classNames from 'classnames/bind'
|
||||
import Overlay from 'react-overlays/lib/Overlay'
|
||||
import {
|
||||
changeSearch,
|
||||
clearSearch,
|
||||
submitSearch,
|
||||
showSearch,
|
||||
} from '../actions/search'
|
||||
import SearchPopout from './search_popout'
|
||||
import Input from './input'
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
value: state.getIn(['search', 'value']),
|
||||
submitted: state.getIn(['search', 'submitted']),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
onChange (value) {
|
||||
dispatch(changeSearch(value))
|
||||
},
|
||||
|
||||
onClear () {
|
||||
dispatch(clearSearch())
|
||||
},
|
||||
|
||||
onSubmit () {
|
||||
dispatch(submitSearch())
|
||||
},
|
||||
|
||||
onShow () {
|
||||
dispatch(showSearch())
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
class Search extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
submitted: PropTypes.bool,
|
||||
onShow: PropTypes.func.isRequired,
|
||||
openInRoute: PropTypes.bool,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onKeyUp: PropTypes.func.isRequired,
|
||||
handleSubmit: PropTypes.func,
|
||||
withOverlay: PropTypes.bool,
|
||||
handleClear: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
state = {
|
||||
expanded: false,
|
||||
}
|
||||
|
||||
handleChange = (e) => {
|
||||
this.props.onChange(e.target.value)
|
||||
}
|
||||
|
||||
handleFocus = () => {
|
||||
this.setState({ expanded: true })
|
||||
this.props.onShow()
|
||||
}
|
||||
|
||||
handleBlur = () => {
|
||||
this.setState({ expanded: false })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { value, submitted, onKeyUp, handleClear, handleSubmit, withOverlay } = this.props
|
||||
const { expanded } = this.state
|
||||
|
||||
const hasValue = value ? value.length > 0 || submitted : 0
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.justifyContentCenter, _s.height53PX].join(' ')}>
|
||||
<Input
|
||||
hasClear
|
||||
value={value}
|
||||
prependIcon='search'
|
||||
placeholder='Search on Gab...'
|
||||
onChange={this.handleChange}
|
||||
onKeyUp={onKeyUp}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
onClear={handleClear}
|
||||
/>
|
||||
|
||||
{
|
||||
withOverlay &&
|
||||
<Overlay show={expanded && !hasValue} placement='bottom' target={this}>
|
||||
<SearchPopout />
|
||||
</Overlay>
|
||||
}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -1 +0,0 @@
|
||||
export { default } from './search';
|
@ -1,93 +0,0 @@
|
||||
import classNames from 'classnames/bind';
|
||||
import Overlay from 'react-overlays/lib/Overlay';
|
||||
import Icon from '../icon';
|
||||
import SearchPopout from '../search_popout';
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
export default class Search extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
// value: PropTypes.string.isRequired,
|
||||
submitted: PropTypes.bool,
|
||||
// onShow: PropTypes.func.isRequired,
|
||||
openInRoute: PropTypes.bool,
|
||||
// placeholder: PropTypes.string.isRequired,
|
||||
searchTitle: PropTypes.string,
|
||||
// onChange: PropTypes.func.isRequired,
|
||||
// onKeyUp: PropTypes.func.isRequired,
|
||||
handleSubmit: PropTypes.func,
|
||||
withOverlay: PropTypes.bool,
|
||||
// handleClear: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
expanded: false,
|
||||
};
|
||||
|
||||
handleFocus = () => {
|
||||
this.setState({ expanded: true });
|
||||
this.props.onShow();
|
||||
}
|
||||
|
||||
handleBlur = () => {
|
||||
this.setState({ expanded: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { value, submitted, placeholder, searchTitle, onKeyUp, handleClear, handleSubmit, withOverlay, onChange } = this.props;
|
||||
const { expanded } = this.state;
|
||||
|
||||
const hasValue = value ? value.length > 0 || submitted : 0;
|
||||
|
||||
const btnClasses = cx({
|
||||
default: 1,
|
||||
cursorPointer: 1,
|
||||
marginRight5PX: 1,
|
||||
paddingHorizontal10PX: 1,
|
||||
paddingVertical10PX: 1,
|
||||
circle: 1,
|
||||
backgroundColorBrandLight: 1,
|
||||
displayNone: !hasValue,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.justifyContentCenter, _s.height53PX].join(' ')}>
|
||||
<div className={[_s.default, _s.backgroundWhite, _s.border1PX, _s.bordercolorSecondary, _s.flexRow, _s.circle, _s.alignItemsCenter].join(' ')}>
|
||||
<Icon id='search' width='16px' height='16px' className={[_s.default, _s.marginLeft15PX, _s.marginRight10PX].join(' ')} />
|
||||
<input
|
||||
className={[_s.default, _s.text, _s.outlineFocusBrand, _s.lineHeight125, _s.displayBlock, _s.paddingVertical10PX, _s.paddingHorizontal10PX, _s.backgroundTransparent, _s.fontSize15PX, _s.flexGrow1].join(' ')}
|
||||
type='text'
|
||||
placeholder='Search on Gab...'
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onKeyUp={onKeyUp}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
/>
|
||||
<div role='button' tabIndex='0' className={btnClasses} onClick={handleClear}>
|
||||
<Icon id='close' width='10px' height='10px' className={_s.fillColorWhite} aria-label={placeholder} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{
|
||||
withOverlay &&
|
||||
<Overlay show={expanded && !hasValue} placement='bottom' target={this}>
|
||||
<SearchPopout />
|
||||
</Overlay>
|
||||
}
|
||||
|
||||
{
|
||||
(searchTitle && handleSubmit) &&
|
||||
<Button onClick={handleSubmit}>{intl.formatMessage(messages.searchTitle)}</Button>
|
||||
}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
.search {
|
||||
position: relative;
|
||||
|
||||
&__input {
|
||||
display: block;
|
||||
padding: 7px 30px 6px 10px;
|
||||
@include search-input();
|
||||
}
|
||||
|
||||
&__icon {
|
||||
&::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
&::-moz-focus-inner,
|
||||
&:focus {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
.fa {
|
||||
cursor: default;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 6px;
|
||||
z-index: 2;
|
||||
font-size: 16px;
|
||||
color: $gab-placeholder-accent;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
|
||||
@include size(18px);
|
||||
|
||||
&.active {
|
||||
pointer-events: auto;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.fa-search.active {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fa-times-circle {
|
||||
cursor: pointer;
|
||||
font-size: 17px;
|
||||
color: $gab-alert-red;
|
||||
|
||||
&:hover {
|
||||
color: lighten($gab-alert-red, 7%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 630px) and (max-height: 400px) {
|
||||
will-change: margin-top;
|
||||
transition: margin-top 400ms 100ms;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 360px) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 895px) {
|
||||
.search-page .search {
|
||||
display: none;
|
||||
}
|
||||
}
|
@ -275,7 +275,7 @@ class HeaderMenuItem extends PureComponent {
|
||||
alignItemsCenter: 1,
|
||||
radiusSmall: 1,
|
||||
// border1PX: shouldShowActive,
|
||||
// bordercolorSecondary: shouldShowActive,
|
||||
// borderColorSecondary: shouldShowActive,
|
||||
backgroundSubtle2: shouldShowActive,
|
||||
})
|
||||
|
||||
|
@ -47,7 +47,7 @@ export default class SidebarSectionItem extends PureComponent {
|
||||
alignItemsCenter: 1,
|
||||
radiusSmall: 1,
|
||||
// border1PX: shouldShowActive,
|
||||
// bordercolorSecondary: shouldShowActive,
|
||||
// borderColorSecondary: shouldShowActive,
|
||||
backgroundSubtle2: shouldShowActive,
|
||||
})
|
||||
|
||||
@ -86,7 +86,7 @@ export default class SidebarSectionItem extends PureComponent {
|
||||
to={to}
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
className={[_s.default, _s.noUnderline, _s.cursorPointer, _s.width100PC, _s.alignItemsStart, _s.flexGrow1].join(' ')}
|
||||
className={[_s.default, _s.noUnderline, _s.cursorPointer, _s.width100PC, _s.alignItemsStart].join(' ')}
|
||||
>
|
||||
<div className={containerClasses}>
|
||||
<div className={[_s.default]}>
|
||||
|
@ -16,6 +16,7 @@ import StatusContent from '../status_content';
|
||||
import StatusActionBar from '../status_action_bar';
|
||||
import Icon from '../icon';
|
||||
import Poll from '../poll';
|
||||
import StatusHeader from '../status_header'
|
||||
|
||||
// We use the component (and not the container) since we do not want
|
||||
// to use the progress bar to show download progress
|
||||
@ -403,10 +404,6 @@ class Status extends ImmutablePureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
if (account === undefined || account === null) {
|
||||
statusAvatar = <Avatar account={status.get('account')} size={50} />;
|
||||
}
|
||||
|
||||
const handlers = this.props.muted
|
||||
? {}
|
||||
: {
|
||||
@ -427,7 +424,7 @@ class Status extends ImmutablePureComponent {
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
<div
|
||||
className={[_s.default, _s.backgroundWhite, _s.radiusSmall, _s.marginBottom15PX, _s.border1PX, _s.bordercolorSecondary].join(' ')}
|
||||
className={[_s.default, _s.backgroundColorPrimary, _s.radiusSmall, _s.marginBottom15PX, _s.border1PX, _s.borderColorSecondary].join(' ')}
|
||||
tabIndex={this.props.muted ? null : 0}
|
||||
data-featured={featured ? 'true' : null}
|
||||
aria-label={textForScreenReader(intl, status, rebloggedByText)}
|
||||
@ -445,60 +442,7 @@ class Status extends ImmutablePureComponent {
|
||||
data-id={status.get('id')}
|
||||
>
|
||||
|
||||
<div className={[_s.default, _s.paddingHorizontal15PX, _s.paddingVertical10PX].join(' ')}>
|
||||
<div className={[_s.default, _s.flexRow, _s.marginTop5PX].join(' ')}>
|
||||
<div className={[_s.default, _s.marginRight10PX].join(' ')}>{statusAvatar}</div>
|
||||
<div className={[_s.default, _s.alignItemsStart, _s.flexGrow1, _s.marginTop5PX].join(' ')}>
|
||||
<div className={[_s.default, _s.flexRow, _s.width100PC, _s.alignItemsStart].join(' ')}>
|
||||
<NavLink
|
||||
className={[_s.default, _s.flexRow, _s.alignItemsStart, _s.noUnderline].join(' ')}
|
||||
to={`/${status.getIn(['account', 'acct'])}`}
|
||||
title={status.getIn(['account', 'acct'])}
|
||||
>
|
||||
<DisplayName account={status.get('account')} />
|
||||
</NavLink>
|
||||
<Icon id='ellipsis' width='20px' height='20px' className={[_s.default, _s.fillcolorSecondary, _s.marginLeftAuto].join(' ')} />
|
||||
</div>
|
||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.lineHeight15].join(' ')}>
|
||||
<NavLink
|
||||
to={statusUrl}
|
||||
className={[_s.default, _s.text, _s.fontSize13PX, _s.noUnderline, _s.colorSecondary].join(' ')}
|
||||
>
|
||||
<RelativeTimestamp timestamp={status.get('created_at')} />
|
||||
</NavLink>
|
||||
<span className={[_s.default, _s.text, _s.fontSize12PX, _s.marginLeft5PX, _s.colorSecondary].join(' ')}>•</span>
|
||||
<Icon id='globe' width='12px' height='12px' className={[_s.default, _s.displayInline, _s.marginLeft5PX, _s.fillcolorSecondary].join(' ')}/>
|
||||
|
||||
{
|
||||
!!status.get('group') &&
|
||||
<Fragment>
|
||||
<span className={[_s.default, _s.text, _s.fontSize12PX, _s.marginLeft5PX, _s.colorSecondary].join(' ')}>•</span>
|
||||
<NavLink
|
||||
to={`/groups/${status.getIn(['group', 'id'])}`}
|
||||
className={[_s.default, _s.text, _s.fontSize13PX, _s.marginLeft5PX, _s.colorPrimary].join(' ')}
|
||||
>
|
||||
{status.getIn(['group', 'title'])}
|
||||
</NavLink>
|
||||
</Fragment>
|
||||
}
|
||||
|
||||
{
|
||||
status.get('revised_at') !== null &&
|
||||
<Fragment>
|
||||
<span className={[_s.default, _s.text, _s.fontSize12PX, _s.marginLeft5PX, _s.colorSecondary].join(' ')}>•</span>
|
||||
<button
|
||||
onClick={() => other.onShowRevisions(status)}
|
||||
className={[_s.default, _s.text, _s.fontSize13PX, _s.marginLeft5PX, _s.colorSecondary].join(' ')}
|
||||
>
|
||||
Edited
|
||||
</button>
|
||||
</Fragment>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<StatusHeader status={status} />
|
||||
|
||||
<div className={_s.default}>
|
||||
<StatusContent
|
||||
|
@ -165,134 +165,6 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
handleDeleteClick = () => {
|
||||
this.props.onDelete(this.props.status, this.context.router.history);
|
||||
}
|
||||
|
||||
handleEditClick = () => {
|
||||
this.props.onEdit(this.props.status);
|
||||
}
|
||||
|
||||
handlePinClick = () => {
|
||||
this.props.onPin(this.props.status);
|
||||
}
|
||||
|
||||
handleMentionClick = () => {
|
||||
this.props.onMention(this.props.status.get('account'), this.context.router.history);
|
||||
}
|
||||
|
||||
handleMuteClick = () => {
|
||||
this.props.onMute(this.props.status.get('account'));
|
||||
}
|
||||
|
||||
handleBlockClick = () => {
|
||||
this.props.onBlock(this.props.status);
|
||||
}
|
||||
|
||||
handleOpen = () => {
|
||||
this.context.router.history.push(`/${this.props.status.getIn(['account', 'acct'])}/posts/${this.props.status.get('id')}`);
|
||||
}
|
||||
|
||||
handleEmbed = () => {
|
||||
this.props.onEmbed(this.props.status);
|
||||
}
|
||||
|
||||
handleReport = () => {
|
||||
this.props.onReport(this.props.status);
|
||||
}
|
||||
|
||||
handleConversationMuteClick = () => {
|
||||
this.props.onMuteConversation(this.props.status);
|
||||
}
|
||||
|
||||
handleCopy = () => {
|
||||
const url = this.props.status.get('url');
|
||||
const textarea = document.createElement('textarea');
|
||||
|
||||
textarea.textContent = url;
|
||||
textarea.style.position = 'fixed';
|
||||
|
||||
document.body.appendChild(textarea);
|
||||
|
||||
try {
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
} catch (e) {
|
||||
//
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
}
|
||||
|
||||
handleGroupRemoveAccount = () => {
|
||||
const { status } = this.props;
|
||||
|
||||
this.props.onGroupRemoveAccount(status.getIn(['group', 'id']), status.getIn(['account', 'id']));
|
||||
}
|
||||
|
||||
handleGroupRemovePost = () => {
|
||||
const { status } = this.props;
|
||||
|
||||
this.props.onGroupRemoveStatus(status.getIn(['group', 'id']), status.get('id'));
|
||||
}
|
||||
|
||||
_makeMenu = (publicStatus) => {
|
||||
const { status, intl: { formatMessage }, withDismiss, withGroupAdmin } = this.props;
|
||||
const mutingConversation = status.get('muted');
|
||||
|
||||
let menu = [];
|
||||
|
||||
menu.push({ text: formatMessage(messages.open), action: this.handleOpen });
|
||||
|
||||
if (publicStatus) {
|
||||
menu.push({ text: formatMessage(messages.copy), action: this.handleCopy });
|
||||
menu.push({ text: formatMessage(messages.embed), action: this.handleEmbed });
|
||||
}
|
||||
|
||||
if (!me) {
|
||||
return menu;
|
||||
}
|
||||
|
||||
menu.push(null);
|
||||
|
||||
if (status.getIn(['account', 'id']) === me || withDismiss) {
|
||||
menu.push({ text: formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });
|
||||
menu.push(null);
|
||||
}
|
||||
|
||||
if (status.getIn(['account', 'id']) === me) {
|
||||
if (publicStatus) {
|
||||
menu.push({ text: formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
|
||||
} else {
|
||||
if (status.get('visibility') === 'private') {
|
||||
menu.push({ text: formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private), action: this.handleReblogClick });
|
||||
}
|
||||
}
|
||||
menu.push({ text: formatMessage(messages.delete), action: this.handleDeleteClick });
|
||||
menu.push({ text: formatMessage(messages.edit), action: this.handleEditClick });
|
||||
} else {
|
||||
menu.push({ text: formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
|
||||
menu.push(null);
|
||||
menu.push({ text: formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
||||
menu.push({ text: formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
||||
menu.push({ text: formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
||||
|
||||
if (isStaff) {
|
||||
menu.push(null);
|
||||
menu.push({ text: formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
|
||||
menu.push({ text: formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });
|
||||
}
|
||||
|
||||
if (withGroupAdmin) {
|
||||
menu.push(null);
|
||||
menu.push({ text: formatMessage(messages.group_remove_account), action: this.handleGroupRemoveAccount });
|
||||
menu.push({ text: formatMessage(messages.group_remove_post), action: this.handleGroupRemovePost });
|
||||
}
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
render () {
|
||||
const { status, intl: { formatMessage } } = this.props;
|
||||
|
||||
@ -311,8 +183,6 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
<IconButton className='status-action-bar-button' title={formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} />
|
||||
);
|
||||
|
||||
const menu = this._makeMenu(publicStatus);
|
||||
|
||||
const items = [
|
||||
{
|
||||
title: formatMessage(messages.like),
|
||||
@ -357,7 +227,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
flexRow: 1,
|
||||
width100PC: 1,
|
||||
borderTop1PX: !shouldCondense,
|
||||
bordercolorSecondary: !shouldCondense,
|
||||
borderColorSecondary: !shouldCondense,
|
||||
marginTop5PX: hasInteractions,
|
||||
})
|
||||
|
||||
@ -404,17 +274,6 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
<StatusActionBarItem key={`status-action-bar-item-${i}`} {...item} />
|
||||
))
|
||||
}
|
||||
|
||||
{/*<div className='status-action-bar__dropdown'>
|
||||
<DropdownMenuContainer
|
||||
status={status}
|
||||
items={menu}
|
||||
icon='ellipsis-h'
|
||||
size={18}
|
||||
direction='right'
|
||||
title={formatMessage(messages.more)}
|
||||
/>
|
||||
</div>*/}
|
||||
</div>
|
||||
</div>
|
||||
<div className='status-action-bar__comment'>
|
||||
|
268
app/javascript/gabsocial/components/status_header.js
Normal file
268
app/javascript/gabsocial/components/status_header.js
Normal file
@ -0,0 +1,268 @@
|
||||
import { Fragment } from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import RelativeTimestamp from './relative_timestamp'
|
||||
import DisplayName from './display_name'
|
||||
import Text from './text'
|
||||
import DotTextSeperator from './dot_text_seperator'
|
||||
import Icon from './icon'
|
||||
import Button from './button'
|
||||
import Avatar from './avatar'
|
||||
|
||||
export default class StatusHeader extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
status: ImmutablePropTypes.map,
|
||||
}
|
||||
|
||||
handleStatusOptionsClick() {
|
||||
console.log("handleStatusOptionsClick")
|
||||
}
|
||||
|
||||
handleOpenStatusEdits() {
|
||||
console.log("handleOpenStatusEdits")
|
||||
}
|
||||
|
||||
handleDeleteClick = () => {
|
||||
this.props.onDelete(this.props.status, this.context.router.history);
|
||||
}
|
||||
|
||||
handleEditClick = () => {
|
||||
this.props.onEdit(this.props.status);
|
||||
}
|
||||
|
||||
handlePinClick = () => {
|
||||
this.props.onPin(this.props.status);
|
||||
}
|
||||
|
||||
handleMentionClick = () => {
|
||||
this.props.onMention(this.props.status.get('account'), this.context.router.history);
|
||||
}
|
||||
|
||||
handleMuteClick = () => {
|
||||
this.props.onMute(this.props.status.get('account'));
|
||||
}
|
||||
|
||||
handleBlockClick = () => {
|
||||
this.props.onBlock(this.props.status);
|
||||
}
|
||||
|
||||
handleOpen = () => {
|
||||
this.context.router.history.push(`/${this.props.status.getIn(['account', 'acct'])}/posts/${this.props.status.get('id')}`);
|
||||
}
|
||||
|
||||
handleEmbed = () => {
|
||||
this.props.onEmbed(this.props.status);
|
||||
}
|
||||
|
||||
handleReport = () => {
|
||||
this.props.onReport(this.props.status);
|
||||
}
|
||||
|
||||
handleConversationMuteClick = () => {
|
||||
this.props.onMuteConversation(this.props.status);
|
||||
}
|
||||
|
||||
handleCopy = () => {
|
||||
const url = this.props.status.get('url');
|
||||
const textarea = document.createElement('textarea');
|
||||
|
||||
textarea.textContent = url;
|
||||
textarea.style.position = 'fixed';
|
||||
|
||||
document.body.appendChild(textarea);
|
||||
|
||||
try {
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
} catch (e) {
|
||||
//
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
}
|
||||
|
||||
handleGroupRemoveAccount = () => {
|
||||
const { status } = this.props;
|
||||
|
||||
this.props.onGroupRemoveAccount(status.getIn(['group', 'id']), status.getIn(['account', 'id']));
|
||||
}
|
||||
|
||||
handleGroupRemovePost = () => {
|
||||
const { status } = this.props;
|
||||
|
||||
this.props.onGroupRemoveStatus(status.getIn(['group', 'id']), status.get('id'));
|
||||
}
|
||||
|
||||
_makeMenu = (publicStatus) => {
|
||||
const { status, intl: { formatMessage }, withDismiss, withGroupAdmin } = this.props;
|
||||
const mutingConversation = status.get('muted');
|
||||
|
||||
let menu = [];
|
||||
|
||||
menu.push({ text: formatMessage(messages.open), action: this.handleOpen });
|
||||
|
||||
if (publicStatus) {
|
||||
menu.push({ text: formatMessage(messages.copy), action: this.handleCopy });
|
||||
menu.push({ text: formatMessage(messages.embed), action: this.handleEmbed });
|
||||
}
|
||||
|
||||
if (!me) return menu
|
||||
|
||||
menu.push(null);
|
||||
|
||||
if (status.getIn(['account', 'id']) === me || withDismiss) {
|
||||
menu.push({ text: formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });
|
||||
menu.push(null);
|
||||
}
|
||||
|
||||
if (status.getIn(['account', 'id']) === me) {
|
||||
if (publicStatus) {
|
||||
menu.push({ text: formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
|
||||
} else {
|
||||
if (status.get('visibility') === 'private') {
|
||||
menu.push({ text: formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private), action: this.handleReblogClick });
|
||||
}
|
||||
}
|
||||
menu.push({ text: formatMessage(messages.delete), action: this.handleDeleteClick });
|
||||
menu.push({ text: formatMessage(messages.edit), action: this.handleEditClick });
|
||||
} else {
|
||||
menu.push({ text: formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
|
||||
menu.push(null);
|
||||
menu.push({ text: formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
||||
menu.push({ text: formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
||||
menu.push({ text: formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
||||
|
||||
if (isStaff) {
|
||||
menu.push(null);
|
||||
menu.push({ text: formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
|
||||
menu.push({ text: formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });
|
||||
}
|
||||
|
||||
if (withGroupAdmin) {
|
||||
menu.push(null);
|
||||
menu.push({ text: formatMessage(messages.group_remove_account), action: this.handleGroupRemoveAccount });
|
||||
menu.push({ text: formatMessage(messages.group_remove_post), action: this.handleGroupRemovePost });
|
||||
}
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { status } = this.props
|
||||
|
||||
const statusUrl = `/${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`;
|
||||
|
||||
// const menu = this._makeMenu(publicStatus);
|
||||
// <div className='status-action-bar__dropdown'>
|
||||
// <DropdownMenuContainer
|
||||
// status={status}
|
||||
// items={menu}
|
||||
// icon='ellipsis-h'
|
||||
// size={18}
|
||||
// direction='right'
|
||||
// title={formatMessage(messages.more)}
|
||||
// />
|
||||
// </div>
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.paddingHorizontal15PX, _s.paddingVertical10PX].join(' ')}>
|
||||
<div className={[_s.default, _s.flexRow, _s.marginTop5PX].join(' ')}>
|
||||
|
||||
<NavLink
|
||||
to={`/${status.getIn(['account', 'acct'])}`}
|
||||
title={status.getIn(['account', 'acct'])}
|
||||
className={[_s.default, _s.marginRight10PX].join(' ')}
|
||||
>
|
||||
<Avatar account={status.get('account')} size={50} />
|
||||
</NavLink>
|
||||
|
||||
<div className={[_s.default, _s.alignItemsStart, _s.flexGrow1, _s.marginTop5PX].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.width100PC, _s.alignItemsStart].join(' ')}>
|
||||
<NavLink
|
||||
className={[_s.default, _s.flexRow, _s.alignItemsStart, _s.noUnderline].join(' ')}
|
||||
to={`/${status.getIn(['account', 'acct'])}`}
|
||||
title={status.getIn(['account', 'acct'])}
|
||||
>
|
||||
<DisplayName account={status.get('account')} />
|
||||
</NavLink>
|
||||
|
||||
<Button
|
||||
text
|
||||
backgroundColor='none'
|
||||
color='none'
|
||||
icon='ellipsis'
|
||||
iconWidth='20px'
|
||||
iconHeight='20px'
|
||||
iconClassName={_s.fillcolorSecondary}
|
||||
className={_s.marginLeftAuto}
|
||||
onClick={this.handleStatusOptionsClick}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.lineHeight15].join(' ')}>
|
||||
<Button
|
||||
text
|
||||
underlineOnHover
|
||||
backgroundColor='none'
|
||||
color='none'
|
||||
to={statusUrl}
|
||||
>
|
||||
<Text size='small' color='secondary'>
|
||||
<RelativeTimestamp timestamp={status.get('created_at')} />
|
||||
</Text>
|
||||
</Button>
|
||||
|
||||
<DotTextSeperator />
|
||||
|
||||
<Icon id='globe' width='12px' height='12px' className={[_s.default, _s.displayInline, _s.marginLeft5PX, _s.fillcolorSecondary].join(' ')} />
|
||||
|
||||
{
|
||||
!!status.get('group') &&
|
||||
<Fragment>
|
||||
<DotTextSeperator />
|
||||
<Button
|
||||
text
|
||||
underlineOnHover
|
||||
backgroundColor='none'
|
||||
color='none'
|
||||
to={`/groups/${status.getIn(['group', 'id'])}`}
|
||||
className={_s.marginLeft5PX}
|
||||
>
|
||||
<Text size='small' color='secondary'>
|
||||
{status.getIn(['group', 'title'])}
|
||||
</Text>
|
||||
</Button>
|
||||
</Fragment>
|
||||
}
|
||||
|
||||
{
|
||||
status.get('revised_at') !== null &&
|
||||
<Fragment>
|
||||
<DotTextSeperator />
|
||||
<Button
|
||||
text
|
||||
underlineOnHover
|
||||
backgroundColor='none'
|
||||
color='none'
|
||||
onClick={this.handleOpenStatusEdits}
|
||||
className={_s.marginLeft5PX}
|
||||
>
|
||||
<Text size='small' color='secondary'>
|
||||
Edited
|
||||
</Text>
|
||||
</Button>
|
||||
</Fragment>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -8,6 +8,7 @@ const COLORS = {
|
||||
brand: 'brand',
|
||||
error: 'error',
|
||||
white: 'white',
|
||||
inherit: 'inherit',
|
||||
}
|
||||
|
||||
const SIZES = {
|
||||
@ -26,6 +27,11 @@ const WEIGHTS = {
|
||||
extraBold: 'extraBold',
|
||||
}
|
||||
|
||||
const ALIGNMENTS = {
|
||||
center: 'center',
|
||||
left: 'left',
|
||||
}
|
||||
|
||||
export default class Text extends PureComponent {
|
||||
static propTypes = {
|
||||
tagName: PropTypes.string,
|
||||
@ -34,6 +40,7 @@ export default class Text extends PureComponent {
|
||||
color: PropTypes.oneOf(Object.keys(COLORS)),
|
||||
size: PropTypes.oneOf(Object.keys(SIZES)),
|
||||
weight: PropTypes.oneOf(Object.keys(WEIGHTS)),
|
||||
align: PropTypes.oneOf(Object.keys(ALIGNMENTS)),
|
||||
underline: PropTypes.bool,
|
||||
}
|
||||
|
||||
@ -45,7 +52,16 @@ export default class Text extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { tagName, className, children, color, size, weight, underline } = this.props
|
||||
const {
|
||||
tagName,
|
||||
className,
|
||||
children,
|
||||
color,
|
||||
size,
|
||||
weight,
|
||||
underline,
|
||||
align
|
||||
} = this.props
|
||||
|
||||
const classes = cx(className, {
|
||||
default: 1,
|
||||
@ -55,15 +71,21 @@ export default class Text extends PureComponent {
|
||||
colorSecondary: color === COLORS.secondary,
|
||||
colorBrand: color === COLORS.brand,
|
||||
colorWhite: color === COLORS.white,
|
||||
inherit: color === COLORS.inherit,
|
||||
|
||||
fontSize19PX: size === SIZES.large,
|
||||
fontSize15PX: size === SIZES.medium,
|
||||
fontSize14PX: size === SIZES.normal,
|
||||
fontSize13PX: size === SIZES.small,
|
||||
fontSize12PX: size === SIZES.extraSmall,
|
||||
|
||||
fontWeightNormal: weight === WEIGHTS.normal,
|
||||
fontWeightMedium: weight === WEIGHTS.medium,
|
||||
fontWeightBold: weight === WEIGHTS.bold,
|
||||
fontWeightExtraBold: weight === WEIGHTS.extraBold,
|
||||
|
||||
textAlignLeft: align === ALIGNMENTS.left,
|
||||
textAlignCenter: align === ALIGNMENTS.center,
|
||||
|
||||
underline: underline,
|
||||
})
|
||||
|
@ -1,19 +1,28 @@
|
||||
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 ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { injectIntl, defineMessages } from 'react-intl'
|
||||
import { me } from '../initial_state'
|
||||
import ComposeFormContainer from '../features/compose/containers/compose_form_container'
|
||||
import Avatar from './avatar'
|
||||
import Heading from './heading'
|
||||
|
||||
const messages = defineMessages({
|
||||
createPost: { id: 'column_header.create_post', defaultMessage: 'Create Post' },
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
account: state.getIn(['accounts', me]),
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
export default
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class TimelineComposeBlock extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
size: PropTypes.number,
|
||||
}
|
||||
@ -23,14 +32,14 @@ class TimelineComposeBlock extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { account, size, ...rest } = this.props;
|
||||
const { account, size, intl, ...rest } = this.props
|
||||
|
||||
return (
|
||||
<section className={[_s.default, _s.overflowHidden, _s.radiusSmall, _s.border1PX, _s.bordercolorSecondary, _s.backgroundWhite, _s.marginBottom15PX].join(' ')}>
|
||||
<div className={[_s.default, _s.backgroundSubtle, _s.borderBottom1PX, _s.bordercolorSecondary, _s.paddingHorizontal15PX, _s.paddingVertical2PX].join(' ')}>
|
||||
<h1 className={[_s.default, _s.text, _s.colorSecondary, _s.fontSize12PX, _s.fontWeightMedium, _s.lineHeight2, _s.paddingVertical2PX].join(' ')}>
|
||||
Create Post
|
||||
</h1>
|
||||
<section className={[_s.default, _s.overflowHidden, _s.radiusSmall, _s.border1PX, _s.borderColorSecondary, _s.backgroundColorPrimary, _s.marginBottom15PX].join(' ')}>
|
||||
<div className={[_s.default, _s.backgroundSubtle, _s.borderBottom1PX, _s.borderColorSecondary, _s.paddingHorizontal15PX, _s.paddingVertical2PX].join(' ')}>
|
||||
<Heading size='h5'>
|
||||
{intl.formatMessage(messages.createPost)}
|
||||
</Heading>
|
||||
</div>
|
||||
<div className={[_s.default, _s.flexRow, _s.paddingVertical15PX, _s.paddingHorizontal15PX].join(' ')}>
|
||||
<div className={[_s.default, _s.marginRight10PX].join(' ')}>
|
||||
|
@ -4,6 +4,11 @@ import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import classNames from 'classnames/bind'
|
||||
import { shortNumberFormat } from '../utils/numbers'
|
||||
import Text from './text'
|
||||
import Button from './button'
|
||||
import Image from './image'
|
||||
import TrendingItemCard from './trends_panel_item_card'
|
||||
import DotTextSeperator from './dot_text_seperator'
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
@ -42,12 +47,20 @@ export default class TrendingItem extends ImmutablePureComponent {
|
||||
return (
|
||||
<NavLink
|
||||
to='/test'
|
||||
className={[_s.default, _s.noUnderline, _s.marginBottom10PX].join(' ')}
|
||||
className={[_s.default, _s.noUnderline, _s.paddingHorizontal15PX, _s.paddingVertical5PX, _s.borderColorSecondary, _s.borderBottom1PX, _s.backgroundSubtle_onHover].join(' ')}
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
>
|
||||
<span className={[_s.default, _s.text, _s.displayFlex, _s.colorBrand, _s.fontSize15PX, _s.fontWeightBold, _s.lineHeight15].join(' ')}>#randomhashtag</span>
|
||||
<span className={subtitleClasses}>10,240 Gabs</span>
|
||||
<div className={[_s.default, _s.flexRow, _s.marginTop5PX].join(' ')}>
|
||||
<Text size='small' color='secondary'>1</Text>
|
||||
<DotTextSeperator />
|
||||
<Text size='small' color='secondary' className={_s.marginLeft5PX}>Politics</Text>
|
||||
</div>
|
||||
<div className={[_s.default, _s.paddingVertical5PX].join(' ')}>
|
||||
<Text color='primary' weight='bold' size='medium'>Trump Campaign</Text>
|
||||
<Text color='secondary' className={[_s.marginTop5PX, _s.marginBottom10PX].join(' ')}>46.7K Gabs</Text>
|
||||
<TrendingItemCard />
|
||||
</div>
|
||||
</NavLink>
|
||||
)
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
import { FormattedMessage } from 'react-intl'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import classNames from 'classnames/bind'
|
||||
import { shortNumberFormat } from '../utils/numbers'
|
||||
import Text from './text'
|
||||
import Button from './button'
|
||||
import Image from './image'
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
export default class TrendingItemCard extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
trend: ImmutablePropTypes.map.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
hovering: false,
|
||||
}
|
||||
|
||||
handleOnMouseEnter = () => {
|
||||
this.setState({ hovering: true })
|
||||
}
|
||||
|
||||
handleOnMouseLeave = () => {
|
||||
this.setState({ hovering: false })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { trend } = this.props
|
||||
const { hovering } = this.state
|
||||
|
||||
const subtitleClasses = cx({
|
||||
default: 1,
|
||||
text: 1,
|
||||
displayFlex: 1,
|
||||
fontSize13PX: 1,
|
||||
fontWeightNormal: 1,
|
||||
colorSecondary: 1,
|
||||
underline: hovering,
|
||||
})
|
||||
|
||||
|
||||
// URL with title, description
|
||||
|
||||
// URL with video
|
||||
|
||||
// URL with title, description, image
|
||||
return (
|
||||
<div className={[_s.default, _s.flexRow, _s.overflowHidden, _s.borderColorSecondary, _s.border1PX, _s.radiusSmall, _s.backgroundSubtle_onHover].join(' ')}>
|
||||
<div className={[_s.default, _s.flexNormal, _s.paddingVertical10PX, _s.paddingHorizontal10PX].join(' ')}>
|
||||
<Text color='secondary' className={_s.lineHeight15}>
|
||||
NYPost
|
||||
</Text>
|
||||
<Text size='medium' color='primary'>
|
||||
The best flower subscription services: BloomsyBox, Bouqs...
|
||||
</Text>
|
||||
</div>
|
||||
<Image width='92px' height='92px' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import Search from '../../../../components/search';
|
||||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'search.placeholder', defaultMessage: 'Search' },
|
||||
});
|
||||
|
||||
export default @injectIntl
|
||||
class ComposeSearch 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,
|
||||
};
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, value, onShow, openInRoute } = this.props;
|
||||
|
||||
return (
|
||||
<Search
|
||||
value={value}
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
onChange={this.handleChange}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
handleClear={this.handleClear}
|
||||
onShow={onShow}
|
||||
withOverlay
|
||||
openInRoute
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -1 +0,0 @@
|
||||
export { default } from './compose_search';
|
@ -1,7 +1,7 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import TrendingItem from '../../../../components/trending_item';
|
||||
import TrendingItem from '../../../../components/trends_panel_item';
|
||||
import Icon from '../../../../components/icon';
|
||||
import { WhoToFollowPanel } from '../../../../components/panel';
|
||||
// import TrendsPanel from '../../ui/components/trends_panel';
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
import { mascot } from '../../initial_state';
|
||||
import Motion from '../ui/util/optional_motion';
|
||||
import ComposeFormContainer from './containers/compose_form_container';
|
||||
import SearchContainer from './containers/search_container';
|
||||
// import SearchContainer from './containers/search_container';
|
||||
import SearchResultsContainer from './containers/search_results_container';
|
||||
import NavigationBar from './components/navigation_bar';
|
||||
import elephantUIPlane from '../../../images/logo_ui_column_footer.png';
|
||||
@ -76,7 +76,7 @@ class Compose extends ImmutablePureComponent {
|
||||
<div className='drawer' role='region' aria-label={intl.formatMessage(messages.compose)}>
|
||||
{header}
|
||||
|
||||
{isSearchPage && <SearchContainer /> }
|
||||
{ /* isSearchPage && <SearchContainer /> */ }
|
||||
|
||||
<div className='drawer__pager'>
|
||||
{!isSearchPage && <div className='drawer__inner' onFocus={this.onFocus}>
|
||||
|
@ -1,34 +0,0 @@
|
||||
import {
|
||||
changeSearch,
|
||||
clearSearch,
|
||||
submitSearch,
|
||||
showSearch,
|
||||
} from '../../../actions/search';
|
||||
import ComposeSearch from '../components/compose_search';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
value: state.getIn(['search', 'value']),
|
||||
submitted: state.getIn(['search', 'submitted']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
onChange (value) {
|
||||
dispatch(changeSearch(value));
|
||||
},
|
||||
|
||||
onClear () {
|
||||
dispatch(clearSearch());
|
||||
},
|
||||
|
||||
onSubmit () {
|
||||
dispatch(submitSearch());
|
||||
},
|
||||
|
||||
onShow () {
|
||||
dispatch(showSearch());
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ComposeSearch);
|
@ -0,0 +1,104 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { Link } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
import { fetchGroups } from '../../../actions/groups';
|
||||
import { openModal } from '../../../actions/modal';
|
||||
import { me } from '../../../initial_state';
|
||||
import GroupCard from './card';
|
||||
import GroupCreate from '../create';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.groups', defaultMessage: 'Groups' },
|
||||
create: { id: 'groups.create', defaultMessage: 'Create group' },
|
||||
tab_featured: { id: 'groups.tab_featured', defaultMessage: 'Featured' },
|
||||
tab_member: { id: 'groups.tab_member', defaultMessage: 'Member' },
|
||||
tab_admin: { id: 'groups.tab_admin', defaultMessage: 'Manage' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, { activeTab }) => ({
|
||||
groupIds: state.getIn(['group_lists', activeTab]),
|
||||
account: state.getIn(['accounts', me]),
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class Groups extends ImmutablePureComponent {
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
activeTab: PropTypes.string.isRequired,
|
||||
showCreateForm: PropTypes.bool,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
groups: ImmutablePropTypes.map,
|
||||
groupIds: ImmutablePropTypes.list,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
this.props.dispatch(fetchGroups(this.props.activeTab));
|
||||
}
|
||||
|
||||
componentDidUpdate(oldProps) {
|
||||
if (this.props.activeTab && this.props.activeTab !== oldProps.activeTab) {
|
||||
this.props.dispatch(fetchGroups(this.props.activeTab));
|
||||
}
|
||||
}
|
||||
|
||||
handleOpenProUpgradeModal = () => {
|
||||
this.props.dispatch(openModal('PRO_UPGRADE'));
|
||||
}
|
||||
|
||||
renderHeader() {
|
||||
const { intl, activeTab, account, onOpenProUpgradeModal } = this.props;
|
||||
|
||||
const isPro = account.get('is_pro');
|
||||
|
||||
return (
|
||||
<div className="group-column-header">
|
||||
<div className="group-column-header__cta">
|
||||
{
|
||||
account && isPro &&
|
||||
<Link to="/groups/create" className="button standard-small">{intl.formatMessage(messages.create)}</Link>
|
||||
}
|
||||
{
|
||||
account && !isPro &&
|
||||
<button onClick={this.handleOpenProUpgradeModal} className="button standard-small">{intl.formatMessage(messages.create)}</button>
|
||||
}
|
||||
</div>
|
||||
<div className="group-column-header__title">{intl.formatMessage(messages.heading)}</div>
|
||||
|
||||
<div className="column-header__wrapper">
|
||||
<h1 className="column-header">
|
||||
<Link to='/groups' className={classNames('btn grouped', {'active': 'featured' === activeTab})}>
|
||||
{intl.formatMessage(messages.tab_featured)}
|
||||
</Link>
|
||||
|
||||
<Link to='/groups/browse/member' className={classNames('btn grouped', {'active': 'member' === activeTab})}>
|
||||
{intl.formatMessage(messages.tab_member)}
|
||||
</Link>
|
||||
|
||||
<Link to='/groups/browse/admin' className={classNames('btn grouped', {'active': 'admin' === activeTab})}>
|
||||
{intl.formatMessage(messages.tab_admin)}
|
||||
</Link>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { groupIds, showCreateForm } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{!showCreateForm && this.renderHeader()}
|
||||
{showCreateForm && <GroupCreate /> }
|
||||
|
||||
<div className="group-card-list">
|
||||
{groupIds.map(id => <GroupCard key={id} id={id} />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { default } from './group_timeline';
|
@ -0,0 +1,104 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { Link } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
import { fetchGroups } from '../../../actions/groups';
|
||||
import { openModal } from '../../../actions/modal';
|
||||
import { me } from '../../../initial_state';
|
||||
import GroupCard from './card';
|
||||
import GroupCreate from '../create';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.groups', defaultMessage: 'Groups' },
|
||||
create: { id: 'groups.create', defaultMessage: 'Create group' },
|
||||
tab_featured: { id: 'groups.tab_featured', defaultMessage: 'Featured' },
|
||||
tab_member: { id: 'groups.tab_member', defaultMessage: 'Member' },
|
||||
tab_admin: { id: 'groups.tab_admin', defaultMessage: 'Manage' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, { activeTab }) => ({
|
||||
groupIds: state.getIn(['group_lists', activeTab]),
|
||||
account: state.getIn(['accounts', me]),
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class Groups extends ImmutablePureComponent {
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
activeTab: PropTypes.string.isRequired,
|
||||
showCreateForm: PropTypes.bool,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
groups: ImmutablePropTypes.map,
|
||||
groupIds: ImmutablePropTypes.list,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
this.props.dispatch(fetchGroups(this.props.activeTab));
|
||||
}
|
||||
|
||||
componentDidUpdate(oldProps) {
|
||||
if (this.props.activeTab && this.props.activeTab !== oldProps.activeTab) {
|
||||
this.props.dispatch(fetchGroups(this.props.activeTab));
|
||||
}
|
||||
}
|
||||
|
||||
handleOpenProUpgradeModal = () => {
|
||||
this.props.dispatch(openModal('PRO_UPGRADE'));
|
||||
}
|
||||
|
||||
renderHeader() {
|
||||
const { intl, activeTab, account, onOpenProUpgradeModal } = this.props;
|
||||
|
||||
const isPro = account.get('is_pro');
|
||||
|
||||
return (
|
||||
<div className="group-column-header">
|
||||
<div className="group-column-header__cta">
|
||||
{
|
||||
account && isPro &&
|
||||
<Link to="/groups/create" className="button standard-small">{intl.formatMessage(messages.create)}</Link>
|
||||
}
|
||||
{
|
||||
account && !isPro &&
|
||||
<button onClick={this.handleOpenProUpgradeModal} className="button standard-small">{intl.formatMessage(messages.create)}</button>
|
||||
}
|
||||
</div>
|
||||
<div className="group-column-header__title">{intl.formatMessage(messages.heading)}</div>
|
||||
|
||||
<div className="column-header__wrapper">
|
||||
<h1 className="column-header">
|
||||
<Link to='/groups' className={classNames('btn grouped', {'active': 'featured' === activeTab})}>
|
||||
{intl.formatMessage(messages.tab_featured)}
|
||||
</Link>
|
||||
|
||||
<Link to='/groups/browse/member' className={classNames('btn grouped', {'active': 'member' === activeTab})}>
|
||||
{intl.formatMessage(messages.tab_member)}
|
||||
</Link>
|
||||
|
||||
<Link to='/groups/browse/admin' className={classNames('btn grouped', {'active': 'admin' === activeTab})}>
|
||||
{intl.formatMessage(messages.tab_admin)}
|
||||
</Link>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { groupIds, showCreateForm } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{!showCreateForm && this.renderHeader()}
|
||||
{showCreateForm && <GroupCreate /> }
|
||||
|
||||
<div className="group-card-list">
|
||||
{groupIds.map(id => <GroupCard key={id} id={id} />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { default } from './groups_directory';
|
@ -6,7 +6,7 @@ import { setupListAdder, resetListAdder } from '../../actions/lists';
|
||||
import List from './components/list';
|
||||
import Account from '../../components/account';
|
||||
import IconButton from '../../components/icon_button';
|
||||
import NewListForm from '../lists/components/new_list_form';
|
||||
import NewListForm from '../lists_directory/components/new_list_form';
|
||||
|
||||
const getOrderedLists = createSelector([state => state.get('lists')], lists => {
|
||||
if (!lists) {
|
||||
|
@ -1 +0,0 @@
|
||||
export { default } from './lists';
|
@ -0,0 +1 @@
|
||||
export { default } from './lists_directory';
|
@ -1,13 +1,10 @@
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { createSelector } from 'reselect'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import classNames from 'classnames/bind'
|
||||
import { fetchLists } from '../../actions/lists'
|
||||
import ColumnIndicator from '../../components/column_indicator'
|
||||
import ScrollableList from '../../components/scrollable_list'
|
||||
import Icon from '../../components/icon'
|
||||
import List from '../../components/list'
|
||||
|
||||
const messages = defineMessages({
|
||||
add: { id: 'lists.new.create', defaultMessage: 'Add List' },
|
||||
@ -30,11 +27,9 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
},
|
||||
})
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
export default @connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class Lists extends ImmutablePureComponent {
|
||||
class ListsDirectory extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
@ -63,56 +58,18 @@ class Lists extends ImmutablePureComponent {
|
||||
|
||||
const emptyMessage = intl.formatMessage(messages.empty)
|
||||
|
||||
const listItems = lists.map(list => ({
|
||||
to: `/list/${list.get('id')}`,
|
||||
title: list.get('title'),
|
||||
}))
|
||||
|
||||
return (
|
||||
<ScrollableList
|
||||
<List
|
||||
scrollKey='lists'
|
||||
emptyMessage={emptyMessage}
|
||||
>
|
||||
<div className={[_s.default, _s.backgroundWhite, _s.radiusSmall, _s.overflowHidden, _s.border1PX, _s.bordercolorSecondary].join(' ')}>
|
||||
{
|
||||
lists.map((list, i) => {
|
||||
const isLast = lists.length - 1 === i
|
||||
return (
|
||||
<ListItem key={list.get('id')} list={list} isLast={isLast} />
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</ScrollableList>
|
||||
items={listItems}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ListItem extends ImmutablePureComponent {
|
||||
static propTypes = {
|
||||
isLast: PropTypes.bool,
|
||||
list: ImmutablePropTypes.map,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { list, isLast } = this.props
|
||||
|
||||
const containerClasses = cx({
|
||||
default: 1,
|
||||
cursorPointer: 1,
|
||||
noUnderline: 1,
|
||||
paddingHorizontal15PX: 1,
|
||||
paddingVertical15PX: 1,
|
||||
flexRow: 1,
|
||||
alignItemsCenter: 1,
|
||||
backgroundSubtle_onHover: 1,
|
||||
bordercolorSecondary: !isLast,
|
||||
borderBottom1PX: !isLast,
|
||||
})
|
||||
|
||||
return (
|
||||
<NavLink to={`/list/${list.get('id')}`} className={containerClasses} >
|
||||
<span className={[_s.default, _s.text, _s.colorPrimary, _s.fontSize14PX].join(' ')}>
|
||||
{list.get('title')}
|
||||
</span>
|
||||
<Icon id='angle-right' className={[_s.marginLeftAuto, _s.fillColorBlack].join(' ')} width='10px' height='10px' />
|
||||
</NavLink>
|
||||
)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import SearchContainer from '../compose/containers/search_container';
|
||||
// import SearchContainer from '../compose/containers/search_container';
|
||||
import SearchResultsContainer from '../compose/containers/search_results_container';
|
||||
|
||||
export default class Search extends PureComponent {
|
||||
@ -6,7 +6,7 @@ export default class Search extends PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div className='column search-page'>
|
||||
<SearchContainer />
|
||||
{ /* <SearchContainer /> */ }
|
||||
|
||||
<div className='drawer__pager'>
|
||||
<div className='drawer__inner darker'>
|
||||
|
@ -161,7 +161,7 @@ export default class Card extends ImmutablePureComponent {
|
||||
)
|
||||
|
||||
const description = (
|
||||
<div className={[_s.default, _s.flexNormal, _s.paddingHorizontal10PX, _s.paddingVertical10PX, _s.bordercolorSecondary, _s.borderLeft1PX].join(' ')}>
|
||||
<div className={[_s.default, _s.flexNormal, _s.paddingHorizontal10PX, _s.paddingVertical10PX, _s.borderColorSecondary, _s.borderLeft1PX].join(' ')}>
|
||||
{title}
|
||||
<p className={[_s.default, _s.displayFlex, _s.text, _s.marginVertical5PX, _s.overflowWrapBreakWord, _s.colorSecondary, _s.fontSize13PX, _s.fontWeightNormal].join(' ')}>
|
||||
{trim(card.get('description') || '', maxDescription)}
|
||||
@ -192,7 +192,7 @@ export default class Card extends ImmutablePureComponent {
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.width100PC, _s.paddingHorizontal10PX].join(' ')}>
|
||||
<div className={[_s.default, _s.overflowHidden, _s.width100PC, _s.bordercolorSecondary2, _s.border1PX, _s.radiusSmall].join(' ')}>
|
||||
<div className={[_s.default, _s.overflowHidden, _s.width100PC, _s.borderColorSecondary2, _s.border1PX, _s.radiusSmall].join(' ')}>
|
||||
<div className={[_s.default, _s.width100PC].join(' ')}>
|
||||
<div className={[_s.default, _s.width100PC, _s.paddingTop5625PC].join(' ')}>
|
||||
{ !!embed && embed}
|
||||
@ -231,7 +231,7 @@ export default class Card extends ImmutablePureComponent {
|
||||
<div className={[_s.default, _s.width100PC, _s.paddingHorizontal10PX].join(' ')}>
|
||||
<a
|
||||
href={card.get('url')}
|
||||
className={[_s.default, _s.cursorPointer, _s.flexRow, _s.overflowHidden, _s.noUnderline, _s.width100PC, _s.bordercolorSecondary2, _s.border1PX, _s.radiusSmall].join(' ')}
|
||||
className={[_s.default, _s.cursorPointer, _s.flexRow, _s.overflowHidden, _s.noUnderline, _s.width100PC, _s.borderColorSecondary2, _s.border1PX, _s.radiusSmall].join(' ')}
|
||||
rel='noopener'
|
||||
ref={this.setRef}
|
||||
>
|
||||
|
@ -60,7 +60,7 @@ import {
|
||||
// Groups,
|
||||
// GroupTimeline,
|
||||
ListTimeline,
|
||||
Lists,
|
||||
ListsDirectory,
|
||||
// GroupMembers,
|
||||
// GroupRemovedAccounts,
|
||||
// GroupCreate,
|
||||
@ -195,7 +195,7 @@ class SwitchingColumnsArea extends PureComponent {
|
||||
|
||||
<WrappedRoute path='/tags/:id' publicRoute component={HashtagTimeline} content={children} />
|
||||
*/}
|
||||
<WrappedRoute path='/lists' page={ListsPage} component={Lists} content={children} />
|
||||
<WrappedRoute path='/lists' page={ListsPage} component={ListsDirectory} content={children} />
|
||||
<WrappedRoute path='/list/:id' page={ListPage} component={ListTimeline} content={children} />
|
||||
|
||||
<WrappedRoute path='/notifications' page={NotificationsPage} component={Notifications} content={children} />
|
||||
|
@ -50,8 +50,8 @@ export function Groups () {
|
||||
return import(/* webpackChunkName: "features/groups/index" */'../../groups/index');
|
||||
}
|
||||
|
||||
export function Lists () {
|
||||
return import(/* webpackChunkName: "features/lists" */'../../lists');
|
||||
export function ListsDirectory () {
|
||||
return import(/* webpackChunkName: "features/lists_directory" */'../../lists_directory');
|
||||
}
|
||||
|
||||
export function Status () {
|
||||
|
@ -2228,7 +2228,7 @@
|
||||
"id": "getting_started.security"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "About this server",
|
||||
"defaultMessage": "About",
|
||||
"id": "navigation_bar.info"
|
||||
},
|
||||
{
|
||||
|
@ -240,7 +240,7 @@
|
||||
"navigation_bar.filters": "Muted words",
|
||||
"navigation_bar.follow_requests": "Follow requests",
|
||||
"navigation_bar.follows_and_followers": "Follows and followers",
|
||||
"navigation_bar.info": "About this server",
|
||||
"navigation_bar.info": "About",
|
||||
"navigation_bar.keyboard_shortcuts": "Hotkeys",
|
||||
"navigation_bar.lists": "Lists",
|
||||
"navigation_bar.logout": "Logout",
|
||||
|
@ -237,7 +237,7 @@
|
||||
"navigation_bar.favourites": "Favourites",
|
||||
"navigation_bar.filters": "Muted words",
|
||||
"navigation_bar.follow_requests": "Follow requests",
|
||||
"navigation_bar.info": "About this server",
|
||||
"navigation_bar.info": "About",
|
||||
"navigation_bar.keyboard_shortcuts": "Hotkeys",
|
||||
"navigation_bar.lists": "Lists",
|
||||
"navigation_bar.logout": "Logout",
|
||||
|
@ -22,11 +22,11 @@ export default class ListsPage extends PureComponent {
|
||||
title='Lists'
|
||||
actions={[
|
||||
{
|
||||
icon: 'subtract',
|
||||
icon: 'list-delete',
|
||||
onClick: this.handleClickEditLists
|
||||
},
|
||||
{
|
||||
icon: 'add',
|
||||
icon: 'list-add',
|
||||
onClick: this.handleClickNewList
|
||||
},
|
||||
]}
|
||||
|
@ -95,14 +95,15 @@ body {
|
||||
|
||||
.whiteSpaceNoWrap { white-space: nowrap; }
|
||||
|
||||
.outlineFocusBrand:focus {outline: 2px solid #21cf7a; }
|
||||
.outlineNone { outline: none; }
|
||||
.outlineFocusBrand:focus { outline: 2px solid #21cf7a; }
|
||||
.resizeNone { resize: none; }
|
||||
|
||||
.circle { border-radius: 9999px; }
|
||||
.radiusSmall { border-radius: 8px; }
|
||||
|
||||
.bordercolorSecondary2 { border-color: #e5e9ed; }
|
||||
.bordercolorSecondary { border-color: #ECECED; }
|
||||
.borderColorSecondary2 { border-color: #e5e9ed; }
|
||||
.borderColorSecondary { border-color: #ECECED; }
|
||||
.borderColorWhite { border-color: #fff; }
|
||||
.borderColorBrand { border-color: #21cf7a; }
|
||||
.borderRight1PX { border-right-width: 1px; }
|
||||
@ -131,15 +132,17 @@ body {
|
||||
.backgroundSubtle_onHover:hover { background-color: #F5F8FA; }
|
||||
.backgroundSubtle2 { background-color: #e8ecef; }
|
||||
.backgroundcolorSecondary3 { background-color: #F6F6F9; }
|
||||
.backgroundWhite { background-color: #fff; }
|
||||
.backgroundColorPrimary { 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; }
|
||||
.backgroundColorBrand_onHover:hover { background-color: #21cf7a; }
|
||||
.backgroundColorBrandDark { background-color: #38A16B; }
|
||||
.backgroundColorBrandDark_onHover:hover { background-color: #38A16B; }
|
||||
.colorPrimary { color: #000; }
|
||||
.colorWhite { color: #fff; }
|
||||
.colorWhite_onHover:hover { color: #fff; }
|
||||
.colorSecondary { color: #4B4F55; }
|
||||
.colorBrand { color: #21cf7a }
|
||||
.fillColorBlack { fill: #000; }
|
||||
@ -175,9 +178,9 @@ body {
|
||||
.height350PX { height: 350px; }
|
||||
|
||||
.width1015PX { width: 1015px; }
|
||||
.width660PX { width: 660px; }
|
||||
.width645PX { width: 645px; }
|
||||
.width400PX { width: 400px; }
|
||||
.width325PX { width: 325px; }
|
||||
.width340PX { width: 340px; }
|
||||
.width240PX { width: 240px; }
|
||||
.width100PC { width: 100%; }
|
||||
.width72PX { width: 72px; }
|
||||
@ -185,42 +188,43 @@ body {
|
||||
|
||||
@media (min-width: 1480px) {
|
||||
.width1015PX { width: 1080px; }
|
||||
.width660PX { width: 700px; }
|
||||
.width325PX { width: 350px; }
|
||||
.width645PX { width: 700px; }
|
||||
.width340PX { width: 350px; }
|
||||
.width240PX { width: 250px; }
|
||||
}
|
||||
|
||||
@media (min-width: 1160px) and (max-width: 1280px) {
|
||||
.width1015PX { width: 910px; }
|
||||
.width660PX { width: 580px; }
|
||||
.width325PX { width: 300px; }
|
||||
.width645PX { width: 580px; }
|
||||
.width340PX { width: 300px; }
|
||||
.width240PX { width: 230px; }
|
||||
}
|
||||
|
||||
@media (min-width: 1080px) and (max-width: 1160px) {
|
||||
.width1015PX { width: 850px; }
|
||||
.width660PX { width: 525px; }
|
||||
.width325PX { width: 300px; }
|
||||
.width645PX { width: 525px; }
|
||||
.width340PX { width: 300px; }
|
||||
.width240PX { width: 210px; }
|
||||
}
|
||||
|
||||
@media (min-width: 992px) and (max-width: 1080px) {
|
||||
.width1015PX { width: 850px; }
|
||||
.width660PX { width: 525px; }
|
||||
.width325PX { width: 300px; }
|
||||
.width645PX { width: 525px; }
|
||||
.width340PX { width: 300px; }
|
||||
.width240PX { width: 100px; }
|
||||
}
|
||||
|
||||
@media (min-width: 0px) and (max-width: 992px) {
|
||||
.width1015PX { width: 600px; }
|
||||
.width660PX { width: 600px; }
|
||||
.width325PX { width: 0px; }
|
||||
.width645PX { width: 600px; }
|
||||
.width340PX { width: 0px; }
|
||||
.width240PX { width: 100px; }
|
||||
}
|
||||
|
||||
.top0 { top: 0; }
|
||||
.top60PC { top: 60%; }
|
||||
|
||||
.textAlignLeft { text-align: left; }
|
||||
.textAlignCenter { text-align: center; }
|
||||
|
||||
.fontSize24PX { font-size: 24px; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user