From d089e43b8a03e8a4b1b95a83c044561cfc0290e8 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Fri, 20 Aug 2021 03:54:49 -0400 Subject: [PATCH] Add tooltip about highlight feature --- public/_locales/en/messages.json | 12 +++- public/content.css | 21 +++++++ src/background.ts | 2 + src/config.ts | 2 + src/content.ts | 15 ++++- src/js-components/skipButtonControlBar.ts | 10 +++- src/render/Tooltip.tsx | 73 +++++++++++++++++++++++ 7 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 src/render/Tooltip.tsx diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index 24f9e632..3e7a3acf 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -19,7 +19,7 @@ "channelWhitelisted": { "message": "Channel Whitelisted!" }, - "Segment": { + "Segment": { "message": "segment" }, "Segments": { @@ -711,6 +711,10 @@ "help": { "message": "Help" }, + "GotIt": { + "message": "Got it", + "description": "Used as the button to dismiss a tooltip" + }, "experiementOptOut": { "message": "Opt-out of all future experiments", "description": "This is used in a popup about a new experiment to get a list of unlisted videos to back up since all unlisted videos uploaded before 2017 will be set to private." @@ -787,5 +791,11 @@ }, "Credits": { "message": "Credits" + }, + "highlightNewFeature": { + "message": "New! Get to the point of the video with one click with the new highlight category" + }, + "LearnMore": { + "message": "Learn More" } } diff --git a/public/content.css b/public/content.css index 54e6cb85..b2e4b1e5 100644 --- a/public/content.css +++ b/public/content.css @@ -518,4 +518,25 @@ input::-webkit-inner-spin-button { bottom: 0px; display: block; margin: auto; +} + +.sponsorBlockTooltip { + position: absolute; + background-color: rgba(28, 28, 28, 0.7); + border-radius: 5px; + padding: 10px; + max-width: 300px; + white-space: normal; + line-height: 1.5em; +} + +.sponsorBlockTooltip::after { + content: " "; + position: absolute; + top: 100%; + left: 15%; + margin-left: -15px; + border-width: 15px; + border-style: solid; + border-color: rgba(28, 28, 28, 0.7) transparent transparent transparent; } \ No newline at end of file diff --git a/src/background.ts b/src/background.ts index 2d5ffe8e..d11abb96 100644 --- a/src/background.ts +++ b/src/background.ts @@ -80,6 +80,8 @@ chrome.runtime.onInstalled.addListener(function () { const newUserID = utils.generateUserID(); //save this UUID Config.config.userID = newUserID; + + Config.config.highlightCategoryUpdate = false; } }, 1500); }); diff --git a/src/config.ts b/src/config.ts index 25b3a11b..f30dde4d 100644 --- a/src/config.ts +++ b/src/config.ts @@ -41,6 +41,7 @@ interface SBConfig { showDonationLink: boolean, autoHideInfoButton: boolean, autoSkipOnMusicVideos: boolean, + highlightCategoryUpdate: boolean // What categories should be skipped categorySelections: CategorySelection[], @@ -185,6 +186,7 @@ const Config: SBObject = { showDonationLink: true, autoHideInfoButton: true, autoSkipOnMusicVideos: false, + highlightCategoryUpdate: false, // TODO: Remove this once update is done categorySelections: [{ name: "sponsor" as Category, diff --git a/src/content.ts b/src/content.ts index 804af61d..46a1a1c5 100644 --- a/src/content.ts +++ b/src/content.ts @@ -15,6 +15,7 @@ import { Message, MessageResponse } from "./messageTypes"; import * as Chat from "./js-components/chat"; import { getCategoryActionType } from "./utils/categoryUtils"; import { SkipButtonControlBar } from "./js-components/skipButtonControlBar"; +import { Tooltip } from "./render/Tooltip"; // Hack to get the CSS loaded on permission-based sites (Invidious) utils.wait(() => Config.config !== null, 5000, 10).then(addCSS); @@ -1104,7 +1105,19 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u if (!autoSkip && skippingSegments.length === 1 && getCategoryActionType(skippingSegments[0].category) === CategoryActionType.POI) { - skipButtonControlBar.enable(skippingSegments[0]); + skipButtonControlBar.enable(skippingSegments[0], !Config.config.highlightCategoryUpdate ? 15 : 0); + + if (!Config.config.highlightCategoryUpdate) { + new Tooltip({ + text: chrome.i18n.getMessage("highlightNewFeature"), + link: "https://blog.ajay.app/highlight-sponsorblock", + referenceNode: skipButtonControlBar.getElement().parentElement, + prependElement: skipButtonControlBar.getElement(), + timeout: 15 + }); + + Config.config.highlightCategoryUpdate = true; + } activeSkipKeybindElement?.setShowKeybindHint(false); activeSkipKeybindElement = skipButtonControlBar; diff --git a/src/js-components/skipButtonControlBar.ts b/src/js-components/skipButtonControlBar.ts index 9a8af4ec..37a5d409 100644 --- a/src/js-components/skipButtonControlBar.ts +++ b/src/js-components/skipButtonControlBar.ts @@ -18,6 +18,7 @@ export class SkipButtonControlBar { showKeybindHint = true; timeout: NodeJS.Timeout; + duration = 0; skip: (segment: SponsorTime) => void; @@ -42,6 +43,10 @@ export class SkipButtonControlBar { this.container.addEventListener("mouseleave", () => this.startTimer()); } + getElement(): HTMLElement { + return this.container; + } + attachToPage(): void { const leftControlsContainer = document.querySelector(".ytp-left-controls"); this.chapterText = document.querySelector(".ytp-chapter-container"); @@ -51,7 +56,8 @@ export class SkipButtonControlBar { } } - enable(segment: SponsorTime): void { + enable(segment: SponsorTime, duration?: number): void { + if (duration) this.duration = duration; this.segment = segment; this.refreshText(); @@ -78,7 +84,7 @@ export class SkipButtonControlBar { startTimer(): void { this.stopTimer(); - this.timeout = setTimeout(() => this.disable(), Config.config.skipNoticeDuration * 1000); + this.timeout = setTimeout(() => this.disable(), Math.max(Config.config.skipNoticeDuration, this.duration) * 1000); } disable(): void { diff --git a/src/render/Tooltip.tsx b/src/render/Tooltip.tsx new file mode 100644 index 00000000..7bb2e1f3 --- /dev/null +++ b/src/render/Tooltip.tsx @@ -0,0 +1,73 @@ +import * as React from "react"; +import * as ReactDOM from "react-dom"; + +export interface TooltipProps { + text: string, + link?: string, + referenceNode: HTMLElement, + prependElement?: HTMLElement, // Element to append before + bottomOffset?: string + timeout?: number; +} + +export class Tooltip { + text: string; + container: HTMLDivElement; + + timer: NodeJS.Timeout; + + constructor(props: TooltipProps) { + props.bottomOffset ??= "70px"; + this.text = props.text; + + this.container = document.createElement('div'); + this.container.id = "sponsorTooltip" + props.text; + this.container.style.display = "relative"; + + if (props.prependElement) { + props.referenceNode.insertBefore(this.container, props.prependElement); + } else { + props.referenceNode.appendChild(this.container); + } + + if (props.timeout) { + this.timer = setTimeout(() => this.close(), props.timeout * 1000); + } + + ReactDOM.render( +
+
+ + + + {this.text + (props.link ? ". " : "")} + {props.link ? + + {chrome.i18n.getMessage("LearnMore")} + + : null} + +
+ +
, + this.container + ) + } + + close(): void { + ReactDOM.unmountComponentAtNode(this.container); + this.container.remove(); + + if (this.timer) clearTimeout(this.timer); + } +} \ No newline at end of file