diff --git a/maze-utils b/maze-utils index e2f19e21..2c6822ec 160000 --- a/maze-utils +++ b/maze-utils @@ -1 +1 @@ -Subproject commit e2f19e21c23342638e26fd642ca9665b5b2ee775 +Subproject commit 2c6822ec85f97a919279742d22cc98426fb752b9 diff --git a/public/_locales b/public/_locales index c9dcf1ec..0285b879 160000 --- a/public/_locales +++ b/public/_locales @@ -1 +1 @@ -Subproject commit c9dcf1ec21c068c7b235fb146bb4922aa5b5706d +Subproject commit 0285b87951827abe87cd5f7fe4032a1389b0954a diff --git a/public/options/options.css b/public/options/options.css index 657fbee2..35ae92af 100644 --- a/public/options/options.css +++ b/public/options/options.css @@ -116,14 +116,26 @@ html, body { color: white; } -.option-group > div { +.option-group > div, .extraOptionGroup { min-height: 50px; padding: 15px 0; - border-bottom: 1px solid var(--border-color); border-image: linear-gradient(to right, var(--border-color), #00000000 80%) 1; } +.option-group > div { + border-bottom: 1px solid var(--border-color); +} +.extraOptionGroup { + border-top: 1px solid var(--border-color); +} +.extraOptionGroup tr:not(:last-child) { + padding-bottom: 15px; + display: block; +} +#category-type { + padding: 0; +} -.categoryExtraOptions { +.categoryChooserTable .categoryExtraOptions { padding-bottom: 15px; } @@ -364,6 +376,11 @@ input[type='number'] { padding: 4px; } +.sb-number-input { + margin-left: 4px; + margin-right: 4px; +} + .switch-label { width: inherit; } @@ -744,4 +761,40 @@ svg { .advanced-config-help-message { margin-bottom: 10px; transition: none; +} + +.categoryChooserTopRow { + display: flex; + align-items: center; + justify-content: space-between; + + margin-bottom: 10px; +} + +.partiallyHidden { + opacity: 0.5; +} + +.partiallyHidden:hover { + opacity: 1; +} + +.reset-button svg { + margin-left: 5px; + width: 10px; + fill: var(--white); + + cursor: pointer; +} + +.skipProfileMenu { + position: absolute; +} + +.configurationInfo > *:not(:last-child) { + margin-bottom: 10px; +} + +.configurationInfo .option-text-box { + width: 100%; } \ No newline at end of file diff --git a/public/options/options.html b/public/options/options.html index 0a8f6f44..bd1a7c90 100644 --- a/public/options/options.html +++ b/public/options/options.html @@ -80,66 +80,6 @@ -
-
- - -
-
- -
-
- - -
-
- -
-
- - -
-
- -
- - -
__MSG_minDurationDescription__
-
- -
-
- - -
- -
__MSG_whatManualSkipOnFullVideo__
-
-
diff --git a/public/popup.css b/public/popup.css index aa3fd108..76b03c13 100644 --- a/public/popup.css +++ b/public/popup.css @@ -277,8 +277,8 @@ border-radius: 8px; background-color: var(--sb-grey-bg-color); justify-content: space-evenly; - overflow: hidden; display: flex; + position: relative; } .sbControlsMenu-item { display: flex; @@ -627,4 +627,62 @@ .sbPopupButton { width: 16px; fill: var(--sb-main-fg-color); +} + +#skipProfileMenu { + position: absolute; + top: 80px; + left: 50%; + + background-color: #292828; + border-radius: 10px; + padding: 10px; + + transform: translateX(-50%); +} + +#skipProfileActions { + padding-top: 10px; +} + +.skipOptionAction { + transition: border-color 0.2s ease-in-out, background-color 0.2s ease-in-out; + font-size: 14px; + padding: 5px; + margin: 5px; + + background-color: #222; + border-radius: 5px; + + cursor: help; + user-select: none; + + border-color: transparent; + border-width: 2px; + border-style: solid; +} +.skipOptionAction:not(.highlighted, .disabled):hover { + background-color: var(--sb-grey-bg-color); +} +.skipOptionAction.selected { + border-color: var(--sb-red-bg-color); +} +.skipOptionAction.highlighted { + border-color: rgb(127, 0, 0); +} +.skipOptionAction:not(.highlighted, .disabled) { + cursor: pointer; +} +.skipOptionAction.disabled { + color: #808080 +} + +.optionsSelector { + background-color: #c00000; + color: white; + + border: none; + font-size: 14px; + padding: 5px; + border-radius: 5px; } \ No newline at end of file diff --git a/src/components/options/CategoryChooserComponent.tsx b/src/components/options/CategoryChooserComponent.tsx index 1da4f641..23cc4dad 100644 --- a/src/components/options/CategoryChooserComponent.tsx +++ b/src/components/options/CategoryChooserComponent.tsx @@ -1,30 +1,160 @@ import * as React from "react"; import * as CompileConfig from "../../../config.json"; -import { Category } from "../../types"; -import CategorySkipOptionsComponent from "./CategorySkipOptionsComponent"; +import { Category, CategorySelection, CategorySkipOption } from "../../types"; +import { CategorySkipOptionsComponent, ExtraOptionComponent, ToggleOption } from "./CategorySkipOptionsComponent"; +import { SelectOptionComponent } from "./SelectOptionComponent"; +import Config, { ConfigurationID, CustomConfiguration } from "../../config"; +import { generateUserID } from "../../../maze-utils/src/setup"; -export interface CategoryChooserProps { +let forceUpdateSkipProfilesTimeout: NodeJS.Timeout | null = null; +let forceUpdateSkipProfileIDsTimeout: NodeJS.Timeout | null = null; -} +export function CategoryChooserComponent() { + const [configurations, setConfigurations] = React.useState(Config.local!.skipProfiles); + const [selectedConfigurationID, setSelectedConfigurationID] = React.useState(null); + const [channelListText, setChannelListText] = React.useState(""); -export interface CategoryChooserState { + const [configurationName, setConfigurationName] = React.useState(""); + const [selections, setSelections] = React.useState([]); -} + React.useEffect(() => { + setConfigurationName(getConfigurationValue(selectedConfigurationID, "name", "")); -class CategoryChooserComponent extends React.Component { + updateChannelList(setChannelListText, selectedConfigurationID!); + setSelections(getConfigurationValue(selectedConfigurationID, "categorySelections")); + }, [selectedConfigurationID]); - constructor(props: CategoryChooserProps) { - super(props); - - // Setup state - this.state = { - + const createNewConfig = () => { + let newID = generateUserID().substring(0, 5); + while (Config.local.skipProfiles[newID]) { + newID = generateUserID().substring(0, 5); } - } - render(): React.ReactElement { - return ( + const newConfiguration: CustomConfiguration = { + name: `${chrome.i18n.getMessage("NewConfiguration")} ${Object.keys(Config.local.skipProfiles).length}`, + categorySelections: [], + showAutogeneratedChapters: null, + autoSkipOnMusicVideos: null, + skipNonMusicOnlyOnYoutubeMusic: null, + muteSegments: null, + fullVideoSegments: null, + manualSkipOnFullVideo: null, + minDuration: null + }; + + Config.local!.skipProfiles[newID] = newConfiguration; + forceUpdateConfigurations(); + setConfigurations(Config.local!.skipProfiles); + setSelectedConfigurationID(newID as ConfigurationID); + + updateChannelList(setChannelListText, newID as ConfigurationID); + }; + React.useEffect(() => { + if (window.location.hash === "#newProfile") { + createNewConfig(); + } + }, []); + + return ( + <> +
+ { + if (value === "null") value = null; + + setSelectedConfigurationID(value as ConfigurationID); + updateChannelList(setChannelListText, value as ConfigurationID); + }} + value={selectedConfigurationID!} + options={[{ + value: "null", + label: chrome.i18n.getMessage("DefaultConfiguration") + }].concat(Object.entries(configurations).map(([key, value]) => ({ + value: key, + label: value.name + })))} + /> + +
createNewConfig()}> + {chrome.i18n.getMessage("NewConfiguration")} +
+
+ + { + selectedConfigurationID && +
+ { + const newName = e.target.value; + getConfig(selectedConfigurationID)!.name = newName; + setConfigurationName(newName); + + forceUpdateConfigurations(); + setConfigurations(Config.local!.skipProfiles); + }}/> + +
+ {chrome.i18n.getMessage("ChannelListInstructionsSB")} +
+ +