Adding opengraph tags. Fixes #5

This commit is contained in:
Dessalines 2020-09-11 13:09:21 -05:00
parent d909ec8096
commit 89d15c9d09
21 changed files with 246 additions and 165 deletions

View File

@ -1,5 +1,4 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { import {
UserOperation, UserOperation,
@ -25,6 +24,7 @@ import {
import autosize from 'autosize'; import autosize from 'autosize';
import { SiteForm } from './site-form'; import { SiteForm } from './site-form';
import { UserListing } from './user-listing'; import { UserListing } from './user-listing';
import { HtmlTags } from './html-tags';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
interface AdminSettingsState { interface AdminSettingsState {
@ -97,7 +97,10 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle} /> <HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
{this.state.loading ? ( {this.state.loading ? (
<h5> <h5>
<svg class="icon icon-spinner spin"> <svg class="icon icon-spinner spin">

View File

@ -1,6 +1,7 @@
import { Component } from 'inferno'; import { Component } from 'inferno';
import { Route, Switch } from 'inferno-router'; import { Route, Switch } from 'inferno-router';
import { Provider } from 'inferno-i18next'; import { Provider } from 'inferno-i18next';
import { Helmet } from 'inferno-helmet';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
import { routes } from '../../shared/routes'; import { routes } from '../../shared/routes';
import { Navbar } from '../../shared/components/navbar'; import { Navbar } from '../../shared/components/navbar';
@ -23,6 +24,16 @@ export class App extends Component<AppProps, any> {
<> <>
<Provider i18next={i18n}> <Provider i18next={i18n}>
<div> <div>
{this.props.site.site.icon && (
<Helmet>
<link
id="favicon"
rel="icon"
type="image/x-icon"
href={this.props.site.site.icon}
/>
</Helmet>
)}
<Navbar site={this.props.site} /> <Navbar site={this.props.site} />
<div class="mt-4 p-0 fl-1"> <div class="mt-4 p-0 fl-1">
<Switch> <Switch>

View File

@ -1,5 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet'; import { HtmlTags } from './html-tags';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { import {
UserOperation, UserOperation,
@ -94,7 +94,10 @@ export class Communities extends Component<any, CommunitiesState> {
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle} /> <HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
{this.state.loading ? ( {this.state.loading ? (
<h5 class=""> <h5 class="">
<svg class="icon icon-spinner spin"> <svg class="icon icon-spinner spin">

View File

@ -1,5 +1,4 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { DataType } from '../interfaces'; import { DataType } from '../interfaces';
import { import {
@ -27,6 +26,7 @@ import {
import { UserService, WebSocketService } from '../services'; import { UserService, WebSocketService } from '../services';
import { PostListings } from './post-listings'; import { PostListings } from './post-listings';
import { CommentNodes } from './comment-nodes'; import { CommentNodes } from './comment-nodes';
import { HtmlTags } from './html-tags';
import { SortSelect } from './sort-select'; import { SortSelect } from './sort-select';
import { DataTypeSelect } from './data-type-select'; import { DataTypeSelect } from './data-type-select';
import { Sidebar } from './sidebar'; import { Sidebar } from './sidebar';
@ -46,7 +46,6 @@ import {
editPostFindRes, editPostFindRes,
commentsToFlatNodes, commentsToFlatNodes,
setupTippy, setupTippy,
favIconUrl,
notifyPost, notifyPost,
setIsoData, setIsoData,
wsSubscribe, wsSubscribe,
@ -226,30 +225,12 @@ export class Community extends Component<any, State> {
} }
get documentTitle(): string { get documentTitle(): string {
if (this.state.communityRes) { return `${this.state.communityRes.community.title} - ${this.state.siteRes.site.name}`;
return `${this.state.communityRes.community.title} - ${this.state.siteRes.site.name}`;
} else {
return 'Lemmy';
}
}
get favIcon(): string {
return this.state.siteRes.site.icon
? this.state.siteRes.site.icon
: favIconUrl;
} }
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle}>
<link
id="favicon"
rel="icon"
type="image/x-icon"
href={this.favIcon}
/>
</Helmet>
{this.state.loading ? ( {this.state.loading ? (
<h5> <h5>
<svg class="icon icon-spinner spin"> <svg class="icon icon-spinner spin">
@ -259,6 +240,12 @@ export class Community extends Component<any, State> {
) : ( ) : (
<div class="row"> <div class="row">
<div class="col-12 col-md-8"> <div class="col-12 col-md-8">
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
description={this.state.communityRes.community.title}
image={this.state.communityRes.community.icon}
/>
{this.communityInfo()} {this.communityInfo()}
{this.selects()} {this.selects()}
{this.listings()} {this.listings()}

View File

@ -1,7 +1,7 @@
import { Component } from 'inferno'; import { Component } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { CommunityForm } from './community-form'; import { CommunityForm } from './community-form';
import { HtmlTags } from './html-tags';
import { import {
Community, Community,
UserOperation, UserOperation,
@ -70,7 +70,10 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle} /> <HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
{this.state.loading ? ( {this.state.loading ? (
<h5> <h5>
<svg class="icon icon-spinner spin"> <svg class="icon icon-spinner spin">

View File

@ -1,7 +1,7 @@
import { Component } from 'inferno'; import { Component } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { PostForm } from './post-form'; import { PostForm } from './post-form';
import { HtmlTags } from './html-tags';
import { import {
isBrowser, isBrowser,
lemmyHttp, lemmyHttp,
@ -82,7 +82,10 @@ export class CreatePost extends Component<any, CreatePostState> {
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle} /> <HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
{this.state.loading ? ( {this.state.loading ? (
<h5> <h5>
<svg class="icon icon-spinner spin"> <svg class="icon icon-spinner spin">

View File

@ -1,7 +1,7 @@
import { Component } from 'inferno'; import { Component } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { PrivateMessageForm } from './private-message-form'; import { PrivateMessageForm } from './private-message-form';
import { HtmlTags } from './html-tags';
import { UserService, WebSocketService } from '../services'; import { UserService, WebSocketService } from '../services';
import { import {
Site, Site,
@ -102,7 +102,10 @@ export class CreatePrivateMessage extends Component<
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle} /> <HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
{this.state.loading ? ( {this.state.loading ? (
<h5> <h5>
<svg class="icon icon-spinner spin"> <svg class="icon icon-spinner spin">

View File

@ -0,0 +1,52 @@
import { Component } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { httpExternalPath } from '../env';
interface HtmlTagsProps {
title: string;
path: string;
description?: string;
image?: string;
}
/// Taken from https://metatags.io/
export class HtmlTags extends Component<HtmlTagsProps, any> {
render() {
let url = httpExternalPath(this.props.path);
return (
<Helmet title={this.props.title}>
{/* Primary Meta Tags */}
<meta name="title" content={this.props.title} />
{this.props.description && (
<meta name="description" content={this.props.description} />
)}
{/* Open Graph / Facebook */}
<meta property="og:type" content="website" />
<meta property="og:url" content={url} />
<meta property="og:title" content={this.props.title} />
{this.props.description && (
<meta property="og:description" content={this.props.description} />
)}
{this.props.image && (
<meta property="og:image" content={this.props.image} />
)}
{/* Twitter */}
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content={url} />
<meta property="twitter:title" content={this.props.title} />
{this.props.description && (
<meta
property="twitter:description"
content={this.props.description}
/>
)}
{this.props.image && (
<meta property="twitter:image" content={this.props.image} />
)}
</Helmet>
);
}
}

View File

@ -1,5 +1,4 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { import {
UserOperation, UserOperation,
@ -37,6 +36,7 @@ import {
} from '../utils'; } from '../utils';
import { CommentNodes } from './comment-nodes'; import { CommentNodes } from './comment-nodes';
import { PrivateMessage } from './private-message'; import { PrivateMessage } from './private-message';
import { HtmlTags } from './html-tags';
import { SortSelect } from './sort-select'; import { SortSelect } from './sort-select';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
@ -117,7 +117,6 @@ export class Inbox extends Component<any, InboxState> {
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle} />
{this.state.loading ? ( {this.state.loading ? (
<h5> <h5>
<svg class="icon icon-spinner spin"> <svg class="icon icon-spinner spin">
@ -127,6 +126,10 @@ export class Inbox extends Component<any, InboxState> {
) : ( ) : (
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
<h5 class="mb-1"> <h5 class="mb-1">
{i18n.t('inbox')} {i18n.t('inbox')}
<small> <small>

View File

@ -1,8 +1,8 @@
import { Component } from 'inferno'; import { Component } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { GetSiteResponse } from 'lemmy-js-client'; import { GetSiteResponse } from 'lemmy-js-client';
import { setIsoData } from '../utils'; import { setIsoData } from '../utils';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
import { HtmlTags } from './html-tags';
interface InstancesState { interface InstancesState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
@ -26,7 +26,10 @@ export class Instances extends Component<any, InstancesState> {
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle} /> <HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
<div> <div>
<h5>{i18n.t('linked_instances')}</h5> <h5>{i18n.t('linked_instances')}</h5>
{this.state.siteRes && {this.state.siteRes &&

View File

@ -22,6 +22,7 @@ import {
setIsoData, setIsoData,
} from '../utils'; } from '../utils';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
import { HtmlTags } from './html-tags';
interface State { interface State {
loginForm: LoginForm; loginForm: LoginForm;
@ -78,17 +79,16 @@ export class Login extends Component<any, State> {
} }
get documentTitle(): string { get documentTitle(): string {
if (this.state.site.name) { return `${i18n.t('login')} - ${this.state.site.name}`;
return `${i18n.t('login')} - ${this.state.site.name}`;
} else {
return 'Lemmy';
}
} }
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle} /> <HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
<div class="row"> <div class="row">
<div class="col-12 col-lg-6 mb-4">{this.loginForm()}</div> <div class="col-12 col-lg-6 mb-4">{this.loginForm()}</div>
<div class="col-12 col-lg-6">{this.registerForm()}</div> <div class="col-12 col-lg-6">{this.registerForm()}</div>

View File

@ -1,5 +1,4 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Link } from 'inferno-router'; import { Link } from 'inferno-router';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { import {
@ -53,7 +52,6 @@ import {
editPostFindRes, editPostFindRes,
commentsToFlatNodes, commentsToFlatNodes,
setupTippy, setupTippy,
favIconUrl,
notifyPost, notifyPost,
setIsoData, setIsoData,
wsSubscribe, wsSubscribe,
@ -63,6 +61,7 @@ import {
} from '../utils'; } from '../utils';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
import { T } from 'inferno-i18next'; import { T } from 'inferno-i18next';
import { HtmlTags } from './html-tags';
interface MainState { interface MainState {
subscribedCommunities: CommunityUser[]; subscribedCommunities: CommunityUser[];
@ -240,23 +239,13 @@ export class Main extends Component<any, MainState> {
return `${this.state.siteRes.site.name}`; return `${this.state.siteRes.site.name}`;
} }
get favIcon(): string {
return this.state.siteRes.site.icon
? this.state.siteRes.site.icon
: favIconUrl;
}
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle}> <HtmlTags
<link title={this.documentTitle}
id="favicon" path={this.context.router.route.match.url}
rel="icon" />
type="image/x-icon"
href={this.favIcon}
/>
</Helmet>
<div class="row"> <div class="row">
<main role="main" class="col-12 col-md-8"> <main role="main" class="col-12 col-md-8">
{this.posts()} {this.posts()}

View File

@ -1,5 +1,4 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Link } from 'inferno-router'; import { Link } from 'inferno-router';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { import {
@ -30,6 +29,7 @@ import {
lemmyHttp, lemmyHttp,
} from '../utils'; } from '../utils';
import { MomentTime } from './moment-time'; import { MomentTime } from './moment-time';
import { HtmlTags } from './html-tags';
import moment from 'moment'; import moment from 'moment';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
@ -353,17 +353,16 @@ export class Modlog extends Component<any, ModlogState> {
} }
get documentTitle(): string { get documentTitle(): string {
if (this.state.site) { return `Modlog - ${this.state.site.name}`;
return `Modlog - ${this.state.site.name}`;
} else {
return 'Lemmy';
}
} }
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle} /> <HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
{this.state.loading ? ( {this.state.loading ? (
<h5 class=""> <h5 class="">
<svg class="icon icon-spinner spin"> <svg class="icon icon-spinner spin">

View File

@ -1,5 +1,4 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { import {
UserOperation, UserOperation,
@ -18,6 +17,7 @@ import {
wsSubscribe, wsSubscribe,
} from '../utils'; } from '../utils';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
import { HtmlTags } from './html-tags';
interface State { interface State {
passwordChangeForm: PasswordChangeForm; passwordChangeForm: PasswordChangeForm;
@ -61,7 +61,10 @@ export class PasswordChange extends Component<any, State> {
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle} /> <HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
<div class="row"> <div class="row">
<div class="col-12 col-lg-6 offset-lg-3 mb-4"> <div class="col-12 col-lg-6 offset-lg-3 mb-4">
<h5>{i18n.t('password_change')}</h5> <h5>{i18n.t('password_change')}</h5>

View File

@ -38,6 +38,7 @@ import {
previewLines, previewLines,
} from '../utils'; } from '../utils';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
import { externalHost } from '../env';
interface PostListingState { interface PostListingState {
showEdit: boolean; showEdit: boolean;
@ -309,7 +310,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
)} )}
</li> </li>
<li className="list-inline-item"></li> <li className="list-inline-item"></li>
{post.url && !(hostname(post.url) == window.location.hostname) && ( {post.url && !(hostname(post.url) == externalHost) && (
<> <>
<li className="list-inline-item"> <li className="list-inline-item">
<a <a
@ -413,43 +414,37 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{post.name} {post.name}
</Link> </Link>
)} )}
{(isImage(post.url) || this.props.post.thumbnail_url) && ( {(isImage(post.url) || this.props.post.thumbnail_url) &&
<> (!this.state.imageExpanded ? (
{!this.state.imageExpanded ? ( <span
class="text-monospace unselectable pointer ml-2 text-muted small"
data-tippy-content={i18n.t('expand_here')}
onClick={linkEvent(this, this.handleImageExpandClick)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-plus-square"></use>
</svg>
</span>
) : (
<span>
<span <span
class="text-monospace unselectable pointer ml-2 text-muted small" class="text-monospace unselectable pointer ml-2 text-muted small"
data-tippy-content={i18n.t('expand_here')}
onClick={linkEvent(this, this.handleImageExpandClick)} onClick={linkEvent(this, this.handleImageExpandClick)}
> >
<svg class="icon icon-inline"> <svg class="icon icon-inline">
<use xlinkHref="#icon-plus-square"></use> <use xlinkHref="#icon-minus-square"></use>
</svg> </svg>
</span> </span>
) : ( <div>
<span>
<span <span
class="text-monospace unselectable pointer ml-2 text-muted small" class="pointer"
onClick={linkEvent(this, this.handleImageExpandClick)} onClick={linkEvent(this, this.handleImageExpandClick)}
> >
<svg class="icon icon-inline"> <img class="img-fluid img-expanded" src={this.getImage()} />
<use xlinkHref="#icon-minus-square"></use>
</svg>
</span> </span>
<div> </div>
<span </span>
class="pointer" ))}
onClick={linkEvent(this, this.handleImageExpandClick)}
>
<img
class="img-fluid img-expanded"
src={this.getImage()}
/>
</span>
</div>
</span>
)}
</>
)}
{post.removed && ( {post.removed && (
<small className="ml-2 text-muted font-italic"> <small className="ml-2 text-muted font-italic">
{i18n.t('removed')} {i18n.t('removed')}

View File

@ -1,5 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet'; import { HtmlTags } from './html-tags';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { import {
UserOperation, UserOperation,
@ -36,7 +36,6 @@ import {
createPostLikeRes, createPostLikeRes,
commentsToFlatNodes, commentsToFlatNodes,
setupTippy, setupTippy,
favIconUrl,
setIsoData, setIsoData,
getIdFromProps, getIdFromProps,
getCommentIdFromProps, getCommentIdFromProps,
@ -44,6 +43,8 @@ import {
setAuth, setAuth,
lemmyHttp, lemmyHttp,
isBrowser, isBrowser,
previewLines,
isImage,
} from '../utils'; } from '../utils';
import { PostListing } from './post-listing'; import { PostListing } from './post-listing';
import { Sidebar } from './sidebar'; import { Sidebar } from './sidebar';
@ -148,7 +149,7 @@ export class Post extends Component<any, PostState> {
// Necessary if you are on a post and you click another post (same route) // Necessary if you are on a post and you click another post (same route)
if (_lastProps.location.pathname !== _lastProps.history.location.pathname) { if (_lastProps.location.pathname !== _lastProps.history.location.pathname) {
// Couldnt get a refresh working. This does for now. // TODO Couldnt get a refresh working. This does for now.
location.reload(); location.reload();
// let currentId = this.props.match.params.id; // let currentId = this.props.match.params.id;
@ -191,30 +192,29 @@ export class Post extends Component<any, PostState> {
} }
get documentTitle(): string { get documentTitle(): string {
if (this.state.postRes) { return `${this.state.postRes.post.name} - ${this.state.siteRes.site.name}`;
return `${this.state.postRes.post.name} - ${this.state.siteRes.site.name}`;
} else {
return 'Lemmy';
}
} }
get favIcon(): string { get imageTag(): string {
return this.state.siteRes.site.icon return (
? this.state.siteRes.site.icon this.state.postRes.post.thumbnail_url ||
: favIconUrl; (this.state.postRes.post.url
? isImage(this.state.postRes.post.url)
? this.state.postRes.post.url
: undefined
: undefined)
);
}
get descriptionTag(): string {
return this.state.postRes.post.body
? previewLines(this.state.postRes.post.body)
: undefined;
} }
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle}>
<link
id="favicon"
rel="icon"
type="image/x-icon"
href={this.favIcon}
/>
</Helmet>
{this.state.loading ? ( {this.state.loading ? (
<h5> <h5>
<svg class="icon icon-spinner spin"> <svg class="icon icon-spinner spin">
@ -224,6 +224,12 @@ export class Post extends Component<any, PostState> {
) : ( ) : (
<div class="row"> <div class="row">
<div class="col-12 col-md-8 mb-3"> <div class="col-12 col-md-8 mb-3">
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
image={this.imageTag}
description={this.descriptionTag}
/>
<PostListing <PostListing
post={this.state.postRes.post} post={this.state.postRes.post}
showBody showBody

View File

@ -1,5 +1,4 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { import {
UserOperation, UserOperation,
@ -32,6 +31,7 @@ import {
setAuth, setAuth,
} from '../utils'; } from '../utils';
import { PostListing } from './post-listing'; import { PostListing } from './post-listing';
import { HtmlTags } from './html-tags';
import { UserListing } from './user-listing'; import { UserListing } from './user-listing';
import { CommunityLink } from './community-link'; import { CommunityLink } from './community-link';
import { SortSelect } from './sort-select'; import { SortSelect } from './sort-select';
@ -165,23 +165,20 @@ export class Search extends Component<any, SearchState> {
} }
get documentTitle(): string { get documentTitle(): string {
if (this.state.site.name) { if (this.state.q) {
if (this.state.q) { return `${i18n.t('search')} - ${this.state.q} - ${this.state.site.name}`;
return `${i18n.t('search')} - ${this.state.q} - ${
this.state.site.name
}`;
} else {
return `${i18n.t('search')} - ${this.state.site.name}`;
}
} else { } else {
return 'Lemmy'; return `${i18n.t('search')} - ${this.state.site.name}`;
} }
} }
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle} /> <HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
<h5>{i18n.t('search')}</h5> <h5>{i18n.t('search')}</h5>
{this.selects()} {this.selects()}
{this.searchForm()} {this.searchForm()}

View File

@ -1,10 +1,10 @@
import { Component } from 'inferno'; import { Component } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Site } from 'lemmy-js-client'; import { Site } from 'lemmy-js-client';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
import { T } from 'inferno-i18next'; import { T } from 'inferno-i18next';
import { repoUrl, isBrowser } from '../utils'; import { repoUrl, isBrowser } from '../utils';
import { IsoData } from 'shared/interfaces'; import { IsoData } from 'shared/interfaces';
import { HtmlTags } from './html-tags';
interface SilverUser { interface SilverUser {
name: string; name: string;
@ -74,7 +74,10 @@ export class Sponsors extends Component<any, SponsorsState> {
render() { render() {
return ( return (
<div class="container text-center"> <div class="container text-center">
<Helmet title={this.documentTitle} /> <HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
{this.topMessage()} {this.topMessage()}
<hr /> <hr />
{this.sponsors()} {this.sponsors()}

View File

@ -1,5 +1,4 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Link } from 'inferno-router'; import { Link } from 'inferno-router';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { import {
@ -33,7 +32,6 @@ import {
getLanguage, getLanguage,
mdToHtml, mdToHtml,
elementUrl, elementUrl,
favIconUrl,
setIsoData, setIsoData,
getIdFromProps, getIdFromProps,
getUsernameFromProps, getUsernameFromProps,
@ -44,8 +42,10 @@ import {
createPostLikeFindRes, createPostLikeFindRes,
setAuth, setAuth,
lemmyHttp, lemmyHttp,
previewLines,
} from '../utils'; } from '../utils';
import { UserListing } from './user-listing'; import { UserListing } from './user-listing';
import { HtmlTags } from './html-tags';
import { SortSelect } from './sort-select'; import { SortSelect } from './sort-select';
import { ListingTypeSelect } from './listing-type-select'; import { ListingTypeSelect } from './listing-type-select';
import { MomentTime } from './moment-time'; import { MomentTime } from './moment-time';
@ -250,30 +250,18 @@ export class User extends Component<any, UserState> {
} }
get documentTitle(): string { get documentTitle(): string {
if (this.state.siteRes.site.name) { return `@${this.state.userName} - ${this.state.siteRes.site.name}`;
return `@${this.state.userName} - ${this.state.siteRes.site.name}`;
} else {
return 'Lemmy';
}
} }
get favIcon(): string { get bioTag(): string {
return this.state.siteRes.site.icon return this.state.userRes.user.bio
? this.state.siteRes.site.icon ? previewLines(this.state.userRes.user.bio)
: favIconUrl; : undefined;
} }
render() { render() {
return ( return (
<div class="container"> <div class="container">
<Helmet title={this.documentTitle}>
<link
id="favicon"
rel="icon"
type="image/x-icon"
href={this.favIcon}
/>
</Helmet>
{this.state.loading ? ( {this.state.loading ? (
<h5> <h5>
<svg class="icon icon-spinner spin"> <svg class="icon icon-spinner spin">
@ -284,6 +272,12 @@ export class User extends Component<any, UserState> {
<div class="row"> <div class="row">
<div class="col-12 col-md-8"> <div class="col-12 col-md-8">
<> <>
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
description={this.bioTag}
image={this.state.userRes.user.avatar}
/>
{this.userInfo()} {this.userInfo()}
<hr /> <hr />
</> </>

View File

@ -1,15 +1,46 @@
import { isBrowser } from './utils'; import { isBrowser } from './utils';
const nodeHostname = process.env.LEMMY_HOST || 'localhost'; // used for local dev const testHost = 'localhost:8536';
const host = isBrowser() ? window.location.hostname : nodeHostname;
const secure = isBrowser() && window.location.protocol == 'https:' ? 's' : '';
const port = isBrowser()
? window.location.port == '1234' || window.location.port == '1235'
? 8536
: window.location.port
: 8536;
const endpoint = `${host}:${port}`;
export const wsUri = `ws${secure}://${endpoint}/api/v1/ws`; const internalHost = process.env.LEMMY_INTERNAL_HOST || testHost; // used for local dev
export const httpUri = `http${secure}://${endpoint}/api/v1`; export const externalHost = isBrowser()
export const pictrsUri = `http${secure}://${endpoint}/pictrs/image`; ? `${window.location.hostname}:${
window.location.port == '1234' || window.location.port == '1235'
? 8536
: window.location.port
}`
: process.env.LEMMY_EXTERNAL_HOST || testHost;
// ? window.location.port == '1234' || window.location.port == '1235'
const secure = isBrowser() && window.location.protocol == 'https:' ? 's' : '';
const host = isBrowser() ? externalHost : internalHost;
const httpBase = `http${secure}://${host}`;
export const wsUri = `ws${secure}://${host}/api/v1/ws`;
export const httpUri = `${httpBase}/api/v1`;
const httpExternalUri = `http${secure}://${externalHost}`;
export const pictrsUri = `${httpBase}/pictrs/image`;
console.log(`Internal host: ${internalHost}`);
console.log(`External host: ${externalHost}`);
export function httpExternalPath(path: string) {
return `${httpExternalUri}${path}`;
}
// export const httpUri = `http${secure}://${endpoint}/api/v1`;
// export const pictrsUri = `http${secure}://${endpoint}/pictrs/image`;
// const host = isBrowser() ? window.location.hostname : localHostname;
// const secure = isBrowser() && window.location.protocol == 'https:' ? 's' : '';
// const port = isBrowser()
// ? window.location.port == '1234' || window.location.port == '1235'
// ? 8536
// : window.location.port
// : 8536;
// const endpoint = `${host}:${port}`;
//
// export const wsUri = `ws${secure}://${endpoint}/api/v1/ws`;
// export const httpUri = `http${secure}://${endpoint}/api/v1`;
// export const pictrsUri = `http${secure}://${endpoint}/pictrs/image`;

View File

@ -271,7 +271,6 @@ export function isVideo(url: string) {
// TODO this broke // TODO this broke
export function validURL(str: string) { export function validURL(str: string) {
console.log(str);
// try { // try {
return !!new URL(str); return !!new URL(str);
// } catch { // } catch {
@ -439,8 +438,6 @@ export function getMomentLanguage(): string {
export function setTheme(theme: string, forceReload: boolean = false) { export function setTheme(theme: string, forceReload: boolean = false) {
if (isBrowser() && (theme !== 'darkly' || forceReload)) { if (isBrowser() && (theme !== 'darkly' || forceReload)) {
console.log(`setting theme ${theme}`);
// Unload all the other themes // Unload all the other themes
for (var i = 0; i < themes.length; i++) { for (var i = 0; i < themes.length; i++) {
let styleSheet = document.getElementById(themes[i]); let styleSheet = document.getElementById(themes[i]);
@ -1078,11 +1075,7 @@ export function previewLines(
export function hostname(url: string): string { export function hostname(url: string): string {
let cUrl = new URL(url); let cUrl = new URL(url);
// TODO return cUrl.port ? `${cUrl.hostname}:${cUrl.port}` : `${cUrl.hostname}`;
return `${cUrl.hostname}:${cUrl.port}`;
// return window.location.port
// ? `${cUrl.hostname}:${cUrl.port}`
// : `${cUrl.hostname}`;
} }
function canUseWebP() { function canUseWebP() {