group settings into tabs

This commit is contained in:
Áron Hegymegi-Kiss
2021-12-12 23:31:09 +01:00
parent 7186829bc3
commit dface28c84
5 changed files with 721 additions and 637 deletions

View File

@@ -845,5 +845,33 @@
"hourAbbreviation": { "hourAbbreviation": {
"message": "h", "message": "h",
"description": "100h" "description": "100h"
},
"optionsTabCategories" : {
"message": "Categories",
"description": "Appears in Options as a tab header for setting up categories."
},
"optionsTabBehavior" : {
"message": "Behavior",
"description": "Appears in Options as a tab header for options related to the general behavior of the extension."
},
"optionsTabInterface" : {
"message": "Interface",
"description": "Appears in Options as a tab header for options related to GUI and sounds"
},
"optionsTabKeyBinds" : {
"message": "Key Bindings",
"description": "Appears in Options as a tab header for keybinds"
},
"optionsTabPrivacy" : {
"message": "Privacy",
"description": "Appears in Options as a tab header for options related to privacy (data stored/sent to server)"
},
"optionsTabBackup" : {
"message": "Backup/Restore",
"description": "Appears in Options as a tab header for options related to saving/restoring your settings"
},
"optionsTabAdvanced" : {
"message": "Advanced",
"description": "Appears in Options as a tab header for advanced/niche options"
} }
} }

View File

