forked from nutomic/lemmy
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:
parent
6365439c16
commit
5623f11b05
3 changed files with 558 additions and 473 deletions
19
ui/assets/css/main.css
vendored
19
ui/assets/css/main.css
vendored
|
@ -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;
|
||||
|
|
198
ui/src/components/post-listing.tsx
vendored
198
ui/src/components/post-listing.tsx
vendored
|
@ -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>
|
||||
);
|
||||
|
|
4
ui/src/components/symbols.tsx
vendored
4
ui/src/components/symbols.tsx
vendored
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue