diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/NoticeComponent.tsx | 25 | ||||
-rw-r--r-- | src/components/NoticeTextSectionComponent.tsx | 16 | ||||
-rw-r--r-- | src/components/SponsorTimeEditComponent.tsx | 10 | ||||
-rw-r--r-- | src/components/SubmissionNoticeComponent.tsx | 48 | ||||
-rw-r--r-- | src/config.ts | 2 | ||||
-rw-r--r-- | src/render/GenericNotice.tsx | 37 | ||||
-rw-r--r-- | src/utils/constants.ts | 21 | ||||
-rw-r--r-- | src/utils/genericUtils.ts | 2 |
8 files changed, 132 insertions, 29 deletions
diff --git a/src/components/NoticeComponent.tsx b/src/components/NoticeComponent.tsx index c3128e72..83540875 100644 --- a/src/components/NoticeComponent.tsx +++ b/src/components/NoticeComponent.tsx @@ -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; diff --git a/src/components/NoticeTextSectionComponent.tsx b/src/components/NoticeTextSectionComponent.tsx index 5e74a1d6..71fcb263 100644 --- a/src/components/NoticeTextSectionComponent.tsx +++ b/src/components/NoticeTextSectionComponent.tsx @@ -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> ); } } diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index 9d749ac0..17651e19 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -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 { diff --git a/src/components/SubmissionNoticeComponent.tsx b/src/components/SubmissionNoticeComponent.tsx index de9e9f7d..64146822 100644 --- a/src/components/SubmissionNoticeComponent.tsx +++ b/src/components/SubmissionNoticeComponent.tsx @@ -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; diff --git a/src/config.ts b/src/config.ts index 5a0fe5be..c5080a6c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -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: {}, diff --git a/src/render/GenericNotice.tsx b/src/render/GenericNotice.tsx index 08570eab..d00799fb 100644 --- a/src/render/GenericNotice.tsx +++ b/src/render/GenericNotice.tsx @@ -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} /> ) } diff --git a/src/utils/constants.ts b/src/utils/constants.ts new file mode 100644 index 00000000..6fb91a8d --- /dev/null +++ b/src/utils/constants.ts @@ -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`) + }]; + } +}
\ No newline at end of file diff --git a/src/utils/genericUtils.ts b/src/utils/genericUtils.ts index a11f9c4c..409dc6e9 100644 --- a/src/utils/genericUtils.ts +++ b/src/utils/genericUtils.ts @@ -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, |