WIP: feat(frontend): overhaul styling with warm and editorial look #12

Closed
dylan wants to merge 15 commits from feat/overhaul-frontend-design into master
2 changed files with 12 additions and 16 deletions
Showing only changes of commit 255e48ffb1 - Show all commits

View File

@@ -137,7 +137,7 @@ const Home = () => {
setVods(topSix);
setCounts(prev => ({ ...prev, vods: data.length }));
})
}, []);
}, [user]);
const handleDropMarker = async () => {
if (markerBusy) return;
@@ -274,9 +274,9 @@ const Home = () => {
fps={vod.fps}
fileSize={vod.fileSize}
mediaApiPath="/api/v1/vods"
playerPath="/vod"
playerPath="/video"
itemLabel="vod"
onEdit={() => navigate(`/vods/${vod.id}/edit`)}
onEdit={() => navigate(`/video/${vod.id}/edit`)}
/>
))}
</div>
@@ -298,9 +298,9 @@ const Home = () => {
fps={clip.fps}
fileSize={clip.fileSize}
mediaApiPath="/api/v1/clips"
playerPath="/clip"
playerPath="/video"
itemLabel="clip"
onEdit={() => navigate(`/clip/${clip.id}/edit`)}
onEdit={() => navigate(`/video/${clip.id}/edit`)}
/>
))}
</div>

View File

@@ -69,10 +69,6 @@ const MediaPlayer = ({ noun, getMediaUrl, fetchDetails }: MediaPlayerProps) => {
}, []);
// ── Data loading ────────────────────────────────────────────────────────
// The video stream itself is loaded by the <video> element from `mediaUrl`,
// which lets the browser fetch it incrementally via Range requests. We only
// need to fetch the metadata here; it shares the media endpoint's auth, so a
// 401/403 here also stands in for the stream being inaccessible.
useEffect(() => {
if (!id) { setError(`${noun} ID is required.`); return; }
@@ -82,6 +78,7 @@ const MediaPlayer = ({ noun, getMediaUrl, fetchDetails }: MediaPlayerProps) => {
if (e instanceof AuthError) setNotAuthenticated(true);
else setError(`Failed to load ${noun.toLowerCase()} details.`);
});
}, [id, noun, fetchDetails]);
useEffect(() => {
@@ -103,7 +100,6 @@ const MediaPlayer = ({ noun, getMediaUrl, fetchDetails }: MediaPlayerProps) => {
scheduleHide();
}, [scheduleHide]);
// ── Fullscreen ──────────────────────────────────────────────────────────
useEffect(() => {
const onChange = () => setIsFullscreen(!!document.fullscreenElement);
document.addEventListener('fullscreenchange', onChange);
@@ -259,7 +255,7 @@ const MediaPlayer = ({ noun, getMediaUrl, fetchDetails }: MediaPlayerProps) => {
<div className="h-full flex flex-col px-13 py-8 gap-4">
<button
onClick={() => navigate(-1)}
className={clsx(quietLinkClass, "flex items-center gap-1.5 flex-shrink-0")}
className={clsx(quietLinkClass, "flex items-center gap-1.5 shrink-0")}
>
<ArrowLeft size={15} />
Back
@@ -307,7 +303,7 @@ const MediaPlayer = ({ noun, getMediaUrl, fetchDetails }: MediaPlayerProps) => {
{/* Action flash — a badge that swells and fades on play, pause and seek. */}
{flash && FlashIcon && (
<div key={flash.id} className="absolute inset-0 flex items-center justify-center pointer-events-none">
<div className="animate-flash-badge flex h-[74px] w-[74px] items-center justify-center rounded-full bg-player/55 backdrop-blur-[2px] text-on-dark">
<div className="animate-flash-badge flex h-18.5 w-18.5 items-center justify-center rounded-full bg-player/55 backdrop-blur-[2px] text-on-dark">
<FlashIcon size={30} fill="currentColor" strokeWidth={1} />
</div>
</div>
@@ -316,8 +312,8 @@ const MediaPlayer = ({ noun, getMediaUrl, fetchDetails }: MediaPlayerProps) => {
{/* Controls overlay — pointer-events-none so video clicks pass through */}
<div className={`absolute inset-0 flex flex-col justify-end transition-opacity duration-300 pointer-events-none ${controlsVisible ? 'opacity-100' : 'opacity-0'}`}>
{/* Gradients — top one carries the title, bottom one the controls */}
<div className="absolute inset-x-0 top-0 h-28 bg-gradient-to-b from-black/55 to-transparent" />
<div className="absolute inset-0 bg-gradient-to-t from-black/75 via-black/10 to-transparent" />
<div className="absolute inset-x-0 top-0 h-28 bg-linear-to-b from-black/55 to-transparent" />
<div className="absolute inset-0 bg-linear-to-t from-black/75 via-black/10 to-transparent" />
{/* Title plate */}
<div className={clsx(
@@ -365,7 +361,7 @@ const MediaPlayer = ({ noun, getMediaUrl, fetchDetails }: MediaPlayerProps) => {
{/* Time under the cursor */}
{hoverTime !== null && (
<div
className="absolute bottom-4 -translate-x-1/2 rounded-[6px] bg-player/85 px-1.5 py-0.5 font-data text-[11px] text-on-dark tabular-nums pointer-events-none"
className="absolute bottom-4 -translate-x-1/2 rounded-md bg-player/85 px-1.5 py-0.5 font-data text-[11px] text-on-dark tabular-nums pointer-events-none"
style={{ left: `${hoverPct}%` }}
>
{formatTime(hoverTime)}
@@ -416,7 +412,7 @@ const MediaPlayer = ({ noun, getMediaUrl, fetchDetails }: MediaPlayerProps) => {
<p className="font-data text-[12px] text-faint-mono">loading video…</p>
)}
<Card className="p-5 flex-shrink-0 flex flex-wrap items-end justify-between gap-x-8 gap-y-3">
<Card className="p-5 shrink-0 flex flex-wrap items-end justify-between gap-x-8 gap-y-3">
<div className="min-w-0">
<p className={kickerClass}>{noun}</p>
<p className="font-heading text-[25px] tracking-[-0.015em] leading-tight pt-1">