Skip to content

Commit

Permalink
feat: button placement
Browse files Browse the repository at this point in the history
  • Loading branch information
VampireChicken12 committed Jan 20, 2024
1 parent 34601c0 commit 2fdd45c
Show file tree
Hide file tree
Showing 30 changed files with 479 additions and 324 deletions.
20 changes: 16 additions & 4 deletions public/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,21 @@
"label": "Feature menu"
},
"loopButton": {
"label": "Loop"
"label": "Loop",
"toggle": {
"off": "Loop off",
"on": "Loop on"
}
},
"maximizePlayerButton": {
"label": "Maximize"
"label": "Maximize",
"toggle": {
"off": "Maximize off",
"on": "Maximize on"
}
},
"openTranscriptButton": {
"label": "Open Transcript"
"label": "Open transcript"
},
"screenshotButton": {
"copiedToClipboard": "Screenshot copied to clipboard",
Expand All @@ -31,7 +39,11 @@
}
},
"volumeBoostButton": {
"label": "Volume Boost"
"label": "Volume Boost",
"toggle": {
"off": "Volume boost off",
"on": "Volume boost on"
}
}
}
},
Expand Down
11 changes: 7 additions & 4 deletions public/locales/en-US.json.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ interface EnUS {
content: {
features: {
featureMenu: { label: "Feature menu" };
loopButton: { label: "Loop" };
maximizePlayerButton: { label: "Maximize" };
openTranscriptButton: { label: "Open Transcript" };
loopButton: { label: "Loop"; toggle: { off: "Loop off"; on: "Loop on" } };
maximizePlayerButton: { label: "Maximize"; toggle: { off: "Maximize off"; on: "Maximize on" } };
openTranscriptButton: { label: "Open transcript" };
screenshotButton: { copiedToClipboard: "Screenshot copied to clipboard"; label: "Screenshot" };
videoHistory: { resumeButton: "Resume"; resumePrompt: { close: "Close" } };
volumeBoostButton: { label: "Volume Boost" };
volumeBoostButton: {
label: "Volume Boost";
toggle: { off: "Volume boost off"; on: "Volume boost on" };
};
};
};
options: {
Expand Down
8 changes: 8 additions & 0 deletions src/assets/img/loopOff.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions src/assets/img/loopOn.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 5 additions & 23 deletions src/assets/img/maximize.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 8 additions & 52 deletions src/assets/img/minimize.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/assets/img/volumeBoostOff.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/assets/img/volumeBoostOn.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 24 additions & 16 deletions src/features/buttonPlacement/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { GetIconType } from "@/src/icons";
import type { ButtonPlacement, FeaturesThatHaveButtons } from "@/src/types";

import { waitForSpecificMessage } from "@/src/utils/utilities";
import { addFeatureItemToMenu, removeFeatureItemFromMenu } from "@/src/features/featureMenu/utils";
import { removeTooltip, waitForSpecificMessage } from "@/src/utils/utilities";

import { addFeatureItemToMenu, removeFeatureItemFromMenu } from "../featureMenu/utils";
import { type ListenerType, makeFeatureButton, placeButton } from "./utils";
import { type ListenerType, getFeatureButtonId, makeFeatureButton, placeButton } from "./utils";
export const featuresInControls = new Set<FeaturesThatHaveButtons>();

export async function addFeatureButton<
Name extends FeaturesThatHaveButtons,
Expand All @@ -20,34 +21,41 @@ export async function addFeatureButton<
case "below_player":
case "player_controls_left":
case "player_controls_right": {
// Add the feature name to the set of features in the controls
featuresInControls.add(featureName);
const button = makeFeatureButton(featureName, placement, label, icon, listener, isToggle);
placeButton(button, placement);
break;
}
}
}
export async function removeFeatureButton(featureName: FeaturesThatHaveButtons) {
// Wait for the "options" message from the content script
const optionsData = await waitForSpecificMessage("options", "request_data", "content");
if (!optionsData) return;
const {
data: { options }
} = optionsData;
// Extract the necessary properties from the options object
const {
button_placements: { [featureName]: buttonPlacement }
} = options;
switch (buttonPlacement) {
export async function removeFeatureButton<Name extends FeaturesThatHaveButtons>(featureName: Name, placement?: ButtonPlacement) {
if (placement === undefined) {
// Wait for the "options" message from the content script
const optionsData = await waitForSpecificMessage("options", "request_data", "content");
if (!optionsData) return;
({
data: {
options: {
button_placements: { [featureName]: placement }
}
}
} = optionsData);
}
switch (placement) {
case "feature_menu": {
removeFeatureItemFromMenu(featureName);
break;
}
case "below_player":
case "player_controls_left":
case "player_controls_right": {
const button = document.querySelector<HTMLButtonElement>(`#yte-feature-${featureName}-button`);
// Remove the feature name from the set of features in the controls
featuresInControls.delete(featureName);
const button = document.querySelector<HTMLButtonElement>(`#${getFeatureButtonId(featureName)}`);
if (!button) return;
button.remove();
removeTooltip(`yte-feature-${featureName}-tooltip`);
break;
}
}
Expand Down
56 changes: 40 additions & 16 deletions src/features/buttonPlacement/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { getFeatureIds, getFeatureMenuItem } from "@/src/features/featureMenu/utils";
import { type GetIconType } from "@/src/icons";
import { type ButtonPlacement, type FeaturesThatHaveButtons } from "@/src/types";
import eventManager from "@/src/utils/EventManager";
import { createStyledElement, createTooltip } from "@/src/utils/utilities";

import { getFeatureIds } from "../featureMenu/utils";
// TODO: fix icon type for toggle buttons

export type ListenerType<Toggle extends boolean> = Toggle extends true ? (checked?: boolean) => void : () => void;

function buttonClickListener<Placement extends ButtonPlacement, Name extends FeaturesThatHaveButtons, Toggle extends boolean>(
Expand All @@ -16,10 +14,9 @@ function buttonClickListener<Placement extends ButtonPlacement, Name extends Fea
) {
if (isToggle) {
button.ariaChecked = button.ariaChecked ? (!JSON.parse(button.ariaChecked)).toString() : "false";
// TODO: add language strings for toggle features and update the tooltip text
if (typeof icon === "object" && "off" in icon && "on" in icon) {
updateFeatureButtonIcon(button, JSON.parse(button.ariaChecked) ? icon.on : icon.off);
} else if (typeof icon === "object" && icon instanceof SVGSVGElement) {
} else if (icon instanceof SVGSVGElement) {
updateFeatureButtonIcon(button, icon);
}
listener(JSON.parse(button.ariaChecked) as boolean);
Expand All @@ -38,6 +35,7 @@ export function makeFeatureButton<Name extends FeaturesThatHaveButtons, Placemen
) {
if (placement === "feature_menu") throw new Error("Cannot make a feature button for the feature menu");
const buttonExists = document.querySelector(`button#${getFeatureButtonId(featureName)}`) !== null;
// TODO: fix left controls chapter container shrinking buttons
// TODO: fix right controls button making control buttons overflow
const button = createStyledElement({
classlist: ["ytp-button"],
Expand All @@ -53,41 +51,64 @@ export function makeFeatureButton<Name extends FeaturesThatHaveButtons, Placemen
width: "48px"
}
});
const { listener: tooltipListener } = createTooltip({
direction: placement === "below_player" ? "up" : "up",
button.dataset.title = label;
const { listener: tooltipListener, update } = createTooltip({
direction: placement === "below_player" ? "down" : "up",
element: button,
featureName,
id: `yte-feature-${featureName}-tooltip`,
text: label
id: `yte-feature-${featureName}-tooltip`
});
if (buttonExists) {
eventManager.removeEventListener(button, "click", featureName);
eventManager.addEventListener(button, "click", () => buttonClickListener<Placement, Name, Toggle>(button, icon, listener, isToggle), featureName);
eventManager.addEventListener(
button,
"click",
() => {
buttonClickListener<Placement, Name, Toggle>(button, icon, listener, isToggle);
update();
},
featureName
);
eventManager.removeEventListener(button, "mouseover", featureName);
eventManager.addEventListener(button, "mouseover", tooltipListener, featureName);
return button;
}

button.dataset.title = label;
if (isToggle) {
button.ariaChecked = "false";
if (typeof icon === "object" && "off" in icon && "on" in icon) {
button.append(icon.off);
} else if (typeof icon === "object" && icon instanceof SVGSVGElement) {
} else if (icon instanceof SVGSVGElement) {
button.append(icon);
}
} else {
if (icon instanceof SVGSVGElement) {
button.append(icon);
}
}

eventManager.addEventListener(button, "mouseover", tooltipListener, featureName);
eventManager.addEventListener(button, "click", () => buttonClickListener<Placement, Name, Toggle>(button, icon, listener, isToggle), featureName);
eventManager.addEventListener(
button,
"click",
() => {
buttonClickListener<Placement, Name, Toggle>(button, icon, listener, isToggle);
update();
},
featureName
);
return button;
}
function updateFeatureButtonIcon(button: HTMLButtonElement, icon: SVGElement) {
export function updateFeatureButtonIcon(button: HTMLButtonElement, icon: SVGElement) {
if (button.firstChild) {
button.firstChild.remove();
button.append(icon);
button.firstChild.replaceWith(icon);
}
}
export function updateFeatureButtonTitle(featureName: FeaturesThatHaveButtons, title: string) {
const button = document.querySelector<HTMLButtonElement>(`#${getFeatureButtonId(featureName)}`);
if (!button) return;
button.dataset.title = title;
}
export function placeButton(button: HTMLButtonElement, placement: Exclude<ButtonPlacement, "feature_menu">) {
switch (placement) {
case "below_player": {
Expand Down Expand Up @@ -148,4 +169,7 @@ export function checkIfFeatureButtonExists(featureName: FeaturesThatHaveButtons,
export function getFeatureButtonId(featureName: FeaturesThatHaveButtons) {
return `yte-feature-${featureName}-button` as const;
}
export function getFeatureButton(featureName: FeaturesThatHaveButtons) {
return getFeatureMenuItem(featureName) ?? document.querySelector<HTMLButtonElement>(`#${getFeatureButtonId(featureName)}`);
}
export const buttonContainerId = "yte-button-container";
6 changes: 2 additions & 4 deletions src/features/featureMenu/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import type { FeatureMenuOpenType } from "@/src/types";

import eventManager from "@/src/utils/EventManager";
import { createSVGElement, createStyledElement, createTooltip, isWatchPage, waitForAllElements } from "@/src/utils/utilities";

import { waitForSpecificMessage } from "../../utils/utilities";
import { createSVGElement, createStyledElement, createTooltip, isWatchPage, waitForAllElements, waitForSpecificMessage } from "@/src/utils/utilities";

function createFeatureMenu() {
// Create the feature menu div
Expand Down Expand Up @@ -118,7 +116,7 @@ export function setupFeatureMenuEventListeners(featureMenuOpenType: FeatureMenuO
const { listener: showFeatureMenuTooltip, remove: removeFeatureMenuTooltip } = createTooltip({
element: featureMenuButton,
featureName: "featureMenu",
id: "yte-feature-menu-tooltip"
id: "yte-feature-featureMenu-tooltip"
});
const hideYouTubeSettings = () => {
const settingsMenu = document.querySelector<HTMLDivElement>("div.ytp-settings-menu:not(#yte-feature-menu)");
Expand Down
Loading

0 comments on commit 2fdd45c

Please sign in to comment.