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.
This commit is contained in:
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 { .thumbnail {
max-height: 62px; object-fit: cover;
max-width: 400px; max-height: 80px;
width: 100%;
}
svg.thumbnail {
height: 40px;
} }
.no-s-hows { .no-s-hows {
@ -188,6 +193,16 @@ hr {
border: unset; 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 { .link-overlay:hover {
transition: .1s; transition: .1s;
opacity: 1; opacity: 1;

View file

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