Rename flavours/glitch/features/drawer to flavours/glitch/features/compose
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
// Package imports.
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import {
|
||||
FormattedMessage,
|
||||
defineMessages,
|
||||
} from 'react-intl';
|
||||
|
||||
// Components.
|
||||
import Avatar from 'flavours/glitch/components/avatar';
|
||||
import Permalink from 'flavours/glitch/components/permalink';
|
||||
|
||||
// Utils.
|
||||
import { hiddenComponent } from 'flavours/glitch/util/react_helpers';
|
||||
import { profileLink } from 'flavours/glitch/util/backend_links';
|
||||
|
||||
// Messages.
|
||||
const messages = defineMessages({
|
||||
edit: {
|
||||
defaultMessage: 'Edit profile',
|
||||
id: 'navigation_bar.edit_profile',
|
||||
},
|
||||
});
|
||||
|
||||
// The component.
|
||||
export default function DrawerAccount ({ account }) {
|
||||
|
||||
// We need an account to render.
|
||||
if (!account) {
|
||||
return (
|
||||
<div className='drawer--account'>
|
||||
{ profileLink !== undefined && (
|
||||
<a
|
||||
className='edit'
|
||||
href={ profileLink }
|
||||
>
|
||||
<FormattedMessage {...messages.edit} />
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// The result.
|
||||
return (
|
||||
<div className='drawer--account'>
|
||||
<Permalink
|
||||
className='avatar'
|
||||
href={account.get('url')}
|
||||
to={`/accounts/${account.get('id')}`}
|
||||
>
|
||||
<span {...hiddenComponent}>{account.get('acct')}</span>
|
||||
<Avatar
|
||||
account={account}
|
||||
size={40}
|
||||
/>
|
||||
</Permalink>
|
||||
<Permalink
|
||||
className='acct'
|
||||
href={account.get('url')}
|
||||
to={`/accounts/${account.get('id')}`}
|
||||
>
|
||||
<strong>@{account.get('acct')}</strong>
|
||||
</Permalink>
|
||||
{ profileLink !== undefined && (
|
||||
<a
|
||||
className='edit'
|
||||
href={ profileLink }
|
||||
><FormattedMessage {...messages.edit} /></a>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Props.
|
||||
DrawerAccount.propTypes = { account: ImmutablePropTypes.map };
|
127
app/javascript/flavours/glitch/features/compose/header/index.js
Normal file
127
app/javascript/flavours/glitch/features/compose/header/index.js
Normal file
@@ -0,0 +1,127 @@
|
||||
// Package imports.
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { defineMessages } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
// Components.
|
||||
import Icon from 'flavours/glitch/components/icon';
|
||||
|
||||
// Utils.
|
||||
import { conditionalRender } from 'flavours/glitch/util/react_helpers';
|
||||
import { signOutLink } from 'flavours/glitch/util/backend_links';
|
||||
|
||||
// Messages.
|
||||
const messages = defineMessages({
|
||||
community: {
|
||||
defaultMessage: 'Local timeline',
|
||||
id: 'navigation_bar.community_timeline',
|
||||
},
|
||||
home_timeline: {
|
||||
defaultMessage: 'Home',
|
||||
id: 'tabs_bar.home',
|
||||
},
|
||||
logout: {
|
||||
defaultMessage: 'Logout',
|
||||
id: 'navigation_bar.logout',
|
||||
},
|
||||
notifications: {
|
||||
defaultMessage: 'Notifications',
|
||||
id: 'tabs_bar.notifications',
|
||||
},
|
||||
public: {
|
||||
defaultMessage: 'Federated timeline',
|
||||
id: 'navigation_bar.public_timeline',
|
||||
},
|
||||
settings: {
|
||||
defaultMessage: 'App settings',
|
||||
id: 'navigation_bar.app_settings',
|
||||
},
|
||||
start: {
|
||||
defaultMessage: 'Getting started',
|
||||
id: 'getting_started.heading',
|
||||
},
|
||||
});
|
||||
|
||||
// The component.
|
||||
export default function DrawerHeader ({
|
||||
columns,
|
||||
unreadNotifications,
|
||||
showNotificationsBadge,
|
||||
intl,
|
||||
onSettingsClick,
|
||||
}) {
|
||||
|
||||
// Only renders the component if the column isn't being shown.
|
||||
const renderForColumn = conditionalRender.bind(null,
|
||||
columnId => !columns || !columns.some(
|
||||
column => column.get('id') === columnId
|
||||
)
|
||||
);
|
||||
|
||||
// The result.
|
||||
return (
|
||||
<nav className='drawer--header'>
|
||||
<Link
|
||||
aria-label={intl.formatMessage(messages.start)}
|
||||
title={intl.formatMessage(messages.start)}
|
||||
to='/getting-started'
|
||||
><Icon icon='asterisk' /></Link>
|
||||
{renderForColumn('HOME', (
|
||||
<Link
|
||||
aria-label={intl.formatMessage(messages.home_timeline)}
|
||||
title={intl.formatMessage(messages.home_timeline)}
|
||||
to='/timelines/home'
|
||||
><Icon icon='home' /></Link>
|
||||
))}
|
||||
{renderForColumn('NOTIFICATIONS', (
|
||||
<Link
|
||||
aria-label={intl.formatMessage(messages.notifications)}
|
||||
title={intl.formatMessage(messages.notifications)}
|
||||
to='/notifications'
|
||||
>
|
||||
<span className='icon-badge-wrapper'>
|
||||
<Icon icon='bell' />
|
||||
{ showNotificationsBadge && unreadNotifications > 0 && <div className='icon-badge' />}
|
||||
</span>
|
||||
</Link>
|
||||
))}
|
||||
{renderForColumn('COMMUNITY', (
|
||||
<Link
|
||||
aria-label={intl.formatMessage(messages.community)}
|
||||
title={intl.formatMessage(messages.community)}
|
||||
to='/timelines/public/local'
|
||||
><Icon icon='users' /></Link>
|
||||
))}
|
||||
{renderForColumn('PUBLIC', (
|
||||
<Link
|
||||
aria-label={intl.formatMessage(messages.public)}
|
||||
title={intl.formatMessage(messages.public)}
|
||||
to='/timelines/public'
|
||||
><Icon icon='globe' /></Link>
|
||||
))}
|
||||
<a
|
||||
aria-label={intl.formatMessage(messages.settings)}
|
||||
onClick={onSettingsClick}
|
||||
href='#'
|
||||
title={intl.formatMessage(messages.settings)}
|
||||
><Icon icon='cogs' /></a>
|
||||
<a
|
||||
aria-label={intl.formatMessage(messages.logout)}
|
||||
data-method='delete'
|
||||
href={ signOutLink }
|
||||
title={intl.formatMessage(messages.logout)}
|
||||
><Icon icon='sign-out' /></a>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
// Props.
|
||||
DrawerHeader.propTypes = {
|
||||
columns: ImmutablePropTypes.list,
|
||||
unreadNotifications: PropTypes.number,
|
||||
showNotificationsBadge: PropTypes.bool,
|
||||
intl: PropTypes.object,
|
||||
onSettingsClick: PropTypes.func,
|
||||
};
|
166
app/javascript/flavours/glitch/features/compose/index.js
Normal file
166
app/javascript/flavours/glitch/features/compose/index.js
Normal file
@@ -0,0 +1,166 @@
|
||||
// Package imports.
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
|
||||
// Actions.
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
import {
|
||||
changeSearch,
|
||||
clearSearch,
|
||||
showSearch,
|
||||
submitSearch,
|
||||
} from 'flavours/glitch/actions/search';
|
||||
import { cycleElefriendCompose } from 'flavours/glitch/actions/compose';
|
||||
|
||||
// Components.
|
||||
import Composer from 'flavours/glitch/features/composer';
|
||||
import DrawerAccount from './account';
|
||||
import DrawerHeader from './header';
|
||||
import DrawerResults from './results';
|
||||
import DrawerSearch from './search';
|
||||
|
||||
// Utils.
|
||||
import { me, mascot } from 'flavours/glitch/util/initial_state';
|
||||
import { wrap } from 'flavours/glitch/util/redux_helpers';
|
||||
|
||||
// Messages.
|
||||
const messages = defineMessages({
|
||||
compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new toot' },
|
||||
});
|
||||
|
||||
// State mapping.
|
||||
const mapStateToProps = state => ({
|
||||
account: state.getIn(['accounts', me]),
|
||||
columns: state.getIn(['settings', 'columns']),
|
||||
elefriend: state.getIn(['compose', 'elefriend']),
|
||||
results: state.getIn(['search', 'results']),
|
||||
searchHidden: state.getIn(['search', 'hidden']),
|
||||
searchValue: state.getIn(['search', 'value']),
|
||||
submitted: state.getIn(['search', 'submitted']),
|
||||
unreadNotifications: state.getIn(['notifications', 'unread']),
|
||||
showNotificationsBadge: state.getIn(['local_settings', 'notifications', 'tab_badge']),
|
||||
});
|
||||
|
||||
// Dispatch mapping.
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
onChange (value) {
|
||||
dispatch(changeSearch(value));
|
||||
},
|
||||
onClear () {
|
||||
dispatch(clearSearch());
|
||||
},
|
||||
onClickElefriend () {
|
||||
dispatch(cycleElefriendCompose());
|
||||
},
|
||||
onShow () {
|
||||
dispatch(showSearch());
|
||||
},
|
||||
onSubmit () {
|
||||
dispatch(submitSearch());
|
||||
},
|
||||
onOpenSettings (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
dispatch(openModal('SETTINGS', {}));
|
||||
},
|
||||
});
|
||||
|
||||
// The component.
|
||||
export default @connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class Compose extends React.PureComponent {
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
isSearchPage: PropTypes.bool,
|
||||
multiColumn: PropTypes.bool,
|
||||
|
||||
// State props.
|
||||
account: ImmutablePropTypes.map,
|
||||
columns: ImmutablePropTypes.list,
|
||||
results: ImmutablePropTypes.map,
|
||||
elefriend: PropTypes.number,
|
||||
searchHidden: PropTypes.bool,
|
||||
searchValue: PropTypes.string,
|
||||
submitted: PropTypes.bool,
|
||||
unreadNotifications: PropTypes.number,
|
||||
showNotificationsBadge: PropTypes.bool,
|
||||
|
||||
// Dispatch props.
|
||||
onChange: PropTypes.func,
|
||||
onClear: PropTypes.func,
|
||||
onClickElefriend: PropTypes.func,
|
||||
onShow: PropTypes.func,
|
||||
onSubmit: PropTypes.func,
|
||||
onOpenSettings: PropTypes.func,
|
||||
};
|
||||
|
||||
// Rendering.
|
||||
render () {
|
||||
const {
|
||||
account,
|
||||
columns,
|
||||
elefriend,
|
||||
intl,
|
||||
multiColumn,
|
||||
onChange,
|
||||
onClear,
|
||||
onClickElefriend,
|
||||
onOpenSettings,
|
||||
onShow,
|
||||
onSubmit,
|
||||
results,
|
||||
searchHidden,
|
||||
searchValue,
|
||||
submitted,
|
||||
isSearchPage,
|
||||
unreadNotifications,
|
||||
showNotificationsBadge,
|
||||
} = this.props;
|
||||
const computedClass = classNames('drawer', `mbstobon-${elefriend}`);
|
||||
|
||||
// The result.
|
||||
return (
|
||||
<div className={computedClass} role='region' aria-label={intl.formatMessage(messages.compose)}>
|
||||
{multiColumn && (
|
||||
<DrawerHeader
|
||||
columns={columns}
|
||||
unreadNotifications={unreadNotifications}
|
||||
showNotificationsBadge={showNotificationsBadge}
|
||||
intl={intl}
|
||||
onSettingsClick={onOpenSettings}
|
||||
/>
|
||||
)}
|
||||
{(multiColumn || isSearchPage) && <DrawerSearch
|
||||
intl={intl}
|
||||
onChange={onChange}
|
||||
onClear={onClear}
|
||||
onShow={onShow}
|
||||
onSubmit={onSubmit}
|
||||
submitted={submitted}
|
||||
value={searchValue}
|
||||
/> }
|
||||
<div className='drawer__pager'>
|
||||
{!isSearchPage && <div className='drawer__inner'>
|
||||
<DrawerAccount account={account} />
|
||||
<Composer />
|
||||
{multiColumn && (
|
||||
<div className='drawer__inner__mastodon'>
|
||||
{mascot ? <img alt='' draggable='false' src={mascot} /> : <button className='mastodon' onClick={onClickElefriend} />}
|
||||
</div>
|
||||
)}
|
||||
</div>}
|
||||
|
||||
{(multiColumn || isSearchPage) &&
|
||||
<DrawerResults
|
||||
results={results}
|
||||
visible={submitted && !searchHidden}
|
||||
/>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
117
app/javascript/flavours/glitch/features/compose/results/index.js
Normal file
117
app/javascript/flavours/glitch/features/compose/results/index.js
Normal file
@@ -0,0 +1,117 @@
|
||||
// Package imports.
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import {
|
||||
FormattedMessage,
|
||||
defineMessages,
|
||||
} from 'react-intl';
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
// Components.
|
||||
import Icon from 'flavours/glitch/components/icon';
|
||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||
import StatusContainer from 'flavours/glitch/containers/status_container';
|
||||
import Hashtag from 'flavours/glitch/components/hashtag';
|
||||
|
||||
// Utils.
|
||||
import Motion from 'flavours/glitch/util/optional_motion';
|
||||
|
||||
// Messages.
|
||||
const messages = defineMessages({
|
||||
total: {
|
||||
defaultMessage: '{count, number} {count, plural, one {result} other {results}}',
|
||||
id: 'search_results.total',
|
||||
},
|
||||
});
|
||||
|
||||
// The component.
|
||||
export default function DrawerResults ({
|
||||
results,
|
||||
visible,
|
||||
}) {
|
||||
const accounts = results ? results.get('accounts') : null;
|
||||
const statuses = results ? results.get('statuses') : null;
|
||||
const hashtags = results ? results.get('hashtags') : null;
|
||||
|
||||
// This gets the total number of items.
|
||||
const count = [accounts, statuses, hashtags].reduce(function (size, item) {
|
||||
if (item && item.size) {
|
||||
return size + item.size;
|
||||
}
|
||||
return size;
|
||||
}, 0);
|
||||
|
||||
// The result.
|
||||
return (
|
||||
<Motion
|
||||
defaultStyle={{ x: -100 }}
|
||||
style={{
|
||||
x: spring(visible ? 0 : -100, {
|
||||
stiffness: 210,
|
||||
damping: 20,
|
||||
}),
|
||||
}}
|
||||
>
|
||||
{({ x }) => (
|
||||
<div
|
||||
className='drawer--results'
|
||||
style={{
|
||||
transform: `translateX(${x}%)`,
|
||||
visibility: x === -100 ? 'hidden' : 'visible',
|
||||
}}
|
||||
>
|
||||
<header>
|
||||
<Icon icon='search' fixedWidth />
|
||||
<FormattedMessage
|
||||
{...messages.total}
|
||||
values={{ count }}
|
||||
/>
|
||||
</header>
|
||||
{accounts && accounts.size ? (
|
||||
<section>
|
||||
<h5><Icon icon='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='People' /></h5>
|
||||
|
||||
{accounts.map(
|
||||
accountId => (
|
||||
<AccountContainer
|
||||
id={accountId}
|
||||
key={accountId}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</section>
|
||||
) : null}
|
||||
{statuses && statuses.size ? (
|
||||
<section>
|
||||
<h5><Icon icon='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>
|
||||
|
||||
{statuses.map(
|
||||
statusId => (
|
||||
<StatusContainer
|
||||
id={statusId}
|
||||
key={statusId}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</section>
|
||||
) : null}
|
||||
{hashtags && hashtags.size ? (
|
||||
<section>
|
||||
<h5><Icon icon='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></h5>
|
||||
|
||||
{hashtags.map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
|
||||
</section>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</Motion>
|
||||
);
|
||||
}
|
||||
|
||||
// Props.
|
||||
DrawerResults.propTypes = {
|
||||
results: ImmutablePropTypes.map,
|
||||
visible: PropTypes.bool,
|
||||
};
|
152
app/javascript/flavours/glitch/features/compose/search/index.js
Normal file
152
app/javascript/flavours/glitch/features/compose/search/index.js
Normal file
@@ -0,0 +1,152 @@
|
||||
// Package imports.
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import {
|
||||
FormattedMessage,
|
||||
defineMessages,
|
||||
} from 'react-intl';
|
||||
import Overlay from 'react-overlays/lib/Overlay';
|
||||
|
||||
// Components.
|
||||
import Icon from 'flavours/glitch/components/icon';
|
||||
import DrawerSearchPopout from './popout';
|
||||
|
||||
// Utils.
|
||||
import { focusRoot } from 'flavours/glitch/util/dom_helpers';
|
||||
import {
|
||||
assignHandlers,
|
||||
hiddenComponent,
|
||||
} from 'flavours/glitch/util/react_helpers';
|
||||
|
||||
// Messages.
|
||||
const messages = defineMessages({
|
||||
placeholder: {
|
||||
defaultMessage: 'Search',
|
||||
id: 'search.placeholder',
|
||||
},
|
||||
});
|
||||
|
||||
// Handlers.
|
||||
const handlers = {
|
||||
|
||||
handleBlur () {
|
||||
this.setState({ expanded: false });
|
||||
},
|
||||
|
||||
handleChange ({ target: { value } }) {
|
||||
const { onChange } = this.props;
|
||||
if (onChange) {
|
||||
onChange(value);
|
||||
}
|
||||
},
|
||||
|
||||
handleClear (e) {
|
||||
const {
|
||||
onClear,
|
||||
submitted,
|
||||
value,
|
||||
} = this.props;
|
||||
e.preventDefault(); // Prevents focus change ??
|
||||
if (onClear && (submitted || value && value.length)) {
|
||||
onClear();
|
||||
}
|
||||
},
|
||||
|
||||
handleFocus () {
|
||||
const { onShow } = this.props;
|
||||
this.setState({ expanded: true });
|
||||
if (onShow) {
|
||||
onShow();
|
||||
}
|
||||
},
|
||||
|
||||
handleKeyUp (e) {
|
||||
const { onSubmit } = this.props;
|
||||
switch (e.key) {
|
||||
case 'Enter':
|
||||
if (onSubmit) {
|
||||
onSubmit();
|
||||
}
|
||||
break;
|
||||
case 'Escape':
|
||||
focusRoot();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// The component.
|
||||
export default class DrawerSearch extends React.PureComponent {
|
||||
|
||||
// Constructor.
|
||||
constructor (props) {
|
||||
super(props);
|
||||
assignHandlers(this, handlers);
|
||||
this.state = { expanded: false };
|
||||
}
|
||||
|
||||
// Rendering.
|
||||
render () {
|
||||
const {
|
||||
handleBlur,
|
||||
handleChange,
|
||||
handleClear,
|
||||
handleFocus,
|
||||
handleKeyUp,
|
||||
} = this.handlers;
|
||||
const {
|
||||
intl,
|
||||
submitted,
|
||||
value,
|
||||
} = this.props;
|
||||
const { expanded } = this.state;
|
||||
const active = value && value.length || submitted;
|
||||
const computedClass = classNames('drawer--search', { active });
|
||||
|
||||
return (
|
||||
<div className={computedClass}>
|
||||
<label>
|
||||
<span {...hiddenComponent}>
|
||||
<FormattedMessage {...messages.placeholder} />
|
||||
</span>
|
||||
<input
|
||||
type='text'
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
value={value || ''}
|
||||
onChange={handleChange}
|
||||
onKeyUp={handleKeyUp}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
</label>
|
||||
<div
|
||||
aria-label={intl.formatMessage(messages.placeholder)}
|
||||
className='icon'
|
||||
onClick={handleClear}
|
||||
role='button'
|
||||
tabIndex='0'
|
||||
>
|
||||
<Icon icon='search' />
|
||||
<Icon icon='times-circle' />
|
||||
</div>
|
||||
<Overlay
|
||||
placement='bottom'
|
||||
show={expanded && !active}
|
||||
target={this}
|
||||
><DrawerSearchPopout /></Overlay>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Props.
|
||||
DrawerSearch.propTypes = {
|
||||
value: PropTypes.string,
|
||||
submitted: PropTypes.bool,
|
||||
onChange: PropTypes.func,
|
||||
onSubmit: PropTypes.func,
|
||||
onClear: PropTypes.func,
|
||||
onShow: PropTypes.func,
|
||||
intl: PropTypes.object,
|
||||
};
|
@@ -0,0 +1,109 @@
|
||||
// Package imports.
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import {
|
||||
FormattedMessage,
|
||||
defineMessages,
|
||||
} from 'react-intl';
|
||||
import spring from 'react-motion/lib/spring';
|
||||
|
||||
// Utils.
|
||||
import Motion from 'flavours/glitch/util/optional_motion';
|
||||
import { searchEnabled } from 'flavours/glitch/util/initial_state';
|
||||
|
||||
// Messages.
|
||||
const messages = defineMessages({
|
||||
format: {
|
||||
defaultMessage: 'Advanced search format',
|
||||
id: 'search_popout.search_format',
|
||||
},
|
||||
hashtag: {
|
||||
defaultMessage: 'hashtag',
|
||||
id: 'search_popout.tips.hashtag',
|
||||
},
|
||||
status: {
|
||||
defaultMessage: 'status',
|
||||
id: 'search_popout.tips.status',
|
||||
},
|
||||
text: {
|
||||
defaultMessage: 'Simple text returns matching display names, usernames and hashtags',
|
||||
id: 'search_popout.tips.text',
|
||||
},
|
||||
full_text: {
|
||||
defaultMessage: 'Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.',
|
||||
id: 'search_popout.tips.full_text',
|
||||
},
|
||||
user: {
|
||||
defaultMessage: 'user',
|
||||
id: 'search_popout.tips.user',
|
||||
},
|
||||
});
|
||||
|
||||
// The spring used by our motion.
|
||||
const motionSpring = spring(1, { damping: 35, stiffness: 400 });
|
||||
|
||||
// The component.
|
||||
export default function DrawerSearchPopout ({ style }) {
|
||||
|
||||
// The result.
|
||||
return (
|
||||
<div
|
||||
className='drawer--search--popout'
|
||||
style={{
|
||||
...style,
|
||||
position: 'absolute',
|
||||
width: 285,
|
||||
}}
|
||||
>
|
||||
<Motion
|
||||
defaultStyle={{
|
||||
opacity: 0,
|
||||
scaleX: 0.85,
|
||||
scaleY: 0.75,
|
||||
}}
|
||||
style={{
|
||||
opacity: motionSpring,
|
||||
scaleX: motionSpring,
|
||||
scaleY: motionSpring,
|
||||
}}
|
||||
>
|
||||
{({ opacity, scaleX, scaleY }) => (
|
||||
<div
|
||||
style={{
|
||||
opacity: opacity,
|
||||
transform: `scale(${scaleX}, ${scaleY})`,
|
||||
}}
|
||||
>
|
||||
<h4><FormattedMessage {...messages.format} /></h4>
|
||||
<ul>
|
||||
<li>
|
||||
<em>#example</em>
|
||||
{' '}
|
||||
<FormattedMessage {...messages.hashtag} />
|
||||
</li>
|
||||
<li>
|
||||
<em>@username@domain</em>
|
||||
{' '}
|
||||
<FormattedMessage {...messages.user} />
|
||||
</li>
|
||||
<li>
|
||||
<em>URL</em>
|
||||
{' '}
|
||||
<FormattedMessage {...messages.user} />
|
||||
</li>
|
||||
<li>
|
||||
<em>URL</em>
|
||||
{' '}
|
||||
<FormattedMessage {...messages.status} />
|
||||
</li>
|
||||
</ul>
|
||||
{ searchEnabled ? <FormattedMessage {...messages.full_text} /> : <FormattedMessage {...messages.text} /> }
|
||||
</div>
|
||||
)}
|
||||
</Motion>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Props.
|
||||
DrawerSearchPopout.propTypes = { style: PropTypes.object };
|
Reference in New Issue
Block a user