feat: Wired /embed/:videoId route outside AppShell for chrome-free rend…
- "frontend/src/App.tsx" - "frontend/src/pages/WatchPage.tsx" - "frontend/src/App.css" GSD-Task: S03/T02
This commit is contained in:
parent
cf7c8b26a0
commit
ddb283cc28
4 changed files with 58 additions and 4 deletions
|
|
@ -6449,6 +6449,13 @@ a.app-footer__about:hover,
|
|||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.watch-page__header-top {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.watch-page__title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
|
|
@ -6456,6 +6463,29 @@ a.app-footer__about:hover,
|
|||
margin: 0 0 0.25rem;
|
||||
}
|
||||
|
||||
.watch-page__embed-btn {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.3rem 0.75rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
background: var(--surface-alt, var(--surface));
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition: background 0.15s, color 0.15s, border-color 0.15s;
|
||||
}
|
||||
|
||||
.watch-page__embed-btn:hover {
|
||||
border-color: var(--accent);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.watch-page__embed-btn--copied {
|
||||
background: var(--accent);
|
||||
color: var(--surface);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.watch-page__creator {
|
||||
font-size: 0.9rem;
|
||||
color: var(--accent);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ const CreatorTiers = React.lazy(() => import("./pages/CreatorTiers"));
|
|||
const PostEditor = React.lazy(() => import("./pages/PostEditor"));
|
||||
const PostsList = React.lazy(() => import("./pages/PostsList"));
|
||||
const ShortPlayer = React.lazy(() => import("./pages/ShortPlayer"));
|
||||
const EmbedPlayer = React.lazy(() => import("./pages/EmbedPlayer"));
|
||||
import AdminDropdown from "./components/AdminDropdown";
|
||||
import ImpersonationBanner from "./components/ImpersonationBanner";
|
||||
import AppFooter from "./components/AppFooter";
|
||||
|
|
@ -228,7 +229,10 @@ function AppShell() {
|
|||
export default function App() {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<AppShell />
|
||||
<Routes>
|
||||
<Route path="/embed/:videoId" element={<Suspense fallback={<LoadingFallback />}><EmbedPlayer /></Suspense>} />
|
||||
<Route path="/*" element={<AppShell />} />
|
||||
</Routes>
|
||||
</AuthProvider>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { useParams, useSearchParams, Link } from "react-router-dom";
|
||||
import { useDocumentTitle } from "../hooks/useDocumentTitle";
|
||||
import { useMediaSync } from "../hooks/useMediaSync";
|
||||
|
|
@ -10,6 +10,7 @@ import VideoPlayer from "../components/VideoPlayer";
|
|||
import AudioWaveform from "../components/AudioWaveform";
|
||||
import PlayerControls from "../components/PlayerControls";
|
||||
import TranscriptSidebar from "../components/TranscriptSidebar";
|
||||
import { copyToClipboard } from "../utils/clipboard";
|
||||
|
||||
export default function WatchPage() {
|
||||
const { videoId } = useParams<{ videoId: string }>();
|
||||
|
|
@ -25,9 +26,20 @@ export default function WatchPage() {
|
|||
const [error, setError] = useState<string | null>(null);
|
||||
const [transcriptError, setTranscriptError] = useState(false);
|
||||
const [chapters, setChapters] = useState<Chapter[]>([]);
|
||||
const [embedCopied, setEmbedCopied] = useState(false);
|
||||
|
||||
const mediaSync = useMediaSync();
|
||||
|
||||
const handleCopyEmbed = useCallback(async () => {
|
||||
const height = video?.video_url ? 405 : 120;
|
||||
const snippet = `<iframe src="${window.location.origin}/embed/${videoId}" width="720" height="${height}" frameborder="0" allowfullscreen></iframe>`;
|
||||
const ok = await copyToClipboard(snippet);
|
||||
if (ok) {
|
||||
setEmbedCopied(true);
|
||||
setTimeout(() => setEmbedCopied(false), 2000);
|
||||
}
|
||||
}, [videoId, video?.video_url]);
|
||||
|
||||
useDocumentTitle(video ? `${video.filename} — Chrysopedia` : "Loading…");
|
||||
|
||||
// Fetch video detail
|
||||
|
|
@ -106,7 +118,15 @@ export default function WatchPage() {
|
|||
return (
|
||||
<div className="watch-page">
|
||||
<header className="watch-page__header">
|
||||
<div className="watch-page__header-top">
|
||||
<h1 className="watch-page__title">{video.filename}</h1>
|
||||
<button
|
||||
className={`watch-page__embed-btn${embedCopied ? " watch-page__embed-btn--copied" : ""}`}
|
||||
onClick={handleCopyEmbed}
|
||||
>
|
||||
{embedCopied ? "Copied!" : "Copy Embed Code"}
|
||||
</button>
|
||||
</div>
|
||||
{video.creator_name && video.creator_slug && (
|
||||
<Link
|
||||
to={`/creators/${video.creator_slug}`}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/admin-pipeline.ts","./src/api/admin-techniques.ts","./src/api/auth.ts","./src/api/chat.ts","./src/api/client.ts","./src/api/consent.ts","./src/api/creator-dashboard.ts","./src/api/creators.ts","./src/api/follows.ts","./src/api/highlights.ts","./src/api/index.ts","./src/api/posts.ts","./src/api/reports.ts","./src/api/search.ts","./src/api/shorts.ts","./src/api/stats.ts","./src/api/techniques.ts","./src/api/topics.ts","./src/api/videos.ts","./src/components/AdminDropdown.tsx","./src/components/AppFooter.tsx","./src/components/AudioWaveform.tsx","./src/components/CategoryIcons.tsx","./src/components/ChapterMarkers.tsx","./src/components/ChatWidget.tsx","./src/components/ConfirmModal.tsx","./src/components/CopyLinkButton.tsx","./src/components/CreatorAvatar.tsx","./src/components/ImpersonationBanner.tsx","./src/components/PersonalityProfile.tsx","./src/components/PlayerControls.tsx","./src/components/PostsFeed.tsx","./src/components/ProtectedRoute.tsx","./src/components/ReportIssueModal.tsx","./src/components/SearchAutocomplete.tsx","./src/components/SocialIcons.tsx","./src/components/SortDropdown.tsx","./src/components/TableOfContents.tsx","./src/components/TagList.tsx","./src/components/ToggleSwitch.tsx","./src/components/TranscriptSidebar.tsx","./src/components/VideoPlayer.tsx","./src/context/AuthContext.tsx","./src/hooks/useCountUp.ts","./src/hooks/useDocumentTitle.ts","./src/hooks/useMediaSync.ts","./src/hooks/useSortPreference.ts","./src/pages/About.tsx","./src/pages/AdminAuditLog.tsx","./src/pages/AdminPipeline.tsx","./src/pages/AdminReports.tsx","./src/pages/AdminTechniquePages.tsx","./src/pages/AdminUsers.tsx","./src/pages/ChapterReview.tsx","./src/pages/ChatPage.tsx","./src/pages/ConsentDashboard.tsx","./src/pages/CreatorDashboard.tsx","./src/pages/CreatorDetail.tsx","./src/pages/CreatorSettings.tsx","./src/pages/CreatorTiers.tsx","./src/pages/CreatorsBrowse.tsx","./src/pages/HighlightQueue.tsx","./src/pages/Home.tsx","./src/pages/Login.tsx","./src/pages/PostEditor.tsx","./src/pages/PostsList.tsx","./src/pages/Register.tsx","./src/pages/SearchResults.tsx","./src/pages/ShortPlayer.tsx","./src/pages/SubTopicPage.tsx","./src/pages/TechniquePage.tsx","./src/pages/TopicsBrowse.tsx","./src/pages/WatchPage.tsx","./src/utils/catSlug.ts","./src/utils/citations.tsx"],"version":"5.6.3"}
|
||||
{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/admin-pipeline.ts","./src/api/admin-techniques.ts","./src/api/auth.ts","./src/api/chat.ts","./src/api/client.ts","./src/api/consent.ts","./src/api/creator-dashboard.ts","./src/api/creators.ts","./src/api/follows.ts","./src/api/highlights.ts","./src/api/index.ts","./src/api/posts.ts","./src/api/reports.ts","./src/api/search.ts","./src/api/shorts.ts","./src/api/stats.ts","./src/api/techniques.ts","./src/api/topics.ts","./src/api/videos.ts","./src/components/AdminDropdown.tsx","./src/components/AppFooter.tsx","./src/components/AudioWaveform.tsx","./src/components/CategoryIcons.tsx","./src/components/ChapterMarkers.tsx","./src/components/ChatWidget.tsx","./src/components/ConfirmModal.tsx","./src/components/CopyLinkButton.tsx","./src/components/CreatorAvatar.tsx","./src/components/ImpersonationBanner.tsx","./src/components/PersonalityProfile.tsx","./src/components/PlayerControls.tsx","./src/components/PostsFeed.tsx","./src/components/ProtectedRoute.tsx","./src/components/ReportIssueModal.tsx","./src/components/SearchAutocomplete.tsx","./src/components/SocialIcons.tsx","./src/components/SortDropdown.tsx","./src/components/TableOfContents.tsx","./src/components/TagList.tsx","./src/components/ToggleSwitch.tsx","./src/components/TranscriptSidebar.tsx","./src/components/VideoPlayer.tsx","./src/context/AuthContext.tsx","./src/hooks/useCountUp.ts","./src/hooks/useDocumentTitle.ts","./src/hooks/useMediaSync.ts","./src/hooks/useSortPreference.ts","./src/pages/About.tsx","./src/pages/AdminAuditLog.tsx","./src/pages/AdminPipeline.tsx","./src/pages/AdminReports.tsx","./src/pages/AdminTechniquePages.tsx","./src/pages/AdminUsers.tsx","./src/pages/ChapterReview.tsx","./src/pages/ChatPage.tsx","./src/pages/ConsentDashboard.tsx","./src/pages/CreatorDashboard.tsx","./src/pages/CreatorDetail.tsx","./src/pages/CreatorSettings.tsx","./src/pages/CreatorTiers.tsx","./src/pages/CreatorsBrowse.tsx","./src/pages/EmbedPlayer.tsx","./src/pages/HighlightQueue.tsx","./src/pages/Home.tsx","./src/pages/Login.tsx","./src/pages/PostEditor.tsx","./src/pages/PostsList.tsx","./src/pages/Register.tsx","./src/pages/SearchResults.tsx","./src/pages/ShortPlayer.tsx","./src/pages/SubTopicPage.tsx","./src/pages/TechniquePage.tsx","./src/pages/TopicsBrowse.tsx","./src/pages/WatchPage.tsx","./src/utils/catSlug.ts","./src/utils/citations.tsx","./src/utils/clipboard.ts"],"version":"5.6.3"}
|
||||
Loading…
Add table
Reference in a new issue