pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

update popup modal logic

Pas a02ea7c6 520c3223

+229 -283
+77 -1
src/components/overlays/Modal.tsx
··· 1 - import { ReactNode, useCallback } from "react"; 1 + import classNames from "classnames"; 2 + import { ReactNode, useCallback, useEffect } from "react"; 2 3 import { Helmet } from "react-helmet-async"; 3 4 5 + import { IconPatch } from "@/components/buttons/IconPatch"; 6 + import { Icons } from "@/components/Icon"; 4 7 import { OverlayPortal } from "@/components/overlays/OverlayDisplay"; 8 + import { Flare } from "@/components/utils/Flare"; 9 + import { Heading2 } from "@/components/utils/Text"; 5 10 import { useQueryParam } from "@/hooks/useQueryParams"; 6 11 7 12 export function useModal(id: string) { ··· 40 45 </OverlayPortal> 41 46 ); 42 47 } 48 + 49 + export function FancyModal(props: { 50 + id: string; 51 + children?: ReactNode; 52 + title?: string; 53 + size?: "md" | "xl"; 54 + oneTime?: boolean; 55 + }) { 56 + const modal = useModal(props.id); 57 + 58 + useEffect(() => { 59 + if (props.oneTime) { 60 + const isDismissed = localStorage.getItem(`modal-${props.id}-dismissed`); 61 + if (!isDismissed) { 62 + modal.show(); 63 + } 64 + } 65 + }, [modal, props.id, props.oneTime]); 66 + 67 + const handleClose = () => { 68 + if (props.oneTime) { 69 + localStorage.setItem(`modal-${props.id}-dismissed`, "true"); 70 + } 71 + modal.hide(); 72 + }; 73 + 74 + return ( 75 + <OverlayPortal darken close={handleClose} show={modal.isShown}> 76 + <Helmet> 77 + <html data-no-scroll /> 78 + </Helmet> 79 + <div className="flex absolute inset-0 items-center justify-center"> 80 + <Flare.Base 81 + className={classNames( 82 + "group -m-[0.705em] rounded-3xl bg-background-main transition-colors duration-300 focus:relative focus:z-10", 83 + "w-full mx-4 p-6 bg-mediaCard-hoverBackground bg-opacity-60 backdrop-filter backdrop-blur-lg shadow-lg", 84 + props.size === "md" ? "max-w-md" : "max-w-2xl", 85 + )} 86 + > 87 + <div className="transition-transform duration-300 overflow-y-scroll max-h-[90dvh] scrollbar-none"> 88 + <Flare.Light 89 + flareSize={300} 90 + cssColorVar="--colors-mediaCard-hoverAccent" 91 + backgroundClass="bg-mediaCard-hoverBackground duration-100" 92 + className="rounded-3xl bg-background-main group-hover:opacity-100" 93 + /> 94 + <Flare.Child className="pointer-events-auto relative mb-2p-[0.4em] transition-transform duration-300"> 95 + <div className="flex justify-between items-center mb-4"> 96 + {props.title && ( 97 + <Heading2 className="!mt-0 !mb-0 pr-6"> 98 + {props.title} 99 + </Heading2> 100 + )} 101 + <button 102 + type="button" 103 + className="text-s font-semibold text-type-secondary hover:text-white transition-transform hover:scale-95" 104 + onClick={handleClose} 105 + > 106 + <IconPatch icon={Icons.X} /> 107 + </button> 108 + </div> 109 + <div className="text-lg text-type-secondary"> 110 + {props.children} 111 + </div> 112 + </Flare.Child> 113 + </div> 114 + </Flare.Base> 115 + </div> 116 + </OverlayPortal> 117 + ); 118 + }
+94 -134
src/pages/HomePage.tsx
··· 50 50 const s = useSearch(search); 51 51 const [showBookmarks, setShowBookmarks] = useState(false); 52 52 const [showWatching, setShowWatching] = useState(false); 53 + // const modal = useModal("notice"); 53 54 54 55 const handleClick = (path: To) => { 55 56 window.scrollTo(0, 0); ··· 58 59 59 60 const enableDiscover = usePreferencesStore((state) => state.enableDiscover); 60 61 61 - /* 62 - // Safari Notice 63 - const [showModal, setShowModal] = useState(() => { 64 - const isSafari = 65 - typeof navigator !== "undefined" && 66 - /Safari/.test(navigator.userAgent) && 67 - !/Chrome/.test(navigator.userAgent); 68 - 69 - const isMac = 70 - typeof navigator !== "undefined" && /Mac/.test(navigator.platform); 71 - 72 - const isIOS = 73 - typeof navigator !== "undefined" && 74 - /iPhone|iPad|iPod/.test(navigator.userAgent); 75 - 76 - return isSafari && (isMac || isIOS); 77 - }); 78 - */ 79 - 80 - /* One time notice 81 - const [showModal, setShowModal] = useState(false); 82 - 83 - useEffect(() => { 84 - const isDismissed = localStorage.getItem("popupDismissed"); 85 - if (!isDismissed) { 86 - setShowModal(true); 87 - } 88 - }, []); 89 - 90 - const handleCloseModal = () => { 91 - setShowModal(false); 92 - localStorage.setItem("popupDismissed", "true"); 93 - }; 94 - */ 95 - 96 62 // const { loggedIn } = useAuth(); // Adjust padding for popup show button based on logged in state 97 63 98 64 return ( 99 65 <HomeLayout showBg={showBg}> 100 - {/* Popup show button 101 - <a 102 - onClick={() => setShowModal(true)} 66 + {/* <a 67 + onClick={() => modal.show()} 103 68 className={` text-white tabbable rounded-full z-50 fixed top-5 ${ 104 69 loggedIn 105 70 ? "right-[7.5rem] lg:right-[12.5rem] lg:text-2xl" ··· 110 75 <IconPill icon={Icons.WARNING}> 111 76 <span className="font-bold select-none">READ</span> 112 77 </IconPill> 113 - </a> 114 - */} 78 + </a> */} 115 79 <div className="mb-16 sm:mb-24"> 116 80 <Helmet> 117 81 <style type="text/css">{` ··· 122 86 <title>{t("global.name")}</title> 123 87 </Helmet> 124 88 125 - {/* Popup 126 - {showModal && ( 127 - <PopupModal 128 - styles="max-w-2xl" // max-w-md for short 129 - title="We’re changing our backend server!" 130 - message={ 131 - <div> 132 - <p> 133 - On <strong>January 8th</strong>, the backend server will 134 - change from: 135 - </p> 136 - <p> 137 - <strong>server.vidbinge.com</strong> →{" "} 138 - <strong>server.fifthwit.tech</strong> 139 - </p> 140 - <br /> 141 - <p> 142 - You will need to <strong>migrate your account </strong> to the 143 - new server or choose to continue using the old server by 144 - updating your settings. 145 - </p> 146 - <br /> 147 - <p> 148 - <strong>What You Need to Know:</strong> 149 - </p> 150 - <ul> 151 - <li> 152 - 1. <strong>Migrating Your Account:</strong> Your data (e.g., 153 - bookmarks) will not be automatically transferred. You’ll 154 - need to migrate your account from the settings page. Or from 155 - below. 156 - </li> 157 - <li> 158 - 2. <strong>Staying on the Old Server:</strong> If you don’t 159 - want to change to the new server, your data will remain safe 160 - on <strong>server.vidbinge.com</strong>. You can change the 161 - Backend URL in your settings to 162 - &quot;https://server.vidbinge.com&quot;. 163 - </li> 164 - </ul> 165 - <br /> 166 - <p> 167 - <strong>Steps to Move Your Data:</strong> 168 - </p> 169 - <ol> 170 - <li> 171 - 1. Log into your account on{" "} 172 - <strong>server.vidbinge.com</strong>. 173 - </li> 174 - <li> 175 - (If you already are logged in, press here:{" "} 176 - <a href="/migration" className="text-type-link"> 177 - Migrate my data. 178 - </a> 179 - ) 180 - </li> 181 - <li> 182 - 2. Go to the <strong>Settings</strong> page. 183 - </li> 184 - <li> 185 - 3. Scroll down to{" "} 186 - <strong>Connections &gt; Custom Server</strong>. 187 - </li> 188 - <li> 189 - 3. Press the &quot;Migrate my data to a new server.&quot; 190 - button. 191 - </li> 192 - <li> 193 - 4. Enter the new server url:{" "} 194 - <strong>https://server.fifthwit.tech</strong> and press 195 - &quot;Migrate&quot;. 196 - </li> 197 - <li>5. Login to your account with the same passphrase!</li> 198 - </ol> 199 - <br /> 200 - <p> 201 - Thank you for your understanding and support during this 202 - transition! If you have questions or need help, feel free to 203 - reach out on the{" "} 204 - <a 205 - href="https://discord.com/invite/7z6znYgrTG" 206 - target="_blank" 207 - rel="noopener noreferrer" 208 - className="text-type-link" 209 - > 210 - P-Stream Discord 211 - </a> 212 - ! 213 - </p> 214 - </div> 215 - } 216 - onClose={handleCloseModal} 217 - /> 218 - )} 89 + {/* Popup 90 + <FancyModal 91 + id="notice" 92 + title="We're changing our backend server!" 93 + oneTime 94 + > 95 + <div> 96 + <p> 97 + On <strong>January 8th</strong>, the backend server will change 98 + from: 99 + </p> 100 + <p> 101 + <strong>server.vidbinge.com</strong> →{" "} 102 + <strong>server.fifthwit.tech</strong> 103 + </p> 104 + <br /> 105 + <p> 106 + You will need to <strong>migrate your account </strong> to the new 107 + server or choose to continue using the old server by updating your 108 + settings. 109 + </p> 110 + <br /> 111 + <p> 112 + <strong>What You Need to Know:</strong> 113 + </p> 114 + <ul> 115 + <li> 116 + 1. <strong>Migrating Your Account:</strong> Your data (e.g., 117 + bookmarks) will not be automatically transferred. You&apos;ll 118 + need to migrate your account from the settings page. Or from 119 + below. 120 + </li> 121 + <li> 122 + 2. <strong>Staying on the Old Server:</strong> If you don&apos;t 123 + want to change to the new server, your data will remain safe on{" "} 124 + <strong>server.vidbinge.com</strong>. You can change the Backend 125 + URL in your settings to &quot;https://server.vidbinge.com&quot;. 126 + </li> 127 + </ul> 128 + <br /> 129 + <p> 130 + <strong>Steps to Move Your Data:</strong> 131 + </p> 132 + <ol> 133 + <li> 134 + 1. Log into your account on <strong>server.vidbinge.com</strong> 135 + . 136 + </li> 137 + <li> 138 + (If you already are logged in, press here:{" "} 139 + <a href="/migration" className="text-type-link"> 140 + Migrate my data. 141 + </a> 142 + ) 143 + </li> 144 + <li> 145 + 2. Go to the <strong>Settings</strong> page. 146 + </li> 147 + <li> 148 + 3. Scroll down to{" "} 149 + <strong>Connections &gt; Custom Server</strong>. 150 + </li> 151 + <li> 152 + 3. Press the &quot;Migrate my data to a new server.&quot; 153 + button. 154 + </li> 155 + <li> 156 + 4. Enter the new server url:{" "} 157 + <strong>https://server.fifthwit.tech</strong> and press 158 + &quot;Migrate&quot;. 159 + </li> 160 + <li>5. Login to your account with the same passphrase!</li> 161 + </ol> 162 + <br /> 163 + <p> 164 + Thank you for your understanding and support during this 165 + transition! If you have questions or need help, feel free to reach 166 + out on the{" "} 167 + <a 168 + href="https://discord.com/invite/7z6znYgrTG" 169 + target="_blank" 170 + rel="noopener noreferrer" 171 + className="text-type-link" 172 + > 173 + P-Stream Discord 174 + </a> 175 + ! 176 + </p> 177 + </div> 178 + </FancyModal> 219 179 */} 220 180 221 181 <HeroPart searchParams={searchParams} setIsSticky={setShowBg} />
+58 -68
src/pages/onboarding/Onboarding.tsx
··· 8 8 import { Stepper } from "@/components/layout/Stepper"; 9 9 import { BiggerCenterContainer } from "@/components/layout/ThinContainer"; 10 10 import { VerticalLine } from "@/components/layout/VerticalLine"; 11 - import { Modal, ModalCard, useModal } from "@/components/overlays/Modal"; 11 + import { 12 + FancyModal, 13 + Modal, 14 + ModalCard, 15 + useModal, 16 + } from "@/components/overlays/Modal"; 12 17 import { 13 18 StatusCircle, 14 19 StatusCircleProps, ··· 33 38 import { useAuthStore } from "@/stores/auth"; 34 39 import { getProxyUrls } from "@/utils/proxyUrls"; 35 40 36 - import { PopupModal } from "../parts/home/PopupModal"; 37 41 import { Status, testFebboxToken } from "../parts/settings/SetupPart"; 38 42 39 43 async function getFebboxTokenStatus(febboxToken: string | null) { ··· 179 183 export function OnboardingPage() { 180 184 const navigate = useNavigateOnboarding(); 181 185 const skipModal = useModal("skip"); 186 + const infoModal = useModal("info"); 182 187 const { completeAndRedirect } = useRedirectBack(); 183 188 const { t } = useTranslation(); 184 189 const noProxies = getProxyUrls().length === 0; ··· 188 193 /Safari/.test(navigator.userAgent) && 189 194 !/Chrome/.test(navigator.userAgent) && 190 195 !/Edg/.test(navigator.userAgent); 191 - 192 - const [showModal, setShowModal] = useState(false); 193 - 194 - const handleCloseModal = () => { 195 - setShowModal(false); 196 - }; 197 196 198 197 return ( 199 198 <MinimalPageLayout> ··· 216 215 </div> 217 216 </ModalCard> 218 217 </Modal> 219 - {showModal && ( 220 - <PopupModal 221 - styles="max-w-2xl" // max-w-md for short max-w-2xl long 222 - title="Understanding a setup" 223 - message={ 224 - <div> 225 - <p> 226 - P-Stream doesn&apos;t host videos. It relies on third-party 227 - websites for content, so you need to choose how it connects to 228 - those sites. 229 - <br /> 230 - <br /> 231 - <strong>Your Options:</strong> 232 - <br /> 233 - <strong>1. Extension (Recommended)</strong> 234 - <br /> 235 - The extension gives you access to the most sources. It acts as a 236 - local proxy and can handle sites that need special cookies or 237 - headers to load. 238 - <br /> 239 - <br /> 240 - <strong>2. Proxy</strong> 241 - <br /> 242 - The proxy scrapes media from other websites. It bypasses browser 243 - restrictions (like CORS) to allow scraping. 244 - <br /> 245 - <br /> 246 - <strong>3. Default Setup</strong> 218 + <FancyModal id={infoModal.id} title="Understanding a setup" size="xl"> 219 + <div> 220 + <p> 221 + P-Stream doesn&apos;t host videos. It relies on third-party websites 222 + for content, so you need to choose how it connects to those sites. 223 + <br /> 224 + <br /> 225 + <strong>Your Options:</strong> 226 + <br /> 227 + <strong>1. Extension (Recommended)</strong> 228 + <br /> 229 + The extension gives you access to the most sources. It acts as a 230 + local proxy and can handle sites that need special cookies or 231 + headers to load. 232 + <br /> 233 + <br /> 234 + <strong>2. Proxy</strong> 235 + <br /> 236 + The proxy scrapes media from other websites. It bypasses browser 237 + restrictions (like CORS) to allow scraping. 238 + <br /> 239 + <br /> 240 + <strong>3. Default Setup</strong> 241 + <br /> 242 + Uses P-Stream&apos;s built-in proxy. It&apos;s the easiest option 243 + but might be slower due to shared bandwidth. 244 + <br /> 245 + <br /> 246 + {conf().ALLOW_FEBBOX_KEY && ( 247 + <> 248 + <strong>Optional FED API (Febbox) UI token</strong> 247 249 <br /> 248 - Uses P-Stream&apos;s built-in proxy. It&apos;s the easiest 249 - option but might be slower due to shared bandwidth. 250 + Bringing your own Febbox account allows you to unlock FED API, 251 + our best source with 4K quality, Dolby Atmos, the most content, 252 + and the best (fastest) load times. This the highly recommended! 250 253 <br /> 251 254 <br /> 252 - {conf().ALLOW_FEBBOX_KEY && ( 253 - <> 254 - <strong>Optional FED API (Febbox) UI token</strong> 255 - <br /> 256 - Bringing your own Febbox account allows you to unlock FED 257 - API, our best source with 4K quality, Dolby Atmos, the most 258 - content, and the best (fastest) load times. This the highly 259 - recommended! 260 - <br /> 261 - <br /> 262 - </> 263 - )} 264 - If you have more questions on how this works, feel free to ask 265 - on the{" "} 266 - <a 267 - href="https://discord.com/invite/7z6znYgrTG" 268 - target="_blank" 269 - rel="noopener noreferrer" 270 - className="text-type-link" 271 - > 272 - P-Stream Discord 273 - </a>{" "} 274 - server! 275 - </p> 276 - </div> 277 - } 278 - onClose={handleCloseModal} 279 - /> 280 - )} 255 + </> 256 + )} 257 + If you have more questions on how this works, feel free to ask on 258 + the{" "} 259 + <a 260 + href="https://discord.com/invite/7z6znYgrTG" 261 + target="_blank" 262 + rel="noopener noreferrer" 263 + className="text-type-link" 264 + > 265 + P-Stream Discord 266 + </a>{" "} 267 + server! 268 + </p> 269 + </div> 270 + </FancyModal> 281 271 <BiggerCenterContainer> 282 272 <Stepper steps={2} current={1} className="mb-12" /> 283 273 <Heading2 className="!mt-0 !text-3xl"> ··· 287 277 {t("onboarding.start.explainer")} 288 278 <div 289 279 className="pt-4 flex cursor-pointer items-center text-type-link" 290 - onClick={() => setShowModal(true)} 280 + onClick={() => infoModal.show()} 291 281 > 292 282 <p>More info</p> 293 283 <Icon className="pl-2" icon={Icons.CIRCLE_QUESTION} />
-80
src/pages/parts/home/PopupModal.tsx
··· 1 - import classNames from "classnames"; 2 - import { ReactNode, useEffect } from "react"; 3 - 4 - import { IconPatch } from "@/components/buttons/IconPatch"; 5 - import { Icons } from "@/components/Icon"; 6 - import { Flare } from "@/components/utils/Flare"; 7 - import { Heading2 } from "@/components/utils/Text"; 8 - 9 - export interface PopupModalProps { 10 - title: string; 11 - message: ReactNode; 12 - closable?: boolean; 13 - onClose?: () => void; 14 - styles?: string; 15 - } 16 - 17 - export function PopupModal({ 18 - title, 19 - message, 20 - closable = true, 21 - onClose, 22 - styles, 23 - }: PopupModalProps) { 24 - useEffect(() => { 25 - document.body.style.overflow = "hidden"; 26 - 27 - return () => { 28 - document.body.style.overflow = ""; 29 - }; 30 - }, []); 31 - 32 - return ( 33 - <div 34 - className={classNames( 35 - "fixed inset-0 z-[100] flex items-center justify-center", 36 - "bg-background-main bg-opacity-75 backdrop-filter backdrop-blur-sm", 37 - "transition-opacity duration-400", 38 - "pointer-events-auto", 39 - )} 40 - onClick={onClose} 41 - > 42 - <Flare.Base 43 - className={classNames( 44 - "group -m-[0.705em] rounded-3xl bg-background-main transition-colors duration-300 focus:relative focus:z-10", 45 - "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", 46 - )} 47 - > 48 - <div 49 - className={classNames( 50 - "transition-transform duration-300", 51 - "overflow-y-scroll max-h-[90dvh] md:max-h-[90dvh] scrollbar-none", 52 - styles, 53 - )} 54 - > 55 - <Flare.Light 56 - flareSize={300} 57 - cssColorVar="--colors-mediaCard-hoverAccent" 58 - backgroundClass="bg-mediaCard-hoverBackground duration-100" 59 - className="rounded-3xl bg-background-main group-hover:opacity-100" 60 - /> 61 - <Flare.Child className="pointer-events-auto relative mb-2p-[0.4em] transition-transform duration-300"> 62 - <div className="flex justify-between items-center mb-4"> 63 - <Heading2 className="!mt-0 !mb-0 pr-6">{title}</Heading2> 64 - {closable && ( 65 - <button 66 - type="button" 67 - className="fixed right-4 text-s font-semibold text-type-secondary hover:text-white transition-transform hover:scale-110" 68 - onClick={onClose} 69 - > 70 - <IconPatch icon={Icons.X} /> 71 - </button> 72 - )} 73 - </div> 74 - <p className="text-lg text-type-secondary">{message}</p> 75 - </Flare.Child> 76 - </div> 77 - </Flare.Base> 78 - </div> 79 - ); 80 - }