@@ -1,10 +1,138 @@
/* Options page CSS */ /* Options page CSS */
/* Dark mode CSS, this is the default if unsupported */
html { html {
color-scheme: dark; color-scheme: dark;
} }
body { body {
background-color: #333333;
}
#navigation {
background-color: #181818;
color: white;
}
.tab-heading {
background-color: #242424;
color: white;
}
.tab-heading:hover {
outline: 3px solid white;
}
.medium-description, .switch-container, .text-label-container, .categoryTableElement {
color: white;
}
.small-description, p,li {
color: #dfdfdf;
}
.option-button.disabled {
background-color: #520000;
color: grey;
}
.slider {
background-color: #707070;
}
h1,h2,h3,h4,h5,h6 {
color: #dad8d8;
}
.option-group > div {
border-bottom: 1px solid #484848;
border-image: linear-gradient(to right, #484848, #00000000 80%) 1;
}
.categoryTableElement td {
border-top: 1px solid #484848;
}
/* Light mode, if requested */
@media only screen and (prefers-color-scheme: light) {
html {
color-scheme: light;
}
body {
background-color: #f9f9f9;
}
#navigation {
background-color: #dbdbdb;
color: #212121;
}
.tab-heading {
background-color: #ababab;
color: black;
}
.tab-heading:hover {
outline: 3px solid #2e2e2e;
}
.medium-description, .switch-container, .text-label-container, .categoryTableElement {
color: black;
}
.small-description, p,li {
color: #262626;
}
.option-button.disabled {
background-color: #ffcaca;
color: grey;
}
.slider {
background-color: #bfbebe;
}
h1,h2,h3,h4,h5,h6 {
color: #707070;
}
.option-group > div {
border-bottom: 1px solid #d9d9d9;
border-image: linear-gradient(to right, #d9d9d9, #00000000 80%) 1;
}
.categoryTableElement td {
border-top: 1px solid #d9d9d9;
}
}
html, body {
font-family: sans-serif; font-family: sans-serif;
margin: 0;
}
* {
box-sizing: border-box;
}
#options-container {
display: flex;
justify-content: space-between;
}
#navigation {
display: flex;
flex-direction: column;
gap: 20px;
flex-basis: 20%;
min-width: 300px;
max-width: 600px;
border-radius: 15px;
margin: 15px;
}
.tab-heading {
font-size: 18px;
height: 50px;
line-height: 50px;
width: 80%;
margin: 0 auto;
border-radius: 15px;
cursor: pointer;
}
.tab-heading.selected {
background-color: #c00000;
color: white;
}
.option-group > div {
min-height: 50px;
padding: 20px 0;
}
.option-group > div:last-child {
border-bottom: inherit;
} }
.center { .center {
@@ -27,13 +155,20 @@ body {
display: inline; display: inline;
} }
.small-description { .small-description{
color: white;
font-size: 13px; font-size: 13px;
padding: 15px 0 0 20px;
}
.small-description td {
padding: 10px 0 20px 20px;
}
.categoryTableElement td {
padding-top: 10px;
} }
.medium-description { .medium-description {
color: white;
font-size: 15px; font-size: 15px;
} }
@@ -53,21 +188,23 @@ body {
width: max-content; width: max-content;
} }
.option-button:hover { .option-button:hover:not(.disabled) {
background-color: #fc0303; background-color: #fc0303;
} }
.option-button.disabled { .option-button.disabled {
cursor: default; cursor: default;
background-color: #520000;
color: grey;
} }
#options { #options {
max-width: 60%; height: 100vh;
flex-basis: 80%;
overflow: auto;
text-align: left; text-align: left;
display: inline-block; padding: 80px 15px 0 3%;
box-sizing: border-box;
transition: padding 0.3s;
} }
#options.embed { #options.embed {
@@ -76,13 +213,15 @@ body {
display: inline-block; display: inline-block;
} }
#title .profilepic {
height: 60px;
}
.switch-container { .switch-container {
content: attr(label-name); content: attr(label-name);
position: absolute;
width: max-content; width: max-content;
font-size: 14px; font-size: 14px;
color: white;
display: table; display: table;
} }
@@ -96,7 +235,6 @@ body {
.text-label-container { .text-label-container {
font-size: 14px; font-size: 14px;
color: white;
} }
.switch { .switch {
@@ -119,7 +257,6 @@ body {
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background-color: #707070;
} }
.animated * { .animated * {
@@ -162,11 +299,8 @@ input:checked + .slider:before {
} }
/* Boilerplate CSS from https://ajay.app */
body { /* Boilerplate CSS from https://ajay.app (edited) */
background-color: #333333;
}
.projectPreview { .projectPreview {
position: relative; position: relative;
@@ -196,29 +330,21 @@ body {
transform: translateY(-50%); transform: translateY(-50%);
} }
.createdBy { #createdBy {
font-size: 14px; font-size: 14px;
text-align: center; text-align: center;
padding-top: 0px; margin-top: auto;
padding-bottom: 0px;
display: inline-block;
} }
#title { #title {
background-color: #636363;
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
font-size: 50px; font-size: 40px;
color: #212121;
padding: 20px; padding: 20px;
text-decoration: none; text-decoration: none;
transition: font-size 1s;
} }
.subtitle { .subtitle {
@@ -237,7 +363,6 @@ body {
} }
.profilepic { .profilepic {
background-color: #636363 !important;
vertical-align: middle; vertical-align: middle;
} }
@@ -281,21 +406,9 @@ a {
p,li { p,li {
font-size: 20px; font-size: 20px;
color: #c4c4c4;
padding: 10px; padding: 10px;
} }
@media screen and (orientation:portrait) {
#options {
max-width: 100%;
}
.previewColorOption {
display: none;
}
}
.previewImage { .previewImage {
max-height: 200px; max-height: 200px;
} }
@@ -316,10 +429,6 @@ img {
color: #dad8d8; color: #dad8d8;
} }
h1,h2,h3,h4,h5,h6 {
color: #dad8d8;
}
svg { svg {
text-decoration: none; text-decoration: none;
} }
@@ -337,8 +446,6 @@ svg {
.categoryTableElement { .categoryTableElement {
font-size: 16px; font-size: 16px;
color: white;
} }
.categoryTableElement > * { .categoryTableElement > * {
@@ -368,4 +475,50 @@ svg {
#sbDonate { #sbDonate {
font-size: 10px; font-size: 10px;
} }
/* Handle smaller screensizes */
@media only screen and (max-height: 770px), only screen and (max-width: 1200px) {
#options-container {
flex-direction: column;
}
#navigation {
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
align-items: center;
gap: 8px;
min-width: unset;
max-width: unset;
padding: 8px;
}
#options {
padding: 0 50px;
}
.tab-heading {
width: unset;
min-width: 150px;
height: 40px;
line-height: 40px;
margin: 0;
flex-grow: 1;
}
#title {
width: 100%;
font-size: 30px;
}
#title .profilepic {
height: 40px;
}
#createdBy {
margin: unset;
width: 100%;
}
}
@media only screen and (max-width: 800px) {
#options {
padding: 0 15px;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -31,24 +31,24 @@ class CategoryChooserComponent extends React.Component<CategoryChooserProps, Cat
{/* Headers */} {/* Headers */}
<tr id={"CategoryOptionsRow"} <tr id={"CategoryOptionsRow"}
className="categoryTableElement categoryTableHeader"> className="categoryTableElement categoryTableHeader">
<td id={"CategoryOptionName"}> <th id={"CategoryOptionName"}>
{chrome.i18n.getMessage("category")} {chrome.i18n.getMessage("category")}
</td> </th>
<td id={"CategorySkipOption"} <th id={"CategorySkipOption"}
className="skipOption"> className="skipOption">
{chrome.i18n.getMessage("skipOption")} {chrome.i18n.getMessage("skipOption")}
</td> </th>
<td id={"CategoryColorOption"} <th id={"CategoryColorOption"}
className="colorOption"> className="colorOption">
{chrome.i18n.getMessage("seekBarColor")} {chrome.i18n.getMessage("seekBarColor")}
</td> </th>
<td id={"CategoryPreviewColorOption"} <th id={"CategoryPreviewColorOption"}
className="previewColorOption"> className="previewColorOption">
{chrome.i18n.getMessage("previewColor")} {chrome.i18n.getMessage("previewColor")}
</td> </th>
</tr> </tr>
{this.getCategorySkipOptions()} {this.getCategorySkipOptions()}

View File

@@ -38,23 +38,23 @@ async function init() {
const optionsElements = optionsContainer.querySelectorAll("*"); const optionsElements = optionsContainer.querySelectorAll("*");
for (let i = 0; i < optionsElements.length; i++) { for (let i = 0; i < optionsElements.length; i++) {
if ((optionsElements[i].getAttribute("private-mode-only") === "true" && !(await isIncognitoAllowed())) if ((optionsElements[i].getAttribute("data-private-only") === "true" && !(await isIncognitoAllowed()))
|| (optionsElements[i].getAttribute("no-safari") === "true" && navigator.vendor === "Apple Computer, Inc.") || (optionsElements[i].getAttribute("data-no-safari") === "true" && navigator.vendor === "Apple Computer, Inc.")
|| (optionsElements[i].getAttribute("if-false") && Config.config[optionsElements[i].getAttribute("if-false")])) { || (optionsElements[i].getAttribute("data-dependent-on") && Config.config[optionsElements[i].getAttribute("data-dependent-on")])) {
optionsElements[i].classList.add("hidden"); optionsElements[i].classList.add("hidden");
continue; continue;
} }
const option = optionsElements[i].getAttribute("sync-option"); const option = optionsElements[i].getAttribute("data-sync");
switch (optionsElements[i].getAttribute("option-type")) { switch (optionsElements[i].getAttribute("data-type")) {
case "toggle": { case "toggle": {
const optionResult = Config.config[option]; const optionResult = Config.config[option];
const checkbox = optionsElements[i].querySelector("input"); const checkbox = optionsElements[i].querySelector("input");
const reverse = optionsElements[i].getAttribute("toggle-type") === "reverse"; const reverse = optionsElements[i].getAttribute("data-toggle-type") === "reverse";
const confirmMessage = optionsElements[i].getAttribute("confirm-message"); const confirmMessage = optionsElements[i].getAttribute("data-confirm-message");
if (optionResult != undefined) { if (optionResult != undefined) {
checkbox.checked = optionResult; checkbox.checked = optionResult;
@@ -91,7 +91,7 @@ async function init() {
// Enable the notice // Enable the notice
Config.config["dontShowNotice"] = false; Config.config["dontShowNotice"] = false;
const showNoticeSwitch = <HTMLInputElement> document.querySelector("[sync-option='dontShowNotice'] > label > label > input"); const showNoticeSwitch = <HTMLInputElement> document.querySelector("[data-sync='dontShowNotice'] > div > label > input");
showNoticeSwitch.checked = true; showNoticeSwitch.checked = true;
} }
@@ -154,7 +154,7 @@ async function init() {
const button = optionsElements[i].querySelector(".trigger-button"); const button = optionsElements[i].querySelector(".trigger-button");
button.addEventListener("click", () => activatePrivateTextChange(<HTMLElement> optionsElements[i])); button.addEventListener("click", () => activatePrivateTextChange(<HTMLElement> optionsElements[i]));
const privateTextChangeOption = optionsElements[i].getAttribute("sync-option"); const privateTextChangeOption = optionsElements[i].getAttribute("data-sync");
// See if anything extra must be done // See if anything extra must be done
switch (privateTextChangeOption) { switch (privateTextChangeOption) {
case "invidiousInstances": case "invidiousInstances":
@@ -166,7 +166,7 @@ async function init() {
case "button-press": { case "button-press": {
const actionButton = optionsElements[i].querySelector(".trigger-button"); const actionButton = optionsElements[i].querySelector(".trigger-button");
switch(optionsElements[i].getAttribute("sync-option")) { switch(optionsElements[i].getAttribute("data-sync")) {
case "copyDebugInformation": case "copyDebugInformation":
actionButton.addEventListener("click", copyDebugOutputToClipboard); actionButton.addEventListener("click", copyDebugOutputToClipboard);
break; break;
@@ -219,6 +219,18 @@ async function init() {
} }
} }
// Tab interaction
const tabElements = document.getElementsByClassName("tab-heading");
for (let i = 0; i < tabElements.length; i++) {
tabElements[i].addEventListener("click", () => {
document.querySelectorAll(".tab-heading").forEach(element => { element.classList.remove("selected"); });
optionsContainer.querySelectorAll(".option-group").forEach(element => { element.classList.add("hidden"); });
tabElements[i].classList.add("selected");
document.getElementById(tabElements[i].getAttribute("data-for")).classList.remove("hidden");
});
}
optionsContainer.classList.remove("hidden"); optionsContainer.classList.remove("hidden");
optionsContainer.classList.add("animated"); optionsContainer.classList.add("animated");
} }
@@ -233,7 +245,7 @@ function optionsConfigUpdateListener() {
const optionsElements = optionsContainer.querySelectorAll("*"); const optionsElements = optionsContainer.querySelectorAll("*");
for (let i = 0; i < optionsElements.length; i++) { for (let i = 0; i < optionsElements.length; i++) {
switch (optionsElements[i].getAttribute("option-type")) { switch (optionsElements[i].getAttribute("data-type")) {
case "display": case "display":
updateDisplayElement(<HTMLElement> optionsElements[i]) updateDisplayElement(<HTMLElement> optionsElements[i])
} }
@@ -246,7 +258,7 @@ function optionsConfigUpdateListener() {
* @param element * @param element
*/ */
function updateDisplayElement(element: HTMLElement) { function updateDisplayElement(element: HTMLElement) {
const displayOption = element.getAttribute("sync-option") const displayOption = element.getAttribute("data-sync")
const displayText = Config.config[displayOption]; const displayText = Config.config[displayOption];
element.innerText = displayText; element.innerText = displayText;
@@ -361,7 +373,7 @@ function activateKeybindChange(element: HTMLElement) {
button.classList.add("disabled"); button.classList.add("disabled");
const option = element.getAttribute("sync-option"); const option = element.getAttribute("data-sync");
const currentlySet = Config.config[option] !== null ? chrome.i18n.getMessage("keybindCurrentlySet") : ""; const currentlySet = Config.config[option] !== null ? chrome.i18n.getMessage("keybindCurrentlySet") : "";
@@ -393,7 +405,7 @@ function keybindKeyPressed(element: HTMLElement, e: KeyboardEvent) {
document.addEventListener("keydown", (e) => keybindKeyPressed(element, e), {once: true}); document.addEventListener("keydown", (e) => keybindKeyPressed(element, e), {once: true});
} else { } else {
const button: HTMLElement = element.querySelector(".trigger-button"); const button: HTMLElement = element.querySelector(".trigger-button");
const option = element.getAttribute("sync-option"); const option = element.getAttribute("data-sync");
// Make sure keybind isn't used by the other listener // Make sure keybind isn't used by the other listener
// TODO: If other keybindings are going to be added, we need a better way to find the other keys used. // TODO: If other keybindings are going to be added, we need a better way to find the other keys used.
@@ -447,7 +459,7 @@ function activatePrivateTextChange(element: HTMLElement) {
button.classList.add("disabled"); button.classList.add("disabled");
const textBox = <HTMLInputElement> element.querySelector(".option-text-box"); const textBox = <HTMLInputElement> element.querySelector(".option-text-box");
const option = element.getAttribute("sync-option"); const option = element.getAttribute("data-sync");
// See if anything extra must be done // See if anything extra must be done
switch (option) { switch (option) {
@@ -475,7 +487,7 @@ function activatePrivateTextChange(element: HTMLElement) {
const setButton = element.querySelector(".text-change-set"); const setButton = element.querySelector(".text-change-set");
setButton.addEventListener("click", async () => { setButton.addEventListener("click", async () => {
const confirmMessage = element.getAttribute("confirm-message"); const confirmMessage = element.getAttribute("data-confirm-message");
if (confirmMessage === null || confirm(chrome.i18n.getMessage(confirmMessage))) { if (confirmMessage === null || confirm(chrome.i18n.getMessage(confirmMessage))) {
@@ -490,7 +502,7 @@ function activatePrivateTextChange(element: HTMLElement) {
Config.convertJSON(); Config.convertJSON();
if (newConfig.supportInvidious) { if (newConfig.supportInvidious) {
const checkbox = <HTMLInputElement> document.querySelector("#support-invidious > label > label > input"); const checkbox = <HTMLInputElement> document.querySelector("#support-invidious > div > label > input");
checkbox.checked = true; checkbox.checked = true;
await invidiousOnClick(checkbox, "supportInvidious"); await invidiousOnClick(checkbox, "supportInvidious");