const post = this.postView.post;
return (
- <div className="post-listing">
+ <div className="post-listing mt-2">
{!this.state.showEdit ? (
<>
{this.listing()}
createdLine() {
const post_view = this.postView;
- const url = post_view.post.url;
- const body = post_view.post.body;
return (
- <ul className="list-inline mb-1 text-muted small">
+ <ul className="list-inline mb-1 text-muted small mt-2">
<li className="list-inline-item">
<PersonListing person={post_view.creator} />
</span>
)}
{this.props.showCommunity && (
- <span>
- <span className="mx-1"> {i18n.t("to")} </span>
- <CommunityLink community={post_view.community} />
- </span>
+ <>
+ {" "}
+ {i18n.t("to")} <CommunityLink community={post_view.community} />
+ </>
)}
</li>
{post_view.post.language_id !== 0 && (
</span>
)}
<li className="list-inline-item">•</li>
- {url && !(hostname(url) === getExternalHost()) && (
- <>
- <li className="list-inline-item">
- <a
- className="text-muted font-italic"
- href={url}
- title={url}
- rel={relTags}
- >
- {hostname(url)}
- </a>
- </li>
- <li className="list-inline-item">•</li>
- </>
- )}
<li className="list-inline-item">
<span>
<MomentTime
/>
</span>
</li>
- {body && (
- <>
- <li className="list-inline-item">•</li>
- <li className="list-inline-item">
- <button
- className="text-muted btn btn-sm btn-link p-0"
- data-tippy-content={mdNoImages.render(body)}
- data-tippy-allowHtml={true}
- onClick={linkEvent(this, this.handleShowBody)}
- >
- <Icon icon="book-open" classes="icon-inline mr-1" />
- </button>
- </li>
- </>
- )}
</ul>
);
}
const post = this.postView.post;
return (
<Link
- className={`d-inline-block ${
+ className={`d-inline ${
!post.featured_community && !post.featured_local
? "text-body"
: "text-primary"
to={`/post/${post.id}`}
title={i18n.t("comments")}
>
- <div
- className="d-inline-block"
+ <span
+ className="d-inline"
dangerouslySetInnerHTML={mdToHtmlInline(post.name)}
/>
</Link>
const url = post.url;
return (
- <div className="post-title overflow-hidden">
- <h5>
- {url ? (
- this.props.showBody ? (
+ <>
+ <div className="post-title overflow-hidden">
+ <h5 className="d-inline">
+ {url && this.props.showBody ? (
<a
- className={`d-inline-block ${
+ className={
!post.featured_community && !post.featured_local
? "text-body"
: "text-primary"
- }`}
+ }
href={url}
title={url}
rel={relTags}
- >
- <div
- className="d-inline-block"
- dangerouslySetInnerHTML={mdToHtmlInline(post.name)}
- />
- </a>
+ dangerouslySetInnerHTML={mdToHtmlInline(post.name)}
+ ></a>
) : (
this.postLink
- )
- ) : (
- this.postLink
- )}
+ )}
+ </h5>
{(url && isImage(url)) ||
(post.thumbnail_url && (
<button
</button>
))}
{post.removed && (
- <small className="ml-2 text-muted font-italic">
+ <small className="ml-2 badge text-bg-secondary">
{i18n.t("removed")}
</small>
)}
{post.featured_community && (
<small
className="unselectable pointer ml-2 text-muted font-italic"
- data-tippy-content={i18n.t("featured")}
+ data-tippy-content={i18n.t("featured_in_community")}
+ aria-label={i18n.t("featured_in_community")}
>
<Icon icon="pin" classes="icon-inline text-primary" />
</small>
{post.featured_local && (
<small
className="unselectable pointer ml-2 text-muted font-italic"
- data-tippy-content={i18n.t("featured")}
+ data-tippy-content={i18n.t("featured_in_local")}
+ aria-label={i18n.t("featured_in_local")}
>
<Icon icon="pin" classes="icon-inline text-secondary" />
</small>
)}
{post.nsfw && (
- <small className="ml-2 text-muted font-italic">
+ <small className="ml-2 badge text-bg-danger">
{i18n.t("nsfw")}
</small>
)}
- </h5>
- </div>
+ </div>
+ {url && this.urlLine()}
+ </>
+ );
+ }
+
+ urlLine() {
+ const post = this.postView.post;
+ const url = post.url;
+
+ return (
+ <p className="d-flex text-muted align-items-center gap-1 small m-0">
+ {url && !(hostname(url) === getExternalHost()) && (
+ <a
+ className="text-muted font-italic"
+ href={url}
+ title={url}
+ rel={relTags}
+ >
+ {hostname(url)}
+ </a>
+ )}
+ </p>
);
}
const post = this.postView.post;
return (
- <div className="d-flex align-items-center justify-content-start flex-wrap text-muted font-weight-bold mb-1">
+ <div className="d-flex align-items-center justify-content-start flex-wrap text-muted font-weight-bold">
{this.commentsButton}
{canShare() && (
<button
- className="btn btn-link"
+ className="btn btn-sm btn-link"
onClick={linkEvent(this, this.handleShare)}
type="button"
>
{mobile && !this.props.viewOnly && this.mobileVotes}
{UserService.Instance.myUserInfo &&
!this.props.viewOnly &&
- this.postActions(mobile)}
+ this.postActions()}
</div>
);
}
- get hasAdvancedButtons() {
+ showPreviewButton() {
+ const post_view = this.postView;
+ const body = post_view.post.body;
+
return (
- this.myPost ||
- (this.showBody && this.postView.post.body) ||
- amMod(this.props.moderators) ||
- amAdmin() ||
- this.canMod_ ||
- this.canAdmin_
+ <button
+ className="btn btn-link btn-animate text-muted py-0"
+ data-tippy-content={body && mdNoImages.render(body)}
+ data-tippy-allowHtml={true}
+ onClick={linkEvent(this, this.handleShowBody)}
+ >
+ <Icon
+ icon="book-open"
+ classes={classNames("icon-inline mr-1", {
+ "text-success": this.state.showBody,
+ })}
+ />
+ </button>
);
}
- postActions(mobile = false) {
+ postActions() {
// Possible enhancement: Priority+ pattern instead of just hard coding which get hidden behind the show more button.
// Possible enhancement: Make each button a component.
const post_view = this.postView;
+ const post = post_view.post;
+
return (
<>
{this.saveButton}
{this.crossPostButton}
+ {/**
+ * If there is a URL, or if the post has a body and we were told not to
+ * show the body, show the MetadataCard/body toggle.
+ */}
+ {(post.url || (post.body && !this.props.showBody)) &&
+ this.showPreviewButton()}
+
{this.showBody && post_view.post.body && this.viewSourceButton}
- {this.hasAdvancedButtons && (
- <div className="dropdown">
- <button
- className="btn btn-link btn-animate text-muted py-0 dropdown-toggle"
- onClick={linkEvent(this, this.handleShowAdvanced)}
- data-tippy-content={i18n.t("more")}
- data-bs-toggle="dropdown"
- aria-expanded="false"
- aria-label={i18n.t("more")}
- >
- <Icon icon="more-vertical" inline />
- </button>
+ <div className="dropdown">
+ <button
+ className="btn btn-link btn-animate text-muted py-0 dropdown-toggle"
+ onClick={linkEvent(this, this.handleShowAdvanced)}
+ data-tippy-content={i18n.t("more")}
+ data-bs-toggle="dropdown"
+ aria-expanded="false"
+ aria-controls="advancedButtonsDropdown"
+ aria-label={i18n.t("more")}
+ >
+ <Icon icon="more-vertical" inline />
+ </button>
- <ul className="dropdown-menu">
- {!this.myPost ? (
- <>
- <li>{this.reportButton}</li>
- <li>{this.blockButton}</li>
- </>
- ) : (
- <>
- <li>{this.editButton}</li>
- <li>{this.deleteButton}</li>
- </>
- )}
+ <ul className="dropdown-menu" id="advancedButtonsDropdown">
+ {!this.myPost ? (
+ <>
+ <li>{this.reportButton}</li>
+ <li>{this.blockButton}</li>
+ </>
+ ) : (
+ <>
+ <li>{this.editButton}</li>
+ <li>{this.deleteButton}</li>
+ </>
+ )}
- {/* Any mod can do these, not limited to hierarchy*/}
- {(amMod(this.props.moderators) || amAdmin()) && (
- <>
- <li>
- <hr className="dropdown-divider" />
- </li>
- <li>{this.lockButton}</li>
- {this.featureButtons}
- </>
- )}
+ {/* Any mod can do these, not limited to hierarchy*/}
+ {(amMod(this.props.moderators) || amAdmin()) && (
+ <>
+ <li>
+ <hr className="dropdown-divider" />
+ </li>
+ <li>{this.lockButton}</li>
+ {this.featureButtons}
+ </>
+ )}
- {(this.canMod_ || this.canAdmin_) && (
- <li>{this.modRemoveButton}</li>
- )}
- </ul>
- </div>
- )}
+ {(this.canMod_ || this.canAdmin_) && (
+ <li>{this.modRemoveButton}</li>
+ )}
+ </ul>
+ </div>
</>
);
}
const post_view = this.postView;
return (
<Link
- className="btn btn-link text-muted py-0 pl-0 text-muted"
+ className="btn btn-link text-muted pl-0 text-muted"
title={i18n.t("number_of_comments", {
count: Number(post_view.counts.comments),
formattedCount: Number(post_view.counts.comments),
get reportButton() {
return (
<button
- className="btn btn-link btn-animate text-muted py-0 dropdown-item"
+ className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
onClick={linkEvent(this, this.handleShowReportDialog)}
- data-tippy-content={i18n.t("show_report_dialog")}
aria-label={i18n.t("show_report_dialog")}
>
- <Icon icon="flag" inline />
+ <Icon classes="mr-1" icon="flag" inline />
+ {i18n.t("create_report")}
</button>
);
}
get blockButton() {
return (
<button
- className="btn btn-link btn-animate text-muted py-0 dropdown-item"
+ className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
onClick={linkEvent(this, this.handleBlockPersonClick)}
- data-tippy-content={i18n.t("block_user")}
aria-label={i18n.t("block_user")}
>
- {this.state.blockLoading ? <Spinner /> : <Icon icon="slash" inline />}
+ {this.state.blockLoading ? (
+ <Spinner />
+ ) : (
+ <Icon classes="mr-1" icon="slash" inline />
+ )}
+ {i18n.t("block_user")}
</button>
);
}
get editButton() {
return (
<button
- className="btn btn-link text-muted dropdown-item"
+ className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
onClick={linkEvent(this, this.handleEditClick)}
- data-tippy-content={i18n.t("edit")}
aria-label={i18n.t("edit")}
>
<Icon classes="mr-1" icon="edit" inline />
const label = !deleted ? i18n.t("delete") : i18n.t("restore");
return (
<button
- className="btn btn-link text-muted dropdown-item"
+ className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
onClick={linkEvent(this, this.handleDeleteClick)}
- data-tippy-content={label}
aria-label={label}
>
{this.state.deleteLoading ? (
classes={classNames("mr-1", { "text-danger": deleted })}
inline
/>
- {i18n.t("delete")}
+ {label}
</>
)}
</button>
const label = locked ? i18n.t("unlock") : i18n.t("lock");
return (
<button
- className="btn btn-link text-muted dropdown-item"
+ className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
onClick={linkEvent(this, this.handleModLock)}
- data-tippy-content={label}
aria-label={label}
>
{this.state.lockLoading ? (
classes={classNames("mr-1", { "text-danger": locked })}
inline
/>
- {i18n.t("lock")}
+ {label}
</>
)}
</button>
<>
<li>
<button
- className="btn btn-link text-muted dropdown-item"
+ className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
onClick={linkEvent(this, this.handleModFeaturePostCommunity)}
data-tippy-content={labelCommunity}
aria-label={labelCommunity}
<li>
{amAdmin() && (
<button
- className="btn btn-link text-muted dropdown-item"
+ className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
onClick={linkEvent(this, this.handleModFeaturePostLocal)}
data-tippy-content={labelLocal}
aria-label={labelLocal}
const removed = this.postView.post.removed;
return (
<button
- className="btn btn-link text-muted dropdown-item"
+ className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
onClick={linkEvent(
this,
!removed ? this.handleModRemoveShow : this.handleModRemoveSubmit