This commit is contained in:
Dessalines 2021-02-23 09:59:03 -05:00
commit 2e2b18c717
66 changed files with 1858 additions and 1879 deletions

View file

@ -3,8 +3,8 @@
} }
.navbar-expand-lg .navbar-nav .nav-link { .navbar-expand-lg .navbar-nav .nav-link {
padding-right: .75rem !important; padding-right: 0.75rem !important;
padding-left: .75rem !important; padding-left: 0.75rem !important;
} }
.pointer { .pointer {
@ -16,12 +16,12 @@
} }
.no-click { .no-click {
pointer-events:none; pointer-events: none;
opacity: 0.65; opacity: 0.65;
} }
.upvote:hover { .upvote:hover {
color: var(--info); color: var(--info);
} }
.upvote { .upvote {
@ -56,19 +56,19 @@
} }
.md-div h1 { .md-div h1 {
font-size:2rem; font-size: 2rem;
} }
.md-div h2 { .md-div h2 {
font-size:1.8rem; font-size: 1.8rem;
} }
.md-div h3 { .md-div h3 {
font-size:1.6rem; font-size: 1.6rem;
} }
.md-div h4 { .md-div h4 {
font-size:1.4rem; font-size: 1.4rem;
} }
.md-div h5 { .md-div h5 {
font-size:1.2rem; font-size: 1.2rem;
} }
.md-div table { .md-div table {
@ -100,7 +100,7 @@
} }
.post-title { .post-title {
line-height: 1.0; line-height: 1;
} }
.post-title a:visited { .post-title a:visited {
@ -133,8 +133,12 @@
} }
@keyframes spins { @keyframes spins {
0% { transform: rotate(0deg); } 0% {
100% { transform: rotate(359deg); } transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
} }
.dropdown-menu { .dropdown-menu {
@ -185,7 +189,7 @@ hr {
.text-wrap-truncate { .text-wrap-truncate {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis text-overflow: ellipsis;
} }
#app { #app {
@ -221,29 +225,29 @@ hr {
top: 0; top: 0;
right: 0; right: 0;
padding: 2px; padding: 2px;
height: 1.5em; height: 1.5em;
width: 1.5em; width: 1.5em;
background: rgba(0,0,0,.4); background: rgba(0, 0, 0, 0.4);
border-bottom-left-radius: 0.25rem !important; border-bottom-left-radius: 0.25rem !important;
border-top-right-radius: 0.25rem !important; border-top-right-radius: 0.25rem !important;
} }
.link-overlay:hover { .link-overlay:hover {
transition: .1s; transition: 0.1s;
opacity: 1; opacity: 1;
} }
.link-overlay { .link-overlay {
transition: opacity .1s ease-in-out; transition: opacity 0.1s ease-in-out;
position: absolute; position: absolute;
opacity: 0; opacity: 0;
left: 0; left: 0;
height: 100%; height: 100%;
width: 100%; width: 100%;
padding: 10px; padding: 10px;
background: rgba(0,0,0,.6); background: rgba(0, 0, 0, 0.6);
} }
.placeholder { .placeholder {
height: 50px; height: 50px;
width: 50px; width: 50px;
@ -278,13 +282,12 @@ pre {
.show-input { .show-input {
width: 13em !important; width: 13em !important;
} }
.hide-input { .hide-input {
background: transparent !important; background: transparent !important;
width: 0px !important; width: 0px !important;
padding: 0 !important; padding: 0 !important;
} }
br.big { br.big {
display: block; display: block;
@ -299,7 +302,7 @@ br.big {
} }
.avatar-overlay { .avatar-overlay {
width: 20%; width: 20%;
height: 20%; height: 20%;
max-width: 120px; max-width: 120px;
max-height: 120px; max-height: 120px;
@ -310,7 +313,8 @@ br.big {
} }
.img-icon { .img-icon {
width: 2rem; height: 2rem; width: 2rem;
height: 2rem;
} }
.tribute-container ul { .tribute-container ul {
@ -318,16 +322,21 @@ br.big {
margin-top: 2px; margin-top: 2px;
padding: 0; padding: 0;
list-style: none; list-style: none;
background: var(--light); } background: var(--light);
}
.tribute-container li { .tribute-container li {
padding: 5px 5px; padding: 5px 5px;
cursor: pointer; } cursor: pointer;
.tribute-container li.highlight { }
background: var(--primary); } .tribute-container li.highlight {
.tribute-container li span { background: var(--primary);
font-weight: bold; } }
.tribute-container li.no-match { .tribute-container li span {
cursor: default; } font-weight: bold;
.tribute-container .menu-highlighted { }
font-weight: bold; .tribute-container li.no-match {
cursor: default;
}
.tribute-container .menu-highlighted {
font-weight: bold;
} }

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,3 @@
$white: #fff; $white: #fff;
$gray-100: #f8f9fa; $gray-100: #f8f9fa;
$gray-200: #ebebeb; $gray-200: #ebebeb;
@ -31,7 +30,9 @@ $yiq-contrasted-threshold: 175;
$body-bg: $gray-900; $body-bg: $gray-900;
$body-color: $gray-300; $body-color: $gray-300;
$link-color: $success; $link-color: $success;
$font-family-sans-serif: "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; $font-family-sans-serif: "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji",
"Segoe UI Emoji", "Segoe UI Symbol";
$font-size-base: 0.9375rem; $font-size-base: 0.9375rem;
$h1-font-size: 3rem; $h1-font-size: 3rem;
$h2-font-size: 2.5rem; $h2-font-size: 2.5rem;
@ -53,16 +54,18 @@ $dropdown-link-hover-bg: $primary;
$nav-link-padding-x: 2rem; $nav-link-padding-x: 2rem;
$nav-link-disabled-color: $gray-500; $nav-link-disabled-color: $gray-500;
$nav-tabs-border-color: $gray-700; $nav-tabs-border-color: $gray-700;
$nav-tabs-link-hover-border-color: $nav-tabs-border-color $nav-tabs-border-color transparent; $nav-tabs-link-hover-border-color: $nav-tabs-border-color $nav-tabs-border-color
transparent;
$nav-tabs-link-active-color: $white; $nav-tabs-link-active-color: $white;
$nav-tabs-link-active-border-color: $nav-tabs-border-color $nav-tabs-border-color transparent; $nav-tabs-link-active-border-color: $nav-tabs-border-color
$nav-tabs-border-color transparent;
$navbar-padding-y: 1rem; $navbar-padding-y: 1rem;
$navbar-dark-color: rgba($white,.6); $navbar-dark-color: rgba($white, 0.6);
$navbar-dark-hover-color: $white; $navbar-dark-hover-color: $white;
$navbar-light-color: rgba($white,.6); $navbar-light-color: rgba($white, 0.6);
$navbar-light-hover-color: $white; $navbar-light-hover-color: $white;
$navbar-light-active-color: $white; $navbar-light-active-color: $white;
$navbar-light-toggler-border-color: rgba($gray-900, .1); $navbar-light-toggler-border-color: rgba($gray-900, 0.1);
$pagination-color: $white; $pagination-color: $white;
$pagination-bg: $success; $pagination-bg: $success;
$pagination-border-width: 0; $pagination-border-width: 0;
@ -98,7 +101,7 @@ $custom-select-bg: $secondary;
$custom-select-color: $white; $custom-select-color: $white;
$input-bg: $secondary; $input-bg: $secondary;
$input-color: $white; $input-color: $white;
$input-disabled-bg: darken($secondary, 10%);; $input-disabled-bg: darken($secondary, 10%);
$light: $gray-800; $light: $gray-800;
$navbar-light-brand-color: $navbar-dark-active-color; $navbar-light-brand-color: $navbar-dark-active-color;
$navbar-light-brand-hover-color: $navbar-dark-active-color; $navbar-light-brand-hover-color: $navbar-dark-active-color;

View file

@ -1,14 +1,13 @@
$blue: #5555ff;
$blue: #5555Ff; $cyan: #55ffff;
$cyan: #55FFFF; $green: #55ff55;
$green: #55FF55; $indigo: #ff55ff;
$indigo: #FF55FF; $red: #ff5555;
$red: #FF5555; $yellow: #fefe54;
$yellow: #FEFE54; $orange: #a85400;
$orange: #A85400; $pink: #fe54fe;
$pink: #FE54FE; $purple: #fe5454;
$purple: #FE5454; $primary: #fefe54;
$primary: #FEFE54;
$body-bg: #000084; $body-bg: #000084;
$gray-300: #bbb; $gray-300: #bbb;
$body-color: $gray-300; $body-color: $gray-300;
@ -17,17 +16,17 @@ $font-family-sans-serif: DOS, Monaco, Menlo, Consolas, "Courier New", monospace;
$font-family-monospace: DOS, Monaco, Menlo, Consolas, "Courier New", monospace; $font-family-monospace: DOS, Monaco, Menlo, Consolas, "Courier New", monospace;
$navbar-dark-color: $gray-300; $navbar-dark-color: $gray-300;
$navbar-light-brand-color: $gray-300; $navbar-light-brand-color: $gray-300;
$success: #00AA00; $success: #00aa00;
$danger: #AA0000; $danger: #aa0000;
$info: #00AAAA; $info: #00aaaa;
$warning: #AA00AA; $warning: #aa00aa;
$navbar-dark-active-color: $gray-100; $navbar-dark-active-color: $gray-100;
$enable-rounded: false; $enable-rounded: false;
$input-color: $white; $input-color: $white;
$input-bg: rgb(102, 102, 102); $input-bg: rgb(102, 102, 102);
$input-disabled-bg: $gray-800; $input-disabled-bg: $gray-800;
$nav-tabs-link-active-color: $gray-100; $nav-tabs-link-active-color: $gray-100;
$navbar-dark-hover-color: rgba($gray-300, .75); $navbar-dark-hover-color: rgba($gray-300, 0.75);
$light: $gray-800; $light: $gray-800;
$navbar-light-disabled-color: $gray-800; $navbar-light-disabled-color: $gray-800;
$navbar-light-active-color: $gray-100; $navbar-light-active-color: $gray-100;
@ -37,4 +36,4 @@ $card-bg: $gray-800;
$card-border-color: $white; $card-border-color: $white;
$input-placeholder-color: $gray-500; $input-placeholder-color: $gray-500;
$mark-bg: #463b00; $mark-bg: #463b00;
$secondary: $gray-900; $secondary: $gray-900;

View file

@ -1,23 +1,23 @@
$white: #ffffff; $white: #ffffff;
$orange: #f1641e; $orange: #f1641e;
$cyan: #02bdc2; $cyan: #02bdc2;
$green: #00C853; $green: #00c853;
$secondary: $green; $secondary: $green;
$body-color: $gray-700; $body-color: $gray-700;
$link-color: theme-color("primary");; $link-color: theme-color("primary");
$primary: $orange; $primary: $orange;
$red: #d8486a; $red: #d8486a;
$border-radius: 0.5rem; $border-radius: 0.5rem;
$border-radius-lg: 0.5rem; $border-radius-lg: 0.5rem;
$border-radius-sm: 1rem; $border-radius-sm: 1rem;
$font-family-sans-serif: -apple-system,BlinkMacSystemFont,"Droid Sans","Segoe UI","Helvetica",Arial,sans-serif; $font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Droid Sans",
"Segoe UI", "Helvetica", Arial, sans-serif;
$headings-color: $gray-700; $headings-color: $gray-700;
$input-btn-focus-color: rgba($component-active-bg, .75); $input-btn-focus-color: rgba($component-active-bg, 0.75);
$form-feedback-valid-color: theme-color("info"); $form-feedback-valid-color: theme-color("info");
$navbar-light-color: $gray-600; $navbar-light-color: $gray-600;
$black: #222222; $black: #222222;
$navbar-dark-toggler-border-color: rgba($black, .1); $navbar-dark-toggler-border-color: rgba($black, 0.1);
$navbar-light-active-color: $gray-900; $navbar-light-active-color: $gray-900;
$card-color: $gray-700; $card-color: $gray-700;
$card-cap-color: $gray-700; $card-cap-color: $gray-700;

View file

@ -1,4 +1,3 @@
$blue: #01cdfe; $blue: #01cdfe;
$indigo: #b967ff; $indigo: #b967ff;
$purple: #b967ff; $purple: #b967ff;
@ -21,14 +20,14 @@ $yiq-text-light: $gray-300;
$secondary: $blue; $secondary: $blue;
$text-muted: $gray-500; $text-muted: $gray-500;
$primary: $pink; $primary: $pink;
$navbar-light-hover-color: rgba($primary, .7); $navbar-light-hover-color: rgba($primary, 0.7);
$light: darken($gray-100,1.5); $light: darken($gray-100, 1.5);
$font-family-sans-serif: "Lucida Console", Monaco, monospace; $font-family-sans-serif: "Lucida Console", Monaco, monospace;
$card-bg: $body-bg; $card-bg: $body-bg;
$navbar-dark-color: rgba($body-bg, .5); $navbar-dark-color: rgba($body-bg, 0.5);
$navbar-light-active-color: rgba($gray-200, .9); $navbar-light-active-color: rgba($gray-200, 0.9);
$navbar-light-disabled-color: rgba($gray-200, .3); $navbar-light-disabled-color: rgba($gray-200, 0.3);
$navbar-light-color: rgba($white, .5); $navbar-light-color: rgba($white, 0.5);
$input-bg: $gray-700; $input-bg: $gray-700;
$input-color: $gray-200; $input-color: $gray-200;
$input-disabled-bg: $gray-800; $input-disabled-bg: $gray-800;

View file

@ -20,6 +20,6 @@ $yiq-text-light: $gray-300;
$secondary: $blue; $secondary: $blue;
$text-muted: $gray-500; $text-muted: $gray-500;
$primary: $pink; $primary: $pink;
$navbar-light-hover-color: rgba($primary, .7); $navbar-light-hover-color: rgba($primary, 0.7);
$light: darken($gray-100,1.5); $light: darken($gray-100, 1.5);
$font-family-sans-serif: "Lucida Console", Monaco, monospace; $font-family-sans-serif: "Lucida Console", Monaco, monospace;

View file

@ -1,7 +1,7 @@
import { hydrate } from 'inferno-hydrate'; import { hydrate } from "inferno-hydrate";
import { BrowserRouter } from 'inferno-router'; import { BrowserRouter } from "inferno-router";
import { initializeSite } from '../shared/initialize'; import { initializeSite } from "../shared/initialize";
import { App } from '../shared/components/app'; import { App } from "../shared/components/app";
const site = window.isoData.site_res; const site = window.isoData.site_res;
initializeSite(site); initializeSite(site);
@ -12,4 +12,4 @@ const wrapper = (
</BrowserRouter> </BrowserRouter>
); );
hydrate(wrapper, document.getElementById('root')); hydrate(wrapper, document.getElementById("root"));

View file

@ -1,38 +1,38 @@
import serialize from 'serialize-javascript'; import serialize from "serialize-javascript";
import express from 'express'; import express from "express";
import { StaticRouter } from 'inferno-router'; import { StaticRouter } from "inferno-router";
import { renderToString } from 'inferno-server'; import { renderToString } from "inferno-server";
import { matchPath } from 'inferno-router'; import { matchPath } from "inferno-router";
import path from 'path'; import path from "path";
import { App } from '../shared/components/app'; import { App } from "../shared/components/app";
import { import {
ILemmyConfig, ILemmyConfig,
InitialFetchRequest, InitialFetchRequest,
IsoData, IsoData,
} from '../shared/interfaces'; } from "../shared/interfaces";
import { routes } from '../shared/routes'; import { routes } from "../shared/routes";
import IsomorphicCookie from 'isomorphic-cookie'; import IsomorphicCookie from "isomorphic-cookie";
import { GetSite, LemmyHttp } from 'lemmy-js-client'; import { GetSite, LemmyHttp } from "lemmy-js-client";
import process from 'process'; import process from "process";
import { Helmet } from 'inferno-helmet'; import { Helmet } from "inferno-helmet";
import { initializeSite } from '../shared/initialize'; import { initializeSite } from "../shared/initialize";
import { httpUri } from '../shared/env'; import { httpUri } from "../shared/env";
import { IncomingHttpHeaders } from 'http'; import { IncomingHttpHeaders } from "http";
import { setOptionalAuth } from '../shared/utils'; import { setOptionalAuth } from "../shared/utils";
const server = express(); const server = express();
const port = 1234; const port = 1234;
server.use(express.json()); server.use(express.json());
server.use(express.urlencoded({ extended: false })); server.use(express.urlencoded({ extended: false }));
server.use('/static', express.static(path.resolve('./dist'))); server.use("/static", express.static(path.resolve("./dist")));
// server.use(cookieParser()); // server.use(cookieParser());
server.get('/*', async (req, res) => { server.get("/*", async (req, res) => {
const activeRoute = routes.find(route => matchPath(req.path, route)) || {}; const activeRoute = routes.find(route => matchPath(req.path, route)) || {};
const context = {} as any; const context = {} as any;
let auth: string = IsomorphicCookie.load('jwt', req); let auth: string = IsomorphicCookie.load("jwt", req);
let getSiteForm: GetSite = {}; let getSiteForm: GetSite = {};
setOptionalAuth(getSiteForm, auth); setOptionalAuth(getSiteForm, auth);
@ -63,13 +63,13 @@ server.get('/*', async (req, res) => {
return res.redirect(`/404?err=${errCode}`); return res.redirect(`/404?err=${errCode}`);
} }
let acceptLang = req.headers['accept-language'] let acceptLang = req.headers["accept-language"]
? req.headers['accept-language'].split(',')[0] ? req.headers["accept-language"].split(",")[0]
: 'en'; : "en";
let lang = site.my_user let lang = site.my_user
? site.my_user.lang == 'browser' ? site.my_user.lang == "browser"
? acceptLang ? acceptLang
: 'en' : "en"
: acceptLang; : acceptLang;
let isoData: IsoData = { let isoData: IsoData = {
@ -96,7 +96,7 @@ server.get('/*', async (req, res) => {
); );
const root = renderToString(wrapper); const root = renderToString(wrapper);
const cspStr = process.env.LEMMY_EXTERNAL_HOST ? renderToString(cspHtml) : ''; const cspStr = process.env.LEMMY_EXTERNAL_HOST ? renderToString(cspHtml) : "";
const helmet = Helmet.renderStatic(); const helmet = Helmet.renderStatic();
const config: ILemmyConfig = { wsHost: process.env.LEMMY_WS_HOST }; const config: ILemmyConfig = { wsHost: process.env.LEMMY_WS_HOST };
@ -157,17 +157,17 @@ function setForwardedHeaders(
let out = { let out = {
host: headers.host, host: headers.host,
}; };
if (headers['x-real-ip']) { if (headers["x-real-ip"]) {
out['x-real-ip'] = headers['x-real-ip']; out["x-real-ip"] = headers["x-real-ip"];
} }
if (headers['x-forwarded-for']) { if (headers["x-forwarded-for"]) {
out['x-forwarded-for'] = headers['x-forwarded-for']; out["x-forwarded-for"] = headers["x-forwarded-for"];
} }
return out; return out;
} }
process.on('SIGINT', () => { process.on("SIGINT", () => {
console.info('Interrupted'); console.info("Interrupted");
process.exit(0); process.exit(0);
}); });

View file

@ -1,28 +1,28 @@
import { register } from 'register-service-worker'; import { register } from "register-service-worker";
register('/service-worker.js', { register("/service-worker.js", {
registrationOptions: { scope: './' }, registrationOptions: { scope: "./" },
ready() { ready() {
console.log('Service worker is active.'); console.log("Service worker is active.");
}, },
registered() { registered() {
console.log('Service worker has been registered.'); console.log("Service worker has been registered.");
}, },
cached() { cached() {
console.log('Content has been cached for offline use.'); console.log("Content has been cached for offline use.");
}, },
updatefound() { updatefound() {
console.log('New content is downloading.'); console.log("New content is downloading.");
}, },
updated() { updated() {
console.log('New content is available; please refresh.'); console.log("New content is available; please refresh.");
}, },
offline() { offline() {
console.log( console.log(
'No internet connection found. App is running in offline mode.' "No internet connection found. App is running in offline mode."
); );
}, },
error(error) { error(error) {
console.error('Error during service worker registration:', error); console.error("Error during service worker registration:", error);
}, },
}); });

View file

@ -1,5 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
UserOperation, UserOperation,
SiteResponse, SiteResponse,
@ -7,8 +7,8 @@ import {
SaveSiteConfig, SaveSiteConfig,
GetSiteConfigResponse, GetSiteConfigResponse,
GetSiteConfig, GetSiteConfig,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService } from '../services'; import { WebSocketService } from "../services";
import { import {
wsJsonToRes, wsJsonToRes,
capitalizeFirstLetter, capitalizeFirstLetter,
@ -20,14 +20,14 @@ import {
wsUserOp, wsUserOp,
wsClient, wsClient,
authField, authField,
} from '../utils'; } from "../utils";
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 { HtmlTags } from "./html-tags";
import { Spinner } from './icon'; import { Spinner } from "./icon";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { InitialFetchRequest } from 'shared/interfaces'; import { InitialFetchRequest } from "shared/interfaces";
interface AdminSettingsState { interface AdminSettingsState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
@ -96,7 +96,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
} }
get documentTitle(): string { get documentTitle(): string {
return `${i18n.t('admin_settings')} - ${ return `${i18n.t("admin_settings")} - ${
this.state.siteRes.site_view.site.name this.state.siteRes.site_view.site.name
}`; }`;
} }
@ -131,7 +131,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
admins() { admins() {
return ( return (
<> <>
<h5>{capitalizeFirstLetter(i18n.t('admins'))}</h5> <h5>{capitalizeFirstLetter(i18n.t("admins"))}</h5>
<ul class="list-unstyled"> <ul class="list-unstyled">
{this.state.siteRes.admins.map(admin => ( {this.state.siteRes.admins.map(admin => (
<li class="list-inline-item"> <li class="list-inline-item">
@ -146,7 +146,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
bannedUsers() { bannedUsers() {
return ( return (
<> <>
<h5>{i18n.t('banned_users')}</h5> <h5>{i18n.t("banned_users")}</h5>
<ul class="list-unstyled"> <ul class="list-unstyled">
{this.state.siteRes.banned.map(banned => ( {this.state.siteRes.banned.map(banned => (
<li class="list-inline-item"> <li class="list-inline-item">
@ -161,14 +161,14 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
adminSettings() { adminSettings() {
return ( return (
<div> <div>
<h5>{i18n.t('admin_settings')}</h5> <h5>{i18n.t("admin_settings")}</h5>
<form onSubmit={linkEvent(this, this.handleSiteConfigSubmit)}> <form onSubmit={linkEvent(this, this.handleSiteConfigSubmit)}>
<div class="form-group row"> <div class="form-group row">
<label <label
class="col-12 col-form-label" class="col-12 col-form-label"
htmlFor={this.siteConfigTextAreaId} htmlFor={this.siteConfigTextAreaId}
> >
{i18n.t('site_config')} {i18n.t("site_config")}
</label> </label>
<div class="col-12"> <div class="col-12">
<textarea <textarea
@ -186,7 +186,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
{this.state.siteConfigLoading ? ( {this.state.siteConfigLoading ? (
<Spinner /> <Spinner />
) : ( ) : (
capitalizeFirstLetter(i18n.t('save')) capitalizeFirstLetter(i18n.t("save"))
)} )}
</button> </button>
</div> </div>
@ -213,8 +213,8 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
this.context.router.history.push('/'); this.context.router.history.push("/");
this.state.loading = false; this.state.loading = false;
this.setState(this.state); this.setState(this.state);
return; return;
@ -222,7 +222,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
let data = wsJsonToRes<SiteResponse>(msg).data; let data = wsJsonToRes<SiteResponse>(msg).data;
this.state.siteRes.site_view = data.site_view; this.state.siteRes.site_view = data.site_view;
this.setState(this.state); this.setState(this.state);
toast(i18n.t('site_saved')); toast(i18n.t("site_saved"));
} else if (op == UserOperation.GetSiteConfig) { } else if (op == UserOperation.GetSiteConfig) {
let data = wsJsonToRes<GetSiteConfigResponse>(msg).data; let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
this.state.siteConfigRes = data; this.state.siteConfigRes = data;
@ -236,7 +236,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
this.state.siteConfigRes = data; this.state.siteConfigRes = data;
this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson; this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson;
this.state.siteConfigLoading = false; this.state.siteConfigLoading = false;
toast(i18n.t('site_saved')); toast(i18n.t("site_saved"));
this.setState(this.state); this.setState(this.state);
} }
} }

View file

@ -1,16 +1,16 @@
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 { Helmet } from "inferno-helmet";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { routes } from '../routes'; import { routes } from "../routes";
import { Navbar } from './navbar'; import { Navbar } from "./navbar";
import { Footer } from './footer'; import { Footer } from "./footer";
import { NoMatch } from './no-match'; import { NoMatch } from "./no-match";
import { Theme } from './theme'; import { Theme } from "./theme";
import { Symbols } from './symbols'; import { Symbols } from "./symbols";
import { GetSiteResponse } from 'lemmy-js-client'; import { GetSiteResponse } from "lemmy-js-client";
import './styles.scss'; import "./styles.scss";
export interface AppProps { export interface AppProps {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;

View file

@ -1,5 +1,5 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { PictrsImage } from './pictrs-image'; import { PictrsImage } from "./pictrs-image";
interface BannerIconHeaderProps { interface BannerIconHeaderProps {
banner?: string; banner?: string;

View file

@ -1,6 +1,6 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { Icon } from './icon'; import { Icon } from "./icon";
interface CakeDayProps { interface CakeDayProps {
creatorName: string; creatorName: string;
@ -19,6 +19,6 @@ export class CakeDay extends Component<CakeDayProps, any> {
} }
cakeDayTippy(): string { cakeDayTippy(): string {
return i18n.t('cake_day_info', { creator_name: this.props.creatorName }); return i18n.t("cake_day_info", { creator_name: this.props.creatorName });
} }
} }

View file

@ -1,13 +1,13 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { Link } from 'inferno-router'; import { Link } from "inferno-router";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
CreateComment, CreateComment,
EditComment, EditComment,
UserOperation, UserOperation,
CommentResponse, CommentResponse,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { CommentNode as CommentNodeI } from '../interfaces'; import { CommentNode as CommentNodeI } from "../interfaces";
import { import {
authField, authField,
capitalizeFirstLetter, capitalizeFirstLetter,
@ -15,12 +15,12 @@ import {
wsJsonToRes, wsJsonToRes,
wsSubscribe, wsSubscribe,
wsUserOp, wsUserOp,
} from '../utils'; } from "../utils";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { T } from 'inferno-i18next'; import { T } from "inferno-i18next";
import { MarkdownTextArea } from './markdown-textarea'; import { MarkdownTextArea } from "./markdown-textarea";
import { Icon } from './icon'; import { Icon } from "./icon";
interface CommentFormProps { interface CommentFormProps {
postId?: number; postId?: number;
@ -41,12 +41,12 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
private subscription: Subscription; private subscription: Subscription;
private emptyState: CommentFormState = { private emptyState: CommentFormState = {
buttonTitle: !this.props.node buttonTitle: !this.props.node
? capitalizeFirstLetter(i18n.t('post')) ? capitalizeFirstLetter(i18n.t("post"))
: this.props.edit : this.props.edit
? capitalizeFirstLetter(i18n.t('save')) ? capitalizeFirstLetter(i18n.t("save"))
: capitalizeFirstLetter(i18n.t('reply')), : capitalizeFirstLetter(i18n.t("reply")),
finished: false, finished: false,
formId: 'empty_form', formId: "empty_form",
}; };
constructor(props: any, context: any) { constructor(props: any, context: any) {

View file

@ -1,5 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Link } from 'inferno-router'; import { Link } from "inferno-router";
import { import {
CreateCommentLike, CreateCommentLike,
DeleteComment, DeleteComment,
@ -17,9 +17,9 @@ import {
TransferSite, TransferSite,
CommentView, CommentView,
UserMentionView, UserMentionView,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { CommentNode as CommentNodeI, BanType } from '../interfaces'; import { CommentNode as CommentNodeI, BanType } from "../interfaces";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { import {
mdToHtml, mdToHtml,
getUnixTime, getUnixTime,
@ -29,15 +29,15 @@ import {
colorList, colorList,
wsClient, wsClient,
authField, authField,
} from '../utils'; } from "../utils";
import moment from 'moment'; import moment from "moment";
import { MomentTime } from './moment-time'; import { MomentTime } from "./moment-time";
import { CommentForm } from './comment-form'; import { CommentForm } from "./comment-form";
import { CommentNodes } from './comment-nodes'; import { CommentNodes } from "./comment-nodes";
import { UserListing } from './user-listing'; import { UserListing } from "./user-listing";
import { CommunityLink } from './community-link'; import { CommunityLink } from "./community-link";
import { Icon, Spinner } from './icon'; import { Icon, Spinner } from "./icon";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
interface CommentNodeState { interface CommentNodeState {
showReply: boolean; showReply: boolean;
@ -137,14 +137,14 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
return ( return (
<div <div
className={`comment ${ className={`comment ${
cv.comment.parent_id && !this.props.noIndent ? 'ml-1' : '' cv.comment.parent_id && !this.props.noIndent ? "ml-1" : ""
}`} }`}
> >
<div <div
id={`comment-${cv.comment.id}`} id={`comment-${cv.comment.id}`}
className={`details comment-node py-2 ${ className={`details comment-node py-2 ${
!this.props.noBorder ? 'border-top border-light' : '' !this.props.noBorder ? "border-top border-light" : ""
} ${this.isCommentNew ? 'mark' : ''}`} } ${this.isCommentNew ? "mark" : ""}`}
style={ style={
!this.props.noIndent && !this.props.noIndent &&
cv.comment.parent_id && cv.comment.parent_id &&
@ -152,7 +152,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
} }
> >
<div <div
class={`${!this.props.noIndent && cv.comment.parent_id && 'ml-2'}`} class={`${!this.props.noIndent && cv.comment.parent_id && "ml-2"}`}
> >
<div class="d-flex flex-wrap align-items-center text-muted small"> <div class="d-flex flex-wrap align-items-center text-muted small">
<span class="mr-2"> <span class="mr-2">
@ -161,27 +161,27 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{this.isMod && ( {this.isMod && (
<div className="badge badge-light d-none d-sm-inline mr-2"> <div className="badge badge-light d-none d-sm-inline mr-2">
{i18n.t('mod')} {i18n.t("mod")}
</div> </div>
)} )}
{this.isAdmin && ( {this.isAdmin && (
<div className="badge badge-light d-none d-sm-inline mr-2"> <div className="badge badge-light d-none d-sm-inline mr-2">
{i18n.t('admin')} {i18n.t("admin")}
</div> </div>
)} )}
{this.isPostCreator && ( {this.isPostCreator && (
<div className="badge badge-light d-none d-sm-inline mr-2"> <div className="badge badge-light d-none d-sm-inline mr-2">
{i18n.t('creator')} {i18n.t("creator")}
</div> </div>
)} )}
{(cv.creator_banned_from_community || cv.creator.banned) && ( {(cv.creator_banned_from_community || cv.creator.banned) && (
<div className="badge badge-danger mr-2"> <div className="badge badge-danger mr-2">
{i18n.t('banned')} {i18n.t("banned")}
</div> </div>
)} )}
{this.props.showCommunity && ( {this.props.showCommunity && (
<> <>
<span class="mx-1">{i18n.t('to')}</span> <span class="mx-1">{i18n.t("to")}</span>
<CommunityLink community={cv.community} /> <CommunityLink community={cv.community} />
<span class="mx-2"></span> <span class="mx-2"></span>
<Link className="mr-2" to={`/post/${cv.post.id}`}> <Link className="mr-2" to={`/post/${cv.post.id}`}>
@ -193,10 +193,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
onClick={linkEvent(this, this.handleCommentCollapse)} onClick={linkEvent(this, this.handleCommentCollapse)}
aria-label={ aria-label={
this.state.collapsed ? i18n.t('expand') : i18n.t('collapse') this.state.collapsed ? i18n.t("expand") : i18n.t("collapse")
} }
> >
{this.state.collapsed ? '+' : '—'} {this.state.collapsed ? "+" : "—"}
</button> </button>
{/* This is an expanding spacer for mobile */} {/* This is an expanding spacer for mobile */}
<div className="mr-lg-4 flex-grow-1 flex-lg-grow-0 unselectable pointer mx-2"></div> <div className="mr-lg-4 flex-grow-1 flex-lg-grow-0 unselectable pointer mx-2"></div>
@ -207,7 +207,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
> >
<span <span
class="mr-1 font-weight-bold" class="mr-1 font-weight-bold"
aria-label={i18n.t('number_of_points', { aria-label={i18n.t("number_of_points", {
count: this.state.score, count: this.state.score,
})} })}
> >
@ -249,13 +249,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
onClick={linkEvent(this, this.handleMarkRead)} onClick={linkEvent(this, this.handleMarkRead)}
data-tippy-content={ data-tippy-content={
this.commentOrMentionRead this.commentOrMentionRead
? i18n.t('mark_as_unread') ? i18n.t("mark_as_unread")
: i18n.t('mark_as_read') : i18n.t("mark_as_read")
} }
aria-label={ aria-label={
this.commentOrMentionRead this.commentOrMentionRead
? i18n.t('mark_as_unread') ? i18n.t("mark_as_unread")
: i18n.t('mark_as_read') : i18n.t("mark_as_read")
} }
> >
{this.state.readLoading ? ( {this.state.readLoading ? (
@ -264,7 +264,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<Icon <Icon
icon="check" icon="check"
classes={`icon-inline ${ classes={`icon-inline ${
this.commentOrMentionRead && 'text-success' this.commentOrMentionRead && "text-success"
}`} }`}
/> />
)} )}
@ -274,11 +274,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<> <>
<button <button
className={`btn btn-link btn-animate ${ className={`btn btn-link btn-animate ${
this.state.my_vote == 1 ? 'text-info' : 'text-muted' this.state.my_vote == 1 ? "text-info" : "text-muted"
}`} }`}
onClick={linkEvent(node, this.handleCommentUpvote)} onClick={linkEvent(node, this.handleCommentUpvote)}
data-tippy-content={i18n.t('upvote')} data-tippy-content={i18n.t("upvote")}
aria-label={i18n.t('upvote')} aria-label={i18n.t("upvote")}
> >
<Icon icon="arrow-up1" classes="icon-inline" /> <Icon icon="arrow-up1" classes="icon-inline" />
{this.state.upvotes !== this.state.score && ( {this.state.upvotes !== this.state.score && (
@ -289,12 +289,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<button <button
className={`btn btn-link btn-animate ${ className={`btn btn-link btn-animate ${
this.state.my_vote == -1 this.state.my_vote == -1
? 'text-danger' ? "text-danger"
: 'text-muted' : "text-muted"
}`} }`}
onClick={linkEvent(node, this.handleCommentDownvote)} onClick={linkEvent(node, this.handleCommentDownvote)}
data-tippy-content={i18n.t('downvote')} data-tippy-content={i18n.t("downvote")}
aria-label={i18n.t('downvote')} aria-label={i18n.t("downvote")}
> >
<Icon icon="arrow-down1" classes="icon-inline" /> <Icon icon="arrow-down1" classes="icon-inline" />
{this.state.upvotes !== this.state.score && ( {this.state.upvotes !== this.state.score && (
@ -305,8 +305,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleReplyClick)} onClick={linkEvent(this, this.handleReplyClick)}
data-tippy-content={i18n.t('reply')} data-tippy-content={i18n.t("reply")}
aria-label={i18n.t('reply')} aria-label={i18n.t("reply")}
> >
<Icon icon="reply1" classes="icon-inline" /> <Icon icon="reply1" classes="icon-inline" />
</button> </button>
@ -314,8 +314,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<button <button
className="btn btn-link btn-animate text-muted" className="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleShowAdvanced)} onClick={linkEvent(this, this.handleShowAdvanced)}
data-tippy-content={i18n.t('more')} data-tippy-content={i18n.t("more")}
aria-label={i18n.t('more')} aria-label={i18n.t("more")}
> >
<Icon icon="more-vertical" classes="icon-inline" /> <Icon icon="more-vertical" classes="icon-inline" />
</button> </button>
@ -326,7 +326,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<Link <Link
className="text-muted" className="text-muted"
to={`/create_private_message/recipient/${cv.creator.id}`} to={`/create_private_message/recipient/${cv.creator.id}`}
title={i18n.t('message').toLowerCase()} title={i18n.t("message").toLowerCase()}
> >
<Icon icon="mail" /> <Icon icon="mail" />
</Link> </Link>
@ -340,10 +340,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this.handleSaveCommentClick this.handleSaveCommentClick
)} )}
data-tippy-content={ data-tippy-content={
cv.saved ? i18n.t('unsave') : i18n.t('save') cv.saved ? i18n.t("unsave") : i18n.t("save")
} }
aria-label={ aria-label={
cv.saved ? i18n.t('unsave') : i18n.t('save') cv.saved ? i18n.t("unsave") : i18n.t("save")
} }
> >
{this.state.saveLoading ? ( {this.state.saveLoading ? (
@ -352,7 +352,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<Icon <Icon
icon="star" icon="star"
classes={`icon-inline ${ classes={`icon-inline ${
cv.saved && 'text-warning' cv.saved && "text-warning"
}`} }`}
/> />
)} )}
@ -360,13 +360,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<button <button
className="btn btn-link btn-animate text-muted" className="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleViewSource)} onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t('view_source')} data-tippy-content={i18n.t("view_source")}
aria-label={i18n.t('view_source')} aria-label={i18n.t("view_source")}
> >
<Icon <Icon
icon="file-text" icon="file-text"
classes={`icon-inline ${ classes={`icon-inline ${
this.state.viewSource && 'text-success' this.state.viewSource && "text-success"
}`} }`}
/> />
</button> </button>
@ -375,8 +375,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleEditClick)} onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t('edit')} data-tippy-content={i18n.t("edit")}
aria-label={i18n.t('edit')} aria-label={i18n.t("edit")}
> >
<Icon icon="edit" classes="icon-inline" /> <Icon icon="edit" classes="icon-inline" />
</button> </button>
@ -388,19 +388,19 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)} )}
data-tippy-content={ data-tippy-content={
!cv.comment.deleted !cv.comment.deleted
? i18n.t('delete') ? i18n.t("delete")
: i18n.t('restore') : i18n.t("restore")
} }
aria-label={ aria-label={
!cv.comment.deleted !cv.comment.deleted
? i18n.t('delete') ? i18n.t("delete")
: i18n.t('restore') : i18n.t("restore")
} }
> >
<Icon <Icon
icon="trash" icon="trash"
classes={`icon-inline ${ classes={`icon-inline ${
cv.comment.deleted && 'text-danger' cv.comment.deleted && "text-danger"
}`} }`}
/> />
</button> </button>
@ -416,9 +416,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleModRemoveShow this.handleModRemoveShow
)} )}
aria-label={i18n.t('remove')} aria-label={i18n.t("remove")}
> >
{i18n.t('remove')} {i18n.t("remove")}
</button> </button>
) : ( ) : (
<button <button
@ -427,9 +427,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleModRemoveSubmit this.handleModRemoveSubmit
)} )}
aria-label={i18n.t('restore')} aria-label={i18n.t("restore")}
> >
{i18n.t('restore')} {i18n.t("restore")}
</button> </button>
)} )}
</> </>
@ -445,9 +445,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleModBanFromCommunityShow this.handleModBanFromCommunityShow
)} )}
aria-label={i18n.t('ban')} aria-label={i18n.t("ban")}
> >
{i18n.t('ban')} {i18n.t("ban")}
</button> </button>
) : ( ) : (
<button <button
@ -456,9 +456,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleModBanFromCommunitySubmit this.handleModBanFromCommunitySubmit
)} )}
aria-label={i18n.t('unban')} aria-label={i18n.t("unban")}
> >
{i18n.t('unban')} {i18n.t("unban")}
</button> </button>
))} ))}
{!cv.creator_banned_from_community && {!cv.creator_banned_from_community &&
@ -472,21 +472,21 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)} )}
aria-label={ aria-label={
this.isMod this.isMod
? i18n.t('remove_as_mod') ? i18n.t("remove_as_mod")
: i18n.t('appoint_as_mod') : i18n.t("appoint_as_mod")
} }
> >
{this.isMod {this.isMod
? i18n.t('remove_as_mod') ? i18n.t("remove_as_mod")
: i18n.t('appoint_as_mod')} : i18n.t("appoint_as_mod")}
</button> </button>
) : ( ) : (
<> <>
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
aria-label={i18n.t('are_you_sure')} aria-label={i18n.t("are_you_sure")}
> >
{i18n.t('are_you_sure')} {i18n.t("are_you_sure")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
@ -494,9 +494,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleAddModToCommunity this.handleAddModToCommunity
)} )}
aria-label={i18n.t('yes')} aria-label={i18n.t("yes")}
> >
{i18n.t('yes')} {i18n.t("yes")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
@ -504,9 +504,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleCancelConfirmAppointAsMod this.handleCancelConfirmAppointAsMod
)} )}
aria-label={i18n.t('no')} aria-label={i18n.t("no")}
> >
{i18n.t('no')} {i18n.t("no")}
</button> </button>
</> </>
))} ))}
@ -523,17 +523,17 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleShowConfirmTransferCommunity this.handleShowConfirmTransferCommunity
)} )}
aria-label={i18n.t('transfer_community')} aria-label={i18n.t("transfer_community")}
> >
{i18n.t('transfer_community')} {i18n.t("transfer_community")}
</button> </button>
) : ( ) : (
<> <>
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
aria-label={i18n.t('are_you_sure')} aria-label={i18n.t("are_you_sure")}
> >
{i18n.t('are_you_sure')} {i18n.t("are_you_sure")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
@ -541,9 +541,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleTransferCommunity this.handleTransferCommunity
)} )}
aria-label={i18n.t('yes')} aria-label={i18n.t("yes")}
> >
{i18n.t('yes')} {i18n.t("yes")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
@ -552,9 +552,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this this
.handleCancelShowConfirmTransferCommunity .handleCancelShowConfirmTransferCommunity
)} )}
aria-label={i18n.t('no')} aria-label={i18n.t("no")}
> >
{i18n.t('no')} {i18n.t("no")}
</button> </button>
</> </>
))} ))}
@ -569,9 +569,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleModBanShow this.handleModBanShow
)} )}
aria-label={i18n.t('ban_from_site')} aria-label={i18n.t("ban_from_site")}
> >
{i18n.t('ban_from_site')} {i18n.t("ban_from_site")}
</button> </button>
) : ( ) : (
<button <button
@ -580,9 +580,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleModBanSubmit this.handleModBanSubmit
)} )}
aria-label={i18n.t('unban_from_site')} aria-label={i18n.t("unban_from_site")}
> >
{i18n.t('unban_from_site')} {i18n.t("unban_from_site")}
</button> </button>
))} ))}
{!cv.creator.banned && {!cv.creator.banned &&
@ -596,18 +596,18 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)} )}
aria-label={ aria-label={
this.isAdmin this.isAdmin
? i18n.t('remove_as_admin') ? i18n.t("remove_as_admin")
: i18n.t('appoint_as_admin') : i18n.t("appoint_as_admin")
} }
> >
{this.isAdmin {this.isAdmin
? i18n.t('remove_as_admin') ? i18n.t("remove_as_admin")
: i18n.t('appoint_as_admin')} : i18n.t("appoint_as_admin")}
</button> </button>
) : ( ) : (
<> <>
<button class="btn btn-link btn-animate text-muted"> <button class="btn btn-link btn-animate text-muted">
{i18n.t('are_you_sure')} {i18n.t("are_you_sure")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
@ -615,9 +615,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleAddAdmin this.handleAddAdmin
)} )}
aria-label={i18n.t('yes')} aria-label={i18n.t("yes")}
> >
{i18n.t('yes')} {i18n.t("yes")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
@ -625,9 +625,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleCancelConfirmAppointAsAdmin this.handleCancelConfirmAppointAsAdmin
)} )}
aria-label={i18n.t('no')} aria-label={i18n.t("no")}
> >
{i18n.t('no')} {i18n.t("no")}
</button> </button>
</> </>
))} ))}
@ -644,17 +644,17 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleShowConfirmTransferSite this.handleShowConfirmTransferSite
)} )}
aria-label={i18n.t('transfer_site')} aria-label={i18n.t("transfer_site")}
> >
{i18n.t('transfer_site')} {i18n.t("transfer_site")}
</button> </button>
) : ( ) : (
<> <>
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
aria-label={i18n.t('are_you_sure')} aria-label={i18n.t("are_you_sure")}
> >
{i18n.t('are_you_sure')} {i18n.t("are_you_sure")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
@ -662,9 +662,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleTransferSite this.handleTransferSite
)} )}
aria-label={i18n.t('yes')} aria-label={i18n.t("yes")}
> >
{i18n.t('yes')} {i18n.t("yes")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
@ -672,9 +672,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this, this,
this.handleCancelShowConfirmTransferSite this.handleCancelShowConfirmTransferSite
)} )}
aria-label={i18n.t('no')} aria-label={i18n.t("no")}
> >
{i18n.t('no')} {i18n.t("no")}
</button> </button>
</> </>
))} ))}
@ -698,22 +698,22 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
class="sr-only" class="sr-only"
htmlFor={`mod-remove-reason-${cv.comment.id}`} htmlFor={`mod-remove-reason-${cv.comment.id}`}
> >
{i18n.t('reason')} {i18n.t("reason")}
</label> </label>
<input <input
type="text" type="text"
id={`mod-remove-reason-${cv.comment.id}`} id={`mod-remove-reason-${cv.comment.id}`}
class="form-control mr-2" class="form-control mr-2"
placeholder={i18n.t('reason')} placeholder={i18n.t("reason")}
value={this.state.removeReason} value={this.state.removeReason}
onInput={linkEvent(this, this.handleModRemoveReasonChange)} onInput={linkEvent(this, this.handleModRemoveReasonChange)}
/> />
<button <button
type="submit" type="submit"
class="btn btn-secondary" class="btn btn-secondary"
aria-label={i18n.t('remove_comment')} aria-label={i18n.t("remove_comment")}
> >
{i18n.t('remove_comment')} {i18n.t("remove_comment")}
</button> </button>
</form> </form>
)} )}
@ -724,13 +724,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
class="col-form-label" class="col-form-label"
htmlFor={`mod-ban-reason-${cv.comment.id}`} htmlFor={`mod-ban-reason-${cv.comment.id}`}
> >
{i18n.t('reason')} {i18n.t("reason")}
</label> </label>
<input <input
type="text" type="text"
id={`mod-ban-reason-${cv.comment.id}`} id={`mod-ban-reason-${cv.comment.id}`}
class="form-control mr-2" class="form-control mr-2"
placeholder={i18n.t('reason')} placeholder={i18n.t("reason")}
value={this.state.banReason} value={this.state.banReason}
onInput={linkEvent(this, this.handleModBanReasonChange)} onInput={linkEvent(this, this.handleModBanReasonChange)}
/> />
@ -744,7 +744,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
onChange={linkEvent(this, this.handleModRemoveDataChange)} onChange={linkEvent(this, this.handleModRemoveDataChange)}
/> />
<label class="form-check-label" htmlFor="mod-ban-remove-data"> <label class="form-check-label" htmlFor="mod-ban-remove-data">
{i18n.t('remove_posts_comments')} {i18n.t("remove_posts_comments")}
</label> </label>
</div> </div>
</div> </div>
@ -758,9 +758,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<button <button
type="submit" type="submit"
class="btn btn-secondary" class="btn btn-secondary"
aria-label={i18n.t('ban')} aria-label={i18n.t("ban")}
> >
{i18n.t('ban')} {cv.creator.name} {i18n.t("ban")} {cv.creator.name}
</button> </button>
</div> </div>
</form> </form>
@ -800,7 +800,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<Link <Link
className="btn btn-link btn-animate text-muted" className="btn btn-link btn-animate text-muted"
to={`/post/${cv.post.id}/comment/${cv.comment.id}`} to={`/post/${cv.post.id}/comment/${cv.comment.id}`}
title={this.props.showContext ? i18n.t('show_context') : i18n.t('link')} title={this.props.showContext ? i18n.t("show_context") : i18n.t("link")}
> >
<Icon icon="link" classes="icon-inline" /> <Icon icon="link" classes="icon-inline" />
</Link> </Link>
@ -890,9 +890,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
get commentUnlessRemoved(): string { get commentUnlessRemoved(): string {
let comment = this.props.node.comment_view.comment; let comment = this.props.node.comment_view.comment;
return comment.removed return comment.removed
? `*${i18n.t('removed')}*` ? `*${i18n.t("removed")}*`
: comment.deleted : comment.deleted
? `*${i18n.t('deleted')}*` ? `*${i18n.t("deleted")}*`
: comment.content; : comment.content;
} }
@ -1212,7 +1212,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
} }
get isCommentNew(): boolean { get isCommentNew(): boolean {
let now = moment.utc().subtract(10, 'minutes'); let now = moment.utc().subtract(10, "minutes");
let then = moment.utc(this.props.node.comment_view.comment.published); let then = moment.utc(this.props.node.comment_view.comment.published);
return now.isBefore(then); return now.isBefore(then);
} }
@ -1235,24 +1235,24 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
get scoreColor() { get scoreColor() {
if (this.state.my_vote == 1) { if (this.state.my_vote == 1) {
return 'text-info'; return "text-info";
} else if (this.state.my_vote == -1) { } else if (this.state.my_vote == -1) {
return 'text-danger'; return "text-danger";
} else { } else {
return 'text-muted'; return "text-muted";
} }
} }
get pointsTippy(): string { get pointsTippy(): string {
let points = i18n.t('number_of_points', { let points = i18n.t("number_of_points", {
count: this.state.score, count: this.state.score,
}); });
let upvotes = i18n.t('number_of_upvotes', { let upvotes = i18n.t("number_of_upvotes", {
count: this.state.upvotes, count: this.state.upvotes,
}); });
let downvotes = i18n.t('number_of_downvotes', { let downvotes = i18n.t("number_of_downvotes", {
count: this.state.downvotes, count: this.state.downvotes,
}); });

View file

@ -1,7 +1,7 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { CommentNode as CommentNodeI } from '../interfaces'; import { CommentNode as CommentNodeI } from "../interfaces";
import { CommunityModeratorView, UserViewSafe } from 'lemmy-js-client'; import { CommunityModeratorView, UserViewSafe } from "lemmy-js-client";
import { CommentNode } from './comment-node'; import { CommentNode } from "./comment-node";
interface CommentNodesProps { interface CommentNodesProps {
nodes: CommentNodeI[]; nodes: CommentNodeI[];
@ -18,10 +18,7 @@ interface CommentNodesProps {
enableDownvotes: boolean; enableDownvotes: boolean;
} }
export class CommentNodes extends Component< export class CommentNodes extends Component<CommentNodesProps, any> {
CommentNodesProps,
any
> {
constructor(props: any, context: any) { constructor(props: any, context: any) {
super(props, context); super(props, context);
} }

View file

@ -1,6 +1,6 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { HtmlTags } from './html-tags'; import { HtmlTags } from "./html-tags";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
UserOperation, UserOperation,
CommunityView, CommunityView,
@ -11,8 +11,8 @@ import {
SortType, SortType,
ListingType, ListingType,
SiteView, SiteView,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService } from '../services'; import { WebSocketService } from "../services";
import { import {
wsJsonToRes, wsJsonToRes,
toast, toast,
@ -24,11 +24,11 @@ import {
wsClient, wsClient,
authField, authField,
setOptionalAuth, setOptionalAuth,
} from '../utils'; } from "../utils";
import { CommunityLink } from './community-link'; import { CommunityLink } from "./community-link";
import { Spinner } from './icon'; import { Spinner } from "./icon";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { InitialFetchRequest } from 'shared/interfaces'; import { InitialFetchRequest } from "shared/interfaces";
const communityLimit = 100; const communityLimit = 100;
@ -52,7 +52,7 @@ export class Communities extends Component<any, CommunitiesState> {
loading: true, loading: true,
page: getPageFromProps(this.props), page: getPageFromProps(this.props),
site_view: this.isoData.site_res.site_view, site_view: this.isoData.site_res.site_view,
searchText: '', searchText: "",
}; };
constructor(props: any, context: any) { constructor(props: any, context: any) {
@ -94,7 +94,7 @@ export class Communities extends Component<any, CommunitiesState> {
} }
get documentTitle(): string { get documentTitle(): string {
return `${i18n.t('communities')} - ${this.state.site_view.site.name}`; return `${i18n.t("communities")} - ${this.state.site_view.site.name}`;
} }
render() { render() {
@ -112,7 +112,7 @@ export class Communities extends Component<any, CommunitiesState> {
<div> <div>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h4>{i18n.t('list_of_communities')}</h4> <h4>{i18n.t("list_of_communities")}</h4>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="float-md-right">{this.searchForm()}</div> <div class="float-md-right">{this.searchForm()}</div>
@ -123,17 +123,17 @@ export class Communities extends Component<any, CommunitiesState> {
<table id="community_table" class="table table-sm table-hover"> <table id="community_table" class="table table-sm table-hover">
<thead class="pointer"> <thead class="pointer">
<tr> <tr>
<th>{i18n.t('name')}</th> <th>{i18n.t("name")}</th>
<th>{i18n.t('category')}</th> <th>{i18n.t("category")}</th>
<th class="text-right">{i18n.t('subscribers')}</th> <th class="text-right">{i18n.t("subscribers")}</th>
<th class="text-right"> <th class="text-right">
{i18n.t('users')} / {i18n.t('month')} {i18n.t("users")} / {i18n.t("month")}
</th> </th>
<th class="text-right d-none d-lg-table-cell"> <th class="text-right d-none d-lg-table-cell">
{i18n.t('posts')} {i18n.t("posts")}
</th> </th>
<th class="text-right d-none d-lg-table-cell"> <th class="text-right d-none d-lg-table-cell">
{i18n.t('comments')} {i18n.t("comments")}
</th> </th>
<th></th> <th></th>
</tr> </tr>
@ -163,7 +163,7 @@ export class Communities extends Component<any, CommunitiesState> {
this.handleUnsubscribe this.handleUnsubscribe
)} )}
> >
{i18n.t('unsubscribe')} {i18n.t("unsubscribe")}
</span> </span>
) : ( ) : (
<span <span
@ -174,7 +174,7 @@ export class Communities extends Component<any, CommunitiesState> {
this.handleSubscribe this.handleSubscribe
)} )}
> >
{i18n.t('subscribe')} {i18n.t("subscribe")}
</span> </span>
)} )}
</td> </td>
@ -201,16 +201,16 @@ export class Communities extends Component<any, CommunitiesState> {
id="communities-search" id="communities-search"
class="form-control mr-2 mb-2" class="form-control mr-2 mb-2"
value={this.state.searchText} value={this.state.searchText}
placeholder={`${i18n.t('search')}...`} placeholder={`${i18n.t("search")}...`}
onInput={linkEvent(this, this.handleSearchChange)} onInput={linkEvent(this, this.handleSearchChange)}
required required
minLength={3} minLength={3}
/> />
<label class="sr-only" htmlFor="communities-search"> <label class="sr-only" htmlFor="communities-search">
{i18n.t('search')} {i18n.t("search")}
</label> </label>
<button type="submit" class="btn btn-secondary mr-2 mb-2"> <button type="submit" class="btn btn-secondary mr-2 mb-2">
<span>{i18n.t('search')}</span> <span>{i18n.t("search")}</span>
</button> </button>
</form> </form>
); );
@ -224,7 +224,7 @@ export class Communities extends Component<any, CommunitiesState> {
class="btn btn-secondary mr-1" class="btn btn-secondary mr-1"
onClick={linkEvent(this, this.prevPage)} onClick={linkEvent(this, this.prevPage)}
> >
{i18n.t('prev')} {i18n.t("prev")}
</button> </button>
)} )}
@ -233,7 +233,7 @@ export class Communities extends Component<any, CommunitiesState> {
class="btn btn-secondary" class="btn btn-secondary"
onClick={linkEvent(this, this.nextPage)} onClick={linkEvent(this, this.nextPage)}
> >
{i18n.t('next')} {i18n.t("next")}
</button> </button>
)} )}
</div> </div>
@ -297,7 +297,7 @@ export class Communities extends Component<any, CommunitiesState> {
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split('/'); let pathSplit = req.path.split("/");
let page = pathSplit[3] ? Number(pathSplit[3]) : 1; let page = pathSplit[3] ? Number(pathSplit[3]) : 1;
let listCommunitiesForm: ListCommunities = { let listCommunitiesForm: ListCommunities = {
type_: ListingType.All, type_: ListingType.All,
@ -313,7 +313,7 @@ export class Communities extends Component<any, CommunitiesState> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
return; return;
} else if (op == UserOperation.ListCommunities) { } else if (op == UserOperation.ListCommunities) {
let data = wsJsonToRes<ListCommunitiesResponse>(msg).data; let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;

View file

@ -1,6 +1,6 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Prompt } from 'inferno-router'; import { Prompt } from "inferno-router";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
EditCommunity, EditCommunity,
CreateCommunity, CreateCommunity,
@ -8,8 +8,8 @@ import {
Category, Category,
CommunityResponse, CommunityResponse,
CommunityView, CommunityView,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService } from '../services'; import { WebSocketService } from "../services";
import { import {
wsJsonToRes, wsJsonToRes,
capitalizeFirstLetter, capitalizeFirstLetter,
@ -19,12 +19,12 @@ import {
wsUserOp, wsUserOp,
wsClient, wsClient,
authField, authField,
} from '../utils'; } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { MarkdownTextArea } from './markdown-textarea'; import { MarkdownTextArea } from "./markdown-textarea";
import { ImageUploadForm } from './image-upload-form'; import { ImageUploadForm } from "./image-upload-form";
import { Icon, Spinner } from './icon'; import { Icon, Spinner } from "./icon";
interface CommunityFormProps { interface CommunityFormProps {
community_view?: CommunityView; // If a community is given, that means this is an edit community_view?: CommunityView; // If a community is given, that means this is an edit
@ -122,16 +122,16 @@ export class CommunityForm extends Component<
this.state.communityForm.title || this.state.communityForm.title ||
this.state.communityForm.description) this.state.communityForm.description)
} }
message={i18n.t('block_leaving')} message={i18n.t("block_leaving")}
/> />
<form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}> <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
{!this.props.community_view && ( {!this.props.community_view && (
<div class="form-group row"> <div class="form-group row">
<label class="col-12 col-form-label" htmlFor="community-name"> <label class="col-12 col-form-label" htmlFor="community-name">
{i18n.t('name')} {i18n.t("name")}
<span <span
class="pointer unselectable ml-2 text-muted" class="pointer unselectable ml-2 text-muted"
data-tippy-content={i18n.t('name_explain')} data-tippy-content={i18n.t("name_explain")}
> >
<Icon icon="help-circle" classes="icon-inline" /> <Icon icon="help-circle" classes="icon-inline" />
</span> </span>
@ -147,17 +147,17 @@ export class CommunityForm extends Component<
minLength={3} minLength={3}
maxLength={20} maxLength={20}
pattern="[a-z0-9_]+" pattern="[a-z0-9_]+"
title={i18n.t('community_reqs')} title={i18n.t("community_reqs")}
/> />
</div> </div>
</div> </div>
)} )}
<div class="form-group row"> <div class="form-group row">
<label class="col-12 col-form-label" htmlFor="community-title"> <label class="col-12 col-form-label" htmlFor="community-title">
{i18n.t('display_name')} {i18n.t("display_name")}
<span <span
class="pointer unselectable ml-2 text-muted" class="pointer unselectable ml-2 text-muted"
data-tippy-content={i18n.t('display_name_explain')} data-tippy-content={i18n.t("display_name_explain")}
> >
<Icon icon="help-circle" classes="icon-inline" /> <Icon icon="help-circle" classes="icon-inline" />
</span> </span>
@ -176,9 +176,9 @@ export class CommunityForm extends Component<
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{i18n.t('icon')}</label> <label>{i18n.t("icon")}</label>
<ImageUploadForm <ImageUploadForm
uploadTitle={i18n.t('upload_icon')} uploadTitle={i18n.t("upload_icon")}
imageSrc={this.state.communityForm.icon} imageSrc={this.state.communityForm.icon}
onUpload={this.handleIconUpload} onUpload={this.handleIconUpload}
onRemove={this.handleIconRemove} onRemove={this.handleIconRemove}
@ -186,9 +186,9 @@ export class CommunityForm extends Component<
/> />
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{i18n.t('banner')}</label> <label>{i18n.t("banner")}</label>
<ImageUploadForm <ImageUploadForm
uploadTitle={i18n.t('upload_banner')} uploadTitle={i18n.t("upload_banner")}
imageSrc={this.state.communityForm.banner} imageSrc={this.state.communityForm.banner}
onUpload={this.handleBannerUpload} onUpload={this.handleBannerUpload}
onRemove={this.handleBannerRemove} onRemove={this.handleBannerRemove}
@ -196,7 +196,7 @@ export class CommunityForm extends Component<
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-12 col-form-label" htmlFor={this.id}> <label class="col-12 col-form-label" htmlFor={this.id}>
{i18n.t('sidebar')} {i18n.t("sidebar")}
</label> </label>
<div class="col-12"> <div class="col-12">
<MarkdownTextArea <MarkdownTextArea
@ -207,7 +207,7 @@ export class CommunityForm extends Component<
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-12 col-form-label" htmlFor="community-category"> <label class="col-12 col-form-label" htmlFor="community-category">
{i18n.t('category')} {i18n.t("category")}
</label> </label>
<div class="col-12"> <div class="col-12">
<select <select
@ -235,7 +235,7 @@ export class CommunityForm extends Component<
onChange={linkEvent(this, this.handleCommunityNsfwChange)} onChange={linkEvent(this, this.handleCommunityNsfwChange)}
/> />
<label class="form-check-label" htmlFor="community-nsfw"> <label class="form-check-label" htmlFor="community-nsfw">
{i18n.t('nsfw')} {i18n.t("nsfw")}
</label> </label>
</div> </div>
</div> </div>
@ -251,9 +251,9 @@ export class CommunityForm extends Component<
{this.state.loading ? ( {this.state.loading ? (
<Spinner /> <Spinner />
) : this.props.community_view ? ( ) : this.props.community_view ? (
capitalizeFirstLetter(i18n.t('save')) capitalizeFirstLetter(i18n.t("save"))
) : ( ) : (
capitalizeFirstLetter(i18n.t('create')) capitalizeFirstLetter(i18n.t("create"))
)} )}
</button> </button>
{this.props.community_view && ( {this.props.community_view && (
@ -262,7 +262,7 @@ export class CommunityForm extends Component<
class="btn btn-secondary" class="btn btn-secondary"
onClick={linkEvent(this, this.handleCancel)} onClick={linkEvent(this, this.handleCancel)}
> >
{i18n.t('cancel')} {i18n.t("cancel")}
</button> </button>
)} )}
</div> </div>
@ -324,7 +324,7 @@ export class CommunityForm extends Component<
} }
handleIconRemove() { handleIconRemove() {
this.state.communityForm.icon = ''; this.state.communityForm.icon = "";
this.setState(this.state); this.setState(this.state);
} }
@ -334,14 +334,14 @@ export class CommunityForm extends Component<
} }
handleBannerRemove() { handleBannerRemove() {
this.state.communityForm.banner = ''; this.state.communityForm.banner = "";
this.setState(this.state); this.setState(this.state);
} }
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
this.state.loading = false; this.state.loading = false;
this.setState(this.state); this.setState(this.state);
return; return;

