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
40 lines
982 B
TypeScript
40 lines
982 B
TypeScript
import type { LogoPosition } from "@/lib/types";
|
|
|
|
function logoPositionClass(pos?: LogoPosition) {
|
|
switch (pos) {
|
|
case "top_left":
|
|
return "top-0 left-0";
|
|
case "bottom_left":
|
|
return "bottom-0 left-0";
|
|
case "bottom_right":
|
|
return "bottom-0 right-0";
|
|
default:
|
|
return "top-0 right-0";
|
|
}
|
|
}
|
|
|
|
interface LogoWatermarkProps {
|
|
logo: string;
|
|
position?: LogoPosition;
|
|
opacity?: number;
|
|
}
|
|
|
|
export function LogoWatermark({ logo, position, opacity = 1 }: LogoWatermarkProps) {
|
|
return (
|
|
<div
|
|
className={`pointer-events-none absolute z-10 p-3 ${logoPositionClass(position)}`}
|
|
style={{ opacity }}
|
|
>
|
|
{logo.trimStart().startsWith("<") ? (
|
|
<div
|
|
dangerouslySetInnerHTML={{ __html: logo }}
|
|
className="h-12 w-auto"
|
|
/>
|
|
) : (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img src={logo} alt="" className="h-12 w-auto object-contain" />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|