mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2026-03-24 22:58:18 +03:00
Add initial sponsor help page
This commit is contained in:
@@ -24,6 +24,7 @@ export interface NoticeProps {
|
||||
|
||||
smaller?: boolean,
|
||||
limitWidth?: boolean,
|
||||
extraClass?: string,
|
||||
|
||||
// Callback for when this is closed
|
||||
closeListener: () => void,
|
||||
@@ -35,8 +36,6 @@ export interface NoticeProps {
|
||||
}
|
||||
|
||||
export interface NoticeState {
|
||||
noticeTitle: string,
|
||||
|
||||
maxCountdownTime: () => number,
|
||||
|
||||
countdownTime: number,
|
||||
@@ -54,9 +53,13 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
|
||||
amountOfPreviousNotices: number;
|
||||
|
||||
parentRef: React.RefObject<HTMLDivElement>;
|
||||
|
||||
constructor(props: NoticeProps) {
|
||||
super(props);
|
||||
|
||||
this.parentRef = React.createRef();
|
||||
|
||||
const maxCountdownTime = () => {
|
||||
if (this.props.maxCountdownTime) return this.props.maxCountdownTime();
|
||||
else return Config.config.skipNoticeDuration;
|
||||
@@ -71,8 +74,6 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
|
||||
// Setup state
|
||||
this.state = {
|
||||
noticeTitle: props.noticeTitle,
|
||||
|
||||
maxCountdownTime,
|
||||
|
||||
//the countdown until this notice closes
|
||||
@@ -97,9 +98,11 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
return (
|
||||
<div id={"sponsorSkipNotice" + this.idSuffix}
|
||||
className={"sponsorSkipObject sponsorSkipNoticeParent"
|
||||
+ (this.props.showInSecondSlot ? " secondSkipNotice" : "")}
|
||||
+ (this.props.showInSecondSlot ? " secondSkipNotice" : "")
|
||||
+ (this.props.extraClass ? ` ${this.props.extraClass}` : "")}
|
||||
onMouseEnter={(e) => this.onMouseEnter(e) }
|
||||
onMouseLeave={() => this.timerMouseLeave()}
|
||||
ref={this.parentRef}
|
||||
style={noticeStyle} >
|
||||
<div className={"sponsorSkipNoticeTableContainer"
|
||||
+ (this.props.fadeIn ? " sponsorSkipNoticeFadeIn" : "")
|
||||
@@ -123,7 +126,7 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
style={{float: "left"}}
|
||||
className="sponsorSkipMessage sponsorSkipObject">
|
||||
|
||||
{this.state.noticeTitle}
|
||||
{this.props.noticeTitle}
|
||||
</span>
|
||||
|
||||
{this.props.firstColumn}
|
||||
@@ -344,12 +347,6 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
if (!silent) this.props.closeListener();
|
||||
}
|
||||
|
||||
changeNoticeTitle(title: string): void {
|
||||
this.setState({
|
||||
noticeTitle: title
|
||||
});
|
||||
}
|
||||
|
||||
addNoticeInfoMessage(message: string, message2 = ""): void {
|
||||
//TODO: Replace
|
||||
|
||||
@@ -384,6 +381,10 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
||||
}
|
||||
}
|
||||
|
||||
getElement(): React.RefObject<HTMLDivElement> {
|
||||
return this.parentRef;
|
||||
}
|
||||
}
|
||||
|
||||
export default NoticeComponent;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface NoticeTextSelectionProps {
|
||||
icon?: string,
|
||||
text: string,
|
||||
idSuffix: string,
|
||||
onClick?: (event: React.MouseEvent) => unknown
|
||||
@@ -24,12 +25,21 @@ class NoticeTextSelectionComponent extends React.Component<NoticeTextSelectionPr
|
||||
}
|
||||
|
||||
return (
|
||||
<p id={"sponsorTimesInfoMessage" + this.props.idSuffix}
|
||||
<tr id={"sponsorTimesInfoMessage" + this.props.idSuffix}
|
||||
onClick={this.props.onClick}
|
||||
style={style}
|
||||
className="sponsorTimesInfoMessage">
|
||||
{this.props.text}
|
||||
</p>
|
||||
|
||||
<td>
|
||||
{this.props.icon ?
|
||||
<img src={chrome.runtime.getURL(this.props.icon)} className="sponsorTimesInfoIcon" />
|
||||
: null}
|
||||
|
||||
<span>
|
||||
{this.props.text}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface SponsorTimeEditProps {
|
||||
|
||||
submissionNotice: SubmissionNoticeComponent;
|
||||
categoryList?: Category[];
|
||||
categoryChangeListener?: (index: number, category: Category) => void;
|
||||
}
|
||||
|
||||
export interface SponsorTimeEditState {
|
||||
@@ -365,9 +366,10 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
}
|
||||
|
||||
categorySelectionChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||
const chosenCategory = event.target.value as Category;
|
||||
|
||||
// See if show more categories was pressed
|
||||
if (event.target.value !== DEFAULT_CATEGORY && !Config.config.categorySelections.some((category) => category.name === event.target.value)) {
|
||||
const chosenCategory = event.target.value;
|
||||
event.target.value = DEFAULT_CATEGORY;
|
||||
|
||||
// Alert that they have to enable this category first
|
||||
@@ -381,8 +383,12 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
}
|
||||
|
||||
const sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
this.handleReplacingLostTimes(event.target.value as Category, sponsorTime.actionType, sponsorTime);
|
||||
this.handleReplacingLostTimes(chosenCategory, sponsorTime.actionType, sponsorTime);
|
||||
this.saveEditTimes();
|
||||
|
||||
if (this.props.categoryChangeListener) {
|
||||
this.props.categoryChangeListener(this.props.index, chosenCategory);
|
||||
}
|
||||
}
|
||||
|
||||
actionTypeSelectionChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import * as React from "react";
|
||||
import Config from "../config"
|
||||
import { ContentContainer } from "../types";
|
||||
import GenericNotice from "../render/GenericNotice";
|
||||
import { Category, ContentContainer } from "../types";
|
||||
import * as CompileConfig from "../../config.json";
|
||||
|
||||
import NoticeComponent from "./NoticeComponent";
|
||||
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||
import SponsorTimeEditComponent from "./SponsorTimeEditComponent";
|
||||
import { getGuidelineInfo } from "../utils/constants";
|
||||
|
||||
export interface SubmissionNoticeProps {
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
@@ -32,6 +35,8 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
|
||||
videoObserver: MutationObserver;
|
||||
|
||||
guidelinesReminder: GenericNotice;
|
||||
|
||||
constructor(props: SubmissionNoticeProps) {
|
||||
super(props);
|
||||
this.noticeRef = React.createRef();
|
||||
@@ -128,6 +133,7 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
index={i}
|
||||
contentContainer={this.props.contentContainer}
|
||||
submissionNotice={this}
|
||||
categoryChangeListener={this.categoryChangeListener.bind(this)}
|
||||
ref={timeRef}>
|
||||
</SponsorTimeEditComponent>
|
||||
);
|
||||
@@ -154,6 +160,7 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
this.guidelinesReminder?.close();
|
||||
this.noticeRef.current.close(true);
|
||||
|
||||
this.contentContainer().resetSponsorSubmissionNotice();
|
||||
@@ -190,6 +197,45 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
|
||||
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
categoryChangeListener(index: number, category: Category): void {
|
||||
const dialogWidth = this.noticeRef?.current?.getElement()?.current?.offsetWidth;
|
||||
if (category !== "chooseACategory" && Config.config.showCategoryGuidelines
|
||||
&& this.contentContainer().v.offsetWidth > dialogWidth * 2) {
|
||||
const options = {
|
||||
title: chrome.i18n.getMessage(`category_${category}`),
|
||||
textBoxes: getGuidelineInfo(category),
|
||||
buttons: [{
|
||||
name: chrome.i18n.getMessage("learnMore"),
|
||||
listener: () => window.open(CompileConfig.wikiLinks[category])
|
||||
},
|
||||
{
|
||||
name: chrome.i18n.getMessage("Hide"),
|
||||
listener: () => {
|
||||
Config.config.showCategoryGuidelines = false;
|
||||
this.guidelinesReminder?.close();
|
||||
this.guidelinesReminder = null;
|
||||
}
|
||||
}],
|
||||
timed: false,
|
||||
style: {
|
||||
right: `${dialogWidth + 10}px`,
|
||||
},
|
||||
extraClass: "sb-guidelines-notice"
|
||||
};
|
||||
|
||||
if (options.textBoxes) {
|
||||
if (this.guidelinesReminder) {
|
||||
this.guidelinesReminder.update(options);
|
||||
} else {
|
||||
this.guidelinesReminder = new GenericNotice(null, "GuidelinesReminder", options);
|
||||
}
|
||||
} else {
|
||||
this.guidelinesReminder?.close();
|
||||
this.guidelinesReminder = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SubmissionNoticeComponent;
|
||||
|
||||
@@ -55,6 +55,7 @@ interface SBConfig {
|
||||
scrollToEditTimeUpdate: boolean,
|
||||
categoryPillUpdate: boolean,
|
||||
darkMode: boolean,
|
||||
showCategoryGuidelines: boolean,
|
||||
|
||||
// Used to cache calculated text color info
|
||||
categoryPillColors: {
|
||||
@@ -167,6 +168,7 @@ const Config: SBObject = {
|
||||
scrollToEditTimeUpdate: false, // false means the tooltip will be shown
|
||||
categoryPillUpdate: false,
|
||||
darkMode: true,
|
||||
showCategoryGuidelines: true,
|
||||
|
||||
categoryPillColors: {},
|
||||
|
||||
|
||||
@@ -13,12 +13,19 @@ export interface ButtonListener {
|
||||
listener: (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
|
||||
}
|
||||
|
||||
export interface TextBox {
|
||||
icon: string,
|
||||
text: string
|
||||
}
|
||||
|
||||
export interface NoticeOptions {
|
||||
title: string,
|
||||
textBoxes?: string[],
|
||||
textBoxes?: TextBox[],
|
||||
buttons?: ButtonListener[],
|
||||
fadeIn?: boolean,
|
||||
timed?: boolean
|
||||
style?: React.CSSProperties;
|
||||
extraClass?: string;
|
||||
}
|
||||
|
||||
export default class GenericNotice {
|
||||
@@ -27,9 +34,11 @@ export default class GenericNotice {
|
||||
|
||||
noticeElement: HTMLDivElement;
|
||||
noticeRef: React.MutableRefObject<NoticeComponent>;
|
||||
idSuffix: string;
|
||||
|
||||
constructor(contentContainer: ContentContainer, idSuffix: string, options: NoticeOptions) {
|
||||
this.noticeRef = React.createRef();
|
||||
this.idSuffix = idSuffix;
|
||||
|
||||
this.contentContainer = contentContainer;
|
||||
|
||||
@@ -40,39 +49,47 @@ export default class GenericNotice {
|
||||
|
||||
referenceNode.prepend(this.noticeElement);
|
||||
|
||||
this.update(options);
|
||||
}
|
||||
|
||||
update(options: NoticeOptions): void {
|
||||
ReactDOM.render(
|
||||
<NoticeComponent
|
||||
noticeTitle={options.title}
|
||||
idSuffix={idSuffix}
|
||||
idSuffix={this.idSuffix}
|
||||
fadeIn={options.fadeIn ?? true}
|
||||
timed={options.timed ?? true}
|
||||
ref={this.noticeRef}
|
||||
style={options.style}
|
||||
extraClass={options.extraClass}
|
||||
closeListener={() => this.close()} >
|
||||
|
||||
{this.getMessageBox(idSuffix, options.textBoxes)}
|
||||
{this.getMessageBox(this.idSuffix, options.textBoxes)}
|
||||
|
||||
<tr id={"sponsorSkipNoticeSpacer" + idSuffix}
|
||||
<tr id={"sponsorSkipNoticeSpacer" + this.idSuffix}
|
||||
className="sponsorBlockSpacer">
|
||||
</tr>
|
||||
|
||||
<div className="sponsorSkipNoticeRightSection"
|
||||
<tr className="sponsorSkipNoticeRightSection"
|
||||
style={{position: "relative"}}>
|
||||
|
||||
{this.getButtons(options.buttons)}
|
||||
</div>
|
||||
<td>
|
||||
{this.getButtons(options.buttons)}
|
||||
</td>
|
||||
</tr>
|
||||
</NoticeComponent>,
|
||||
this.noticeElement
|
||||
);
|
||||
}
|
||||
|
||||
getMessageBox(idSuffix: string, textBoxes: string[]): JSX.Element[] {
|
||||
getMessageBox(idSuffix: string, textBoxes: TextBox[]): JSX.Element[] {
|
||||
if (textBoxes) {
|
||||
const result = [];
|
||||
for (let i = 0; i < textBoxes.length; i++) {
|
||||
result.push(
|
||||
<NoticeTextSelectionComponent idSuffix={idSuffix}
|
||||
key={i}
|
||||
text={textBoxes[i]} />
|
||||
icon={textBoxes[i].icon}
|
||||
text={textBoxes[i].text} />
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
21
src/utils/constants.ts
Normal file
21
src/utils/constants.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { TextBox } from "../render/GenericNotice";
|
||||
import { Category } from "../types";
|
||||
|
||||
export function getGuidelineInfo(category: Category): TextBox[] {
|
||||
switch (category) {
|
||||
case "sponsor":
|
||||
return [{
|
||||
icon: "icons/money.svg",
|
||||
text: chrome.i18n.getMessage(`category_${category}_guideline1`)
|
||||
}, {
|
||||
icon: "icons/close-smaller.svg",
|
||||
text: chrome.i18n.getMessage(`category_${category}_guideline2`)
|
||||
}, {
|
||||
icon: "icons/segway.png",
|
||||
text: chrome.i18n.getMessage(`generic_guideline1`)
|
||||
}, {
|
||||
icon: "icons/right-arrow.svg",
|
||||
text: chrome.i18n.getMessage(`generic_guideline2`)
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ function hexToRgb(hex: string): {r: number, g: number, b: number} {
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16)
|
||||
} : null;
|
||||
}
|
||||
}
|
||||
|
||||
export const GenericUtils = {
|
||||
wait,
|
||||
|
||||
Reference in New Issue
Block a user