mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-25 22:01:13 +00:00
Adding opengraph tags. Fixes #5
This commit is contained in:
parent
d909ec8096
commit
89d15c9d09
21 changed files with 246 additions and 165 deletions
|
@ -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">
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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()}
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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">
|
||||||
|
|
52
src/shared/components/html-tags.tsx
Normal file
52
src/shared/components/html-tags.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
||||||
|
|
|
@ -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 &&
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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()}
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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,9 +414,8 @@ 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
|
<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')}
|
data-tippy-content={i18n.t('expand_here')}
|
||||||
|
@ -440,16 +440,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
class="pointer"
|
class="pointer"
|
||||||
onClick={linkEvent(this, this.handleImageExpandClick)}
|
onClick={linkEvent(this, this.handleImageExpandClick)}
|
||||||
>
|
>
|
||||||
<img
|
<img class="img-fluid img-expanded" src={this.getImage()} />
|
||||||
class="img-fluid img-expanded"
|
|
||||||
src={this.getImage()}
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</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')}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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} - ${
|
return `${i18n.t('search')} - ${this.state.q} - ${this.state.site.name}`;
|
||||||
this.state.site.name
|
|
||||||
}`;
|
|
||||||
} else {
|
} else {
|
||||||
return `${i18n.t('search')} - ${this.state.site.name}`;
|
return `${i18n.t('search')} - ${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}
|
||||||
|
/>
|
||||||
<h5>{i18n.t('search')}</h5>
|
<h5>{i18n.t('search')}</h5>
|
||||||
{this.selects()}
|
{this.selects()}
|
||||||
{this.searchForm()}
|
{this.searchForm()}
|
||||||
|
|
|
@ -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()}
|
||||||
|
|
|
@ -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 />
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -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 internalHost = process.env.LEMMY_INTERNAL_HOST || testHost; // used for local dev
|
||||||
const port = isBrowser()
|
export const externalHost = isBrowser()
|
||||||
? window.location.port == '1234' || window.location.port == '1235'
|
? `${window.location.hostname}:${
|
||||||
|
window.location.port == '1234' || window.location.port == '1235'
|
||||||
? 8536
|
? 8536
|
||||||
: window.location.port
|
: window.location.port
|
||||||
: 8536;
|
}`
|
||||||
const endpoint = `${host}:${port}`;
|
: process.env.LEMMY_EXTERNAL_HOST || testHost;
|
||||||
|
|
||||||
export const wsUri = `ws${secure}://${endpoint}/api/v1/ws`;
|
// ? window.location.port == '1234' || window.location.port == '1235'
|
||||||
export const httpUri = `http${secure}://${endpoint}/api/v1`;
|
const secure = isBrowser() && window.location.protocol == 'https:' ? 's' : '';
|
||||||
export const pictrsUri = `http${secure}://${endpoint}/pictrs/image`;
|
|
||||||
|
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`;
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in a new issue