Merge remote-tracking branch 'upstream/main' into main

This commit is contained in:
Ivo Barros 2023-06-22 02:17:22 +01:00
commit 0beb2a4341
165 changed files with 1890 additions and 1689 deletions

View file

@ -1,6 +1,6 @@
{
"name": "lemmy-ui",
"version": "0.18.0-rc.4",
"version": "0.18.0-rc.5",
"description": "An isomorphic UI for lemmy",
"repository": "https://github.com/LemmyNet/lemmy-ui",
"license": "AGPL-3.0",
@ -22,9 +22,16 @@
"translations:update": "git submodule update --remote --recursive"
},
"lint-staged": {
"*.{ts,tsx,js}": ["prettier --write", "eslint --fix"],
"*.{css, scss}": ["prettier --write"],
"package.json": ["sortpack"]
"*.{ts,tsx,js}": [
"prettier --write",
"eslint --fix"
],
"*.{css, scss}": [
"prettier --write"
],
"package.json": [
"sortpack"
]
},
"dependencies": {
"@babel/plugin-proposal-decorators": "^7.21.0",

View file

@ -1,8 +1,8 @@
import { initializeSite } from "@utils/app";
import { hydrate } from "inferno-hydrate";
import { Router } from "inferno-router";
import { App } from "../shared/components/app/app";
import { HistoryService } from "../shared/services/HistoryService";
import { initializeSite } from "../shared/utils";
import "bootstrap/js/dist/collapse";
import "bootstrap/js/dist/dropdown";

View file

@ -1,3 +1,5 @@
import { initializeSite, isAuthPath } from "@utils/app";
import { ErrorPageData } from "@utils/types";
import type { Request, Response } from "express";
import { StaticRouter, matchPath } from "inferno-router";
import { renderToString } from "inferno-server";
@ -15,7 +17,6 @@ import {
FailedRequestState,
wrapClient,
} from "../../shared/services/HttpService";
import { ErrorPageData, initializeSite, isAuthPath } from "../../shared/utils";
import { createSsrHtml } from "../utils/create-ssr-html";
import { getErrorPageData } from "../utils/get-error-page-data";
import { setForwardedHeaders } from "../utils/set-forwarded-headers";

View file

@ -25,7 +25,7 @@ if (!process.env["LEMMY_UI_DISABLE_CSP"] && !process.env["LEMMY_UI_DEBUG"]) {
server.get("/robots.txt", RobotsHandler);
server.get("/service-worker.js", ServiceWorkerHandler);
server.get("/manifest", ManifestHandler);
server.get("/manifest.webmanifest", ManifestHandler);
server.get("/css/themes/:name", ThemeHandler);
server.get("/css/themelist", ThemesListHandler);
server.get("/*", CatchAllHandler);

View file

@ -2,8 +2,8 @@ import { Helmet } from "inferno-helmet";
import { renderToString } from "inferno-server";
import serialize from "serialize-javascript";
import sharp from "sharp";
import { favIconPngUrl, favIconUrl } from "../../shared/config";
import { ILemmyConfig, IsoDataOptionalSite } from "../../shared/interfaces";
import { favIconPngUrl, favIconUrl } from "../../shared/utils";
import { fetchIconPng } from "./fetch-icon-png";
const customHtmlHeader = process.env["LEMMY_UI_CUSTOM_HTML_HEADER"] || "";
@ -77,7 +77,7 @@ export async function createSsrHtml(
/>
<!-- Web app manifest -->
<link rel="manifest" href="/manifest" />
<link rel="manifest" href="/manifest.webmanifest" />
<link rel="apple-touch-icon" href=${appleTouchIcon} />
<link rel="apple-touch-startup-image" href=${appleTouchIcon} />

View file

@ -1,5 +1,5 @@
import { ErrorPageData } from "@utils/types";
import { GetSiteResponse } from "lemmy-js-client";
import { ErrorPageData } from "../../shared/utils";
export function getErrorPageData(error: Error, site?: GetSiteResponse) {
const errorPageData: ErrorPageData = {};

View file

@ -1,10 +1,10 @@
import { Component, createRef, linkEvent, RefObject } from "inferno";
import { isAuthPath, setIsoData } from "@utils/app";
import { Component, RefObject, createRef, linkEvent } from "inferno";
import { Provider } from "inferno-i18next-dess";
import { Route, Switch } from "inferno-router";
import { i18n } from "../../i18next";
import { IsoDataOptionalSite } from "../../interfaces";
import { routes } from "../../routes";
import { isAuthPath, setIsoData } from "../../utils";
import AuthGuard from "../common/auth-guard";
import ErrorGuard from "../common/error-guard";
import { ErrorPage } from "./error-page";

View file

@ -1,9 +1,9 @@
import { setIsoData } from "@utils/app";
import { Component } from "inferno";
import { T } from "inferno-i18next-dess";
import { Link } from "inferno-router";
import { i18n } from "../../i18next";
import { IsoDataOptionalSite } from "../../interfaces";
import { setIsoData } from "../../utils";
export class ErrorPage extends Component<any, any> {
private isoData: IsoDataOptionalSite = setIsoData(this.context);

View file

@ -1,8 +1,8 @@
import { Component } from "inferno";
import { NavLink } from "inferno-router";
import { GetSiteResponse } from "lemmy-js-client";
import { docsUrl, joinLemmyUrl, repoUrl } from "../../config";
import { i18n } from "../../i18next";
import { docsUrl, joinLemmyUrl, repoUrl } from "../../utils";
import { VERSION } from "../../version";
interface FooterProps {

View file

@ -1,5 +1,6 @@
import { myAuth, showAvatars } from "@utils/app";
import { isBrowser } from "@utils/browser";
import { poll } from "@utils/helpers";
import { numToSI, poll } from "@utils/helpers";
import { amAdmin, canCreateCommunity } from "@utils/roles";
import { Component, createRef, linkEvent } from "inferno";
import { NavLink } from "inferno-router";
@ -9,17 +10,11 @@ import {
GetUnreadCountResponse,
GetUnreadRegistrationApplicationCountResponse,
} from "lemmy-js-client";
import { donateLemmyUrl, updateUnreadCountsInterval } from "../../config";
import { i18n } from "../../i18next";
import { UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import {
donateLemmyUrl,
myAuth,
numToSI,
showAvatars,
toast,
updateUnreadCountsInterval,
} from "../../utils";
import { toast } from "../../toast";
import { Icon } from "../common/icon";
import { PictrsImage } from "../common/pictrs-image";

View file

@ -1,3 +1,5 @@
import { myAuthRequired } from "@utils/app";
import { capitalizeFirstLetter } from "@utils/helpers";
import { Component } from "inferno";
import { T } from "inferno-i18next-dess";
import { Link } from "inferno-router";
@ -5,7 +7,6 @@ import { CreateComment, EditComment, Language } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { CommentNodeI } from "../../interfaces";
import { UserService } from "../../services";
import { capitalizeFirstLetter, myAuthRequired } from "../../utils";
import { Icon } from "../common/icon";
import { MarkdownTextArea } from "../common/markdown-textarea";

View file

@ -1,3 +1,12 @@
import {
colorList,
getCommentParentId,
myAuth,
myAuthRequired,
newVote,
showScores,
} from "@utils/app";
import { futureDaysToUnixTime, numToSI } from "@utils/helpers";
import {
amCommunityCreator,
canAdmin,
@ -38,6 +47,7 @@ import {
TransferCommunity,
} from "lemmy-js-client";
import moment from "moment";
import { commentTreeMaxDepth } from "../../config";
import { i18n } from "../../i18next";
import {
BanType,
@ -46,21 +56,9 @@ import {
PurgeType,
VoteType,
} from "../../interfaces";
import { mdToHtml, mdToHtmlNoImages } from "../../markdown";
import { UserService } from "../../services";
import {
colorList,
commentTreeMaxDepth,
futureDaysToUnixTime,
getCommentParentId,
mdToHtml,
mdToHtmlNoImages,
myAuth,
myAuthRequired,
newVote,
numToSI,
setupTippy,
showScores,
} from "../../utils";
import { setupTippy } from "../../tippy";
import { Icon, PurgeWarning, Spinner } from "../common/icon";
import { MomentTime } from "../common/moment-time";
import { CommunityLink } from "../community/community-link";

View file

@ -1,3 +1,4 @@
import { colorList } from "@utils/app";
import classNames from "classnames";
import { Component } from "inferno";
import {
@ -26,7 +27,6 @@ import {
TransferCommunity,
} from "lemmy-js-client";
import { CommentNodeI, CommentViewType } from "../../interfaces";
import { colorList } from "../../utils";
import { CommentNode } from "./comment-node";
interface CommentNodesProps {

View file

@ -1,3 +1,4 @@
import { myAuthRequired } from "@utils/app";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import {
@ -7,7 +8,6 @@ import {
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { CommentNodeI, CommentViewType } from "../../interfaces";
import { myAuthRequired } from "../../utils";
import { Icon, Spinner } from "../common/icon";
import { PersonListing } from "../person/person-listing";
import { CommentNode } from "./comment-node";

View file

@ -1,3 +1,4 @@
import { numToSI } from "@utils/helpers";
import { Link } from "inferno-router";
import {
CommunityAggregates,
@ -5,7 +6,6 @@ import {
SiteAggregates,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { numToSI } from "../../utils";
interface BadgesProps {
counts: CommunityAggregates | SiteAggregates;

View file

@ -1,7 +1,8 @@
import { randomStr } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { CommentSortType } from "lemmy-js-client";
import { relTags, sortingHelpUrl } from "../../config";
import { i18n } from "../../i18next";
import { randomStr, relTags, sortingHelpUrl } from "../../utils";
import { Icon } from "./icon";
interface CommentSortSelectProps {

View file

@ -1,5 +1,5 @@
import { Component } from "inferno";
import { getEmojiMart } from "../../utils";
import { getEmojiMart } from "../../markdown";
interface EmojiMartProps {
onEmojiClick?(val: any): any;

View file

@ -38,7 +38,8 @@ export class EmojiPicker extends Component<EmojiPickerProps, EmojiPickerState> {
{this.state.showPicker && (
<>
<div className="emoji-picker-container">
<div className="position-relative">
<div className="emoji-picker-container position-absolute w-100">
<EmojiMart
onEmojiClick={this.handleEmojiClick}
pickerOptions={{}}
@ -48,6 +49,7 @@ export class EmojiPicker extends Component<EmojiPickerProps, EmojiPickerState> {
onClick={linkEvent(this, this.togglePicker)}
className="click-away-container"
/>
</div>
</>
)}
</span>

View file

@ -1,5 +1,5 @@
import { setIsoData } from "@utils/app";
import { Component } from "inferno";
import { setIsoData } from "../../utils";
import { ErrorPage } from "../app/error-page";
class ErrorGuard extends Component<any, any> {

View file

@ -3,7 +3,7 @@ import { Component } from "inferno";
import { Helmet } from "inferno-helmet";
import { httpExternalPath } from "../../env";
import { i18n } from "../../i18next";
import { md } from "../../utils";
import { md } from "../../markdown";
interface HtmlTagsProps {
title: string;

View file

@ -1,7 +1,8 @@
import { randomStr } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { i18n } from "../../i18next";
import { HttpService, UserService } from "../../services";
import { randomStr, toast } from "../../utils";
import { toast } from "../../toast";
import { Icon } from "./icon";
interface ImageUploadFormProps {

View file

@ -1,9 +1,10 @@
import { selectableLanguages } from "@utils/app";
import { randomStr } from "@utils/helpers";
import classNames from "classnames";
import { Component, linkEvent } from "inferno";
import { Language } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { UserService } from "../../services/UserService";
import { randomStr, selectableLanguages } from "../../utils";
import { Icon } from "./icon";
interface LanguageSelectProps {

View file

@ -1,8 +1,8 @@
import { randomStr } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { ListingType } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { UserService } from "../../services";
import { randomStr } from "../../utils";
interface ListingTypeSelectProps {
type_: ListingType;

View file

@ -1,26 +1,22 @@
import { isBrowser } from "@utils/browser";
import { numToSI, randomStr } from "@utils/helpers";
import autosize from "autosize";
import classNames from "classnames";
import { NoOptionI18nKeys } from "i18next";
import { Component, linkEvent } from "inferno";
import { Language } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { HttpService, UserService } from "../../services";
import {
concurrentImageUpload,
customEmojisLookup,
markdownFieldCharacterLimit,
markdownHelpUrl,
maxUploadImages,
mdToHtml,
numToSI,
pictrsDeleteToast,
randomStr,
relTags,
setupTippy,
setupTribute,
toast,
} from "../../utils";
} from "../../config";
import { i18n } from "../../i18next";
import { customEmojisLookup, mdToHtml, setupTribute } from "../../markdown";
import { HttpService, UserService } from "../../services";
import { setupTippy } from "../../tippy";
import { pictrsDeleteToast, toast } from "../../toast";
import { EmojiPicker } from "./emoji-picker";
import { Icon, Spinner } from "./icon";
import { LanguageSelect } from "./language-select";

View file

@ -1,7 +1,7 @@
import { capitalizeFirstLetter } from "@utils/helpers";
import { Component } from "inferno";
import moment from "moment";
import { i18n } from "../../i18next";
import { capitalizeFirstLetter } from "../../utils";
import { Icon } from "./icon";
interface MomentTimeProps {

View file

@ -1,5 +1,5 @@
import { ThemeColor } from "@utils/types";
import classNames from "classnames";
import { ThemeColor } from "../../utils";
interface ProgressBarProps {
className?: string;

View file

@ -1,3 +1,4 @@
import { myAuthRequired } from "@utils/app";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import {
@ -5,7 +6,7 @@ import {
RegistrationApplicationView,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml, myAuthRequired } from "../../utils";
import { mdToHtml } from "../../markdown";
import { PersonListing } from "../person/person-listing";
import { Spinner } from "./icon";
import { MarkdownTextArea } from "./markdown-textarea";

View file

@ -1,3 +1,4 @@
import { Choice } from "@utils/types";
import classNames from "classnames";
import {
ChangeEvent,
@ -7,7 +8,6 @@ import {
RefObject,
} from "inferno";
import { i18n } from "../../i18next";
import { Choice } from "../../utils";
import { Icon, Spinner } from "./icon";
interface SearchableSelectProps {

View file

@ -1,7 +1,8 @@
import { randomStr } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { SortType } from "lemmy-js-client";
import { relTags, sortingHelpUrl } from "../../config";
import { i18n } from "../../i18next";
import { randomStr, relTags, sortingHelpUrl } from "../../utils";
import { Icon } from "./icon";
interface SortSelectProps {

View file

@ -1,5 +1,18 @@
import { getQueryParams, getQueryString } from "@utils/helpers";
import {
editCommunity,
myAuth,
myAuthRequired,
setIsoData,
showLocal,
} from "@utils/app";
import {
getPageFromString,
getQueryParams,
getQueryString,
numToSI,
} from "@utils/helpers";
import type { QueryParams } from "@utils/types";
import { RouteDataResponse } from "@utils/types";
import { Component, linkEvent } from "inferno";
import {
CommunityResponse,
@ -12,16 +25,6 @@ import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { FirstLoadService } from "../../services/FirstLoadService";
import { HttpService, RequestState } from "../../services/HttpService";
import {
RouteDataResponse,
editCommunity,
getPageFromString,
myAuth,
myAuthRequired,
numToSI,
setIsoData,
showLocal,
} from "../../utils";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";
import { ListingTypeSelect } from "../common/listing-type-select";

View file

@ -1,3 +1,5 @@
import { myAuthRequired } from "@utils/app";
import { capitalizeFirstLetter, randomStr } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import {
CommunityView,
@ -6,7 +8,6 @@ import {
Language,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { capitalizeFirstLetter, myAuthRequired, randomStr } from "../../utils";
import { Icon, Spinner } from "../common/icon";
import { ImageUploadForm } from "../common/image-upload-form";
import { LanguageSelect } from "../common/language-select";

View file

@ -1,7 +1,9 @@
import { showAvatars } from "@utils/app";
import { hostname } from "@utils/helpers";
import { Component } from "inferno";
import { Link } from "inferno-router";
import { Community } from "lemmy-js-client";
import { hostname, relTags, showAvatars } from "../../utils";
import { relTags } from "../../config";
import { PictrsImage } from "../common/pictrs-image";
interface CommunityLinkProps {

View file

@ -1,5 +1,28 @@
import { getQueryParams, getQueryString } from "@utils/helpers";
import {
commentsToFlatNodes,
communityRSSUrl,
editComment,
editPost,
editWith,
enableDownvotes,
enableNsfw,
getCommentParentId,
getDataTypeString,
myAuth,
postToCommentSortType,
setIsoData,
showLocal,
updateCommunityBlock,
updatePersonBlock,
} from "@utils/app";
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
import {
getPageFromString,
getQueryParams,
getQueryString,
} from "@utils/helpers";
import type { QueryParams } from "@utils/types";
import { RouteDataResponse } from "@utils/types";
import { Component, linkEvent } from "inferno";
import { RouteComponentProps } from "inferno-router/dist/Route";
import {
@ -54,6 +77,7 @@ import {
SortType,
TransferCommunity,
} from "lemmy-js-client";
import { fetchLimit, relTags } from "../../config";
import { i18n } from "../../i18next";
import {
CommentViewType,
@ -63,31 +87,8 @@ import {
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { HttpService, RequestState } from "../../services/HttpService";
import {
RouteDataResponse,
commentsToFlatNodes,
communityRSSUrl,
editComment,
editPost,
editWith,
enableDownvotes,
enableNsfw,
fetchLimit,
getCommentParentId,
getDataTypeString,
getPageFromString,
myAuth,
postToCommentSortType,
relTags,
restoreScrollPosition,
saveScrollPosition,
setIsoData,
setupTippy,
showLocal,
toast,
updateCommunityBlock,
updatePersonBlock,
} from "../../utils";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
import { CommentNodes } from "../comment/comment-nodes";
import { BannerIconHeader } from "../common/banner-icon-header";
import { DataTypeSelect } from "../common/data-type-select";

View file

@ -1,3 +1,4 @@
import { enableNsfw, setIsoData } from "@utils/app";
import { Component } from "inferno";
import {
CreateCommunity as CreateCommunityI,
@ -5,7 +6,6 @@ import {
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { HttpService } from "../../services/HttpService";
import { enableNsfw, setIsoData } from "../../utils";
import { HtmlTags } from "../common/html-tags";
import { CommunityForm } from "./community-form";

View file

@ -1,3 +1,5 @@
import { myAuthRequired } from "@utils/app";
import { getUnixTime, hostname } from "@utils/helpers";
import { amAdmin, amMod, amTopMod } from "@utils/roles";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
@ -16,8 +18,8 @@ import {
RemoveCommunity,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml } from "../../markdown";
import { UserService } from "../../services";
import { getUnixTime, hostname, mdToHtml, myAuthRequired } from "../../utils";
import { Badges } from "../common/badges";
import { BannerIconHeader } from "../common/banner-icon-header";
import { Icon, PurgeWarning, Spinner } from "../common/icon";

View file

@ -1,3 +1,11 @@
import {
fetchThemeList,
myAuthRequired,
setIsoData,
showLocal,
} from "@utils/app";
import { capitalizeFirstLetter } from "@utils/helpers";
import { RouteDataResponse } from "@utils/types";
import classNames from "classnames";
import { Component, linkEvent } from "inferno";
import {
@ -12,19 +20,10 @@ import {
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { removeFromEmojiDataModel, updateEmojiDataModel } from "../../markdown";
import { FirstLoadService } from "../../services/FirstLoadService";
import { HttpService, RequestState } from "../../services/HttpService";
import {
RouteDataResponse,
capitalizeFirstLetter,
fetchThemeList,
myAuthRequired,
removeFromEmojiDataModel,
setIsoData,
showLocal,
toast,
updateEmojiDataModel,
} from "../../utils";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";
import Tabs from "../common/tabs";

View file

@ -1,3 +1,4 @@
import { myAuthRequired, setIsoData } from "@utils/app";
import { Component, linkEvent } from "inferno";
import {
CreateCustomEmoji,
@ -6,14 +7,9 @@ import {
GetSiteResponse,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { customEmojisLookup } from "../../markdown";
import { HttpService } from "../../services/HttpService";
import {
customEmojisLookup,
myAuthRequired,
pictrsDeleteToast,
setIsoData,
toast,
} from "../../utils";
import { pictrsDeleteToast, toast } from "../../toast";
import { EmojiMart } from "../common/emoji-mart";
import { HtmlTags } from "../common/html-tags";
import { Icon } from "../common/icon";

View file

@ -1,6 +1,28 @@
import { getQueryParams, getQueryString } from "@utils/helpers";
import {
commentsToFlatNodes,
editComment,
editPost,
editWith,
enableDownvotes,
enableNsfw,
getCommentParentId,
getDataTypeString,
myAuth,
postToCommentSortType,
setIsoData,
showLocal,
updatePersonBlock,
} from "@utils/app";
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
import {
getPageFromString,
getQueryParams,
getQueryString,
getRandomFromList,
} from "@utils/helpers";
import { canCreateCommunity } from "@utils/roles";
import type { QueryParams } from "@utils/types";
import { RouteDataResponse } from "@utils/types";
import { NoOptionI18nKeys } from "i18next";
import { Component, MouseEventHandler, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
@ -50,41 +72,19 @@ import {
SortType,
TransferCommunity,
} from "lemmy-js-client";
import { fetchLimit, relTags, trendingFetchLimit } from "../../config";
import { i18n } from "../../i18next";
import {
CommentViewType,
DataType,
InitialFetchRequest,
} from "../../interfaces";
import { mdToHtml } from "../../markdown";
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { HttpService, RequestState } from "../../services/HttpService";
import {
RouteDataResponse,
commentsToFlatNodes,
editComment,
editPost,
editWith,
enableDownvotes,
enableNsfw,
fetchLimit,
getCommentParentId,
getDataTypeString,
getPageFromString,
getRandomFromList,
mdToHtml,
myAuth,
postToCommentSortType,
relTags,
restoreScrollPosition,
saveScrollPosition,
setIsoData,
setupTippy,
showLocal,
toast,
trendingFetchLimit,
updatePersonBlock,
} from "../../utils";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
import { CommentNodes } from "../comment/comment-nodes";
import { DataTypeSelect } from "../common/data-type-select";
import { HtmlTags } from "../common/html-tags";

View file

@ -1,14 +1,16 @@
import { setIsoData } from "@utils/app";
import { RouteDataResponse } from "@utils/types";
import { Component } from "inferno";
import {
GetFederatedInstancesResponse,
GetSiteResponse,
Instance,
} from "lemmy-js-client";
import { relTags } from "../../config";
import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { FirstLoadService } from "../../services/FirstLoadService";
import { HttpService, RequestState } from "../../services/HttpService";
import { RouteDataResponse, relTags, setIsoData } from "../../utils";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";

View file

@ -1,7 +1,8 @@
import { setIsoData } from "@utils/app";
import { Component } from "inferno";
import { GetSiteResponse } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml, setIsoData } from "../../utils";
import { mdToHtml } from "../../markdown";
import { HtmlTags } from "../common/html-tags";
interface LegalState {

View file

@ -1,10 +1,12 @@
import { myAuth, setIsoData } from "@utils/app";
import { isBrowser } from "@utils/browser";
import { validEmail } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { GetSiteResponse, LoginResponse } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { myAuth, setIsoData, toast, validEmail } from "../../utils";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";

View file

@ -1,8 +1,9 @@
import { myAuthRequired } from "@utils/app";
import { capitalizeFirstLetter } from "@utils/helpers";
import classNames from "classnames";
import { Component, FormEventHandler, linkEvent } from "inferno";
import { EditSite, LocalSiteRateLimit } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { capitalizeFirstLetter, myAuthRequired } from "../../utils";
import { Spinner } from "../common/icon";
import Tabs from "../common/tabs";

View file

@ -1,3 +1,4 @@
import { fetchThemeList, setIsoData } from "@utils/app";
import { Component, linkEvent } from "inferno";
import { Helmet } from "inferno-helmet";
import {
@ -9,7 +10,6 @@ import {
import { i18n } from "../../i18next";
import { UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { fetchThemeList, setIsoData } from "../../utils";
import { Spinner } from "../common/icon";
import { SiteForm } from "./site-form";

View file

@ -1,4 +1,6 @@
import { myAuth, setIsoData } from "@utils/app";
import { isBrowser } from "@utils/browser";
import { validEmail } from "@utils/helpers";
import { Options, passwordStrength } from "check-password-strength";
import { NoOptionI18nKeys } from "i18next";
import { Component, linkEvent } from "inferno";
@ -10,17 +12,12 @@ import {
LoginResponse,
SiteView,
} from "lemmy-js-client";
import { joinLemmyUrl } from "../../config";
import { i18n } from "../../i18next";
import { mdToHtml } from "../../markdown";
import { UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import {
joinLemmyUrl,
mdToHtml,
myAuth,
setIsoData,
toast,
validEmail,
} from "../../utils";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
import { Icon, Spinner } from "../common/icon";
import { MarkdownTextArea } from "../common/markdown-textarea";

View file

@ -1,3 +1,5 @@
import { myAuthRequired } from "@utils/app";
import { capitalizeFirstLetter, validInstanceTLD } from "@utils/helpers";
import {
Component,
InfernoKeyboardEvent,
@ -12,11 +14,6 @@ import {
ListingType,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import {
capitalizeFirstLetter,
myAuthRequired,
validInstanceTLD,
} from "../../utils";
import { Icon, Spinner } from "../common/icon";
import { ImageUploadForm } from "../common/image-upload-form";
import { LanguageSelect } from "../common/language-select";

View file

@ -1,7 +1,7 @@
import { Component, linkEvent } from "inferno";
import { PersonView, Site, SiteAggregates } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml } from "../../utils";
import { mdToHtml } from "../../markdown";
import { Badges } from "../common/badges";
import { BannerIconHeader } from "../common/banner-icon-header";
import { Icon } from "../common/icon";

View file

@ -1,7 +1,8 @@
import { myAuthRequired } from "@utils/app";
import { capitalizeFirstLetter } from "@utils/helpers";
import { Component, InfernoMouseEvent, linkEvent } from "inferno";
import { EditSite, Tagline } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { capitalizeFirstLetter, myAuthRequired } from "../../utils";
import { HtmlTags } from "../common/html-tags";
import { Icon, Spinner } from "../common/icon";
import { MarkdownTextArea } from "../common/markdown-textarea";

View file

@ -1,6 +1,20 @@
import { debounce, getQueryParams, getQueryString } from "@utils/helpers";
import {
fetchUsers,
getUpdatedSearchId,
myAuth,
personToChoice,
setIsoData,
} from "@utils/app";
import {
debounce,
getIdFromString,
getPageFromString,
getQueryParams,
getQueryString,
} from "@utils/helpers";
import { amAdmin, amMod } from "@utils/roles";
import type { QueryParams } from "@utils/types";
import { Choice, RouteDataResponse } from "@utils/types";
import { NoOptionI18nKeys } from "i18next";
import { Component, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
@ -31,22 +45,11 @@ import {
Person,
} from "lemmy-js-client";
import moment from "moment";
import { fetchLimit } from "../config";
import { i18n } from "../i18next";
import { InitialFetchRequest } from "../interfaces";
import { FirstLoadService } from "../services/FirstLoadService";
import { HttpService, RequestState } from "../services/HttpService";
import {
Choice,
RouteDataResponse,
fetchLimit,
fetchUsers,
getIdFromString,
getPageFromString,
getUpdatedSearchId,
myAuth,
personToChoice,
setIsoData,
} from "../utils";
import { HtmlTags } from "./common/html-tags";
import { Icon, Spinner } from "./common/icon";
import { MomentTime } from "./common/moment-time";

View file

@ -1,3 +1,17 @@
import {
commentsToFlatNodes,
editCommentReply,
editMention,
editPrivateMessage,
editWith,
enableDownvotes,
getCommentParentId,
myAuth,
myAuthRequired,
setIsoData,
updatePersonBlock,
} from "@utils/app";
import { RouteDataResponse } from "@utils/types";
import { Component, linkEvent } from "inferno";
import {
AddAdmin,
@ -44,28 +58,13 @@ import {
SaveComment,
TransferCommunity,
} from "lemmy-js-client";
import { fetchLimit, relTags } from "../../config";
import { i18n } from "../../i18next";
import { CommentViewType, InitialFetchRequest } from "../../interfaces";
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { HttpService, RequestState } from "../../services/HttpService";
import {
RouteDataResponse,
commentsToFlatNodes,
editCommentReply,
editMention,
editPrivateMessage,
editWith,
enableDownvotes,
fetchLimit,
getCommentParentId,
myAuth,
myAuthRequired,
relTags,
setIsoData,
toast,
updatePersonBlock,
} from "../../utils";
import { toast } from "../../toast";
import { CommentNodes } from "../comment/comment-nodes";
import { CommentSortSelect } from "../common/comment-sort-select";
import { HtmlTags } from "../common/html-tags";

View file

@ -1,9 +1,10 @@
import { myAuth, setIsoData } from "@utils/app";
import { capitalizeFirstLetter } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { GetSiteResponse, LoginResponse } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { HttpService, UserService } from "../../services";
import { RequestState } from "../../services/HttpService";
import { capitalizeFirstLetter, myAuth, setIsoData } from "../../utils";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";

View file

@ -1,3 +1,4 @@
import { commentsToFlatNodes } from "@utils/app";
import { Component } from "inferno";
import {
AddAdmin,
@ -37,7 +38,7 @@ import {
TransferCommunity,
} from "lemmy-js-client";
import { CommentViewType, PersonDetailsView } from "../../interfaces";
import { commentsToFlatNodes, setupTippy } from "../../utils";
import { setupTippy } from "../../tippy";
import { CommentNodes } from "../comment/comment-nodes";
import { Paginator } from "../common/paginator";
import { PostListing } from "../post/post-listing";

View file

@ -1,8 +1,10 @@
import { showAvatars } from "@utils/app";
import { hostname, isCakeDay } from "@utils/helpers";
import classNames from "classnames";
import { Component } from "inferno";
import { Link } from "inferno-router";
import { Person } from "lemmy-js-client";
import { hostname, isCakeDay, relTags, showAvatars } from "../../utils";
import { relTags } from "../../config";
import { PictrsImage } from "../common/pictrs-image";
import { CakeDay } from "./cake-day";

View file

@ -1,6 +1,27 @@
import { getQueryParams, getQueryString } from "@utils/helpers";
import {
editComment,
editPost,
editWith,
enableDownvotes,
enableNsfw,
getCommentParentId,
myAuth,
myAuthRequired,
setIsoData,
updatePersonBlock,
} from "@utils/app";
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
import {
capitalizeFirstLetter,
futureDaysToUnixTime,
getPageFromString,
getQueryParams,
getQueryString,
numToSI,
} from "@utils/helpers";
import { canMod, isAdmin, isBanned } from "@utils/roles";
import type { QueryParams } from "@utils/types";
import { RouteDataResponse } from "@utils/types";
import classNames from "classnames";
import { NoOptionI18nKeys } from "i18next";
import { Component, linkEvent } from "inferno";
@ -50,35 +71,15 @@ import {
TransferCommunity,
} from "lemmy-js-client";
import moment from "moment";
import { fetchLimit, relTags } from "../../config";
import { i18n } from "../../i18next";
import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
import { mdToHtml } from "../../markdown";
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { HttpService, RequestState } from "../../services/HttpService";
import {
RouteDataResponse,
capitalizeFirstLetter,
editComment,
editPost,
editWith,
enableDownvotes,
enableNsfw,
fetchLimit,
futureDaysToUnixTime,
getCommentParentId,
getPageFromString,
mdToHtml,
myAuth,
myAuthRequired,
numToSI,
relTags,
restoreScrollPosition,
saveScrollPosition,
setIsoData,
setupTippy,
toast,
updatePersonBlock,
} from "../../utils";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
import { BannerIconHeader } from "../common/banner-icon-header";
import { HtmlTags } from "../common/html-tags";
import { Icon, Spinner } from "../common/icon";

View file

@ -1,3 +1,9 @@
import {
editRegistrationApplication,
myAuthRequired,
setIsoData,
} from "@utils/app";
import { RouteDataResponse } from "@utils/types";
import { Component, linkEvent } from "inferno";
import {
ApproveRegistrationApplication,
@ -5,19 +11,13 @@ import {
ListRegistrationApplicationsResponse,
RegistrationApplicationView,
} from "lemmy-js-client";
import { fetchLimit } from "../../config";
import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { HttpService, RequestState } from "../../services/HttpService";
import {
RouteDataResponse,
editRegistrationApplication,
fetchLimit,
myAuthRequired,
setIsoData,
setupTippy,
} from "../../utils";
import { setupTippy } from "../../tippy";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";
import { Paginator } from "../common/paginator";

View file

@ -1,4 +1,12 @@
import {
editCommentReport,
editPostReport,
editPrivateMessageReport,
myAuthRequired,
setIsoData,
} from "@utils/app";
import { amAdmin } from "@utils/roles";
import { RouteDataResponse } from "@utils/types";
import { Component, linkEvent } from "inferno";
import {
CommentReportResponse,
@ -18,20 +26,12 @@ import {
ResolvePostReport,
ResolvePrivateMessageReport,
} from "lemmy-js-client";
import { fetchLimit } from "../../config";
import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { HttpService, UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { RequestState } from "../../services/HttpService";
import {
RouteDataResponse,
editCommentReport,
editPostReport,
editPrivateMessageReport,
fetchLimit,
myAuthRequired,
setIsoData,
} from "../../utils";
import { CommentReport } from "../comment/comment-report";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";

View file

@ -1,4 +1,19 @@
import { debounce } from "@utils/helpers";
import {
communityToChoice,
fetchCommunities,
fetchThemeList,
fetchUsers,
myAuth,
myAuthRequired,
personToChoice,
setIsoData,
setTheme,
showLocal,
updateCommunityBlock,
updatePersonBlock,
} from "@utils/app";
import { capitalizeFirstLetter, debounce } from "@utils/helpers";
import { Choice } from "@utils/types";
import classNames from "classnames";
import { NoOptionI18nKeys } from "i18next";
import { Component, linkEvent } from "inferno";
@ -13,30 +28,12 @@ import {
PersonBlockView,
SortType,
} from "lemmy-js-client";
import { elementUrl, emDash, relTags } from "../../config";
import { i18n, languages } from "../../i18next";
import { UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import {
Choice,
capitalizeFirstLetter,
communityToChoice,
elementUrl,
emDash,
fetchCommunities,
fetchThemeList,
fetchUsers,
myAuth,
myAuthRequired,
personToChoice,
relTags,
setIsoData,
setTheme,
setupTippy,
showLocal,
toast,
updateCommunityBlock,
updatePersonBlock,
} from "../../utils";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
import { Icon, Spinner } from "../common/icon";
import { ImageUploadForm } from "../common/image-upload-form";

View file

@ -1,8 +1,9 @@
import { setIsoData } from "@utils/app";
import { Component } from "inferno";
import { GetSiteResponse, VerifyEmailResponse } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { HttpService, RequestState } from "../../services/HttpService";
import { setIsoData, toast } from "../../utils";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";

View file

@ -1,5 +1,7 @@
import { getQueryParams } from "@utils/helpers";
import { enableDownvotes, enableNsfw, myAuth, setIsoData } from "@utils/app";
import { getIdFromString, getQueryParams } from "@utils/helpers";
import type { QueryParams } from "@utils/types";
import { Choice, RouteDataResponse } from "@utils/types";
import { Component } from "inferno";
import { RouteComponentProps } from "inferno-router/dist/Route";
import {
@ -17,15 +19,6 @@ import {
RequestState,
WrappedLemmyHttp,
} from "../../services/HttpService";
import {
Choice,
RouteDataResponse,
enableDownvotes,
enableNsfw,
getIdFromString,
myAuth,
setIsoData,
} from "../../utils";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";
import { PostForm } from "./post-form";

View file

@ -1,8 +1,8 @@
import { Component, linkEvent } from "inferno";
import { Post } from "lemmy-js-client";
import * as sanitizeHtml from "sanitize-html";
import { relTags } from "../../config";
import { i18n } from "../../i18next";
import { relTags } from "../../utils";
import { Icon } from "../common/icon";
interface MetadataCardProps {
@ -75,10 +75,14 @@ export class MetadataCard extends Component<
</div>
)}
{this.state.expanded && post.embed_video_url && (
<div className="ratio ratio-16x9">
<iframe
allowFullScreen
className="post-metadata-iframe"
src={post.embed_video_url}
title={post.embed_title}
></iframe>
</div>
)}
</>
);

View file

@ -1,4 +1,18 @@
import { debounce } from "@utils/helpers";
import {
communityToChoice,
fetchCommunities,
myAuth,
myAuthRequired,
} from "@utils/app";
import {
capitalizeFirstLetter,
debounce,
getIdFromString,
validTitle,
validURL,
} from "@utils/helpers";
import { isImage } from "@utils/media";
import { Choice } from "@utils/types";
import autosize from "autosize";
import { Component, InfernoNode, linkEvent } from "inferno";
import {
@ -10,29 +24,19 @@ import {
PostView,
SearchResponse,
} from "lemmy-js-client";
import {
archiveTodayUrl,
ghostArchiveUrl,
relTags,
trendingFetchLimit,
webArchiveUrl,
} from "../../config";
import { i18n } from "../../i18next";
import { PostFormParams } from "../../interfaces";
import { UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import {
Choice,
archiveTodayUrl,
capitalizeFirstLetter,
communityToChoice,
fetchCommunities,
getIdFromString,
ghostArchiveUrl,
isImage,
myAuth,
myAuthRequired,
relTags,
setupTippy,
toast,
trendingFetchLimit,
validTitle,
validURL,
webArchiveUrl,
} from "../../utils";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
import { Icon, Spinner } from "../common/icon";
import { LanguageSelect } from "../common/language-select";
import { MarkdownTextArea } from "../common/markdown-textarea";

View file

@ -1,4 +1,7 @@
import { myAuthRequired, newVote, showScores } from "@utils/app";
import { canShare, share } from "@utils/browser";
import { futureDaysToUnixTime, hostname, numToSI } from "@utils/helpers";
import { isImage, isVideo } from "@utils/media";
import {
amAdmin,
amCommunityCreator,
@ -34,25 +37,13 @@ import {
SavePost,
TransferCommunity,
} from "lemmy-js-client";
import { relTags } from "../../config";
import { getExternalHost, getHttpBase } from "../../env";
import { i18n } from "../../i18next";
import { BanType, PostFormParams, PurgeType, VoteType } from "../../interfaces";
import { mdNoImages, mdToHtml, mdToHtmlInline } from "../../markdown";
import { UserService } from "../../services";
import {
futureDaysToUnixTime,
hostname,
isImage,
isVideo,
mdNoImages,
mdToHtml,
mdToHtmlInline,
myAuthRequired,
newVote,
numToSI,
relTags,
setupTippy,
showScores,
} from "../../utils";
import { setupTippy } from "../../tippy";
import { Icon, PurgeWarning, Spinner } from "../common/icon";
import { MomentTime } from "../common/moment-time";
import { PictrsImage } from "../common/pictrs-image";
@ -746,10 +737,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
to={`/post/${post_view.post.id}?scrollToComments=true`}
data-tippy-content={title}
>
<span className="me-1">
<Icon icon="message-square" classes="me-1" inline />
{post_view.counts.comments}
</span>
{this.unreadCount && (
<span className="badge text-bg-warning">
<span className="text-muted fst-italic">
({this.unreadCount} {i18n.t("new")})
</span>
)}

View file

@ -1,8 +1,8 @@
import { myAuthRequired } from "@utils/app";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import { PostReportView, PostView, ResolvePostReport } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { myAuthRequired } from "../../utils";
import { Icon, Spinner } from "../common/icon";
import { PersonListing } from "../person/person-listing";
import { PostListing } from "./post-listing";

View file

@ -1,7 +1,29 @@
import { isBrowser } from "@utils/browser";
import {
buildCommentsTree,
commentsToFlatNodes,
editComment,
editWith,
enableDownvotes,
enableNsfw,
getCommentIdFromProps,
getCommentParentId,
getDepthFromComment,
getIdFromProps,
myAuth,
setIsoData,
updateCommunityBlock,
updatePersonBlock,
} from "@utils/app";
import {
isBrowser,
restoreScrollPosition,
saveScrollPosition,
} from "@utils/browser";
import { debounce } from "@utils/helpers";
import { isImage } from "@utils/media";
import { RouteDataResponse } from "@utils/types";
import autosize from "autosize";
import { Component, createRef, linkEvent, RefObject } from "inferno";
import { Component, RefObject, createRef, linkEvent } from "inferno";
import {
AddAdmin,
AddModToCommunity,
@ -53,6 +75,7 @@ import {
SavePost,
TransferCommunity,
} from "lemmy-js-client";
import { commentTreeMaxDepth } from "../../config";
import { i18n } from "../../i18next";
import {
CommentNodeI,
@ -62,29 +85,8 @@ import {
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { HttpService, RequestState } from "../../services/HttpService";
import {
buildCommentsTree,
commentsToFlatNodes,
commentTreeMaxDepth,
editComment,
editWith,
enableDownvotes,
enableNsfw,
getCommentIdFromProps,
getCommentParentId,
getDepthFromComment,
getIdFromProps,
isImage,
myAuth,
restoreScrollPosition,
RouteDataResponse,
saveScrollPosition,
setIsoData,
setupTippy,
toast,
updateCommunityBlock,
updatePersonBlock,
} from "../../utils";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
import { CommentForm } from "../comment/comment-form";
import { CommentNodes } from "../comment/comment-nodes";
import { HtmlTags } from "../common/html-tags";

View file

@ -1,3 +1,5 @@
import { getRecipientIdFromProps, myAuth, setIsoData } from "@utils/app";
import { RouteDataResponse } from "@utils/types";
import { Component } from "inferno";
import {
CreatePrivateMessage as CreatePrivateMessageI,
@ -9,13 +11,7 @@ import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { FirstLoadService } from "../../services/FirstLoadService";
import { HttpService, RequestState } from "../../services/HttpService";
import {
RouteDataResponse,
getRecipientIdFromProps,
myAuth,
setIsoData,
toast,
} from "../../utils";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";
import { PrivateMessageForm } from "./private-message-form";

View file

@ -1,3 +1,5 @@
import { myAuthRequired } from "@utils/app";
import { capitalizeFirstLetter } from "@utils/helpers";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import {
@ -6,13 +8,9 @@ import {
Person,
PrivateMessageView,
} from "lemmy-js-client";
import { relTags } from "../../config";
import { i18n } from "../../i18next";
import {
capitalizeFirstLetter,
myAuthRequired,
relTags,
setupTippy,
} from "../../utils";
import { setupTippy } from "../../tippy";
import { Icon, Spinner } from "../common/icon";
import { MarkdownTextArea } from "../common/markdown-textarea";
import NavigationPrompt from "../common/navigation-prompt";

View file

@ -1,3 +1,4 @@
import { myAuthRequired } from "@utils/app";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import {
@ -5,7 +6,7 @@ import {
ResolvePrivateMessageReport,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml, myAuthRequired } from "../../utils";
import { mdToHtml } from "../../markdown";
import { Icon, Spinner } from "../common/icon";
import { PersonListing } from "../person/person-listing";

View file

@ -1,3 +1,4 @@
import { myAuthRequired } from "@utils/app";
import { Component, InfernoNode, linkEvent } from "inferno";
import {
CreatePrivateMessage,
@ -9,8 +10,8 @@ import {
PrivateMessageView,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml } from "../../markdown";
import { UserService } from "../../services";
import { mdToHtml, myAuthRequired } from "../../utils";
import { Icon, Spinner } from "../common/icon";
import { MomentTime } from "../common/moment-time";
import { PersonListing } from "../person/person-listing";

View file

@ -1,5 +1,28 @@
import { debounce, getQueryParams, getQueryString } from "@utils/helpers";
import {
commentsToFlatNodes,
communityToChoice,
enableDownvotes,
enableNsfw,
fetchCommunities,
fetchUsers,
getUpdatedSearchId,
myAuth,
personToChoice,
setIsoData,
showLocal,
} from "@utils/app";
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
import {
capitalizeFirstLetter,
debounce,
getIdFromString,
getPageFromString,
getQueryParams,
getQueryString,
numToSI,
} from "@utils/helpers";
import type { QueryParams } from "@utils/types";
import { Choice, RouteDataResponse } from "@utils/types";
import type { NoOptionI18nKeys } from "i18next";
import { Component, linkEvent } from "inferno";
import {
@ -22,32 +45,11 @@ import {
SearchType,
SortType,
} from "lemmy-js-client";
import { fetchLimit } from "../config";
import { i18n } from "../i18next";
import { CommentViewType, InitialFetchRequest } from "../interfaces";
import { FirstLoadService } from "../services/FirstLoadService";
import { HttpService, RequestState } from "../services/HttpService";
import {
Choice,
RouteDataResponse,
capitalizeFirstLetter,
commentsToFlatNodes,
communityToChoice,
enableDownvotes,
enableNsfw,
fetchCommunities,
fetchLimit,
fetchUsers,
getIdFromString,
getPageFromString,
getUpdatedSearchId,
myAuth,
numToSI,
personToChoice,
restoreScrollPosition,
saveScrollPosition,
setIsoData,
showLocal,
} from "../utils";
import { CommentNodes } from "./comment/comment-nodes";
import { HtmlTags } from "./common/html-tags";
import { Spinner } from "./common/icon";

26
src/shared/config.ts Normal file
View file

@ -0,0 +1,26 @@
export const favIconUrl = "/static/assets/icons/favicon.svg";
export const favIconPngUrl = "/static/assets/icons/apple-touch-icon.png";
export const repoUrl = "https://github.com/LemmyNet";
export const joinLemmyUrl = "https://join-lemmy.org";
export const donateLemmyUrl = `${joinLemmyUrl}/donate`;
export const docsUrl = `${joinLemmyUrl}/docs/en/index.html`;
export const helpGuideUrl = `${joinLemmyUrl}/docs/en/users/01-getting-started.html`; // TODO find a way to redirect to the non-en folder
export const markdownHelpUrl = `${joinLemmyUrl}/docs/en/users/02-media.html`;
export const sortingHelpUrl = `${joinLemmyUrl}/docs/en/users/03-votes-and-ranking.html`;
export const archiveTodayUrl = "https://archive.today";
export const ghostArchiveUrl = "https://ghostarchive.org";
export const webArchiveUrl = "https://web.archive.org";
export const elementUrl = "https://element.io";
export const postRefetchSeconds: number = 60 * 1000;
export const trendingFetchLimit = 6;
export const mentionDropdownFetchLimit = 10;
export const commentTreeMaxDepth = 8;
export const markdownFieldCharacterLimit = 50000;
export const maxUploadImages = 20;
export const concurrentImageUpload = 4;
export const updateUnreadCountsInterval = 30000;
export const fetchLimit = 40;
export const relTags = "noopener nofollow";
export const emDash = "\u2014";

View file

@ -1,6 +1,6 @@
import { isBrowser } from "@utils/browser";
import i18next, { i18nTyped, Resource } from "i18next";
import { UserService } from "./services";
import { UserService } from "./services/UserService";
import { ar } from "./translations/ar";
import { bg } from "./translations/bg";
import { ca } from "./translations/ca";

View file

@ -1,7 +1,7 @@
import { ErrorPageData } from "@utils/types";
import { CommentView, GetSiteResponse } from "lemmy-js-client";
import type { ParsedQs } from "qs";
import { RequestState, WrappedLemmyHttp } from "./services/HttpService";
import { ErrorPageData } from "./utils";
/**
* This contains serialized data, it needs to be deserialized before use.

307
src/shared/markdown.ts Normal file
View file

@ -0,0 +1,307 @@
import { communitySearch, personSearch } from "@utils/app";
import { isBrowser } from "@utils/browser";
import { debounce, groupBy } from "@utils/helpers";
import { CommunityTribute, PersonTribute } from "@utils/types";
import { Picker } from "emoji-mart";
import emojiShortName from "emoji-short-name";
import { CustomEmojiView } from "lemmy-js-client";
import { default as MarkdownIt } from "markdown-it";
import markdown_it_container from "markdown-it-container";
// import markdown_it_emoji from "markdown-it-emoji/bare";
import markdown_it_footnote from "markdown-it-footnote";
import markdown_it_html5_embed from "markdown-it-html5-embed";
import markdown_it_sub from "markdown-it-sub";
import markdown_it_sup from "markdown-it-sup";
import Renderer from "markdown-it/lib/renderer";
import Token from "markdown-it/lib/token";
export let Tribute: any;
export let md: MarkdownIt = new MarkdownIt();
export let mdNoImages: MarkdownIt = new MarkdownIt();
export const customEmojis: EmojiMartCategory[] = [];
export let customEmojisLookup: Map<string, CustomEmojiView> = new Map<
string,
CustomEmojiView
>();
if (isBrowser()) {
Tribute = require("tributejs");
}
export function mdToHtml(text: string) {
return { __html: md.render(text) };
}
export function mdToHtmlNoImages(text: string) {
return { __html: mdNoImages.render(text) };
}
export function mdToHtmlInline(text: string) {
return { __html: md.renderInline(text) };
}
const spoilerConfig = {
validate: (params: string) => {
return params.trim().match(/^spoiler\s+(.*)$/);
},
render: (tokens: any, idx: any) => {
var m = tokens[idx].info.trim().match(/^spoiler\s+(.*)$/);
if (tokens[idx].nesting === 1) {
// opening tag
return `<details><summary> ${md.utils.escapeHtml(m[1])} </summary>\n`;
} else {
// closing tag
return "</details>\n";
}
},
};
const html5EmbedConfig = {
html5embed: {
useImageSyntax: true, // Enables video/audio embed with ![]() syntax (default)
attributes: {
audio: 'controls preload="metadata"',
video: 'width="100%" max-height="100%" controls loop preload="metadata"',
},
},
};
export function setupMarkdown() {
const markdownItConfig: MarkdownIt.Options = {
html: false,
linkify: true,
typographer: true,
};
// const emojiDefs = Array.from(customEmojisLookup.entries()).reduce(
// (main, [key, value]) => ({ ...main, [key]: value }),
// {}
// );
md = new MarkdownIt(markdownItConfig)
.use(markdown_it_sub)
.use(markdown_it_sup)
.use(markdown_it_footnote)
.use(markdown_it_html5_embed, html5EmbedConfig)
.use(markdown_it_container, "spoiler", spoilerConfig);
// .use(markdown_it_emoji, {
// defs: emojiDefs,
// });
mdNoImages = new MarkdownIt(markdownItConfig)
.use(markdown_it_sub)
.use(markdown_it_sup)
.use(markdown_it_footnote)
.use(markdown_it_html5_embed, html5EmbedConfig)
.use(markdown_it_container, "spoiler", spoilerConfig)
// .use(markdown_it_emoji, {
// defs: emojiDefs,
// })
.disable("image");
const defaultRenderer = md.renderer.rules.image;
md.renderer.rules.image = function (
tokens: Token[],
idx: number,
options: MarkdownIt.Options,
env: any,
self: Renderer
) {
//Provide custom renderer for our emojis to allow us to add a css class and force size dimensions on them.
const item = tokens[idx] as any;
const title = item.attrs.length >= 3 ? item.attrs[2][1] : "";
const src: string = item.attrs[0][1];
const isCustomEmoji = customEmojisLookup.get(title) != undefined;
if (!isCustomEmoji) {
return defaultRenderer?.(tokens, idx, options, env, self) ?? "";
}
const alt_text = item.content;
return `<img class="icon icon-emoji" src="${src}" title="${title}" alt="${alt_text}"/>`;
};
md.renderer.rules.table_open = function () {
return '<table class="table">';
};
}
export function setupEmojiDataModel(custom_emoji_views: CustomEmojiView[]) {
const groupedEmojis = groupBy(
custom_emoji_views,
x => x.custom_emoji.category
);
for (const [category, emojis] of Object.entries(groupedEmojis)) {
customEmojis.push({
id: category,
name: category,
emojis: emojis.map(emoji => ({
id: emoji.custom_emoji.shortcode,
name: emoji.custom_emoji.shortcode,
keywords: emoji.keywords.map(x => x.keyword),
skins: [{ src: emoji.custom_emoji.image_url }],
})),
});
}
customEmojisLookup = new Map(
custom_emoji_views.map(view => [view.custom_emoji.shortcode, view])
);
}
export function updateEmojiDataModel(custom_emoji_view: CustomEmojiView) {
const emoji: EmojiMartCustomEmoji = {
id: custom_emoji_view.custom_emoji.shortcode,
name: custom_emoji_view.custom_emoji.shortcode,
keywords: custom_emoji_view.keywords.map(x => x.keyword),
skins: [{ src: custom_emoji_view.custom_emoji.image_url }],
};
const categoryIndex = customEmojis.findIndex(
x => x.id == custom_emoji_view.custom_emoji.category
);
if (categoryIndex == -1) {
customEmojis.push({
id: custom_emoji_view.custom_emoji.category,
name: custom_emoji_view.custom_emoji.category,
emojis: [emoji],
});
} else {
const emojiIndex = customEmojis[categoryIndex].emojis.findIndex(
x => x.id == custom_emoji_view.custom_emoji.shortcode
);
if (emojiIndex == -1) {
customEmojis[categoryIndex].emojis.push(emoji);
} else {
customEmojis[categoryIndex].emojis[emojiIndex] = emoji;
}
}
customEmojisLookup.set(
custom_emoji_view.custom_emoji.shortcode,
custom_emoji_view
);
}
export function removeFromEmojiDataModel(id: number) {
let view: CustomEmojiView | undefined;
for (const item of customEmojisLookup.values()) {
if (item.custom_emoji.id === id) {
view = item;
break;
}
}
if (!view) return;
const categoryIndex = customEmojis.findIndex(
x => x.id == view?.custom_emoji.category
);
const emojiIndex = customEmojis[categoryIndex].emojis.findIndex(
x => x.id == view?.custom_emoji.shortcode
);
customEmojis[categoryIndex].emojis = customEmojis[
categoryIndex
].emojis.splice(emojiIndex, 1);
customEmojisLookup.delete(view?.custom_emoji.shortcode);
}
export function getEmojiMart(
onEmojiSelect: (e: any) => void,
customPickerOptions: any = {}
) {
const pickerOptions = {
...customPickerOptions,
onEmojiSelect: onEmojiSelect,
custom: customEmojis,
};
return new Picker(pickerOptions);
}
export function setupTribute() {
return new Tribute({
noMatchTemplate: function () {
return "";
},
collection: [
// Emojis
{
trigger: ":",
menuItemTemplate: (item: any) => {
const shortName = `:${item.original.key}:`;
return `${item.original.val} ${shortName}`;
},
selectTemplate: (item: any) => {
const customEmoji = customEmojisLookup.get(
item.original.key
)?.custom_emoji;
if (customEmoji == undefined) return `${item.original.val}`;
else
return `![${customEmoji.alt_text}](${customEmoji.image_url} "${customEmoji.shortcode}")`;
},
values: Object.entries(emojiShortName)
.map(e => {
return { key: e[1], val: e[0] };
})
.concat(
Array.from(customEmojisLookup.entries()).map(k => ({
key: k[0],
val: `<img class="icon icon-emoji" src="${k[1].custom_emoji.image_url}" title="${k[1].custom_emoji.shortcode}" alt="${k[1].custom_emoji.alt_text}" />`,
}))
),
allowSpaces: false,
autocompleteMode: true,
// TODO
// menuItemLimit: mentionDropdownFetchLimit,
menuShowMinLength: 2,
},
// Persons
{
trigger: "@",
selectTemplate: (item: any) => {
const it: PersonTribute = item.original;
return `[${it.key}](${it.view.person.actor_id})`;
},
values: debounce(async (text: string, cb: any) => {
cb(await personSearch(text));
}),
allowSpaces: false,
autocompleteMode: true,
// TODO
// menuItemLimit: mentionDropdownFetchLimit,
menuShowMinLength: 2,
},
// Communities
{
trigger: "!",
selectTemplate: (item: any) => {
const it: CommunityTribute = item.original;
return `[${it.key}](${it.view.community.actor_id})`;
},
values: debounce(async (text: string, cb: any) => {
cb(await communitySearch(text));
}),
allowSpaces: false,
autocompleteMode: true,
// TODO
// menuItemLimit: mentionDropdownFetchLimit,
menuShowMinLength: 2,
},
],
});
}
interface EmojiMartCategory {
id: string;
name: string;
emojis: EmojiMartCustomEmoji[];
}
interface EmojiMartCustomEmoji {
id: string;
name: string;
keywords: string[];
skins: EmojiMartSkin[];
}
interface EmojiMartSkin {
src: string;
}

View file

@ -1,7 +1,7 @@
import { LemmyHttp } from "lemmy-js-client";
import { getHttpBase } from "../../shared/env";
import { i18n } from "../../shared/i18next";
import { toast } from "../../shared/utils";
import { toast } from "../../shared/toast";
type EmptyRequestState = {
state: "empty";

View file

@ -1,11 +1,12 @@
// import Cookies from 'js-cookie';
import { isAuthPath } from "@utils/app";
import { isBrowser } from "@utils/browser";
import IsomorphicCookie from "isomorphic-cookie";
import jwt_decode from "jwt-decode";
import { LoginResponse, MyUserInfo } from "lemmy-js-client";
import { isHttps } from "../env";
import { i18n } from "../i18next";
import { isAuthPath, toast } from "../utils";
import { toast } from "../toast";
interface Claims {
sub: number;

19
src/shared/tippy.ts Normal file
View file

@ -0,0 +1,19 @@
import { isBrowser } from "@utils/browser";
import tippy from "tippy.js";
export let tippyInstance: any;
if (isBrowser()) {
tippyInstance = tippy("[data-tippy-content]");
}
export function setupTippy() {
if (isBrowser()) {
tippyInstance.forEach((e: any) => e.destroy());
tippyInstance = tippy("[data-tippy-content]", {
delay: [500, 0],
// Display on "long press"
touch: ["hold", 500],
});
}
}

54
src/shared/toast.ts Normal file
View file

@ -0,0 +1,54 @@
import { isBrowser } from "@utils/browser";
import { ThemeColor } from "@utils/types";
import Toastify from "toastify-js";
import { i18n } from "./i18next";
export function toast(text: string, background: ThemeColor = "success") {
if (isBrowser()) {
const backgroundColor = `var(--bs-${background})`;
Toastify({
text: text,
backgroundColor: backgroundColor,
gravity: "bottom",
position: "left",
duration: 5000,
}).showToast();
}
}
export function pictrsDeleteToast(filename: string, deleteUrl: string) {
if (isBrowser()) {
const clickToDeleteText = i18n.t("click_to_delete_picture", { filename });
const deletePictureText = i18n.t("picture_deleted", {
filename,
});
const failedDeletePictureText = i18n.t("failed_to_delete_picture", {
filename,
});
const backgroundColor = `var(--bs-light)`;
const toast = Toastify({
text: clickToDeleteText,
backgroundColor: backgroundColor,
gravity: "top",
position: "right",
duration: 10000,
onClick: () => {
if (toast) {
fetch(deleteUrl).then(res => {
toast.hideToast();
if (res.ok === true) {
alert(deletePictureText);
} else {
alert(failedDeletePictureText);
}
});
}
},
close: true,
});
toast.showToast();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,54 @@
import { getCommentParentId, getDepthFromComment } from "@utils/app";
import { CommentView } from "lemmy-js-client";
import { CommentNodeI } from "../../interfaces";
export default function buildCommentsTree(
comments: CommentView[],
parentComment: boolean
): CommentNodeI[] {
const map = new Map<number, CommentNodeI>();
const depthOffset = !parentComment
? 0
: getDepthFromComment(comments[0].comment) ?? 0;
for (const comment_view of comments) {
const depthI = getDepthFromComment(comment_view.comment) ?? 0;
const depth = depthI ? depthI - depthOffset : 0;
const node: CommentNodeI = {
comment_view,
children: [],
depth,
};
map.set(comment_view.comment.id, { ...node });
}
const tree: CommentNodeI[] = [];
// if its a parent comment fetch, then push the first comment to the top node.
if (parentComment) {
const cNode = map.get(comments[0].comment.id);
if (cNode) {
tree.push(cNode);
}
}
for (const comment_view of comments) {
const child = map.get(comment_view.comment.id);
if (child) {
const parent_id = getCommentParentId(comment_view.comment);
if (parent_id) {
const parent = map.get(parent_id);
// Necessary because blocked comment might not exist
if (parent) {
parent.children.push(child);
}
} else {
if (!parentComment) {
tree.push(child);
}
}
}
}
return tree;
}

View file

@ -0,0 +1,11 @@
import { hsl } from "@utils/helpers";
export const colorList: string[] = [
hsl(0),
hsl(50),
hsl(100),
hsl(150),
hsl(200),
hsl(250),
hsl(300),
];

View file

@ -0,0 +1,12 @@
import { CommentView } from "lemmy-js-client";
import { CommentNodeI } from "../../interfaces";
export default function commentsToFlatNodes(
comments: CommentView[]
): CommentNodeI[] {
const nodes: CommentNodeI[] = [];
for (const comment of comments) {
nodes.push({ comment_view: comment, children: [], depth: 0 });
}
return nodes;
}

View file

@ -0,0 +1,4 @@
export default function communityRSSUrl(actorId: string, sort: string): string {
const url = new URL(actorId);
return `${url.origin}/feeds${url.pathname}.xml?sort=${sort}`;
}

View file

@ -0,0 +1,14 @@
import { fetchCommunities } from "@utils/app";
import { hostname } from "@utils/helpers";
import { CommunityTribute } from "@utils/types";
export default async function communitySearch(
text: string
): Promise<CommunityTribute[]> {
const communitiesResponse = await fetchCommunities(text);
return communitiesResponse.map(cv => ({
key: `!${cv.community.name}@${hostname(cv.community.actor_id)}`,
view: cv,
}));
}

View file

@ -0,0 +1,8 @@
import { hostname } from "@utils/helpers";
import { CommunityView } from "lemmy-js-client";
export default function communitySelectName(cv: CommunityView): string {
return cv.community.local
? cv.community.title
: `${hostname(cv.community.actor_id)}/${cv.community.title}`;
}

View file

@ -0,0 +1,10 @@
import { communitySelectName } from "@utils/app";
import { Choice } from "@utils/types";
import { CommunityView } from "lemmy-js-client";
export default function communityToChoice(cv: CommunityView): Choice {
return {
value: cv.community.id.toString(),
label: communitySelectName(cv),
};
}

View file

@ -0,0 +1,28 @@
import { CommentSortType, SortType } from "lemmy-js-client";
export default function convertCommentSortType(
sort: SortType
): CommentSortType {
switch (sort) {
case "TopAll":
case "TopHour":
case "TopSixHour":
case "TopTwelveHour":
case "TopDay":
case "TopWeek":
case "TopMonth":
case "TopYear": {
return "Top";
}
case "New": {
return "New";
}
case "Hot":
case "Active": {
return "Hot";
}
default: {
return "Hot";
}
}
}

View file

@ -0,0 +1,9 @@
import { editListImmutable } from "@utils/helpers";
import { CommentReplyView } from "lemmy-js-client";
export default function editCommentReply(
data: CommentReplyView,
replies: CommentReplyView[]
): CommentReplyView[] {
return editListImmutable("comment_reply", data, replies);
}

View file

@ -0,0 +1,9 @@
import { editListImmutable } from "@utils/helpers";
import { CommentReportView } from "lemmy-js-client";
export default function editCommentReport(
data: CommentReportView,
reports: CommentReportView[]
): CommentReportView[] {
return editListImmutable("comment_report", data, reports);
}

View file

@ -0,0 +1,9 @@
import { editListImmutable } from "@utils/helpers";
import { CommentView } from "lemmy-js-client";
export default function editComment(
data: CommentView,
comments: CommentView[]
): CommentView[] {
return editListImmutable("comment", data, comments);
}

View file

@ -0,0 +1,9 @@
import { editListImmutable } from "@utils/helpers";
import { CommunityView } from "lemmy-js-client";
export default function editCommunity(
data: CommunityView,
communities: CommunityView[]
): CommunityView[] {
return editListImmutable("community", data, communities);
}

View file

@ -0,0 +1,9 @@
import { editListImmutable } from "@utils/helpers";
import { PersonMentionView } from "lemmy-js-client";
export default function editMention(
data: PersonMentionView,
comments: PersonMentionView[]
): PersonMentionView[] {
return editListImmutable("person_mention", data, comments);
}

View file

@ -0,0 +1,9 @@
import { editListImmutable } from "@utils/helpers";
import { PostReportView } from "lemmy-js-client";
export default function editPostReport(
data: PostReportView,
reports: PostReportView[]
) {
return editListImmutable("post_report", data, reports);
}

View file

@ -0,0 +1,9 @@
import { editListImmutable } from "@utils/helpers";
import { PostView } from "lemmy-js-client";
export default function editPost(
data: PostView,
posts: PostView[]
): PostView[] {
return editListImmutable("post", data, posts);
}

View file

@ -0,0 +1,9 @@
import { editListImmutable } from "@utils/helpers";
import { PrivateMessageReportView } from "lemmy-js-client";
export default function editPrivateMessageReport(
data: PrivateMessageReportView,
reports: PrivateMessageReportView[]
): PrivateMessageReportView[] {
return editListImmutable("private_message_report", data, reports);
}

View file

@ -0,0 +1,9 @@
import { editListImmutable } from "@utils/helpers";
import { PrivateMessageView } from "lemmy-js-client";
export default function editPrivateMessage(
data: PrivateMessageView,
messages: PrivateMessageView[]
): PrivateMessageView[] {
return editListImmutable("private_message", data, messages);
}

View file

@ -0,0 +1,9 @@
import { editListImmutable } from "@utils/helpers";
import { RegistrationApplicationView } from "lemmy-js-client";
export default function editRegistrationApplication(
data: RegistrationApplicationView,
apps: RegistrationApplicationView[]
): RegistrationApplicationView[] {
return editListImmutable("registration_application", data, apps);
}

View file

@ -0,0 +1,14 @@
import { WithComment } from "@utils/types";
export default function editWith<D extends WithComment, L extends WithComment>(
{ comment, counts, saved, my_vote }: D,
list: L[]
) {
return [
...list.map(c =>
c.comment.id === comment.id
? { ...c, comment, counts, saved, my_vote }
: c
),
];
}

View file

@ -0,0 +1,5 @@
import { GetSiteResponse } from "lemmy-js-client";
export default function enableDownvotes(siteRes: GetSiteResponse): boolean {
return siteRes.site_view.local_site.enable_downvotes;
}

View file

@ -0,0 +1,5 @@
import { GetSiteResponse } from "lemmy-js-client";
export default function enableNsfw(siteRes: GetSiteResponse): boolean {
return siteRes.site_view.local_site.enable_nsfw;
}

View file

@ -0,0 +1,7 @@
import { fetchSearchResults } from "@utils/app";
export default async function fetchCommunities(q: string) {
const res = await fetchSearchResults(q, "Communities");
return res.state === "success" ? res.data.communities : [];
}

View file

@ -0,0 +1,18 @@
import { myAuth } from "@utils/app";
import { Search, SearchType } from "lemmy-js-client";
import { fetchLimit } from "../../config";
import { HttpService } from "../../services";
export default function fetchSearchResults(q: string, type_: SearchType) {
const form: Search = {
q,
type_,
sort: "TopAll",
listing_type: "All",
page: 1,
limit: fetchLimit,
auth: myAuth(),
};
return HttpService.client.search(form);
}

Some files were not shown because too many files have changed in this diff Show more