生态应用

This commit is contained in:
mtvpls
2026-02-13 17:13:17 +08:00
parent f0cedc1651
commit 7a5acbbe69
3 changed files with 209 additions and 2 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

+209 -2
View File
@@ -22,6 +22,7 @@ import {
Monitor,
MoveDown,
MoveUp,
Package,
Rss,
Settings,
Shield,
@@ -65,6 +66,7 @@ export const UserMenu: React.FC = () => {
const [isFavoritesPanelOpen, setIsFavoritesPanelOpen] = useState(false);
const [isEmailSettingsOpen, setIsEmailSettingsOpen] = useState(false);
const [isDeviceManagementOpen, setIsDeviceManagementOpen] = useState(false);
const [isEcoAppsOpen, setIsEcoAppsOpen] = useState(false);
const [authInfo, setAuthInfo] = useState<AuthInfo | null>(null);
const [storageType, setStorageType] = useState<string>('localstorage');
const [mounted, setMounted] = useState(false);
@@ -78,7 +80,7 @@ export const UserMenu: React.FC = () => {
// Body 滚动锁定 - 使用 overflow 方式避免布局问题
useEffect(() => {
if (isSettingsOpen || isChangePasswordOpen || isSubscribeOpen || isOfflineDownloadPanelOpen || isEmailSettingsOpen || isDeviceManagementOpen) {
if (isSettingsOpen || isChangePasswordOpen || isSubscribeOpen || isOfflineDownloadPanelOpen || isEmailSettingsOpen || isDeviceManagementOpen || isEcoAppsOpen) {
const body = document.body;
const html = document.documentElement;
@@ -97,7 +99,7 @@ export const UserMenu: React.FC = () => {
html.style.overflow = originalHtmlOverflow;
};
}
}, [isSettingsOpen, isChangePasswordOpen, isSubscribeOpen, isOfflineDownloadPanelOpen, isEmailSettingsOpen, isDeviceManagementOpen]);
}, [isSettingsOpen, isChangePasswordOpen, isSubscribeOpen, isOfflineDownloadPanelOpen, isEmailSettingsOpen, isDeviceManagementOpen, isEcoAppsOpen]);
// 设置相关状态
const [defaultAggregateSearch, setDefaultAggregateSearch] = useState(true);
@@ -1285,6 +1287,18 @@ export const UserMenu: React.FC = () => {
</button>
)}
{/* 生态应用按钮 */}
<button
onClick={() => {
setIsOpen(false);
setIsEcoAppsOpen(true);
}}
className='w-full px-3 py-2 text-left flex items-center gap-2.5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors text-sm'
>
<Package className='w-4 h-4 text-gray-500 dark:text-gray-400' />
<span className='font-medium'></span>
</button>
{/* 分割线 */}
<div className='my-1 border-t border-gray-200 dark:border-gray-700'></div>
@@ -2859,6 +2873,194 @@ export const UserMenu: React.FC = () => {
</>
);
// 生态应用面板内容
const ecoAppsPanel = (
<>
{/* 背景遮罩 */}
<div
className='fixed inset-0 bg-black/50 backdrop-blur-sm z-[1000]'
onClick={() => setIsEcoAppsOpen(false)}
onTouchMove={(e) => {
e.preventDefault();
}}
onWheel={(e) => {
e.preventDefault();
}}
style={{
touchAction: 'none',
}}
/>
{/* 生态应用面板 */}
<div
className='fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-2xl bg-white dark:bg-gray-900 rounded-xl shadow-xl z-[1001] overflow-hidden'
>
<div
className='h-full max-h-[85vh] flex flex-col'
data-panel-content
onTouchMove={(e) => {
e.stopPropagation();
}}
style={{
touchAction: 'auto',
}}
>
{/* 标题栏 */}
<div className='flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700'>
<h3 className='text-xl font-bold text-gray-800 dark:text-gray-200'>
</h3>
<button
onClick={() => setIsEcoAppsOpen(false)}
className='w-8 h-8 p-1 rounded-full flex items-center justify-center text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors'
aria-label='Close'
>
<X className='w-full h-full' />
</button>
</div>
{/* 应用列表 */}
<div className='flex-1 overflow-y-auto p-6'>
<div className='grid gap-6 md:grid-cols-1'>
{/* MoonTVPlus-PC 客户端 */}
<div className='bg-gray-50 dark:bg-gray-800 rounded-lg p-5 border border-gray-200 dark:border-gray-700'>
<div className='flex items-start gap-4'>
<div className='flex-shrink-0 relative'>
<img
src='/logo.png'
alt='MoonTVPlus-PC'
className='w-16 h-16 rounded-xl object-cover'
/>
<div className='absolute -bottom-1 -right-1 w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center shadow-lg'>
<Monitor className='w-3.5 h-3.5 text-white' />
</div>
</div>
<div className='flex-1 min-w-0'>
<h4 className='text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2'>
MoonTVPlus-PC客户端
</h4>
<p className='text-sm text-gray-600 dark:text-gray-400 mb-3'>
Windows开发的客户端mkv视频
</p>
<a
href='https://github.com/mtvpls/MoonTVPlus-PC/releases'
target='_blank'
rel='noopener noreferrer'
className='inline-flex items-center gap-2 px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white text-sm font-medium rounded-lg transition-colors'
>
<Download className='w-4 h-4' />
<ExternalLink className='w-3 h-3' />
</a>
</div>
</div>
</div>
{/* Selene 跨平台客户端 */}
<div className='bg-gray-50 dark:bg-gray-800 rounded-lg p-5 border border-gray-200 dark:border-gray-700'>
<div className='flex items-start gap-4'>
<div className='flex-shrink-0 relative'>
<img
src='/icons/Selene.png'
alt='Selene'
className='w-16 h-16 rounded-xl object-cover'
/>
<span className='absolute -top-1 -right-1 px-1.5 py-0.5 bg-orange-500 text-white text-[10px] font-bold rounded'>
</span>
</div>
<div className='flex-1 min-w-0'>
<h4 className='text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2'>
Selene
</h4>
<p className='text-sm text-gray-600 dark:text-gray-400 mb-3'>
</p>
<div className='flex flex-wrap gap-2'>
<a
href='https://github.com/mtvpls/MoonTVPlus/releases/tag/Selene_Beta4'
target='_blank'
rel='noopener noreferrer'
className='inline-flex items-center gap-2 px-4 py-2 bg-green-500 hover:bg-green-600 text-white text-sm font-medium rounded-lg transition-colors'
>
<Download className='w-4 h-4' />
<ExternalLink className='w-3 h-3' />
</a>
<button
onClick={() => {
const ua = navigator.userAgent.toLowerCase();
let targetUrl = 'https://github.com/mtvpls/Selene-Build/actions/workflows/build.yml';
// 根据 UA 判断平台
if (ua.includes('windows')) {
targetUrl = 'https://github.com/mtvpls/Selene-Build/actions/workflows/build.yml';
} else if (ua.includes('mac')) {
targetUrl = 'https://github.com/mtvpls/Selene-Build/actions/workflows/build.yml';
} else if (ua.includes('linux')) {
targetUrl = 'https://github.com/mtvpls/Selene-Build/actions/workflows/build.yml';
}
window.open(targetUrl, '_blank');
}}
className='inline-flex items-center gap-2 px-4 py-2 bg-purple-500 hover:bg-purple-600 text-white text-sm font-medium rounded-lg transition-colors'
>
<Download className='w-4 h-4' />
<ExternalLink className='w-3 h-3' />
</button>
</div>
</div>
</div>
</div>
{/* OrionTV TV专用客户端 */}
<div className='bg-gray-50 dark:bg-gray-800 rounded-lg p-5 border border-gray-200 dark:border-gray-700'>
<div className='flex items-start gap-4'>
<div className='flex-shrink-0 relative'>
<img
src='/icons/OrionTV.png'
alt='OrionTV'
className='w-16 h-16 rounded-xl object-cover'
/>
<span className='absolute -top-1 -right-1 px-1.5 py-0.5 bg-orange-500 text-white text-[10px] font-bold rounded'>
</span>
</div>
<div className='flex-1 min-w-0'>
<h4 className='text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2'>
OrionTV TV专用客户端
</h4>
<p className='text-sm text-gray-600 dark:text-gray-400 mb-3'>
tv专用
</p>
<a
href='https://github.com/mtvpls/MoonTVPlus/releases/tag/OrionTV%E9%80%82%E9%85%8D%E7%89%882'
target='_blank'
rel='noopener noreferrer'
className='inline-flex items-center gap-2 px-4 py-2 bg-indigo-500 hover:bg-indigo-600 text-white text-sm font-medium rounded-lg transition-colors'
>
<Download className='w-4 h-4' />
<ExternalLink className='w-3 h-3' />
</a>
</div>
</div>
</div>
</div>
</div>
{/* 底部说明 */}
<div className='p-6 pt-4 border-t border-gray-200 dark:border-gray-700'>
<p className='text-xs text-gray-500 dark:text-gray-400 text-center'>
使
</p>
</div>
</div>
</div>
</>
);
return (
<>
<div className='relative'>
@@ -2942,6 +3144,11 @@ export const UserMenu: React.FC = () => {
mounted &&
createPortal(deviceManagementPanel, document.body)}
{/* 使用 Portal 将生态应用面板渲染到 document.body */}
{isEcoAppsOpen &&
mounted &&
createPortal(ecoAppsPanel, document.body)}
{/* 确认对话框 */}
{confirmDialog.isOpen &&
mounted &&