diff --git a/manifest/manifest.json b/manifest/manifest.json index 7bb8af26..fc207352 100644 --- a/manifest/manifest.json +++ b/manifest/manifest.json @@ -50,6 +50,10 @@ "icons/heart.svg", "icons/visible.svg", "icons/not_visible.svg", + "icons/money.svg", + "icons/segway.png", + "icons/close-smaller.svg", + "icons/right-arrow.svg", "icons/PlayerInfoIconSponsorBlocker.svg", "icons/PlayerDeleteIconSponsorBlocker.svg", "popup.html", diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index ef9f325d..a367acf5 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -239,6 +239,9 @@ "showSkipNotice": { "message": "Show Notice After A Segment Is Skipped" }, + "showCategoryGuidelines": { + "message": "Show Category Help" + }, "noticeVisibilityMode0": { "message": "Full Size Skip Notices" }, @@ -542,18 +545,39 @@ "message": "to", "description": "Used between segments. Example: 1:20 to 1:30" }, + "generic_guideline1": { + "message": "Include segue transitions" + }, + "generic_guideline2": { + "message": "Plays as if nothing was skipped" + }, "category_sponsor": { "message": "Sponsor" }, "category_sponsor_description": { "message": "Paid promotion, paid referrals and direct advertisements. Not for self-promotion or free shoutouts to causes/creators/websites/products they like." }, + "category_sponsor_guideline1": { + "message": "Paid promotions" + }, + "category_sponsor_guideline2": { + "message": "Not for donations or custom merch" + }, "category_selfpromo": { "message": "Unpaid/Self Promotion" }, "category_selfpromo_description": { "message": "Similar to \"sponsor\" except for unpaid or self promotion. This includes sections about merchandise, donations, or information about who they collaborated with." }, + "category_selfpromo_guideline1": { + "message": "Applies to donations, memberships and custom merch" + }, + "category_selfpromo_guideline2": { + "message": "Free shoutouts that don't add to the video" + }, + "category_selfpromo_guideline3": { + "message": "Generic and company-created merch is Sponsor" + }, "category_exclusive_access": { "message": "Exclusive Access" }, diff --git a/public/content.css b/public/content.css index 6a2c1a04..ded0e3f3 100644 --- a/public/content.css +++ b/public/content.css @@ -347,6 +347,22 @@ color: rgb(235, 235, 235); } +.sb-guidelines-notice .sponsorTimesInfoMessage td { + padding-left: 5px; + padding-top: 2px; + padding-bottom: 2px; + font-size: 15px; + + display: flex; + align-items: center; +} + +.sponsorTimesInfoIcon { + width: 30px; + padding-right: 10px; + padding-left: 10px; +} + .segmentSummary { outline: none !important; } diff --git a/public/icons/close-smaller.svg b/public/icons/close-smaller.svg new file mode 100644 index 00000000..9a740f53 --- /dev/null +++ b/public/icons/close-smaller.svg @@ -0,0 +1,37 @@ + + + + + + diff --git a/public/icons/money.svg b/public/icons/money.svg new file mode 100644 index 00000000..fde5f8a9 --- /dev/null +++ b/public/icons/money.svg @@ -0,0 +1,37 @@ + + + + + + diff --git a/public/icons/right-arrow.svg b/public/icons/right-arrow.svg new file mode 100644 index 00000000..638cf96e --- /dev/null +++ b/public/icons/right-arrow.svg @@ -0,0 +1,37 @@ + + + + + + diff --git a/public/icons/segway.png b/public/icons/segway.png new file mode 100644 index 00000000..b1057c13 Binary files /dev/null and b/public/icons/segway.png differ diff --git a/public/options/options.html b/public/options/options.html index e23be2ab..d50f9c5c 100644 --- a/public/options/options.html +++ b/public/options/options.html @@ -175,6 +175,18 @@ + +
+
+ + +
+
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 { amountOfPreviousNotices: number; + parentRef: React.RefObject; + 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 { // Setup state this.state = { - noticeTitle: props.noticeTitle, - maxCountdownTime, //the countdown until this notice closes @@ -97,9 +98,11 @@ class NoticeComponent extends React.Component { return (
this.onMouseEnter(e) } onMouseLeave={() => this.timerMouseLeave()} + ref={this.parentRef} style={noticeStyle} >
{ style={{float: "left"}} className="sponsorSkipMessage sponsorSkipObject"> - {this.state.noticeTitle} + {this.props.noticeTitle} {this.props.firstColumn} @@ -344,12 +347,6 @@ class NoticeComponent extends React.Component { 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 { document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); } } + + getElement(): React.RefObject { + 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 - {this.props.text} -

+ + + {this.props.icon ? + + : null} + + + {this.props.text} + + + ); } } 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): 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): 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 ); @@ -154,6 +160,7 @@ class SubmissionNoticeComponent extends React.Component 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) => 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; + 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( this.close()} > - {this.getMessageBox(idSuffix, options.textBoxes)} + {this.getMessageBox(this.idSuffix, options.textBoxes)} - -
- - {this.getButtons(options.buttons)} -
+ + {this.getButtons(options.buttons)} + +
, 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( + 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,