View file

@ -1,8 +1,8 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { Link } from 'inferno-router'; import { Link } from "inferno-router";
import { CommunitySafe } from 'lemmy-js-client'; import { CommunitySafe } from "lemmy-js-client";
import { hostname, showAvatars } from '../utils'; import { hostname, showAvatars } from "../utils";
import { PictrsImage } from './pictrs-image'; import { PictrsImage } from "./pictrs-image";
interface CommunityLinkProps { interface CommunityLinkProps {
// TODO figure this out better // TODO figure this out better
@ -39,7 +39,7 @@ export class CommunityLink extends Component<CommunityLinkProps, any> {
return ( return (
<Link <Link
title={apubName} title={apubName}
className={`${this.props.muted ? 'text-muted' : ''}`} className={`${this.props.muted ? "text-muted" : ""}`}
to={link} to={link}
> >
{!this.props.hideAvatar && community.icon && showAvatars() && ( {!this.props.hideAvatar && community.icon && showAvatars() && (

View file

@ -1,6 +1,6 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { DataType, InitialFetchRequest } from '../interfaces'; import { DataType, InitialFetchRequest } from "../interfaces";
import { import {
UserOperation, UserOperation,
GetCommunityResponse, GetCommunityResponse,
@ -21,17 +21,17 @@ import {
GetSiteResponse, GetSiteResponse,
Category, Category,
ListCategoriesResponse, ListCategoriesResponse,
} from 'lemmy-js-client'; } from "lemmy-js-client";
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 { 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";
import { CommunityLink } from './community-link'; import { CommunityLink } from "./community-link";
import { BannerIconHeader } from './banner-icon-header'; import { BannerIconHeader } from "./banner-icon-header";
import { Icon, Spinner } from './icon'; import { Icon, Spinner } from "./icon";
import { import {
wsJsonToRes, wsJsonToRes,
fetchLimit, fetchLimit,
@ -56,8 +56,8 @@ import {
setOptionalAuth, setOptionalAuth,
saveScrollPosition, saveScrollPosition,
restoreScrollPosition, restoreScrollPosition,
} from '../utils'; } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
interface State { interface State {
communityRes: GetCommunityResponse; communityRes: GetCommunityResponse;
@ -160,7 +160,7 @@ export class Community extends Component<any, State> {
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split('/'); let pathSplit = req.path.split("/");
let promises: Promise<any>[] = []; let promises: Promise<any>[] = [];
// It can be /c/main, or /c/1 // It can be /c/main, or /c/1
@ -358,7 +358,7 @@ export class Community extends Component<any, State> {
class="btn btn-secondary mr-1" class="btn btn-secondary mr-1"
onClick={linkEvent(this, this.prevPage)} onClick={linkEvent(this, this.prevPage)}
> >
{i18n.t('prev')} {i18n.t("prev")}
</button> </button>
)} )}
{this.state.posts.length > 0 && ( {this.state.posts.length > 0 && (
@ -366,7 +366,7 @@ export class Community extends Component<any, State> {
class="btn btn-secondary" class="btn btn-secondary"
onClick={linkEvent(this, this.nextPage)} onClick={linkEvent(this, this.nextPage)}
> >
{i18n.t('next')} {i18n.t("next")}
</button> </button>
)} )}
</div> </div>
@ -436,8 +436,8 @@ export class Community extends Component<any, State> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
this.context.router.history.push('/'); this.context.router.history.push("/");
return; return;
} else if (msg.reconnect) { } else if (msg.reconnect) {
WebSocketService.Instance.send( WebSocketService.Instance.send(

View file

@ -1,15 +1,15 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { CommunityForm } from './community-form'; import { CommunityForm } from "./community-form";
import { HtmlTags } from './html-tags'; import { HtmlTags } from "./html-tags";
import { Spinner } from './icon'; import { Spinner } from "./icon";
import { import {
CommunityView, CommunityView,
UserOperation, UserOperation,
SiteView, SiteView,
ListCategoriesResponse, ListCategoriesResponse,
Category, Category,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { import {
setIsoData, setIsoData,
toast, toast,
@ -18,10 +18,10 @@ import {
isBrowser, isBrowser,
wsUserOp, wsUserOp,
wsClient, wsClient,
} from '../utils'; } from "../utils";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { InitialFetchRequest } from 'shared/interfaces'; import { InitialFetchRequest } from "shared/interfaces";
interface CreateCommunityState { interface CreateCommunityState {
site_view: SiteView; site_view: SiteView;
@ -46,7 +46,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
this.subscription = wsSubscribe(this.parseMessage); this.subscription = wsSubscribe(this.parseMessage);
if (!UserService.Instance.user && isBrowser()) { if (!UserService.Instance.user && isBrowser()) {
toast(i18n.t('not_logged_in'), 'danger'); toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`); this.context.router.history.push(`/login`);
} }
@ -66,7 +66,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
} }
get documentTitle(): string { get documentTitle(): string {
return `${i18n.t('create_community')} - ${this.state.site_view.site.name}`; return `${i18n.t("create_community")} - ${this.state.site_view.site.name}`;
} }
render() { render() {
@ -83,7 +83,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
) : ( ) : (
<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('create_community')}</h5> <h5>{i18n.t("create_community")}</h5>
<CommunityForm <CommunityForm
categories={this.state.categories} categories={this.state.categories}
onCreate={this.handleCommunityCreate} onCreate={this.handleCommunityCreate}

View file

@ -1,8 +1,8 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { PostForm } from './post-form'; import { PostForm } from "./post-form";
import { HtmlTags } from './html-tags'; import { HtmlTags } from "./html-tags";
import { Spinner } from './icon'; import { Spinner } from "./icon";
import { import {
authField, authField,
isBrowser, isBrowser,
@ -13,8 +13,8 @@ import {
wsJsonToRes, wsJsonToRes,
wsSubscribe, wsSubscribe,
wsUserOp, wsUserOp,
} from '../utils'; } from "../utils";
import { UserService, WebSocketService } from '../services'; import { UserService, WebSocketService } from "../services";
import { import {
UserOperation, UserOperation,
ListCommunitiesResponse, ListCommunitiesResponse,
@ -24,9 +24,9 @@ import {
SortType, SortType,
ListingType, ListingType,
PostView, PostView,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { InitialFetchRequest, PostFormParams } from 'shared/interfaces'; import { InitialFetchRequest, PostFormParams } from "shared/interfaces";
interface CreatePostState { interface CreatePostState {
site_view: SiteView; site_view: SiteView;
@ -49,7 +49,7 @@ export class CreatePost extends Component<any, CreatePostState> {
this.state = this.emptyState; this.state = this.emptyState;
if (!UserService.Instance.user && isBrowser()) { if (!UserService.Instance.user && isBrowser()) {
toast(i18n.t('not_logged_in'), 'danger'); toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`); this.context.router.history.push(`/login`);
} }
@ -84,7 +84,7 @@ export class CreatePost extends Component<any, CreatePostState> {
} }
get documentTitle(): string { get documentTitle(): string {
return `${i18n.t('create_post')} - ${this.state.site_view.site.name}`; return `${i18n.t("create_post")} - ${this.state.site_view.site.name}`;
} }
render() { render() {
@ -101,7 +101,7 @@ export class CreatePost extends Component<any, CreatePostState> {
) : ( ) : (
<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('create_post')}</h5> <h5>{i18n.t("create_post")}</h5>
<PostForm <PostForm
communities={this.state.communities} communities={this.state.communities}
onCreate={this.handlePostCreate} onCreate={this.handlePostCreate}
@ -119,13 +119,13 @@ export class CreatePost extends Component<any, CreatePostState> {
get params(): PostFormParams { get params(): PostFormParams {
let urlParams = new URLSearchParams(this.props.location.search); let urlParams = new URLSearchParams(this.props.location.search);
let params: PostFormParams = { let params: PostFormParams = {
name: urlParams.get('title'), name: urlParams.get("title"),
community_name: urlParams.get('community_name') || this.prevCommunityName, community_name: urlParams.get("community_name") || this.prevCommunityName,
community_id: urlParams.get('community_id') community_id: urlParams.get("community_id")
? Number(urlParams.get('community_id')) || this.prevCommunityId ? Number(urlParams.get("community_id")) || this.prevCommunityId
: null, : null,
body: urlParams.get('body'), body: urlParams.get("body"),
url: urlParams.get('url'), url: urlParams.get("url"),
}; };
return params; return params;
@ -136,8 +136,8 @@ export class CreatePost extends Component<any, CreatePostState> {
return this.props.match.params.name; return this.props.match.params.name;
} else if (this.props.location.state) { } else if (this.props.location.state) {
let lastLocation = this.props.location.state.prevPath; let lastLocation = this.props.location.state.prevPath;
if (lastLocation.includes('/c/')) { if (lastLocation.includes("/c/")) {
return lastLocation.split('/c/')[1]; return lastLocation.split("/c/")[1];
} }
} }
return null; return null;
@ -148,8 +148,8 @@ export class CreatePost extends Component<any, CreatePostState> {
return this.props.match.params.id; return this.props.match.params.id;
} else if (this.props.location.state) { } else if (this.props.location.state) {
let lastLocation = this.props.location.state.prevPath; let lastLocation = this.props.location.state.prevPath;
if (lastLocation.includes('/community/')) { if (lastLocation.includes("/community/")) {
return Number(lastLocation.split('/community/')[1]); return Number(lastLocation.split("/community/")[1]);
} }
} }
return null; return null;
@ -172,7 +172,7 @@ export class CreatePost extends Component<any, CreatePostState> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
return; return;
} else if (op == UserOperation.ListCommunities) { } else if (op == UserOperation.ListCommunities) {
let data = wsJsonToRes<ListCommunitiesResponse>(msg).data; let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;

View file

@ -1,9 +1,9 @@
import { Component } from 'inferno'; import { Component } from "inferno";
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 { HtmlTags } from "./html-tags";
import { Spinner } from './icon'; import { Spinner } from "./icon";
import { UserService, WebSocketService } from '../services'; import { UserService, WebSocketService } from "../services";
import { import {
SiteView, SiteView,
UserOperation, UserOperation,
@ -11,7 +11,7 @@ import {
UserViewSafe, UserViewSafe,
SortType, SortType,
GetUserDetails, GetUserDetails,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { import {
authField, authField,
getRecipientIdFromProps, getRecipientIdFromProps,
@ -22,9 +22,9 @@ import {
wsJsonToRes, wsJsonToRes,
wsSubscribe, wsSubscribe,
wsUserOp, wsUserOp,
} from '../utils'; } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { InitialFetchRequest } from 'shared/interfaces'; import { InitialFetchRequest } from "shared/interfaces";
interface CreatePrivateMessageState { interface CreatePrivateMessageState {
site_view: SiteView; site_view: SiteView;
@ -56,7 +56,7 @@ export class CreatePrivateMessage extends Component<
this.subscription = wsSubscribe(this.parseMessage); this.subscription = wsSubscribe(this.parseMessage);
if (!UserService.Instance.user) { if (!UserService.Instance.user) {
toast(i18n.t('not_logged_in'), 'danger'); toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`); this.context.router.history.push(`/login`);
} }
@ -80,7 +80,7 @@ export class CreatePrivateMessage extends Component<
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let user_id = Number(req.path.split('/').pop()); let user_id = Number(req.path.split("/").pop());
let form: GetUserDetails = { let form: GetUserDetails = {
user_id, user_id,
sort: SortType.New, sort: SortType.New,
@ -91,7 +91,7 @@ export class CreatePrivateMessage extends Component<
} }
get documentTitle(): string { get documentTitle(): string {
return `${i18n.t('create_private_message')} - ${ return `${i18n.t("create_private_message")} - ${
this.state.site_view.site.name this.state.site_view.site.name
}`; }`;
} }
@ -116,7 +116,7 @@ export class CreatePrivateMessage extends Component<
) : ( ) : (
<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('create_private_message')}</h5> <h5>{i18n.t("create_private_message")}</h5>
<PrivateMessageForm <PrivateMessageForm
onCreate={this.handlePrivateMessageCreate} onCreate={this.handlePrivateMessageCreate}
recipient={this.state.recipient.user} recipient={this.state.recipient.user}
@ -129,7 +129,7 @@ export class CreatePrivateMessage extends Component<
} }
handlePrivateMessageCreate() { handlePrivateMessageCreate() {
toast(i18n.t('message_sent')); toast(i18n.t("message_sent"));
// Navigate to the front // Navigate to the front
this.context.router.history.push(`/`); this.context.router.history.push(`/`);
@ -138,7 +138,7 @@ export class CreatePrivateMessage extends Component<
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
this.state.loading = false; this.state.loading = false;
this.setState(this.state); this.setState(this.state);
return; return;

View file

@ -1,7 +1,7 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { DataType } from '../interfaces'; import { DataType } from "../interfaces";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
interface DataTypeSelectProps { interface DataTypeSelectProps {
type_: DataType; type_: DataType;
@ -36,7 +36,7 @@ export class DataTypeSelect extends Component<
<div class="btn-group btn-group-toggle flex-wrap mb-2"> <div class="btn-group btn-group-toggle flex-wrap mb-2">
<label <label
className={`pointer btn btn-outline-secondary className={`pointer btn btn-outline-secondary
${this.state.type_ == DataType.Post && 'active'} ${this.state.type_ == DataType.Post && "active"}
`} `}
> >
<input <input
@ -45,11 +45,11 @@ export class DataTypeSelect extends Component<
checked={this.state.type_ == DataType.Post} checked={this.state.type_ == DataType.Post}
onChange={linkEvent(this, this.handleTypeChange)} onChange={linkEvent(this, this.handleTypeChange)}
/> />
{i18n.t('posts')} {i18n.t("posts")}
</label> </label>
<label <label
className={`pointer btn btn-outline-secondary ${ className={`pointer btn btn-outline-secondary ${
this.state.type_ == DataType.Comment && 'active' this.state.type_ == DataType.Comment && "active"
}`} }`}
> >
<input <input
@ -58,7 +58,7 @@ export class DataTypeSelect extends Component<
checked={this.state.type_ == DataType.Comment} checked={this.state.type_ == DataType.Comment}
onChange={linkEvent(this, this.handleTypeChange)} onChange={linkEvent(this, this.handleTypeChange)}
/> />
{i18n.t('comments')} {i18n.t("comments")}
</label> </label>
</div> </div>
); );

View file

@ -1,8 +1,8 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { Link } from 'inferno-router'; import { Link } from "inferno-router";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { repoUrl, joinLemmyUrl, docsUrl } from '../utils'; import { repoUrl, joinLemmyUrl, docsUrl } from "../utils";
import { GetSiteResponse } from 'lemmy-js-client'; import { GetSiteResponse } from "lemmy-js-client";
interface FooterProps { interface FooterProps {
site: GetSiteResponse; site: GetSiteResponse;
@ -23,29 +23,29 @@ export class Footer extends Component<FooterProps, any> {
</li> </li>
<li className="nav-item"> <li className="nav-item">
<Link className="nav-link" to="/modlog"> <Link className="nav-link" to="/modlog">
{i18n.t('modlog')} {i18n.t("modlog")}
</Link> </Link>
</li> </li>
{this.props.site.federated_instances && ( {this.props.site.federated_instances && (
<li class="nav-item"> <li class="nav-item">
<Link className="nav-link" to="/instances"> <Link className="nav-link" to="/instances">
{i18n.t('instances')} {i18n.t("instances")}
</Link> </Link>
</li> </li>
)} )}
<li class="nav-item"> <li class="nav-item">
<a className="nav-link" href={docsUrl}> <a className="nav-link" href={docsUrl}>
{i18n.t('docs')} {i18n.t("docs")}
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a className="nav-link" href={repoUrl}> <a className="nav-link" href={repoUrl}>
{i18n.t('code')} {i18n.t("code")}
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a className="nav-link" href={joinLemmyUrl}> <a className="nav-link" href={joinLemmyUrl}>
{i18n.t('join_lemmy')} {i18n.t("join_lemmy")}
</a> </a>
</li> </li>
</ul> </ul>

View file

@ -1,7 +1,7 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { Helmet } from 'inferno-helmet'; import { Helmet } from "inferno-helmet";
import { httpExternalPath } from '../env'; import { httpExternalPath } from "../env";
import { md } from '../utils'; import { md } from "../utils";
interface HtmlTagsProps { interface HtmlTagsProps {
title: string; title: string;
@ -17,10 +17,10 @@ export class HtmlTags extends Component<HtmlTagsProps, any> {
return ( return (
<Helmet title={this.props.title}> <Helmet title={this.props.title}>
{['title', 'og:title', 'twitter:title'].map(t => ( {["title", "og:title", "twitter:title"].map(t => (
<meta property={t} content={this.props.title} /> <meta property={t} content={this.props.title} />
))} ))}
{['og:url', 'twitter:url'].map(u => ( {["og:url", "twitter:url"].map(u => (
<meta property={u} content={url} /> <meta property={u} content={url} />
))} ))}
@ -32,12 +32,12 @@ export class HtmlTags extends Component<HtmlTagsProps, any> {
{/* Optional desc and images */} {/* Optional desc and images */}
{this.props.description && {this.props.description &&
['description', 'og:description', 'twitter:description'].map(n => ( ["description", "og:description", "twitter:description"].map(n => (
<meta name={n} content={md.renderInline(this.props.description)} /> <meta name={n} content={md.renderInline(this.props.description)} />
))} ))}
{this.props.image && {this.props.image &&
['og:image', 'twitter:image'].map(p => ( ["og:image", "twitter:image"].map(p => (
<meta property={p} content={this.props.image} /> <meta property={p} content={this.props.image} />
))} ))}
</Helmet> </Helmet>

View file

@ -1,4 +1,4 @@
import { Component } from 'inferno'; import { Component } from "inferno";
interface IconProps { interface IconProps {
icon: string; icon: string;

View file

@ -1,8 +1,8 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Post } from 'lemmy-js-client'; import { Post } from "lemmy-js-client";
import { mdToHtml } from '../utils'; import { mdToHtml } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { Icon } from './icon'; import { Icon } from "./icon";
interface FramelyCardProps { interface FramelyCardProps {
post: Post; post: Post;
@ -61,9 +61,9 @@ export class IFramelyCard extends Component<
<button <button
class="mt-2 btn btn-secondary text-monospace" class="mt-2 btn btn-secondary text-monospace"
onClick={linkEvent(this, this.handleIframeExpand)} onClick={linkEvent(this, this.handleIframeExpand)}
data-tippy-content={i18n.t('expand_here')} data-tippy-content={i18n.t("expand_here")}
> >
{this.state.expanded ? '-' : '+'} {this.state.expanded ? "-" : "+"}
</button> </button>
)} )}
</div> </div>

View file

@ -1,9 +1,9 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { pictrsUri } from '../env'; import { pictrsUri } from "../env";
import { UserService } from '../services'; import { UserService } from "../services";
import { toast, randomStr } from '../utils'; import { toast, randomStr } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { Icon } from './icon'; import { Icon } from "./icon";
interface ImageUploadFormProps { interface ImageUploadFormProps {
uploadTitle: string; uploadTitle: string;
@ -44,15 +44,15 @@ export class ImageUploadForm extends Component<
<span class="d-inline-block position-relative"> <span class="d-inline-block position-relative">
<img <img
src={this.props.imageSrc} src={this.props.imageSrc}
height={this.props.rounded ? 60 : ''} height={this.props.rounded ? 60 : ""}
width={this.props.rounded ? 60 : ''} width={this.props.rounded ? 60 : ""}
className={`img-fluid ${ className={`img-fluid ${
this.props.rounded ? 'rounded-circle' : '' this.props.rounded ? "rounded-circle" : ""
}`} }`}
/> />
<a <a
onClick={linkEvent(this, this.handleRemoveImage)} onClick={linkEvent(this, this.handleRemoveImage)}
aria-label={i18n.t('remove')} aria-label={i18n.t("remove")}
> >
<Icon icon="x" classes="mini-overlay" /> <Icon icon="x" classes="mini-overlay" />
</a> </a>
@ -76,20 +76,20 @@ export class ImageUploadForm extends Component<
event.preventDefault(); event.preventDefault();
let file = event.target.files[0]; let file = event.target.files[0];
const formData = new FormData(); const formData = new FormData();
formData.append('images[]', file); formData.append("images[]", file);
i.state.loading = true; i.state.loading = true;
i.setState(i.state); i.setState(i.state);
fetch(pictrsUri, { fetch(pictrsUri, {
method: 'POST', method: "POST",
body: formData, body: formData,
}) })
.then(res => res.json()) .then(res => res.json())
.then(res => { .then(res => {
console.log('pictrs upload:'); console.log("pictrs upload:");
console.log(res); console.log(res);
if (res.msg == 'ok') { if (res.msg == "ok") {
let hash = res.files[0].file; let hash = res.files[0].file;
let url = `${pictrsUri}/${hash}`; let url = `${pictrsUri}/${hash}`;
i.state.loading = false; i.state.loading = false;
@ -98,13 +98,13 @@ export class ImageUploadForm extends Component<
} else { } else {
i.state.loading = false; i.state.loading = false;
i.setState(i.state); i.setState(i.state);
toast(JSON.stringify(res), 'danger'); toast(JSON.stringify(res), "danger");
} }
}) })
.catch(error => { .catch(error => {
i.state.loading = false; i.state.loading = false;
i.setState(i.state); i.setState(i.state);
toast(error, 'danger'); toast(error, "danger");
}); });
} }

View file

@ -1,5 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
UserOperation, UserOperation,
CommentView, CommentView,
@ -16,8 +16,8 @@ import {
PrivateMessageResponse, PrivateMessageResponse,
SiteView, SiteView,
UserMentionView, UserMentionView,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { import {
wsJsonToRes, wsJsonToRes,
fetchLimit, fetchLimit,
@ -33,14 +33,14 @@ import {
wsUserOp, wsUserOp,
wsClient, wsClient,
authField, authField,
} 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 { HtmlTags } from "./html-tags";
import { SortSelect } from './sort-select'; import { SortSelect } from "./sort-select";
import { Icon, Spinner } from './icon'; import { Icon, Spinner } from "./icon";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { InitialFetchRequest } from 'shared/interfaces'; import { InitialFetchRequest } from "shared/interfaces";
enum UnreadOrAll { enum UnreadOrAll {
Unread, Unread,
@ -102,7 +102,7 @@ export class Inbox extends Component<any, InboxState> {
this.handleSortChange = this.handleSortChange.bind(this); this.handleSortChange = this.handleSortChange.bind(this);
if (!UserService.Instance.user && isBrowser()) { if (!UserService.Instance.user && isBrowser()) {
toast(i18n.t('not_logged_in'), 'danger'); toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`); this.context.router.history.push(`/login`);
} }
@ -128,7 +128,7 @@ export class Inbox extends Component<any, InboxState> {
} }
get documentTitle(): string { get documentTitle(): string {
return `@${UserService.Instance.user.name} ${i18n.t('inbox')} - ${ return `@${UserService.Instance.user.name} ${i18n.t("inbox")} - ${
this.state.site_view.site.name this.state.site_view.site.name
}`; }`;
} }
@ -148,7 +148,7 @@ export class Inbox extends Component<any, InboxState> {
path={this.context.router.route.match.url} path={this.context.router.route.match.url}
/> />
<h5 class="mb-1"> <h5 class="mb-1">
{i18n.t('inbox')} {i18n.t("inbox")}
<small> <small>
<a <a
href={`/feeds/inbox/${UserService.Instance.auth}.xml`} href={`/feeds/inbox/${UserService.Instance.auth}.xml`}
@ -171,7 +171,7 @@ export class Inbox extends Component<any, InboxState> {
role="button" role="button"
onClick={linkEvent(this, this.markAllAsRead)} onClick={linkEvent(this, this.markAllAsRead)}
> >
{i18n.t('mark_all_as_read')} {i18n.t("mark_all_as_read")}
</span> </span>
</li> </li>
</ul> </ul>
@ -196,7 +196,7 @@ export class Inbox extends Component<any, InboxState> {
<div class="btn-group btn-group-toggle flex-wrap mb-2"> <div class="btn-group btn-group-toggle flex-wrap mb-2">
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.unreadOrAll == UnreadOrAll.Unread && 'active'} ${this.state.unreadOrAll == UnreadOrAll.Unread && "active"}
`} `}
> >
<input <input
@ -205,11 +205,11 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.unreadOrAll == UnreadOrAll.Unread} checked={this.state.unreadOrAll == UnreadOrAll.Unread}
onChange={linkEvent(this, this.handleUnreadOrAllChange)} onChange={linkEvent(this, this.handleUnreadOrAllChange)}
/> />
{i18n.t('unread')} {i18n.t("unread")}
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.unreadOrAll == UnreadOrAll.All && 'active'} ${this.state.unreadOrAll == UnreadOrAll.All && "active"}
`} `}
> >
<input <input
@ -218,7 +218,7 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.unreadOrAll == UnreadOrAll.All} checked={this.state.unreadOrAll == UnreadOrAll.All}
onChange={linkEvent(this, this.handleUnreadOrAllChange)} onChange={linkEvent(this, this.handleUnreadOrAllChange)}
/> />
{i18n.t('all')} {i18n.t("all")}
</label> </label>
</div> </div>
); );
@ -229,7 +229,7 @@ export class Inbox extends Component<any, InboxState> {
<div class="btn-group btn-group-toggle flex-wrap mb-2"> <div class="btn-group btn-group-toggle flex-wrap mb-2">
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.messageType == MessageType.All && 'active'} ${this.state.messageType == MessageType.All && "active"}
`} `}
> >
<input <input
@ -238,11 +238,11 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.messageType == MessageType.All} checked={this.state.messageType == MessageType.All}
onChange={linkEvent(this, this.handleMessageTypeChange)} onChange={linkEvent(this, this.handleMessageTypeChange)}
/> />
{i18n.t('all')} {i18n.t("all")}
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.messageType == MessageType.Replies && 'active'} ${this.state.messageType == MessageType.Replies && "active"}
`} `}
> >
<input <input
@ -251,11 +251,11 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.messageType == MessageType.Replies} checked={this.state.messageType == MessageType.Replies}
onChange={linkEvent(this, this.handleMessageTypeChange)} onChange={linkEvent(this, this.handleMessageTypeChange)}
/> />
{i18n.t('replies')} {i18n.t("replies")}
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.messageType == MessageType.Mentions && 'active'} ${this.state.messageType == MessageType.Mentions && "active"}
`} `}
> >
<input <input
@ -264,11 +264,11 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.messageType == MessageType.Mentions} checked={this.state.messageType == MessageType.Mentions}
onChange={linkEvent(this, this.handleMessageTypeChange)} onChange={linkEvent(this, this.handleMessageTypeChange)}
/> />
{i18n.t('mentions')} {i18n.t("mentions")}
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.messageType == MessageType.Messages && 'active'} ${this.state.messageType == MessageType.Messages && "active"}
`} `}
> >
<input <input
@ -277,7 +277,7 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.messageType == MessageType.Messages} checked={this.state.messageType == MessageType.Messages}
onChange={linkEvent(this, this.handleMessageTypeChange)} onChange={linkEvent(this, this.handleMessageTypeChange)}
/> />
{i18n.t('messages')} {i18n.t("messages")}
</label> </label>
</div> </div>
); );
@ -437,7 +437,7 @@ export class Inbox extends Component<any, InboxState> {
class="btn btn-secondary mr-1" class="btn btn-secondary mr-1"
onClick={linkEvent(this, this.prevPage)} onClick={linkEvent(this, this.prevPage)}
> >
{i18n.t('prev')} {i18n.t("prev")}
</button> </button>
)} )}
{this.unreadCount() > 0 && ( {this.unreadCount() > 0 && (
@ -445,7 +445,7 @@ export class Inbox extends Component<any, InboxState> {
class="btn btn-secondary" class="btn btn-secondary"
onClick={linkEvent(this, this.nextPage)} onClick={linkEvent(this, this.nextPage)}
> >
{i18n.t('next')} {i18n.t("next")}
</button> </button>
)} )}
</div> </div>
@ -566,7 +566,7 @@ export class Inbox extends Component<any, InboxState> {
let op = wsUserOp(msg); let op = wsUserOp(msg);
console.log(msg); console.log(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
return; return;
} else if (msg.reconnect) { } else if (msg.reconnect) {
this.refetch(); this.refetch();
@ -753,7 +753,7 @@ export class Inbox extends Component<any, InboxState> {
this.setState(this.state); this.setState(this.state);
} else if (data.comment_view.creator.id == UserService.Instance.user.id) { } else if (data.comment_view.creator.id == UserService.Instance.user.id) {
// TODO this seems wrong, you should be using form_id // TODO this seems wrong, you should be using form_id
toast(i18n.t('reply_sent')); toast(i18n.t("reply_sent"));
} }
} else if (op == UserOperation.CreatePrivateMessage) { } else if (op == UserOperation.CreatePrivateMessage) {
let data = wsJsonToRes<PrivateMessageResponse>(msg).data; let data = wsJsonToRes<PrivateMessageResponse>(msg).data;

View file

@ -1,8 +1,8 @@
import { Component } from 'inferno'; import { Component } from "inferno";
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'; import { HtmlTags } from "./html-tags";
interface InstancesState { interface InstancesState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
@ -20,7 +20,7 @@ export class Instances extends Component<any, InstancesState> {
} }
get documentTitle(): string { get documentTitle(): string {
return `${i18n.t('instances')} - ${this.state.siteRes.site_view.site.name}`; return `${i18n.t("instances")} - ${this.state.siteRes.site_view.site.name}`;
} }
render() { render() {
@ -34,18 +34,18 @@ export class Instances extends Component<any, InstancesState> {
/> />
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h5>{i18n.t('linked_instances')}</h5> <h5>{i18n.t("linked_instances")}</h5>
{this.itemList(federated_instances.linked)} {this.itemList(federated_instances.linked)}
</div> </div>
{federated_instances.allowed.length > 0 && ( {federated_instances.allowed.length > 0 && (
<div class="col-md-6"> <div class="col-md-6">
<h5>{i18n.t('allowed_instances')}</h5> <h5>{i18n.t("allowed_instances")}</h5>
{this.itemList(federated_instances.allowed)} {this.itemList(federated_instances.allowed)}
</div> </div>
)} )}
{federated_instances.blocked.length > 0 && ( {federated_instances.blocked.length > 0 && (
<div class="col-md-6"> <div class="col-md-6">
<h5>{i18n.t('blocked_instances')}</h5> <h5>{i18n.t("blocked_instances")}</h5>
{this.itemList(federated_instances.blocked)} {this.itemList(federated_instances.blocked)}
</div> </div>
)} )}
@ -67,7 +67,7 @@ export class Instances extends Component<any, InstancesState> {
))} ))}
</ul> </ul>
) : ( ) : (
<div>{i18n.t('none_found')}</div> <div>{i18n.t("none_found")}</div>
); );
} }
} }

