diff options
author | Dessalines <tyhou13@gmx.com> | 2020-02-17 11:18:01 -0500 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2020-02-17 11:18:01 -0500 |
commit | 55f91ac5dc1816463fb99d6974f89acd46de3444 (patch) | |
tree | 8c06996dfefb3dba27856c4efa36b669530c09d2 /ui | |
parent | b6ce26023efc75ca2b871d12c4f1c2c7b9696083 (diff) |
First pass at adding oembeds / iframely.
Diffstat (limited to 'ui')
-rw-r--r-- | ui/src/components/iframely-card.tsx | 100 | ||||
-rw-r--r-- | ui/src/components/post-listing.tsx | 53 | ||||
-rw-r--r-- | ui/src/interfaces.ts | 15 |
3 files changed, 164 insertions, 4 deletions
diff --git a/ui/src/components/iframely-card.tsx b/ui/src/components/iframely-card.tsx new file mode 100644 index 00000000..73f3cef7 --- /dev/null +++ b/ui/src/components/iframely-card.tsx @@ -0,0 +1,100 @@ +import { Component, linkEvent } from 'inferno'; +import { FramelyData } from '../interfaces'; +import { mdToHtml } from '../utils'; + +interface FramelyCardProps { + iframely: FramelyData; +} + +interface FramelyCardState { + expanded: boolean; +} + +export class IFramelyCard extends Component< + FramelyCardProps, + FramelyCardState +> { + private emptyState: FramelyCardState = { + expanded: false, + }; + + constructor(props: any, context: any) { + super(props, context); + this.state = this.emptyState; + } + + render() { + let iframely = this.props.iframely; + return ( + <> + <div class="card my-2"> + <div class="row no-gutters"> + {iframely.thumbnail_url && ( + <div class="col-sm-3"> + {iframely.html ? ( + <span + class="pointer" + onClick={linkEvent(this, this.handleIframeExpand)} + > + <img class="card-img" src={iframely.thumbnail_url} /> + </span> + ) : ( + <img + class="img-fluid card-img" + src={iframely.thumbnail_url} + /> + )} + </div> + )} + <div class="col-sm-9"> + <div class="card-body"> + <h5 class="card-title d-inline"> + <span> + <a class="text-body" target="_blank" href={iframely.url}> + {iframely.title} + </a> + </span> + </h5> + <span class="d-inline-block ml-2 mb-2 small text-muted"> + <a class="text-muted" target="_blank" href={iframely.url}> + {new URL(iframely.url).hostname} + <svg class="ml-1 icon"> + <use xlinkHref="#icon-external-link"></use> + </svg> + </a> + {iframely.html && ( + <span + class="ml-2 pointer" + onClick={linkEvent(this, this.handleIframeExpand)} + > + {this.state.expanded ? '[-]' : '[+]'} + </span> + )} + </span> + {iframely.description && ( + <div + className="card-text small text-muted md-div" + dangerouslySetInnerHTML={mdToHtml(iframely.description)} + /> + )} + </div> + </div> + </div> + </div> + {this.state.expanded && ( + <div class="my-2 embed-responsive embed-responsive-16by9"> + <div + class="embed-responsive-item" + dangerouslySetInnerHTML={{ __html: iframely.html }} + /> + </div> + )} + </> + ); + } + + handleIframeExpand(i: IFramelyCard) { + i.state.expanded = !i.state.expanded; + i.setState(i.state); + } +} diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index d3772544..5cc63251 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -15,9 +15,11 @@ import { AddAdminForm, TransferSiteForm, TransferCommunityForm, + FramelyData, } from '../interfaces'; import { MomentTime } from './moment-time'; import { PostForm } from './post-form'; +import { IFramelyCard } from './iframely-card'; import { mdToHtml, canMod, @@ -47,6 +49,7 @@ interface PostListingState { score: number; upvotes: number; downvotes: number; + iframely: FramelyData; } interface PostListingProps { @@ -74,6 +77,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { score: this.props.post.score, upvotes: this.props.post.upvotes, downvotes: this.props.post.downvotes, + iframely: null, }; constructor(props: any, context: any) { @@ -84,6 +88,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> { this.handlePostDisLike = this.handlePostDisLike.bind(this); this.handleEditPost = this.handleEditPost.bind(this); this.handleEditCancel = this.handleEditCancel.bind(this); + + if (this.props.post.url) { + this.fetchIframely(); + } } componentWillReceiveProps(nextProps: PostListingProps) { @@ -141,7 +149,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { </button> )} </div> - {post.url && isImage(post.url) && !this.state.imageExpanded && ( + {this.hasImage() && !this.state.imageExpanded && ( <span title={i18n.t('expand_here')} class="pointer" @@ -151,7 +159,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { className={`mx-2 mt-1 float-left img-fluid thumbnail rounded ${(post.nsfw || post.community_nsfw) && 'img-blur'}`} - src={imageThumbnailer(post.url)} + src={imageThumbnailer(this.getImage())} /> </span> )} @@ -205,7 +213,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { </a> </small> )} - {post.url && isImage(post.url) && ( + {this.hasImage() && ( <> {!this.state.imageExpanded ? ( <span @@ -228,7 +236,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> { class="pointer" onClick={linkEvent(this, this.handleImageExpandClick)} > - <img class="img-fluid img-expanded" src={post.url} /> + <img + class="img-fluid img-expanded" + src={this.getImage()} + /> </span> </div> </span> @@ -587,6 +598,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> { </li> )} </ul> + {post.url && this.props.showBody && this.state.iframely && ( + <IFramelyCard iframely={this.state.iframely} /> + )} {this.state.showRemoveDialog && ( <form class="form-inline" @@ -737,6 +751,37 @@ export class PostListing extends Component<PostListingProps, PostListingState> { ); } + fetchIframely() { + fetch(`/iframely/oembed?url=${this.props.post.url}`) + .then(res => res.json()) + .then(res => { + this.state.iframely = res; + this.setState(this.state); + }) + .catch(error => { + console.error(`Iframely service not set up properly. ${error}`); + }); + } + + hasImage(): boolean { + return ( + (this.props.post.url && isImage(this.props.post.url)) || + (this.state.iframely && this.state.iframely.thumbnail_url !== undefined) + ); + } + + getImage(): string { + let simpleImg = isImage(this.props.post.url); + if (simpleImg) { + return this.props.post.url; + } else if (this.state.iframely) { + let iframelyThumbnail = this.state.iframely.thumbnail_url; + if (iframelyThumbnail) { + return iframelyThumbnail; + } + } + } + handlePostLike(i: PostListing) { let new_vote = i.state.my_vote == 1 ? 0 : 1; diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index 5846b548..5baadb17 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -876,3 +876,18 @@ export interface WebSocketJsonResponse { error?: string; reconnect?: boolean; } + +export interface FramelyData { + url: string; + type: string; + version?: string; + title: string; + author?: string; + author_url?: string; + provider_name?: string; + thumbnail_url?: string; + thumbnail_width?: number; + thumbnail_height?: number; + description?: string; + html?: string; +} |