Skip to content

Commit

Permalink
chore: Renamed to ui
Browse files Browse the repository at this point in the history
  • Loading branch information
matvp91 committed Sep 6, 2024
1 parent fe1266d commit 8d2400d
Show file tree
Hide file tree
Showing 36 changed files with 211 additions and 54 deletions.
2 changes: 1 addition & 1 deletion packages/hlsjs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HLSjs wrapper</title>
<link rel="stylesheet" href="/lib/Controls/index.scss" />
<link rel="stylesheet" href="/lib/ui/index.scss" />
<link
href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
rel="stylesheet"
Expand Down
13 changes: 0 additions & 13 deletions packages/hlsjs/lib/Controls/hooks/useSettings.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/hlsjs/lib/Controls/index.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion packages/hlsjs/lib/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import EventEmitter from "eventemitter3";
import type { Spec } from "immutability-helper";
import type { Level, MediaPlaylist } from "hls.js";

export { Controls as HlsControls } from "./Controls";
export { Root as HlsUi } from "./ui";

export type HlsInterstitial = {
seekAllowed: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
}
}

.mix-controls-buttons {
.mix-controls-bottom {
display: flex;
column-gap: 1em;
height: 4em;
Expand All @@ -34,3 +34,7 @@
.mix-controls-gutter {
flex-grow: 1;
}

.mix-controls-progress {
display: flex;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useEffect, useState } from "react";
import cn from "clsx";
import { Progress } from "./Progress";
import PlayIcon from "../icons/play.svg?react";
Expand All @@ -7,61 +6,76 @@ import SettingsIcon from "../icons/settings.svg?react";
import SubtitlesIcon from "../icons/subtitles.svg?react";
import { useVisible } from "../hooks/useVisible";
import { Settings } from "./Settings";
import { useSettings } from "../hooks/useSettings";
import { SqButton } from "./SqButton";
import { useSettings } from "../hooks/useSettings";
import { TimeStat } from "./TimeStat";
import type { HlsState, HlsFacade } from "../../main";

type ControlsProps = {
facade: HlsFacade;
state: HlsState;
};

export function Controls({ facade }: ControlsProps) {
const [state, setState] = useState<HlsState>(facade.state);
const { visible, elementRef } = useVisible();
const [settingsMode, setSettingsMode] = useSettings();
export function Controls({ facade, state }: ControlsProps) {
const { visible, elementRef, nudge } = useVisible();
const [settingsMode, setSettingsMode] = useSettings({
onChange: () => {
nudge();
},
});

useEffect(() => {
const update = () => setState(facade.state);
facade.on("*", update);
return () => {
facade.off("*", update);
};
}, [facade]);
let controlsVisible = visible;
if (settingsMode) {
controlsVisible = true;
}

return (
<>
<div
ref={elementRef}
className={cn("mix-controls", visible && "mix-controls--visible")}
className={cn(
"mix-controls",
controlsVisible && "mix-controls--visible",
)}
>
{showSeekbar(state) ? (
<Progress
state={state}
onSeeked={(time) => {
facade.seekTo(time);
}}
/>
<div className="mix-controls-progress">
<Progress
state={state}
onSeeked={(time) => {
facade.seekTo(time);
}}
/>
<TimeStat state={state} />
</div>
) : null}
<div className="mix-controls-buttons">
<div className="mix-controls-bottom">
<SqButton onClick={() => facade.playOrPause()}>
{state.playheadState === "play" ? <PauseIcon /> : <PlayIcon />}
</SqButton>
<div className="mix-controls-gutter" />
<SqButton
onClick={() => setSettingsMode("text-audio")}
selected={settingsMode === "text-audio"}
data-settings-action
>
<SubtitlesIcon />
</SqButton>
<SqButton
onClick={() => setSettingsMode("quality")}
selected={settingsMode === "quality"}
data-settings-action
>
<SettingsIcon />
</SqButton>
</div>
</div>
<Settings facade={facade} state={state} mode={settingsMode} />
<Settings
facade={facade}
state={state}
mode={settingsMode}
onClose={() => setSettingsMode(null)}
/>
</>
);
}
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
position: relative;
height: 3em;
margin: 0 1.5em;
width: 100%;
}

.mix-progress-range {
Expand Down
13 changes: 13 additions & 0 deletions packages/hlsjs/lib/ui/components/Root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Controls } from "./Controls";
import { useHlsState } from "../hooks/useHlsState";
import type { HlsFacade } from "../../main";

type RootProps = {
facade: HlsFacade;
};

export function Root({ facade }: RootProps) {
const state = useHlsState(facade);

return <Controls facade={facade} state={state} />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ type SettingsProps = {
facade: HlsFacade;
state: HlsState;
mode: SettingsMode | null;
onClose(): void;
};

export function Settings({ facade, state, mode }: SettingsProps) {
export function Settings({ facade, state, mode, onClose }: SettingsProps) {
const ref = useRef<HTMLDivElement>(null);
const lastModeRef = useRef<SettingsMode>();
const modePrev = usePrevious(mode);
Expand All @@ -33,6 +34,38 @@ export function Settings({ facade, state, mode }: SettingsProps) {
}
}, [modePrev, mode]);

useEffect(() => {
if (mode === null) {
return;
}

const onPointerDown = (event: MouseEvent) => {
const element = event.target as HTMLElement;

const SETTINGS_ACTION_ATTR = "data-settings-action";
if (
element.hasAttribute(SETTINGS_ACTION_ATTR) ||
element.closest("button")?.hasAttribute(SETTINGS_ACTION_ATTR)
) {
return;
}

const isOver = element
.closest(".mix-container")
?.querySelector(".mix-settings")
?.contains(element);

if (!isOver) {
onClose();
}
};

window.addEventListener("pointerdown", onPointerDown);
return () => {
window.removeEventListener("pointerdown", onPointerDown);
};
}, [mode, onClose]);

useLayoutEffect(() => {
const element = ref.current;
if (!element) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ type SqButtonProps = {
selected?: boolean;
};

export function SqButton({ children, onClick, selected }: SqButtonProps) {
export function SqButton({
children,
onClick,
selected,
...rest
}: SqButtonProps) {
return (
<button
className={cn("mix-sqbutton", selected && "mix-sqbutton--selected")}
onClick={onClick}
{...rest}
>
{children}
</button>
Expand Down
7 changes: 7 additions & 0 deletions packages/hlsjs/lib/ui/components/TimeStat.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.mix-timestat {
color: #ffffff;
white-space: nowrap;
margin-right: 1.5em;
display: flex;
align-items: center;
}
45 changes: 45 additions & 0 deletions packages/hlsjs/lib/ui/components/TimeStat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { HlsState } from "../../main";

type TimeStatProps = {
state: HlsState;
};

export function TimeStat({ state }: TimeStatProps) {
const remainingTime =
state.seekRange.end - state.time - state.seekRange.start;

const value = toHMS(remainingTime);

return value !== null ? (
<div className="mix-timestat">{toHMS(remainingTime)}</div>
) : null;
}

export function toHMS(seconds: number) {
if (!Number.isFinite(seconds)) {
return null;
}

const pad = (value: number) =>
(10 ** 2 + Math.floor(value)).toString().substring(1);

seconds = Math.floor(seconds);
if (seconds < 0) {
seconds = 0;
}

let result = "";

const h = Math.trunc(seconds / 3600) % 24;
if (h) {
result += `${pad(h)}:`;
}

const m = Math.trunc(seconds / 60) % 60;
result += `${pad(m)}:`;

const s = Math.trunc(seconds % 60);
result += `${pad(s)}`;

return result;
}
File renamed without changes.
16 changes: 16 additions & 0 deletions packages/hlsjs/lib/ui/hooks/useHlsState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useEffect, useState } from "react";
import { HlsFacade, HlsState } from "../../main";

export function useHlsState(facade: HlsFacade) {
const [state, setState] = useState<HlsState>(facade.state);

useEffect(() => {
const update = () => setState(facade.state);
facade.on("*", update);
return () => {
facade.off("*", update);
};
}, [facade]);

return state;
}
File renamed without changes.
25 changes: 25 additions & 0 deletions packages/hlsjs/lib/ui/hooks/useSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useEffect, useState } from "react";

export type SettingsMode = "text-audio" | "quality";

type UseSettingsParams = {
onChange(): void;
};

export function useSettings({ onChange }: UseSettingsParams) {
const [settings, setSettings_] = useState<SettingsMode | null>(null);

const setSettings = (value: SettingsMode | null) => {
if (value === null) {
setSettings_(null);
} else {
setSettings_((v) => (v !== value ? value : null));
}
};

useEffect(() => {
onChange();
}, [settings]);

return [settings, setSettings] as const;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ export function useVisible() {

const [visible, setVisible] = useState(false);

const onPointerMove = () => {
clearTimeout(ref.current);

setVisible(true);

ref.current = setTimeout(() => {
setVisible(false);
}, 3000);
};

useEffect(() => {
const container = elementRef.current?.closest(".mix-container") as
| HTMLDivElement
Expand All @@ -15,16 +25,6 @@ export function useVisible() {
return;
}

const onPointerMove = () => {
clearTimeout(ref.current);

setVisible(true);

ref.current = setTimeout(() => {
setVisible(false);
}, 3000);
};

const onPointerLeave = () => {
clearTimeout(ref.current);
setVisible(false);
Expand All @@ -39,8 +39,13 @@ export function useVisible() {
};
}, []);

const nudge = () => {
onPointerMove();
};

return {
visible,
elementRef,
nudge,
};
}
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ $size-sm: 0.85em;
@import "./components/Pane.scss";
@import "./components/TextAudioPane.scss";
@import "./components/SqButton.scss";
@import "./components/TimeStat.scss";

.mix-container {
aspect-ratio: 16 / 9;
Expand Down
Loading

0 comments on commit 8d2400d

Please sign in to comment.