mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-12-22 19:01:26 +00:00
Make blur work correctly
This commit is contained in:
parent
1b4903d732
commit
ce723776a5
14 changed files with 86 additions and 103 deletions
|
@ -42,6 +42,7 @@
|
|||
"classnames": "^2.5.1",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"cookie": "^0.6.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"css-loader": "^6.10.0",
|
||||
"date-fns": "^3.6.0",
|
||||
|
@ -94,6 +95,7 @@
|
|||
"@types/autosize": "^4.0.3",
|
||||
"@types/bootstrap": "^5.2.10",
|
||||
"@types/cookie": "^0.6.0",
|
||||
"@types/cookie-parser": "^1.4.7",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/html-to-text": "^9.0.4",
|
||||
"@types/lodash.isequal": "^4.5.8",
|
||||
|
|
|
@ -59,6 +59,9 @@ importers:
|
|||
cookie:
|
||||
specifier: ^0.6.0
|
||||
version: 0.6.0
|
||||
cookie-parser:
|
||||
specifier: ^1.4.6
|
||||
version: 1.4.6
|
||||
copy-webpack-plugin:
|
||||
specifier: ^12.0.2
|
||||
version: 12.0.2(webpack@5.91.0(webpack-cli@5.1.4))
|
||||
|
@ -210,6 +213,9 @@ importers:
|
|||
'@types/cookie':
|
||||
specifier: ^0.6.0
|
||||
version: 0.6.0
|
||||
'@types/cookie-parser':
|
||||
specifier: ^1.4.7
|
||||
version: 1.4.7
|
||||
'@types/express':
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
|
@ -1207,6 +1213,9 @@ packages:
|
|||
'@types/connect@3.4.38':
|
||||
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
|
||||
|
||||
'@types/cookie-parser@1.4.7':
|
||||
resolution: {integrity: sha512-Fvuyi354Z+uayxzIGCwYTayFKocfV7TuDYZClCdIP9ckhvAu/ixDtCB6qx2TT0FKjPLf1f3P/J1rgf6lPs64mw==}
|
||||
|
||||
'@types/cookie@0.6.0':
|
||||
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
||||
|
||||
|
@ -1856,9 +1865,17 @@ packages:
|
|||
convert-source-map@2.0.0:
|
||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||
|
||||
cookie-parser@1.4.6:
|
||||
resolution: {integrity: sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
cookie-signature@1.0.6:
|
||||
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
|
||||
|
||||
cookie@0.4.1:
|
||||
resolution: {integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
cookie@0.6.0:
|
||||
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
@ -5742,6 +5759,10 @@ snapshots:
|
|||
dependencies:
|
||||
'@types/node': 20.11.30
|
||||
|
||||
'@types/cookie-parser@1.4.7':
|
||||
dependencies:
|
||||
'@types/express': 4.17.21
|
||||
|
||||
'@types/cookie@0.6.0': {}
|
||||
|
||||
'@types/eslint-scope@3.7.7':
|
||||
|
@ -6479,8 +6500,15 @@ snapshots:
|
|||
|
||||
convert-source-map@2.0.0: {}
|
||||
|
||||
cookie-parser@1.4.6:
|
||||
dependencies:
|
||||
cookie: 0.4.1
|
||||
cookie-signature: 1.0.6
|
||||
|
||||
cookie-signature@1.0.6: {}
|
||||
|
||||
cookie@0.4.1: {}
|
||||
|
||||
cookie@0.6.0: {}
|
||||
|
||||
copy-webpack-plugin@11.0.0(webpack@5.91.0(webpack-cli@5.1.4)):
|
||||
|
|
|
@ -461,3 +461,11 @@ br.big {
|
|||
.totp-link {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
#app[data-adult-consent] {
|
||||
filter: blur(10px);
|
||||
-webkit-filter: blur(10px);
|
||||
-moz-filter: blur(10px);
|
||||
-o-filter: blur(10px);
|
||||
-ms-filter: blur(10px);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { initializeSite } from "@utils/app";
|
||||
import { hydrate } from "inferno-hydrate";
|
||||
import { BrowserRouter } from "inferno-router";
|
||||
import { App } from "../shared/components/app/app";
|
||||
import App from "../shared/components/app/app";
|
||||
import { lazyHighlightjs } from "../shared/lazy-highlightjs";
|
||||
import { loadUserLanguage } from "../shared/services/I18NextService";
|
||||
import { verifyDynamicImports } from "../shared/dynamic-imports";
|
||||
|
|
|
@ -6,7 +6,7 @@ import { StaticRouter, matchPath } from "inferno-router";
|
|||
import { Match } from "inferno-router/dist/Route";
|
||||
import { renderToString } from "inferno-server";
|
||||
import { GetSiteResponse, LemmyHttp } from "lemmy-js-client";
|
||||
import { App } from "../../shared/components/app/app";
|
||||
import App from "../../shared/components/app/app";
|
||||
import {
|
||||
InitialFetchRequest,
|
||||
IsoDataOptionalSite,
|
||||
|
@ -28,6 +28,7 @@ import {
|
|||
} from "../../shared/services/";
|
||||
import { parsePath } from "history";
|
||||
import { getQueryString } from "@utils/helpers";
|
||||
import { adultConsentCookieKey } from "../../shared/config";
|
||||
|
||||
export default async (req: Request, res: Response) => {
|
||||
try {
|
||||
|
@ -142,6 +143,9 @@ export default async (req: Request, res: Response) => {
|
|||
site_res: site,
|
||||
routeData,
|
||||
errorPageData,
|
||||
showAdultConsentModal:
|
||||
!!site?.site_view.site.content_warning &&
|
||||
!(site.my_user || req.cookies[adultConsentCookieKey]),
|
||||
};
|
||||
|
||||
const wrapper = (
|
||||
|
|
|
@ -14,8 +14,10 @@ import ThemesListHandler from "./handlers/themes-list-handler";
|
|||
import { setCacheControl, setDefaultCsp } from "./middleware";
|
||||
import CodeThemeHandler from "./handlers/code-theme-handler";
|
||||
import { verifyDynamicImports } from "../shared/dynamic-imports";
|
||||
import cookieParser from "cookie-parser";
|
||||
|
||||
const server = express();
|
||||
server.use(cookieParser());
|
||||
|
||||
const [hostname, port] = process.env["LEMMY_UI_HOST"]
|
||||
? process.env["LEMMY_UI_HOST"].split(":")
|
||||
|
|
|
@ -75,37 +75,19 @@ export async function createSsrHtml(
|
|||
.map(x => `<link rel="preload" as="script" href="${x}" />`)
|
||||
.join("");
|
||||
|
||||
// Blurring has to happen even if all style sheets fail to load.
|
||||
const blurStyles = !site?.site_view.site.content_warning
|
||||
? ""
|
||||
: `
|
||||
<style>
|
||||
[data-lemmy-blur=on] #app > :not(#adultConsentModal) {
|
||||
filter: blur(10px);
|
||||
pointer-events: none; ${/* prevent accidental link clicks */ ""}
|
||||
}
|
||||
html[data-lemmy-blur=on] {
|
||||
overflow: hidden; ${/* Firefox on Android allows otherwise to peek behind the urlbar */ ""}
|
||||
}
|
||||
</style>`;
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html ${helmet.htmlAttributes.toString()}>
|
||||
<head>
|
||||
<script nonce="${cspNonce}">
|
||||
window.isoData = ${serialize(isoData)};
|
||||
|
||||
if (!document.documentElement.hasAttribute("data-bs-theme")) {
|
||||
const light = window.matchMedia("(prefers-color-scheme: light)").matches;
|
||||
document.documentElement.setAttribute("data-bs-theme", light ? "light" : "dark");
|
||||
}
|
||||
if (document.documentElement.hasAttribute("data-lemmy-blur")) {
|
||||
const consent = localStorage.getItem("adult-consent") === "true";
|
||||
document.documentElement.setAttribute("data-lemmy-blur", consent ? "off" : "on");
|
||||
}
|
||||
</script>
|
||||
${blurStyles}
|
||||
${lazyScripts}
|
||||
<script nonce="${cspNonce}">window.isoData = ${serialize(isoData)}</script>
|
||||
|
||||
<!-- A remote debugging utility for mobile -->
|
||||
${erudaStr}
|
||||
|
|
|
@ -13,39 +13,39 @@ import { Navbar } from "./navbar";
|
|||
import "./styles.scss";
|
||||
import { Theme } from "./theme";
|
||||
import AnonymousGuard from "../common/anonymous-guard";
|
||||
import { destroyTippy, setupTippy } from "../../tippy";
|
||||
import AdultConsentModal from "../common/adult-consent-modal";
|
||||
|
||||
export class App extends Component<any, any> {
|
||||
function handleJumpToContent(event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
export default class App extends Component<any, any> {
|
||||
private isoData: IsoDataOptionalSite = setIsoData(this.context);
|
||||
private readonly mainContentRef = createRef<HTMLElement>();
|
||||
private readonly rootRef = createRef<HTMLDivElement>();
|
||||
|
||||
componentDidMount(): void {
|
||||
setupTippy(this.rootRef);
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
destroyTippy();
|
||||
}
|
||||
|
||||
handleJumpToContent(event) {
|
||||
event.preventDefault();
|
||||
this.mainContentRef.current?.focus();
|
||||
}
|
||||
|
||||
render() {
|
||||
const siteRes = this.isoData.site_res;
|
||||
const siteView = siteRes?.site_view;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Provider i18next={I18NextService.i18n}>
|
||||
<div id="app" className="lemmy-site" ref={this.rootRef}>
|
||||
<Provider i18next={I18NextService.i18n}>
|
||||
{/* This fragment is required to avoid an SSR error*/}
|
||||
<>
|
||||
{this.isoData.showAdultConsentModal && (
|
||||
<AdultConsentModal
|
||||
contentWarning={siteView!.site.content_warning!}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
id="app"
|
||||
className="lemmy-site"
|
||||
ref={this.rootRef}
|
||||
data-adult-consent={this.isoData.showAdultConsentModal}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="btn skip-link bg-light position-absolute start-0 z-3"
|
||||
onClick={linkEvent(this, this.handleJumpToContent)}
|
||||
onClick={linkEvent(this, handleJumpToContent)}
|
||||
>
|
||||
{I18NextService.i18n.t("jump_to_content", "Jump to content")}
|
||||
</button>
|
||||
|
@ -53,11 +53,6 @@ export class App extends Component<any, any> {
|
|||
<Theme defaultTheme={siteView.local_site.default_theme} />
|
||||
)}
|
||||
<Navbar siteRes={siteRes} />
|
||||
{siteRes?.site_view.site.content_warning && (
|
||||
<AdultConsentModal
|
||||
contentWarning={siteRes.site_view.site.content_warning}
|
||||
/>
|
||||
)}
|
||||
<div className="mt-4 p-0 fl-1">
|
||||
<Switch>
|
||||
{routes.map(
|
||||
|
@ -117,8 +112,8 @@ export class App extends Component<any, any> {
|
|||
</div>
|
||||
<Footer site={siteRes} />
|
||||
</div>
|
||||
</Provider>
|
||||
</>
|
||||
</>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import { Component, LinkedEvent, createRef, linkEvent } from "inferno";
|
||||
import { modalMixin } from "../mixins/modal-mixin";
|
||||
import { adultConsentLocalStorageKey } from "../../config";
|
||||
import { setIsoData } from "@utils/app";
|
||||
import { IsoDataOptionalSite } from "../../interfaces";
|
||||
import { adultConsentCookieKey } from "../../config";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { I18NextService } from "../../services";
|
||||
import { isBrowser } from "@utils/browser";
|
||||
import { Helmet } from "inferno-helmet";
|
||||
import { isHttps } from "@utils/env";
|
||||
import { IsoData } from "../../interfaces";
|
||||
import { setIsoData } from "@utils/app";
|
||||
|
||||
interface AdultConsentModalProps {
|
||||
contentWarning: string;
|
||||
|
@ -35,13 +34,6 @@ class AdultConsentModalInner extends Component<AdultConsentModalProps, any> {
|
|||
data-bs-backdrop="static"
|
||||
ref={this.modalDivRef}
|
||||
>
|
||||
<Helmet
|
||||
htmlAttributes={{
|
||||
// There is a hack included in create-ssr-html that fixes this
|
||||
// attribute early based on localStorage.
|
||||
"data-lemmy-blur": this.props.show ? "on" : "off",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="modal-dialog modal-fullscreen-sm-down"
|
||||
data-bs-backdrop="static"
|
||||
|
@ -96,7 +88,8 @@ interface AdultConsentModalState {
|
|||
}
|
||||
|
||||
function handleAdultConsent(i: AdultConsentModal) {
|
||||
localStorage.setItem(adultConsentLocalStorageKey, "true");
|
||||
document.cookie = `${adultConsentCookieKey}=true; Path=/; SameSite=Strict${isHttps() ? "; Secure" : ""}`;
|
||||
document.querySelector("#app")?.removeAttribute("data-adult-consent");
|
||||
i.setState({ show: false });
|
||||
}
|
||||
|
||||
|
@ -112,32 +105,16 @@ function handleAdultConsentGoBack(i: AdultConsentModal) {
|
|||
}
|
||||
|
||||
export default class AdultConsentModal extends Component<
|
||||
{ contentWarning: string },
|
||||
Pick<AdultConsentModalProps, "contentWarning">,
|
||||
AdultConsentModalState
|
||||
> {
|
||||
private isoData: IsoDataOptionalSite = setIsoData(this.context);
|
||||
private isoData: IsoData = setIsoData(this.context);
|
||||
redirectTimeout: NodeJS.Timeout;
|
||||
state: AdultConsentModalState = {
|
||||
show: false,
|
||||
show: this.isoData.showAdultConsentModal,
|
||||
redirectCountdown: Infinity,
|
||||
};
|
||||
|
||||
componentWillMount() {
|
||||
const siteRes = this.isoData.site_res;
|
||||
|
||||
if (siteRes?.site_view.site.content_warning) {
|
||||
if (isBrowser()) {
|
||||
if (localStorage.getItem(adultConsentLocalStorageKey) !== "true") {
|
||||
this.setState({ show: true });
|
||||
} else {
|
||||
this.setState({ show: false });
|
||||
}
|
||||
} else {
|
||||
this.setState({ show: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.state.redirectCountdown === 0) {
|
||||
this.context.router.history.back();
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import classNames from "classnames";
|
||||
import { Component } from "inferno";
|
||||
|
||||
import { setIsoData } from "@utils/app";
|
||||
import { IsoDataOptionalSite } from "shared/interfaces";
|
||||
import { shouldBlurNsfw } from "@utils/helpers";
|
||||
import { UserService } from "../../services";
|
||||
|
||||
const iconThumbnailSize = 96;
|
||||
const thumbnailSize = 256;
|
||||
|
@ -21,8 +19,6 @@ interface PictrsImageProps {
|
|||
}
|
||||
|
||||
export class PictrsImage extends Component<PictrsImageProps, any> {
|
||||
private isoData: IsoDataOptionalSite = setIsoData(this.context);
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
@ -31,7 +27,10 @@ export class PictrsImage extends Component<PictrsImageProps, any> {
|
|||
const { src, icon, iconOverlay, banner, thumbnail, nsfw, pushup, cardTop } =
|
||||
this.props;
|
||||
|
||||
const blurImage = nsfw && shouldBlurNsfw(this.isoData.site_res);
|
||||
const blurImage =
|
||||
nsfw &&
|
||||
(UserService.Instance.myUserInfo?.local_user_view.local_user.blur_nsfw ??
|
||||
true);
|
||||
|
||||
return (
|
||||
<picture>
|
||||
|
|
|
@ -28,7 +28,7 @@ export const fetchLimit = 20;
|
|||
export const relTags = "noopener nofollow";
|
||||
export const emDash = "\u2014";
|
||||
export const authCookieName = "jwt";
|
||||
export const adultConsentLocalStorageKey = "adult-consent";
|
||||
export const adultConsentCookieKey = "adultConsent";
|
||||
|
||||
// No. of max displayed communities per
|
||||
// page on route "/communities"
|
||||
|
|
|
@ -16,6 +16,7 @@ export interface IsoData<T extends RouteData = any> {
|
|||
routeData: T;
|
||||
site_res: GetSiteResponse;
|
||||
errorPageData?: ErrorPageData;
|
||||
showAdultConsentModal: boolean;
|
||||
}
|
||||
|
||||
export type IsoDataOptionalSite<T extends RouteData = any> = Partial<
|
||||
|
|
|
@ -25,7 +25,6 @@ import validTitle from "./valid-title";
|
|||
import validURL from "./valid-url";
|
||||
import dedupByProperty from "./dedup-by-property";
|
||||
import getApubName from "./apub-name";
|
||||
import shouldBlurNsfw from "./should-blur-nsfw";
|
||||
|
||||
export {
|
||||
capitalizeFirstLetter,
|
||||
|
@ -55,5 +54,4 @@ export {
|
|||
validURL,
|
||||
dedupByProperty,
|
||||
getApubName,
|
||||
shouldBlurNsfw,
|
||||
};
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
import { SiteResponse } from "lemmy-js-client";
|
||||
import { adultConsentLocalStorageKey } from "../../config";
|
||||
import { UserService } from "../../services";
|
||||
import { isBrowser } from "@utils/browser";
|
||||
|
||||
export default function shouldBlurNsfw(siteRes?: SiteResponse) {
|
||||
return siteRes?.site_view.site.content_warning
|
||||
? !(
|
||||
(isBrowser() && localStorage.getItem(adultConsentLocalStorageKey)) ||
|
||||
UserService.Instance.myUserInfo
|
||||
)
|
||||
: UserService.Instance.myUserInfo?.local_user_view.local_user.blur_nsfw;
|
||||
}
|
Loading…
Reference in a new issue