Files
k-tv/k-tv-frontend/app/(main)/tv/components/top-control-bar.tsx
Gabriel Kaszewski 8ed8da2d90 refactor(frontend): extract logic to hooks, split inline components
Area 1 (tv/page.tsx 964→423 lines):
- hooks: use-fullscreen, use-idle, use-volume, use-quality, use-subtitles,
  use-channel-input, use-channel-passwords, use-tv-keyboard
- components: SubtitlePicker, VolumeControl, QualityPicker, TopControlBar,
  LogoWatermark, AutoplayPrompt, ChannelNumberOverlay, TvBaseLayer

Area 2 (edit-channel-sheet.tsx 1244→678 lines):
- hooks: use-channel-form (all form state + reset logic)
- lib/schemas.ts: extracted Zod schemas + extractErrors
- components: AlgorithmicFilterEditor, RecyclePolicyEditor, WebhookEditor,
  AccessSettingsEditor, LogoEditor

Area 3 (dashboard/page.tsx 406→261 lines):
- hooks: use-channel-order, use-import-channel, use-regenerate-all
- lib/channel-export.ts: pure export utility
- components: DashboardHeader
2026-03-17 02:25:02 +01:00

157 lines
4.4 KiB
TypeScript

import { Cast, Info, Maximize2, Minimize2 } from "lucide-react";
import type { LucideIcon } from "lucide-react";
import { SubtitlePicker } from "./subtitle-picker";
import { VolumeControl } from "./volume-control";
import { QualityPicker } from "./quality-picker";
import type { SubtitleTrack } from "./video-player";
interface TopControlBarProps {
// Subtitles
subtitleTracks: SubtitleTrack[];
activeSubtitleTrack: number;
showSubtitlePicker: boolean;
onToggleSubtitlePicker: () => void;
onChangeSubtitleTrack: (id: number) => void;
// Volume
volume: number;
isMuted: boolean;
VolumeIcon: LucideIcon;
showVolumeSlider: boolean;
onToggleVolumeSlider: () => void;
onToggleMute: () => void;
onVolumeChange: (v: number) => void;
// Fullscreen
isFullscreen: boolean;
onToggleFullscreen: () => void;
// Cast
castAvailable: boolean;
isCasting: boolean;
castDeviceName?: string | null;
streamUrl?: string | null;
onRequestCast: (url: string) => void;
onStopCasting: () => void;
// Quality
quality: string;
qualityOptions: { value: string; label: string }[];
showQualityPicker: boolean;
onToggleQualityPicker: () => void;
onChangeQuality: (q: string) => void;
// Stats & guide
showStats: boolean;
onToggleStats: () => void;
showSchedule: boolean;
onToggleSchedule: () => void;
}
export function TopControlBar({
subtitleTracks,
activeSubtitleTrack,
showSubtitlePicker,
onToggleSubtitlePicker,
onChangeSubtitleTrack,
volume,
isMuted,
VolumeIcon,
showVolumeSlider,
onToggleVolumeSlider,
onToggleMute,
onVolumeChange,
isFullscreen,
onToggleFullscreen,
castAvailable,
isCasting,
castDeviceName,
streamUrl,
onRequestCast,
onStopCasting,
quality,
qualityOptions,
showQualityPicker,
onToggleQualityPicker,
onChangeQuality,
showStats,
onToggleStats,
showSchedule,
onToggleSchedule,
}: TopControlBarProps) {
return (
<div className="flex justify-end gap-2 p-4">
<SubtitlePicker
tracks={subtitleTracks}
activeTrack={activeSubtitleTrack}
show={showSubtitlePicker}
onToggle={onToggleSubtitlePicker}
onChangeTrack={(id) => {
onChangeSubtitleTrack(id);
if (id !== activeSubtitleTrack) onToggleSubtitlePicker();
}}
/>
<VolumeControl
volume={volume}
isMuted={isMuted}
VolumeIcon={VolumeIcon}
showSlider={showVolumeSlider}
onToggleSlider={onToggleVolumeSlider}
onToggleMute={onToggleMute}
onVolumeChange={(v) => {
onVolumeChange(v);
}}
/>
<button
className="pointer-events-auto rounded-md bg-black/50 p-1.5 text-zinc-400 backdrop-blur transition-colors hover:bg-black/70 hover:text-white"
onClick={onToggleFullscreen}
title={isFullscreen ? "Exit fullscreen [F]" : "Fullscreen [F]"}
>
{isFullscreen ? (
<Minimize2 className="h-4 w-4" />
) : (
<Maximize2 className="h-4 w-4" />
)}
</button>
{castAvailable && (
<button
className={`pointer-events-auto rounded-md bg-black/50 p-1.5 backdrop-blur transition-colors hover:bg-black/70 hover:text-white ${
isCasting ? "text-blue-400" : "text-zinc-400"
}`}
onClick={() =>
isCasting ? onStopCasting() : streamUrl && onRequestCast(streamUrl)
}
title={
isCasting
? `Stop casting to ${castDeviceName ?? "TV"}`
: "Cast to TV"
}
>
<Cast className="h-4 w-4" />
</button>
)}
<QualityPicker
quality={quality}
options={qualityOptions}
showPicker={showQualityPicker}
onToggle={onToggleQualityPicker}
onChangeQuality={onChangeQuality}
/>
<button
className={`pointer-events-auto rounded-md bg-black/50 p-1.5 backdrop-blur transition-colors hover:bg-black/70 hover:text-white ${showStats ? "text-violet-400" : "text-zinc-400"}`}
onClick={onToggleStats}
title="Stats for nerds [S]"
>
<Info className="h-4 w-4" />
</button>
<button
className="pointer-events-auto rounded-md bg-black/50 px-3 py-1.5 text-xs text-zinc-400 backdrop-blur transition-colors hover:bg-black/70 hover:text-white"
onClick={onToggleSchedule}
>
{showSchedule ? "Hide guide" : "Guide [G]"}
</button>
</div>
);
}