Merge branch 'main' into feat/default-to-user-primary-lang

This commit is contained in:
Jay Sitter 2023-06-22 17:34:20 -04:00 committed by GitHub
commit 5648843f4e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 276 additions and 126 deletions

2
.github/CODEOWNERS vendored
View file

@ -1 +1 @@
* @dessalines @SleeplessOne1917 @alectrocute * @dessalines @SleeplessOne1917 @alectrocute @jsit

View file

@ -1,6 +1,6 @@
{ {
"name": "lemmy-ui", "name": "lemmy-ui",
"version": "0.18.0-rc.5", "version": "0.18.0-rc.6",
"description": "An isomorphic UI for lemmy", "description": "An isomorphic UI for lemmy",
"repository": "https://github.com/LemmyNet/lemmy-ui", "repository": "https://github.com/LemmyNet/lemmy-ui",
"license": "AGPL-3.0", "license": "AGPL-3.0",

View file

@ -1,12 +1,13 @@
import { initializeSite, isAuthPath } from "@utils/app"; import { initializeSite, isAuthPath } from "@utils/app";
import { getHttpBaseInternal } from "@utils/env";
import { ErrorPageData } from "@utils/types"; import { ErrorPageData } from "@utils/types";
import fetch from "cross-fetch";
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import { StaticRouter, matchPath } from "inferno-router"; import { StaticRouter, matchPath } from "inferno-router";
import { renderToString } from "inferno-server"; import { renderToString } from "inferno-server";
import IsomorphicCookie from "isomorphic-cookie"; import IsomorphicCookie from "isomorphic-cookie";
import { GetSite, GetSiteResponse, LemmyHttp } from "lemmy-js-client"; import { GetSite, GetSiteResponse, LemmyHttp } from "lemmy-js-client";
import { App } from "../../shared/components/app/app"; import { App } from "../../shared/components/app/app";
import { getHttpBaseInternal } from "../../shared/env";
import { import {
InitialFetchRequest, InitialFetchRequest,
IsoDataOptionalSite, IsoDataOptionalSite,

View file

@ -1,6 +1,7 @@
import { getHttpBaseExternal, getHttpBaseInternal } from "@utils/env";
import fetch from "cross-fetch";
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import { LemmyHttp } from "lemmy-js-client"; import { LemmyHttp } from "lemmy-js-client";
import { getHttpBaseExternal, getHttpBaseInternal } from "../../shared/env";
import { wrapClient } from "../../shared/services/HttpService"; import { wrapClient } from "../../shared/services/HttpService";
import generateManifestJson from "../utils/generate-manifest-json"; import generateManifestJson from "../utils/generate-manifest-json";
import { setForwardedHeaders } from "../utils/set-forwarded-headers"; import { setForwardedHeaders } from "../utils/set-forwarded-headers";

View file

@ -4,15 +4,20 @@ import { readdir } from "fs/promises";
const extraThemesFolder = const extraThemesFolder =
process.env["LEMMY_UI_EXTRA_THEMES_FOLDER"] || "./extra_themes"; process.env["LEMMY_UI_EXTRA_THEMES_FOLDER"] || "./extra_themes";
const themes = ["darkly", "darkly-red", "litely", "litely-red"]; const themes: ReadonlyArray<string> = [
"darkly",
"darkly-red",
"litely",
"litely-red",
];
export async function buildThemeList(): Promise<string[]> { export async function buildThemeList(): Promise<ReadonlyArray<string>> {
if (existsSync(extraThemesFolder)) { if (existsSync(extraThemesFolder)) {
const dirThemes = await readdir(extraThemesFolder); const dirThemes = await readdir(extraThemesFolder);
const cssThemes = dirThemes const cssThemes = dirThemes
.filter(d => d.endsWith(".css")) .filter(d => d.endsWith(".css"))
.map(d => d.replace(".css", "")); .map(d => d.replace(".css", ""));
themes.push(...cssThemes); return themes.concat(cssThemes);
} }
return themes; return themes;
} }

View file

@ -4,6 +4,7 @@ import serialize from "serialize-javascript";
import sharp from "sharp"; import sharp from "sharp";
import { favIconPngUrl, favIconUrl } from "../../shared/config"; import { favIconPngUrl, favIconUrl } from "../../shared/config";
import { ILemmyConfig, IsoDataOptionalSite } from "../../shared/interfaces"; import { ILemmyConfig, IsoDataOptionalSite } from "../../shared/interfaces";
import { buildThemeList } from "./build-themes-list";
import { fetchIconPng } from "./fetch-icon-png"; import { fetchIconPng } from "./fetch-icon-png";
const customHtmlHeader = process.env["LEMMY_UI_CUSTOM_HTML_HEADER"] || ""; const customHtmlHeader = process.env["LEMMY_UI_CUSTOM_HTML_HEADER"] || "";
@ -16,6 +17,10 @@ export async function createSsrHtml(
) { ) {
const site = isoData.site_res; const site = isoData.site_res;
const fallbackTheme = `<link rel="stylesheet" type="text/css" href="/css/themes/${
(await buildThemeList())[0]
}.css" />`;
if (!appleTouchIcon) { if (!appleTouchIcon) {
appleTouchIcon = site?.site_view.site.icon appleTouchIcon = site?.site_view.site.icon
? `data:image/png;base64,${sharp( ? `data:image/png;base64,${sharp(
@ -68,7 +73,7 @@ export async function createSsrHtml(
<!-- Required meta tags --> <!-- Required meta tags -->
<meta name="Description" content="Lemmy"> <meta name="Description" content="Lemmy">
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link <link
id="favicon" id="favicon"
rel="shortcut icon" rel="shortcut icon"
@ -85,7 +90,7 @@ export async function createSsrHtml(
<link rel="stylesheet" type="text/css" href="/static/styles/styles.css" /> <link rel="stylesheet" type="text/css" href="/static/styles/styles.css" />
<!-- Current theme and more --> <!-- Current theme and more -->
${helmet.link.toString()} ${helmet.link.toString() || fallbackTheme}
</head> </head>

View file

@ -1,3 +1,5 @@
import fetch from "cross-fetch";
export async function fetchIconPng(iconUrl: string) { export async function fetchIconPng(iconUrl: string) {
return await fetch(iconUrl) return await fetch(iconUrl)
.then(res => res.blob()) .then(res => res.blob())

View file

@ -1,8 +1,8 @@
import { getHttpBaseExternal } from "@utils/env";
import { readFile } from "fs/promises"; import { readFile } from "fs/promises";
import { GetSiteResponse } from "lemmy-js-client"; import { GetSiteResponse } from "lemmy-js-client";
import path from "path"; import path from "path";
import sharp from "sharp"; import sharp from "sharp";
import { getHttpBaseExternal } from "../../shared/env";
import { fetchIconPng } from "./fetch-icon-png"; import { fetchIconPng } from "./fetch-icon-png";
const iconSizes = [72, 96, 128, 144, 152, 192, 384, 512]; const iconSizes = [72, 96, 128, 144, 152, 192, 384, 512];

View file

@ -1,7 +1,7 @@
import { httpExternalPath } from "@utils/env";
import { htmlToText } from "html-to-text"; import { htmlToText } from "html-to-text";
import { Component } from "inferno"; import { Component } from "inferno";
import { Helmet } from "inferno-helmet"; import { Helmet } from "inferno-helmet";
import { httpExternalPath } from "../../env";
import { md } from "../../markdown"; import { md } from "../../markdown";
import { I18NextService } from "../../services"; import { I18NextService } from "../../services";

View file

@ -22,7 +22,7 @@ export class PictrsImage extends Component<PictrsImageProps, any> {
render() { render() {
return ( return (
<picture className="pictrs-image d-inline-block overflow-hidden"> <picture>
<source srcSet={this.src("webp")} type="image/webp" /> <source srcSet={this.src("webp")} type="image/webp" />
<source srcSet={this.props.src} /> <source srcSet={this.props.src} />
<source srcSet={this.src("jpg")} type="image/jpeg" /> <source srcSet={this.src("jpg")} type="image/jpeg" />
@ -31,7 +31,7 @@ export class PictrsImage extends Component<PictrsImageProps, any> {
alt={this.alt()} alt={this.alt()}
title={this.alt()} title={this.alt()}
loading="lazy" loading="lazy"
className={classNames({ className={classNames("overflow-hidden pictrs-image", {
"img-fluid": !this.props.icon && !this.props.iconOverlay, "img-fluid": !this.props.icon && !this.props.iconOverlay,
banner: this.props.banner, banner: this.props.banner,
"thumbnail rounded": "thumbnail rounded":

View file

@ -67,6 +67,13 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
</option> </option>
<option value={"TopHour"}>{I18NextService.i18n.t("top_hour")}</option>
<option value={"TopSixHour"}>
{I18NextService.i18n.t("top_six_hours")}
</option>
<option value={"TopTwelveHour"}>
{I18NextService.i18n.t("top_twelve_hours")}
</option>
<option value={"TopDay"}>{I18NextService.i18n.t("top_day")}</option> <option value={"TopDay"}>{I18NextService.i18n.t("top_day")}</option>
<option value={"TopWeek"}>{I18NextService.i18n.t("top_week")}</option> <option value={"TopWeek"}>{I18NextService.i18n.t("top_week")}</option>
<option value={"TopMonth"}> <option value={"TopMonth"}>

View file

@ -15,7 +15,6 @@ import {
updateCommunityBlock, updateCommunityBlock,
updatePersonBlock, updatePersonBlock,
} from "@utils/app"; } from "@utils/app";
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
import { import {
getPageFromString, getPageFromString,
getQueryParams, getQueryParams,
@ -229,10 +228,6 @@ export class Community extends Component<
setupTippy(); setupTippy();
} }
componentWillUnmount() {
saveScrollPosition(this.context);
}
static async fetchInitialData({ static async fetchInitialData({
client, client,
path, path,
@ -609,7 +604,6 @@ export class Community extends Component<
}); });
} }
restoreScrollPosition(this.context);
setupTippy(); setupTippy();
} }

View file

@ -13,7 +13,6 @@ import {
showLocal, showLocal,
updatePersonBlock, updatePersonBlock,
} from "@utils/app"; } from "@utils/app";
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
import { import {
getPageFromString, getPageFromString,
getQueryParams, getQueryParams,
@ -293,10 +292,6 @@ export class Home extends Component<any, HomeState> {
setupTippy(); setupTippy();
} }
componentWillUnmount() {
saveScrollPosition(this.context);
}
static async fetchInitialData({ static async fetchInitialData({
client, client,
auth, auth,
@ -800,7 +795,6 @@ export class Home extends Component<any, HomeState> {
}); });
} }
restoreScrollPosition(this.context);
setupTippy(); setupTippy();
} }

View file

@ -1,6 +1,12 @@
import { myAuthRequired, newVote, showScores } from "@utils/app"; import { myAuthRequired, newVote, showScores } from "@utils/app";
import { canShare, share } from "@utils/browser"; import { canShare, share } from "@utils/browser";
import { futureDaysToUnixTime, hostname, numToSI } from "@utils/helpers"; import { getExternalHost, getHttpBase } from "@utils/env";
import {
capitalizeFirstLetter,
futureDaysToUnixTime,
hostname,
numToSI,
} from "@utils/helpers";
import { isImage, isVideo } from "@utils/media"; import { isImage, isVideo } from "@utils/media";
import { import {
amAdmin, amAdmin,
@ -38,7 +44,6 @@ import {
TransferCommunity, TransferCommunity,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { relTags } from "../../config"; import { relTags } from "../../config";
import { getExternalHost, getHttpBase } from "../../env";
import { BanType, PostFormParams, PurgeType, VoteType } from "../../interfaces"; import { BanType, PostFormParams, PurgeType, VoteType } from "../../interfaces";
import { mdNoImages, mdToHtml, mdToHtmlInline } from "../../markdown"; import { mdNoImages, mdToHtml, mdToHtmlInline } from "../../markdown";
import { I18NextService, UserService } from "../../services"; import { I18NextService, UserService } from "../../services";
@ -234,25 +239,40 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
} }
get img() { get img() {
return this.imageSrc ? ( if (this.imageSrc) {
<> return (
<div className="offset-sm-3 my-2 d-none d-sm-block"> <>
<a href={this.imageSrc} className="d-inline-block"> <div className="offset-sm-3 my-2 d-none d-sm-block">
<PictrsImage src={this.imageSrc} /> <a href={this.imageSrc} className="d-inline-block">
</a> <PictrsImage src={this.imageSrc} />
</a>
</div>
<div className="my-2 d-block d-sm-none">
<a
className="d-inline-block"
onClick={linkEvent(this, this.handleImageExpandClick)}
>
<PictrsImage src={this.imageSrc} />
</a>
</div>
</>
);
}
const { post } = this.postView;
const { url } = post;
if (url && isVideo(url)) {
return (
<div className="embed-responsive mt-3">
<video muted controls className="embed-responsive-item col-12">
<source src={url} type="video/mp4" />
</video>
</div> </div>
<div className="my-2 d-block d-sm-none"> );
<a }
className="d-inline-block"
onClick={linkEvent(this, this.handleImageExpandClick)} return <></>;
>
<PictrsImage src={this.imageSrc} />
</a>
</div>
</>
) : (
<></>
);
} }
imgThumb(src: string) { imgThumb(src: string) {
@ -320,17 +340,19 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
} else if (url) { } else if (url) {
if (!this.props.hideImage && isVideo(url)) { if (!this.props.hideImage && isVideo(url)) {
return ( return (
<div className="embed-responsive embed-responsive-16by9"> <a
<video className="text-body"
playsInline href={url}
muted title={url}
loop rel={relTags}
controls data-tippy-content={I18NextService.i18n.t("expand_here")}
className="embed-responsive-item" onClick={linkEvent(this, this.handleImageExpandClick)}
> aria-label={I18NextService.i18n.t("expand_here")}
<source src={url} type="video/mp4" /> >
</video> <div className="thumbnail rounded bg-light d-flex justify-content-center">
</div> <Icon icon="play" classes="d-flex align-items-center" />
</div>
</a>
); );
} else { } else {
return ( return (
@ -981,7 +1003,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
classes={classNames("me-1", { "text-danger": locked })} classes={classNames("me-1", { "text-danger": locked })}
inline inline
/> />
{label} {capitalizeFirstLetter(label)}
</> </>
)} )}
</button> </button>

View file

@ -24,3 +24,15 @@ export const updateUnreadCountsInterval = 30000;
export const fetchLimit = 40; export const fetchLimit = 40;
export const relTags = "noopener nofollow"; export const relTags = "noopener nofollow";
export const emDash = "\u2014"; export const emDash = "\u2014";
/**
* Accepted formats:
* !community@server.com
* /c/community@server.com
* /m/community@server.com
* /u/username@server.com
*/
export const instanceLinkRegex =
/(\/[cmu]\/|!)[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
export const testHost = "0.0.0.0:8536";

View file

@ -1,66 +0,0 @@
import { isBrowser } from "@utils/browser";
const testHost = "0.0.0.0:8536";
function getInternalHost() {
return !isBrowser()
? process.env.LEMMY_UI_LEMMY_INTERNAL_HOST ?? testHost
: testHost; // used for local dev
}
export function getExternalHost() {
return isBrowser()
? `${window.location.hostname}${
["1234", "1235"].includes(window.location.port)
? ":8536"
: window.location.port == ""
? ""
: `:${window.location.port}`
}`
: process.env.LEMMY_UI_LEMMY_EXTERNAL_HOST || testHost;
}
function getSecure() {
return (
isBrowser()
? window.location.protocol.includes("https")
: process.env.LEMMY_UI_HTTPS === "true"
)
? "s"
: "";
}
function getHost() {
return isBrowser() ? getExternalHost() : getInternalHost();
}
function getBaseLocal(s = "") {
return `http${s}://${getHost()}`;
}
export function getHttpBaseInternal() {
return getBaseLocal(); // Don't use secure here
}
export function getHttpBaseExternal() {
return `http${getSecure()}://${getExternalHost()}`;
}
export function getHttpBase() {
return getBaseLocal(getSecure());
}
export function isHttps() {
return getSecure() === "s";
}
console.log(`httpbase: ${getHttpBase()}`);
console.log(`isHttps: ${isHttps()}`);
// This is for html tags, don't include port
export function httpExternalPath(path: string) {
return `http${getSecure()}://${getExternalHost().replace(
/:\d+/g,
""
)}${path}`;
}

View file

@ -14,6 +14,7 @@ import markdown_it_sub from "markdown-it-sub";
import markdown_it_sup from "markdown-it-sup"; import markdown_it_sup from "markdown-it-sup";
import Renderer from "markdown-it/lib/renderer"; import Renderer from "markdown-it/lib/renderer";
import Token from "markdown-it/lib/token"; import Token from "markdown-it/lib/token";
import { instanceLinkRegex } from "./config";
export let Tribute: any; export let Tribute: any;
@ -72,6 +73,75 @@ const html5EmbedConfig = {
}, },
}; };
function localInstanceLinkParser(md: MarkdownIt) {
md.core.ruler.push("replace-text", state => {
for (let i = 0; i < state.tokens.length; i++) {
if (state.tokens[i].type !== "inline") {
continue;
}
const inlineTokens: Token[] = state.tokens[i].children || [];
for (let j = inlineTokens.length - 1; j >= 0; j--) {
if (
inlineTokens[j].type === "text" &&
new RegExp(instanceLinkRegex).test(inlineTokens[j].content)
) {
const text = inlineTokens[j].content;
const matches = Array.from(text.matchAll(instanceLinkRegex));
let lastIndex = 0;
const newTokens: Token[] = [];
let linkClass = "community-link";
for (const match of matches) {
// If there is plain text before the match, add it as a separate token
if (match.index !== undefined && match.index > lastIndex) {
const textToken = new state.Token("text", "", 0);
textToken.content = text.slice(lastIndex, match.index);
newTokens.push(textToken);
}
let href;
if (match[0].startsWith("!")) {
href = "/c/" + match[0].substring(1);
} else if (match[0].startsWith("/m/")) {
href = "/c/" + match[0].substring(3);
} else {
href = match[0];
if (match[0].startsWith("/u/")) {
linkClass = "user-link";
}
}
const linkOpenToken = new state.Token("link_open", "a", 1);
linkOpenToken.attrs = [
["href", href],
["class", linkClass],
];
const textToken = new state.Token("text", "", 0);
textToken.content = match[0];
const linkCloseToken = new state.Token("link_close", "a", -1);
newTokens.push(linkOpenToken, textToken, linkCloseToken);
lastIndex =
(match.index !== undefined ? match.index : 0) + match[0].length;
}
// If there is plain text after the last match, add it as a separate token
if (lastIndex < text.length) {
const textToken = new state.Token("text", "", 0);
textToken.content = text.slice(lastIndex);
newTokens.push(textToken);
}
inlineTokens.splice(j, 1, ...newTokens);
}
}
}
});
}
export function setupMarkdown() { export function setupMarkdown() {
const markdownItConfig: MarkdownIt.Options = { const markdownItConfig: MarkdownIt.Options = {
html: false, html: false,
@ -88,7 +158,8 @@ export function setupMarkdown() {
.use(markdown_it_sup) .use(markdown_it_sup)
.use(markdown_it_footnote) .use(markdown_it_footnote)
.use(markdown_it_html5_embed, html5EmbedConfig) .use(markdown_it_html5_embed, html5EmbedConfig)
.use(markdown_it_container, "spoiler", spoilerConfig); .use(markdown_it_container, "spoiler", spoilerConfig)
.use(localInstanceLinkParser);
// .use(markdown_it_emoji, { // .use(markdown_it_emoji, {
// defs: emojiDefs, // defs: emojiDefs,
// }); // });
@ -99,6 +170,7 @@ export function setupMarkdown() {
.use(markdown_it_footnote) .use(markdown_it_footnote)
.use(markdown_it_html5_embed, html5EmbedConfig) .use(markdown_it_html5_embed, html5EmbedConfig)
.use(markdown_it_container, "spoiler", spoilerConfig) .use(markdown_it_container, "spoiler", spoilerConfig)
.use(localInstanceLinkParser)
// .use(markdown_it_emoji, { // .use(markdown_it_emoji, {
// defs: emojiDefs, // defs: emojiDefs,
// }) // })

View file

@ -1,5 +1,5 @@
import { getHttpBase } from "@utils/env";
import { LemmyHttp } from "lemmy-js-client"; import { LemmyHttp } from "lemmy-js-client";
import { getHttpBase } from "../../shared/env";
import { toast } from "../../shared/toast"; import { toast } from "../../shared/toast";
import { I18NextService } from "./I18NextService"; import { I18NextService } from "./I18NextService";

View file

@ -1,10 +1,10 @@
// import Cookies from 'js-cookie'; // import Cookies from 'js-cookie';
import { isAuthPath } from "@utils/app"; import { isAuthPath } from "@utils/app";
import { isBrowser } from "@utils/browser"; import { isBrowser } from "@utils/browser";
import { isHttps } from "@utils/env";
import IsomorphicCookie from "isomorphic-cookie"; import IsomorphicCookie from "isomorphic-cookie";
import jwt_decode from "jwt-decode"; import jwt_decode from "jwt-decode";
import { LoginResponse, MyUserInfo } from "lemmy-js-client"; import { LoginResponse, MyUserInfo } from "lemmy-js-client";
import { isHttps } from "../env";
import { toast } from "../toast"; import { toast } from "../toast";
import { I18NextService } from "./I18NextService"; import { I18NextService } from "./I18NextService";

View file

@ -5,6 +5,9 @@ export default function convertCommentSortType(
): CommentSortType { ): CommentSortType {
switch (sort) { switch (sort) {
case "TopAll": case "TopAll":
case "TopHour":
case "TopSixHour":
case "TopTwelveHour":
case "TopDay": case "TopDay":
case "TopWeek": case "TopWeek":
case "TopMonth": case "TopMonth":

View file

@ -1,5 +1,6 @@
export default function restoreScrollPosition(context: any) { export default function restoreScrollPosition(context: any) {
const path: string = context.router.route.location.pathname; const path: string = context.router.route.location.pathname;
const y = Number(sessionStorage.getItem(`scrollPosition_${path}`)); const y = Number(sessionStorage.getItem(`scrollPosition_${path}`));
window.scrollTo(0, y); window.scrollTo(0, y);
} }

View file

@ -1,5 +1,6 @@
export default function saveScrollPosition(context: any) { export default function saveScrollPosition(context: any) {
const path: string = context.router.route.location.pathname; const path: string = context.router.route.location.pathname;
const y = window.scrollY; const y = window.scrollY;
sessionStorage.setItem(`scrollPosition_${path}`, y.toString()); sessionStorage.setItem(`scrollPosition_${path}`, y.toString());
} }

View file

@ -0,0 +1,5 @@
import { getHost } from "@utils/env";
export default function getBaseLocal(s = "") {
return `http${s}://${getHost()}`;
}

View file

@ -0,0 +1,14 @@
import { isBrowser } from "@utils/browser";
import { testHost } from "../../config";
export default function getExternalHost() {
return isBrowser()
? `${window.location.hostname}${
["1234", "1235"].includes(window.location.port)
? ":8536"
: window.location.port == ""
? ""
: `:${window.location.port}`
}`
: process.env.LEMMY_UI_LEMMY_EXTERNAL_HOST || testHost;
}

6
src/shared/utils/env/get-host.ts vendored Normal file
View file

@ -0,0 +1,6 @@
import { isBrowser } from "@utils/browser";
import { getExternalHost, getInternalHost } from "@utils/env";
export default function getHost() {
return isBrowser() ? getExternalHost() : getInternalHost();
}

View file

@ -0,0 +1,5 @@
import { getExternalHost, getSecure } from "@utils/env";
export default function getHttpBaseExternal() {
return `http${getSecure()}://${getExternalHost()}`;
}

View file

@ -0,0 +1,5 @@
import { getBaseLocal } from "@utils/env";
export default function getHttpBaseInternal() {
return getBaseLocal(); // Don't use secure here
}

5
src/shared/utils/env/get-http-base.ts vendored Normal file
View file

@ -0,0 +1,5 @@
import { getBaseLocal, getSecure } from "@utils/env";
export default function getHttpBase() {
return getBaseLocal(getSecure());
}

View file

@ -0,0 +1,8 @@
import { isBrowser } from "@utils/browser";
import { testHost } from "../../config";
export default function getInternalHost() {
return !isBrowser()
? process.env.LEMMY_UI_LEMMY_INTERNAL_HOST ?? testHost
: testHost; // used for local dev
}

11
src/shared/utils/env/get-secure.ts vendored Normal file
View file

@ -0,0 +1,11 @@
import { isBrowser } from "@utils/browser";
export default function getSecure() {
return (
isBrowser()
? window.location.protocol.includes("https")
: process.env.LEMMY_UI_HTTPS === "true"
)
? "s"
: "";
}

View file

@ -0,0 +1,9 @@
import { getExternalHost, getSecure } from "@utils/env";
// This is for html tags, don't include port
export default function httpExternalPath(path: string) {
return `http${getSecure()}://${getExternalHost().replace(
/:\d+/g,
""
)}${path}`;
}

23
src/shared/utils/env/index.ts vendored Normal file
View file

@ -0,0 +1,23 @@
import getBaseLocal from "./get-base-local";
import getExternalHost from "./get-external-host";
import getHost from "./get-host";
import getHttpBase from "./get-http-base";
import getHttpBaseExternal from "./get-http-base-external";
import getHttpBaseInternal from "./get-http-base-internal";
import getInternalHost from "./get-internal-host";
import getSecure from "./get-secure";
import httpExternalPath from "./http-external-path";
import isHttps from "./is-https";
export {
getBaseLocal,
getExternalHost,
getHost,
getHttpBase,
getHttpBaseExternal,
getHttpBaseInternal,
getInternalHost,
getSecure,
httpExternalPath,
isHttps,
};

5
src/shared/utils/env/is-https.ts vendored Normal file
View file

@ -0,0 +1,5 @@
import { getSecure } from "@utils/env";
export default function isHttps() {
return getSecure() === "s";
}