From 31c6557214b915775da5070c8449f85db75fd203 Mon Sep 17 00:00:00 2001 From: Izan Gil <66965250+SrIzan10@users.noreply.github.com> Date: Mon, 6 Apr 2026 16:56:20 +0200 Subject: [PATCH] chore(ui): dogpoop redesign (thanks claude, i spent 50 cents on api credits for this) --- apps/web/src/app/globals.css | 130 ++++++++++++++---- .../app/StreamPlayer/StreamPlayer.tsx | 56 +++++--- 2 files changed, 144 insertions(+), 42 deletions(-) diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css index 1b5a98c..4dc51f0 100644 --- a/apps/web/src/app/globals.css +++ b/apps/web/src/app/globals.css @@ -133,9 +133,14 @@ body { @apply bg-background text-foreground; } - - .scrollbar-hide::-webkit-scrollbar { display: none; } - .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; } + + .scrollbar-hide::-webkit-scrollbar { + display: none; + } + .scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; + } } h1 { @@ -147,41 +152,76 @@ h2 { } media-controller { - --media-primary-color: #ffffff; - --media-secondary-color: hsla(var(--background), 0.85); - --media-control-hover-background: hsla(var(--accent), 0.85); - --media-control-background: hsla(var(--secondary), 0.85); - --media-loading-icon-color: #ffffff; + --media-primary-color: hsl(var(--primary-foreground)); + --media-secondary-color: transparent; + --media-control-background: transparent; + --media-control-hover-background: hsl(var(--primary) / 0.25); + --media-icon-color: hsl(var(--primary-foreground)); + --media-text-color: hsl(var(--primary-foreground)); + --media-loading-icon-color: hsl(var(--primary-foreground)); + --media-font-family: inherit; + --media-font-size: 0.75rem; + --media-control-height: 36px; + --media-control-padding: 0 8px; border-radius: var(--radius); overflow: hidden; - border: 1px solid hsl(var(--border)); + border: 1px solid hsl(var(--border) / 0.6); + box-shadow: 0 4px 24px hsl(var(--background) / 0.4); } media-control-bar { - background-color: hsla(var(--background), 0.8); - backdrop-filter: blur(8px); + background: linear-gradient( + to top, + hsl(var(--mantle) / 0.95) 0%, + hsl(var(--background) / 0.7) 100% + ); + backdrop-filter: blur(12px) saturate(1.4); + -webkit-backdrop-filter: blur(12px) saturate(1.4); width: 100%; box-sizing: border-box; justify-content: space-between; + padding: 0 6px; + border-top: 1px solid hsl(var(--border) / 0.3); + height: 44px; } media-time-range { - --media-range-track-height: 6px; - --media-range-thumb-height: 14px; - --media-range-thumb-width: 14px; + --media-control-background: transparent; + --media-control-hover-background: transparent; + --media-range-track-height: 3px; + --media-range-thumb-height: 12px; + --media-range-thumb-width: 12px; --media-range-thumb-border-radius: 50%; - --media-range-bar-color: #ffffff; - --media-range-thumb-background: #ffffff; - --media-preview-background: hsla(var(--card), 0.9); + --media-range-bar-color: hsl(var(--primary)); + --media-range-thumb-background: hsl(var(--primary)); + --media-range-track-color: hsl(var(--primary-foreground) / 0.2); + --media-range-track-border-radius: 2px; + --media-preview-background: hsl(var(--card) / 0.95); --media-preview-border-radius: var(--radius); } +media-volume-range { + --media-control-background: transparent; + --media-control-hover-background: transparent; + --media-range-track-height: 3px; + --media-range-thumb-height: 10px; + --media-range-thumb-width: 10px; + --media-range-thumb-border-radius: 50%; + --media-range-bar-color: hsl(var(--primary-foreground)); + --media-range-thumb-background: hsl(var(--primary-foreground)); + --media-range-track-color: hsl(var(--primary-foreground) / 0.2); + --media-range-track-border-radius: 2px; + max-width: 72px; +} + media-time-display { - --media-text-color: #ffffff; + --media-text-color: hsl(var(--primary-foreground) / 0.85); + font-size: 0.7rem; + letter-spacing: 0.02em; } media-controller::part(centered-layer) { - background-color: hsla(var(--background), 0.2); + background: radial-gradient(ellipse at center, hsl(var(--background) / 0.15) 0%, transparent 70%); transition: opacity 0.3s ease; } @@ -191,15 +231,55 @@ media-controller:not([mediapaused])[userinactive]::part(centered-layer) { } media-loading-indicator { - --media-loading-icon-width: 48px; - --media-loading-icon-height: 48px; - --media-loading-icon-color: #ffffff; + --media-loading-icon-width: 44px; + --media-loading-icon-height: 44px; + --media-loading-icon-color: hsl(var(--primary)); +} + +media-play-button, +media-mute-button, +media-fullscreen-button, +media-seek-backward-button, +media-seek-forward-button, +media-chrome-button { + border-radius: calc(var(--radius) - 2px); + transition: + background 0.15s ease, + color 0.15s ease; } media-play-button:hover, media-mute-button:hover, media-fullscreen-button:hover, media-seek-backward-button:hover, -media-seek-forward-button:hover { - --media-control-hover-background: rgba(255, 255, 255, 0.2); -} \ No newline at end of file +media-seek-forward-button:hover, +media-chrome-button:hover { + --media-control-hover-background: hsl(var(--primary) / 0.2); +} + +media-live-button { + --media-live-button-icon-color: hsl(var(--primary-foreground) / 0.6); + --media-live-button-indicator-color: hsl(var(--primary-foreground) / 0.4); + font-size: 0.65rem; + letter-spacing: 0.08em; + font-weight: 600; + text-transform: uppercase; +} + +media-live-button[mediatimeislive] { + --media-live-button-icon-color: hsl(var(--primary-foreground)); + --media-live-button-indicator-color: hsl(var(--primary)); +} + +.stream-player-top-bar { + display: flex; + align-items: flex-start; + padding: 10px 12px; + width: 100%; + background: linear-gradient(to bottom, hsl(var(--mantle) / 0.7) 0%, transparent 100%); + pointer-events: none; +} + +.stream-player-top-bar > * { + pointer-events: auto; +} diff --git a/apps/web/src/components/app/StreamPlayer/StreamPlayer.tsx b/apps/web/src/components/app/StreamPlayer/StreamPlayer.tsx index ea29cfb..5980e18 100644 --- a/apps/web/src/components/app/StreamPlayer/StreamPlayer.tsx +++ b/apps/web/src/components/app/StreamPlayer/StreamPlayer.tsx @@ -11,6 +11,7 @@ import { MediaVolumeRange, MediaFullscreenButton, MediaChromeButton, + MediaLiveButton, } from 'media-chrome/react'; import { RefreshCw, RotateCw } from 'lucide-react'; import HlsVideo from 'hls-video-element/react'; @@ -25,6 +26,15 @@ import { cn } from '@/lib/utils'; const WAITING_RECOVERY_DELAY_MS = 8000; const RECOVERY_COOLDOWN_MS = 2000; +function LiveBadge({ recovering }: { recovering: boolean }) { + return ( +
+ + {recovering ? 'Reconnecting' : 'Live'} +
+ ); +} + export default function StreamPlayer() { const { username } = useParams(); const { session } = useSession(); @@ -177,7 +187,7 @@ export default function StreamPlayer() { }, [clearWaitingTimeout, playerKey, triggerRecovery]); return ( -
+
- -
- - - -
-
- {(process.env.NODE_ENV === 'development' || userInfo?.isLive) && ( - triggerRecovery('manual_reload')}> - - - - Retry stream - - )} - + + {/* Top bar — live badge */} + {userInfo?.isLive && ( +
+
+ )} + + + + + +
+ {userInfo?.isLive && } + {(process.env.NODE_ENV === 'development' || userInfo?.isLive) && ( + triggerRecovery('manual_reload')} + className={cn('transition-opacity', isRecovering && 'opacity-50 pointer-events-none')} + > + + + + Retry stream + + )} +