View file

@ -1,8 +1,8 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { ListingType } from 'lemmy-js-client'; import { ListingType } from "lemmy-js-client";
import { UserService } from '../services'; import { UserService } from "../services";
import { randomStr } from '../utils'; import { randomStr } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
interface ListingTypeSelectProps { interface ListingTypeSelectProps {
type_: ListingType; type_: ListingType;
@ -41,8 +41,8 @@ export class ListingTypeSelect extends Component<
<div class="btn-group btn-group-toggle flex-wrap mb-2"> <div class="btn-group btn-group-toggle flex-wrap mb-2">
<label <label
className={`btn btn-outline-secondary className={`btn btn-outline-secondary
${this.state.type_ == ListingType.Subscribed && 'active'} ${this.state.type_ == ListingType.Subscribed && "active"}
${UserService.Instance.user == undefined ? 'disabled' : 'pointer'} ${UserService.Instance.user == undefined ? "disabled" : "pointer"}
`} `}
> >
<input <input
@ -53,12 +53,12 @@ export class ListingTypeSelect extends Component<
onChange={linkEvent(this, this.handleTypeChange)} onChange={linkEvent(this, this.handleTypeChange)}
disabled={UserService.Instance.user == undefined} disabled={UserService.Instance.user == undefined}
/> />
{i18n.t('subscribed')} {i18n.t("subscribed")}
</label> </label>
{this.props.showLocal && ( {this.props.showLocal && (
<label <label
className={`pointer btn btn-outline-secondary ${ className={`pointer btn btn-outline-secondary ${
this.state.type_ == ListingType.Local && 'active' this.state.type_ == ListingType.Local && "active"
}`} }`}
> >
<input <input
@ -68,15 +68,15 @@ export class ListingTypeSelect extends Component<
checked={this.state.type_ == ListingType.Local} checked={this.state.type_ == ListingType.Local}
onChange={linkEvent(this, this.handleTypeChange)} onChange={linkEvent(this, this.handleTypeChange)}
/> />
{i18n.t('local')} {i18n.t("local")}
</label> </label>
)} )}
<label <label
className={`pointer btn btn-outline-secondary ${ className={`pointer btn btn-outline-secondary ${
(this.state.type_ == ListingType.All && 'active') || (this.state.type_ == ListingType.All && "active") ||
(!this.props.showLocal && (!this.props.showLocal &&
this.state.type_ == ListingType.Local && this.state.type_ == ListingType.Local &&
'active') "active")
}`} }`}
> >
<input <input
@ -86,7 +86,7 @@ export class ListingTypeSelect extends Component<
checked={this.state.type_ == ListingType.All} checked={this.state.type_ == ListingType.All}
onChange={linkEvent(this, this.handleTypeChange)} onChange={linkEvent(this, this.handleTypeChange)}
/> />
{i18n.t('all')} {i18n.t("all")}
</label> </label>
</div> </div>
); );

View file

