diff options
author | Dessalines <tyhou13@gmx.com> | 2020-03-03 02:29:45 -0500 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2020-03-03 02:29:45 -0500 |
commit | 44bbc459736ac53b9150903af14c20a497caf9ab (patch) | |
tree | 0bf8899cfc448e7b70230de52cec9119aa43f011 | |
parent | 5f6f51b549d42943b85d8f7dc9d193aec0935ab6 (diff) |
A first pass at adding icons, and tippy tooltips.
- Adding icons for post-listing, comment-node, and navbar.
- Adding html titles.
- Updating moment expand to use users locale.
-rw-r--r-- | ui/assets/css/main.css | 26 | ||||
-rw-r--r-- | ui/assets/css/tippy.css | 1 | ||||
-rw-r--r-- | ui/package.json | 1 | ||||
-rw-r--r-- | ui/src/components/comment-form.tsx | 14 | ||||
-rw-r--r-- | ui/src/components/comment-node.tsx | 141 | ||||
-rw-r--r-- | ui/src/components/community.tsx | 1 | ||||
-rw-r--r-- | ui/src/components/iframely-card.tsx | 2 | ||||
-rw-r--r-- | ui/src/components/inbox.tsx | 1 | ||||
-rw-r--r-- | ui/src/components/main.tsx | 2 | ||||
-rw-r--r-- | ui/src/components/moment-time.tsx | 27 | ||||
-rw-r--r-- | ui/src/components/navbar.tsx | 32 | ||||
-rw-r--r-- | ui/src/components/post-form.tsx | 16 | ||||
-rw-r--r-- | ui/src/components/post-listing.tsx | 133 | ||||
-rw-r--r-- | ui/src/components/symbols.tsx | 57 | ||||
-rw-r--r-- | ui/src/components/user.tsx | 1 | ||||
-rw-r--r-- | ui/src/index.html | 1 | ||||
-rw-r--r-- | ui/src/utils.ts | 12 | ||||
-rw-r--r-- | ui/translations/en.json | 2 | ||||
-rw-r--r-- | ui/yarn.lock | 12 |
19 files changed, 373 insertions, 109 deletions
diff --git a/ui/assets/css/main.css b/ui/assets/css/main.css index b03f2703..d206a508 100644 --- a/ui/assets/css/main.css +++ b/ui/assets/css/main.css @@ -95,8 +95,17 @@ fill: currentColor; vertical-align: middle; align-self: center; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } +.icon-inline { + margin-bottom: 2px; +} .spin { animation: spins 2s linear infinite; @@ -225,3 +234,20 @@ hr { height: 50px; width: 50px; } + +.unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.list-inline-item-action { + display: inline-block; +} + +.list-inline-item-action:not(:last-child) { + margin-right: 1.2rem; +} diff --git a/ui/assets/css/tippy.css b/ui/assets/css/tippy.css new file mode 100644 index 00000000..ff0a3132 --- /dev/null +++ b/ui/assets/css/tippy.css @@ -0,0 +1 @@ +.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}.tippy-iOS{cursor:pointer!important;-webkit-tap-highlight-color:transparent}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{border-width:8px 8px 0;border-top-color:#333;bottom:-7px;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;border-width:0 8px 8px;border-bottom-color:#333;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:#333;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:#333;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}
\ No newline at end of file diff --git a/ui/package.json b/ui/package.json index f12f947a..8658d136 100644 --- a/ui/package.json +++ b/ui/package.json @@ -41,6 +41,7 @@ "reconnecting-websocket": "^4.4.0", "rxjs": "^6.4.0", "terser": "^4.6.3", + "tippy.js": "^6.0.0", "toastify-js": "^1.6.2", "tributejs": "^4.1.1", "twemoji": "^12.1.2", diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index eaa054d8..aa8e651d 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -141,16 +141,22 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { <a href={markdownHelpUrl} target="_blank" - class="d-inline-block float-right text-muted small font-weight-bold" + class="d-inline-block float-right text-muted font-weight-bold" + title={i18n.t('formatting_help')} > - {i18n.t('formatting_help')} + <svg class="icon icon-inline"> + <use xlinkHref="#icon-help-circle"></use> + </svg> </a> - <form class="d-inline-block mr-2 float-right text-muted small font-weight-bold"> + <form class="d-inline-block mr-3 float-right text-muted font-weight-bold"> <label htmlFor={`file-upload-${this.id}`} className={`${UserService.Instance.user && 'pointer'}`} + data-tippy-content={i18n.t('upload_image')} > - {i18n.t('upload_image')} + <svg class="icon icon-inline"> + <use xlinkHref="#icon-image"></use> + </svg> </label> <input id={`file-upload-${this.id}`} diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index cd95a75b..3db87aa5 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -26,6 +26,7 @@ import { isMod, pictshareAvatarThumbnail, showAvatars, + setupTippy, } from '../utils'; import moment from 'moment'; import { MomentTime } from './moment-time'; @@ -102,6 +103,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this.handleCommentDownvote = this.handleCommentDownvote.bind(this); } + componentDidUpdate() { + setupTippy(); + } + componentWillReceiveProps(nextProps: CommentNodeProps) { this.state.my_vote = nextProps.node.comment.my_vote; this.state.upvotes = nextProps.node.comment.upvotes; @@ -128,18 +133,22 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { this.state.my_vote == 1 ? 'text-info' : 'text-muted' }`} onClick={linkEvent(node, this.handleCommentUpvote)} + data-tippy-content={i18n.t('upvote')} > <svg class="icon upvote"> <use xlinkHref="#icon-arrow-up"></use> </svg> </button> - <div class={`font-weight-bold text-muted`}>{this.state.score}</div> + <div class={`unselectable font-weight-bold text-muted`}> + {this.state.score} + </div> {WebSocketService.Instance.site.enable_downvotes && ( <button className={`vote-animate btn btn-link p-0 ${ this.state.my_vote == -1 ? 'text-danger' : 'text-muted' }`} onClick={linkEvent(node, this.handleCommentDownvote)} + data-tippy-content={i18n.t('downvote')} > <svg class="icon downvote"> <use xlinkHref="#icon-arrow-down"></use> @@ -192,11 +201,19 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { </li> )} <li className="list-inline-item"> - <span> - (<span className="text-info">+{this.state.upvotes}</span> - <span> | </span> - <span className="text-danger">-{this.state.downvotes}</span> - <span>) </span> + <span className="text-info"> + <svg class="small icon icon-inline mr-1"> + <use xlinkHref="#icon-arrow-up"></use> + </svg> + {this.state.upvotes} + </span> + </li> + <li className="list-inline-item"> + <span className="text-danger"> + <svg class="small icon icon-inline mr-1"> + <use xlinkHref="#icon-arrow-down"></use> + </svg> + {this.state.downvotes} </span> </li> {this.props.showCommunity && ( @@ -214,7 +231,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { </li> <li className="list-inline-item"> <div - className="pointer text-monospace" + className="unselectable pointer text-monospace" onClick={linkEvent(this, this.handleCommentCollapse)} > {this.state.collapsed ? '[+]' : '[-]'} @@ -239,97 +256,141 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { dangerouslySetInnerHTML={mdToHtml(this.commentUnlessRemoved)} /> )} - <ul class="list-inline mb-1 text-muted small font-weight-bold"> + <ul class="list-inline mb-1 text-muted font-weight-bold h6"> {this.props.markable && ( - <li className="list-inline-item"> + <li className="list-inline-item-action"> <span class="pointer" onClick={linkEvent(this, this.handleMarkRead)} + data-tippy-content={ + node.comment.read + ? i18n.t('mark_as_unread') + : i18n.t('mark_as_read') + } > - {node.comment.read - ? i18n.t('mark_as_unread') - : i18n.t('mark_as_read')} + <svg + class={`icon icon-inline ${node.comment.read && + 'text-success'}`} + > + <use xlinkHref="#icon-check"></use> + </svg> </span> </li> )} {UserService.Instance.user && !this.props.viewOnly && ( <> - <li className="list-inline-item"> + <li className="list-inline-item-action"> <span class="pointer" onClick={linkEvent(this, this.handleReplyClick)} + data-tippy-content={i18n.t('reply')} > - {i18n.t('reply')} + <svg class="icon icon-inline"> + <use xlinkHref="#icon-reply1"></use> + </svg> </span> </li> - <li className="list-inline-item mr-2"> + <li className="list-inline-item-action"> <span class="pointer" onClick={linkEvent(this, this.handleSaveCommentClick)} + data-tippy-content={ + node.comment.saved ? i18n.t('unsave') : i18n.t('save') + } > - {node.comment.saved ? i18n.t('unsave') : i18n.t('save')} + <svg + class={`icon icon-inline ${node.comment.saved && + 'text-warning'}`} + > + <use xlinkHref="#icon-star"></use> + </svg> </span> </li> {!this.myComment && ( - <li className="list-inline-item"> + <li className="list-inline-item-action"> <Link class="text-muted" to={`/create_private_message?recipient_id=${node.comment.creator_id}`} + title={i18n.t('message').toLowerCase()} > - {i18n.t('message').toLowerCase()} + <svg class="icon icon-inline"> + <use xlinkHref="#icon-mail"></use> + </svg> </Link> </li> )} - <li className="list-inline-item"> + <li className="list-inline-item-action"> <Link className="text-muted" to={`/post/${node.comment.post_id}/comment/${node.comment.id}`} + title={i18n.t('link')} > - {i18n.t('link')} + <svg class="icon icon-inline"> + <use xlinkHref="#icon-external-link"></use> + </svg> </Link> </li> {!this.state.showAdvanced ? ( - <li className="list-inline-item"> + <li className="list-inline-item-action"> <span - className="pointer" + className="unselectable pointer" onClick={linkEvent(this, this.handleShowAdvanced)} + data-tippy-content={i18n.t('more')} > - {i18n.t('more')} + <svg class="icon icon-inline"> + <use xlinkHref="#icon-more-vertical"></use> + </svg> </span> </li> ) : ( <> - <li className="list-inline-item">•</li> - <li className="list-inline-item"> + <li className="list-inline-item-action"> <span className="pointer" onClick={linkEvent(this, this.handleViewSource)} + data-tippy-content={i18n.t('view_source')} > - {i18n.t('view_source')} + <svg + class={`icon icon-inline ${this.state + .viewSource && 'text-success'}`} + > + <use xlinkHref="#icon-eye"></use> + </svg> </span> </li> - <li className="list-inline-item">•</li> {this.myComment && ( <> - <li className="list-inline-item"> + <li className="list-inline-item-action">•</li> + <li className="list-inline-item-action"> <span class="pointer" onClick={linkEvent(this, this.handleEditClick)} + data-tippy-content={i18n.t('edit')} > - {i18n.t('edit')} + <svg class="icon icon-inline"> + <use xlinkHref="#icon-edit"></use> + </svg> </span> </li> - <li className="list-inline-item"> + <li className="list-inline-item-action"> <span class="pointer" onClick={linkEvent( this, this.handleDeleteClick )} + data-tippy-content={ + !node.comment.deleted + ? i18n.t('delete') + : i18n.t('restore') + } > - {!node.comment.deleted - ? i18n.t('delete') - : i18n.t('restore')} + <svg + class={`icon icon-inline ${node.comment + .deleted && 'text-danger'}`} + > + <use xlinkHref="#icon-trash"></use> + </svg> </span> </li> </> @@ -337,7 +398,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { {/* Admins and mods can remove comments */} {(this.canMod || this.canAdmin) && ( <> - <li className="list-inline-item"> + <li className="list-inline-item-action"> {!node.comment.removed ? ( <span class="pointer" @@ -366,7 +427,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { {this.canMod && ( <> {!this.isMod && ( - <li className="list-inline-item"> + <li className="list-inline-item-action"> {!node.comment.banned_from_community ? ( <span class="pointer" @@ -391,7 +452,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { </li> )} {!node.comment.banned_from_community && ( - <li className="list-inline-item"> + <li className="list-inline-item-action"> {!this.state.showConfirmAppointAsMod ? ( <span class="pointer" @@ -436,7 +497,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { {/* Community creators and admins can transfer community to another mod */} {(this.amCommunityCreator || this.canAdmin) && this.isMod && ( - <li className="list-inline-item"> + <li className="list-inline-item-action"> {!this.state.showConfirmTransferCommunity ? ( <span class="pointer" @@ -479,7 +540,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { {this.canAdmin && ( <> {!this.isAdmin && ( - <li className="list-inline-item"> + <li className="list-inline-item-action"> {!node.comment.banned ? ( <span class="pointer" @@ -504,7 +565,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { </li> )} {!node.comment.banned && ( - <li className="list-inline-item"> + <li className="list-inline-item-action"> {!this.state.showConfirmAppointAsAdmin ? ( <span class="pointer" @@ -548,7 +609,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { )} {/* Site Creator can transfer to another admin */} {this.amSiteCreator && this.isAdmin && ( - <li className="list-inline-item"> + <li className="list-inline-item-action"> {!this.state.showConfirmTransferSite ? ( <span class="pointer" diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx index 67386469..1c875d04 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -208,6 +208,7 @@ export class Community extends Component<any, State> { SortType[this.state.sort] }`} target="_blank" + title="RSS" > <svg class="icon text-muted small"> <use xlinkHref="#icon-rss">#</use> diff --git a/ui/src/components/iframely-card.tsx b/ui/src/components/iframely-card.tsx index 4bae06d1..31929eaf 100644 --- a/ui/src/components/iframely-card.tsx +++ b/ui/src/components/iframely-card.tsx @@ -1,6 +1,7 @@ import { Component, linkEvent } from 'inferno'; import { FramelyData } from '../interfaces'; import { mdToHtml } from '../utils'; +import { i18n } from '../i18next'; interface FramelyCardProps { iframely: FramelyData; @@ -54,6 +55,7 @@ export class IFramelyCard extends Component< <span class="ml-2 pointer text-monospace" onClick={linkEvent(this, this.handleIframeExpand)} + data-tippy-content={i18n.t('expand_here')} > {this.state.expanded ? '[-]' : '[+]'} </span> diff --git a/ui/src/components/inbox.tsx b/ui/src/components/inbox.tsx index 56bf1578..0d07dca5 100644 --- a/ui/src/components/inbox.tsx +++ b/ui/src/components/inbox.tsx @@ -116,6 +116,7 @@ export class Inbox extends Component<any, InboxState> { <a href={`/feeds/inbox/${UserService.Instance.auth}.xml`} target="_blank" + title="RSS" > <svg class="icon mx-2 text-muted small"> <use xlinkHref="#icon-rss">#</use> diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx index 81612009..014d82d3 100644 --- a/ui/src/components/main.tsx +++ b/ui/src/components/main.tsx @@ -441,6 +441,7 @@ export class Main extends Component<any, MainState> { <a href={`/feeds/all.xml?sort=${SortType[this.state.sort]}`} target="_blank" + title="RSS" > <svg class="icon mx-1 text-muted small"> <use xlinkHref="#icon-rss">#</use> @@ -454,6 +455,7 @@ export class Main extends Component<any, MainState> { SortType[this.state.sort] }`} target="_blank" + title="RSS" > <svg class="icon mx-1 text-muted small"> <use xlinkHref="#icon-rss">#</use> diff --git a/ui/src/components/moment-time.tsx b/ui/src/components/moment-time.tsx index fd2a7efa..a256f785 100644 --- a/ui/src/components/moment-time.tsx +++ b/ui/src/components/moment-time.tsx @@ -1,6 +1,6 @@ import { Component } from 'inferno'; import moment from 'moment'; -import { getMomentLanguage } from '../utils'; +import { getMomentLanguage, setupTippy } from '../utils'; import { i18n } from '../i18next'; interface MomentTimeProps { @@ -20,16 +20,37 @@ export class MomentTime extends Component<MomentTimeProps, any> { moment.locale(lang); } + componentDidMount() { + setupTippy(); + } + render() { if (this.props.data.updated) { return ( - <span title={this.props.data.updated} className="font-italics"> + <span + data-tippy-content={this.format(this.props.data.updated)} + className="font-italics pointer unselectable" + > {i18n.t('modified')} {moment.utc(this.props.data.updated).fromNow()} </span> ); } else { let str = this.props.data.published || this.props.data.when_; - return <span title={str}>{moment.utc(str).fromNow()}</span>; + return ( + <span + className="pointer unselectable" + data-tippy-content={this.format(str)} + > + {moment.utc(str).fromNow()} + </span> + ); } } + + format(input: string): string { + return moment + .utc(input) + .local() + .format('LLLL'); + } } diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.tsx index 75cdd554..031c2ecb 100644 --- a/ui/src/components/navbar.tsx +++ b/ui/src/components/navbar.tsx @@ -26,6 +26,7 @@ import { fetchLimit, isCommentType, toast, + setupTippy, } from '../utils'; import { version } from '../version'; import { i18n } from '../i18next'; @@ -84,6 +85,10 @@ export class Navbar extends Component<any, NavbarState> { WebSocketService.Instance.getSite(); } + componentDidMount() { + setupTippy(); + } + render() { return this.navbar(); } @@ -105,6 +110,7 @@ export class Navbar extends Component<any, NavbarState> { type="button" aria-label="menu" onClick={linkEvent(this, this.expandNavbar)} + data-tippy-content={i18n.t('expand_here')} > <span class="navbar-toggler-icon"></span> </button> @@ -113,12 +119,16 @@ export class Navbar extends Component<any, NavbarState> { > <ul class="navbar-nav mr-auto"> <li class="nav-item"> - <Link class="nav-link" to="/communities"> + <Link + class="nav-link" + to="/communities" + title={i18n.t('communities')} + > {i18n.t('communities')} </Link> </li> <li class="nav-item"> - <Link class="nav-link" to="/search"> + <Link class="nav-link" to="/search" title={i18n.t('search')}> {i18n.t('search')} </Link> </li> @@ -129,12 +139,17 @@ export class Navbar extends Component<any, NavbarState> { pathname: '/create_post', state: { prevPath: this.currentLocation }, }} + title={i18n.t('create_post')} > {i18n.t('create_post')} </Link> </li> <li class="nav-item"> - <Link class="nav-link" to="/create_community"> + <Link + class="nav-link" + to="/create_community" + title={i18n.t('create_community')} + > {i18n.t('create_community')} </Link> </li> @@ -154,9 +169,9 @@ export class Navbar extends Component<any, NavbarState> { {this.state.isLoggedIn ? ( <> <li className="nav-item mt-1"> - <Link class="nav-link" to="/inbox"> + <Link class="nav-link" to="/inbox" title={i18n.t('inbox')}> <svg class="icon"> - <use xlinkHref="#icon-mail"></use> + <use xlinkHref="#icon-bell"></use> </svg> {this.state.unreadCount > 0 && ( <span class="ml-1 badge badge-light"> @@ -169,6 +184,7 @@ export class Navbar extends Component<any, NavbarState> { <Link class="nav-link" to={`/u/${UserService.Instance.user.username}`} + title={i18n.t('settings')} > <span> {UserService.Instance.user.avatar && showAvatars() && ( @@ -187,7 +203,11 @@ export class Navbar extends Component<any, NavbarState> { </li> </> ) : ( - <Link class="nav-link" to="/login"> + <Link + class="nav-link" + to="/login" + title={i18n.t('login_sign_up')} + > {i18n.t('login_sign_up')} </Link> )} diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index d502330b..ef25a546 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -32,6 +32,7 @@ import { toast, randomStr, setupTribute, + setupTippy, } from '../utils'; import autosize from 'autosize'; import Tribute from 'tributejs/src/Tribute.js'; @@ -142,6 +143,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> { this.setState(this.state); autosize.update(textarea); }); + setupTippy(); } componentWillUnmount() { @@ -179,9 +181,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> { <label htmlFor="file-upload" className={`${UserService.Instance.user && - 'pointer'} d-inline-block mr-2 float-right text-muted small font-weight-bold`} + 'pointer'} d-inline-block float-right text-muted h6 font-weight-bold`} + data-tippy-content={i18n.t('upload_image')} > - {i18n.t('upload_image')} + <svg class="icon icon-inline"> + <use xlinkHref="#icon-image"></use> + </svg> </label> <input id="file-upload" @@ -279,9 +284,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> { <a href={markdownHelpUrl} target="_blank" - class="d-inline-block float-right text-muted small font-weight-bold" + class="d-inline-block float-right text-muted h6 font-weight-bold" + title={i18n.t('formatting_help')} > - {i18n.t('formatting_help')} + <svg class="icon icon-inline"> + <use xlinkHref="#icon-help-circle"></use> + </svg> </a> </div> </div> diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index 732664e8..5f3fef09 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -30,6 +30,7 @@ import { pictshareAvatarThumbnail, showAvatars, imageThumbnailer, + setupTippy, } from '../utils'; import { i18n } from '../i18next'; @@ -101,6 +102,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> { } } + componentDidUpdate() { + setupTippy(); + } + componentWillReceiveProps(nextProps: PostListingProps) { this.state.my_vote = nextProps.post.my_vote; this.state.upvotes = nextProps.post.upvotes; @@ -185,7 +190,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { return ( <span class="text-body pointer" - title={i18n.t('expand_here')} + data-tippy-content={i18n.t('expand_here')} onClick={linkEvent(this, this.handleImageExpandClick)} > {this.imgThumb()} @@ -246,12 +251,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> { this.state.my_vote == 1 ? 'text-info' : 'text-muted' }`} onClick={linkEvent(this, this.handlePostLike)} + data-tippy-content={i18n.t('upvote')} > <svg class="icon upvote"> <use xlinkHref="#icon-arrow-up"></use> </svg> </button> - <div class={`font-weight-bold text-muted px-1`}> + <div class={`unselectable font-weight-bold text-muted px-1`}> {this.state.score} </div> {WebSocketService.Instance.site.enable_downvotes && ( @@ -260,6 +266,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { this.state.my_vote == -1 ? 'text-danger' : 'text-muted' }`} onClick={linkEvent(this, this.handlePostDisLike)} + data-tippy-content={i18n.t('downvote')} > <svg class="icon downvote"> <use xlinkHref="#icon-arrow-down"></use> @@ -333,8 +340,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> { <> {!this.state.imageExpanded ? ( <span - |