Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions build.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ const buildOptions = {
},
},
],
define: {
"process.env.NODE_ENV": JSON.stringify(env),
},
mainFields: ["browser", "module", "main"],
conditions: ["production", "default"],
};
Expand All @@ -119,9 +122,6 @@ if (env === "prod") {
Object.assign(buildOptions, {
minify: true,
pure: ["console.debug"], // Remove all `console.debug()` calls in production builds.
define: {
"process.env.NODE_ENV": '"production"',
},
});
}

Expand Down
30 changes: 30 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@number-flow/react": "^0.5.10",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-slider": "^1.2.0",
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tooltip": "^1.2.8",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
Expand Down
15 changes: 15 additions & 0 deletions src/components/Switch.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import * as SwitchPrimitive from "@radix-ui/react-switch";

export default function Switch({ checked, onCheckedChange, ...props }) {
return (
<SwitchPrimitive.Root
className="switch__slider"
checked={checked}
onCheckedChange={onCheckedChange}
{...props}
>
<SwitchPrimitive.Thumb className="switch__thumb" />
</SwitchPrimitive.Root>
);
}
51 changes: 51 additions & 0 deletions src/components/Switch.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
@use "~@destinygg/libstiny" as dgg;
@use "@destinygg/libstiny/lib/utils/transitions" as transitions;

.switch {
&__slider {
@include transitions.create-transition(all, default);
position: relative;
display: inline-block;
width: dgg.$switch-width;
height: dgg.$switch-height;
flex-shrink: 0;
cursor: pointer;
background-color: dgg.$switch-background-default-rest;
border-radius: dgg.$semantic-radii-pill;
border: none;
padding: 0;

&:hover {
background-color: dgg.$switch-background-default-hover;
}

&[data-state="checked"] {
background-color: dgg.$switch-background-active-rest;

&:hover {
background-color: dgg.$switch-background-active-hover;
}
}

// Override libstiny's ::before thumb in favor of the Radix UI Switch thumb element.
&::before {
content: none;
}
}

&__thumb {
@include transitions.create-transition(all, movement);
display: block;
position: absolute;
height: dgg.$switch-toggle-size;
width: dgg.$switch-toggle-size;
left: dgg.$space-1;
bottom: dgg.$space-1;
background-color: dgg.$switch-toggle-background;
border-radius: 50%;

&[data-state="checked"] {
transform: translateX(dgg.$switch-toggle-size);
}
}
}
48 changes: 34 additions & 14 deletions src/controls/settings/MainMenu.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
import React from "react";
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import { ChevronRight } from "lucide-react";
import Switch from "../../components/Switch.jsx";

