mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-22 12:21:13 +00:00
Merge pull request #59 from LemmyNet/pictrs_v2
Making front end work w/ pictrs v2. Fixes #57
This commit is contained in:
commit
80f1a7d4ba
8 changed files with 95 additions and 92 deletions
|
@ -297,6 +297,10 @@ br.big {
|
|||
margin-top: -60px;
|
||||
}
|
||||
|
||||
.img-icon {
|
||||
width: 2rem; height: 2rem;
|
||||
}
|
||||
|
||||
.tribute-container ul {
|
||||
margin: 0;
|
||||
margin-top: 2px;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Component } from 'inferno';
|
||||
import { PictrsImage } from './pictrs-image';
|
||||
|
||||
interface BannerIconHeaderProps {
|
||||
banner?: string;
|
||||
|
@ -13,15 +14,12 @@ export class BannerIconHeader extends Component<BannerIconHeaderProps, any> {
|
|||
render() {
|
||||
return (
|
||||
<div class="position-relative mb-2">
|
||||
{this.props.banner && (
|
||||
<img src={this.props.banner} class="banner img-fluid" />
|
||||
)}
|
||||
{this.props.banner && <PictrsImage src={this.props.banner} />}
|
||||
{this.props.icon && (
|
||||
<img
|
||||
<PictrsImage
|
||||
src={this.props.icon}
|
||||
className={`ml-2 mb-0 ${
|
||||
this.props.banner ? 'avatar-pushup' : ''
|
||||
} rounded-circle avatar-overlay`}
|
||||
iconOverlay
|
||||
pushup={!!this.props.banner}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { Component } from 'inferno';
|
||||
import { Link } from 'inferno-router';
|
||||
import { Community } from 'lemmy-js-client';
|
||||
import { hostname, pictrsAvatarThumbnail, showAvatars } from '../utils';
|
||||
import { hostname, showAvatars } from '../utils';
|
||||
import { PictrsImage } from './pictrs-image';
|
||||
|
||||
interface CommunityOther {
|
||||
name: string;
|
||||
|
@ -47,11 +48,7 @@ export class CommunityLink extends Component<CommunityLinkProps, any> {
|
|||
to={link}
|
||||
>
|
||||
{!this.props.hideAvatar && community.icon && showAvatars() && (
|
||||
<img
|
||||
style="width: 2rem; height: 2rem;"
|
||||
src={pictrsAvatarThumbnail(community.icon)}
|
||||
class="rounded-circle mr-2"
|
||||
/>
|
||||
<PictrsImage src={community.icon} icon />
|
||||
)}
|
||||
<span>{displayName}</span>
|
||||
</Link>
|
||||
|
|
|
@ -20,7 +20,6 @@ import {
|
|||
} from 'lemmy-js-client';
|
||||
import {
|
||||
wsJsonToRes,
|
||||
pictrsAvatarThumbnail,
|
||||
showAvatars,
|
||||
fetchLimit,
|
||||
toast,
|
||||
|
@ -32,6 +31,7 @@ import {
|
|||
wsSubscribe,
|
||||
} from '../utils';
|
||||
import { i18n } from '../i18next';
|
||||
import { PictrsImage } from './pictrs-image';
|
||||
|
||||
interface NavbarProps {
|
||||
site: GetSiteResponse;
|
||||
|
@ -190,12 +190,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
to="/"
|
||||
>
|
||||
{this.props.site.site.icon && showAvatars() && (
|
||||
<img
|
||||
src={pictrsAvatarThumbnail(this.props.site.site.icon)}
|
||||
height="32"
|
||||
width="32"
|
||||
class="rounded-circle mr-2"
|
||||
/>
|
||||
<PictrsImage src={this.props.site.site.icon} icon />
|
||||
)}
|
||||
{this.props.site.site.name}
|
||||
</Link>
|
||||
|
@ -345,12 +340,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
>
|
||||
<span>
|
||||
{user.avatar && showAvatars() && (
|
||||
<img
|
||||
src={pictrsAvatarThumbnail(user.avatar)}
|
||||
height="32"
|
||||
width="32"
|
||||
class="rounded-circle mr-2"
|
||||
/>
|
||||
<PictrsImage src={user.avatar} icon />
|
||||
)}
|
||||
{user.preferred_username
|
||||
? user.preferred_username
|
||||
|
|
66
src/shared/components/pictrs-image.tsx
Normal file
66
src/shared/components/pictrs-image.tsx
Normal file
|
@ -0,0 +1,66 @@
|
|||
import { Component } from 'inferno';
|
||||
|
||||
const iconThumbnailSize = 96;
|
||||
const thumbnailSize = 256;
|
||||
|
||||
interface PictrsImageProps {
|
||||
src: string;
|
||||
icon?: boolean;
|
||||
thumbnail?: boolean;
|
||||
nsfw?: boolean;
|
||||
iconOverlay?: boolean;
|
||||
pushup?: boolean;
|
||||
}
|
||||
|
||||
export class PictrsImage extends Component<PictrsImageProps, any> {
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<picture>
|
||||
<source srcSet={this.src('webp')} type="image/webp" />
|
||||
<source srcSet={this.src('jpg')} type="image/jpeg" />
|
||||
<img
|
||||
src={this.src('jpg')}
|
||||
className={`img-fluid
|
||||
${this.props.thumbnail ? 'thumbnail rounded ' : 'img-expanded '}
|
||||
${this.props.thumbnail && this.props.nsfw && 'img-blur '}
|
||||
${this.props.icon && 'rounded-circle img-icon mr-2 '}
|
||||
${this.props.iconOverlay && 'ml-2 mb-0 rounded-circle avatar-overlay '}
|
||||
${this.props.pushup && 'avatar-pushup '}
|
||||
`}
|
||||
/>
|
||||
</picture>
|
||||
);
|
||||
}
|
||||
|
||||
src(format: string): string {
|
||||
// sample url:
|
||||
// http://localhost:8535/pictrs/image/file.png?thumbnail=256&format=jpg
|
||||
|
||||
let split = this.props.src.split('/pictrs/image/');
|
||||
|
||||
// If theres not multiple, then its not a pictrs image
|
||||
if (split.length == 1) {
|
||||
return this.props.src;
|
||||
}
|
||||
|
||||
let host = split[0];
|
||||
let path = split[1];
|
||||
|
||||
let params = { format };
|
||||
|
||||
if (this.props.thumbnail) {
|
||||
params['thumbnail'] = thumbnailSize;
|
||||
} else if (this.props.icon) {
|
||||
params['thumbnail'] = iconThumbnailSize;
|
||||
}
|
||||
|
||||
let paramsStr = `?${new URLSearchParams(params).toString()}`;
|
||||
let out = `${host}/pictrs/image/${path}${paramsStr}`;
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ import { PostForm } from './post-form';
|
|||
import { IFramelyCard } from './iframely-card';
|
||||
import { UserListing } from './user-listing';
|
||||
import { CommunityLink } from './community-link';
|
||||
import { PictrsImage } from './pictrs-image';
|
||||
import {
|
||||
md,
|
||||
mdToHtml,
|
||||
|
@ -32,7 +33,6 @@ import {
|
|||
isImage,
|
||||
isVideo,
|
||||
getUnixTime,
|
||||
pictrsImage,
|
||||
setupTippy,
|
||||
hostname,
|
||||
previewLines,
|
||||
|
@ -164,27 +164,26 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
imgThumb(src: string) {
|
||||
let post = this.props.post;
|
||||
return (
|
||||
<img
|
||||
className={`img-fluid thumbnail rounded ${
|
||||
post.nsfw || post.community_nsfw ? 'img-blur' : ''
|
||||
}`}
|
||||
<PictrsImage
|
||||
src={src}
|
||||
thumbnail
|
||||
nsfw={post.nsfw || post.community_nsfw}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
getImage(thumbnail: boolean = false) {
|
||||
getImageSrc(): string {
|
||||
let post = this.props.post;
|
||||
if (isImage(post.url)) {
|
||||
if (post.url.includes('pictrs')) {
|
||||
return pictrsImage(post.url, thumbnail);
|
||||
return post.url;
|
||||
} else if (post.thumbnail_url) {
|
||||
return pictrsImage(post.thumbnail_url, thumbnail);
|
||||
return post.thumbnail_url;
|
||||
} else {
|
||||
return post.url;
|
||||
}
|
||||
} else if (post.thumbnail_url) {
|
||||
return pictrsImage(post.thumbnail_url, thumbnail);
|
||||
return post.thumbnail_url;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -200,7 +199,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
data-tippy-content={i18n.t('expand_here')}
|
||||
onClick={linkEvent(this, this.handleImageExpandClick)}
|
||||
>
|
||||
{this.imgThumb(this.getImage(true))}
|
||||
{this.imgThumb(this.getImageSrc())}
|
||||
<svg class="icon mini-overlay">
|
||||
<use xlinkHref="#icon-image"></use>
|
||||
</svg>
|
||||
|
@ -215,7 +214,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
rel="noopener"
|
||||
title={post.url}
|
||||
>
|
||||
{this.imgThumb(this.getImage(true))}
|
||||
{this.imgThumb(this.getImageSrc())}
|
||||
<svg class="icon mini-overlay">
|
||||
<use xlinkHref="#icon-external-link"></use>
|
||||
</svg>
|
||||
|
@ -442,7 +441,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
class="pointer"
|
||||
onClick={linkEvent(this, this.handleImageExpandClick)}
|
||||
>
|
||||
<img class="img-fluid img-expanded" src={this.getImage()} />
|
||||
<PictrsImage src={this.getImageSrc()} />
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
import { Component } from 'inferno';
|
||||
import { Link } from 'inferno-router';
|
||||
import { UserView } from 'lemmy-js-client';
|
||||
import {
|
||||
pictrsAvatarThumbnail,
|
||||
showAvatars,
|
||||
hostname,
|
||||
isCakeDay,
|
||||
} from '../utils';
|
||||
import { showAvatars, hostname, isCakeDay } from '../utils';
|
||||
import { CakeDay } from './cake-day';
|
||||
import { PictrsImage } from './pictrs-image';
|
||||
|
||||
export interface UserOther {
|
||||
name: string;
|
||||
|
@ -59,11 +55,7 @@ export class UserListing extends Component<UserListingProps, any> {
|
|||
to={link}
|
||||
>
|
||||
{!this.props.hideAvatar && user.avatar && showAvatars() && (
|
||||
<img
|
||||
style="width: 2rem; height: 2rem;"
|
||||
src={pictrsAvatarThumbnail(user.avatar)}
|
||||
class="rounded-circle mr-2"
|
||||
/>
|
||||
<PictrsImage src={user.avatar} icon />
|
||||
)}
|
||||
<span>{displayName}</span>
|
||||
</Link>
|
||||
|
|
|
@ -491,15 +491,6 @@ export function objectFlip(obj: any) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
export function pictrsAvatarThumbnail(src: string): string {
|
||||
// sample url: http://localhost:8535/pictrs/image/thumbnail256/gs7xuu.jpg
|
||||
let split = src.split('/pictrs/image');
|
||||
let out = `${split[0]}/pictrs/image/${
|
||||
canUseWebP() ? 'webp/' : ''
|
||||
}thumbnail96${split[1]}`;
|
||||
return out;
|
||||
}
|
||||
|
||||
export function showAvatars(): boolean {
|
||||
return (
|
||||
(UserService.Instance.user && UserService.Instance.user.show_avatars) ||
|
||||
|
@ -520,23 +511,6 @@ export function isCakeDay(published: string): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
// Converts to image thumbnail
|
||||
export function pictrsImage(hash: string, thumbnail: boolean = false): string {
|
||||
let root = `/pictrs/image`;
|
||||
|
||||
// Necessary for other servers / domains
|
||||
if (hash.includes('pictrs')) {
|
||||
let split = hash.split('/pictrs/image/');
|
||||
root = `${split[0]}/pictrs/image`;
|
||||
hash = split[1];
|
||||
}
|
||||
|
||||
let out = `${root}/${canUseWebP() ? 'webp/' : ''}${
|
||||
thumbnail ? 'thumbnail256/' : ''
|
||||
}${hash}`;
|
||||
return out;
|
||||
}
|
||||
|
||||
export function isCommentType(
|
||||
item: Comment | PrivateMessage | Post
|
||||
): item is Comment {
|
||||
|
@ -1090,23 +1064,6 @@ export function hostname(url: string): string {
|
|||
return cUrl.port ? `${cUrl.hostname}:${cUrl.port}` : `${cUrl.hostname}`;
|
||||
}
|
||||
|
||||
function canUseWebP() {
|
||||
// TODO pictshare might have a webp conversion bug, try disabling this
|
||||
return false;
|
||||
|
||||
// var elem = document.createElement('canvas');
|
||||
// if (!!(elem.getContext && elem.getContext('2d'))) {
|
||||
// var testString = !(window.mozInnerScreenX == null) ? 'png' : 'webp';
|
||||
// // was able or not to get WebP representation
|
||||
// return (
|
||||
// elem.toDataURL('image/webp').startsWith('data:image/' + testString)
|
||||
// );
|
||||
// }
|
||||
|
||||
// // very old browser like IE 8, canvas not supported
|
||||
// return false;
|
||||
}
|
||||
|
||||
export function validTitle(title?: string): boolean {
|
||||
// Initial title is null, minimum length is taken care of by textarea's minLength={3}
|
||||
if (title === null || title.length < 3) return true;
|
||||
|
|
Loading…
Reference in a new issue