Remove supported sites page (#40)

* Remove supported sites page

* Remove supported sites page component
This commit is contained in:
Nexmoe
2025-12-19 20:41:58 +08:00
committed by GitHub
parent 41f40b6e71
commit db16d5d051
3 changed files with 34 additions and 133 deletions

View File

@@ -14,18 +14,16 @@ import { About } from './pages/About'
import { Home } from './pages/Home'
import { Settings } from './pages/Settings'
import { Subscriptions } from './pages/Subscriptions'
import { SupportedSites } from './pages/SupportedSites'
import { loadSettingsAtom, settingsAtom } from './store/settings'
import { loadSubscriptionsAtom, setSubscriptionsAtom } from './store/subscriptions'
type Page = 'home' | 'subscriptions' | 'settings' | 'about' | 'sites'
type Page = 'home' | 'subscriptions' | 'settings' | 'about'
const pageToPath: Record<Page, string> = {
home: '/',
subscriptions: '/subscriptions',
settings: '/settings',
about: '/about',
sites: '/sites'
about: '/about'
}
const normalizePathname = (pathname: string): string => {
@@ -42,8 +40,6 @@ const pathToPage = (pathname: string): Page => {
return 'settings'
case '/about':
return 'about'
case '/sites':
return 'sites'
default:
return 'home'
}
@@ -61,6 +57,7 @@ function AppContent() {
const navigate = useNavigate()
const location = useLocation()
const currentPage = pathToPage(location.pathname)
const supportedSitesUrl = 'https://vidbee.org/supported-sites/'
const handlePageChange = (page: Page) => {
const targetPath = pageToPath[page] ?? '/'
@@ -69,6 +66,10 @@ function AppContent() {
}
}
const handleOpenSupportedSites = () => {
window.open(supportedSitesUrl, '_blank')
}
useEffect(() => {
loadSettings()
}, [loadSettings])
@@ -227,7 +228,11 @@ function AppContent() {
return (
<div className="flex flex-row h-screen">
{/* Sidebar Navigation */}
<Sidebar currentPage={currentPage} onPageChange={handlePageChange} />
<Sidebar
currentPage={currentPage}
onPageChange={handlePageChange}
onOpenSupportedSites={handleOpenSupportedSites}
/>
{/* Main Content */}
<main className="flex flex-col flex-1 min-h-0 overflow-hidden bg-background">
@@ -244,7 +249,7 @@ function AppContent() {
path="/"
element={
<Home
onOpenSupportedSites={() => handlePageChange('sites')}
onOpenSupportedSites={handleOpenSupportedSites}
onOpenSettings={() => handlePageChange('settings')}
/>
}
@@ -252,7 +257,6 @@ function AppContent() {
<Route path="/subscriptions" element={<Subscriptions />} />
<Route path="/settings" element={<Settings />} />
<Route path="/about" element={<About />} />
<Route path="/sites" element={<SupportedSites />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</div>

View File

@@ -24,9 +24,20 @@ import MingcuteRssLine from '~icons/mingcute/rss-line'
import MingcuteSettingsFill from '~icons/mingcute/settings-3-fill'
import MingcuteSettingsLine from '~icons/mingcute/settings-3-line'
type Page = 'home' | 'subscriptions' | 'settings' | 'about' | 'sites'
type Page = 'home' | 'subscriptions' | 'settings' | 'about'
type NavigationTarget = Page | 'supported-sites'
interface NavigationItem {
id: NavigationTarget
icon: {
active: React.ComponentType<{ className?: string }>
inactive: React.ComponentType<{ className?: string }>
}
label: string
onClick?: () => void
}
interface PageNavigationItem {
id: Page
icon: {
active: React.ComponentType<{ className?: string }>
@@ -38,9 +49,10 @@ interface NavigationItem {
interface SidebarProps {
currentPage: Page
onPageChange: (page: Page) => void
onOpenSupportedSites: () => void
}
export function Sidebar({ currentPage, onPageChange }: SidebarProps) {
export function Sidebar({ currentPage, onPageChange, onOpenSupportedSites }: SidebarProps) {
const { t, i18n } = useTranslation()
const saveSetting = useSetAtom(saveSettingAtom)
@@ -64,16 +76,17 @@ export function Sidebar({ currentPage, onPageChange }: SidebarProps) {
label: t('menu.rss')
},
{
id: 'sites',
id: 'supported-sites',
icon: {
active: MingcuteCheckCircleFill,
inactive: MingcuteCheckCircleLine
},
label: t('menu.supportedSites')
label: t('menu.supportedSites'),
onClick: onOpenSupportedSites
}
]
const bottomNavigationItems: NavigationItem[] = [
const bottomNavigationItems: PageNavigationItem[] = [
{
id: 'settings',
icon: {
@@ -107,15 +120,16 @@ export function Sidebar({ currentPage, onPageChange }: SidebarProps) {
}
const renderNavigationItem = (item: NavigationItem, showLabel = true) => {
const isActive = currentPage === item.id
const isActive = item.id !== 'supported-sites' && currentPage === item.id
const IconComponent = isActive ? item.icon.active : item.icon.inactive
const handleClick = item.onClick ?? (() => onPageChange(item.id as Page))
return (
<div key={item.id} className="flex flex-col items-center gap-1">
<Button
variant="ghost"
size="icon"
onClick={() => onPageChange(item.id)}
onClick={handleClick}
className={`no-drag w-12 h-12 ${isActive ? 'bg-primary/10' : ''}`}
>
<IconComponent className={`h-5! w-5! ${isActive ? 'text-primary' : ''}`} />

View File

@@ -1,117 +0,0 @@
import { Button } from '@renderer/components/ui/button'
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle
} from '@renderer/components/ui/card'
import { RemoteImage } from '@renderer/components/ui/remote-image'
import { popularSites } from '@renderer/data/popularSites'
import { ipcServices } from '@renderer/lib/ipc'
import { ExternalLink } from 'lucide-react'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
const referenceUrl = 'https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md'
function SiteIcon({ domain, alt }: { domain: string; alt: string }) {
const [iconUrl, setIconUrl] = useState<string | null>(null)
useEffect(() => {
let cancelled = false
const loadIcon = async () => {
try {
const dataUrl = await ipcServices.app.getSiteIcon(domain)
if (!cancelled) {
setIconUrl(dataUrl)
}
} catch (error) {
console.error('Failed to load site icon:', error)
if (!cancelled) {
setIconUrl(null)
}
}
}
void loadIcon()
return () => {
cancelled = true
}
}, [domain])
return <RemoteImage src={iconUrl} alt={alt} className="w-full h-full" />
}
export function SupportedSites() {
const { t } = useTranslation()
return (
<div className="container mx-auto max-w-5xl p-6 space-y-6" style={{ maxWidth: '100%' }}>
<Card>
<CardHeader>
<CardTitle>{t('sites.pageTitle')}</CardTitle>
<CardDescription>{t('sites.pageDescription')}</CardDescription>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">{t('sites.pageIntro')}</p>
</CardContent>
</Card>
<section className="space-y-3">
<h2 className="text-lg font-semibold px-6">{t('sites.popularSection')}</h2>
<ul className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
{popularSites.map((site) => {
const labelKey = `sites.popular.${site.id}.label`
const descriptionKey = `sites.popular.${site.id}.description`
const label = t(labelKey)
const description = t(descriptionKey)
const hasDescription = description !== descriptionKey
return (
<li key={site.id}>
<a
href={site.url}
target="_blank"
rel="noreferrer"
className="flex items-center gap-3 rounded-md border border-border px-4 py-3 transition-colors hover:bg-muted/50 hover:border-primary/50 group"
>
<div className="shrink-0 w-10 h-10 rounded-xs overflow-hidden">
<SiteIcon domain={site.domain} alt={label} />
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<p className="text-sm font-medium truncate">{label}</p>
<ExternalLink className="w-3 h-3 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity shrink-0" />
</div>
{hasDescription ? (
<p className="mt-0.5 text-xs text-muted-foreground line-clamp-1">
{description}
</p>
) : null}
</div>
</a>
</li>
)
})}
</ul>
</section>
<Card>
<CardHeader>
<CardTitle>{t('sites.moreTitle')}</CardTitle>
<CardDescription>{t('sites.moreDescription')}</CardDescription>
</CardHeader>
<CardContent>
<Button asChild variant="outline">
<a href={referenceUrl} target="_blank" rel="noreferrer">
{t('sites.openFullList')}
</a>
</Button>
</CardContent>
</Card>
</div>
)
}