diff --git a/app/components/at_mention/at_mention.js b/app/components/at_mention/at_mention.js new file mode 100644 index 000000000..7fe1b0c72 --- /dev/null +++ b/app/components/at_mention/at_mention.js @@ -0,0 +1,50 @@ +// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React, {PropTypes, PureComponent} from 'react'; +import {Text} from 'react-native'; + +import CustomPropTypes from 'app/constants/custom_prop_types'; + +export default class AtMention extends PureComponent { + static propTypes = { + mentionName: PropTypes.string.isRequired, + mentionStyle: CustomPropTypes.Style, + textStyle: CustomPropTypes.Style, + usersByUsername: PropTypes.object.isRequired + }; + + getUsernameFromMentionName = () => { + let mentionName = this.props.mentionName; + + while (mentionName.length > 0) { + if (this.props.usersByUsername[mentionName]) { + return this.props.usersByUsername[mentionName].username; + } + + // Repeatedly trim off trailing punctuation in case this is at the end of a sentence + if ((/[._-]$/).test(mentionName)) { + mentionName = mentionName.substring(0, mentionName.length - 1); + } else { + break; + } + } + + // Just assume this is a mention for a user that we don't have + return mentionName; + } + + render() { + const username = this.getUsernameFromMentionName(); + const suffix = this.props.mentionName.substring(username.length); + + return ( + + + {'@' + username} + + {suffix} + + ); + } +} diff --git a/app/components/at_mention/at_mention_container.js b/app/components/at_mention/at_mention_container.js new file mode 100644 index 000000000..fe5ffee2b --- /dev/null +++ b/app/components/at_mention/at_mention_container.js @@ -0,0 +1,17 @@ +// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import {connect} from 'react-redux'; + +import {getUsersByUsername} from 'mattermost-redux/selectors/entities/users'; + +import AtMention from './at_mention'; + +function mapStateToProps(state, ownProps) { + return { + usersByUsername: getUsersByUsername(state), + ...ownProps + }; +} + +export default connect(mapStateToProps)(AtMention); diff --git a/app/components/at_mention/index.js b/app/components/at_mention/index.js new file mode 100644 index 000000000..6ff7e5ece --- /dev/null +++ b/app/components/at_mention/index.js @@ -0,0 +1,5 @@ +// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import AtMention from './at_mention_container'; +export default AtMention; diff --git a/app/components/markdown/markdown.js b/app/components/markdown/markdown.js index 34994e390..c7af96f31 100644 --- a/app/components/markdown/markdown.js +++ b/app/components/markdown/markdown.js @@ -10,6 +10,7 @@ import { View } from 'react-native'; +import AtMention from 'app/components/at_mention'; import CustomPropTypes from 'app/constants/custom_prop_types'; import {concatStyles} from 'app/utils/theme'; @@ -49,6 +50,7 @@ export default class Markdown extends PureComponent { code: this.renderCodeSpan, link: MarkdownLink, image: this.renderImage, + atMention: this.renderAtMention, paragraph: this.renderParagraph, heading: this.renderHeading, @@ -95,6 +97,16 @@ export default class Markdown extends PureComponent { ); } + renderAtMention = ({context, mentionName}) => { + return ( + + ); + } + renderParagraph = ({children}) => { return ( diff --git a/app/components/post/post.js b/app/components/post/post.js index 6bfe885d2..3e8f331de 100644 --- a/app/components/post/post.js +++ b/app/components/post/post.js @@ -564,6 +564,9 @@ const getMarkdownTextStyles = makeStyleSheetFromTheme((theme) => { height: StyleSheet.hairlineWidth, flex: 1, marginVertical: 10 + }, + mention: { + color: theme.linkColor } }); }); diff --git a/package.json b/package.json index ee279b6a7..1c8143665 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,8 @@ "version": "0.0.1", "private": true, "dependencies": { - "commonmark": "hmhealey/commonmark.js#00189db64c261926de98db16ca14d5b1bcba4d8e", - "commonmark-react-renderer": "hmhealey/commonmark-react-renderer#2e8ea6ac67b683b44782f403b69a06bb0e5c63e6", + "commonmark": "hmhealey/commonmark.js#46784f1461fa34e148940534c1763af6d344ab0f", + "commonmark-react-renderer": "hmhealey/commonmark-react-renderer#7479202c42ab1b722359adadaa13f738edf5f88a", "deep-equal": "1.0.1", "harmony-reflect": "1.5.1", "intl": "1.2.5",