Add initial sponsor help page

This commit is contained in:
Ajay
2022-05-31 00:50:32 -04:00
parent d7ff6aa6a2
commit 588c42d579
16 changed files with 299 additions and 29 deletions

View File

@@ -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;

View File

@@ -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>
);
}
}

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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: {},

View File

@@ -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
View 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`)
}];
}
}

View File

@@ -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,