update popup modal logic

This commit is contained in:
Pas 2025-03-29 12:20:04 -06:00
parent 520c32235c
commit a02ea7c684
4 changed files with 230 additions and 284 deletions

View file

@ -1,7 +1,12 @@
import { ReactNode, useCallback } from "react";
import classNames from "classnames";
import { ReactNode, useCallback, useEffect } from "react";
import { Helmet } from "react-helmet-async";
import { IconPatch } from "@/components/buttons/IconPatch";
import { Icons } from "@/components/Icon";
import { OverlayPortal } from "@/components/overlays/OverlayDisplay";
import { Flare } from "@/components/utils/Flare";
import { Heading2 } from "@/components/utils/Text";
import { useQueryParam } from "@/hooks/useQueryParams";
export function useModal(id: string) {
@ -40,3 +45,74 @@ export function Modal(props: { id: string; children?: ReactNode }) {
</OverlayPortal>
);
}
export function FancyModal(props: {
id: string;
children?: ReactNode;
title?: string;
size?: "md" | "xl";
oneTime?: boolean;
}) {
const modal = useModal(props.id);
useEffect(() => {
if (props.oneTime) {
const isDismissed = localStorage.getItem(`modal-${props.id}-dismissed`);
if (!isDismissed) {
modal.show();
}
}
}, [modal, props.id, props.oneTime]);
const handleClose = () => {
if (props.oneTime) {
localStorage.setItem(`modal-${props.id}-dismissed`, "true");
}
modal.hide();
};
return (
<OverlayPortal darken close={handleClose} show={modal.isShown}>
<Helmet>
<html data-no-scroll />
</Helmet>
<div className="flex absolute inset-0 items-center justify-center">
<Flare.Base
className={classNames(
"group -m-[0.705em] rounded-3xl bg-background-main transition-colors duration-300 focus:relative focus:z-10",
"w-full mx-4 p-6 bg-mediaCard-hoverBackground bg-opacity-60 backdrop-filter backdrop-blur-lg shadow-lg",
props.size === "md" ? "max-w-md" : "max-w-2xl",
)}
>
<div className="transition-transform duration-300 overflow-y-scroll max-h-[90dvh] scrollbar-none">
<Flare.Light
flareSize={300}
cssColorVar="--colors-mediaCard-hoverAccent"
backgroundClass="bg-mediaCard-hoverBackground duration-100"
className="rounded-3xl bg-background-main group-hover:opacity-100"
/>
<Flare.Child className="pointer-events-auto relative mb-2p-[0.4em] transition-transform duration-300">
<div className="flex justify-between items-center mb-4">
{props.title && (
<Heading2 className="!mt-0 !mb-0 pr-6">
{props.title}
</Heading2>
)}
<button
type="button"
className="text-s font-semibold text-type-secondary hover:text-white transition-transform hover:scale-95"
onClick={handleClose}
>
<IconPatch icon={Icons.X} />
</button>
</div>
<div className="text-lg text-type-secondary">
{props.children}
</div>
</Flare.Child>
</div>
</Flare.Base>
</div>
</OverlayPortal>
);
}

View file