@ -1,5 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
Login as LoginForm, Login as LoginForm,
Register, Register,
@ -9,8 +9,8 @@ import {
GetSiteResponse, GetSiteResponse,
GetCaptchaResponse, GetCaptchaResponse,
SiteView, SiteView,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { import {
wsJsonToRes, wsJsonToRes,
validEmail, validEmail,
@ -21,10 +21,10 @@ import {
wsUserOp, wsUserOp,
wsClient, wsClient,
authField, authField,
} from '../utils'; } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { HtmlTags } from './html-tags'; import { HtmlTags } from "./html-tags";
import { Icon, Spinner } from './icon'; import { Icon, Spinner } from "./icon";
interface State { interface State {
loginForm: LoginForm; loginForm: LoginForm;
@ -80,7 +80,7 @@ export class Login extends Component<any, State> {
} }
get documentTitle(): string { get documentTitle(): string {
return `${i18n.t('login')} - ${this.state.site_view.site.name}`; return `${i18n.t("login")} - ${this.state.site_view.site.name}`;
} }
render() { render() {
@ -102,13 +102,13 @@ export class Login extends Component<any, State> {
return ( return (
<div> <div>
<form onSubmit={linkEvent(this, this.handleLoginSubmit)}> <form onSubmit={linkEvent(this, this.handleLoginSubmit)}>
<h5>{i18n.t('login')}</h5> <h5>{i18n.t("login")}</h5>
<div class="form-group row"> <div class="form-group row">
<label <label
class="col-sm-2 col-form-label" class="col-sm-2 col-form-label"
htmlFor="login-email-or-username" htmlFor="login-email-or-username"
> >
{i18n.t('email_or_username')} {i18n.t("email_or_username")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input <input
@ -124,7 +124,7 @@ export class Login extends Component<any, State> {
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="login-password"> <label class="col-sm-2 col-form-label" htmlFor="login-password">
{i18n.t('password')} {i18n.t("password")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input <input
@ -140,16 +140,16 @@ export class Login extends Component<any, State> {
onClick={linkEvent(this, this.handlePasswordReset)} onClick={linkEvent(this, this.handlePasswordReset)}
className="btn p-0 btn-link d-inline-block float-right text-muted small font-weight-bold pointer-events" className="btn p-0 btn-link d-inline-block float-right text-muted small font-weight-bold pointer-events"
disabled={!validEmail(this.state.loginForm.username_or_email)} disabled={!validEmail(this.state.loginForm.username_or_email)}
title={i18n.t('no_password_reset')} title={i18n.t("no_password_reset")}
> >
{i18n.t('forgot_password')} {i18n.t("forgot_password")}
</button> </button>
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-10"> <div class="col-sm-10">
<button type="submit" class="btn btn-secondary"> <button type="submit" class="btn btn-secondary">
{this.state.loginLoading ? <Spinner /> : i18n.t('login')} {this.state.loginLoading ? <Spinner /> : i18n.t("login")}
</button> </button>
</div> </div>
</div> </div>
@ -161,11 +161,11 @@ export class Login extends Component<any, State> {
registerForm() { registerForm() {
return ( return (
<form onSubmit={linkEvent(this, this.handleRegisterSubmit)}> <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
<h5>{i18n.t('sign_up')}</h5> <h5>{i18n.t("sign_up")}</h5>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="register-username"> <label class="col-sm-2 col-form-label" htmlFor="register-username">
{i18n.t('username')} {i18n.t("username")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
@ -185,14 +185,14 @@ export class Login extends Component<any, State> {
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="register-email"> <label class="col-sm-2 col-form-label" htmlFor="register-email">
{i18n.t('email')} {i18n.t("email")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input <input
type="email" type="email"
id="register-email" id="register-email"
class="form-control" class="form-control"
placeholder={i18n.t('optional')} placeholder={i18n.t("optional")}
value={this.state.registerForm.email} value={this.state.registerForm.email}
onInput={linkEvent(this, this.handleRegisterEmailChange)} onInput={linkEvent(this, this.handleRegisterEmailChange)}
minLength={3} minLength={3}
@ -200,7 +200,7 @@ export class Login extends Component<any, State> {
{!validEmail(this.state.registerForm.email) && ( {!validEmail(this.state.registerForm.email) && (
<div class="mt-2 mb-0 alert alert-light" role="alert"> <div class="mt-2 mb-0 alert alert-light" role="alert">
<Icon icon="alert-triangle" classes="icon-inline mr-2" /> <Icon icon="alert-triangle" classes="icon-inline mr-2" />
{i18n.t('no_password_reset')} {i18n.t("no_password_reset")}
</div> </div>
)} )}
</div> </div>
@ -208,7 +208,7 @@ export class Login extends Component<any, State> {
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="register-password"> <label class="col-sm-2 col-form-label" htmlFor="register-password">
{i18n.t('password')} {i18n.t("password")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input <input
@ -229,7 +229,7 @@ export class Login extends Component<any, State> {
class="col-sm-2 col-form-label" class="col-sm-2 col-form-label"
htmlFor="register-verify-password" htmlFor="register-verify-password"
> >
{i18n.t('verify_password')} {i18n.t("verify_password")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input <input
@ -248,12 +248,12 @@ export class Login extends Component<any, State> {
{this.state.captcha && ( {this.state.captcha && (
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2" htmlFor="register-captcha"> <label class="col-sm-2" htmlFor="register-captcha">
<span class="mr-2">{i18n.t('enter_code')}</span> <span class="mr-2">{i18n.t("enter_code")}</span>
<button <button
type="button" type="button"
class="btn btn-secondary" class="btn btn-secondary"
onClick={linkEvent(this, this.handleRegenCaptcha)} onClick={linkEvent(this, this.handleRegenCaptcha)}
aria-label={i18n.t('captcha')} aria-label={i18n.t("captcha")}
> >
<Icon icon="refresh-cw" classes="icon-refresh-cw" /> <Icon icon="refresh-cw" classes="icon-refresh-cw" />
</button> </button>
@ -286,7 +286,7 @@ export class Login extends Component<any, State> {
onChange={linkEvent(this, this.handleRegisterShowNsfwChange)} onChange={linkEvent(this, this.handleRegisterShowNsfwChange)}
/> />
<label class="form-check-label" htmlFor="register-show-nsfw"> <label class="form-check-label" htmlFor="register-show-nsfw">
{i18n.t('show_nsfw')} {i18n.t("show_nsfw")}
</label> </label>
</div> </div>
</div> </div>
@ -295,7 +295,7 @@ export class Login extends Component<any, State> {
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-10"> <div class="col-sm-10">
<button type="submit" class="btn btn-secondary"> <button type="submit" class="btn btn-secondary">
{this.state.registerLoading ? <Spinner /> : i18n.t('sign_up')} {this.state.registerLoading ? <Spinner /> : i18n.t("sign_up")}
</button> </button>
</div> </div>
</div> </div>
@ -312,13 +312,13 @@ export class Login extends Component<any, State> {
class="rounded-top img-fluid" class="rounded-top img-fluid"
src={this.captchaPngSrc()} src={this.captchaPngSrc()}
style="border-bottom-right-radius: 0; border-bottom-left-radius: 0;" style="border-bottom-right-radius: 0; border-bottom-left-radius: 0;"
alt={i18n.t('captcha')} alt={i18n.t("captcha")}
/> />
{this.state.captcha.ok.wav && ( {this.state.captcha.ok.wav && (
<button <button
class="rounded-bottom btn btn-sm btn-secondary btn-block" class="rounded-bottom btn btn-sm btn-secondary btn-block"
style="border-top-right-radius: 0; border-top-left-radius: 0;" style="border-top-right-radius: 0; border-top-left-radius: 0;"
title={i18n.t('play_captcha_audio')} title={i18n.t("play_captcha_audio")}
onClick={linkEvent(this, this.handleCaptchaPlay)} onClick={linkEvent(this, this.handleCaptchaPlay)}
type="button" type="button"
disabled={this.state.captchaPlaying} disabled={this.state.captchaPlaying}
@ -363,7 +363,7 @@ export class Login extends Component<any, State> {
handleRegisterEmailChange(i: Login, event: any) { handleRegisterEmailChange(i: Login, event: any) {
i.state.registerForm.email = event.target.value; i.state.registerForm.email = event.target.value;
if (i.state.registerForm.email == '') { if (i.state.registerForm.email == "") {
i.state.registerForm.email = undefined; i.state.registerForm.email = undefined;
} }
i.setState(i.state); i.setState(i.state);
@ -404,11 +404,11 @@ export class Login extends Component<any, State> {
handleCaptchaPlay(i: Login, event: any) { handleCaptchaPlay(i: Login, event: any) {
event.preventDefault(); event.preventDefault();
let snd = new Audio('data:audio/wav;base64,' + i.state.captcha.ok.wav); let snd = new Audio("data:audio/wav;base64," + i.state.captcha.ok.wav);
snd.play(); snd.play();
i.state.captchaPlaying = true; i.state.captchaPlaying = true;
i.setState(i.state); i.setState(i.state);
snd.addEventListener('ended', () => { snd.addEventListener("ended", () => {
snd.currentTime = 0; snd.currentTime = 0;
i.state.captchaPlaying = false; i.state.captchaPlaying = false;
i.setState(this.state); i.setState(this.state);
@ -422,7 +422,7 @@ export class Login extends Component<any, State> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
this.state = this.emptyState; this.state = this.emptyState;
this.state.registerForm.captcha_answer = undefined; this.state.registerForm.captcha_answer = undefined;
// Refetch another captcha // Refetch another captcha
@ -440,8 +440,8 @@ export class Login extends Component<any, State> {
auth: authField(), auth: authField(),
}) })
); );
toast(i18n.t('logged_in')); toast(i18n.t("logged_in"));
this.props.history.push('/'); this.props.history.push("/");
} else if (op == UserOperation.Register) { } else if (op == UserOperation.Register) {
let data = wsJsonToRes<LoginResponse>(msg).data; let data = wsJsonToRes<LoginResponse>(msg).data;
this.state = this.emptyState; this.state = this.emptyState;
@ -452,7 +452,7 @@ export class Login extends Component<any, State> {
auth: authField(), auth: authField(),
}) })
); );
this.props.history.push('/communities'); this.props.history.push("/communities");
} else if (op == UserOperation.GetCaptcha) { } else if (op == UserOperation.GetCaptcha) {
let data = wsJsonToRes<GetCaptchaResponse>(msg).data; let data = wsJsonToRes<GetCaptchaResponse>(msg).data;
if (data.ok) { if (data.ok) {
@ -461,7 +461,7 @@ export class Login extends Component<any, State> {
this.setState(this.state); this.setState(this.state);
} }
} else if (op == UserOperation.PasswordReset) { } else if (op == UserOperation.PasswordReset) {
toast(i18n.t('reset_password_mail_sent')); toast(i18n.t("reset_password_mail_sent"));
} else if (op == UserOperation.GetSite) { } else if (op == UserOperation.GetSite) {
let data = wsJsonToRes<GetSiteResponse>(msg).data; let data = wsJsonToRes<GetSiteResponse>(msg).data;
this.state.site_view = data.site_view; this.state.site_view = data.site_view;

View file

@ -1,5 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Prompt } from 'inferno-router'; import { Prompt } from "inferno-router";
import { import {
mdToHtml, mdToHtml,
randomStr, randomStr,
@ -9,12 +9,12 @@ import {
pictrsDeleteToast, pictrsDeleteToast,
setupTippy, setupTippy,
isBrowser, isBrowser,
} from '../utils'; } from "../utils";
import { UserService } from '../services'; import { UserService } from "../services";
import autosize from 'autosize'; import autosize from "autosize";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { pictrsUri } from '../env'; import { pictrsUri } from "../env";
import { Icon, Spinner } from './icon'; import { Icon, Spinner } from "./icon";
interface MarkdownTextAreaProps { interface MarkdownTextAreaProps {
initialContent: string; initialContent: string;
@ -65,7 +65,7 @@ export class MarkdownTextArea extends Component<
if (textarea) { if (textarea) {
autosize(textarea); autosize(textarea);
this.tribute.attach(textarea); this.tribute.attach(textarea);
textarea.addEventListener('tribute-replaced', () => { textarea.addEventListener("tribute-replaced", () => {
this.state.content = textarea.value; this.state.content = textarea.value;
this.setState(this.state); this.setState(this.state);
autosize.update(textarea); autosize.update(textarea);
@ -94,7 +94,7 @@ export class MarkdownTextArea extends Component<
if (nextProps.finished) { if (nextProps.finished) {
this.state.previewMode = false; this.state.previewMode = false;
this.state.loading = false; this.state.loading = false;
this.state.content = ''; this.state.content = "";
this.setState(this.state); this.setState(this.state);
if (this.props.replyType) { if (this.props.replyType) {
this.props.onReplyCancel(); this.props.onReplyCancel();
@ -117,13 +117,13 @@ export class MarkdownTextArea extends Component<
<form id={this.formId} onSubmit={linkEvent(this, this.handleSubmit)}> <form id={this.formId} onSubmit={linkEvent(this, this.handleSubmit)}>
<Prompt <Prompt
when={!this.props.hideNavigationWarnings && this.state.content} when={!this.props.hideNavigationWarnings && this.state.content}
message={i18n.t('block_leaving')} message={i18n.t("block_leaving")}
/> />
<div class="form-group row"> <div class="form-group row">
<div className={`col-sm-12`}> <div className={`col-sm-12`}>
<textarea <textarea
id={this.id} id={this.id}
className={`form-control ${this.state.previewMode && 'd-none'}`} className={`form-control ${this.state.previewMode && "d-none"}`}
value={this.state.content} value={this.state.content}
onInput={linkEvent(this, this.handleContentChange)} onInput={linkEvent(this, this.handleContentChange)}
onPaste={linkEvent(this, this.handleImageUploadPaste)} onPaste={linkEvent(this, this.handleImageUploadPaste)}
@ -140,7 +140,7 @@ export class MarkdownTextArea extends Component<
)} )}
</div> </div>
<label class="sr-only" htmlFor={this.id}> <label class="sr-only" htmlFor={this.id}>
{i18n.t('body')} {i18n.t("body")}
</label> </label>
</div> </div>
<div class="row"> <div class="row">
@ -164,41 +164,41 @@ export class MarkdownTextArea extends Component<
class="btn btn-sm btn-secondary mr-2" class="btn btn-sm btn-secondary mr-2"
onClick={linkEvent(this, this.handleReplyCancel)} onClick={linkEvent(this, this.handleReplyCancel)}
> >
{i18n.t('cancel')} {i18n.t("cancel")}
</button> </button>
)} )}
{this.state.content && ( {this.state.content && (
<button <button
className={`btn btn-sm btn-secondary mr-2 ${ className={`btn btn-sm btn-secondary mr-2 ${
this.state.previewMode && 'active' this.state.previewMode && "active"
}`} }`}
onClick={linkEvent(this, this.handlePreviewToggle)} onClick={linkEvent(this, this.handlePreviewToggle)}
> >
{i18n.t('preview')} {i18n.t("preview")}
</button> </button>
)} )}
{/* A flex expander */} {/* A flex expander */}
<div class="flex-grow-1"></div> <div class="flex-grow-1"></div>
<button <button
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
data-tippy-content={i18n.t('bold')} data-tippy-content={i18n.t("bold")}
aria-label={i18n.t('bold')} aria-label={i18n.t("bold")}
onClick={linkEvent(this, this.handleInsertBold)} onClick={linkEvent(this, this.handleInsertBold)}
> >
<Icon icon="bold" classes="icon-inline" /> <Icon icon="bold" classes="icon-inline" />
</button> </button>
<button <button
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
data-tippy-content={i18n.t('italic')} data-tippy-content={i18n.t("italic")}
aria-label={i18n.t('italic')} aria-label={i18n.t("italic")}
onClick={linkEvent(this, this.handleInsertItalic)} onClick={linkEvent(this, this.handleInsertItalic)}
> >
<Icon icon="italic" classes="icon-inline" /> <Icon icon="italic" classes="icon-inline" />
</button> </button>
<button <button
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
data-tippy-content={i18n.t('link')} data-tippy-content={i18n.t("link")}
aria-label={i18n.t('link')} aria-label={i18n.t("link")}
onClick={linkEvent(this, this.handleInsertLink)} onClick={linkEvent(this, this.handleInsertLink)}
> >
<Icon icon="link" classes="icon-inline" /> <Icon icon="link" classes="icon-inline" />
@ -206,8 +206,8 @@ export class MarkdownTextArea extends Component<
<form class="btn btn-sm text-muted font-weight-bold"> <form class="btn btn-sm text-muted font-weight-bold">
<label <label
htmlFor={`file-upload-${this.id}`} htmlFor={`file-upload-${this.id}`}
className={`mb-0 ${UserService.Instance.user && 'pointer'}`} className={`mb-0 ${UserService.Instance.user && "pointer"}`}
data-tippy-content={i18n.t('upload_image')} data-tippy-content={i18n.t("upload_image")}
> >
{this.state.imageLoading ? ( {this.state.imageLoading ? (
<Spinner /> <Spinner />
@ -227,64 +227,64 @@ export class MarkdownTextArea extends Component<
</form> </form>
<button <button
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
data-tippy-content={i18n.t('header')} data-tippy-content={i18n.t("header")}
aria-label={i18n.t('header')} aria-label={i18n.t("header")}
onClick={linkEvent(this, this.handleInsertHeader)} onClick={linkEvent(this, this.handleInsertHeader)}
> >
<Icon icon="header" classes="icon-inline" /> <Icon icon="header" classes="icon-inline" />
</button> </button>
<button <button
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
data-tippy-content={i18n.t('strikethrough')} data-tippy-content={i18n.t("strikethrough")}
aria-label={i18n.t('strikethrough')} aria-label={i18n.t("strikethrough")}
onClick={linkEvent(this, this.handleInsertStrikethrough)} onClick={linkEvent(this, this.handleInsertStrikethrough)}
> >
<Icon icon="strikethrough" classes="icon-inline" /> <Icon icon="strikethrough" classes="icon-inline" />
</button> </button>
<button <button
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
data-tippy-content={i18n.t('quote')} data-tippy-content={i18n.t("quote")}
aria-label={i18n.t('quote')} aria-label={i18n.t("quote")}
onClick={linkEvent(this, this.handleInsertQuote)} onClick={linkEvent(this, this.handleInsertQuote)}
> >
<Icon icon="format_quote" classes="icon-inline" /> <Icon icon="format_quote" classes="icon-inline" />
</button> </button>
<button <button
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
data-tippy-content={i18n.t('list')} data-tippy-content={i18n.t("list")}
aria-label={i18n.t('list')} aria-label={i18n.t("list")}
onClick={linkEvent(this, this.handleInsertList)} onClick={linkEvent(this, this.handleInsertList)}
> >
<Icon icon="list" classes="icon-inline" /> <Icon icon="list" classes="icon-inline" />
</button> </button>
<button <button
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
data-tippy-content={i18n.t('code')} data-tippy-content={i18n.t("code")}
aria-label={i18n.t('code')} aria-label={i18n.t("code")}
onClick={linkEvent(this, this.handleInsertCode)} onClick={linkEvent(this, this.handleInsertCode)}
> >
<Icon icon="code" classes="icon-inline" /> <Icon icon="code" classes="icon-inline" />
</button> </button>
<button <button
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
data-tippy-content={i18n.t('subscript')} data-tippy-content={i18n.t("subscript")}
aria-label={i18n.t('subscript')} aria-label={i18n.t("subscript")}
onClick={linkEvent(this, this.handleInsertSubscript)} onClick={linkEvent(this, this.handleInsertSubscript)}
> >
<Icon icon="subscript" classes="icon-inline" /> <Icon icon="subscript" classes="icon-inline" />
</button> </button>
<button <button
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
data-tippy-content={i18n.t('superscript')} data-tippy-content={i18n.t("superscript")}
aria-label={i18n.t('superscript')} aria-label={i18n.t("superscript")}
onClick={linkEvent(this, this.handleInsertSuperscript)} onClick={linkEvent(this, this.handleInsertSuperscript)}
> >
<Icon icon="superscript" classes="icon-inline" /> <Icon icon="superscript" classes="icon-inline" />
</button> </button>
<button <button
class="btn btn-sm text-muted" class="btn btn-sm text-muted"
data-tippy-content={i18n.t('spoiler')} data-tippy-content={i18n.t("spoiler")}
aria-label={i18n.t('spoiler')} aria-label={i18n.t("spoiler")}
onClick={linkEvent(this, this.handleInsertSpoiler)} onClick={linkEvent(this, this.handleInsertSpoiler)}
> >
<Icon icon="alert-triangle" classes="icon-inline" /> <Icon icon="alert-triangle" classes="icon-inline" />
@ -292,7 +292,7 @@ export class MarkdownTextArea extends Component<
<a <a
href={markdownHelpUrl} href={markdownHelpUrl}
class="btn btn-sm text-muted font-weight-bold" class="btn btn-sm text-muted font-weight-bold"
title={i18n.t('formatting_help')} title={i18n.t("formatting_help")}
rel="noopener" rel="noopener"
> >
<Icon icon="help-circle" classes="icon-inline" /> <Icon icon="help-circle" classes="icon-inline" />
@ -320,20 +320,20 @@ export class MarkdownTextArea extends Component<
} }
const formData = new FormData(); const formData = new FormData();
formData.append('images[]', file); formData.append("images[]", file);
i.state.imageLoading = true; i.state.imageLoading = true;
i.setState(i.state); i.setState(i.state);
fetch(pictrsUri, { fetch(pictrsUri, {
method: 'POST', method: "POST",
body: formData, body: formData,
}) })
.then(res => res.json()) .then(res => res.json())
.then(res => { .then(res => {
console.log('pictrs upload:'); console.log("pictrs upload:");
console.log(res); console.log(res);
if (res.msg == 'ok') { if (res.msg == "ok") {
let hash = res.files[0].file; let hash = res.files[0].file;
let url = `${pictrsUri}/${hash}`; let url = `${pictrsUri}/${hash}`;
let deleteToken = res.files[0].delete_token; let deleteToken = res.files[0].delete_token;
@ -343,33 +343,38 @@ export class MarkdownTextArea extends Component<
content = content ? `${content}\n${imageMarkdown}` : imageMarkdown; content = content ? `${content}\n${imageMarkdown}` : imageMarkdown;
i.state.content = content; i.state.content = content;
i.state.imageLoading = false; i.state.imageLoading = false;
i.contentChange();
i.setState(i.state); i.setState(i.state);
let textarea: any = document.getElementById(i.id); let textarea: any = document.getElementById(i.id);
autosize.update(textarea); autosize.update(textarea);
pictrsDeleteToast( pictrsDeleteToast(
i18n.t('click_to_delete_picture'), i18n.t("click_to_delete_picture"),
i18n.t('picture_deleted'), i18n.t("picture_deleted"),
deleteUrl deleteUrl
); );
} else { } else {
i.state.imageLoading = false; i.state.imageLoading = false;
i.setState(i.state); i.setState(i.state);
toast(JSON.stringify(res), 'danger'); toast(JSON.stringify(res), "danger");
} }
}) })
.catch(error => { .catch(error => {
i.state.imageLoading = false; i.state.imageLoading = false;
i.setState(i.state); i.setState(i.state);
toast(error, 'danger'); toast(error, "danger");
}); });
} }
contentChange() {
if (this.props.onContentChange) {
this.props.onContentChange(this.state.content);
}
}
handleContentChange(i: MarkdownTextArea, event: any) { handleContentChange(i: MarkdownTextArea, event: any) {
i.state.content = event.target.value; i.state.content = event.target.value;
i.contentChange();
i.setState(i.state); i.setState(i.state);
if (i.props.onContentChange) {
i.props.onContentChange(i.state.content);
}
} }
handlePreviewToggle(i: MarkdownTextArea, event: any) { handlePreviewToggle(i: MarkdownTextArea, event: any) {
@ -393,7 +398,7 @@ export class MarkdownTextArea extends Component<
handleInsertLink(i: MarkdownTextArea, event: any) { handleInsertLink(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
if (!i.state.content) { if (!i.state.content) {
i.state.content = ''; i.state.content = "";
} }
let textarea: any = document.getElementById(i.id); let textarea: any = document.getElementById(i.id);
let start: number = textarea.selectionStart; let start: number = textarea.selectionStart;
@ -408,10 +413,11 @@ export class MarkdownTextArea extends Component<
textarea.focus(); textarea.focus();
setTimeout(() => (textarea.selectionEnd = end + 3), 10); setTimeout(() => (textarea.selectionEnd = end + 3), 10);
} else { } else {
i.state.content += '[]()'; i.state.content += "[]()";
textarea.focus(); textarea.focus();
setTimeout(() => (textarea.selectionEnd -= 1), 10); setTimeout(() => (textarea.selectionEnd -= 1), 10);
} }
i.contentChange();
i.setState(i.state); i.setState(i.state);
} }
@ -420,16 +426,16 @@ export class MarkdownTextArea extends Component<
} }
simpleBeginningofLine(chars: string) { simpleBeginningofLine(chars: string) {
this.simpleSurroundBeforeAfter(`${chars} `, '', ''); this.simpleSurroundBeforeAfter(`${chars} `, "", "");
} }
simpleSurroundBeforeAfter( simpleSurroundBeforeAfter(
beforeChars: string, beforeChars: string,
afterChars: string, afterChars: string,
emptyChars = '___' emptyChars = "___"
) { ) {
if (!this.state.content) { if (!this.state.content) {
this.state.content = ''; this.state.content = "";
} }
let textarea: any = document.getElementById(this.id); let textarea: any = document.getElementById(this.id);
let start: number = textarea.selectionStart; let start: number = textarea.selectionStart;
@ -446,6 +452,7 @@ export class MarkdownTextArea extends Component<
} else { } else {
this.state.content += `${beforeChars}${emptyChars}${afterChars}`; this.state.content += `${beforeChars}${emptyChars}${afterChars}`;
} }
this.contentChange();
this.setState(this.state); this.setState(this.state);
setTimeout(() => { setTimeout(() => {
autosize.update(textarea); autosize.update(textarea);
@ -454,47 +461,47 @@ export class MarkdownTextArea extends Component<
handleInsertBold(i: MarkdownTextArea, event: any) { handleInsertBold(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
i.simpleSurround('**'); i.simpleSurround("**");
} }
handleInsertItalic(i: MarkdownTextArea, event: any) { handleInsertItalic(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
i.simpleSurround('*'); i.simpleSurround("*");
} }
handleInsertCode(i: MarkdownTextArea, event: any) { handleInsertCode(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
i.simpleSurround('`'); i.simpleSurround("`");
} }
handleInsertStrikethrough(i: MarkdownTextArea, event: any) { handleInsertStrikethrough(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
i.simpleSurround('~~'); i.simpleSurround("~~");
} }
handleInsertList(i: MarkdownTextArea, event: any) { handleInsertList(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
i.simpleBeginningofLine('-'); i.simpleBeginningofLine("-");
} }
handleInsertQuote(i: MarkdownTextArea, event: any) { handleInsertQuote(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
i.simpleBeginningofLine('>'); i.simpleBeginningofLine(">");
} }
handleInsertHeader(i: MarkdownTextArea, event: any) { handleInsertHeader(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
i.simpleBeginningofLine('#'); i.simpleBeginningofLine("#");
} }
handleInsertSubscript(i: MarkdownTextArea, event: any) { handleInsertSubscript(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
i.simpleSurround('~'); i.simpleSurround("~");
} }
handleInsertSuperscript(i: MarkdownTextArea, event: any) { handleInsertSuperscript(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
i.simpleSurround('^'); i.simpleSurround("^");
} }
simpleInsert(chars: string) { simpleInsert(chars: string) {
@ -509,13 +516,14 @@ export class MarkdownTextArea extends Component<
setTimeout(() => { setTimeout(() => {
autosize.update(textarea); autosize.update(textarea);
}, 10); }, 10);
this.contentChange();
this.setState(this.state); this.setState(this.state);
} }
handleInsertSpoiler(i: MarkdownTextArea, event: any) { handleInsertSpoiler(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
let beforeChars = `\n::: spoiler ${i18n.t('spoiler')}\n`; let beforeChars = `\n::: spoiler ${i18n.t("spoiler")}\n`;
let afterChars = '\n:::\n'; let afterChars = "\n:::\n";
i.simpleSurroundBeforeAfter(beforeChars, afterChars); i.simpleSurroundBeforeAfter(beforeChars, afterChars);
} }
@ -525,15 +533,16 @@ export class MarkdownTextArea extends Component<
if (selectedText) { if (selectedText) {
let quotedText = let quotedText =
selectedText selectedText
.split('\n') .split("\n")
.map(t => `> ${t}`) .map(t => `> ${t}`)
.join('\n') + '\n\n'; .join("\n") + "\n\n";
if (this.state.content == null) { if (this.state.content == null) {
this.state.content = ''; this.state.content = "";
} else { } else {
this.state.content += '\n'; this.state.content += "\n";
} }
this.state.content += quotedText; this.state.content += quotedText;
this.contentChange();
this.setState(this.state); this.setState(this.state);
// Not sure why this needs a delay // Not sure why this needs a delay
setTimeout(() => autosize.update(textarea), 10); setTimeout(() => autosize.update(textarea), 10);

View file

@ -1,6 +1,6 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Link } from 'inferno-router'; import { Link } from "inferno-router";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
UserOperation, UserOperation,
GetModlog, GetModlog,
@ -15,8 +15,8 @@ import {
ModBanView, ModBanView,
ModAddCommunityView, ModAddCommunityView,
ModAddView, ModAddView,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService } from '../services'; import { WebSocketService } from "../services";
import { import {
wsJsonToRes, wsJsonToRes,
fetchLimit, fetchLimit,
@ -26,15 +26,15 @@ import {
isBrowser, isBrowser,
wsUserOp, wsUserOp,
wsClient, wsClient,
} from '../utils'; } from "../utils";
import { MomentTime } from './moment-time'; import { MomentTime } from "./moment-time";
import { HtmlTags } from './html-tags'; import { HtmlTags } from "./html-tags";
import moment from 'moment'; import moment from "moment";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { InitialFetchRequest } from 'shared/interfaces'; import { InitialFetchRequest } from "shared/interfaces";
import { UserListing } from './user-listing'; import { UserListing } from "./user-listing";
import { CommunityLink } from './community-link'; import { CommunityLink } from "./community-link";
import { Spinner } from './icon'; import { Spinner } from "./icon";
enum ModlogEnum { enum ModlogEnum {
ModRemovePost, ModRemovePost,
@ -214,7 +214,7 @@ export class Modlog extends Component<any, ModlogState> {
case ModlogEnum.ModRemovePost: { case ModlogEnum.ModRemovePost: {
let mrpv = i.view as ModRemovePostView; let mrpv = i.view as ModRemovePostView;
return [ return [
mrpv.mod_remove_post.removed ? 'Removed ' : 'Restored ', mrpv.mod_remove_post.removed ? "Removed " : "Restored ",
<span> <span>
Post <Link to={`/post/${mrpv.post.id}`}>{mrpv.post.name}</Link> Post <Link to={`/post/${mrpv.post.id}`}>{mrpv.post.name}</Link>
</span>, </span>,
@ -225,7 +225,7 @@ export class Modlog extends Component<any, ModlogState> {
case ModlogEnum.ModLockPost: { case ModlogEnum.ModLockPost: {
let mlpv = i.view as ModLockPostView; let mlpv = i.view as ModLockPostView;
return [ return [
mlpv.mod_lock_post.locked ? 'Locked ' : 'Unlocked ', mlpv.mod_lock_post.locked ? "Locked " : "Unlocked ",
<span> <span>
Post <Link to={`/post/${mlpv.post.id}`}>{mlpv.post.name}</Link> Post <Link to={`/post/${mlpv.post.id}`}>{mlpv.post.name}</Link>
</span>, </span>,
@ -234,7 +234,7 @@ export class Modlog extends Component<any, ModlogState> {
case ModlogEnum.ModStickyPost: { case ModlogEnum.ModStickyPost: {
let mspv = i.view as ModStickyPostView; let mspv = i.view as ModStickyPostView;
return [ return [
mspv.mod_sticky_post.stickied ? 'Stickied ' : 'Unstickied ', mspv.mod_sticky_post.stickied ? "Stickied " : "Unstickied ",
<span> <span>
Post <Link to={`/post/${mspv.post.id}`}>{mspv.post.name}</Link> Post <Link to={`/post/${mspv.post.id}`}>{mspv.post.name}</Link>
</span>, </span>,
@ -243,15 +243,15 @@ export class Modlog extends Component<any, ModlogState> {
case ModlogEnum.ModRemoveComment: { case ModlogEnum.ModRemoveComment: {
let mrc = i.view as ModRemoveCommentView; let mrc = i.view as ModRemoveCommentView;
return [ return [
mrc.mod_remove_comment.removed ? 'Removed ' : 'Restored ', mrc.mod_remove_comment.removed ? "Removed " : "Restored ",
<span> <span>
Comment{' '} Comment{" "}
<Link to={`/post/${mrc.post.id}/comment/${mrc.comment.id}`}> <Link to={`/post/${mrc.post.id}/comment/${mrc.comment.id}`}>
{mrc.comment.content} {mrc.comment.content}
</Link> </Link>
</span>, </span>,
<span> <span>
{' '} {" "}
by <UserListing user={mrc.commenter} /> by <UserListing user={mrc.commenter} />
</span>, </span>,
mrc.mod_remove_comment.reason && mrc.mod_remove_comment.reason &&
@ -261,7 +261,7 @@ export class Modlog extends Component<any, ModlogState> {
case ModlogEnum.ModRemoveCommunity: { case ModlogEnum.ModRemoveCommunity: {
let mrco = i.view as ModRemoveCommunityView; let mrco = i.view as ModRemoveCommunityView;
return [ return [
mrco.mod_remove_community.removed ? 'Removed ' : 'Restored ', mrco.mod_remove_community.removed ? "Removed " : "Restored ",
<span> <span>
Community <CommunityLink community={mrco.community} /> Community <CommunityLink community={mrco.community} />
</span>, </span>,
@ -277,7 +277,7 @@ export class Modlog extends Component<any, ModlogState> {
let mbfc = i.view as ModBanFromCommunityView; let mbfc = i.view as ModBanFromCommunityView;
return [ return [
<span> <span>
{mbfc.mod_ban_from_community.banned ? 'Banned ' : 'Unbanned '}{' '} {mbfc.mod_ban_from_community.banned ? "Banned " : "Unbanned "}{" "}
</span>, </span>,
<span> <span>
<UserListing user={mbfc.banned_user} /> <UserListing user={mbfc.banned_user} />
@ -302,7 +302,7 @@ export class Modlog extends Component<any, ModlogState> {
let mac = i.view as ModAddCommunityView; let mac = i.view as ModAddCommunityView;
return [ return [
<span> <span>
{mac.mod_add_community.removed ? 'Removed ' : 'Appointed '}{' '} {mac.mod_add_community.removed ? "Removed " : "Appointed "}{" "}
</span>, </span>,
<span> <span>
<UserListing user={mac.modded_user} /> <UserListing user={mac.modded_user} />
@ -316,7 +316,7 @@ export class Modlog extends Component<any, ModlogState> {
case ModlogEnum.ModBan: { case ModlogEnum.ModBan: {
let mb = i.view as ModBanView; let mb = i.view as ModBanView;
return [ return [
<span>{mb.mod_ban.banned ? 'Banned ' : 'Unbanned '} </span>, <span>{mb.mod_ban.banned ? "Banned " : "Unbanned "} </span>,
<span> <span>
<UserListing user={mb.banned_user} /> <UserListing user={mb.banned_user} />
</span>, </span>,
@ -330,7 +330,7 @@ export class Modlog extends Component<any, ModlogState> {
case ModlogEnum.ModAdd: { case ModlogEnum.ModAdd: {
let ma = i.view as ModAddView; let ma = i.view as ModAddView;
return [ return [
<span>{ma.mod_add.removed ? 'Removed ' : 'Appointed '} </span>, <span>{ma.mod_add.removed ? "Removed " : "Appointed "} </span>,
<span> <span>
<UserListing user={ma.modded_user} /> <UserListing user={ma.modded_user} />
</span>, </span>,
@ -385,18 +385,18 @@ export class Modlog extends Component<any, ModlogState> {
className="text-body" className="text-body"
to={`/c/${this.state.communityName}`} to={`/c/${this.state.communityName}`}
> >
/c/{this.state.communityName}{' '} /c/{this.state.communityName}{" "}
</Link> </Link>
)} )}
<span>{i18n.t('modlog')}</span> <span>{i18n.t("modlog")}</span>
</h5> </h5>
<div class="table-responsive"> <div class="table-responsive">
<table id="modlog_table" class="table table-sm table-hover"> <table id="modlog_table" class="table table-sm table-hover">
<thead class="pointer"> <thead class="pointer">
<tr> <tr>
<th> {i18n.t('time')}</th> <th> {i18n.t("time")}</th>
<th>{i18n.t('mod')}</th> <th>{i18n.t("mod")}</th>
<th>{i18n.t('action')}</th> <th>{i18n.t("action")}</th>
</tr> </tr>
</thead> </thead>
{this.combined()} {this.combined()}
@ -417,14 +417,14 @@ export class Modlog extends Component<any, ModlogState> {
class="btn btn-secondary mr-1" class="btn btn-secondary mr-1"
onClick={linkEvent(this, this.prevPage)} onClick={linkEvent(this, this.prevPage)}
> >
{i18n.t('prev')} {i18n.t("prev")}
</button> </button>
)} )}
<button <button
class="btn btn-secondary" class="btn btn-secondary"
onClick={linkEvent(this, this.nextPage)} onClick={linkEvent(this, this.nextPage)}
> >
{i18n.t('next')} {i18n.t("next")}
</button> </button>
</div> </div>
); );
@ -452,7 +452,7 @@ export class Modlog extends Component<any, ModlogState> {
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split('/'); let pathSplit = req.path.split("/");
let communityId = pathSplit[3]; let communityId = pathSplit[3];
let promises: Promise<any>[] = []; let promises: Promise<any>[] = [];
@ -472,7 +472,7 @@ export class Modlog extends Component<any, ModlogState> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
return; return;
} else if (op == UserOperation.GetModlog) { } else if (op == UserOperation.GetModlog) {
let data = wsJsonToRes<GetModlogResponse>(msg).data; let data = wsJsonToRes<GetModlogResponse>(msg).data;

View file

@ -1,8 +1,8 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import moment from 'moment'; import moment from "moment";
import { getMomentLanguage, capitalizeFirstLetter } from '../utils'; import { getMomentLanguage, capitalizeFirstLetter } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { Icon } from './icon'; import { Icon } from "./icon";
interface MomentTimeProps { interface MomentTimeProps {
data: { data: {
@ -28,7 +28,7 @@ export class MomentTime extends Component<MomentTimeProps, any> {
return ( return (
<span <span
data-tippy-content={`${capitalizeFirstLetter( data-tippy-content={`${capitalizeFirstLetter(
i18n.t('modified') i18n.t("modified")
)} ${this.format(this.props.data.updated)}`} )} ${this.format(this.props.data.updated)}`}
className="font-italics pointer unselectable" className="font-italics pointer unselectable"
> >
@ -50,6 +50,6 @@ export class MomentTime extends Component<MomentTimeProps, any> {
} }
format(input: string): string { format(input: string): string {
return moment.utc(input).local().format('LLLL'); return moment.utc(input).local().format("LLLL");
} }
} }

View file

@ -1,7 +1,7 @@
import { Component, linkEvent, createRef, RefObject } from 'inferno'; import { Component, linkEvent, createRef, RefObject } from "inferno";
import { Link } from 'inferno-router'; import { Link } from "inferno-router";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { import {
UserOperation, UserOperation,
GetReplies, GetReplies,
@ -16,7 +16,7 @@ import {
CommentResponse, CommentResponse,
PrivateMessageResponse, PrivateMessageResponse,
PrivateMessageView, PrivateMessageView,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { import {
wsJsonToRes, wsJsonToRes,
showAvatars, showAvatars,
@ -32,10 +32,10 @@ import {
wsUserOp, wsUserOp,
wsClient, wsClient,
authField, authField,
} from '../utils'; } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { PictrsImage } from './pictrs-image'; import { PictrsImage } from "./pictrs-image";
import { Icon } from './icon'; import { Icon } from "./icon";
interface NavbarProps { interface NavbarProps {
site_res: GetSiteResponse; site_res: GetSiteResponse;
@ -65,7 +65,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
mentions: [], mentions: [],
messages: [], messages: [],
expanded: false, expanded: false,
searchParam: '', searchParam: "",
toggleSearch: false, toggleSearch: false,
}; };
subscription: any; subscription: any;
@ -127,9 +127,9 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
updateUrl() { updateUrl() {
const searchParam = this.state.searchParam; const searchParam = this.state.searchParam;
this.setState({ searchParam: '' }); this.setState({ searchParam: "" });
this.setState({ toggleSearch: false }); this.setState({ toggleSearch: false });
if (searchParam === '') { if (searchParam === "") {
this.context.router.history.push(`/search/`); this.context.router.history.push(`/search/`);
} else { } else {
const searchParamEncoded = encodeURIComponent(searchParam); const searchParamEncoded = encodeURIComponent(searchParam);
@ -156,7 +156,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
} }
handleSearchBlur(i: Navbar, event: any) { handleSearchBlur(i: Navbar, event: any) {
if (!(event.relatedTarget && event.relatedTarget.name !== 'search-btn')) { if (!(event.relatedTarget && event.relatedTarget.name !== "search-btn")) {
i.state.toggleSearch = false; i.state.toggleSearch = false;
i.setState(i.state); i.setState(i.state);
} }
@ -197,14 +197,14 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<Link <Link
className="ml-auto p-1 navbar-toggler nav-link border-0" className="ml-auto p-1 navbar-toggler nav-link border-0"
to="/inbox" to="/inbox"
title={i18n.t('inbox')} title={i18n.t("inbox")}
> >
<Icon icon="bell" /> <Icon icon="bell" />
{this.state.unreadCount > 0 && ( {this.state.unreadCount > 0 && (
<span <span
class="mx-1 badge badge-light" class="mx-1 badge badge-light"
aria-label={`${this.state.unreadCount} ${i18n.t( aria-label={`${this.state.unreadCount} ${i18n.t(
'unread_messages' "unread_messages"
)}`} )}`}
> >
{this.state.unreadCount} {this.state.unreadCount}
@ -217,48 +217,48 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
type="button" type="button"
aria-label="menu" aria-label="menu"
onClick={linkEvent(this, this.expandNavbar)} onClick={linkEvent(this, this.expandNavbar)}
data-tippy-content={i18n.t('expand_here')} data-tippy-content={i18n.t("expand_here")}
> >
<Icon icon="menu" /> <Icon icon="menu" />
</button> </button>
<div <div
className={`${!this.state.expanded && 'collapse'} navbar-collapse`} className={`${!this.state.expanded && "collapse"} navbar-collapse`}
> >
<ul class="navbar-nav my-2 mr-auto"> <ul class="navbar-nav my-2 mr-auto">
<li class="nav-item"> <li class="nav-item">
<Link <Link
className="nav-link" className="nav-link"
to="/communities" to="/communities"
title={i18n.t('communities')} title={i18n.t("communities")}
> >
{i18n.t('communities')} {i18n.t("communities")}
</Link> </Link>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<Link <Link
className="nav-link" className="nav-link"
to={{ to={{
pathname: '/create_post', pathname: "/create_post",
state: { prevPath: this.currentLocation }, state: { prevPath: this.currentLocation },
}} }}
title={i18n.t('create_post')} title={i18n.t("create_post")}
> >
{i18n.t('create_post')} {i18n.t("create_post")}
</Link> </Link>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<Link <Link
className="nav-link" className="nav-link"
to="/create_community" to="/create_community"
title={i18n.t('create_community')} title={i18n.t("create_community")}
> >
{i18n.t('create_community')} {i18n.t("create_community")}
</Link> </Link>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a <a
className="nav-link" className="nav-link"
title={i18n.t('support_lemmy')} title={i18n.t("support_lemmy")}
href={supportLemmyUrl} href={supportLemmyUrl}
> >
<Icon icon="beer" classes="small" /> <Icon icon="beer" classes="small" />
@ -271,7 +271,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<Link <Link
className="nav-link" className="nav-link"
to={`/admin`} to={`/admin`}
title={i18n.t('admin_settings')} title={i18n.t("admin_settings")}
> >
<Icon icon="settings" /> <Icon icon="settings" />
</Link> </Link>
@ -288,24 +288,24 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<input <input
id="search-input" id="search-input"
class={`form-control mr-0 search-input ${ class={`form-control mr-0 search-input ${
this.state.toggleSearch ? 'show-input' : 'hide-input' this.state.toggleSearch ? "show-input" : "hide-input"
}`} }`}
onInput={linkEvent(this, this.handleSearchParam)} onInput={linkEvent(this, this.handleSearchParam)}
value={this.state.searchParam} value={this.state.searchParam}
ref={this.searchTextField} ref={this.searchTextField}
type="text" type="text"
placeholder={i18n.t('search')} placeholder={i18n.t("search")}
onBlur={linkEvent(this, this.handleSearchBlur)} onBlur={linkEvent(this, this.handleSearchBlur)}
></input> ></input>
<label class="sr-only" htmlFor="search-input"> <label class="sr-only" htmlFor="search-input">
{i18n.t('search')} {i18n.t("search")}
</label> </label>
<button <button
name="search-btn" name="search-btn"
onClick={linkEvent(this, this.handleSearchBtn)} onClick={linkEvent(this, this.handleSearchBtn)}
class="px-1 btn btn-link" class="px-1 btn btn-link"
style="color: var(--gray)" style="color: var(--gray)"
aria-label={i18n.t('search')} aria-label={i18n.t("search")}
> >
<Icon icon="search" /> <Icon icon="search" />
</button> </button>
@ -318,14 +318,14 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<Link <Link
className="nav-link" className="nav-link"
to="/inbox" to="/inbox"
title={i18n.t('inbox')} title={i18n.t("inbox")}
> >
<Icon icon="bell" /> <Icon icon="bell" />
{this.state.unreadCount > 0 && ( {this.state.unreadCount > 0 && (
<span <span
class="ml-1 badge badge-light" class="ml-1 badge badge-light"
aria-label={`${this.state.unreadCount} ${i18n.t( aria-label={`${this.state.unreadCount} ${i18n.t(
'unread_messages' "unread_messages"
)}`} )}`}
> >
{this.state.unreadCount} {this.state.unreadCount}
@ -339,7 +339,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<Link <Link
className="nav-link" className="nav-link"
to={`/u/${user.name}`} to={`/u/${user.name}`}
title={i18n.t('settings')} title={i18n.t("settings")}
> >
<span> <span>
{user.avatar && showAvatars() && ( {user.avatar && showAvatars() && (
@ -359,9 +359,9 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<Link <Link
className="btn btn-success" className="btn btn-success"
to="/login" to="/login"
title={i18n.t('login_sign_up')} title={i18n.t("login_sign_up")}
> >
{i18n.t('login_sign_up')} {i18n.t("login_sign_up")}
</Link> </Link>
</li> </li>
</ul> </ul>
@ -380,7 +380,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
if (msg.error == 'not_logged_in') { if (msg.error == "not_logged_in") {
UserService.Instance.logout(); UserService.Instance.logout();
location.reload(); location.reload();
} }
@ -457,7 +457,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
} }
fetchUnreads() { fetchUnreads() {
console.log('Fetching unreads...'); console.log("Fetching unreads...");
let repliesForm: GetReplies = { let repliesForm: GetReplies = {
sort: SortType.New, sort: SortType.New,
unread_only: true, unread_only: true,
@ -481,7 +481,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
auth: authField(), auth: authField(),
}; };
if (this.currentLocation !== '/inbox') { if (this.currentLocation !== "/inbox") {
WebSocketService.Instance.send(wsClient.getReplies(repliesForm)); WebSocketService.Instance.send(wsClient.getReplies(repliesForm));
WebSocketService.Instance.send( WebSocketService.Instance.send(
wsClient.getUserMentions(userMentionsForm) wsClient.getUserMentions(userMentionsForm)
@ -519,13 +519,13 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
requestNotificationPermission() { requestNotificationPermission() {
if (UserService.Instance.user) { if (UserService.Instance.user) {
document.addEventListener('DOMContentLoaded', function () { document.addEventListener("DOMContentLoaded", function () {
if (!Notification) { if (!Notification) {
toast(i18n.t('notifications_error'), 'danger'); toast(i18n.t("notifications_error"), "danger");
return; return;
} }
if (Notification.permission !== 'granted') if (Notification.permission !== "granted")
Notification.requestPermission(); Notification.requestPermission();
}); });
} }

View file

@ -1,8 +1,8 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
export class NoMatch extends Component<any, any> { export class NoMatch extends Component<any, any> {
private errCode = new URLSearchParams(this.props.location.search).get('err'); private errCode = new URLSearchParams(this.props.location.search).get("err");
constructor(props: any, context: any) { constructor(props: any, context: any) {
super(props, context); super(props, context);
@ -14,7 +14,7 @@ export class NoMatch extends Component<any, any> {
<h1>404</h1> <h1>404</h1>
{this.errCode && ( {this.errCode && (
<h3> <h3>
{i18n.t('code')}: {i18n.t(this.errCode)} {i18n.t("code")}: {i18n.t(this.errCode)}
</h3> </h3>
)} )}
</div> </div>

View file

@ -1,12 +1,12 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
UserOperation, UserOperation,
LoginResponse, LoginResponse,
PasswordChange as PasswordChangeForm, PasswordChange as PasswordChangeForm,
SiteView, SiteView,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { import {
wsJsonToRes, wsJsonToRes,
capitalizeFirstLetter, capitalizeFirstLetter,
@ -16,10 +16,10 @@ import {
wsSubscribe, wsSubscribe,
wsUserOp, wsUserOp,
wsClient, wsClient,
} from '../utils'; } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { HtmlTags } from './html-tags'; import { HtmlTags } from "./html-tags";
import { Spinner } from './icon'; import { Spinner } from "./icon";
interface State { interface State {
passwordChangeForm: PasswordChangeForm; passwordChangeForm: PasswordChangeForm;
@ -57,7 +57,7 @@ export class PasswordChange extends Component<any, State> {
} }
get documentTitle(): string { get documentTitle(): string {
return `${i18n.t('password_change')} - ${this.state.site_view.site.name}`; return `${i18n.t("password_change")} - ${this.state.site_view.site.name}`;
} }
render() { render() {
@ -69,7 +69,7 @@ export class PasswordChange extends Component<any, State> {
/> />
<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>
{this.passwordChangeForm()} {this.passwordChangeForm()}
</div> </div>
</div> </div>
@ -82,7 +82,7 @@ export class PasswordChange extends Component<any, State> {
<form onSubmit={linkEvent(this, this.handlePasswordChangeSubmit)}> <form onSubmit={linkEvent(this, this.handlePasswordChangeSubmit)}>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="new-password"> <label class="col-sm-2 col-form-label" htmlFor="new-password">
{i18n.t('new_password')} {i18n.t("new_password")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input <input
@ -97,7 +97,7 @@ export class PasswordChange extends Component<any, State> {
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="verify-password"> <label class="col-sm-2 col-form-label" htmlFor="verify-password">
{i18n.t('verify_password')} {i18n.t("verify_password")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input <input
@ -116,7 +116,7 @@ export class PasswordChange extends Component<any, State> {
{this.state.loading ? ( {this.state.loading ? (
<Spinner /> <Spinner />
) : ( ) : (
capitalizeFirstLetter(i18n.t('save')) capitalizeFirstLetter(i18n.t("save"))
)} )}
</button> </button>
</div> </div>
@ -148,7 +148,7 @@ export class PasswordChange extends Component<any, State> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
this.state.loading = false; this.state.loading = false;
this.setState(this.state); this.setState(this.state);
return; return;
@ -157,7 +157,7 @@ export class PasswordChange extends Component<any, State> {
this.state = this.emptyState; this.state = this.emptyState;
this.setState(this.state); this.setState(this.state);
UserService.Instance.login(data); UserService.Instance.login(data);
this.props.history.push('/'); this.props.history.push("/");
} }
} }
} }

View file

@ -1,4 +1,4 @@
import { Component } from 'inferno'; import { Component } from "inferno";
const iconThumbnailSize = 96; const iconThumbnailSize = 96;
const thumbnailSize = 256; const thumbnailSize = 256;
@ -22,22 +22,22 @@ export class PictrsImage extends Component<PictrsImageProps, any> {
render() { render() {
return ( return (
<picture> <picture>
<source srcSet={this.src('webp')} type="image/webp" /> <source srcSet={this.src("webp")} type="image/webp" />
<source srcSet={this.src('jpg')} type="image/jpeg" /> <source srcSet={this.src("jpg")} type="image/jpeg" />
<img <img
src={this.src('jpg')} src={this.src("jpg")}
alt={this.alt()} alt={this.alt()}
className={` className={`
${!this.props.icon && !this.props.iconOverlay && 'img-fluid '} ${!this.props.icon && !this.props.iconOverlay && "img-fluid "}
${ ${
this.props.thumbnail && !this.props.icon this.props.thumbnail && !this.props.icon
? 'thumbnail rounded ' ? "thumbnail rounded "
: 'img-expanded ' : "img-expanded "
} }
${this.props.thumbnail && this.props.nsfw && 'img-blur '} ${this.props.thumbnail && this.props.nsfw && "img-blur "}
${this.props.icon && 'rounded-circle img-icon mr-2 '} ${this.props.icon && "rounded-circle img-icon mr-2 "}
${this.props.iconOverlay && 'ml-2 mb-0 rounded-circle avatar-overlay '} ${this.props.iconOverlay && "ml-2 mb-0 rounded-circle avatar-overlay "}
${this.props.pushup && 'avatar-pushup '} ${this.props.pushup && "avatar-pushup "}
`} `}
/> />
</picture> </picture>
@ -48,7 +48,7 @@ export class PictrsImage extends Component<PictrsImageProps, any> {
// sample url: // sample url:
// http://localhost:8535/pictrs/image/file.png?thumbnail=256&format=jpg // http://localhost:8535/pictrs/image/file.png?thumbnail=256&format=jpg
let split = this.props.src.split('/pictrs/image/'); let split = this.props.src.split("/pictrs/image/");
// If theres not multiple, then its not a pictrs image // If theres not multiple, then its not a pictrs image
if (split.length == 1) { if (split.length == 1) {
@ -61,11 +61,11 @@ export class PictrsImage extends Component<PictrsImageProps, any> {
let params = { format }; let params = { format };
if (this.props.thumbnail) { if (this.props.thumbnail) {
params['thumbnail'] = thumbnailSize; params["thumbnail"] = thumbnailSize;
} else if (this.props.icon) { } else if (this.props.icon) {
params['thumbnail'] = iconThumbnailSize; params["thumbnail"] = iconThumbnailSize;
} else { } else {
params['thumbnail'] = maxImageSize; params["thumbnail"] = maxImageSize;
} }
let paramsStr = `?${new URLSearchParams(params).toString()}`; let paramsStr = `?${new URLSearchParams(params).toString()}`;
@ -76,8 +76,8 @@ export class PictrsImage extends Component<PictrsImageProps, any> {
alt(): string { alt(): string {
if (this.props.icon) { if (this.props.icon) {
return ''; return "";
} }
return this.props.alt || ''; return this.props.alt || "";
} }
} }

View file

@ -1,9 +1,9 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Prompt } from 'inferno-router'; import { Prompt } from "inferno-router";
import { PostListings } from './post-listings'; import { PostListings } from "./post-listings";
import { MarkdownTextArea } from './markdown-textarea'; import { MarkdownTextArea } from "./markdown-textarea";
import { Icon, Spinner } from './icon'; import { Icon, Spinner } from "./icon";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
CreatePost, CreatePost,
EditPost, EditPost,
@ -15,9 +15,9 @@ import {
Search, Search,
SearchType, SearchType,
SearchResponse, SearchResponse,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { PostFormParams } from '../interfaces'; import { PostFormParams } from "../interfaces";
import { import {
wsJsonToRes, wsJsonToRes,
getPageTitle, getPageTitle,
@ -36,16 +36,16 @@ import {
wsUserOp, wsUserOp,
wsClient, wsClient,
authField, authField,
} from '../utils'; } from "../utils";
import autosize from 'autosize'; import autosize from "autosize";
var Choices; var Choices;
if (isBrowser()) { if (isBrowser()) {
Choices = require('choices.js'); Choices = require("choices.js");
} }
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { pictrsUri } from '../env'; import { pictrsUri } from "../env";
const MAX_POST_TITLE_LENGTH = 200; const MAX_POST_TITLE_LENGTH = 200;
@ -125,7 +125,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
componentDidMount() { componentDidMount() {
setupTippy(); setupTippy();
this.setupCommunities(); this.setupCommunities();
let textarea: any = document.getElementById('post-title'); let textarea: any = document.getElementById("post-title");
if (textarea) { if (textarea) {
autosize(textarea); autosize(textarea);
} }
@ -160,12 +160,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
this.state.postForm.url || this.state.postForm.url ||
this.state.postForm.body) this.state.postForm.body)
} }
message={i18n.t('block_leaving')} message={i18n.t("block_leaving")}
/> />
<form onSubmit={linkEvent(this, this.handlePostSubmit)}> <form onSubmit={linkEvent(this, this.handlePostSubmit)}>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="post-url"> <label class="col-sm-2 col-form-label" htmlFor="post-url">
{i18n.t('url')} {i18n.t("url")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input <input
@ -182,7 +182,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
role="button" role="button"
onClick={linkEvent(this, this.copySuggestedTitle)} onClick={linkEvent(this, this.copySuggestedTitle)}
> >
{i18n.t('copy_suggested_title', { {i18n.t("copy_suggested_title", {
title: this.state.suggestedTitle, title: this.state.suggestedTitle,
})} })}
</div> </div>
@ -191,9 +191,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
<label <label
htmlFor="file-upload" htmlFor="file-upload"
className={`${ className={`${
UserService.Instance.user && 'pointer' UserService.Instance.user && "pointer"
} d-inline-block float-right text-muted font-weight-bold`} } d-inline-block float-right text-muted font-weight-bold`}
data-tippy-content={i18n.t('upload_image')} data-tippy-content={i18n.t("upload_image")}
> >
<Icon icon="image" classes="icon-inline" /> <Icon icon="image" classes="icon-inline" />
</label> </label>
@ -215,7 +215,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
class="mr-2 d-inline-block float-right text-muted small font-weight-bold" class="mr-2 d-inline-block float-right text-muted small font-weight-bold"
rel="noopener" rel="noopener"
> >
{i18n.t('archive_link')} {i18n.t("archive_link")}
</a> </a>
)} )}
{this.state.imageLoading && <Spinner />} {this.state.imageLoading && <Spinner />}
@ -225,7 +225,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
{this.state.crossPosts.length > 0 && ( {this.state.crossPosts.length > 0 && (
<> <>
<div class="my-1 text-muted small font-weight-bold"> <div class="my-1 text-muted small font-weight-bold">
{i18n.t('cross_posts')} {i18n.t("cross_posts")}
</div> </div>
<PostListings <PostListings
showCommunity showCommunity
@ -239,7 +239,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="post-title"> <label class="col-sm-2 col-form-label" htmlFor="post-title">
{i18n.t('title')} {i18n.t("title")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<textarea <textarea
@ -247,7 +247,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
id="post-title" id="post-title"
onInput={linkEvent(this, this.handlePostNameChange)} onInput={linkEvent(this, this.handlePostNameChange)}
class={`form-control ${ class={`form-control ${
!validTitle(this.state.postForm.name) && 'is-invalid' !validTitle(this.state.postForm.name) && "is-invalid"
}`} }`}
required required
rows={1} rows={1}
@ -256,13 +256,13 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
/> />
{!validTitle(this.state.postForm.name) && ( {!validTitle(this.state.postForm.name) && (
<div class="invalid-feedback"> <div class="invalid-feedback">
{i18n.t('invalid_post_title')} {i18n.t("invalid_post_title")}
</div> </div>
)} )}
{this.state.suggestedPosts.length > 0 && ( {this.state.suggestedPosts.length > 0 && (
<> <>
<div class="my-1 text-muted small font-weight-bold"> <div class="my-1 text-muted small font-weight-bold">
{i18n.t('related_posts')} {i18n.t("related_posts")}
</div> </div>
<PostListings <PostListings
posts={this.state.suggestedPosts} posts={this.state.suggestedPosts}
@ -275,7 +275,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label">{i18n.t('body')}</label> <label class="col-sm-2 col-form-label">{i18n.t("body")}</label>
<div class="col-sm-10"> <div class="col-sm-10">
<MarkdownTextArea <MarkdownTextArea
initialContent={this.state.postForm.body} initialContent={this.state.postForm.body}
@ -286,7 +286,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
{!this.props.post_view && ( {!this.props.post_view && (
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="post-community"> <label class="col-sm-2 col-form-label" htmlFor="post-community">
{i18n.t('community')} {i18n.t("community")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<select <select
@ -295,7 +295,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
value={this.state.postForm.community_id} value={this.state.postForm.community_id}
onInput={linkEvent(this, this.handlePostCommunityChange)} onInput={linkEvent(this, this.handlePostCommunityChange)}
> >
<option>{i18n.t('select_a_community')}</option> <option>{i18n.t("select_a_community")}</option>
{this.props.communities.map(cv => ( {this.props.communities.map(cv => (
<option value={cv.community.id}> <option value={cv.community.id}>
{cv.community.local {cv.community.local
@ -321,7 +321,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
onChange={linkEvent(this, this.handlePostNsfwChange)} onChange={linkEvent(this, this.handlePostNsfwChange)}
/> />
<label class="form-check-label" htmlFor="post-nsfw"> <label class="form-check-label" htmlFor="post-nsfw">
{i18n.t('nsfw')} {i18n.t("nsfw")}
</label> </label>
</div> </div>
</div> </div>
@ -339,9 +339,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
{this.state.loading ? ( {this.state.loading ? (
<Spinner /> <Spinner />
) : this.props.post_view ? ( ) : this.props.post_view ? (
capitalizeFirstLetter(i18n.t('save')) capitalizeFirstLetter(i18n.t("save"))
) : ( ) : (
capitalizeFirstLetter(i18n.t('create')) capitalizeFirstLetter(i18n.t("create"))
)} )}
</button> </button>
{this.props.post_view && ( {this.props.post_view && (
@ -350,7 +350,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
class="btn btn-secondary" class="btn btn-secondary"
onClick={linkEvent(this, this.handleCancel)} onClick={linkEvent(this, this.handleCancel)}
> >
{i18n.t('cancel')} {i18n.t("cancel")}
</button> </button>
)} )}
</div> </div>
@ -364,7 +364,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
event.preventDefault(); event.preventDefault();
// Coerce empty url string to undefined // Coerce empty url string to undefined
if (i.state.postForm.url !== undefined && i.state.postForm.url === '') { if (i.state.postForm.url !== undefined && i.state.postForm.url === "") {
i.state.postForm.url = undefined; i.state.postForm.url = undefined;
} }
@ -388,7 +388,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
); );
i.state.suggestedTitle = undefined; i.state.suggestedTitle = undefined;
setTimeout(() => { setTimeout(() => {
let textarea: any = document.getElementById('post-title'); let textarea: any = document.getElementById("post-title");
autosize.update(textarea); autosize.update(textarea);
}, 10); }, 10);
i.setState(i.state); i.setState(i.state);
@ -441,7 +441,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
auth: authField(false), auth: authField(false),
}; };
if (this.state.postForm.name !== '') { if (this.state.postForm.name !== "") {
WebSocketService.Instance.send(wsClient.search(form)); WebSocketService.Instance.send(wsClient.search(form));
} else { } else {
this.state.suggestedPosts = []; this.state.suggestedPosts = [];
@ -492,20 +492,20 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
} }
const formData = new FormData(); const formData = new FormData();
formData.append('images[]', file); formData.append("images[]", file);
i.state.imageLoading = true; i.state.imageLoading = true;
i.setState(i.state); i.setState(i.state);
fetch(pictrsUri, { fetch(pictrsUri, {
method: 'POST', method: "POST",
body: formData, body: formData,
}) })
.then(res => res.json()) .then(res => res.json())
.then(res => { .then(res => {
console.log('pictrs upload:'); console.log("pictrs upload:");
console.log(res); console.log(res);
if (res.msg == 'ok') { if (res.msg == "ok") {
let hash = res.files[0].file; let hash = res.files[0].file;
let url = `${pictrsUri}/${hash}`; let url = `${pictrsUri}/${hash}`;
let deleteToken = res.files[0].delete_token; let deleteToken = res.files[0].delete_token;
@ -514,61 +514,61 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
i.state.imageLoading = false; i.state.imageLoading = false;
i.setState(i.state); i.setState(i.state);
pictrsDeleteToast( pictrsDeleteToast(
i18n.t('click_to_delete_picture'), i18n.t("click_to_delete_picture"),
i18n.t('picture_deleted'), i18n.t("picture_deleted"),
deleteUrl deleteUrl
); );
} else { } else {
i.state.imageLoading = false; i.state.imageLoading = false;
i.setState(i.state); i.setState(i.state);
toast(JSON.stringify(res), 'danger'); toast(JSON.stringify(res), "danger");
} }
}) })
.catch(error => { .catch(error => {
i.state.imageLoading = false; i.state.imageLoading = false;
i.setState(i.state); i.setState(i.state);
toast(error, 'danger'); toast(error, "danger");
}); });
} }
setupCommunities() { setupCommunities() {
// Set up select searching // Set up select searching
if (isBrowser()) { if (isBrowser()) {
let selectId: any = document.getElementById('post-community'); let selectId: any = document.getElementById("post-community");
if (selectId) { if (selectId) {
this.choices = new Choices(selectId, { this.choices = new Choices(selectId, {
shouldSort: false, shouldSort: false,
classNames: { classNames: {
containerOuter: 'choices', containerOuter: "choices",
containerInner: 'choices__inner bg-light border-0', containerInner: "choices__inner bg-light border-0",
input: 'form-control', input: "form-control",
inputCloned: 'choices__input--cloned', inputCloned: "choices__input--cloned",
list: 'choices__list', list: "choices__list",
listItems: 'choices__list--multiple', listItems: "choices__list--multiple",
listSingle: 'choices__list--single', listSingle: "choices__list--single",
listDropdown: 'choices__list--dropdown', listDropdown: "choices__list--dropdown",
item: 'choices__item bg-light', item: "choices__item bg-light",
itemSelectable: 'choices__item--selectable', itemSelectable: "choices__item--selectable",
itemDisabled: 'choices__item--disabled', itemDisabled: "choices__item--disabled",
itemChoice: 'choices__item--choice', itemChoice: "choices__item--choice",
placeholder: 'choices__placeholder', placeholder: "choices__placeholder",
group: 'choices__group', group: "choices__group",
groupHeading: 'choices__heading', groupHeading: "choices__heading",
button: 'choices__button', button: "choices__button",
activeState: 'is-active', activeState: "is-active",
focusState: 'is-focused', focusState: "is-focused",
openState: 'is-open', openState: "is-open",
disabledState: 'is-disabled', disabledState: "is-disabled",
highlightedState: 'text-info', highlightedState: "text-info",
selectedState: 'text-info', selectedState: "text-info",
flippedState: 'is-flipped', flippedState: "is-flipped",
loadingState: 'is-loading', loadingState: "is-loading",
noResults: 'has-no-results', noResults: "has-no-results",
noChoices: 'has-no-choices', noChoices: "has-no-choices",
}, },
}); });
this.choices.passedElement.element.addEventListener( this.choices.passedElement.element.addEventListener(
'choice', "choice",
(e: any) => { (e: any) => {
this.state.postForm.community_id = Number(e.detail.choice.value); this.state.postForm.community_id = Number(e.detail.choice.value);
this.setState(this.state); this.setState(this.state);
@ -607,7 +607,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
this.state.loading = false; this.state.loading = false;
this.setState(this.state); this.setState(this.state);
return; return;

View file

@ -1,6 +1,6 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Link } from 'inferno-router'; import { Link } from "inferno-router";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { import {
PostView, PostView,
CreatePostLike, CreatePostLike,
@ -17,15 +17,15 @@ import {
TransferSite, TransferSite,
TransferCommunity, TransferCommunity,
CommunityModeratorView, CommunityModeratorView,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { BanType } from '../interfaces'; import { BanType } from "../interfaces";
import { MomentTime } from './moment-time'; import { MomentTime } from "./moment-time";
import { PostForm } from './post-form'; import { PostForm } from "./post-form";
import { IFramelyCard } from './iframely-card'; import { IFramelyCard } from "./iframely-card";
import { UserListing } from './user-listing'; import { UserListing } from "./user-listing";
import { CommunityLink } from './community-link'; import { CommunityLink } from "./community-link";
import { PictrsImage } from './pictrs-image'; import { PictrsImage } from "./pictrs-image";
import { Icon } from './icon'; import { Icon } from "./icon";
import { import {
md, md,
mdToHtml, mdToHtml,
@ -39,9 +39,9 @@ import {
previewLines, previewLines,
wsClient, wsClient,
authField, authField,
} from '../utils'; } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { externalHost } from '../env'; import { externalHost } from "../env";
interface PostListingState { interface PostListingState {
showEdit: boolean; showEdit: boolean;
@ -179,7 +179,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
getImageSrc(): string { getImageSrc(): string {
let post = this.props.post_view.post; let post = this.props.post_view.post;
if (isImage(post.url)) { if (isImage(post.url)) {
if (post.url.includes('pictrs')) { if (post.url.includes("pictrs")) {
return post.url; return post.url;
} else if (post.thumbnail_url) { } else if (post.thumbnail_url) {
return post.thumbnail_url; return post.thumbnail_url;
@ -200,10 +200,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
return ( return (
<div <div
class="float-right text-body pointer d-inline-block position-relative mb-2" class="float-right text-body pointer d-inline-block position-relative mb-2"
data-tippy-content={i18n.t('expand_here')} data-tippy-content={i18n.t("expand_here")}
onClick={linkEvent(this, this.handleImageExpandClick)} onClick={linkEvent(this, this.handleImageExpandClick)}
role="button" role="button"
aria-label={i18n.t('expand_here')} aria-label={i18n.t("expand_here")}
> >
{this.imgThumb(this.getImageSrc())} {this.imgThumb(this.getImageSrc())}
<Icon icon="image" classes="mini-overlay" /> <Icon icon="image" classes="mini-overlay" />
@ -255,7 +255,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<Link <Link
className="text-body" className="text-body"
to={`/post/${post.id}`} to={`/post/${post.id}`}
title={i18n.t('comments')} title={i18n.t("comments")}
> >
<div class="thumbnail rounded bg-light d-flex justify-content-center"> <div class="thumbnail rounded bg-light d-flex justify-content-center">
<Icon icon="message-square" classes="d-flex align-items-center" /> <Icon icon="message-square" classes="d-flex align-items-center" />
@ -273,18 +273,18 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<UserListing user={post_view.creator} /> <UserListing user={post_view.creator} />
{this.isMod && ( {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 && ( {this.isAdmin && (
<span className="mx-1 badge badge-light">{i18n.t('admin')}</span> <span className="mx-1 badge badge-light">{i18n.t("admin")}</span>
)} )}
{(post_view.creator_banned_from_community || {(post_view.creator_banned_from_community ||
post_view.creator.banned) && ( post_view.creator.banned) && (
<span className="mx-1 badge badge-danger">{i18n.t('banned')}</span> <span className="mx-1 badge badge-danger">{i18n.t("banned")}</span>
)} )}
{this.props.showCommunity && ( {this.props.showCommunity && (
<span> <span>
<span class="mx-1"> {i18n.t('to')} </span> <span class="mx-1"> {i18n.t("to")} </span>
<CommunityLink community={post_view.community} /> <CommunityLink community={post_view.community} />
</span> </span>
)} )}
@ -321,7 +321,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
previewLines(post_view.post.body) previewLines(post_view.post.body)
)} )}
data-tippy-allowHtml={true} data-tippy-allowHtml={true}
aria-label={i18n.t('upvote')} aria-label={i18n.t("upvote")}
to={`/post/${post_view.post.id}`} to={`/post/${post_view.post.id}`}
> >
<Icon icon="book-open" classes="icon-inline mr-1" /> <Icon icon="book-open" classes="icon-inline mr-1" />
@ -338,11 +338,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<div className={`vote-bar col-1 pr-0 small text-center`}> <div className={`vote-bar col-1 pr-0 small text-center`}>
<button <button
className={`btn-animate btn btn-link p-0 ${ className={`btn-animate btn btn-link p-0 ${
this.state.my_vote == 1 ? 'text-info' : 'text-muted' this.state.my_vote == 1 ? "text-info" : "text-muted"
}`} }`}
onClick={linkEvent(this, this.handlePostLike)} onClick={linkEvent(this, this.handlePostLike)}
data-tippy-content={i18n.t('upvote')} data-tippy-content={i18n.t("upvote")}
aria-label={i18n.t('upvote')} aria-label={i18n.t("upvote")}
> >
<Icon icon="arrow-up1" classes="upvote" /> <Icon icon="arrow-up1" classes="upvote" />
</button> </button>
@ -355,11 +355,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{this.props.enableDownvotes && ( {this.props.enableDownvotes && (
<button <button
className={`btn-animate btn btn-link p-0 ${ className={`btn-animate btn btn-link p-0 ${
this.state.my_vote == -1 ? 'text-danger' : 'text-muted' this.state.my_vote == -1 ? "text-danger" : "text-muted"
}`} }`}
onClick={linkEvent(this, this.handlePostDisLike)} onClick={linkEvent(this, this.handlePostDisLike)}
data-tippy-content={i18n.t('downvote')} data-tippy-content={i18n.t("downvote")}
aria-label={i18n.t('downvote')} aria-label={i18n.t("downvote")}
> >
<Icon icon="arrow-down1" classes="downvote" /> <Icon icon="arrow-down1" classes="downvote" />
</button> </button>
@ -375,7 +375,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<h5> <h5>
{this.props.showBody && post.url ? ( {this.props.showBody && post.url ? (
<a <a
className={!post.stickied ? 'text-body' : 'text-primary'} className={!post.stickied ? "text-body" : "text-primary"}
href={post.url} href={post.url}
title={post.url} title={post.url}
rel="noopener" rel="noopener"
@ -384,9 +384,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</a> </a>
) : ( ) : (
<Link <Link
className={!post.stickied ? 'text-body' : 'text-primary'} className={!post.stickied ? "text-body" : "text-primary"}
to={`/post/${post.id}`} to={`/post/${post.id}`}
title={i18n.t('comments')} title={i18n.t("comments")}
> >
{post.name} {post.name}
</Link> </Link>
@ -395,7 +395,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
(!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")}
onClick={linkEvent(this, this.handleImageExpandClick)} onClick={linkEvent(this, this.handleImageExpandClick)}
> >
<Icon icon="plus-square" classes="icon-inline" /> <Icon icon="plus-square" classes="icon-inline" />
@ -420,13 +420,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
))} ))}
{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")}
</small> </small>
)} )}
{post.deleted && ( {post.deleted && (
<small <small
className="unselectable pointer ml-2 text-muted font-italic" className="unselectable pointer ml-2 text-muted font-italic"
data-tippy-content={i18n.t('deleted')} data-tippy-content={i18n.t("deleted")}
> >
<Icon icon="trash" classes="icon-inline text-danger" /> <Icon icon="trash" classes="icon-inline text-danger" />
</small> </small>
@ -434,7 +434,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{post.locked && ( {post.locked && (
<small <small
className="unselectable pointer ml-2 text-muted font-italic" className="unselectable pointer ml-2 text-muted font-italic"
data-tippy-content={i18n.t('locked')} data-tippy-content={i18n.t("locked")}
> >
<Icon icon="lock" classes="icon-inline text-danger" /> <Icon icon="lock" classes="icon-inline text-danger" />
</small> </small>
@ -442,14 +442,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{post.stickied && ( {post.stickied && (
<small <small
className="unselectable pointer ml-2 text-muted font-italic" className="unselectable pointer ml-2 text-muted font-italic"
data-tippy-content={i18n.t('stickied')} data-tippy-content={i18n.t("stickied")}
> >
<Icon icon="pin" classes="icon-inline text-primary" /> <Icon icon="pin" classes="icon-inline text-primary" />
</small> </small>
)} )}
{post.nsfw && ( {post.nsfw && (
<small className="ml-2 text-muted font-italic"> <small className="ml-2 text-muted font-italic">
{i18n.t('nsfw')} {i18n.t("nsfw")}
</small> </small>
)} )}
</h5> </h5>
@ -464,13 +464,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button class="btn btn-link text-muted p-0"> <button class="btn btn-link text-muted p-0">
<Link <Link
className="text-muted small" className="text-muted small"
title={i18n.t('number_of_comments', { title={i18n.t("number_of_comments", {
count: post_view.counts.comments, count: post_view.counts.comments,
})} })}
to={`/post/${post_view.post.id}`} to={`/post/${post_view.post.id}`}
> >
<Icon icon="message-square" classes="icon-inline mr-1" /> <Icon icon="message-square" classes="icon-inline mr-1" />
{i18n.t('number_of_comments', { {i18n.t("number_of_comments", {
count: post_view.counts.comments, count: post_view.counts.comments,
})} })}
</Link> </Link>
@ -481,7 +481,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button <button
class="btn text-muted py-0 pr-0" class="btn text-muted py-0 pr-0"
data-tippy-content={this.pointsTippy} data-tippy-content={this.pointsTippy}
aria-label={i18n.t('downvote')} aria-label={i18n.t("downvote")}
> >
<small> <small>
<Icon icon="arrow-down1" classes="icon-inline mr-1" /> <Icon icon="arrow-down1" classes="icon-inline mr-1" />
@ -494,14 +494,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
class="btn btn-link btn-animate text-muted py-0" class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleSavePostClick)} onClick={linkEvent(this, this.handleSavePostClick)}
data-tippy-content={ data-tippy-content={
post_view.saved ? i18n.t('unsave') : i18n.t('save') post_view.saved ? i18n.t("unsave") : i18n.t("save")
} }
aria-label={post_view.saved ? i18n.t('unsave') : i18n.t('save')} aria-label={post_view.saved ? i18n.t("unsave") : i18n.t("save")}
> >
<small> <small>
<Icon <Icon
icon="star" icon="star"
classes={`icon-inline ${post_view.saved && 'text-warning'}`} classes={`icon-inline ${post_view.saved && "text-warning"}`}
/> />
</small> </small>
</button> </button>
@ -515,11 +515,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<div> <div>
<button <button
className={`btn-animate btn py-0 px-1 ${ className={`btn-animate btn py-0 px-1 ${
this.state.my_vote == 1 ? 'text-info' : 'text-muted' this.state.my_vote == 1 ? "text-info" : "text-muted"
}`} }`}
data-tippy-content={this.pointsTippy} data-tippy-content={this.pointsTippy}
onClick={linkEvent(this, this.handlePostLike)} onClick={linkEvent(this, this.handlePostLike)}
aria-label={i18n.t('upvote')} aria-label={i18n.t("upvote")}
> >
<Icon icon="arrow-up1" classes="icon-inline small mr-2" /> <Icon icon="arrow-up1" classes="icon-inline small mr-2" />
{this.state.upvotes} {this.state.upvotes}
@ -527,11 +527,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{this.props.enableDownvotes && ( {this.props.enableDownvotes && (
<button <button
className={`ml-2 btn-animate btn py-0 pl-1 ${ className={`ml-2 btn-animate btn py-0 pl-1 ${
this.state.my_vote == -1 ? 'text-danger' : 'text-muted' this.state.my_vote == -1 ? "text-danger" : "text-muted"
}`} }`}
onClick={linkEvent(this, this.handlePostDisLike)} onClick={linkEvent(this, this.handlePostDisLike)}
data-tippy-content={this.pointsTippy} data-tippy-content={this.pointsTippy}
aria-label={i18n.t('downvote')} aria-label={i18n.t("downvote")}
> >
<Icon icon="arrow-down1" classes="icon-inline small mr-2" /> <Icon icon="arrow-down1" classes="icon-inline small mr-2" />
{this.state.downvotes !== 0 && ( {this.state.downvotes !== 0 && (
@ -543,14 +543,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button <button
class="btn btn-link btn-animate text-muted py-0 pl-1 pr-0" class="btn btn-link btn-animate text-muted py-0 pl-1 pr-0"
onClick={linkEvent(this, this.handleSavePostClick)} onClick={linkEvent(this, this.handleSavePostClick)}
aria-label={post_view.saved ? i18n.t('unsave') : i18n.t('save')} aria-label={post_view.saved ? i18n.t("unsave") : i18n.t("save")}
data-tippy-content={ data-tippy-content={
post_view.saved ? i18n.t('unsave') : i18n.t('save') post_view.saved ? i18n.t("unsave") : i18n.t("save")
} }
> >
<Icon <Icon
icon="star" icon="star"
classes={`icon-inline ${post_view.saved && 'text-warning'}`} classes={`icon-inline ${post_view.saved && "text-warning"}`}
/> />
</button> </button>
@ -558,8 +558,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button <button
class="btn btn-link btn-animate text-muted py-0" class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleShowMoreMobile)} onClick={linkEvent(this, this.handleShowMoreMobile)}
aria-label={i18n.t('more')} aria-label={i18n.t("more")}
data-tippy-content={i18n.t('more')} data-tippy-content={i18n.t("more")}
> >
<Icon icon="more-vertical" classes="icon-inline" /> <Icon icon="more-vertical" classes="icon-inline" />
</button> </button>
@ -579,7 +579,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<ul class="list-inline mb-1 small text-muted"> <ul class="list-inline mb-1 small text-muted">
<> <>
<li className="list-inline-item mr-2"> <li className="list-inline-item mr-2">
{i18n.t('cross_posted_to')} {i18n.t("cross_posted_to")}
</li> </li>
{dupes.map(pv => ( {dupes.map(pv => (
<li className="list-inline-item mr-2"> <li className="list-inline-item mr-2">
@ -608,22 +608,22 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
class="btn btn-link btn-animate text-muted py-0 pl-0" class="btn btn-link btn-animate text-muted py-0 pl-0"
onClick={linkEvent(this, this.handleSavePostClick)} onClick={linkEvent(this, this.handleSavePostClick)}
data-tippy-content={ data-tippy-content={
post_view.saved ? i18n.t('unsave') : i18n.t('save') post_view.saved ? i18n.t("unsave") : i18n.t("save")
} }
aria-label={ aria-label={
post_view.saved ? i18n.t('unsave') : i18n.t('save') post_view.saved ? i18n.t("unsave") : i18n.t("save")
} }
> >
<Icon <Icon
icon="star" icon="star"
classes={`icon-inline ${post_view.saved && 'text-warning'}`} classes={`icon-inline ${post_view.saved && "text-warning"}`}
/> />
</button> </button>
)} )}
<Link <Link
className="btn btn-link btn-animate text-muted py-0" className="btn btn-link btn-animate text-muted py-0"
to={`/create_post${this.crossPostParams}`} to={`/create_post${this.crossPostParams}`}
title={i18n.t('cross_post')} title={i18n.t("cross_post")}
> >
<Icon icon="copy" classes="icon-inline" /> <Icon icon="copy" classes="icon-inline" />
</Link> </Link>
@ -634,8 +634,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button <button
class="btn btn-link btn-animate text-muted py-0" class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleEditClick)} onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t('edit')} data-tippy-content={i18n.t("edit")}
aria-label={i18n.t('edit')} aria-label={i18n.t("edit")}
> >
<Icon icon="edit" classes="icon-inline" /> <Icon icon="edit" classes="icon-inline" />
</button> </button>
@ -643,16 +643,16 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
class="btn btn-link btn-animate text-muted py-0" class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleDeleteClick)} onClick={linkEvent(this, this.handleDeleteClick)}
data-tippy-content={ data-tippy-content={
!post_view.post.deleted ? i18n.t('delete') : i18n.t('restore') !post_view.post.deleted ? i18n.t("delete") : i18n.t("restore")
} }
aria-label={ aria-label={
!post_view.post.deleted ? i18n.t('delete') : i18n.t('restore') !post_view.post.deleted ? i18n.t("delete") : i18n.t("restore")
} }
> >
<Icon <Icon
icon="trash" icon="trash"
classes={`icon-inline ${ classes={`icon-inline ${
post_view.post.deleted && 'text-danger' post_view.post.deleted && "text-danger"
}`} }`}
/> />
</button> </button>
@ -663,8 +663,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button <button
class="btn btn-link btn-animate text-muted py-0" class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleShowAdvanced)} onClick={linkEvent(this, this.handleShowAdvanced)}
data-tippy-content={i18n.t('more')} data-tippy-content={i18n.t("more")}
aria-label={i18n.t('more')} aria-label={i18n.t("more")}
> >
<Icon icon="more-vertical" classes="icon-inline" /> <Icon icon="more-vertical" classes="icon-inline" />
</button> </button>
@ -674,13 +674,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button <button
class="btn btn-link btn-animate text-muted py-0" class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleViewSource)} onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t('view_source')} data-tippy-content={i18n.t("view_source")}
aria-label={i18n.t('view_source')} aria-label={i18n.t("view_source")}
> >
<Icon <Icon
icon="file-text" icon="file-text"
classes={`icon-inline ${ classes={`icon-inline ${
this.state.viewSource && 'text-success' this.state.viewSource && "text-success"
}`} }`}
/> />
</button> </button>
@ -691,16 +691,16 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
class="btn btn-link btn-animate text-muted py-0" class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModLock)} onClick={linkEvent(this, this.handleModLock)}
data-tippy-content={ data-tippy-content={
post_view.post.locked ? i18n.t('unlock') : i18n.t('lock') post_view.post.locked ? i18n.t("unlock") : i18n.t("lock")
} }
aria-label={ aria-label={
post_view.post.locked ? i18n.t('unlock') : i18n.t('lock') post_view.post.locked ? i18n.t("unlock") : i18n.t("lock")
} }
> >
<Icon <Icon
icon="lock" icon="lock"
classes={`icon-inline ${ classes={`icon-inline ${
post_view.post.locked && 'text-danger' post_view.post.locked && "text-danger"
}`} }`}
/> />
</button> </button>
@ -709,19 +709,19 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
onClick={linkEvent(this, this.handleModSticky)} onClick={linkEvent(this, this.handleModSticky)}
data-tippy-content={ data-tippy-content={
post_view.post.stickied post_view.post.stickied
? i18n.t('unsticky') ? i18n.t("unsticky")
: i18n.t('sticky') : i18n.t("sticky")
} }
aria-label={ aria-label={
post_view.post.stickied post_view.post.stickied
? i18n.t('unsticky') ? i18n.t("unsticky")
: i18n.t('sticky') : i18n.t("sticky")
} }
> >
<Icon <Icon
icon="pin" icon="pin"
classes={`icon-inline ${ classes={`icon-inline ${
post_view.post.stickied && 'text-success' post_view.post.stickied && "text-success"
}`} }`}
/> />
</button> </button>
@ -733,17 +733,17 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button <button
class="btn btn-link btn-animate text-muted py-0" class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModRemoveShow)} onClick={linkEvent(this, this.handleModRemoveShow)}
aria-label={i18n.t('remove')} aria-label={i18n.t("remove")}
> >
{i18n.t('remove')} {i18n.t("remove")}
</button> </button>
) : ( ) : (
<button <button
class="btn btn-link btn-animate text-muted py-0" class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModRemoveSubmit)} onClick={linkEvent(this, this.handleModRemoveSubmit)}
aria-label={i18n.t('restore')} aria-label={i18n.t("restore")}
> >
{i18n.t('restore')} {i18n.t("restore")}
</button> </button>
))} ))}
{this.canMod && ( {this.canMod && (
@ -756,9 +756,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this, this,
this.handleModBanFromCommunityShow this.handleModBanFromCommunityShow
)} )}
aria-label={i18n.t('ban')} aria-label={i18n.t("ban")}
> >
{i18n.t('ban')} {i18n.t("ban")}
</button> </button>
) : ( ) : (
<button <button
@ -767,9 +767,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this, this,
this.handleModBanFromCommunitySubmit this.handleModBanFromCommunitySubmit
)} )}
aria-label={i18n.t('unban')} aria-label={i18n.t("unban")}
> >
{i18n.t('unban')} {i18n.t("unban")}
</button> </button>
))} ))}
{!post_view.creator_banned_from_community && {!post_view.creator_banned_from_community &&
@ -779,13 +779,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
onClick={linkEvent(this, this.handleAddModToCommunity)} onClick={linkEvent(this, this.handleAddModToCommunity)}
aria-label={ aria-label={
this.isMod this.isMod
? i18n.t('remove_as_mod') ? i18n.t("remove_as_mod")
: i18n.t('appoint_as_mod') : i18n.t("appoint_as_mod")
} }
> >
{this.isMod {this.isMod
? i18n.t('remove_as_mod') ? i18n.t("remove_as_mod")
: i18n.t('appoint_as_mod')} : i18n.t("appoint_as_mod")}
</button> </button>
)} )}
</> </>
@ -801,24 +801,24 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this, this,
this.handleShowConfirmTransferCommunity this.handleShowConfirmTransferCommunity
)} )}
aria-label={i18n.t('transfer_community')} aria-label={i18n.t("transfer_community")}
> >
{i18n.t('transfer_community')} {i18n.t("transfer_community")}
</button> </button>
) : ( ) : (
<> <>
<button <button
class="d-inline-block mr-1 btn btn-link btn-animate text-muted py-0" class="d-inline-block mr-1 btn btn-link btn-animate text-muted py-0"
aria-label={i18n.t('are_you_sure')} aria-label={i18n.t("are_you_sure")}
> >
{i18n.t('are_you_sure')} {i18n.t("are_you_sure")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1" class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1"
aria-label={i18n.t('yes')} aria-label={i18n.t("yes")}
onClick={linkEvent(this, this.handleTransferCommunity)} onClick={linkEvent(this, this.handleTransferCommunity)}
> >
{i18n.t('yes')} {i18n.t("yes")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted py-0 d-inline-block" class="btn btn-link btn-animate text-muted py-0 d-inline-block"
@ -826,9 +826,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this, this,
this.handleCancelShowConfirmTransferCommunity this.handleCancelShowConfirmTransferCommunity
)} )}
aria-label={i18n.t('no')} aria-label={i18n.t("no")}
> >
{i18n.t('no')} {i18n.t("no")}
</button> </button>
</> </>
))} ))}
@ -840,17 +840,17 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button <button
class="btn btn-link btn-animate text-muted py-0" class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModBanShow)} onClick={linkEvent(this, this.handleModBanShow)}
aria-label={i18n.t('ban_from_site')} aria-label={i18n.t("ban_from_site")}
> >
{i18n.t('ban_from_site')} {i18n.t("ban_from_site")}
</button> </button>
) : ( ) : (
<button <button
class="btn btn-link btn-animate text-muted py-0" class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModBanSubmit)} onClick={linkEvent(this, this.handleModBanSubmit)}
aria-label={i18n.t('unban_from_site')} aria-label={i18n.t("unban_from_site")}
> >
{i18n.t('unban_from_site')} {i18n.t("unban_from_site")}
</button> </button>
))} ))}
{!post_view.creator.banned && post_view.creator.local && ( {!post_view.creator.banned && post_view.creator.local && (
@ -859,13 +859,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
onClick={linkEvent(this, this.handleAddAdmin)} onClick={linkEvent(this, this.handleAddAdmin)}
aria-label={ aria-label={
this.isAdmin this.isAdmin
? i18n.t('remove_as_admin') ? i18n.t("remove_as_admin")
: i18n.t('appoint_as_admin') : i18n.t("appoint_as_admin")
} }
> >
{this.isAdmin {this.isAdmin
? i18n.t('remove_as_admin') ? i18n.t("remove_as_admin")
: i18n.t('appoint_as_admin')} : i18n.t("appoint_as_admin")}
</button> </button>
)} )}
</> </>
@ -880,24 +880,24 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this, this,
this.handleShowConfirmTransferSite this.handleShowConfirmTransferSite
)} )}
aria-label={i18n.t('transfer_site')} aria-label={i18n.t("transfer_site")}
> >
{i18n.t('transfer_site')} {i18n.t("transfer_site")}
</button> </button>
) : ( ) : (
<> <>
<button <button
class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1" class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1"
aria-label={i18n.t('are_you_sure')} aria-label={i18n.t("are_you_sure")}
> >
{i18n.t('are_you_sure')} {i18n.t("are_you_sure")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1" class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1"
onClick={linkEvent(this, this.handleTransferSite)} onClick={linkEvent(this, this.handleTransferSite)}
aria-label={i18n.t('yes')} aria-label={i18n.t("yes")}
> >
{i18n.t('yes')} {i18n.t("yes")}
</button> </button>
<button <button
class="btn btn-link btn-animate text-muted py-0 d-inline-block" class="btn btn-link btn-animate text-muted py-0 d-inline-block"
@ -905,9 +905,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this, this,
this.handleCancelShowConfirmTransferSite this.handleCancelShowConfirmTransferSite
)} )}
aria-label={i18n.t('no')} aria-label={i18n.t("no")}
> >
{i18n.t('no')} {i18n.t("no")}
</button> </button>
</> </>
))} ))}
@ -928,22 +928,22 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
onSubmit={linkEvent(this, this.handleModRemoveSubmit)} onSubmit={linkEvent(this, this.handleModRemoveSubmit)}
> >
<label class="sr-only" htmlFor="post-listing-remove-reason"> <label class="sr-only" htmlFor="post-listing-remove-reason">
{i18n.t('reason')} {i18n.t("reason")}
</label> </label>
<input <input
type="text" type="text"
id="post-listing-remove-reason" id="post-listing-remove-reason"
class="form-control mr-2" class="form-control mr-2"
placeholder={i18n.t('reason')} placeholder={i18n.t("reason")}
value={this.state.removeReason} value={this.state.removeReason}
onInput={linkEvent(this, this.handleModRemoveReasonChange)} onInput={linkEvent(this, this.handleModRemoveReasonChange)}
/> />
<button <button
type="submit" type="submit"
class="btn btn-secondary" class="btn btn-secondary"
aria-label={i18n.t('remove_post')} aria-label={i18n.t("remove_post")}
> >
{i18n.t('remove_post')} {i18n.t("remove_post")}
</button> </button>
</form> </form>
)} )}
@ -951,13 +951,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<form onSubmit={linkEvent(this, this.handleModBanBothSubmit)}> <form onSubmit={linkEvent(this, this.handleModBanBothSubmit)}>
<div class="form-group row"> <div class="form-group row">
<label class="col-form-label" htmlFor="post-listing-ban-reason"> <label class="col-form-label" htmlFor="post-listing-ban-reason">
{i18n.t('reason')} {i18n.t("reason")}
</label> </label>
<input <input
type="text" type="text"
id="post-listing-ban-reason" id="post-listing-ban-reason"
class="form-control mr-2" class="form-control mr-2"
placeholder={i18n.t('reason')} placeholder={i18n.t("reason")}
value={this.state.banReason} value={this.state.banReason}
onInput={linkEvent(this, this.handleModBanReasonChange)} onInput={linkEvent(this, this.handleModBanReasonChange)}
/> />
@ -971,7 +971,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
onChange={linkEvent(this, this.handleModRemoveDataChange)} onChange={linkEvent(this, this.handleModRemoveDataChange)}
/> />
<label class="form-check-label" htmlFor="mod-ban-remove-data"> <label class="form-check-label" htmlFor="mod-ban-remove-data">
{i18n.t('remove_posts_comments')} {i18n.t("remove_posts_comments")}
</label> </label>
</div> </div>
</div> </div>
@ -985,9 +985,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button <button
type="submit" type="submit"
class="btn btn-secondary" class="btn btn-secondary"
aria-label={i18n.t('ban')} aria-label={i18n.t("ban")}
> >
{i18n.t('ban')} {post.creator.name} {i18n.t("ban")} {post.creator.name}
</button> </button>
</div> </div>
</form> </form>
@ -1000,7 +1000,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
let post = this.props.post_view.post; let post = this.props.post_view.post;
return post.thumbnail_url || isImage(post.url) ? ( return post.thumbnail_url || isImage(post.url) ? (
<div class="row"> <div class="row">
<div className={`${this.state.imageExpanded ? 'col-12' : 'col-8'}`}> <div className={`${this.state.imageExpanded ? "col-12" : "col-8"}`}>
{this.postTitleLine()} {this.postTitleLine()}
</div> </div>
<div class="col-4"> <div class="col-4">
@ -1061,7 +1061,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
)} )}
<div <div
class={`${ class={`${
this.state.imageExpanded ? 'col-12' : 'col-12 col-sm-9' this.state.imageExpanded ? "col-12" : "col-12 col-sm-9"
}`} }`}
> >
<div class="row"> <div class="row">
@ -1493,15 +1493,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
} }
get pointsTippy(): string { get pointsTippy(): string {
let points = i18n.t('number_of_points', { let points = i18n.t("number_of_points", {
count: this.state.score, count: this.state.score,
}); });
let upvotes = i18n.t('number_of_upvotes', { let upvotes = i18n.t("number_of_upvotes", {
count: this.state.upvotes, count: this.state.upvotes,
}); });
let downvotes = i18n.t('number_of_downvotes', { let downvotes = i18n.t("number_of_downvotes", {
count: this.state.downvotes, count: this.state.downvotes,
}); });

View file

@ -1,9 +1,9 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { Link } from 'inferno-router'; import { Link } from "inferno-router";
import { PostView } from 'lemmy-js-client'; import { PostView } from "lemmy-js-client";
import { PostListing } from './post-listing'; import { PostListing } from "./post-listing";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { T } from 'inferno-i18next'; import { T } from "inferno-i18next";
interface PostListingsProps { interface PostListingsProps {
posts: PostView[]; posts: PostView[];
@ -38,7 +38,7 @@ export class PostListings extends Component<PostListingsProps, any> {
)) ))
) : ( ) : (
<> <>
<div>{i18n.t('no_posts')}</div> <div>{i18n.t("no_posts")}</div>
{this.props.showCommunity !== undefined && ( {this.props.showCommunity !== undefined && (
<T i18nKey="subscribe_to_communities"> <T i18nKey="subscribe_to_communities">
#<Link to="/communities">#</Link> #<Link to="/communities">#</Link>

View file

@ -1,7 +1,7 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { HtmlTags } from './html-tags'; import { HtmlTags } from "./html-tags";
import { Spinner } from './icon'; import { Spinner } from "./icon";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
UserOperation, UserOperation,
PostView, PostView,
@ -23,14 +23,14 @@ import {
GetCommunityResponse, GetCommunityResponse,
ListCategoriesResponse, ListCategoriesResponse,
Category, Category,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { import {
CommentSortType, CommentSortType,
CommentViewType, CommentViewType,
InitialFetchRequest, InitialFetchRequest,
CommentNode as CommentNodeI, CommentNode as CommentNodeI,
} from '../interfaces'; } from "../interfaces";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { import {
wsJsonToRes, wsJsonToRes,
toast, toast,
@ -55,13 +55,13 @@ import {
restoreScrollPosition, restoreScrollPosition,
buildCommentsTree, buildCommentsTree,
insertCommentIntoTree, insertCommentIntoTree,
} from '../utils'; } from "../utils";
import { PostListing } from './post-listing'; import { PostListing } from "./post-listing";
import { Sidebar } from './sidebar'; import { Sidebar } from "./sidebar";
import { CommentForm } from './comment-form'; import { CommentForm } from "./comment-form";
import { CommentNodes } from './comment-nodes'; import { CommentNodes } from "./comment-nodes";
import autosize from 'autosize'; import autosize from "autosize";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
interface PostState { interface PostState {
postRes: GetPostResponse; postRes: GetPostResponse;
@ -147,7 +147,7 @@ export class Post extends Component<any, PostState> {
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split('/'); let pathSplit = req.path.split("/");
let promises: Promise<any>[] = []; let promises: Promise<any>[] = [];
let id = Number(pathSplit[2]); let id = Number(pathSplit[2]);
@ -173,7 +173,7 @@ export class Post extends Component<any, PostState> {
WebSocketService.Instance.send( WebSocketService.Instance.send(
wsClient.postJoin({ post_id: this.state.postId }) wsClient.postJoin({ post_id: this.state.postId })
); );
autosize(document.querySelectorAll('textarea')); autosize(document.querySelectorAll("textarea"));
} }
componentDidUpdate(_lastProps: any, lastState: PostState) { componentDidUpdate(_lastProps: any, lastState: PostState) {
@ -201,7 +201,7 @@ export class Post extends Component<any, PostState> {
scrollCommentIntoView() { scrollCommentIntoView() {
var elmnt = document.getElementById(`comment-${this.state.commentId}`); var elmnt = document.getElementById(`comment-${this.state.commentId}`);
elmnt.scrollIntoView(); elmnt.scrollIntoView();
elmnt.classList.add('mark'); elmnt.classList.add("mark");
this.state.scrolled = true; this.state.scrolled = true;
this.markScrolledAsRead(this.state.commentId); this.markScrolledAsRead(this.state.commentId);
} }
@ -304,10 +304,10 @@ export class Post extends Component<any, PostState> {
<div class="btn-group btn-group-toggle flex-wrap mr-3 mb-2"> <div class="btn-group btn-group-toggle flex-wrap mr-3 mb-2">
<label <label
className={`btn btn-outline-secondary pointer ${ className={`btn btn-outline-secondary pointer ${
this.state.commentSort === CommentSortType.Hot && 'active' this.state.commentSort === CommentSortType.Hot && "active"
}`} }`}
> >
{i18n.t('hot')} {i18n.t("hot")}
<input <input
type="radio" type="radio"
value={CommentSortType.Hot} value={CommentSortType.Hot}
@ -317,10 +317,10 @@ export class Post extends Component<any, PostState> {
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer ${ className={`btn btn-outline-secondary pointer ${
this.state.commentSort === CommentSortType.Top && 'active' this.state.commentSort === CommentSortType.Top && "active"
}`} }`}
> >
{i18n.t('top')} {i18n.t("top")}
<input <input
type="radio" type="radio"
value={CommentSortType.Top} value={CommentSortType.Top}
@ -330,10 +330,10 @@ export class Post extends Component<any, PostState> {
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer ${ className={`btn btn-outline-secondary pointer ${
this.state.commentSort === CommentSortType.New && 'active' this.state.commentSort === CommentSortType.New && "active"
}`} }`}
> >
{i18n.t('new')} {i18n.t("new")}
<input <input
type="radio" type="radio"
value={CommentSortType.New} value={CommentSortType.New}
@ -343,10 +343,10 @@ export class Post extends Component<any, PostState> {
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer ${ className={`btn btn-outline-secondary pointer ${
this.state.commentSort === CommentSortType.Old && 'active' this.state.commentSort === CommentSortType.Old && "active"
}`} }`}
> >
{i18n.t('old')} {i18n.t("old")}
<input <input
type="radio" type="radio"
value={CommentSortType.Old} value={CommentSortType.Old}
@ -358,10 +358,10 @@ export class Post extends Component<any, PostState> {
<div class="btn-group btn-group-toggle flex-wrap mb-2"> <div class="btn-group btn-group-toggle flex-wrap mb-2">
<label <label
className={`btn btn-outline-secondary pointer ${ className={`btn btn-outline-secondary pointer ${
this.state.commentViewType === CommentViewType.Chat && 'active' this.state.commentViewType === CommentViewType.Chat && "active"
}`} }`}
> >
{i18n.t('chat')} {i18n.t("chat")}
<input <input
type="radio" type="radio"
value={CommentViewType.Chat} value={CommentViewType.Chat}
@ -447,7 +447,7 @@ export class Post extends Component<any, PostState> {
let op = wsUserOp(msg); let op = wsUserOp(msg);
console.log(msg); console.log(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
return; return;
} else if (msg.reconnect) { } else if (msg.reconnect) {
let postId = Number(this.props.match.params.id); let postId = Number(this.props.match.params.id);

View file

@ -1,6 +1,6 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Prompt } from 'inferno-router'; import { Prompt } from "inferno-router";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
CreatePrivateMessage, CreatePrivateMessage,
EditPrivateMessage, EditPrivateMessage,
@ -8,8 +8,8 @@ import {
PrivateMessageResponse, PrivateMessageResponse,
UserSafe, UserSafe,
UserOperation, UserOperation,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService } from '../services'; import { WebSocketService } from "../services";
import { import {
capitalizeFirstLetter, capitalizeFirstLetter,
wsJsonToRes, wsJsonToRes,
@ -20,12 +20,12 @@ import {
wsUserOp, wsUserOp,
wsClient, wsClient,
authField, authField,
} from '../utils'; } from "../utils";
import { UserListing } from './user-listing'; import { UserListing } from "./user-listing";
import { MarkdownTextArea } from './markdown-textarea'; import { MarkdownTextArea } from "./markdown-textarea";
import { Icon, Spinner } from './icon'; import { Icon, Spinner } from "./icon";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { T } from 'inferno-i18next'; import { T } from "inferno-i18next";
interface PrivateMessageFormProps { interface PrivateMessageFormProps {
recipient: UserSafe; recipient: UserSafe;
@ -98,13 +98,13 @@ export class PrivateMessageForm extends Component<
<div> <div>
<Prompt <Prompt
when={!this.state.loading && this.state.privateMessageForm.content} when={!this.state.loading && this.state.privateMessageForm.content}
message={i18n.t('block_leaving')} message={i18n.t("block_leaving")}
/> />
<form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}> <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
{!this.props.privateMessage && ( {!this.props.privateMessage && (
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label"> <label class="col-sm-2 col-form-label">
{capitalizeFirstLetter(i18n.t('to'))} {capitalizeFirstLetter(i18n.t("to"))}
</label> </label>
<div class="col-sm-10 form-control-plaintext"> <div class="col-sm-10 form-control-plaintext">
@ -114,13 +114,13 @@ export class PrivateMessageForm extends Component<
)} )}
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label"> <label class="col-sm-2 col-form-label">
{i18n.t('message')} {i18n.t("message")}
<span <span
onClick={linkEvent(this, this.handleShowDisclaimer)} onClick={linkEvent(this, this.handleShowDisclaimer)}
role="button" role="button"
class="ml-2 pointer text-danger" class="ml-2 pointer text-danger"
data-tippy-content={i18n.t('disclaimer')} data-tippy-content={i18n.t("disclaimer")}
aria-label={i18n.t('disclaimer')} aria-label={i18n.t("disclaimer")}
> >
<Icon icon="alert-triangle" classes="icon-inline" /> <Icon icon="alert-triangle" classes="icon-inline" />
</span> </span>
@ -161,9 +161,9 @@ export class PrivateMessageForm extends Component<
{this.state.loading ? ( {this.state.loading ? (
<Spinner /> <Spinner />
) : this.props.privateMessage ? ( ) : this.props.privateMessage ? (
capitalizeFirstLetter(i18n.t('save')) capitalizeFirstLetter(i18n.t("save"))
) : ( ) : (
capitalizeFirstLetter(i18n.t('send_message')) capitalizeFirstLetter(i18n.t("send_message"))
)} )}
</button> </button>
{this.props.privateMessage && ( {this.props.privateMessage && (
@ -172,7 +172,7 @@ export class PrivateMessageForm extends Component<
class="btn btn-secondary" class="btn btn-secondary"
onClick={linkEvent(this, this.handleCancel)} onClick={linkEvent(this, this.handleCancel)}
> >
{i18n.t('cancel')} {i18n.t("cancel")}
</button> </button>
)} )}
<ul class="d-inline-block float-right list-inline mb-1 text-muted font-weight-bold"> <ul class="d-inline-block float-right list-inline mb-1 text-muted font-weight-bold">
@ -226,7 +226,7 @@ export class PrivateMessageForm extends Component<
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
this.state.loading = false; this.state.loading = false;
this.setState(this.state); this.setState(this.state);
return; return;

View file

@ -1,17 +1,17 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { import {
PrivateMessageView, PrivateMessageView,
DeletePrivateMessage, DeletePrivateMessage,
MarkPrivateMessageAsRead, MarkPrivateMessageAsRead,
UserSafe, UserSafe,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { authField, mdToHtml, toast, wsClient } from '../utils'; import { authField, mdToHtml, toast, wsClient } from "../utils";
import { MomentTime } from './moment-time'; import { MomentTime } from "./moment-time";
import { PrivateMessageForm } from './private-message-form'; import { PrivateMessageForm } from "./private-message-form";
import { UserListing } from './user-listing'; import { UserListing } from "./user-listing";
import { Icon } from './icon'; import { Icon } from "./icon";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
interface PrivateMessageState { interface PrivateMessageState {
showReply: boolean; showReply: boolean;
@ -66,7 +66,7 @@ export class PrivateMessage extends Component<
<ul class="list-inline mb-0 text-muted small"> <ul class="list-inline mb-0 text-muted small">
{/* TODO refactor this */} {/* TODO refactor this */}
<li className="list-inline-item"> <li className="list-inline-item">
{this.mine ? i18n.t('to') : i18n.t('from')} {this.mine ? i18n.t("to") : i18n.t("from")}
</li> </li>
<li className="list-inline-item"> <li className="list-inline-item">
<UserListing user={userOther} /> <UserListing user={userOther} />
@ -118,19 +118,19 @@ export class PrivateMessage extends Component<
onClick={linkEvent(this, this.handleMarkRead)} onClick={linkEvent(this, this.handleMarkRead)}
data-tippy-content={ data-tippy-content={
message_view.private_message.read message_view.private_message.read
? i18n.t('mark_as_unread') ? i18n.t("mark_as_unread")
: i18n.t('mark_as_read') : i18n.t("mark_as_read")
} }
aria-label={ aria-label={
message_view.private_message.read message_view.private_message.read
? i18n.t('mark_as_unread') ? i18n.t("mark_as_unread")
: i18n.t('mark_as_read') : i18n.t("mark_as_read")
} }
> >
<Icon <Icon
icon="check" icon="check"
classes={`icon-inline ${ classes={`icon-inline ${
message_view.private_message.read && 'text-success' message_view.private_message.read && "text-success"
}`} }`}
/> />
</button> </button>
@ -139,8 +139,8 @@ export class PrivateMessage extends Component<
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleReplyClick)} onClick={linkEvent(this, this.handleReplyClick)}
data-tippy-content={i18n.t('reply')} data-tippy-content={i18n.t("reply")}
aria-label={i18n.t('reply')} aria-label={i18n.t("reply")}
> >
<Icon icon="reply1" classes="icon-inline" /> <Icon icon="reply1" classes="icon-inline" />
</button> </button>
@ -153,8 +153,8 @@ export class PrivateMessage extends Component<
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleEditClick)} onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t('edit')} data-tippy-content={i18n.t("edit")}
aria-label={i18n.t('edit')} aria-label={i18n.t("edit")}
> >
<Icon icon="edit" classes="icon-inline" /> <Icon icon="edit" classes="icon-inline" />
</button> </button>
@ -165,20 +165,20 @@ export class PrivateMessage extends Component<
onClick={linkEvent(this, this.handleDeleteClick)} onClick={linkEvent(this, this.handleDeleteClick)}
data-tippy-content={ data-tippy-content={
!message_view.private_message.deleted !message_view.private_message.deleted
? i18n.t('delete') ? i18n.t("delete")
: i18n.t('restore') : i18n.t("restore")
} }
aria-label={ aria-label={
!message_view.private_message.deleted !message_view.private_message.deleted
? i18n.t('delete') ? i18n.t("delete")
: i18n.t('restore') : i18n.t("restore")
} }
> >
<Icon <Icon
icon="trash" icon="trash"
classes={`icon-inline ${ classes={`icon-inline ${
message_view.private_message.deleted && message_view.private_message.deleted &&
'text-danger' "text-danger"
}`} }`}
/> />
</button> </button>
@ -189,13 +189,13 @@ export class PrivateMessage extends Component<
<button <button
class="btn btn-link btn-animate text-muted" class="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleViewSource)} onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t('view_source')} data-tippy-content={i18n.t("view_source")}
aria-label={i18n.t('view_source')} aria-label={i18n.t("view_source")}
> >
<Icon <Icon
icon="file-text" icon="file-text"
classes={`icon-inline ${ classes={`icon-inline ${
this.state.viewSource && 'text-success' this.state.viewSource && "text-success"
}`} }`}
/> />
</button> </button>
@ -218,7 +218,7 @@ export class PrivateMessage extends Component<
get messageUnlessRemoved(): string { get messageUnlessRemoved(): string {
let message = this.props.private_message_view.private_message; let message = this.props.private_message_view.private_message;
return message.deleted ? `*${i18n.t('deleted')}*` : message.content; return message.deleted ? `*${i18n.t("deleted")}*` : message.content;
} }
handleReplyClick(i: PrivateMessage) { handleReplyClick(i: PrivateMessage) {
@ -277,7 +277,7 @@ export class PrivateMessage extends Component<
) { ) {
this.state.showReply = false; this.state.showReply = false;
this.setState(this.state); this.setState(this.state);
toast(i18n.t('message_sent')); toast(i18n.t("message_sent"));
} }
} }
} }

View file

@ -1,5 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
UserOperation, UserOperation,
PostView, PostView,
@ -13,8 +13,8 @@ import {
PostResponse, PostResponse,
CommentResponse, CommentResponse,
Site, Site,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService } from '../services'; import { WebSocketService } from "../services";
import { import {
wsJsonToRes, wsJsonToRes,
fetchLimit, fetchLimit,
@ -32,16 +32,16 @@ import {
setOptionalAuth, setOptionalAuth,
saveScrollPosition, saveScrollPosition,
restoreScrollPosition, restoreScrollPosition,
} from '../utils'; } from "../utils";
import { PostListing } from './post-listing'; import { PostListing } from "./post-listing";
import { HtmlTags } from './html-tags'; import { HtmlTags } from "./html-tags";
import { Spinner } from './icon'; import { Spinner } from "./icon";
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";
import { CommentNodes } from './comment-nodes'; import { CommentNodes } from "./comment-nodes";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { InitialFetchRequest } from 'shared/interfaces'; import { InitialFetchRequest } from "shared/interfaces";
interface SearchProps { interface SearchProps {
q: string; q: string;
@ -89,7 +89,7 @@ export class Search extends Component<any, SearchState> {
}; };
static getSearchQueryFromProps(q: string): string { static getSearchQueryFromProps(q: string): string {
return decodeURIComponent(q) || ''; return decodeURIComponent(q) || "";
} }
static getSearchTypeFromProps(type_: string): SearchType { static getSearchTypeFromProps(type_: string): SearchType {
@ -114,7 +114,7 @@ export class Search extends Component<any, SearchState> {
this.subscription = wsSubscribe(this.parseMessage); this.subscription = wsSubscribe(this.parseMessage);
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.state.q != '') { if (this.state.q != "") {
if (this.isoData.path == this.context.router.route.match.url) { if (this.isoData.path == this.context.router.route.match.url) {
this.state.searchResponse = this.isoData.routeData[0]; this.state.searchResponse = this.isoData.routeData[0];
this.state.loading = false; this.state.loading = false;
@ -139,7 +139,7 @@ export class Search extends Component<any, SearchState> {
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split('/'); let pathSplit = req.path.split("/");
let promises: Promise<any>[] = []; let promises: Promise<any>[] = [];
let form: SearchForm = { let form: SearchForm = {
@ -151,7 +151,7 @@ export class Search extends Component<any, SearchState> {
}; };
setOptionalAuth(form, req.auth); setOptionalAuth(form, req.auth);
if (form.q != '') { if (form.q != "") {
promises.push(req.client.search(form)); promises.push(req.client.search(form));
} }
@ -172,9 +172,9 @@ export class Search extends Component<any, SearchState> {
get documentTitle(): string { get documentTitle(): string {
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 { } else {
return `${i18n.t('search')} - ${this.state.site.name}`; return `${i18n.t("search")} - ${this.state.site.name}`;
} }
} }
@ -185,7 +185,7 @@ export class Search extends Component<any, SearchState> {
title={this.documentTitle} title={this.documentTitle}
path={this.context.router.route.match.url} 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()}
{this.state.type_ == SearchType.All && this.all()} {this.state.type_ == SearchType.All && this.all()}
@ -193,7 +193,7 @@ export class Search extends Component<any, SearchState> {
{this.state.type_ == SearchType.Posts && this.posts()} {this.state.type_ == SearchType.Posts && this.posts()}
{this.state.type_ == SearchType.Communities && this.communities()} {this.state.type_ == SearchType.Communities && this.communities()}
{this.state.type_ == SearchType.Users && this.users()} {this.state.type_ == SearchType.Users && this.users()}
{this.resultsCount() == 0 && <span>{i18n.t('no_results')}</span>} {this.resultsCount() == 0 && <span>{i18n.t("no_results")}</span>}
{this.paginator()} {this.paginator()}
</div> </div>
); );
@ -209,14 +209,14 @@ export class Search extends Component<any, SearchState> {
type="text" type="text"
class="form-control mr-2 mb-2" class="form-control mr-2 mb-2"
value={this.state.searchText} value={this.state.searchText}
placeholder={`${i18n.t('search')}...`} placeholder={`${i18n.t("search")}...`}
aria-label={i18n.t('search')} aria-label={i18n.t("search")}
onInput={linkEvent(this, this.handleQChange)} onInput={linkEvent(this, this.handleQChange)}
required required
minLength={3} minLength={3}
/> />
<button type="submit" class="btn btn-secondary mr-2 mb-2"> <button type="submit" class="btn btn-secondary mr-2 mb-2">
{this.state.loading ? <Spinner /> : <span>{i18n.t('search')}</span>} {this.state.loading ? <Spinner /> : <span>{i18n.t("search")}</span>}
</button> </button>
</form> </form>
); );
@ -229,18 +229,18 @@ export class Search extends Component<any, SearchState> {
value={this.state.type_} value={this.state.type_}
onChange={linkEvent(this, this.handleTypeChange)} onChange={linkEvent(this, this.handleTypeChange)}
class="custom-select w-auto mb-2" class="custom-select w-auto mb-2"
aria-label={i18n.t('type')} aria-label={i18n.t("type")}
> >
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
{i18n.t('type')} {i18n.t("type")}
</option> </option>
<option value={SearchType.All}>{i18n.t('all')}</option> <option value={SearchType.All}>{i18n.t("all")}</option>
<option value={SearchType.Comments}>{i18n.t('comments')}</option> <option value={SearchType.Comments}>{i18n.t("comments")}</option>
<option value={SearchType.Posts}>{i18n.t('posts')}</option> <option value={SearchType.Posts}>{i18n.t("posts")}</option>
<option value={SearchType.Communities}> <option value={SearchType.Communities}>
{i18n.t('communities')} {i18n.t("communities")}
</option> </option>
<option value={SearchType.Users}>{i18n.t('users')}</option> <option value={SearchType.Users}>{i18n.t("users")}</option>
</select> </select>
<span class="ml-2"> <span class="ml-2">
<SortSelect <SortSelect
@ -261,20 +261,20 @@ export class Search extends Component<any, SearchState> {
published: string; published: string;
}[] = []; }[] = [];
let comments = this.state.searchResponse.comments.map(e => { let comments = this.state.searchResponse.comments.map(e => {
return { type_: 'comments', data: e, published: e.comment.published }; return { type_: "comments", data: e, published: e.comment.published };
}); });
let posts = this.state.searchResponse.posts.map(e => { let posts = this.state.searchResponse.posts.map(e => {
return { type_: 'posts', data: e, published: e.post.published }; return { type_: "posts", data: e, published: e.post.published };
}); });
let communities = this.state.searchResponse.communities.map(e => { let communities = this.state.searchResponse.communities.map(e => {
return { return {
type_: 'communities', type_: "communities",
data: e, data: e,
published: e.community.published, published: e.community.published,
}; };
}); });
let users = this.state.searchResponse.users.map(e => { let users = this.state.searchResponse.users.map(e => {
return { type_: 'users', data: e, published: e.user.published }; return { type_: "users", data: e, published: e.user.published };
}); });
combined.push(...comments); combined.push(...comments);
@ -302,7 +302,7 @@ export class Search extends Component<any, SearchState> {
{combined.map(i => ( {combined.map(i => (
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
{i.type_ == 'posts' && ( {i.type_ == "posts" && (
<PostListing <PostListing
key={(i.data as PostView).post.id} key={(i.data as PostView).post.id}
post_view={i.data as PostView} post_view={i.data as PostView}
@ -311,7 +311,7 @@ export class Search extends Component<any, SearchState> {
enableNsfw={this.state.site.enable_nsfw} enableNsfw={this.state.site.enable_nsfw}
/> />
)} )}
{i.type_ == 'comments' && ( {i.type_ == "comments" && (
<CommentNodes <CommentNodes
key={(i.data as CommentView).comment.id} key={(i.data as CommentView).comment.id}
nodes={[{ comment_view: i.data as CommentView }]} nodes={[{ comment_view: i.data as CommentView }]}
@ -320,10 +320,10 @@ export class Search extends Component<any, SearchState> {
enableDownvotes={this.state.site.enable_downvotes} enableDownvotes={this.state.site.enable_downvotes}
/> />
)} )}
{i.type_ == 'communities' && ( {i.type_ == "communities" && (
<div>{this.communityListing(i.data as CommunityView)}</div> <div>{this.communityListing(i.data as CommunityView)}</div>
)} )}
{i.type_ == 'users' && ( {i.type_ == "users" && (
<div>{this.userListing(i.data as UserViewSafe)}</div> <div>{this.userListing(i.data as UserViewSafe)}</div>
)} )}
</div> </div>
@ -382,7 +382,7 @@ export class Search extends Component<any, SearchState> {
<CommunityLink community={community_view.community} /> <CommunityLink community={community_view.community} />
</span> </span>
<span>{` - <span>{` -
${i18n.t('number_of_subscribers', { ${i18n.t("number_of_subscribers", {
count: community_view.counts.subscribers, count: community_view.counts.subscribers,
})} })}
`}</span> `}</span>
@ -395,7 +395,7 @@ export class Search extends Component<any, SearchState> {
<span> <span>
<UserListing user={user_view.user} showApubName /> <UserListing user={user_view.user} showApubName />
</span>, </span>,
<span>{` - ${i18n.t('number_of_comments', { <span>{` - ${i18n.t("number_of_comments", {
count: user_view.counts.comment_count, count: user_view.counts.comment_count,
})}`}</span>, })}`}</span>,
]; ];
@ -421,7 +421,7 @@ export class Search extends Component<any, SearchState> {
class="btn btn-secondary mr-1" class="btn btn-secondary mr-1"
onClick={linkEvent(this, this.prevPage)} onClick={linkEvent(this, this.prevPage)}
> >
{i18n.t('prev')} {i18n.t("prev")}
</button> </button>
)} )}
@ -430,7 +430,7 @@ export class Search extends Component<any, SearchState> {
class="btn btn-secondary" class="btn btn-secondary"
onClick={linkEvent(this, this.nextPage)} onClick={linkEvent(this, this.nextPage)}
> >
{i18n.t('next')} {i18n.t("next")}
</button> </button>
)} )}
</div> </div>
@ -465,7 +465,7 @@ export class Search extends Component<any, SearchState> {
auth: authField(false), auth: authField(false),
}; };
if (this.state.q != '') { if (this.state.q != "") {
WebSocketService.Instance.send(wsClient.search(form)); WebSocketService.Instance.send(wsClient.search(form));
} }
} }
@ -510,7 +510,7 @@ export class Search extends Component<any, SearchState> {
console.log(msg); console.log(msg);
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
return; return;
} else if (op == UserOperation.Search) { } else if (op == UserOperation.Search) {
let data = wsJsonToRes<SearchResponse>(msg).data; let data = wsJsonToRes<SearchResponse>(msg).data;

View file

@ -1,13 +1,13 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Helmet } from 'inferno-helmet'; import { Helmet } from "inferno-helmet";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { retryWhen, delay, take } from 'rxjs/operators'; import { retryWhen, delay, take } from "rxjs/operators";
import { Register, LoginResponse, UserOperation } from 'lemmy-js-client'; import { Register, LoginResponse, UserOperation } from "lemmy-js-client";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { wsUserOp, wsJsonToRes, toast, wsClient } from '../utils'; import { wsUserOp, wsJsonToRes, toast, wsClient } from "../utils";
import { SiteForm } from './site-form'; import { SiteForm } from "./site-form";
import { Spinner } from './icon'; import { Spinner } from "./icon";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
interface State { interface State {
userForm: Register; userForm: Register;
@ -25,8 +25,8 @@ export class Setup extends Component<any, State> {
password_verify: undefined, password_verify: undefined,
show_nsfw: true, show_nsfw: true,
// The first admin signup doesn't need a captcha // The first admin signup doesn't need a captcha
captcha_uuid: '', captcha_uuid: "",
captcha_answer: '', captcha_answer: "",
}, },
doneRegisteringUser: false, doneRegisteringUser: false,
userLoading: false, userLoading: false,
@ -42,7 +42,7 @@ export class Setup extends Component<any, State> {
.subscribe( .subscribe(
msg => this.parseMessage(msg), msg => this.parseMessage(msg),
err => console.error(err), err => console.error(err),
() => console.log('complete') () => console.log("complete")
); );
} }
@ -51,7 +51,7 @@ export class Setup extends Component<any, State> {
} }
get documentTitle(): string { get documentTitle(): string {
return `${i18n.t('setup')} - Lemmy`; return `${i18n.t("setup")} - Lemmy`;
} }
render() { render() {
@ -60,7 +60,7 @@ export class Setup extends Component<any, State> {
<Helmet title={this.documentTitle} /> <Helmet title={this.documentTitle} />
<div class="row"> <div class="row">
<div class="col-12 offset-lg-3 col-lg-6"> <div class="col-12 offset-lg-3 col-lg-6">
<h3>{i18n.t('lemmy_instance_setup')}</h3> <h3>{i18n.t("lemmy_instance_setup")}</h3>
{!this.state.doneRegisteringUser ? ( {!this.state.doneRegisteringUser ? (
this.registerUser() this.registerUser()
) : ( ) : (
@ -75,10 +75,10 @@ export class Setup extends Component<any, State> {
registerUser() { registerUser() {
return ( return (
<form onSubmit={linkEvent(this, this.handleRegisterSubmit)}> <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
<h5>{i18n.t('setup_admin')}</h5> <h5>{i18n.t("setup_admin")}</h5>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="username"> <label class="col-sm-2 col-form-label" htmlFor="username">
{i18n.t('username')} {i18n.t("username")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input <input
@ -96,7 +96,7 @@ export class Setup extends Component<any, State> {
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="email"> <label class="col-sm-2 col-form-label" htmlFor="email">
{i18n.t('email')} {i18n.t("email")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
@ -104,7 +104,7 @@ export class Setup extends Component<any, State> {
type="email" type="email"
id="email" id="email"
class="form-control" class="form-control"
placeholder={i18n.t('optional')} placeholder={i18n.t("optional")}
value={this.state.userForm.email} value={this.state.userForm.email}
onInput={linkEvent(this, this.handleRegisterEmailChange)} onInput={linkEvent(this, this.handleRegisterEmailChange)}
minLength={3} minLength={3}
@ -113,7 +113,7 @@ export class Setup extends Component<any, State> {
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="password"> <label class="col-sm-2 col-form-label" htmlFor="password">
{i18n.t('password')} {i18n.t("password")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input <input
@ -128,7 +128,7 @@ export class Setup extends Component<any, State> {
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="verify-password"> <label class="col-sm-2 col-form-label" htmlFor="verify-password">
{i18n.t('verify_password')} {i18n.t("verify_password")}
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input <input
@ -144,7 +144,7 @@ export class Setup extends Component<any, State> {
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-10"> <div class="col-sm-10">
<button type="submit" class="btn btn-secondary"> <button type="submit" class="btn btn-secondary">
{this.state.userLoading ? <Spinner /> : i18n.t('sign_up')} {this.state.userLoading ? <Spinner /> : i18n.t("sign_up")}
</button> </button>
</div> </div>
</div> </div>
@ -183,7 +183,7 @@ export class Setup extends Component<any, State> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
this.state.userLoading = false; this.state.userLoading = false;
this.setState(this.state); this.setState(this.state);
return; return;
@ -194,7 +194,7 @@ export class Setup extends Component<any, State> {
UserService.Instance.login(data); UserService.Instance.login(data);
this.setState(this.state); this.setState(this.state);
} else if (op == UserOperation.CreateSite) { } else if (op == UserOperation.CreateSite) {
window.location.href = '/'; window.location.href = "/";
} }
} }
} }

View file

@ -1,5 +1,5 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Link } from 'inferno-router'; import { Link } from "inferno-router";
import { import {
CommunityView, CommunityView,
CommunityModeratorView, CommunityModeratorView,
@ -9,15 +9,15 @@ import {
UserViewSafe, UserViewSafe,
AddModToCommunity, AddModToCommunity,
Category, Category,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { mdToHtml, getUnixTime, wsClient, authField } from '../utils'; import { mdToHtml, getUnixTime, wsClient, authField } from "../utils";
import { CommunityForm } from './community-form'; import { CommunityForm } from "./community-form";
import { UserListing } from './user-listing'; import { UserListing } from "./user-listing";
import { CommunityLink } from './community-link'; import { CommunityLink } from "./community-link";
import { BannerIconHeader } from './banner-icon-header'; import { BannerIconHeader } from "./banner-icon-header";
import { Icon } from './icon'; import { Icon } from "./icon";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
interface SidebarProps { interface SidebarProps {
community_view: CommunityView; community_view: CommunityView;
@ -110,22 +110,22 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
onClick={linkEvent(community.id, this.handleUnsubscribe)} onClick={linkEvent(community.id, this.handleUnsubscribe)}
> >
<Icon icon="check" classes="icon-inline text-success mr-1" /> <Icon icon="check" classes="icon-inline text-success mr-1" />
{i18n.t('joined')} {i18n.t("joined")}
</a> </a>
)} )}
{community.removed && ( {community.removed && (
<small className="mr-2 text-muted font-italic"> <small className="mr-2 text-muted font-italic">
{i18n.t('removed')} {i18n.t("removed")}
</small> </small>
)} )}
{community.deleted && ( {community.deleted && (
<small className="mr-2 text-muted font-italic"> <small className="mr-2 text-muted font-italic">
{i18n.t('deleted')} {i18n.t("deleted")}
</small> </small>
)} )}
{community.nsfw && ( {community.nsfw && (
<small className="mr-2 text-muted font-italic"> <small className="mr-2 text-muted font-italic">
{i18n.t('nsfw')} {i18n.t("nsfw")}
</small> </small>
)} )}
</h5> </h5>
@ -146,66 +146,66 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
return ( return (
<ul class="my-1 list-inline"> <ul class="my-1 list-inline">
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t('number_online', { count: this.props.online })} {i18n.t("number_online", { count: this.props.online })}
</li> </li>
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={`${i18n.t('number_of_users', { data-tippy-content={`${i18n.t("number_of_users", {
count: counts.users_active_day, count: counts.users_active_day,
})} ${i18n.t('active_in_the_last')} ${i18n.t('day')}`} })} ${i18n.t("active_in_the_last")} ${i18n.t("day")}`}
> >
{i18n.t('number_of_users', { {i18n.t("number_of_users", {
count: counts.users_active_day, count: counts.users_active_day,
})}{' '} })}{" "}
/ {i18n.t('day')} / {i18n.t("day")}
</li> </li>
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={`${i18n.t('number_of_users', { data-tippy-content={`${i18n.t("number_of_users", {
count: counts.users_active_week, count: counts.users_active_week,
})} ${i18n.t('active_in_the_last')} ${i18n.t('week')}`} })} ${i18n.t("active_in_the_last")} ${i18n.t("week")}`}
> >
{i18n.t('number_of_users', { {i18n.t("number_of_users", {
count: counts.users_active_week, count: counts.users_active_week,
})}{' '} })}{" "}
/ {i18n.t('week')} / {i18n.t("week")}
</li> </li>
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={`${i18n.t('number_of_users', { data-tippy-content={`${i18n.t("number_of_users", {
count: counts.users_active_month, count: counts.users_active_month,
})} ${i18n.t('active_in_the_last')} ${i18n.t('month')}`} })} ${i18n.t("active_in_the_last")} ${i18n.t("month")}`}
> >
{i18n.t('number_of_users', { {i18n.t("number_of_users", {
count: counts.users_active_month, count: counts.users_active_month,
})}{' '} })}{" "}
/ {i18n.t('month')} / {i18n.t("month")}
</li> </li>
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={`${i18n.t('number_of_users', { data-tippy-content={`${i18n.t("number_of_users", {
count: counts.users_active_half_year, count: counts.users_active_half_year,
})} ${i18n.t('active_in_the_last')} ${i18n.t('number_of_months', { })} ${i18n.t("active_in_the_last")} ${i18n.t("number_of_months", {
count: 6, count: 6,
})}`} })}`}
> >
{i18n.t('number_of_users', { {i18n.t("number_of_users", {
count: counts.users_active_half_year, count: counts.users_active_half_year,
})}{' '} })}{" "}
/ {i18n.t('number_of_months', { count: 6 })} / {i18n.t("number_of_months", { count: 6 })}
</li> </li>
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t('number_of_subscribers', { {i18n.t("number_of_subscribers", {
count: counts.subscribers, count: counts.subscribers,
})} })}
</li> </li>
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t('number_of_posts', { {i18n.t("number_of_posts", {
count: counts.posts, count: counts.posts,
})} })}
</li> </li>
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t('number_of_comments', { {i18n.t("number_of_comments", {
count: counts.comments, count: counts.comments,
})} })}
</li> </li>
@ -219,7 +219,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
className="badge badge-secondary" className="badge badge-secondary"
to={`/modlog/community/${this.props.community_view.community.id}`} to={`/modlog/community/${this.props.community_view.community.id}`}
> >
{i18n.t('modlog')} {i18n.t("modlog")}
</Link> </Link>
</li> </li>
</ul> </ul>
@ -229,7 +229,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
mods() { mods() {
return ( return (
<ul class="list-inline small"> <ul class="list-inline small">
<li class="list-inline-item">{i18n.t('mods')}: </li> <li class="list-inline-item">{i18n.t("mods")}: </li>
{this.props.moderators.map(mod => ( {this.props.moderators.map(mod => (
<li class="list-inline-item"> <li class="list-inline-item">
<UserListing user={mod.moderator} /> <UserListing user={mod.moderator} />
@ -246,12 +246,12 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<Link <Link
className={`btn btn-secondary btn-block mb-2 ${ className={`btn btn-secondary btn-block mb-2 ${
community_view.community.deleted || community_view.community.removed community_view.community.deleted || community_view.community.removed
? 'no-click' ? "no-click"
: '' : ""
}`} }`}
to={`/create_post?community_id=${community_view.community.id}`} to={`/create_post?community_id=${community_view.community.id}`}
> >
{i18n.t('create_a_post')} {i18n.t("create_a_post")}
</Link> </Link>
) )
); );
@ -270,7 +270,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
this.handleSubscribe this.handleSubscribe
)} )}
> >
{i18n.t('subscribe')} {i18n.t("subscribe")}
</a> </a>
)} )}
</div> </div>
@ -301,8 +301,8 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
role="button" role="button"
class="pointer" class="pointer"
onClick={linkEvent(this, this.handleEditClick)} onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t('edit')} data-tippy-content={i18n.t("edit")}
aria-label={i18n.t('edit')} aria-label={i18n.t("edit")}
> >
<Icon icon="edit" classes="icon-inline" /> <Icon icon="edit" classes="icon-inline" />
</span> </span>
@ -318,13 +318,13 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
this.handleShowConfirmLeaveModTeamClick this.handleShowConfirmLeaveModTeamClick
)} )}
> >
{i18n.t('leave_mod_team')} {i18n.t("leave_mod_team")}
</span> </span>
</li> </li>
) : ( ) : (
<> <>
<li className="list-inline-item-action"> <li className="list-inline-item-action">
{i18n.t('are_you_sure')} {i18n.t("are_you_sure")}
</li> </li>
<li className="list-inline-item-action"> <li className="list-inline-item-action">
<span <span
@ -332,7 +332,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
role="button" role="button"
onClick={linkEvent(this, this.handleLeaveModTeamClick)} onClick={linkEvent(this, this.handleLeaveModTeamClick)}
> >
{i18n.t('yes')} {i18n.t("yes")}
</span> </span>
</li> </li>
<li className="list-inline-item-action"> <li className="list-inline-item-action">
@ -344,7 +344,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
this.handleCancelLeaveModTeamClick this.handleCancelLeaveModTeamClick
)} )}
> >
{i18n.t('no')} {i18n.t("no")}
</span> </span>
</li> </li>
</> </>
@ -356,19 +356,19 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
onClick={linkEvent(this, this.handleDeleteClick)} onClick={linkEvent(this, this.handleDeleteClick)}
data-tippy-content={ data-tippy-content={
!community_view.community.deleted !community_view.community.deleted
? i18n.t('delete') ? i18n.t("delete")
: i18n.t('restore') : i18n.t("restore")
} }
aria-label={ aria-label={
!community_view.community.deleted !community_view.community.deleted
? i18n.t('delete') ? i18n.t("delete")
: i18n.t('restore') : i18n.t("restore")
} }
> >
<Icon <Icon
icon="trash" icon="trash"
classes={`icon-inline ${ classes={`icon-inline ${
community_view.community.deleted && 'text-danger' community_view.community.deleted && "text-danger"
}`} }`}
/> />
</span> </span>
@ -384,7 +384,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
role="button" role="button"
onClick={linkEvent(this, this.handleModRemoveShow)} onClick={linkEvent(this, this.handleModRemoveShow)}
> >
{i18n.t('remove')} {i18n.t("remove")}
</span> </span>
) : ( ) : (
<span <span
@ -392,7 +392,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
role="button" role="button"
onClick={linkEvent(this, this.handleModRemoveSubmit)} onClick={linkEvent(this, this.handleModRemoveSubmit)}
> >
{i18n.t('restore')} {i18n.t("restore")}
</span> </span>
)} )}
</li> </li>
@ -402,13 +402,13 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<form onSubmit={linkEvent(this, this.handleModRemoveSubmit)}> <form onSubmit={linkEvent(this, this.handleModRemoveSubmit)}>
<div class="form-group row"> <div class="form-group row">
<label class="col-form-label" htmlFor="remove-reason"> <label class="col-form-label" htmlFor="remove-reason">
{i18n.t('reason')} {i18n.t("reason")}
</label> </label>
<input <input
type="text" type="text"
id="remove-reason" id="remove-reason"
class="form-control mr-2" class="form-control mr-2"
placeholder={i18n.t('optional')} placeholder={i18n.t("optional")}
value={this.state.removeReason} value={this.state.removeReason}
onInput={linkEvent(this, this.handleModRemoveReasonChange)} onInput={linkEvent(this, this.handleModRemoveReasonChange)}
/> />
@ -420,7 +420,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
{/* </div> */} {/* </div> */}
<div class="form-group row"> <div class="form-group row">
<button type="submit" class="btn btn-secondary"> <button type="submit" class="btn btn-secondary">
{i18n.t('remove_community')} {i18n.t("remove_community")}
</button> </button>
</div> </div>
</form> </form>

View file

@ -1,17 +1,17 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Prompt } from 'inferno-router'; import { Prompt } from "inferno-router";
import { MarkdownTextArea } from './markdown-textarea'; import { MarkdownTextArea } from "./markdown-textarea";
import { Spinner } from './icon'; import { Spinner } from "./icon";
import { ImageUploadForm } from './image-upload-form'; import { ImageUploadForm } from "./image-upload-form";
import { Site, EditSite } from 'lemmy-js-client'; import { Site, EditSite } from "lemmy-js-client";
import { WebSocketService } from '../services'; import { WebSocketService } from "../services";
import { import {
authField, authField,
capitalizeFirstLetter, capitalizeFirstLetter,
randomStr, randomStr,
wsClient, wsClient,
} from '../utils'; } from "../utils";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
interface SiteFormProps { interface SiteFormProps {
site?: Site; // If a site is given, that means this is an edit site?: Site; // If a site is given, that means this is an edit
@ -97,17 +97,17 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
!this.props.site && !this.props.site &&
(this.state.siteForm.name || this.state.siteForm.description) (this.state.siteForm.name || this.state.siteForm.description)
} }
message={i18n.t('block_leaving')} message={i18n.t("block_leaving")}
/> />
<form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}> <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
<h5>{`${ <h5>{`${
this.props.site this.props.site
? capitalizeFirstLetter(i18n.t('save')) ? capitalizeFirstLetter(i18n.t("save"))
: capitalizeFirstLetter(i18n.t('name')) : capitalizeFirstLetter(i18n.t("name"))
} ${i18n.t('your_site')}`}</h5> } ${i18n.t("your_site")}`}</h5>
<div class="form-group row"> <div class="form-group row">
<label class="col-12 col-form-label" htmlFor="create-site-name"> <label class="col-12 col-form-label" htmlFor="create-site-name">
{i18n.t('name')} {i18n.t("name")}
</label> </label>
<div class="col-12"> <div class="col-12">
<input <input
@ -123,9 +123,9 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{i18n.t('icon')}</label> <label>{i18n.t("icon")}</label>
<ImageUploadForm <ImageUploadForm
uploadTitle={i18n.t('upload_icon')} uploadTitle={i18n.t("upload_icon")}
imageSrc={this.state.siteForm.icon} imageSrc={this.state.siteForm.icon}
onUpload={this.handleIconUpload} onUpload={this.handleIconUpload}
onRemove={this.handleIconRemove} onRemove={this.handleIconRemove}
@ -133,9 +133,9 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
/> />
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{i18n.t('banner')}</label> <label>{i18n.t("banner")}</label>
<ImageUploadForm <ImageUploadForm
uploadTitle={i18n.t('upload_banner')} uploadTitle={i18n.t("upload_banner")}
imageSrc={this.state.siteForm.banner} imageSrc={this.state.siteForm.banner}
onUpload={this.handleBannerUpload} onUpload={this.handleBannerUpload}
onRemove={this.handleBannerRemove} onRemove={this.handleBannerRemove}
@ -143,7 +143,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-12 col-form-label" htmlFor={this.id}> <label class="col-12 col-form-label" htmlFor={this.id}>
{i18n.t('sidebar')} {i18n.t("sidebar")}
</label> </label>
<div class="col-12"> <div class="col-12">
<MarkdownTextArea <MarkdownTextArea
@ -167,7 +167,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
)} )}
/> />
<label class="form-check-label" htmlFor="create-site-downvotes"> <label class="form-check-label" htmlFor="create-site-downvotes">
{i18n.t('enable_downvotes')} {i18n.t("enable_downvotes")}
</label> </label>
</div> </div>
</div> </div>
@ -186,7 +186,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
class="form-check-label" class="form-check-label"
htmlFor="create-site-enable-nsfw" htmlFor="create-site-enable-nsfw"
> >
{i18n.t('enable_nsfw')} {i18n.t("enable_nsfw")}
</label> </label>
</div> </div>
</div> </div>
@ -208,7 +208,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
class="form-check-label" class="form-check-label"
htmlFor="create-site-open-registration" htmlFor="create-site-open-registration"
> >
{i18n.t('open_registration')} {i18n.t("open_registration")}
</label> </label>
</div> </div>
</div> </div>
@ -223,9 +223,9 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
{this.state.loading ? ( {this.state.loading ? (
<Spinner /> <Spinner />
) : this.props.site ? ( ) : this.props.site ? (
capitalizeFirstLetter(i18n.t('save')) capitalizeFirstLetter(i18n.t("save"))
) : ( ) : (
capitalizeFirstLetter(i18n.t('create')) capitalizeFirstLetter(i18n.t("create"))
)} )}
</button> </button>
{this.props.site && ( {this.props.site && (
@ -234,7 +234,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
class="btn btn-secondary" class="btn btn-secondary"
onClick={linkEvent(this, this.handleCancel)} onClick={linkEvent(this, this.handleCancel)}
> >
{i18n.t('cancel')} {i18n.t("cancel")}
</button> </button>
)} )}
</div> </div>
@ -290,7 +290,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
} }
handleIconRemove() { handleIconRemove() {
this.state.siteForm.icon = ''; this.state.siteForm.icon = "";
this.setState(this.state); this.setState(this.state);
} }
@ -300,7 +300,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
} }
handleBannerRemove() { handleBannerRemove() {
this.state.siteForm.banner = ''; this.state.siteForm.banner = "";
this.setState(this.state); this.setState(this.state);
} }
} }

View file

@ -1,8 +1,8 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { SortType } from 'lemmy-js-client'; import { SortType } from "lemmy-js-client";
import { sortingHelpUrl, randomStr } from '../utils'; import { sortingHelpUrl, randomStr } from "../utils";
import { Icon } from './icon'; import { Icon } from "./icon";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
interface SortSelectProps { interface SortSelectProps {
sort: SortType; sort: SortType;
@ -41,38 +41,38 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
value={this.state.sort} value={this.state.sort}
onChange={linkEvent(this, this.handleSortChange)} onChange={linkEvent(this, this.handleSortChange)}
class="custom-select w-auto mr-2 mb-2" class="custom-select w-auto mr-2 mb-2"
aria-label={i18n.t('sort_type')} aria-label={i18n.t("sort_type")}
> >
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
{i18n.t('sort_type')} {i18n.t("sort_type")}
</option> </option>
{!this.props.hideHot && [ {!this.props.hideHot && [
<option value={SortType.Hot}>{i18n.t('hot')}</option>, <option value={SortType.Hot}>{i18n.t("hot")}</option>,
<option value={SortType.Active}>{i18n.t('active')}</option>, <option value={SortType.Active}>{i18n.t("active")}</option>,
]} ]}
<option value={SortType.New}>{i18n.t('new')}</option> <option value={SortType.New}>{i18n.t("new")}</option>
{!this.props.hideMostComments && [ {!this.props.hideMostComments && [
<option value={SortType.MostComments}> <option value={SortType.MostComments}>
{i18n.t('most_comments')} {i18n.t("most_comments")}
</option>, </option>,
<option value={SortType.NewComments}> <option value={SortType.NewComments}>
{i18n.t('new_comments')} {i18n.t("new_comments")}
</option>, </option>,
]} ]}
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
</option> </option>
<option value={SortType.TopDay}>{i18n.t('top_day')}</option> <option value={SortType.TopDay}>{i18n.t("top_day")}</option>
<option value={SortType.TopWeek}>{i18n.t('top_week')}</option> <option value={SortType.TopWeek}>{i18n.t("top_week")}</option>
<option value={SortType.TopMonth}>{i18n.t('top_month')}</option> <option value={SortType.TopMonth}>{i18n.t("top_month")}</option>
<option value={SortType.TopYear}>{i18n.t('top_year')}</option> <option value={SortType.TopYear}>{i18n.t("top_year")}</option>
<option value={SortType.TopAll}>{i18n.t('top_all')}</option> <option value={SortType.TopAll}>{i18n.t("top_all")}</option>
</select> </select>
<a <a
className="text-muted" className="text-muted"
href={sortingHelpUrl} href={sortingHelpUrl}
rel="noopener" rel="noopener"
title={i18n.t('sorting_help')} title={i18n.t("sorting_help")}
> >
<Icon icon="help-circle" classes="icon-inline" /> <Icon icon="help-circle" classes="icon-inline" />
</a> </a>

View file

@ -1,6 +1,6 @@
// Custom css // Custom css
@import '../../../node_modules/tributejs/dist/tribute.css'; @import "../../../node_modules/tributejs/dist/tribute.css";
@import '../../../node_modules/toastify-js/src/toastify.css'; @import "../../../node_modules/toastify-js/src/toastify.css";
@import '../../../node_modules/choices.js/src/styles/choices.scss'; @import "../../../node_modules/choices.js/src/styles/choices.scss";
@import '../../../node_modules/tippy.js/dist/tippy.css'; @import "../../../node_modules/tippy.js/dist/tippy.css";
@import '../../assets/css/main.css'; @import "../../assets/css/main.css";

View file

@ -1,4 +1,4 @@
import { Component } from 'inferno'; import { Component } from "inferno";
export class Symbols extends Component<any, any> { export class Symbols extends Component<any, any> {
constructor(props: any, context: any) { constructor(props: any, context: any) {
@ -10,10 +10,10 @@ export class Symbols extends Component<any, any> {
<svg <svg
aria-hidden="true" aria-hidden="true"
style={{ style={{
position: 'absolute', position: "absolute",
width: 0, width: 0,
height: 0, height: 0,
overflow: 'hidden', overflow: "hidden",
}} }}
version="1.1" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

View file

@ -1,6 +1,6 @@
import { UserSafeSettings } from 'lemmy-js-client'; import { UserSafeSettings } from "lemmy-js-client";
import { Helmet } from 'inferno-helmet'; import { Helmet } from "inferno-helmet";
import { Component } from 'inferno'; import { Component } from "inferno";
interface Props { interface Props {
user: UserSafeSettings | undefined; user: UserSafeSettings | undefined;
@ -9,7 +9,7 @@ interface Props {
export class Theme extends Component<Props> { export class Theme extends Component<Props> {
render() { render() {
const { user } = this.props; const { user } = this.props;
const hasUserTheme = user && user.theme !== 'browser'; const hasUserTheme = user && user.theme !== "browser";
return ( return (
<Helmet> <Helmet>

View file

@ -1,16 +1,16 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import { import {
PostView, PostView,
CommentView, CommentView,
SortType, SortType,
GetUserDetailsResponse, GetUserDetailsResponse,
UserViewSafe, UserViewSafe,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { UserDetailsView } from '../interfaces'; import { UserDetailsView } from "../interfaces";
import { commentsToFlatNodes, setupTippy } from '../utils'; import { commentsToFlatNodes, setupTippy } from "../utils";
import { PostListing } from './post-listing'; import { PostListing } from "./post-listing";
import { CommentNodes } from './comment-nodes'; import { CommentNodes } from "./comment-nodes";
interface UserDetailsProps { interface UserDetailsProps {
userRes: GetUserDetailsResponse; userRes: GetUserDetailsResponse;
@ -187,7 +187,7 @@ export class UserDetails extends Component<UserDetailsProps, any> {
class="btn btn-secondary mr-1" class="btn btn-secondary mr-1"
onClick={linkEvent(this, this.prevPage)} onClick={linkEvent(this, this.prevPage)}
> >
{i18n.t('prev')} {i18n.t("prev")}
</button> </button>
)} )}
{this.props.userRes.comments.length + this.props.userRes.posts.length > {this.props.userRes.comments.length + this.props.userRes.posts.length >
@ -196,7 +196,7 @@ export class UserDetails extends Component<UserDetailsProps, any> {
class="btn btn-secondary" class="btn btn-secondary"
onClick={linkEvent(this, this.nextPage)} onClick={linkEvent(this, this.nextPage)}
> >
{i18n.t('next')} {i18n.t("next")}
</button> </button>
)} )}
</div> </div>

View file

@ -1,9 +1,9 @@
import { Component } from 'inferno'; import { Component } from "inferno";
import { Link } from 'inferno-router'; import { Link } from "inferno-router";
import { UserSafe } from 'lemmy-js-client'; import { UserSafe } from "lemmy-js-client";
import { showAvatars, hostname, isCakeDay } from '../utils'; import { showAvatars, hostname, isCakeDay } from "../utils";
import { CakeDay } from './cake-day'; import { CakeDay } from "./cake-day";
import { PictrsImage } from './pictrs-image'; import { PictrsImage } from "./pictrs-image";
interface UserListingProps { interface UserListingProps {
user: UserSafe; user: UserSafe;
@ -46,7 +46,7 @@ export class UserListing extends Component<UserListingProps, any> {
<> <>
<Link <Link
title={apubName} title={apubName}
className={this.props.muted ? 'text-muted' : 'text-info'} className={this.props.muted ? "text-muted" : "text-info"}
to={link} to={link}
> >
{!this.props.hideAvatar && user.avatar && showAvatars() && ( {!this.props.hideAvatar && user.avatar && showAvatars() && (

View file

@ -1,6 +1,6 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from "inferno";
import { Link } from 'inferno-router'; import { Link } from "inferno-router";
import { Subscription } from 'rxjs'; import { Subscription } from "rxjs";
import { import {
UserOperation, UserOperation,
SortType, SortType,
@ -15,9 +15,9 @@ import {
CommentResponse, CommentResponse,
PostResponse, PostResponse,
BanUserResponse, BanUserResponse,
} from 'lemmy-js-client'; } from "lemmy-js-client";
import { InitialFetchRequest, UserDetailsView } from '../interfaces'; import { InitialFetchRequest, UserDetailsView } from "../interfaces";
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from "../services";
import { import {
wsJsonToRes, wsJsonToRes,
fetchLimit, fetchLimit,
@ -47,20 +47,20 @@ import {
setOptionalAuth, setOptionalAuth,
saveScrollPosition, saveScrollPosition,
restoreScrollPosition, restoreScrollPosition,
} from '../utils'; } from "../utils";
import { UserListing } from './user-listing'; import { UserListing } from "./user-listing";
import { HtmlTags } from './html-tags'; 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";
import { i18n } from '../i18next'; import { i18n } from "../i18next";
import moment from 'moment'; import moment from "moment";
import { UserDetails } from './user-details'; import { UserDetails } from "./user-details";
import { MarkdownTextArea } from './markdown-textarea'; import { MarkdownTextArea } from "./markdown-textarea";
import { Icon, Spinner } from './icon'; import { Icon, Spinner } from "./icon";
import { ImageUploadForm } from './image-upload-form'; import { ImageUploadForm } from "./image-upload-form";
import { BannerIconHeader } from './banner-icon-header'; import { BannerIconHeader } from "./banner-icon-header";
import { CommunityLink } from './community-link'; import { CommunityLink } from "./community-link";
interface UserState { interface UserState {
userRes: GetUserDetailsResponse; userRes: GetUserDetailsResponse;
@ -195,7 +195,7 @@ export class User extends Component<any, UserState> {
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split('/'); let pathSplit = req.path.split("/");
let promises: Promise<any>[] = []; let promises: Promise<any>[] = [];
// It can be /u/me, or /username/1 // It can be /u/me, or /username/1
@ -250,8 +250,8 @@ export class User extends Component<any, UserState> {
componentDidUpdate(lastProps: any) { componentDidUpdate(lastProps: any) {
// 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 ( if (
lastProps.location.pathname.split('/')[2] !== lastProps.location.pathname.split("/")[2] !==
lastProps.history.location.pathname.split('/')[2] lastProps.history.location.pathname.split("/")[2]
) { ) {
// Couldnt get a refresh working. This does for now. // Couldnt get a refresh working. This does for now.
location.reload(); location.reload();
@ -322,7 +322,7 @@ export class User extends Component<any, UserState> {
<div class="btn-group btn-group-toggle flex-wrap mb-2"> <div class="btn-group btn-group-toggle flex-wrap mb-2">
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.view == UserDetailsView.Overview && 'active'} ${this.state.view == UserDetailsView.Overview && "active"}
`} `}
> >
<input <input
@ -331,11 +331,11 @@ export class User extends Component<any, UserState> {
checked={this.state.view === UserDetailsView.Overview} checked={this.state.view === UserDetailsView.Overview}
onChange={linkEvent(this, this.handleViewChange)} onChange={linkEvent(this, this.handleViewChange)}
/> />
{i18n.t('overview')} {i18n.t("overview")}
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.view == UserDetailsView.Comments && 'active'} ${this.state.view == UserDetailsView.Comments && "active"}
`} `}
> >
<input <input
@ -344,11 +344,11 @@ export class User extends Component<any, UserState> {
checked={this.state.view == UserDetailsView.Comments} checked={this.state.view == UserDetailsView.Comments}
onChange={linkEvent(this, this.handleViewChange)} onChange={linkEvent(this, this.handleViewChange)}
/> />
{i18n.t('comments')} {i18n.t("comments")}
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.view == UserDetailsView.Posts && 'active'} ${this.state.view == UserDetailsView.Posts && "active"}
`} `}
> >
<input <input
@ -357,11 +357,11 @@ export class User extends Component<any, UserState> {
checked={this.state.view == UserDetailsView.Posts} checked={this.state.view == UserDetailsView.Posts}
onChange={linkEvent(this, this.handleViewChange)} onChange={linkEvent(this, this.handleViewChange)}
/> />
{i18n.t('posts')} {i18n.t("posts")}
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.view == UserDetailsView.Saved && 'active'} ${this.state.view == UserDetailsView.Saved && "active"}
`} `}
> >
<input <input
@ -370,7 +370,7 @@ export class User extends Component<any, UserState> {
checked={this.state.view == UserDetailsView.Saved} checked={this.state.view == UserDetailsView.Saved}
onChange={linkEvent(this, this.handleViewChange)} onChange={linkEvent(this, this.handleViewChange)}
/> />
{i18n.t('saved')} {i18n.t("saved")}
</label> </label>
</div> </div>
); );
@ -422,7 +422,7 @@ export class User extends Component<any, UserState> {
</li> </li>
{uv.user.banned && ( {uv.user.banned && (
<li className="list-inline-item badge badge-danger"> <li className="list-inline-item badge badge-danger">
{i18n.t('banned')} {i18n.t("banned")}
</li> </li>
)} )}
</ul> </ul>
@ -433,24 +433,24 @@ export class User extends Component<any, UserState> {
class="d-flex align-self-start btn btn-secondary mr-2" class="d-flex align-self-start btn btn-secondary mr-2"
onClick={linkEvent(this, this.handleLogoutClick)} onClick={linkEvent(this, this.handleLogoutClick)}
> >
{i18n.t('logout')} {i18n.t("logout")}
</button> </button>
) : ( ) : (
<> <>
<a <a
className={`d-flex align-self-start btn btn-secondary mr-2 ${ className={`d-flex align-self-start btn btn-secondary mr-2 ${
!uv.user.matrix_user_id && 'invisible' !uv.user.matrix_user_id && "invisible"
}`} }`}
rel="noopener" rel="noopener"
href={`https://matrix.to/#/${uv.user.matrix_user_id}`} href={`https://matrix.to/#/${uv.user.matrix_user_id}`}
> >
{i18n.t('send_secure_message')} {i18n.t("send_secure_message")}
</a> </a>
<Link <Link
className={'d-flex align-self-start btn btn-secondary'} className={"d-flex align-self-start btn btn-secondary"}
to={`/create_private_message/recipient/${uv.user.id}`} to={`/create_private_message/recipient/${uv.user.id}`}
> >
{i18n.t('send_message')} {i18n.t("send_message")}
</Link> </Link>
</> </>
)} )}
@ -466,24 +466,24 @@ export class User extends Component<any, UserState> {
<div> <div>
<ul class="list-inline mb-2"> <ul class="list-inline mb-2">
<li className="list-inline-item badge badge-light"> <li className="list-inline-item badge badge-light">
{i18n.t('number_of_posts', { count: uv.counts.post_count })} {i18n.t("number_of_posts", { count: uv.counts.post_count })}
</li> </li>
<li className="list-inline-item badge badge-light"> <li className="list-inline-item badge badge-light">
{i18n.t('number_of_comments', { {i18n.t("number_of_comments", {
count: uv.counts.comment_count, count: uv.counts.comment_count,
})} })}
</li> </li>
</ul> </ul>
</div> </div>
<div class="text-muted"> <div class="text-muted">
{i18n.t('joined')}{' '} {i18n.t("joined")}{" "}
<MomentTime data={uv.user} showAgo ignoreUpdated /> <MomentTime data={uv.user} showAgo ignoreUpdated />
</div> </div>
<div className="d-flex align-items-center text-muted mb-2"> <div className="d-flex align-items-center text-muted mb-2">
<Icon icon="cake" /> <Icon icon="cake" />
<span className="ml-2"> <span className="ml-2">
{i18n.t('cake_day_title')}{' '} {i18n.t("cake_day_title")}{" "}
{moment.utc(uv.user.published).local().format('MMM DD, YYYY')} {moment.utc(uv.user.published).local().format("MMM DD, YYYY")}
</span> </span>
</div> </div>
</div> </div>
@ -497,12 +497,12 @@ export class User extends Component<any, UserState> {
<div> <div>
<div class="card border-secondary mb-3"> <div class="card border-secondary mb-3">
<div class="card-body"> <div class="card-body">
<h5>{i18n.t('settings')}</h5> <h5>{i18n.t("settings")}</h5>
<form onSubmit={linkEvent(this, this.handleUserSettingsSubmit)}> <form onSubmit={linkEvent(this, this.handleUserSettingsSubmit)}>
<div class="form-group"> <div class="form-group">
<label>{i18n.t('avatar')}</label> <label>{i18n.t("avatar")}</label>
<ImageUploadForm <ImageUploadForm
uploadTitle={i18n.t('upload_avatar')} uploadTitle={i18n.t("upload_avatar")}
imageSrc={this.state.userSettingsForm.avatar} imageSrc={this.state.userSettingsForm.avatar}
onUpload={this.handleAvatarUpload} onUpload={this.handleAvatarUpload}
onRemove={this.handleAvatarRemove} onRemove={this.handleAvatarRemove}
@ -510,16 +510,16 @@ export class User extends Component<any, UserState> {
/> />
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{i18n.t('banner')}</label> <label>{i18n.t("banner")}</label>
<ImageUploadForm <ImageUploadForm
uploadTitle={i18n.t('upload_banner')} uploadTitle={i18n.t("upload_banner")}
imageSrc={this.state.userSettingsForm.banner} imageSrc={this.state.userSettingsForm.banner}
onUpload={this.handleBannerUpload} onUpload={this.handleBannerUpload}
onRemove={this.handleBannerRemove} onRemove={this.handleBannerRemove}
/> />
</div> </div>
<div class="form-group"> <div class="form-group">
<label htmlFor="user-language">{i18n.t('language')}</label> <label htmlFor="user-language">{i18n.t("language")}</label>
<select <select
id="user-language" id="user-language"
value={this.state.userSettingsForm.lang} value={this.state.userSettingsForm.lang}
@ -527,9 +527,9 @@ export class User extends Component<any, UserState> {
class="ml-2 custom-select w-auto" class="ml-2 custom-select w-auto"
> >
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
{i18n.t('language')} {i18n.t("language")}
</option> </option>
<option value="browser">{i18n.t('browser_default')}</option> <option value="browser">{i18n.t("browser_default")}</option>
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
</option> </option>
@ -539,7 +539,7 @@ export class User extends Component<any, UserState> {
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<label htmlFor="user-theme">{i18n.t('theme')}</label> <label htmlFor="user-theme">{i18n.t("theme")}</label>
<select <select
id="user-theme" id="user-theme"
value={this.state.userSettingsForm.theme} value={this.state.userSettingsForm.theme}
@ -547,9 +547,9 @@ export class User extends Component<any, UserState> {
class="ml-2 custom-select w-auto" class="ml-2 custom-select w-auto"
> >
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
{i18n.t('theme')} {i18n.t("theme")}
</option> </option>
<option value="browser">{i18n.t('browser_default')}</option> <option value="browser">{i18n.t("browser_default")}</option>
{themes.map(theme => ( {themes.map(theme => (
<option value={theme}>{theme}</option> <option value={theme}>{theme}</option>
))} ))}
@ -557,7 +557,7 @@ export class User extends Component<any, UserState> {
</div> </div>
<form className="form-group"> <form className="form-group">
<label> <label>
<div class="mr-2">{i18n.t('sort_type')}</div> <div class="mr-2">{i18n.t("sort_type")}</div>
</label> </label>
<ListingTypeSelect <ListingTypeSelect
type_={ type_={
@ -573,7 +573,7 @@ export class User extends Component<any, UserState> {
</form> </form>
<form className="form-group"> <form className="form-group">
<label> <label>
<div class="mr-2">{i18n.t('type')}</div> <div class="mr-2">{i18n.t("type")}</div>
</label> </label>
<SortSelect <SortSelect
sort={ sort={
@ -586,14 +586,14 @@ export class User extends Component<any, UserState> {
</form> </form>
<div class="form-group row"> <div class="form-group row">
<label class="col-lg-5 col-form-label" htmlFor="display-name"> <label class="col-lg-5 col-form-label" htmlFor="display-name">
{i18n.t('display_name')} {i18n.t("display_name")}
</label> </label>
<div class="col-lg-7"> <div class="col-lg-7">
<input <input
id="display-name" id="display-name"
type="text" type="text"
class="form-control" class="form-control"
placeholder={i18n.t('optional')} placeholder={i18n.t("optional")}
value={this.state.userSettingsForm.preferred_username} value={this.state.userSettingsForm.preferred_username}
onInput={linkEvent( onInput={linkEvent(
this, this,
@ -607,7 +607,7 @@ export class User extends Component<any, UserState> {
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-lg-3 col-form-label" htmlFor="user-bio"> <label class="col-lg-3 col-form-label" htmlFor="user-bio">
{i18n.t('bio')} {i18n.t("bio")}
</label> </label>
<div class="col-lg-9"> <div class="col-lg-9">
<MarkdownTextArea <MarkdownTextArea
@ -620,14 +620,14 @@ export class User extends Component<any, UserState> {
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-lg-3 col-form-label" htmlFor="user-email"> <label class="col-lg-3 col-form-label" htmlFor="user-email">
{i18n.t('email')} {i18n.t("email")}
</label> </label>
<div class="col-lg-9"> <div class="col-lg-9">
<input <input
type="email" type="email"
id="user-email" id="user-email"
class="form-control" class="form-control"
placeholder={i18n.t('optional')} placeholder={i18n.t("optional")}
value={this.state.userSettingsForm.email} value={this.state.userSettingsForm.email}
onInput={linkEvent( onInput={linkEvent(
this, this,
@ -640,7 +640,7 @@ export class User extends Component<any, UserState> {
<div class="form-group row"> <div class="form-group row">
<label class="col-lg-5 col-form-label" htmlFor="matrix-user-id"> <label class="col-lg-5 col-form-label" htmlFor="matrix-user-id">
<a href={elementUrl} rel="noopener"> <a href={elementUrl} rel="noopener">
{i18n.t('matrix_user_id')} {i18n.t("matrix_user_id")}
</a> </a>
</label> </label>
<div class="col-lg-7"> <div class="col-lg-7">
@ -660,7 +660,7 @@ export class User extends Component<any, UserState> {
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-lg-5 col-form-label" htmlFor="user-password"> <label class="col-lg-5 col-form-label" htmlFor="user-password">
{i18n.t('new_password')} {i18n.t("new_password")}
</label> </label>
<div class="col-lg-7"> <div class="col-lg-7">
<input <input
@ -681,7 +681,7 @@ export class User extends Component<any, UserState> {
class="col-lg-5 col-form-label" class="col-lg-5 col-form-label"
htmlFor="user-verify-password" htmlFor="user-verify-password"
> >
{i18n.t('verify_password')} {i18n.t("verify_password")}
</label> </label>
<div class="col-lg-7"> <div class="col-lg-7">
<input <input
@ -702,7 +702,7 @@ export class User extends Component<any, UserState> {
class="col-lg-5 col-form-label" class="col-lg-5 col-form-label"
htmlFor="user-old-password" htmlFor="user-old-password"
> >
{i18n.t('old_password')} {i18n.t("old_password")}
</label> </label>
<div class="col-lg-7"> <div class="col-lg-7">
<input <input
@ -732,7 +732,7 @@ export class User extends Component<any, UserState> {
)} )}
/> />
<label class="form-check-label" htmlFor="user-show-nsfw"> <label class="form-check-label" htmlFor="user-show-nsfw">
{i18n.t('show_nsfw')} {i18n.t("show_nsfw")}
</label> </label>
</div> </div>
</div> </div>
@ -750,7 +750,7 @@ export class User extends Component<any, UserState> {
)} )}
/> />
<label class="form-check-label" htmlFor="user-show-avatars"> <label class="form-check-label" htmlFor="user-show-avatars">
{i18n.t('show_avatars')} {i18n.t("show_avatars")}
</label> </label>
</div> </div>
</div> </div>
@ -773,7 +773,7 @@ export class User extends Component<any, UserState> {
class="form-check-label" class="form-check-label"
htmlFor="user-send-notifications-to-email" htmlFor="user-send-notifications-to-email"
> >
{i18n.t('send_notifications_to_email')} {i18n.t("send_notifications_to_email")}
</label> </label>
</div> </div>
</div> </div>
@ -782,7 +782,7 @@ export class User extends Component<any, UserState> {
{this.state.userSettingsLoading ? ( {this.state.userSettingsLoading ? (
<Spinner /> <Spinner />
) : ( ) : (
capitalizeFirstLetter(i18n.t('save')) capitalizeFirstLetter(i18n.t("save"))
)} )}
</button> </button>
</div> </div>
@ -795,12 +795,12 @@ export class User extends Component<any, UserState> {
this.handleDeleteAccountShowConfirmToggle this.handleDeleteAccountShowConfirmToggle
)} )}
> >
{i18n.t('delete_account')} {i18n.t("delete_account")}
</button> </button>
{this.state.deleteAccountShowConfirm && ( {this.state.deleteAccountShowConfirm && (
<> <>
<div class="my-2 alert alert-danger" role="alert"> <div class="my-2 alert alert-danger" role="alert">
{i18n.t('delete_account_confirm')} {i18n.t("delete_account_confirm")}
</div> </div>
<input <input
type="password" type="password"
@ -820,7 +820,7 @@ export class User extends Component<any, UserState> {
{this.state.deleteAccountLoading ? ( {this.state.deleteAccountLoading ? (
<Spinner /> <Spinner />
) : ( ) : (
capitalizeFirstLetter(i18n.t('delete')) capitalizeFirstLetter(i18n.t("delete"))
)} )}
</button> </button>
<button <button
@ -830,7 +830,7 @@ export class User extends Component<any, UserState> {
this.handleDeleteAccountShowConfirmToggle this.handleDeleteAccountShowConfirmToggle
)} )}
> >
{i18n.t('cancel')} {i18n.t("cancel")}
</button> </button>
</> </>
)} )}
@ -848,7 +848,7 @@ export class User extends Component<any, UserState> {
{this.state.userRes.moderates.length > 0 && ( {this.state.userRes.moderates.length > 0 && (
<div class="card border-secondary mb-3"> <div class="card border-secondary mb-3">
<div class="card-body"> <div class="card-body">
<h5>{i18n.t('moderates')}</h5> <h5>{i18n.t("moderates")}</h5>
<ul class="list-unstyled mb-0"> <ul class="list-unstyled mb-0">
{this.state.userRes.moderates.map(cmv => ( {this.state.userRes.moderates.map(cmv => (
<li> <li>
@ -869,7 +869,7 @@ export class User extends Component<any, UserState> {
{this.state.userRes.follows.length > 0 && ( {this.state.userRes.follows.length > 0 && (
<div class="card border-secondary mb-3"> <div class="card border-secondary mb-3">
<div class="card-body"> <div class="card-body">
<h5>{i18n.t('subscribed')}</h5> <h5>{i18n.t("subscribed")}</h5>
<ul class="list-unstyled mb-0"> <ul class="list-unstyled mb-0">
{this.state.userRes.follows.map(cfv => ( {this.state.userRes.follows.map(cfv => (
<li> <li>
@ -974,7 +974,7 @@ export class User extends Component<any, UserState> {
} }
handleAvatarRemove() { handleAvatarRemove() {
this.state.userSettingsForm.avatar = ''; this.state.userSettingsForm.avatar = "";
this.setState(this.state); this.setState(this.state);
} }
@ -984,7 +984,7 @@ export class User extends Component<any, UserState> {
} }
handleBannerRemove() { handleBannerRemove() {
this.state.userSettingsForm.banner = ''; this.state.userSettingsForm.banner = "";
this.setState(this.state); this.setState(this.state);
} }
@ -996,7 +996,7 @@ export class User extends Component<any, UserState> {
handleUserSettingsMatrixUserIdChange(i: User, event: any) { handleUserSettingsMatrixUserIdChange(i: User, event: any) {
i.state.userSettingsForm.matrix_user_id = event.target.value; i.state.userSettingsForm.matrix_user_id = event.target.value;
if ( if (
i.state.userSettingsForm.matrix_user_id == '' && i.state.userSettingsForm.matrix_user_id == "" &&
!i.state.userRes.user_view.user.matrix_user_id !i.state.userRes.user_view.user.matrix_user_id
) { ) {
i.state.userSettingsForm.matrix_user_id = undefined; i.state.userSettingsForm.matrix_user_id = undefined;
@ -1006,7 +1006,7 @@ export class User extends Component<any, UserState> {
handleUserSettingsNewPasswordChange(i: User, event: any) { handleUserSettingsNewPasswordChange(i: User, event: any) {
i.state.userSettingsForm.new_password = event.target.value; i.state.userSettingsForm.new_password = event.target.value;
if (i.state.userSettingsForm.new_password == '') { if (i.state.userSettingsForm.new_password == "") {
i.state.userSettingsForm.new_password = undefined; i.state.userSettingsForm.new_password = undefined;
} }
i.setState(i.state); i.setState(i.state);
@ -1014,7 +1014,7 @@ export class User extends Component<any, UserState> {
handleUserSettingsNewPasswordVerifyChange(i: User, event: any) { handleUserSettingsNewPasswordVerifyChange(i: User, event: any) {
i.state.userSettingsForm.new_password_verify = event.target.value; i.state.userSettingsForm.new_password_verify = event.target.value;
if (i.state.userSettingsForm.new_password_verify == '') { if (i.state.userSettingsForm.new_password_verify == "") {
i.state.userSettingsForm.new_password_verify = undefined; i.state.userSettingsForm.new_password_verify = undefined;
} }
i.setState(i.state); i.setState(i.state);
@ -1022,7 +1022,7 @@ export class User extends Component<any, UserState> {
handleUserSettingsOldPasswordChange(i: User, event: any) { handleUserSettingsOldPasswordChange(i: User, event: any) {
i.state.userSettingsForm.old_password = event.target.value; i.state.userSettingsForm.old_password = event.target.value;
if (i.state.userSettingsForm.old_password == '') { if (i.state.userSettingsForm.old_password == "") {
i.state.userSettingsForm.old_password = undefined; i.state.userSettingsForm.old_password = undefined;
} }
i.setState(i.state); i.setState(i.state);
@ -1051,7 +1051,7 @@ export class User extends Component<any, UserState> {
handleLogoutClick(i: User) { handleLogoutClick(i: User) {
UserService.Instance.logout(); UserService.Instance.logout();
i.context.router.history.push('/'); i.context.router.history.push("/");
} }
handleDeleteAccount(i: User, event: any) { handleDeleteAccount(i: User, event: any) {
@ -1071,7 +1071,7 @@ export class User extends Component<any, UserState> {
UserService.Instance.user.show_nsfw; UserService.Instance.user.show_nsfw;
this.state.userSettingsForm.theme = UserService.Instance.user.theme this.state.userSettingsForm.theme = UserService.Instance.user.theme
? UserService.Instance.user.theme ? UserService.Instance.user.theme
: 'browser'; : "browser";
this.state.userSettingsForm.default_sort_type = this.state.userSettingsForm.default_sort_type =
UserService.Instance.user.default_sort_type; UserService.Instance.user.default_sort_type;
this.state.userSettingsForm.default_listing_type = this.state.userSettingsForm.default_listing_type =
@ -1095,9 +1095,9 @@ export class User extends Component<any, UserState> {
parseMessage(msg: any) { parseMessage(msg: any) {
let op = wsUserOp(msg); let op = wsUserOp(msg);
if (msg.error) { if (msg.error) {
toast(i18n.t(msg.error), 'danger'); toast(i18n.t(msg.error), "danger");
if (msg.error == 'couldnt_find_that_username_or_email') { if (msg.error == "couldnt_find_that_username_or_email") {
this.context.router.history.push('/'); this.context.router.history.push("/");
} }
this.setState({ this.setState({
deleteAccountLoading: false, deleteAccountLoading: false,
@ -1132,7 +1132,7 @@ export class User extends Component<any, UserState> {
deleteAccountLoading: false, deleteAccountLoading: false,
deleteAccountShowConfirm: false, deleteAccountShowConfirm: false,
}); });
this.context.router.history.push('/'); this.context.router.history.push("/");
} else if (op == UserOperation.AddAdmin) { } else if (op == UserOperation.AddAdmin) {
let data = wsJsonToRes<AddAdminResponse>(msg).data; let data = wsJsonToRes<AddAdminResponse>(msg).data;
this.state.siteRes.admins = data.admins; this.state.siteRes.admins = data.admins;
@ -1155,7 +1155,7 @@ export class User extends Component<any, UserState> {
UserService.Instance.user && UserService.Instance.user &&
data.comment_view.creator.id == UserService.Instance.user.id data.comment_view.creator.id == UserService.Instance.user.id
) { ) {
toast(i18n.t('reply_sent')); toast(i18n.t("reply_sent"));
} }
} else if (op == UserOperation.SaveComment) { } else if (op == UserOperation.SaveComment) {
let data = wsJsonToRes<CommentResponse>(msg).data; let data = wsJsonToRes<CommentResponse>(msg).data;

View file

@ -1,6 +1,6 @@
import { isBrowser } from './utils'; import { isBrowser } from "./utils";
const testHost = 'localhost:8536'; const testHost = "localhost:8536";
let internalHost = let internalHost =
(!isBrowser() && process.env.LEMMY_INTERNAL_HOST) || testHost; // used for local dev (!isBrowser() && process.env.LEMMY_INTERNAL_HOST) || testHost; // used for local dev
@ -12,25 +12,25 @@ let secure: string;
if (isBrowser()) { if (isBrowser()) {
// browser // browser
const lemmyConfig = const lemmyConfig =
typeof window.lemmyConfig !== 'undefined' ? window.lemmyConfig : {}; typeof window.lemmyConfig !== "undefined" ? window.lemmyConfig : {};
externalHost = `${window.location.hostname}${ externalHost = `${window.location.hostname}${
['1234', '1235'].includes(window.location.port) ["1234", "1235"].includes(window.location.port)
? ':8536' ? ":8536"
: window.location.port == '' : window.location.port == ""
? '' ? ""
: `:${window.location.port}` : `:${window.location.port}`
}`; }`;
host = externalHost; host = externalHost;
wsHost = lemmyConfig.wsHost || host; wsHost = lemmyConfig.wsHost || host;
secure = window.location.protocol == 'https:' ? 's' : ''; secure = window.location.protocol == "https:" ? "s" : "";
} else { } else {
// server-side // server-side
externalHost = process.env.LEMMY_EXTERNAL_HOST || testHost; externalHost = process.env.LEMMY_EXTERNAL_HOST || testHost;
host = internalHost; host = internalHost;
wsHost = process.env.LEMMY_WS_HOST || host; wsHost = process.env.LEMMY_WS_HOST || host;
secure = process.env.LEMMY_HTTPS == 'true' ? 's' : ''; secure = process.env.LEMMY_HTTPS == "true" ? "s" : "";
} }
const httpBase = `http://${host}`; // Don't use secure here const httpBase = `http://${host}`; // Don't use secure here
@ -42,7 +42,7 @@ console.log(`httpbase: ${httpBase}`);
console.log(`wsUri: ${wsUri}`); console.log(`wsUri: ${wsUri}`);
// This is for html tags, don't include port // This is for html tags, don't include port
const httpExternalUri = `http${secure}://${externalHost.split(':')[0]}`; const httpExternalUri = `http${secure}://${externalHost.split(":")[0]}`;
export function httpExternalPath(path: string) { export function httpExternalPath(path: string) {
return `${httpExternalUri}${path}`; return `${httpExternalUri}${path}`;
} }

View file

@ -1,36 +1,36 @@
import i18next from 'i18next'; import i18next from "i18next";
import { getLanguage } from './utils'; import { getLanguage } from "./utils";
import { en } from './translations/en'; import { en } from "./translations/en";
import { el } from './translations/el'; import { el } from "./translations/el";
import { eu } from './translations/eu'; import { eu } from "./translations/eu";
import { eo } from './translations/eo'; import { eo } from "./translations/eo";
import { es } from './translations/es'; import { es } from "./translations/es";
import { de } from './translations/de'; import { de } from "./translations/de";
import { fr } from './translations/fr'; import { fr } from "./translations/fr";
import { sv } from './translations/sv'; import { sv } from "./translations/sv";
import { ru } from './translations/ru'; import { ru } from "./translations/ru";
import { zh } from './translations/zh'; import { zh } from "./translations/zh";
import { nl } from './translations/nl'; import { nl } from "./translations/nl";
import { it } from './translations/it'; import { it } from "./translations/it";
import { fi } from './translations/fi'; import { fi } from "./translations/fi";
import { ca } from './translations/ca'; import { ca } from "./translations/ca";
import { fa } from './translations/fa'; import { fa } from "./translations/fa";
import { hi } from './translations/hi'; import { hi } from "./translations/hi";
import { pl } from './translations/pl'; import { pl } from "./translations/pl";
import { pt_BR } from './translations/pt_BR'; import { pt_BR } from "./translations/pt_BR";
import { ja } from './translations/ja'; import { ja } from "./translations/ja";
import { ka } from './translations/ka'; import { ka } from "./translations/ka";
import { gl } from './translations/gl'; import { gl } from "./translations/gl";
import { tr } from './translations/tr'; import { tr } from "./translations/tr";
import { hu } from './translations/hu'; import { hu } from "./translations/hu";
import { uk } from './translations/uk'; import { uk } from "./translations/uk";
import { sq } from './translations/sq'; import { sq } from "./translations/sq";
import { km } from './translations/km'; import { km } from "./translations/km";
import { ga } from './translations/ga'; import { ga } from "./translations/ga";
import { sr_Latn } from './translations/sr_Latn'; import { sr_Latn } from "./translations/sr_Latn";
import { da } from './translations/da'; import { da } from "./translations/da";
import { oc } from './translations/oc'; import { oc } from "./translations/oc";
import { hr } from './translations/hr'; import { hr } from "./translations/hr";
// https://github.com/nimbusec-oss/inferno-i18next/blob/master/tests/T.test.js#L66 // https://github.com/nimbusec-oss/inferno-i18next/blob/master/tests/T.test.js#L66
const resources = { const resources = {
@ -68,7 +68,7 @@ const resources = {
}; };
function format(value: any, format: any): any { function format(value: any, format: any): any {
return format === 'uppercase' ? value.toUpperCase() : value; return format === "uppercase" ? value.toUpperCase() : value;
} }
i18next.init({ i18next.init({
@ -77,7 +77,7 @@ i18next.init({
// initImmediate: false, // initImmediate: false,
lng: getLanguage(), lng: getLanguage(),
fallbackLng: 'en', fallbackLng: "en",
resources, resources,
interpolation: { format }, interpolation: { format },
}); });

View file

@ -1,7 +1,7 @@
import { GetSiteResponse } from 'lemmy-js-client'; import { GetSiteResponse } from "lemmy-js-client";
import { UserService } from './services'; import { UserService } from "./services";
import { i18n } from './i18next'; import { i18n } from "./i18next";
import { getLanguage } from './utils'; import { getLanguage } from "./utils";
export function initializeSite(site: GetSiteResponse) { export function initializeSite(site: GetSiteResponse) {
UserService.Instance.user = site.my_user; UserService.Instance.user = site.my_user;

View file

@ -3,7 +3,7 @@ import {
GetSiteResponse, GetSiteResponse,
LemmyHttp, LemmyHttp,
UserMentionView, UserMentionView,
} from 'lemmy-js-client'; } from "lemmy-js-client";
export interface IsoData { export interface IsoData {
path: string; path: string;

View file

@ -1,21 +1,21 @@
import { IRouteProps } from 'inferno-router/dist/Route'; import { IRouteProps } from "inferno-router/dist/Route";
import { Main } from './components/main'; import { Main } from "./components/main";
import { Login } from './components/login'; import { Login } from "./components/login";
import { CreatePost } from './components/create-post'; import { CreatePost } from "./components/create-post";
import { CreateCommunity } from './components/create-community'; import { CreateCommunity } from "./components/create-community";
import { CreatePrivateMessage } from './components/create-private-message'; import { CreatePrivateMessage } from "./components/create-private-message";
import { PasswordChange } from './components/password_change'; import { PasswordChange } from "./components/password_change";
import { Post } from './components/post'; import { Post } from "./components/post";
import { Community } from './components/community'; import { Community } from "./components/community";
import { Communities } from './components/communities'; import { Communities } from "./components/communities";
import { User } from './components/user'; import { User } from "./components/user";
import { Modlog } from './components/modlog'; import { Modlog } from "./components/modlog";
import { Setup } from './components/setup'; import { Setup } from "./components/setup";
import { AdminSettings } from './components/admin-settings'; import { AdminSettings } from "./components/admin-settings";
import { Inbox } from './components/inbox'; import { Inbox } from "./components/inbox";
import { Search } from './components/search'; import { Search } from "./components/search";
import { Instances } from './components/instances'; import { Instances } from "./components/instances";
import { InitialFetchRequest } from './interfaces'; import { InitialFetchRequest } from "./interfaces";
interface IRoutePropsWithFetch extends IRouteProps { interface IRoutePropsWithFetch extends IRouteProps {
fetchInitialData?(req: InitialFetchRequest): Promise<any>[]; fetchInitialData?(req: InitialFetchRequest): Promise<any>[];

View file

@ -1,8 +1,8 @@
// import Cookies from 'js-cookie'; // import Cookies from 'js-cookie';
import IsomorphicCookie from 'isomorphic-cookie'; import IsomorphicCookie from "isomorphic-cookie";
import { UserSafeSettings, LoginResponse } from 'lemmy-js-client'; import { UserSafeSettings, LoginResponse } from "lemmy-js-client";
import jwt_decode from 'jwt-decode'; import jwt_decode from "jwt-decode";
import { Subject, BehaviorSubject } from 'rxjs'; import { Subject, BehaviorSubject } from "rxjs";
interface Claims { interface Claims {
id: number; id: number;
@ -23,29 +23,29 @@ export class UserService {
this.setClaims(this.auth); this.setClaims(this.auth);
} else { } else {
// setTheme(); // setTheme();
console.log('No JWT cookie found.'); console.log("No JWT cookie found.");
} }
} }
public login(res: LoginResponse) { public login(res: LoginResponse) {
let expires = new Date(); let expires = new Date();
expires.setDate(expires.getDate() + 365); expires.setDate(expires.getDate() + 365);
IsomorphicCookie.save('jwt', res.jwt, { expires, secure: false }); IsomorphicCookie.save("jwt", res.jwt, { expires, secure: false });
console.log('jwt cookie set'); console.log("jwt cookie set");
this.setClaims(res.jwt); this.setClaims(res.jwt);
} }
public logout() { public logout() {
IsomorphicCookie.remove('jwt', { secure: false }); IsomorphicCookie.remove("jwt", { secure: false });
this.claims = undefined; this.claims = undefined;
this.user = undefined; this.user = undefined;
// setTheme(); // setTheme();
this.jwtSub.next(); this.jwtSub.next();
console.log('Logged out.'); console.log("Logged out.");
} }
public get auth(): string { public get auth(): string {
return IsomorphicCookie.load('jwt'); return IsomorphicCookie.load("jwt");
} }
private setClaims(jwt: string) { private setClaims(jwt: string) {

View file

@ -1,12 +1,12 @@
import { wsUri } from '../env'; import { wsUri } from "../env";
import { UserViewSafe, WebSocketJsonResponse } from 'lemmy-js-client'; import { UserViewSafe, WebSocketJsonResponse } from "lemmy-js-client";
import { isBrowser } from '../utils'; import { isBrowser } from "../utils";
import { Observable } from 'rxjs'; import { Observable } from "rxjs";
import { share } from 'rxjs/operators'; import { share } from "rxjs/operators";
import { import {
Options as WSOptions, Options as WSOptions,
default as ReconnectingWebSocket, default as ReconnectingWebSocket,
} from 'reconnecting-websocket'; } from "reconnecting-websocket";
export class WebSocketService { export class WebSocketService {
private static _instance: WebSocketService; private static _instance: WebSocketService;

View file

@ -1,2 +1,2 @@
export { UserService } from './UserService'; export { UserService } from "./UserService";
export { WebSocketService } from './WebSocketService'; export { WebSocketService } from "./WebSocketService";