summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDessalines <tyhou13@gmx.com>2020-03-03 02:29:45 -0500
committerDessalines <tyhou13@gmx.com>2020-03-03 02:29:45 -0500
commit44bbc459736ac53b9150903af14c20a497caf9ab (patch)
tree0bf8899cfc448e7b70230de52cec9119aa43f011
parent5f6f51b549d42943b85d8f7dc9d193aec0935ab6 (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.css26
-rw-r--r--ui/assets/css/tippy.css1
-rw-r--r--ui/package.json1
-rw-r--r--ui/src/components/comment-form.tsx14
-rw-r--r--ui/src/components/comment-node.tsx141
-rw-r--r--ui/src/components/community.tsx1
-rw-r--r--ui/src/components/iframely-card.tsx2
-rw-r--r--ui/src/components/inbox.tsx1
-rw-r--r--ui/src/components/main.tsx2
-rw-r--r--ui/src/components/moment-time.tsx27
-rw-r--r--ui/src/components/navbar.tsx32
-rw-r--r--ui/src/components/post-form.tsx16
-rw-r--r--ui/src/components/post-listing.tsx133
-rw-r--r--ui/src/components/symbols.tsx57
-rw-r--r--ui/src/components/user.tsx1
-rw-r--r--ui/src/index.html1
-rw-r--r--ui/src/utils.ts12
-rw-r--r--ui/translations/en.json2
-rw-r--r--ui/yarn.lock12
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
-