diff options
-rw-r--r-- | app/javascript/mastodon/features/compose/components/search.js | 52 | ||||
-rw-r--r-- | app/javascript/styles/components.scss | 31 |
2 files changed, 82 insertions, 1 deletions
diff --git a/app/javascript/mastodon/features/compose/components/search.js b/app/javascript/mastodon/features/compose/components/search.js index 85ef767ab..79abffad8 100644 --- a/app/javascript/mastodon/features/compose/components/search.js +++ b/app/javascript/mastodon/features/compose/components/search.js @@ -1,11 +1,46 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { defineMessages, injectIntl } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { Overlay } from 'react-overlays'; +import { Motion, spring } from 'react-motion'; const messages = defineMessages({ placeholder: { id: 'search.placeholder', defaultMessage: 'Search' }, }); +class SearchPopout extends React.PureComponent { + + static propTypes = { + style: PropTypes.object, + }; + + render () { + const { style } = this.props; + + return ( + <div style={{ ...style, position: 'absolute', width: 285 }}> + <Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}> + {({ opacity, scaleX, scaleY }) => ( + <div className='search-popout' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}> + <h4><FormattedMessage id='search_popout.search_format' defaultMessage='Advanced search format' /></h4> + + <ul> + <li><em>#example</em> <FormattedMessage id='search_popout.tips.hashtag' defaultMessage='hashtag' /></li> + <li><em>@username@domain</em> <FormattedMessage id='search_popout.tips.user' defaultMessage='user' /></li> + <li><em>URL</em> <FormattedMessage id='search_popout.tips.user' defaultMessage='user' /></li> + <li><em>URL</em> <FormattedMessage id='search_popout.tips.status' defaultMessage='status' /></li> + </ul> + + <FormattedMessage id='search_popout.tips.text' defaultMessage='Simple text returns matching display names, usernames and hashtags' /> + </div> + )} + </Motion> + </div> + ); + } + +} + @injectIntl export default class Search extends React.PureComponent { @@ -19,6 +54,10 @@ export default class Search extends React.PureComponent { intl: PropTypes.object.isRequired, }; + state = { + expanded: false, + }; + handleChange = (e) => { this.props.onChange(e.target.value); } @@ -43,11 +82,17 @@ export default class Search extends React.PureComponent { } handleFocus = () => { + this.setState({ expanded: true }); this.props.onShow(); } + handleBlur = () => { + this.setState({ expanded: false }); + } + render () { const { intl, value, submitted } = this.props; + const { expanded } = this.state; const hasValue = value.length > 0 || submitted; return ( @@ -62,6 +107,7 @@ export default class Search extends React.PureComponent { onChange={this.handleChange} onKeyUp={this.handleKeyDown} onFocus={this.handleFocus} + onBlur={this.handleBlur} /> </label> @@ -69,6 +115,10 @@ export default class Search extends React.PureComponent { <i className={`fa fa-search ${hasValue ? '' : 'active'}`} /> <i aria-label={intl.formatMessage(messages.placeholder)} className={`fa fa-times-circle ${hasValue ? 'active' : ''}`} /> </div> + + <Overlay show={expanded && !hasValue} placement='bottom' target={this}> + <SearchPopout /> + </Overlay> </div> ); } diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss index 48d6e0c4d..e83a22e00 100644 --- a/app/javascript/styles/components.scss +++ b/app/javascript/styles/components.scss @@ -4063,6 +4063,37 @@ button.icon-button.active i.fa-retweet { border-radius: 0; } +.search-popout { + background: $simple-background-color; + border-radius: 4px; + padding: 10px 14px; + padding-bottom: 14px; + margin-top: 10px; + color: $ui-primary-color; + box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); + + h4 { + text-transform: uppercase; + color: $ui-primary-color; + font-size: 13px; + font-weight: 500; + margin-bottom: 10px; + } + + li { + padding: 4px 0; + } + + ul { + margin-bottom: 10px; + } + + em { + font-weight: 500; + color: $ui-base-color; + } +} + noscript { text-align: center; |