mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-10 05:27:03 +03:00
Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into chapters
This commit is contained in:
@@ -31,24 +31,24 @@ class CategoryChooserComponent extends React.Component<CategoryChooserProps, Cat
|
||||
{/* Headers */}
|
||||
<tr id={"CategoryOptionsRow"}
|
||||
className="categoryTableElement categoryTableHeader">
|
||||
<td id={"CategoryOptionName"}>
|
||||
<th id={"CategoryOptionName"}>
|
||||
{chrome.i18n.getMessage("category")}
|
||||
</td>
|
||||
</th>
|
||||
|
||||
<td id={"CategorySkipOption"}
|
||||
<th id={"CategorySkipOption"}
|
||||
className="skipOption">
|
||||
{chrome.i18n.getMessage("skipOption")}
|
||||
</td>
|
||||
</th>
|
||||
|
||||
<td id={"CategoryColorOption"}
|
||||
<th id={"CategoryColorOption"}
|
||||
className="colorOption">
|
||||
{chrome.i18n.getMessage("seekBarColor")}
|
||||
</td>
|
||||
</th>
|
||||
|
||||
<td id={"CategoryPreviewColorOption"}
|
||||
<th id={"CategoryPreviewColorOption"}
|
||||
className="previewColorOption">
|
||||
{chrome.i18n.getMessage("previewColor")}
|
||||
</td>
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
{this.getCategorySkipOptions()}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { downvoteButtonColor, SkipNoticeAction } from "../utils/noticeUtils";
|
||||
import { VoteResponse } from "../messageTypes";
|
||||
import { AnimationUtils } from "../utils/animationUtils";
|
||||
import { GenericUtils } from "../utils/genericUtils";
|
||||
import { Tooltip } from "../render/Tooltip";
|
||||
|
||||
export interface CategoryPillProps {
|
||||
vote: (type: number, UUID: SegmentUUID, category?: Category) => Promise<VoteResponse>;
|
||||
@@ -21,6 +22,8 @@ export interface CategoryPillState {
|
||||
|
||||
class CategoryPillComponent extends React.Component<CategoryPillProps, CategoryPillState> {
|
||||
|
||||
tooltip?: Tooltip;
|
||||
|
||||
constructor(props: CategoryPillProps) {
|
||||
super(props);
|
||||
|
||||
@@ -35,15 +38,16 @@ class CategoryPillComponent extends React.Component<CategoryPillProps, CategoryP
|
||||
const style: React.CSSProperties = {
|
||||
backgroundColor: this.getColor(),
|
||||
display: this.state.show ? "flex" : "none",
|
||||
color: this.state.segment?.category === "sponsor"
|
||||
|| this.state.segment?.category === "exclusive_access" ? "white" : "black",
|
||||
color: this.getTextColor(),
|
||||
}
|
||||
|
||||
return (
|
||||
<span style={style}
|
||||
className={"sponsorBlockCategoryPill"}
|
||||
title={this.getTitleText()}
|
||||
onClick={(e) => this.toggleOpen(e)}>
|
||||
aria-label={this.getTitleText()}
|
||||
onClick={(e) => this.toggleOpen(e)}
|
||||
onMouseEnter={() => this.openTooltip()}
|
||||
onMouseLeave={() => this.closeTooltip()}>
|
||||
<span className="sponsorBlockCategoryPillTitleSection">
|
||||
<img className="sponsorSkipLogo sponsorSkipObject"
|
||||
src={chrome.extension.getURL("icons/IconSponsorBlocker256px.png")}>
|
||||
@@ -116,6 +120,45 @@ class CategoryPillComponent extends React.Component<CategoryPillProps, CategoryP
|
||||
return configObject?.color;
|
||||
}
|
||||
|
||||
private getTextColor(): string {
|
||||
const color = this.getColor();
|
||||
if (!color) return null;
|
||||
|
||||
const existingCalculatedColor = Config.config.categoryPillColors[this.state.segment?.category];
|
||||
if (existingCalculatedColor && existingCalculatedColor.lastColor === color) {
|
||||
return existingCalculatedColor.textColor;
|
||||
} else {
|
||||
const luminance = GenericUtils.getLuminance(color);
|
||||
const textColor = luminance > 128 ? "black" : "white";
|
||||
Config.config.categoryPillColors[this.state.segment?.category] = {
|
||||
lastColor: color,
|
||||
textColor
|
||||
};
|
||||
|
||||
return textColor;
|
||||
}
|
||||
}
|
||||
|
||||
private openTooltip(): void {
|
||||
const tooltipMount = document.querySelector("ytd-video-primary-info-renderer > #container") as HTMLElement;
|
||||
if (tooltipMount) {
|
||||
this.tooltip = new Tooltip({
|
||||
text: this.getTitleText(),
|
||||
referenceNode: tooltipMount,
|
||||
bottomOffset: "70px",
|
||||
opacity: 0.95,
|
||||
displayTriangle: false,
|
||||
showLogo: false,
|
||||
showGotIt: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private closeTooltip(): void {
|
||||
this.tooltip?.close();
|
||||
this.tooltip = null;
|
||||
}
|
||||
|
||||
getTitleText(): string {
|
||||
const shortDescription = chrome.i18n.getMessage(`category_${this.state.segment?.category}_pill`);
|
||||
return (shortDescription ? shortDescription + ". ": "") + chrome.i18n.getMessage("categoryPillTitleText");
|
||||
|
||||
75
src/components/KeybindComponent.tsx
Normal file
75
src/components/KeybindComponent.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import Config from "../config";
|
||||
import { Keybind } from "../types";
|
||||
import KeybindDialogComponent from "./KeybindDialogComponent";
|
||||
import { keybindEquals, keybindToString, formatKey } from "../utils/configUtils";
|
||||
|
||||
export interface KeybindProps {
|
||||
option: string;
|
||||
}
|
||||
|
||||
export interface KeybindState {
|
||||
keybind: Keybind;
|
||||
}
|
||||
|
||||
let dialog;
|
||||
|
||||
class KeybindComponent extends React.Component<KeybindProps, KeybindState> {
|
||||
constructor(props: KeybindProps) {
|
||||
super(props);
|
||||
this.state = {keybind: Config.config[this.props.option]};
|
||||
}
|
||||
|
||||
render(): React.ReactElement {
|
||||
return(
|
||||
<>
|
||||
<div className="keybind-buttons inline" title={chrome.i18n.getMessage("change")} onClick={() => this.openEditDialog()}>
|
||||
{this.state.keybind?.ctrl && <div className="key keyControl">Ctrl</div>}
|
||||
{this.state.keybind?.ctrl && <span className="keyControl">+</span>}
|
||||
{this.state.keybind?.alt && <div className="key keyAlt">Alt</div>}
|
||||
{this.state.keybind?.alt && <span className="keyAlt">+</span>}
|
||||
{this.state.keybind?.shift && <div className="key keyShift">Shift</div>}
|
||||
{this.state.keybind?.shift && <span className="keyShift">+</span>}
|
||||
{this.state.keybind?.key != null && <div className="key keyBase">{formatKey(this.state.keybind.key)}</div>}
|
||||
{this.state.keybind == null && <span className="unbound">{chrome.i18n.getMessage("notSet")}</span>}
|
||||
</div>
|
||||
|
||||
{this.state.keybind != null &&
|
||||
<div className="option-button trigger-button inline" onClick={() => this.unbind()}>
|
||||
{chrome.i18n.getMessage("unbind")}
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
equals(other: Keybind): boolean {
|
||||
return keybindEquals(this.state.keybind, other);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return keybindToString(this.state.keybind);
|
||||
}
|
||||
|
||||
openEditDialog(): void {
|
||||
dialog = parent.document.createElement("div");
|
||||
dialog.id = "keybind-dialog";
|
||||
parent.document.body.prepend(dialog);
|
||||
ReactDOM.render(<KeybindDialogComponent option={this.props.option} closeListener={(updateWith) => this.closeEditDialog(updateWith)} />, dialog);
|
||||
}
|
||||
|
||||
closeEditDialog(updateWith: Keybind): void {
|
||||
ReactDOM.unmountComponentAtNode(dialog);
|
||||
dialog.remove();
|
||||
if (updateWith != null)
|
||||
this.setState({keybind: updateWith});
|
||||
}
|
||||
|
||||
unbind(): void {
|
||||
this.setState({keybind: null});
|
||||
Config.config[this.props.option] = null;
|
||||
}
|
||||
}
|
||||
|
||||
export default KeybindComponent;
|
||||
165
src/components/KeybindDialogComponent.tsx
Normal file
165
src/components/KeybindDialogComponent.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
import * as React from "react";
|
||||
import { ChangeEvent } from "react";
|
||||
import Config from "../config";
|
||||
import { Keybind } from "../types";
|
||||
import { keybindEquals, formatKey } from "../utils/configUtils";
|
||||
|
||||
export interface KeybindDialogProps {
|
||||
option: string;
|
||||
closeListener: (updateWith) => void;
|
||||
}
|
||||
|
||||
export interface KeybindDialogState {
|
||||
key: Keybind;
|
||||
error: ErrorMessage;
|
||||
}
|
||||
|
||||
interface ErrorMessage {
|
||||
message: string;
|
||||
blocking: boolean;
|
||||
}
|
||||
|
||||
class KeybindDialogComponent extends React.Component<KeybindDialogProps, KeybindDialogState> {
|
||||
|
||||
constructor(props: KeybindDialogProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
key: {
|
||||
key: null,
|
||||
code: null,
|
||||
ctrl: false,
|
||||
alt: false,
|
||||
shift: false
|
||||
},
|
||||
error: {
|
||||
message: null,
|
||||
blocking: false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render(): React.ReactElement {
|
||||
return(
|
||||
<>
|
||||
<div className="blocker"></div>
|
||||
<div className="dialog">
|
||||
<div id="change-keybind-description">{chrome.i18n.getMessage("keybindDescription")}</div>
|
||||
<div id="change-keybind-settings">
|
||||
<div id="change-keybind-modifiers" className="inline">
|
||||
<div>
|
||||
<input id="change-keybind-ctrl" type="checkbox" onChange={this.keybindModifierChecked} />
|
||||
<label htmlFor="change-keybind-ctrl">Ctrl</label>
|
||||
</div>
|
||||
<div>
|
||||
<input id="change-keybind-alt" type="checkbox" onChange={this.keybindModifierChecked} />
|
||||
<label htmlFor="change-keybind-alt">Alt</label>
|
||||
</div>
|
||||
<div>
|
||||
<input id="change-keybind-shift" type="checkbox" onChange={this.keybindModifierChecked} />
|
||||
<label htmlFor="change-keybind-shift">Shift</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="key inline">{formatKey(this.state.key.key)}</div>
|
||||
</div>
|
||||
<div id="change-keybind-error">{this.state.error?.message}</div>
|
||||
<div id="change-keybind-buttons">
|
||||
<div className={"option-button save-button inline" + ((this.state.error?.blocking || this.state.key.key == null) ? " disabled" : "")} onClick={() => this.save()}>
|
||||
{chrome.i18n.getMessage("save")}
|
||||
</div>
|
||||
<div className="option-button cancel-button inline" onClick={() => this.props.closeListener(null)}>
|
||||
{chrome.i18n.getMessage("cancel")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
parent.document.addEventListener("keydown", this.keybindKeyPressed);
|
||||
document.addEventListener("keydown", this.keybindKeyPressed);
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
parent.document.removeEventListener("keydown", this.keybindKeyPressed);
|
||||
document.removeEventListener("keydown", this.keybindKeyPressed);
|
||||
}
|
||||
|
||||
keybindKeyPressed = (e: KeyboardEvent): void => {
|
||||
if (!e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey && !e.getModifierState("AltGraph")) {
|
||||
if (e.code == "Escape") {
|
||||
this.props.closeListener(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
key: {
|
||||
key: e.key,
|
||||
code: e.code,
|
||||
ctrl: this.state.key.ctrl,
|
||||
alt: this.state.key.alt,
|
||||
shift: this.state.key.shift}
|
||||
}, () => this.setState({ error: this.isKeybindAvailable() }));
|
||||
}
|
||||
}
|
||||
|
||||
keybindModifierChecked = (e: ChangeEvent<HTMLInputElement>): void => {
|
||||
const id = e.target.id;
|
||||
const val = e.target.checked;
|
||||
|
||||
this.setState({
|
||||
key: {
|
||||
key: this.state.key.key,
|
||||
code: this.state.key.code,
|
||||
ctrl: id == "change-keybind-ctrl" ? val: this.state.key.ctrl,
|
||||
alt: id == "change-keybind-alt" ? val: this.state.key.alt,
|
||||
shift: id == "change-keybind-shift" ? val: this.state.key.shift}
|
||||
}, () => this.setState({ error: this.isKeybindAvailable() }));
|
||||
}
|
||||
|
||||
isKeybindAvailable(): ErrorMessage {
|
||||
if (this.state.key.key == null)
|
||||
return null;
|
||||
|
||||
let youtubeShortcuts: Keybind[];
|
||||
if (/[a-zA-Z0-9,.+\-\][:]/.test(this.state.key.key)) {
|
||||
youtubeShortcuts = [{key: "k"}, {key: "j"}, {key: "l"}, {key: "p", shift: true}, {key: "n", shift: true}, {key: ","}, {key: "."}, {key: ",", shift: true}, {key: ".", shift: true},
|
||||
{key: "ArrowRight"}, {key: "ArrowLeft"}, {key: "ArrowUp"}, {key: "ArrowDown"}, {key: "ArrowRight", ctrl: true}, {key: "ArrowLeft", ctrl: true}, {key: "c"}, {key: "o"},
|
||||
{key: "w"}, {key: "+"}, {key: "-"}, {key: "f"}, {key: "t"}, {key: "i"}, {key: "m"}, {key: "a"}, {key: "s"}, {key: "d"}, {key: "Home"}, {key: "End"},
|
||||
{key: "0"}, {key: "1"}, {key: "2"}, {key: "3"}, {key: "4"}, {key: "5"}, {key: "6"}, {key: "7"}, {key: "8"}, {key: "9"}, {key: "]"}, {key: "["}];
|
||||
} else {
|
||||
youtubeShortcuts = [{key: null, code: "KeyK"}, {key: null, code: "KeyJ"}, {key: null, code: "KeyL"}, {key: null, code: "KeyP", shift: true}, {key: null, code: "KeyN", shift: true},
|
||||
{key: null, code: "Comma"}, {key: null, code: "Period"}, {key: null, code: "Comma", shift: true}, {key: null, code: "Period", shift: true}, {key: null, code: "Space"},
|
||||
{key: null, code: "KeyC"}, {key: null, code: "KeyO"}, {key: null, code: "KeyW"}, {key: null, code: "Equal"}, {key: null, code: "Minus"}, {key: null, code: "KeyF"}, {key: null, code: "KeyT"},
|
||||
{key: null, code: "KeyI"}, {key: null, code: "KeyM"}, {key: null, code: "KeyA"}, {key: null, code: "KeyS"}, {key: null, code: "KeyD"}, {key: null, code: "BracketLeft"}, {key: null, code: "BracketRight"}];
|
||||
}
|
||||
|
||||
for (const shortcut of youtubeShortcuts) {
|
||||
const withShift = Object.assign({}, shortcut);
|
||||
if (!/[0-9]/.test(this.state.key.key)) //shift+numbers don't seem to do anything on youtube, all other keys do
|
||||
withShift.shift = true;
|
||||
if (this.equals(shortcut) || this.equals(withShift))
|
||||
return {message: chrome.i18n.getMessage("youtubeKeybindWarning"), blocking: false};
|
||||
}
|
||||
|
||||
if (this.props.option != "skipKeybind" && this.equals(Config.config['skipKeybind']) ||
|
||||
this.props.option != "submitKeybind" && this.equals(Config.config['submitKeybind']) ||
|
||||
this.props.option != "startSponsorKeybind" && this.equals(Config.config['startSponsorKeybind']))
|
||||
return {message: chrome.i18n.getMessage("keyAlreadyUsed"), blocking: true};
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
equals(other: Keybind): boolean {
|
||||
return keybindEquals(this.state.key, other);
|
||||
}
|
||||
|
||||
save(): void {
|
||||
if (this.state.key.key != null && !this.state.error?.blocking) {
|
||||
Config.config[this.props.option] = this.state.key;
|
||||
this.props.closeListener(this.state.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default KeybindDialogComponent;
|
||||
@@ -6,8 +6,8 @@ import NoticeComponent from "./NoticeComponent";
|
||||
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||
import Utils from "../utils";
|
||||
const utils = new Utils();
|
||||
|
||||
import { getSkippingText } from "../utils/categoryUtils";
|
||||
import { keybindToString } from "../utils/configUtils";
|
||||
|
||||
import ThumbsUpSvg from "../svg-icons/thumbs_up_svg";
|
||||
import ThumbsDownSvg from "../svg-icons/thumbs_down_svg";
|
||||
@@ -344,7 +344,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
className="sponsorSkipObject sponsorSkipNoticeButton"
|
||||
style={style}
|
||||
onClick={() => this.prepAction(SkipNoticeAction.Unskip)}>
|
||||
{this.state.skipButtonText + (this.state.showKeybindHint ? " (" + Config.config.skipKeybind + ")" : "")}
|
||||
{this.state.skipButtonText + (this.state.showKeybindHint ? " (" + keybindToString(Config.config.skipKeybind) + ")" : "")}
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
@@ -517,9 +517,10 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
source: SponsorSourceType.Local
|
||||
};
|
||||
|
||||
const segmentTimes = Config.config.segmentTimes.get(sponsorVideoID) || [];
|
||||
const segmentTimes = Config.config.unsubmittedSegments[sponsorVideoID] || [];
|
||||
segmentTimes.push(sponsorTimesSubmitting);
|
||||
Config.config.segmentTimes.set(sponsorVideoID, segmentTimes);
|
||||
Config.config.unsubmittedSegments[sponsorVideoID] = segmentTimes;
|
||||
Config.forceSyncUpdate("unsubmittedSegments");
|
||||
|
||||
this.props.contentContainer().sponsorTimesSubmitting.push(sponsorTimesSubmitting);
|
||||
this.props.contentContainer().updatePreviewBar();
|
||||
@@ -645,18 +646,9 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
|
||||
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
|
||||
|
||||
// Change the sponsor locally
|
||||
if (segment) {
|
||||
if (type === 0) {
|
||||
segment.hidden = SponsorHideType.Downvoted;
|
||||
} else if (category) {
|
||||
segment.category = category; // This is the actual segment on the video page
|
||||
this.segments[index].category = category; //this is the segment inside the skip notice.
|
||||
} else if (type === 1) {
|
||||
segment.hidden = SponsorHideType.Visible;
|
||||
}
|
||||
|
||||
this.contentContainer().updatePreviewBar();
|
||||
if (segment && category) {
|
||||
// This is the segment inside the skip notice
|
||||
this.segments[index].category = category;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,7 +685,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
|
||||
clearConfigListener(): void {
|
||||
if (this.configListener) {
|
||||
Config.configListeners.splice(Config.configListeners.indexOf(this.configListener), 1);
|
||||
Config.configSyncListeners.splice(Config.configSyncListeners.indexOf(this.configListener), 1);
|
||||
this.configListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
// Add as a config listener
|
||||
if (!this.configUpdateListener) {
|
||||
this.configUpdateListener = () => this.configUpdate();
|
||||
Config.configListeners.push(this.configUpdate.bind(this));
|
||||
Config.configSyncListeners.push(this.configUpdate.bind(this));
|
||||
}
|
||||
|
||||
this.checkToShowFullVideoWarning();
|
||||
@@ -93,7 +93,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
|
||||
componentWillUnmount(): void {
|
||||
if (this.configUpdateListener) {
|
||||
Config.configListeners.splice(Config.configListeners.indexOf(this.configUpdate.bind(this)), 1);
|
||||
Config.configSyncListeners.splice(Config.configSyncListeners.indexOf(this.configUpdate.bind(this)), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
</span>
|
||||
): ""}
|
||||
|
||||
{(!isNaN(segment[1])) ? (
|
||||
{(!isNaN(segment[1]) && sponsorTime.actionType != ActionType.Full) ? (
|
||||
<span id={"sponsorTimeInspectButton" + this.idSuffix}
|
||||
className="sponsorTimeEditButton"
|
||||
onClick={this.inspectTime.bind(this)}>
|
||||
@@ -274,7 +274,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
</span>
|
||||
): ""}
|
||||
|
||||
{(!isNaN(segment[1])) ? (
|
||||
{(!isNaN(segment[1]) && sponsorTime.actionType != ActionType.Full) ? (
|
||||
<span id={"sponsorTimeEditButton" + this.idSuffix}
|
||||
className="sponsorTimeEditButton"
|
||||
onClick={this.toggleEditTime.bind(this)}>
|
||||
@@ -409,7 +409,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
if (confirm(chrome.i18n.getMessage("enableThisCategoryFirst")
|
||||
.replace("{0}", chrome.i18n.getMessage("category_" + chosenCategory)))) {
|
||||
// Open options page
|
||||
chrome.runtime.sendMessage({message: "openConfig", hash: chosenCategory + "OptionsName"});
|
||||
chrome.runtime.sendMessage({message: "openConfig", hash: "behavior"});
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -547,7 +547,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
const description = actionType === ActionType.Chapter ? this.descriptionOptionRef?.current?.value : "";
|
||||
sponsorTimesSubmitting[this.props.index].description = description;
|
||||
|
||||
Config.config.segmentTimes.set(this.props.contentContainer().sponsorVideoID, sponsorTimesSubmitting);
|
||||
Config.config.unsubmittedSegments[this.props.contentContainer().sponsorVideoID] = sponsorTimesSubmitting;
|
||||
Config.forceSyncUpdate("unsubmittedSegments");
|
||||
|
||||
this.props.contentContainer().updatePreviewBar();
|
||||
|
||||
@@ -593,7 +594,12 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
sponsorTimes.splice(index, 1);
|
||||
|
||||
//save this
|
||||
Config.config.segmentTimes.set(this.props.contentContainer().sponsorVideoID, sponsorTimes);
|
||||
if (sponsorTimes.length > 0) {
|
||||
Config.config.unsubmittedSegments[this.props.contentContainer().sponsorVideoID] = sponsorTimes;
|
||||
} else {
|
||||
delete Config.config.unsubmittedSegments[this.props.contentContainer().sponsorVideoID];
|
||||
}
|
||||
Config.forceSyncUpdate("unsubmittedSegments");
|
||||
|
||||
this.props.contentContainer().updatePreviewBar();
|
||||
|
||||
|
||||
37
src/components/TooltipComponent.tsx
Normal file
37
src/components/TooltipComponent.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import * as React from "react";
|
||||
import Config from "../config";
|
||||
import { Category, SegmentUUID, SponsorTime } from "../types";
|
||||
|
||||
export interface TooltipProps {
|
||||
text: string;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
export interface TooltipState {
|
||||
|
||||
}
|
||||
|
||||
class TooltipComponent extends React.Component<TooltipProps, TooltipState> {
|
||||
|
||||
constructor(props: TooltipProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render(): React.ReactElement {
|
||||
const style: React.CSSProperties = {
|
||||
display: this.props.show ? "flex" : "none",
|
||||
position: "absolute",
|
||||
}
|
||||
|
||||
return (
|
||||
<span style={style}
|
||||
className={"sponsorBlockTooltip"} >
|
||||
<span className="sponsorBlockTooltipText">
|
||||
{this.props.text}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TooltipComponent;
|
||||
Reference in New Issue
Block a user