export default function MainMenu({ onNavigateQuality, selectedQuality }) {
export default function MainMenu({
onNavigateQuality,
selectedQuality,
isIvsDebug,
onIvsDebugChange,
}) {
return (
<DropdownMenu.Item
className="dropdown__item dropdown__item--nav"
onSelect={(e) => {
e.preventDefault();
onNavigateQuality();
}}
>
<span>Quality</span>
<span className="dropdown__item-value">
{selectedQuality.label}
<ChevronRight size={16} />
</span>
</DropdownMenu.Item>
<>
<DropdownMenu.Item
className="dropdown__item dropdown__item--nav"
onSelect={(e) => {
e.preventDefault();
onNavigateQuality();
}}
>
<span>Quality</span>
<span className="dropdown__item-value">
{selectedQuality.label}
<ChevronRight size={16} />
</span>
</DropdownMenu.Item>

{process.env.NODE_ENV === "dev" && (
<DropdownMenu.Item
className="dropdown__item dropdown__item--nav"
onSelect={(e) => {
e.preventDefault();
}}
>
<span>IVS Debug</span>
<Switch checked={isIvsDebug} onCheckedChange={onIvsDebugChange} />
</DropdownMenu.Item>
)}
</>
);
}
5 changes: 5 additions & 0 deletions src/controls/settings/SettingsButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import MainMenu from "./MainMenu.jsx";
import QualityMenu from "./QualityMenu.jsx";
import { useSettings } from "./useSettings.js";
import { useQualitySelector } from "./useQualitySelector.js";
import { useIvsDebug } from "./useIvsDebug.js";

export default function SettingsButton({ core, container, shouldShow }) {
const {
Expand All @@ -22,6 +23,8 @@ export default function SettingsButton({ core, container, shouldShow }) {
const { selectedQuality, qualityOptions, handleQualityChange } =
useQualitySelector(core);

const { isIvsDebug, setIsIvsDebug } = useIvsDebug(core);

return (
<Tooltip.Root>
<DropdownMenu.Root
Expand Down Expand Up @@ -54,6 +57,8 @@ export default function SettingsButton({ core, container, shouldShow }) {
<MainMenu
onNavigateQuality={navigateToQuality}
selectedQuality={selectedQuality}
isIvsDebug={isIvsDebug}
onIvsDebugChange={setIsIvsDebug}
/>
)}

Expand Down
36 changes: 36 additions & 0 deletions src/controls/settings/useIvsDebug.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useEffect } from "react";
import { usePreferences } from "../usePreferences";

export function useIvsDebug(core) {
const { isIvsDebug, setIsIvsDebug } = usePreferences();

useEffect(() => {
if (!isIvsDebug) {
return;
}

// Sample IVS messages:
// { type: 12, arg: { key: "bufferedPosition", value: 2.334009 } }
// { type: 12, arg: { key: "statistics", value: { bitrate: 3109311, ... } } }
// { type: "PlayerQualityChanged", arg: { name: "720p60", ... } }
const handler = (event) => {
const data = event.data;
const type = data.type;
const detail = data.arg?.key || data.arg?.name;

if (detail === "bufferedPosition") {
return;
}

const label = detail ? `${type} (${detail})` : type;
console.debug(`[Kickstiny] IVS Message: ${label}`, data);
};

core.worker.addEventListener("message", handler);
return () => {
core.worker.removeEventListener("message", handler);
};
}, [isIvsDebug, core]);

return { isIvsDebug, setIsIvsDebug };
}
22 changes: 22 additions & 0 deletions src/controls/usePreferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState, useCallback } from "react";

const QUALITY_STORAGE_KEY = "kickstiny.preference.quality";
const VOLUME_STORAGE_KEY = "kickstiny.preference.volume";
const IVS_DEBUG_STORAGE_KEY = "kickstiny.preference.ivsDebug";

const DEFAULT_VOLUME = 100;

Expand All @@ -25,6 +26,16 @@ export function usePreferences() {
}
});

const [isIvsDebug, setIsIvsDebugState] = useState(() => {
try {
const stored = window.localStorage.getItem(IVS_DEBUG_STORAGE_KEY);
return stored === "true";
} catch (err) {
console.log("[Kickstiny] Unable to read ivs debug preference", err);
return false;
}
});

const setSavedQuality = useCallback((value) => {
try {
window.localStorage.setItem(QUALITY_STORAGE_KEY, value);
Expand All @@ -43,10 +54,21 @@ export function usePreferences() {
}
}, []);

const setIsIvsDebug = useCallback((value) => {
try {
window.localStorage.setItem(IVS_DEBUG_STORAGE_KEY, value.toString());
setIsIvsDebugState(value);
} catch (err) {
console.log("[Kickstiny] Unable to persist ivs debug preference", err);
}
}, []);

return {
savedQuality,
savedVolume,
isIvsDebug,
setSavedQuality,
setSavedVolume,
setIsIvsDebug,
};
}
1 change: 1 addition & 0 deletions src/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@use "./components/Tooltip.scss";
@use "./components/Dropdown.scss";
@use "./components/Slider.scss";
@use "./components/Switch.scss";

@use "./controls/container/Container.scss";
@use "./controls/bar/ControlsBar.scss";
Expand Down