Refactoring thumbnails. Fixes #564

- Adding a default discussion thumbnail
- Adding a cropping max-height, and consistent width.
- Getting rid of hover overlays, in favor of top right content-type icon.
pull/744/head
Dessalines 2020-02-29 13:03:41 -05:00
parent a215076358
commit 434bf35a55
3 changed files with 558 additions and 473 deletions

View File

@ -131,8 +131,13 @@ blockquote {
}
.thumbnail {
max-height: 62px;
max-width: 400px;
object-fit: cover;
max-height: 80px;
width: 100%;
}
svg.thumbnail {
height: 40px;
}
.no-s-hows {
@ -188,6 +193,16 @@ hr {
border: unset;
}
.mini-overlay {
position: absolute;
top: 0;
right: 0;
padding: 2px;
background: rgba(0,0,0,.4);
border-bottom-left-radius: 0.25rem !important;
border-top-right-radius: 0.25rem !important;
}
.link-overlay:hover {
transition: .1s;
opacity: 1;

View File

@ -121,9 +121,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
render() {
return (
<div class="row">
<div class="">
{!this.state.showEdit ? (
this.listing()
<>
{this.listing()}
{this.body()}
</>
) : (
<div class="col-12">
<PostForm
@ -137,23 +140,105 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
);
}
imgThumbnail() {
body() {
return (
<div class="row">
<div class="col-12">
{this.state.url && this.props.showBody && this.state.iframely && (
<IFramelyCard iframely={this.state.iframely} />
)}
{this.props.showBody && this.props.post.body && (
<>
{this.state.viewSource ? (
<pre>{this.props.post.body}</pre>
) : (
<div
className="md-div"
dangerouslySetInnerHTML={mdToHtml(this.props.post.body)}
/>
)}
</>
)}
</div>
</div>
);
}
imgThumb() {
let post = this.props.post;
return (
<object
<img
className={`img-fluid thumbnail rounded ${(post.nsfw ||
post.community_nsfw) &&
'img-blur'}`}
data={imageThumbnailer(this.state.thumbnail)}
></object>
src={imageThumbnailer(this.state.thumbnail)}
/>
);
}
thumbnail() {
let post = this.props.post;
if (isImage(this.state.url)) {
return (
<span
class="text-body pointer"
title={i18n.t('expand_here')}
onClick={linkEvent(this, this.handleImageExpandClick)}
>
{this.imgThumb()}
<svg class="icon mini-overlay">
<use xlinkHref="#icon-image"></use>
</svg>
</span>
);
} else if (this.state.thumbnail) {
return (
<a
className="text-body"
href={this.state.url}
target="_blank"
title={this.state.url}
>
{this.imgThumb()}
<svg class="icon mini-overlay">
<use xlinkHref="#icon-external-link"></use>
</svg>
</a>
);
} else if (this.state.url && !this.state.thumbnail) {
return (
<a
className="text-body"
href={this.state.url}
target="_blank"
title={this.state.url}
>
<svg class="icon thumbnail">
<use xlinkHref="#icon-external-link"></use>
</svg>
</a>
);
} else {
return (
<Link
className="text-body"
to={`/post/${post.id}`}
title={i18n.t('comments')}
>
<svg class="icon thumbnail">
<use xlinkHref="#icon-bubble2"></use>
</svg>
</Link>
);
}
}
listing() {
let post = this.props.post;
return (
<div class="listing col-12">
<div className={`vote-bar mr-2 float-left small text-center`}>
<div class="row">
<div className={`vote-bar col-1 pr-0 small text-center`}>
<button
className={`vote-animate btn btn-link p-0 ${
this.state.my_vote == 1 ? 'text-info' : 'text-muted'
@ -178,32 +263,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</button>
)}
</div>
{this.state.thumbnail && !this.state.imageExpanded && (
<div class="mx-2 mt-1 float-left position-relative">
{isImage(this.state.url) ? (
<span
class="text-body pointer"
title={i18n.t('expand_here')}
onClick={linkEvent(this, this.handleImageExpandClick)}
>
{this.imgThumbnail()}
<svg class="icon thumbnail rounded link-overlay hover-link">
<use xlinkHref="#icon-image"></use>
</svg>
</span>
) : (
<a
className="text-body"
href={this.state.url}
target="_blank"
title={this.state.url}
>
{this.imgThumbnail()}
<svg class="icon thumbnail rounded link-overlay hover-link">
<use xlinkHref="#icon-external-link"></use>
</svg>
</a>
)}
{!this.state.imageExpanded && (
<div class="col-2 pr-0 mt-1">
<div class="position-relative">{this.thumbnail()}</div>
</div>
)}
{this.state.url && isVideo(this.state.url) && (
@ -212,14 +274,16 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
muted
loop
controls
class="mx-2 mt-1 float-left"
class="col-2 pr-0 mt-1"
height="100"
width="150"
>
<source src={this.state.url} type="video/mp4" />
</video>
)}
<div className="ml-4">
<div class="col-9">
<div class="row">
<div className="col-12">
<div className="post-title">
<h5 className="mb-0 d-inline">
{this.props.showBody && this.state.url ? (
@ -280,16 +344,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<div>
<span
class="pointer"
onClick={linkEvent(this, this.handleImageExpandClick)}
onClick={linkEvent(
this,
this.handleImageExpandClick
)}
>
<object
<img
class="img-fluid img-expanded"
data={this.state.thumbnail}
>
<svg class="icon thumbnail rounded placeholder">
<use xlinkHref="#icon-external-link"></use>
</svg>
</object>
src={this.state.thumbnail}
/>
</span>
</div>
</span>
@ -323,7 +386,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
)}
</div>
</div>
<div className="details ml-4">
</div>
<div class="row">
<div className="details col-12">
<ul class="list-inline mb-0 text-muted small">
<li className="list-inline-item">
<span>{i18n.t('by')} </span>
@ -339,7 +404,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<span>{post.creator_name}</span>
</Link>
{this.isMod && (
<span className="mx-1 badge badge-light">{i18n.t('mod')}</span>
<span className="mx-1 badge badge-light">
{i18n.t('mod')}
</span>
)}
{this.isAdmin && (
<span className="mx-1 badge badge-light">
@ -389,7 +456,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</li>
{this.props.post.duplicates.map(post => (
<li className="list-inline-item mr-2">
<Link to={`/post/${post.id}`}>{post.community_name}</Link>
<Link to={`/post/${post.id}`}>
{post.community_name}
</Link>
</li>
))}
</>
@ -433,7 +502,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
class="pointer"
onClick={linkEvent(this, this.handleDeleteClick)}
>
{!post.deleted ? i18n.t('delete') : i18n.t('restore')}
{!post.deleted
? i18n.t('delete')
: i18n.t('restore')}
</span>
</li>
</>
@ -453,7 +524,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
class="pointer"
onClick={linkEvent(this, this.handleModSticky)}
>
{post.stickied ? i18n.t('unsticky') : i18n.t('sticky')}
{post.stickied
? i18n.t('unsticky')
: i18n.t('sticky')}
</span>
</li>
</>
@ -471,7 +544,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
) : (
<span
class="pointer"
onClick={linkEvent(this, this.handleModRemoveSubmit)}
onClick={linkEvent(
this,
this.handleModRemoveSubmit
)}
>
{i18n.t('restore')}
</span>
@ -577,7 +653,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
) : (
<span
class="pointer"
onClick={linkEvent(this, this.handleModBanSubmit)}
onClick={linkEvent(
this,
this.handleModBanSubmit
)}
>
{i18n.t('unban_from_site')}
</span>
@ -648,9 +727,6 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</li>
)}
</ul>
{this.state.url && this.props.showBody && this.state.iframely && (
<IFramelyCard iframely={this.state.iframely} />
)}
{this.state.showRemoveDialog && (
<form
class="form-inline"
@ -695,18 +771,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</div>
</form>
)}
{this.props.showBody && post.body && (
<>
{this.state.viewSource ? (
<pre>{post.body}</pre>
) : (
<div
className="md-div"
dangerouslySetInnerHTML={mdToHtml(post.body)}
/>
)}
</>
)}
</div>
</div>
</div>
</div>
);

View File

@ -15,6 +15,10 @@ export class Symbols extends Component<any, any> {
xmlnsXlink="http://www.w3.org/1999/xlink"
>
<defs>
<symbol id="icon-bubble2" viewBox="0 0 32 32">
<title>bubble2</title>
<path d="M16 6c-1.717 0-3.375 0.271-4.928 0.804-1.46 0.502-2.76 1.211-3.863 2.108-2.069 1.681-3.209 3.843-3.209 6.088 0 1.259 0.35 2.481 1.039 3.63 0.711 1.185 1.781 2.268 3.093 3.133 0.949 0.625 1.587 1.623 1.755 2.747 0.056 0.375 0.091 0.753 0.105 1.129 0.233-0.194 0.461-0.401 0.684-0.624 0.755-0.755 1.774-1.172 2.828-1.172 0.168 0 0.336 0.011 0.505 0.032 0.655 0.083 1.325 0.126 1.99 0.126 1.717 0 3.375-0.271 4.928-0.804 1.46-0.502 2.76-1.211 3.863-2.108 2.069-1.681 3.209-3.843 3.209-6.088s-1.14-4.407-3.209-6.088c-1.104-0.897-2.404-1.606-3.863-2.108-1.553-0.534-3.211-0.804-4.928-0.804zM16 2v0c8.837 0 16 5.82 16 13s-7.163 13-16 13c-0.849 0-1.682-0.054-2.495-0.158-3.437 3.437-7.539 4.053-11.505 4.144v-0.841c2.142-1.049 4-2.961 4-5.145 0-0.305-0.024-0.604-0.068-0.897-3.619-2.383-5.932-6.024-5.932-10.103 0-7.18 7.163-13 16-13z"></path>
</symbol>
<symbol id="icon-image" viewBox="0 0 32 32">
<title>image</title>
<path d="M29.996 4c0.001 0.001 0.003 0.002 0.004 0.004v23.993c-0.001 0.001-0.002 0.003-0.004 0.004h-27.993c-0.001-0.001-0.003-0.002-0.004-0.004v-23.993c0.001-0.001 0.002-0.003 0.004-0.004h27.993zM30 2h-28c-1.1 0-2 0.9-2 2v24c0 1.1 0.9 2 2 2h28c1.1 0 2-0.9 2-2v-24c0-1.1-0.9-2-2-2v0z"></path>