From 12d88d39914639572449bf635e6141b2fe2632ed Mon Sep 17 00:00:00 2001 From: leowang Date: Sun, 24 May 2026 17:29:04 +0800 Subject: [PATCH] Fix stale overlay scroll locks --- public/sw.js | 2 +- src/app/page.tsx | 28 +++++---------- src/components/AnnouncementBanner.tsx | 30 ++++++++++++++++ src/components/UserMenu.tsx | 23 ------------- src/components/VersionPanel.tsx | 22 ------------ .../__tests__/AnnouncementBanner.test.tsx | 31 +++++++++++++++++ src/components/ui/HeroPrimitives.tsx | 34 ++++++++++++++++++- .../ui/__tests__/HeroPrimitives.test.tsx | 34 +++++++++++++++++++ 8 files changed, 137 insertions(+), 67 deletions(-) create mode 100644 src/components/AnnouncementBanner.tsx create mode 100644 src/components/__tests__/AnnouncementBanner.test.tsx diff --git a/public/sw.js b/public/sw.js index 980cb97..c0fcd05 100644 --- a/public/sw.js +++ b/public/sw.js @@ -1 +1 @@ -if(!self.define){let e,a={};const s=(s,c)=>(s=new URL(s+".js",c).href,a[s]||new Promise(a=>{if("document"in self){const e=document.createElement("script");e.src=s,e.onload=a,document.head.appendChild(e)}else e=s,importScripts(s),a()}).then(()=>{let e=a[s];if(!e)throw new Error(`Module ${s} didn’t register its module`);return e}));self.define=(c,i)=>{const t=e||("document"in self?document.currentScript.src:"")||location.href;if(a[t])return;let n={};const r=e=>s(e,t),o={module:{uri:t},exports:n,require:r};a[t]=Promise.all(c.map(e=>o[e]||r(e))).then(e=>(i(...e),n))}}define(["./workbox-e9849328"],function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/app-build-manifest.json",revision:"d2019de4567fa49ebf790c101ad36a37"},{url:"/_next/static/AOD2poraHkhTOa43IALRS/_buildManifest.js",revision:"4740a4478df99a73dadc7052247a6d6d"},{url:"/_next/static/AOD2poraHkhTOa43IALRS/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/1214-239f55f0a9968ae6.js",revision:"239f55f0a9968ae6"},{url:"/_next/static/chunks/212-c92804cd5c36ccfe.js",revision:"c92804cd5c36ccfe"},{url:"/_next/static/chunks/260-1e4d5095326f1929.js",revision:"1e4d5095326f1929"},{url:"/_next/static/chunks/394-ed74bf23acf690cd.js",revision:"ed74bf23acf690cd"},{url:"/_next/static/chunks/4707-a33a49083c72c92d.js",revision:"a33a49083c72c92d"},{url:"/_next/static/chunks/5688-7cf3621a969b7c92.js",revision:"7cf3621a969b7c92"},{url:"/_next/static/chunks/569-39bc114fdf6847db.js",revision:"39bc114fdf6847db"},{url:"/_next/static/chunks/6247-0803ce791127ffc4.js",revision:"0803ce791127ffc4"},{url:"/_next/static/chunks/6837-0542749c23ed2959.js",revision:"0542749c23ed2959"},{url:"/_next/static/chunks/7422-b8e062ed75f815a0.js",revision:"b8e062ed75f815a0"},{url:"/_next/static/chunks/7678-2c39a82db7ab4d79.js",revision:"2c39a82db7ab4d79"},{url:"/_next/static/chunks/7809-e061e97228be14bd.js",revision:"e061e97228be14bd"},{url:"/_next/static/chunks/7870.7199854d4bfb7214.js",revision:"7199854d4bfb7214"},{url:"/_next/static/chunks/835-1311a5ac1bc1a551.js",revision:"1311a5ac1bc1a551"},{url:"/_next/static/chunks/861965c9-56382d4621d981d6.js",revision:"56382d4621d981d6"},{url:"/_next/static/chunks/8964-a51299cec5301680.js",revision:"a51299cec5301680"},{url:"/_next/static/chunks/app/_not-found/page-eaf37efff24851e5.js",revision:"eaf37efff24851e5"},{url:"/_next/static/chunks/app/admin/page-0f29387e2be4272e.js",revision:"0f29387e2be4272e"},{url:"/_next/static/chunks/app/api/admin/category/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/config/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/config_file/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/config_subscription/fetch/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/data_migration/export/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/data_migration/import/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/live/refresh/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/live/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/reset/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/site/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/source/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/source/validate/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/theme/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/user/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/avatar/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/change-password/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/conversations/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/friend-requests/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/friends/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/messages/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/online-users/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/search-users/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/send-message/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/cron/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/danmu/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/detail/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/douban/categories/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/douban/recommends/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/douban/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/favorites/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/health/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/image-proxy/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/live/channels/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/live/epg/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/live/precheck/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/live/sources/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/login/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/logout/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/machine-code/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/playrecords/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/key/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/logo/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/m3u8/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/segment/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/video/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/video/test/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/search/one/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/search/resources/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/search/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/search/suggestions/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/search/ws/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/searchhistory/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/server-config/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/categories/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/latest/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/list/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/parse/all/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/parse/batch/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/parse/single/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/recommend/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/search/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/skipconfigs/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/websocket/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/douban/page-f54a581a7ad3f486.js",revision:"f54a581a7ad3f486"},{url:"/_next/static/chunks/app/layout-91dc4f35c822836a.js",revision:"91dc4f35c822836a"},{url:"/_next/static/chunks/app/live/page-5317e86b4e682269.js",revision:"5317e86b4e682269"},{url:"/_next/static/chunks/app/login/page-4cea8d8ecc9cdf94.js",revision:"4cea8d8ecc9cdf94"},{url:"/_next/static/chunks/app/page-e783191d2c33ca32.js",revision:"e783191d2c33ca32"},{url:"/_next/static/chunks/app/play/page-f7b5e4a15ca70bf8.js",revision:"f7b5e4a15ca70bf8"},{url:"/_next/static/chunks/app/search/page-2d08139976f3568c.js",revision:"2d08139976f3568c"},{url:"/_next/static/chunks/app/shortdrama/page-103d01c7dd76fc57.js",revision:"103d01c7dd76fc57"},{url:"/_next/static/chunks/app/warning/page-7e49052845300dc2.js",revision:"7e49052845300dc2"},{url:"/_next/static/chunks/deb030d4-c5209a2ceb93feb3.js",revision:"c5209a2ceb93feb3"},{url:"/_next/static/chunks/framework-38d00379d7a41d4e.js",revision:"38d00379d7a41d4e"},{url:"/_next/static/chunks/main-80d1b284ea08d4a6.js",revision:"80d1b284ea08d4a6"},{url:"/_next/static/chunks/main-app-2a0dd42e958c98cd.js",revision:"2a0dd42e958c98cd"},{url:"/_next/static/chunks/pages/_app-31f2fea9e30ebfdd.js",revision:"31f2fea9e30ebfdd"},{url:"/_next/static/chunks/pages/_error-55c33958c98286e9.js",revision:"55c33958c98286e9"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-4638d3f2b0151932.js",revision:"4638d3f2b0151932"},{url:"/_next/static/css/ccce47fdcedd91d2.css",revision:"ccce47fdcedd91d2"},{url:"/_next/static/css/e4073aa98cbbf8c1.css",revision:"e4073aa98cbbf8c1"},{url:"/favicon.ico",revision:"27cf5167605c37fe0dc1624590c96b7a"},{url:"/icons/icon-192x192.png",revision:"e214d3db80d2eb6ef7a911b3f9433b81"},{url:"/icons/icon-256x256.png",revision:"a5cd7490191373b684033f1b33c9d9da"},{url:"/icons/icon-384x384.png",revision:"8540e29a41812989d2d5bf8f61e1e755"},{url:"/icons/icon-512x512.png",revision:"3e5597604f2c5d99d7ab62b02f6863d3"},{url:"/logo.png",revision:"3da704450f5c0807a0c8ad9840461521"},{url:"/manifest.json",revision:"46f3847d5e244fb9c639fa86902e15db"},{url:"/robots.txt",revision:"0483b37fb6cf7455cefe516197e39241"},{url:"/screenshot1.png",revision:"d7de3a25686c5b9c9d8c8675bc6109fc"},{url:"/screenshot2.png",revision:"b0b715a3018d2f02aba5d94762473bb6"},{url:"/screenshot3.png",revision:"7e454c28e110e291ee12f494fb3cf40c"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:a,event:s,state:c})=>a&&"opaqueredirect"===a.type?new Response(a.body,{status:200,statusText:"OK",headers:a.headers}):a}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;const a=e.pathname;return!a.startsWith("/api/auth/")&&!!a.startsWith("/api/")},new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;return!e.pathname.startsWith("/api/")},new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>!(self.origin===e.origin),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")}); +if(!self.define){let e,a={};const s=(s,c)=>(s=new URL(s+".js",c).href,a[s]||new Promise(a=>{if("document"in self){const e=document.createElement("script");e.src=s,e.onload=a,document.head.appendChild(e)}else e=s,importScripts(s),a()}).then(()=>{let e=a[s];if(!e)throw new Error(`Module ${s} didn’t register its module`);return e}));self.define=(c,i)=>{const t=e||("document"in self?document.currentScript.src:"")||location.href;if(a[t])return;let n={};const r=e=>s(e,t),u={module:{uri:t},exports:n,require:r};a[t]=Promise.all(c.map(e=>u[e]||r(e))).then(e=>(i(...e),n))}}define(["./workbox-e9849328"],function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/app-build-manifest.json",revision:"7e017214d7c68ca4aa9bbdb7879859e9"},{url:"/_next/static/SVgE5GKtb0zjUpb0Z6Iu5/_buildManifest.js",revision:"4740a4478df99a73dadc7052247a6d6d"},{url:"/_next/static/SVgE5GKtb0zjUpb0Z6Iu5/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/1214-239f55f0a9968ae6.js",revision:"239f55f0a9968ae6"},{url:"/_next/static/chunks/212-c92804cd5c36ccfe.js",revision:"c92804cd5c36ccfe"},{url:"/_next/static/chunks/260-96a9f42b8688c71a.js",revision:"96a9f42b8688c71a"},{url:"/_next/static/chunks/394-ed74bf23acf690cd.js",revision:"ed74bf23acf690cd"},{url:"/_next/static/chunks/4707-a33a49083c72c92d.js",revision:"a33a49083c72c92d"},{url:"/_next/static/chunks/5688-7cf3621a969b7c92.js",revision:"7cf3621a969b7c92"},{url:"/_next/static/chunks/569-6ef1a7bcb3c35760.js",revision:"6ef1a7bcb3c35760"},{url:"/_next/static/chunks/6247-0803ce791127ffc4.js",revision:"0803ce791127ffc4"},{url:"/_next/static/chunks/6837-0542749c23ed2959.js",revision:"0542749c23ed2959"},{url:"/_next/static/chunks/7422-b8e062ed75f815a0.js",revision:"b8e062ed75f815a0"},{url:"/_next/static/chunks/7678-2c39a82db7ab4d79.js",revision:"2c39a82db7ab4d79"},{url:"/_next/static/chunks/7809-e061e97228be14bd.js",revision:"e061e97228be14bd"},{url:"/_next/static/chunks/7870.7199854d4bfb7214.js",revision:"7199854d4bfb7214"},{url:"/_next/static/chunks/835-1311a5ac1bc1a551.js",revision:"1311a5ac1bc1a551"},{url:"/_next/static/chunks/861965c9-56382d4621d981d6.js",revision:"56382d4621d981d6"},{url:"/_next/static/chunks/8964-a123ccc1aaa9f25e.js",revision:"a123ccc1aaa9f25e"},{url:"/_next/static/chunks/app/_not-found/page-eaf37efff24851e5.js",revision:"eaf37efff24851e5"},{url:"/_next/static/chunks/app/admin/page-0f29387e2be4272e.js",revision:"0f29387e2be4272e"},{url:"/_next/static/chunks/app/api/admin/category/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/config/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/config_file/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/config_subscription/fetch/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/data_migration/export/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/data_migration/import/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/live/refresh/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/live/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/reset/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/site/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/source/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/source/validate/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/theme/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/admin/user/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/avatar/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/change-password/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/conversations/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/friend-requests/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/friends/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/messages/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/online-users/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/search-users/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/chat/send-message/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/cron/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/danmu/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/detail/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/douban/categories/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/douban/recommends/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/douban/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/favorites/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/health/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/image-proxy/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/live/channels/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/live/epg/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/live/precheck/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/live/sources/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/login/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/logout/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/machine-code/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/playrecords/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/key/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/logo/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/m3u8/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/segment/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/video/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/proxy/video/test/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/search/one/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/search/resources/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/search/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/search/suggestions/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/search/ws/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/searchhistory/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/server-config/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/categories/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/latest/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/list/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/parse/all/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/parse/batch/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/parse/single/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/recommend/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/shortdrama/search/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/skipconfigs/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/api/websocket/route-86f2c28a81077b9d.js",revision:"86f2c28a81077b9d"},{url:"/_next/static/chunks/app/douban/page-f54a581a7ad3f486.js",revision:"f54a581a7ad3f486"},{url:"/_next/static/chunks/app/layout-91dc4f35c822836a.js",revision:"91dc4f35c822836a"},{url:"/_next/static/chunks/app/live/page-5317e86b4e682269.js",revision:"5317e86b4e682269"},{url:"/_next/static/chunks/app/login/page-4cea8d8ecc9cdf94.js",revision:"4cea8d8ecc9cdf94"},{url:"/_next/static/chunks/app/page-7972ca67735ea7d5.js",revision:"7972ca67735ea7d5"},{url:"/_next/static/chunks/app/play/page-f7b5e4a15ca70bf8.js",revision:"f7b5e4a15ca70bf8"},{url:"/_next/static/chunks/app/search/page-2d08139976f3568c.js",revision:"2d08139976f3568c"},{url:"/_next/static/chunks/app/shortdrama/page-103d01c7dd76fc57.js",revision:"103d01c7dd76fc57"},{url:"/_next/static/chunks/app/warning/page-7e49052845300dc2.js",revision:"7e49052845300dc2"},{url:"/_next/static/chunks/deb030d4-c5209a2ceb93feb3.js",revision:"c5209a2ceb93feb3"},{url:"/_next/static/chunks/framework-38d00379d7a41d4e.js",revision:"38d00379d7a41d4e"},{url:"/_next/static/chunks/main-80d1b284ea08d4a6.js",revision:"80d1b284ea08d4a6"},{url:"/_next/static/chunks/main-app-2a0dd42e958c98cd.js",revision:"2a0dd42e958c98cd"},{url:"/_next/static/chunks/pages/_app-31f2fea9e30ebfdd.js",revision:"31f2fea9e30ebfdd"},{url:"/_next/static/chunks/pages/_error-55c33958c98286e9.js",revision:"55c33958c98286e9"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-4638d3f2b0151932.js",revision:"4638d3f2b0151932"},{url:"/_next/static/css/086a977ee2ee8597.css",revision:"086a977ee2ee8597"},{url:"/_next/static/css/ccce47fdcedd91d2.css",revision:"ccce47fdcedd91d2"},{url:"/favicon.ico",revision:"27cf5167605c37fe0dc1624590c96b7a"},{url:"/icons/icon-192x192.png",revision:"e214d3db80d2eb6ef7a911b3f9433b81"},{url:"/icons/icon-256x256.png",revision:"a5cd7490191373b684033f1b33c9d9da"},{url:"/icons/icon-384x384.png",revision:"8540e29a41812989d2d5bf8f61e1e755"},{url:"/icons/icon-512x512.png",revision:"3e5597604f2c5d99d7ab62b02f6863d3"},{url:"/logo.png",revision:"3da704450f5c0807a0c8ad9840461521"},{url:"/manifest.json",revision:"46f3847d5e244fb9c639fa86902e15db"},{url:"/robots.txt",revision:"0483b37fb6cf7455cefe516197e39241"},{url:"/screenshot1.png",revision:"d7de3a25686c5b9c9d8c8675bc6109fc"},{url:"/screenshot2.png",revision:"b0b715a3018d2f02aba5d94762473bb6"},{url:"/screenshot3.png",revision:"7e454c28e110e291ee12f494fb3cf40c"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:a,event:s,state:c})=>a&&"opaqueredirect"===a.type?new Response(a.body,{status:200,statusText:"OK",headers:a.headers}):a}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;const a=e.pathname;return!a.startsWith("/api/auth/")&&!!a.startsWith("/api/")},new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;return!e.pathname.startsWith("/api/")},new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>!(self.origin===e.origin),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")}); diff --git a/src/app/page.tsx b/src/app/page.tsx index b4d402e..09b362e 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -25,13 +25,13 @@ import { import { getDoubanCategories } from '@/lib/douban.client'; import { DoubanItem } from '@/lib/types'; +import { AnnouncementBanner } from '@/components/AnnouncementBanner'; import CapsuleSwitch from '@/components/CapsuleSwitch'; import ContinueWatching from '@/components/ContinueWatching'; import PageLayout from '@/components/PageLayout'; import ScrollableRow from '@/components/ScrollableRow'; import { useSite } from '@/components/SiteProvider'; import VideoCard from '@/components/VideoCard'; -import { AppDialog } from '@/components/ui/HeroPrimitives'; function HomeClient() { const [activeTab, setActiveTab] = useState<'home' | 'favorites'>('home'); @@ -190,6 +190,13 @@ function HomeClient() {
+ {announcement && showAnnouncement && ( + handleCloseAnnouncement(announcement)} + /> + )} + {activeTab === 'favorites' ? ( // 收藏夹视图 @@ -427,25 +434,6 @@ function HomeClient() { )}
- {announcement && ( - { - if (!isOpen) handleCloseAnnouncement(announcement); - }} - title='提示' - footer={ - - } - > -

{announcement}

-
- )} ); } diff --git a/src/components/AnnouncementBanner.tsx b/src/components/AnnouncementBanner.tsx new file mode 100644 index 0000000..116c04c --- /dev/null +++ b/src/components/AnnouncementBanner.tsx @@ -0,0 +1,30 @@ +'use client'; + +import { Button, Card } from '@heroui/react'; + +interface AnnouncementBannerProps { + announcement: string; + onDismiss: () => void; +} + +export function AnnouncementBanner({ + announcement, + onDismiss, +}: AnnouncementBannerProps) { + return ( + + +
+ Announcement + 提示 +
+ +
+ +

{announcement}

+
+
+ ); +} diff --git a/src/components/UserMenu.tsx b/src/components/UserMenu.tsx index 163d843..3fb0052 100644 --- a/src/components/UserMenu.tsx +++ b/src/components/UserMenu.tsx @@ -72,29 +72,6 @@ export const UserMenu: React.FC = () => { const imageRef = useRef(null); const [showCropper, setShowCropper] = useState(false); - // Body 滚动锁定 - 使用 overflow 方式避免布局问题 - useEffect(() => { - if (isSettingsOpen || isChangePasswordOpen || isChangeAvatarOpen) { - const body = document.body; - const html = document.documentElement; - - // 保存原始样式 - const originalBodyOverflow = body.style.overflow; - const originalHtmlOverflow = html.style.overflow; - - // 只设置 overflow 来阻止滚动 - body.style.overflow = 'hidden'; - html.style.overflow = 'hidden'; - - return () => { - - // 恢复所有原始样式 - body.style.overflow = originalBodyOverflow; - html.style.overflow = originalHtmlOverflow; - }; - } - }, [isSettingsOpen, isChangePasswordOpen]); - // 设置相关状态 const [defaultAggregateSearch, setDefaultAggregateSearch] = useState(true); const [doubanProxyUrl, setDoubanProxyUrl] = useState(''); diff --git a/src/components/VersionPanel.tsx b/src/components/VersionPanel.tsx index 736a9eb..db2dc85 100644 --- a/src/components/VersionPanel.tsx +++ b/src/components/VersionPanel.tsx @@ -49,28 +49,6 @@ export const VersionPanel: React.FC = ({ return () => setMounted(false); }, []); - // Body 滚动锁定 - 使用 overflow 方式避免布局问题 - useEffect(() => { - if (isOpen) { - const body = document.body; - const html = document.documentElement; - - // 保存原始样式 - const originalBodyOverflow = body.style.overflow; - const originalHtmlOverflow = html.style.overflow; - - // 只设置 overflow 来阻止滚动 - body.style.overflow = 'hidden'; - html.style.overflow = 'hidden'; - - return () => { - // 恢复所有原始样式 - body.style.overflow = originalBodyOverflow; - html.style.overflow = originalHtmlOverflow; - }; - } - }, [isOpen]); - // 获取远程变更日志 useEffect(() => { if (isOpen) { diff --git a/src/components/__tests__/AnnouncementBanner.test.tsx b/src/components/__tests__/AnnouncementBanner.test.tsx new file mode 100644 index 0000000..d060290 --- /dev/null +++ b/src/components/__tests__/AnnouncementBanner.test.tsx @@ -0,0 +1,31 @@ +import { fireEvent, render, screen } from '@testing-library/react'; + +import { AnnouncementBanner } from '../AnnouncementBanner'; + +describe('AnnouncementBanner', () => { + beforeEach(() => { + localStorage.clear(); + document.documentElement.style.overflow = ''; + document.body.style.overflow = ''; + }); + + it('renders a non-blocking announcement without a dialog or scroll lock', () => { + const onDismiss = jest.fn(); + + render( + + ); + + expect(screen.getByText('请注意站点公告')).toBeInTheDocument(); + expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); + expect(document.documentElement.style.overflow).toBe(''); + expect(document.body.style.overflow).toBe(''); + + fireEvent.click(screen.getByRole('button', { name: '我知道了' })); + + expect(onDismiss).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/components/ui/HeroPrimitives.tsx b/src/components/ui/HeroPrimitives.tsx index 4305900..a81ab37 100644 --- a/src/components/ui/HeroPrimitives.tsx +++ b/src/components/ui/HeroPrimitives.tsx @@ -20,11 +20,41 @@ import type { SpinnerProps, TabsProps, } from '@heroui/react'; -import { forwardRef } from 'react'; +import { forwardRef, useEffect } from 'react'; import type { Key, ReactNode } from 'react'; type AppButtonProps = ButtonProps; +let activeRootOverlayCount = 0; + +function releaseRootScrollLockIfIdle() { + if (activeRootOverlayCount > 0 || typeof document === 'undefined') return; + + const html = document.documentElement; + const body = document.body; + + if (html.style.overflow === 'hidden') { + html.style.overflow = ''; + } + + if (body.style.overflow === 'hidden') { + body.style.overflow = ''; + } +} + +function useRootOverlayCleanup(isOpen: boolean) { + useEffect(() => { + if (!isOpen) return undefined; + + activeRootOverlayCount += 1; + + return () => { + activeRootOverlayCount = Math.max(0, activeRootOverlayCount - 1); + releaseRootScrollLockIfIdle(); + }; + }, [isOpen]); +} + export const AppButton = forwardRef( function AppButton(props, ref) { return