- Detect shorts by duration (SHORTS_MAX_DURATION_SECONDS, default 180)
and expose is_short in feed, video and channel-activity DTOs.
- Feed gains type=all|long|short and anchor; lists show a two-mode
'Обычные | Shorts' filter (no 'Все') persisted in the URL.
- Clicking a short opens /shorts/🆔 a vertical scroll-snap feed with
autoplay for the active slide, context-aware endpoints and infinite
loading.
- Keep the sound choice across swipes, syncing with the player's own
mute control and guarding against the widget's stale isMuted() reads.
42 lines
2.2 KiB
TypeScript
42 lines
2.2 KiB
TypeScript
import { useQuery } from '@tanstack/react-query'
|
||
import { Link, Navigate, Route, Routes } from 'react-router-dom'
|
||
import { getAuthStatus } from './api/client'
|
||
import AppShell from './components/AppShell'
|
||
import Connect from './pages/Connect'
|
||
import Feed from './pages/Feed'
|
||
import Channels from './pages/Channels'
|
||
import ChannelVideos from './pages/ChannelVideos'
|
||
import VideoPage from './pages/VideoPage'
|
||
import ShortsFeed from './pages/ShortsFeed'
|
||
import Categories from './pages/Categories'
|
||
import Settings from './pages/Settings'
|
||
import './App.css'
|
||
|
||
function App() {
|
||
const { data, isLoading, isError } = useQuery({ queryKey: ['auth-status'], queryFn: getAuthStatus })
|
||
|
||
if (isLoading) return <div className="app-loading"><span className="brand-mark">▶</span><p>Открываем MyTube…</p></div>
|
||
if (isError) return <div className="app-loading"><h1>Не удалось открыть MyTube</h1><p>Проверь подключение к серверу и обнови страницу.</p><button onClick={() => window.location.reload()}>Повторить</button></div>
|
||
if (!data?.authenticated) return <Connect />
|
||
|
||
return <AppShell>
|
||
<Routes>
|
||
<Route path="/" element={<Feed />} />
|
||
<Route path="/category/:categoryId" element={<Feed />} />
|
||
<Route path="/uncategorized" element={<Feed />} />
|
||
<Route path="/local" element={<Feed />} />
|
||
<Route path="/search" element={<Feed />} />
|
||
<Route path="/saved" element={<Navigate to="/local" replace />} />
|
||
<Route path="/channels" element={<Channels />} />
|
||
<Route path="/channels/:channelId/videos" element={<ChannelVideos />} />
|
||
<Route path="/video/:youtubeVideoId" element={<VideoPage />} />
|
||
<Route path="/shorts/:youtubeVideoId" element={<ShortsFeed />} />
|
||
<Route path="/settings" element={<Settings email={data.email} />} />
|
||
<Route path="/settings/categories" element={<Categories />} />
|
||
<Route path="/categories" element={<Navigate to="/settings/categories" replace />} />
|
||
<Route path="*" element={<div className="empty-state"><h1>Страница не найдена</h1><Link to="/">Вернуться к ленте</Link></div>} />
|
||
</Routes>
|
||
</AppShell>
|
||
}
|
||
|
||
export default App
|