diff options
author | Ajay <[email protected]> | 2022-05-31 00:50:32 -0400 |
---|---|---|
committer | Ajay <[email protected]> | 2022-05-31 00:50:32 -0400 |
commit | 588c42d57901d8b9c1f583575de6084d010f22ef (patch) | |
tree | 7a091dfe8bd336210acffaf33cdefb63ab9fa27b | |
parent | d7ff6aa6a2a326f96f89e960f224f72cb8f9d63f (diff) | |
download | SponsorBlock-588c42d57901d8b9c1f583575de6084d010f22ef.tar.gz SponsorBlock-588c42d57901d8b9c1f583575de6084d010f22ef.zip |
Add initial sponsor help page
-rw-r--r-- | manifest/manifest.json | 4 | ||||
-rw-r--r-- | public/_locales/en/messages.json | 24 | ||||
-rw-r--r-- | public/content.css | 16 | ||||
-rw-r--r-- | public/icons/close-smaller.svg | 37 | ||||
-rw-r--r-- | public/icons/money.svg | 37 | ||||
-rw-r--r-- | public/icons/right-arrow.svg | 37 | ||||
-rw-r--r-- | public/icons/segway.png | bin | 0 -> 1316 bytes | |||
-rw-r--r-- | public/options/options.html | 12 | ||||
-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 |
16 files changed, 299 insertions, 29 deletions
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 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + height="48" + width="48" + version="1.1" + id="svg4" + sodipodi:docname="close-smaller.svg" + inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <defs + id="defs8" /> + <sodipodi:namedview + id="namedview6" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + showgrid="false" + inkscape:zoom="13.125" + inkscape:cx="24" + inkscape:cy="24" + inkscape:window-width="1366" + inkscape:window-height="731" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="svg4" /> + <path + d="M12.45 37.65 10.35 35.55 21.9 24 10.35 12.45 12.45 10.35 24 21.9 35.55 10.35 37.65 12.45 26.1 24 37.65 35.55 35.55 37.65 24 26.1Z" + id="path2" + style="fill:#ffffff" /> +</svg> 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 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + height="48" + width="48" + version="1.1" + id="svg4" + sodipodi:docname="money.svg" + inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <defs + id="defs8" /> + <sodipodi:namedview + id="namedview6" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + showgrid="false" + inkscape:zoom="6.5625" + inkscape:cx="37.942857" + inkscape:cy="29.714286" + inkscape:window-width="1366" + inkscape:window-height="731" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="svg4" /> + <path + d="M 22.070204,47.757552 V 42.214123 Q 18.308592,41.554191 15.89984,39.343419 13.491088,37.132647 12.435197,33.766994 l 3.695619,-1.517844 q 1.121884,3.167674 3.233667,4.718514 2.111782,1.55084 5.081476,1.55084 3.167674,0 5.213463,-1.583837 2.045789,-1.583837 2.045789,-4.355551 0,-2.903701 -1.814813,-4.487538 -1.814813,-1.583836 -6.830296,-3.233666 -4.75151,-1.517844 -7.094269,-4.025586 -2.342759,-2.507741 -2.342759,-6.269354 0,-3.629626 2.342759,-6.0713741 2.342759,-2.4417484 6.104371,-2.7717144 V 0.24244792 h 3.959592 V 5.7198835 q 2.969694,0.329966 5.114473,1.9467994 2.144779,1.6168335 3.266663,4.1245751 l -3.695619,1.583837 q -0.923905,-2.111783 -2.474745,-3.068684 -1.55084,-0.9569014 -4.058582,-0.9569014 -3.035687,0 -4.817503,1.3858574 -1.781817,1.385857 -1.781817,3.761612 0,2.507742 1.979796,4.058582 1.979796,1.55084 7.325246,3.20067 4.487537,1.385857 6.632316,3.992589 2.144779,2.606731 2.144779,6.566323 0,4.157572 -2.441748,6.69831 -2.441749,2.540738 -7.193259,3.266663 v 5.477436 z" + id="path2" + style="fill:#ffffff;stroke-width:1.31986" /> +</svg> 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 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + height="48" + width="48" + version="1.1" + id="svg4" + sodipodi:docname="right-arrow.svg" + inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <defs + id="defs8" /> + <sodipodi:namedview + id="namedview6" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + showgrid="false" + inkscape:zoom="13.125" + inkscape:cx="24" + inkscape:cy="24" + inkscape:window-width="1366" + inkscape:window-height="731" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="svg4" /> + <path + d="M15.2 43.9 12.4 41.05 29.55 23.9 12.4 6.75 15.2 3.9 35.2 23.9Z" + id="path2" + style="fill:#ffffff" /> +</svg> diff --git a/public/icons/segway.png b/public/icons/segway.png Binary files differnew file mode 100644 index 00000000..b1057c13 --- /dev/null +++ b/public/icons/segway.png 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 @@ <option value="4">__MSG_noticeVisibilityMode4__</option> </select> </div> + + <div data-type="toggle" data-sync="showCategoryGuidelines"> + <div class="switch-container"> + <label class="switch"> + <input id="showCategoryGuidelines" type="checkbox" checked> + <span class="slider round"></span> + </label> + <label class="switch-label" for="showCategoryGuidelines"> + __MSG_showCategoryGuidelines__ + </label> + </div> + </div> <div data-type="toggle" data-toggle-type="reverse" data-sync="hideVideoPlayerControls"> <div class="switch-container"> 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, |