@ -50,6 +50,7 @@ export function HomePage() {
const s = useSearch(search);
const [showBookmarks, setShowBookmarks] = useState(false);
const [showWatching, setShowWatching] = useState(false);
// const modal = useModal("notice");
const handleClick = (path: To) => {
window.scrollTo(0, 0);
@ -58,48 +59,12 @@ export function HomePage() {
const enableDiscover = usePreferencesStore((state) => state.enableDiscover);
/*
// Safari Notice
const [showModal, setShowModal] = useState(() => {
const isSafari =
typeof navigator !== "undefined" &&
/Safari/.test(navigator.userAgent) &&
!/Chrome/.test(navigator.userAgent);
const isMac =
typeof navigator !== "undefined" && /Mac/.test(navigator.platform);
const isIOS =
typeof navigator !== "undefined" &&
/iPhone|iPad|iPod/.test(navigator.userAgent);
return isSafari && (isMac || isIOS);
});
*/
/* One time notice
const [showModal, setShowModal] = useState(false);
useEffect(() => {
const isDismissed = localStorage.getItem("popupDismissed");
if (!isDismissed) {
setShowModal(true);
}
}, []);
const handleCloseModal = () => {
setShowModal(false);
localStorage.setItem("popupDismissed", "true");
};
*/
// const { loggedIn } = useAuth(); // Adjust padding for popup show button based on logged in state
return (
<HomeLayout showBg={showBg}>
{/* Popup show button
<a
onClick={() => setShowModal(true)}
{/* <a
onClick={() => modal.show()}
className={` text-white tabbable rounded-full z-50 fixed top-5 ${
loggedIn
? "right-[7.5rem] lg:right-[12.5rem] lg:text-2xl"
@ -110,8 +75,7 @@ export function HomePage() {
<IconPill icon={Icons.WARNING}>
<span className="font-bold select-none">READ</span>
</IconPill>
</a>
*/}
</a> */}
<div className="mb-16 sm:mb-24">
<Helmet>
<style type="text/css">{`
@ -122,100 +86,96 @@ export function HomePage() {
<title>{t("global.name")}</title>
</Helmet>
{/* Popup
{showModal && (
<PopupModal
styles="max-w-2xl" // max-w-md for short
title="Were changing our backend server!"
message={
<div>
<p>
On <strong>January 8th</strong>, the backend server will
change from:
</p>
<p>
<strong>server.vidbinge.com</strong> {" "}
<strong>server.fifthwit.tech</strong>
</p>
<br />
<p>
You will need to <strong>migrate your account </strong> to the
new server or choose to continue using the old server by
updating your settings.
</p>
<br />
<p>
<strong>What You Need to Know:</strong>
</p>
<ul>
<li>
1. <strong>Migrating Your Account:</strong> Your data (e.g.,
bookmarks) will not be automatically transferred. Youll
need to migrate your account from the settings page. Or from
below.
</li>
<li>
2. <strong>Staying on the Old Server:</strong> If you dont
want to change to the new server, your data will remain safe
on <strong>server.vidbinge.com</strong>. You can change the
Backend URL in your settings to
&quot;https://server.vidbinge.com&quot;.
</li>
</ul>
<br />
<p>
<strong>Steps to Move Your Data:</strong>
</p>
<ol>
<li>
1. Log into your account on{" "}
<strong>server.vidbinge.com</strong>.
</li>
<li>
(If you already are logged in, press here:{" "}
<a href="/migration" className="text-type-link">
Migrate my data.
</a>
)
</li>
<li>
2. Go to the <strong>Settings</strong> page.
</li>
<li>
3. Scroll down to{" "}
<strong>Connections &gt; Custom Server</strong>.
</li>
<li>
3. Press the &quot;Migrate my data to a new server.&quot;
button.
</li>
<li>
4. Enter the new server url:{" "}
<strong>https://server.fifthwit.tech</strong> and press
&quot;Migrate&quot;.
</li>
<li>5. Login to your account with the same passphrase!</li>
</ol>
<br />
<p>
Thank you for your understanding and support during this
transition! If you have questions or need help, feel free to
reach out on the{" "}
<a
href="https://discord.com/invite/7z6znYgrTG"
target="_blank"
rel="noopener noreferrer"
className="text-type-link"
>
P-Stream Discord
</a>
!
</p>
</div>
}
onClose={handleCloseModal}
/>
)}
{/* Popup
<FancyModal
id="notice"
title="We're changing our backend server!"
oneTime
>
<div>
<p>
On <strong>January 8th</strong>, the backend server will change
from:
</p>
<p>
<strong>server.vidbinge.com</strong> {" "}
<strong>server.fifthwit.tech</strong>
</p>
<br />
<p>
You will need to <strong>migrate your account </strong> to the new
server or choose to continue using the old server by updating your
settings.
</p>
<br />
<p>
<strong>What You Need to Know:</strong>
</p>
<ul>
<li>
1. <strong>Migrating Your Account:</strong> Your data (e.g.,
bookmarks) will not be automatically transferred. You&apos;ll
need to migrate your account from the settings page. Or from
below.
</li>
<li>
2. <strong>Staying on the Old Server:</strong> If you don&apos;t
want to change to the new server, your data will remain safe on{" "}
<strong>server.vidbinge.com</strong>. You can change the Backend
URL in your settings to &quot;https://server.vidbinge.com&quot;.
</li>
</ul>
<br />
<p>
<strong>Steps to Move Your Data:</strong>
</p>
<ol>
<li>
1. Log into your account on <strong>server.vidbinge.com</strong>
.
</li>
<li>
(If you already are logged in, press here:{" "}
<a href="/migration" className="text-type-link">
Migrate my data.
</a>
)
</li>
<li>
2. Go to the <strong>Settings</strong> page.
</li>
<li>
3. Scroll down to{" "}
<strong>Connections &gt; Custom Server</strong>.
</li>
<li>
3. Press the &quot;Migrate my data to a new server.&quot;
button.
</li>
<li>
4. Enter the new server url:{" "}
<strong>https://server.fifthwit.tech</strong> and press
&quot;Migrate&quot;.
</li>
<li>5. Login to your account with the same passphrase!</li>
</ol>
<br />
<p>
Thank you for your understanding and support during this
transition! If you have questions or need help, feel free to reach
out on the{" "}
<a
href="https://discord.com/invite/7z6znYgrTG"
target="_blank"
rel="noopener noreferrer"
className="text-type-link"
>
P-Stream Discord
</a>
!
</p>
</div>
</FancyModal>
*/}
<HeroPart searchParams={searchParams} setIsSticky={setShowBg} />

View file

@ -8,7 +8,12 @@ import { SettingsCard } from "@/components/layout/SettingsCard";
import { Stepper } from "@/components/layout/Stepper";
import { BiggerCenterContainer } from "@/components/layout/ThinContainer";
import { VerticalLine } from "@/components/layout/VerticalLine";
import { Modal, ModalCard, useModal } from "@/components/overlays/Modal";
import {
FancyModal,
Modal,
ModalCard,
useModal,
} from "@/components/overlays/Modal";
import {
StatusCircle,
StatusCircleProps,
@ -33,7 +38,6 @@ import { conf } from "@/setup/config";
import { useAuthStore } from "@/stores/auth";
import { getProxyUrls } from "@/utils/proxyUrls";
import { PopupModal } from "../parts/home/PopupModal";
import { Status, testFebboxToken } from "../parts/settings/SetupPart";
async function getFebboxTokenStatus(febboxToken: string | null) {
@ -179,6 +183,7 @@ export function FEDAPISetup() {
export function OnboardingPage() {
const navigate = useNavigateOnboarding();
const skipModal = useModal("skip");
const infoModal = useModal("info");
const { completeAndRedirect } = useRedirectBack();
const { t } = useTranslation();
const noProxies = getProxyUrls().length === 0;
@ -189,12 +194,6 @@ export function OnboardingPage() {
!/Chrome/.test(navigator.userAgent) &&
!/Edg/.test(navigator.userAgent);
const [showModal, setShowModal] = useState(false);
const handleCloseModal = () => {
setShowModal(false);
};
return (
<MinimalPageLayout>
<PageTitle subpage k="global.pages.onboarding" />
@ -216,68 +215,59 @@ export function OnboardingPage() {
</div>
</ModalCard>
</Modal>
{showModal && (
<PopupModal
styles="max-w-2xl" // max-w-md for short max-w-2xl long
title="Understanding a setup"
message={
<div>
<p>
P-Stream doesn&apos;t host videos. It relies on third-party
websites for content, so you need to choose how it connects to
those sites.
<FancyModal id={infoModal.id} title="Understanding a setup" size="xl">
<div>
<p>
P-Stream doesn&apos;t host videos. It relies on third-party websites
for content, so you need to choose how it connects to those sites.
<br />
<br />
<strong>Your Options:</strong>
<br />
<strong>1. Extension (Recommended)</strong>
<br />
The extension gives you access to the most sources. It acts as a
local proxy and can handle sites that need special cookies or
headers to load.
<br />
<br />
<strong>2. Proxy</strong>
<br />
The proxy scrapes media from other websites. It bypasses browser
restrictions (like CORS) to allow scraping.
<br />
<br />
<strong>3. Default Setup</strong>
<br />
Uses P-Stream&apos;s built-in proxy. It&apos;s the easiest option
but might be slower due to shared bandwidth.
<br />
<br />
{conf().ALLOW_FEBBOX_KEY && (
<>
<strong>Optional FED API (Febbox) UI token</strong>
<br />
Bringing your own Febbox account allows you to unlock FED API,
our best source with 4K quality, Dolby Atmos, the most content,
and the best (fastest) load times. This the highly recommended!
<br />
<br />
<strong>Your Options:</strong>
<br />
<strong>1. Extension (Recommended)</strong>
<br />
The extension gives you access to the most sources. It acts as a
local proxy and can handle sites that need special cookies or
headers to load.
<br />
<br />
<strong>2. Proxy</strong>
<br />
The proxy scrapes media from other websites. It bypasses browser
restrictions (like CORS) to allow scraping.
<br />
<br />
<strong>3. Default Setup</strong>
<br />
Uses P-Stream&apos;s built-in proxy. It&apos;s the easiest
option but might be slower due to shared bandwidth.
<br />
<br />
{conf().ALLOW_FEBBOX_KEY && (
<>
<strong>Optional FED API (Febbox) UI token</strong>
<br />
Bringing your own Febbox account allows you to unlock FED
API, our best source with 4K quality, Dolby Atmos, the most
content, and the best (fastest) load times. This the highly
recommended!
<br />
<br />
</>
)}
If you have more questions on how this works, feel free to ask
on the{" "}
<a
href="https://discord.com/invite/7z6znYgrTG"
target="_blank"
rel="noopener noreferrer"
className="text-type-link"
>
P-Stream Discord
</a>{" "}
server!
</p>
</div>
}
onClose={handleCloseModal}
/>
)}
</>
)}
If you have more questions on how this works, feel free to ask on
the{" "}
<a
href="https://discord.com/invite/7z6znYgrTG"
target="_blank"
rel="noopener noreferrer"
className="text-type-link"
>
P-Stream Discord
</a>{" "}
server!
</p>
</div>
</FancyModal>
<BiggerCenterContainer>
<Stepper steps={2} current={1} className="mb-12" />
<Heading2 className="!mt-0 !text-3xl">
@ -287,7 +277,7 @@ export function OnboardingPage() {
{t("onboarding.start.explainer")}
<div
className="pt-4 flex cursor-pointer items-center text-type-link"
onClick={() => setShowModal(true)}
onClick={() => infoModal.show()}
>
<p>More info</p>
<Icon className="pl-2" icon={Icons.CIRCLE_QUESTION} />

View file

@ -1,80 +0,0 @@
import classNames from "classnames";
import { ReactNode, useEffect } from "react";
import { IconPatch } from "@/components/buttons/IconPatch";
import { Icons } from "@/components/Icon";
import { Flare } from "@/components/utils/Flare";
import { Heading2 } from "@/components/utils/Text";
export interface PopupModalProps {
title: string;
message: ReactNode;
closable?: boolean;
onClose?: () => void;
styles?: string;
}
export function PopupModal({
title,
message,
closable = true,
onClose,
styles,
}: PopupModalProps) {
useEffect(() => {
document.body.style.overflow = "hidden";
return () => {
document.body.style.overflow = "";
};
}, []);
return (
<div
className={classNames(
"fixed inset-0 z-[100] flex items-center justify-center",
"bg-background-main bg-opacity-75 backdrop-filter backdrop-blur-sm",
"transition-opacity duration-400",
"pointer-events-auto",
)}
onClick={onClose}
>
<Flare.Base
className={classNames(
"group -m-[0.705em] rounded-3xl bg-background-main transition-colors duration-300 focus:relative focus:z-10",
"fixed top-0 left-0 right-0 z-50 p-6 bg-mediaCard-hoverBackground bg-opacity-60 backdrop-filter backdrop-blur-lg shadow-lg mx-auto",
)}
>
<div
className={classNames(
"transition-transform duration-300",
"overflow-y-scroll max-h-[90dvh] md:max-h-[90dvh] scrollbar-none",
styles,
)}
>
<Flare.Light
flareSize={300}
cssColorVar="--colors-mediaCard-hoverAccent"
backgroundClass="bg-mediaCard-hoverBackground duration-100"
className="rounded-3xl bg-background-main group-hover:opacity-100"
/>
<Flare.Child className="pointer-events-auto relative mb-2p-[0.4em] transition-transform duration-300">
<div className="flex justify-between items-center mb-4">
<Heading2 className="!mt-0 !mb-0 pr-6">{title}</Heading2>
{closable && (
<button
type="button"
className="fixed right-4 text-s font-semibold text-type-secondary hover:text-white transition-transform hover:scale-110"
onClick={onClose}
>
<IconPatch icon={Icons.X} />
</button>
)}
</div>
<p className="text-lg text-type-secondary">{message}</p>
</Flare.Child>
</div>
</Flare.Base>
</div>
);
}