added background to panel itself
This commit is contained in:
parent
87173ae43f
commit
f7b3af48de
8 changed files with 122 additions and 58 deletions
9
cmd/telesrv-admin/web/dist/assets/index-BdmuVdXP.js
vendored
Normal file
9
cmd/telesrv-admin/web/dist/assets/index-BdmuVdXP.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
cmd/telesrv-admin/web/dist/index.html
vendored
4
cmd/telesrv-admin/web/dist/index.html
vendored
|
|
@ -23,8 +23,8 @@
|
|||
})();
|
||||
</script>
|
||||
|
||||
<script type="module" crossorigin src="/assets/index-C9AiUiug.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-qygZBefQ.css">
|
||||
<script type="module" crossorigin src="/assets/index-BdmuVdXP.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-dNagKGR1.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
|
|
|||
46
cmd/telesrv-admin/web/src/components/AppBackground.tsx
Normal file
46
cmd/telesrv-admin/web/src/components/AppBackground.tsx
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { useEffect, useRef } from "react";
|
||||
import { BgIcons } from "./BgIcons";
|
||||
|
||||
// The product's background: three blurred orbs that drift with the pointer,
|
||||
// and the field of slowly moving icons over them. Ported from the marketing
|
||||
// site so the console reads as the same product.
|
||||
//
|
||||
// One component for both places it appears -- the sign-in screen and the
|
||||
// workspace behind every page -- because two copies of a parallax handler is
|
||||
// how they end up subtly different.
|
||||
export function AppBackground({ className = "" }: { className?: string }) {
|
||||
const orbsRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// The orbs drift with the pointer, the same 30px parallax the site uses.
|
||||
// Written straight to the node instead of through state: this fires on every
|
||||
// mouse move, and re-rendering the tree for a background offset would be a
|
||||
// lot of work to move three blurred circles.
|
||||
useEffect(() => {
|
||||
// Someone who asked the system for less motion gets none of this. The CSS
|
||||
// drift is already disabled for them, and a JS-driven transform would walk
|
||||
// straight past that preference.
|
||||
if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
|
||||
return;
|
||||
}
|
||||
function onMove(event: MouseEvent) {
|
||||
const node = orbsRef.current;
|
||||
if (!node) return;
|
||||
const x = (event.clientX / window.innerWidth - 0.5) * 30;
|
||||
const y = (event.clientY / window.innerHeight - 0.5) * 30;
|
||||
node.style.transform = `translate(${x}px, ${y}px)`;
|
||||
}
|
||||
window.addEventListener("mousemove", onMove);
|
||||
return () => window.removeEventListener("mousemove", onMove);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={`app-background ${className}`.trim()} aria-hidden="true">
|
||||
<div className="bg-orbs" ref={orbsRef}>
|
||||
<div className="bg-orb bg-orb--1" />
|
||||
<div className="bg-orb bg-orb--2" />
|
||||
<div className="bg-orb bg-orb--3" />
|
||||
</div>
|
||||
<BgIcons />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -37,6 +37,7 @@ import { permissionBotVerificationReview, permissionServerManage, permissionAdmi
|
|||
import { type Navigate, type RouteState, routeTitle } from "../routing";
|
||||
import { ThemeSwitch } from "../theme";
|
||||
import { AddServerLinkModal } from "./AddServerLinkModal";
|
||||
import { AppBackground } from "./AppBackground";
|
||||
import { AppLink } from "./AppLink";
|
||||
|
||||
// Compresses a sorted (or unsorted) list of layer numbers into run-length
|
||||
|
|
@ -338,6 +339,9 @@ export function Shell({
|
|||
</header>
|
||||
<main className="content">{children}</main>
|
||||
</div>
|
||||
{/* Behind everything, fixed to the viewport. The sidebar and topbar paint
|
||||
over it, so it shows through the working area only. */}
|
||||
<AppBackground className="app-background--workspace" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { FormEvent } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { api, errorMessage } from "../api";
|
||||
import { BgIcons } from "../components/BgIcons";
|
||||
import { AppBackground } from "../components/AppBackground";
|
||||
import { Alert } from "../components/ui";
|
||||
import { ThemeSwitch } from "../theme";
|
||||
import type { AdminSession, PublicBranding } from "../types";
|
||||
|
|
@ -19,34 +19,11 @@ export function LoginPage({ onLogin }: { onLogin: (session: AdminSession) => voi
|
|||
// failure so the panel simply keeps its own branding.
|
||||
const [branding, setBranding] = useState<PublicBranding | null>(null);
|
||||
const [iconFailed, setIconFailed] = useState(false);
|
||||
const orbsRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
api.publicBranding().then(setBranding).catch(() => undefined);
|
||||
}, []);
|
||||
|
||||
// The orbs drift with the pointer, the same 30px parallax the marketing site
|
||||
// uses. Written straight to the node instead of through state: this fires on
|
||||
// every mouse move, and re-rendering the whole form for a background offset
|
||||
// would be a lot of work to move three blurred circles.
|
||||
useEffect(() => {
|
||||
// Someone who asked the system for less motion gets none of this: the CSS
|
||||
// drift is already disabled for them, and a JS-driven transform would walk
|
||||
// straight past that preference.
|
||||
if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
|
||||
return;
|
||||
}
|
||||
function onMove(event: MouseEvent) {
|
||||
const node = orbsRef.current;
|
||||
if (!node) return;
|
||||
const x = (event.clientX / window.innerWidth - 0.5) * 30;
|
||||
const y = (event.clientY / window.innerHeight - 0.5) * 30;
|
||||
node.style.transform = `translate(${x}px, ${y}px)`;
|
||||
}
|
||||
window.addEventListener("mousemove", onMove);
|
||||
return () => window.removeEventListener("mousemove", onMove);
|
||||
}, []);
|
||||
|
||||
const serverName = branding?.name?.trim() || "OwpenGram";
|
||||
const iconSrc = branding?.has_icon && !iconFailed ? api.publicIconURL() : "/logo.png";
|
||||
|
||||
|
|
@ -68,12 +45,7 @@ export function LoginPage({ onLogin }: { onLogin: (session: AdminSession) => voi
|
|||
|
||||
return (
|
||||
<main className="login-page">
|
||||
<div className="bg-orbs" aria-hidden="true" ref={orbsRef}>
|
||||
<div className="bg-orb bg-orb--1" />
|
||||
<div className="bg-orb bg-orb--2" />
|
||||
<div className="bg-orb bg-orb--3" />
|
||||
</div>
|
||||
<BgIcons />
|
||||
<AppBackground />
|
||||
<section className="login-panel">
|
||||
<div className="login-head">
|
||||
<div className="brand brand-elevated">
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.login-page .bg-orbs {
|
||||
.bg-orbs {
|
||||
position: absolute;
|
||||
inset: -60px;
|
||||
z-index: 0;
|
||||
|
|
@ -283,14 +283,14 @@
|
|||
will-change: transform;
|
||||
}
|
||||
|
||||
.login-page .bg-orb {
|
||||
.bg-orb {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
filter: blur(100px);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.login-page .bg-orb--1 {
|
||||
.bg-orb--1 {
|
||||
top: -15%;
|
||||
left: -10%;
|
||||
width: 700px;
|
||||
|
|
@ -299,7 +299,7 @@
|
|||
animation: loginOrbFloat1 20s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.login-page .bg-orb--2 {
|
||||
.bg-orb--2 {
|
||||
top: 25%;
|
||||
right: -15%;
|
||||
width: 600px;
|
||||
|
|
@ -308,7 +308,7 @@
|
|||
animation: loginOrbFloat2 24s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.login-page .bg-orb--3 {
|
||||
.bg-orb--3 {
|
||||
bottom: -15%;
|
||||
left: 30%;
|
||||
width: 500px;
|
||||
|
|
@ -334,15 +334,15 @@
|
|||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.login-page .bg-orb { filter: blur(60px); }
|
||||
.login-page .bg-orb--1 { width: 350px; height: 350px; }
|
||||
.login-page .bg-orb--2 { width: 300px; height: 300px; }
|
||||
.login-page .bg-orb--3 { width: 250px; height: 250px; }
|
||||
.bg-orb { filter: blur(60px); }
|
||||
.bg-orb--1 { width: 350px; height: 350px; }
|
||||
.bg-orb--2 { width: 300px; height: 300px; }
|
||||
.bg-orb--3 { width: 250px; height: 250px; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.login-page .bg-orb { animation: none; }
|
||||
.login-page .bg-orbs { transition: none; }
|
||||
.bg-orb { animation: none; }
|
||||
.bg-orbs { transition: none; }
|
||||
}
|
||||
|
||||
.login-page .login-panel {
|
||||
|
|
@ -491,9 +491,8 @@
|
|||
|
||||
/* The drifting icon field behind the sign-in card. Sits above the blurred orbs
|
||||
and below the panel, so the two background layers read as one scene.
|
||||
Positioned absolutely inside .login-page rather than fixed like the site's
|
||||
version, because here it belongs to one screen rather than the whole app. */
|
||||
.login-page .bg-icons {
|
||||
Fills whichever .app-background contains it. */
|
||||
.bg-icons {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
|
|
@ -502,9 +501,52 @@
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
.login-page .bg-icon {
|
||||
.bg-icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
|
||||
/* The background wrapper. On the sign-in screen it fills that screen; behind
|
||||
the workspace it is pinned to the viewport so it does not scroll away under
|
||||
a long page, and so the icons -- which bounce off window bounds -- stay
|
||||
inside the area they are drawn in. */
|
||||
.app-background {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.app-background--workspace {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
/* Quieter behind real content than behind a lone sign-in card: the panel is
|
||||
dense with tables and numbers, and the background has to stay background. */
|
||||
.app-background--workspace .bg-icons {
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.app-background--workspace .bg-orb {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* The chrome paints over the background: the sidebar hides the part of it that
|
||||
would otherwise show through the navigation, which is also why the wrapper
|
||||
can span the whole viewport instead of hard-coding the sidebar's width.
|
||||
Only z-index is set here -- the sidebar is already sticky, and restating
|
||||
position would be a chance to change it by accident. The topbar needs
|
||||
nothing: it carries z-index 20 of its own, and a rule here would out-specify
|
||||
its own "position: sticky" and quietly stop it sticking. */
|
||||
.shell > .sidebar {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.workspace > .content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue