Ver código fonte

feat: configurable toast duration & png icon support

Sv443 11 meses atrás
pai
commit
468298e380

+ 30 - 23
assets/translations/README.md

@@ -16,15 +16,15 @@ To submit or edit a translation, please follow [this guide](../../contributing.m
 ### Translation progress:
 |   | Locale | Translated keys | Based on |
 | :----: | ------ | --------------- | :------: |
-| ─ | [`en_US`](./en_US.json) | 242 (default locale) |  |
-| ‼️ | [`de_DE`](./de_DE.json) | `213/242` (88%) | ─ |
-| ─ | [`en_UK`](./en_UK.json) | `242/242` (100%) | `en_US` |
-| ‼️ | [`es_ES`](./es_ES.json) | `213/242` (88%) | ─ |
-| ‼️ | [`fr_FR`](./fr_FR.json) | `213/242` (88%) | ─ |
-| ‼️ | [`hi_IN`](./hi_IN.json) | `213/242` (88%) | ─ |
-| ‼️ | [`ja_JA`](./ja_JA.json) | `213/242` (88%) | ─ |
-| ‼️ | [`pt_BR`](./pt_BR.json) | `213/242` (88%) | ─ |
-| ‼️ | [`zh_CN`](./zh_CN.json) | `213/242` (88%) | ─ |
+| ─ | [`en_US`](./en_US.json) | 243 (default locale) |  |
+| ‼️ | [`de_DE`](./de_DE.json) | `213/243` (87.7%) | ─ |
+| ─ | [`en_UK`](./en_UK.json) | `243/243` (100%) | `en_US` |
+| ‼️ | [`es_ES`](./es_ES.json) | `213/243` (87.7%) | ─ |
+| ‼️ | [`fr_FR`](./fr_FR.json) | `213/243` (87.7%) | ─ |
+| ‼️ | [`hi_IN`](./hi_IN.json) | `213/243` (87.7%) | ─ |
+| ‼️ | [`ja_JA`](./ja_JA.json) | `213/243` (87.7%) | ─ |
+| ‼️ | [`pt_BR`](./pt_BR.json) | `213/243` (87.7%) | ─ |
+| ‼️ | [`zh_CN`](./zh_CN.json) | `213/243` (87.7%) | ─ |
 
 <sub>
 ✅ - Fully translated
@@ -45,7 +45,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 ### Missing keys:
 
-<details><summary><code>de_DE</code> - 29 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>de_DE</code> - 30 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -71,8 +71,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `feature_desc_autoLikeOpenMgmtDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_autoLikeOpenMgmtDialog` | `Open dialog` |
 | `feature_btn_autoLikeOpenMgmtDialog_running` | `Opening...` |
-| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_desc_initTimeout` | `How many seconds to wait for features to initialize before considering them to likely be in an errored state` |
 | `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
+| `feature_desc_toastDuration` | `For how many seconds custom toast notifications should be shown - 0 to disable them entirely` |
 | `feature_desc_resetConfig` | `Reset all settings to their default values` |
 | `feature_btn_resetConfig` | `Reset settings` |
 | `feature_btn_resetConfig_running` | `Confirming...` |
@@ -81,7 +82,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>es_ES</code> - 29 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>es_ES</code> - 30 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -107,8 +108,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `feature_desc_autoLikeOpenMgmtDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_autoLikeOpenMgmtDialog` | `Open dialog` |
 | `feature_btn_autoLikeOpenMgmtDialog_running` | `Opening...` |
-| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_desc_initTimeout` | `How many seconds to wait for features to initialize before considering them to likely be in an errored state` |
 | `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
+| `feature_desc_toastDuration` | `For how many seconds custom toast notifications should be shown - 0 to disable them entirely` |
 | `feature_desc_resetConfig` | `Reset all settings to their default values` |
 | `feature_btn_resetConfig` | `Reset settings` |
 | `feature_btn_resetConfig_running` | `Confirming...` |
@@ -117,7 +119,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>fr_FR</code> - 29 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>fr_FR</code> - 30 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -143,8 +145,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `feature_desc_autoLikeOpenMgmtDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_autoLikeOpenMgmtDialog` | `Open dialog` |
 | `feature_btn_autoLikeOpenMgmtDialog_running` | `Opening...` |
-| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_desc_initTimeout` | `How many seconds to wait for features to initialize before considering them to likely be in an errored state` |
 | `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
+| `feature_desc_toastDuration` | `For how many seconds custom toast notifications should be shown - 0 to disable them entirely` |
 | `feature_desc_resetConfig` | `Reset all settings to their default values` |
 | `feature_btn_resetConfig` | `Reset settings` |
 | `feature_btn_resetConfig_running` | `Confirming...` |
@@ -153,7 +156,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>hi_IN</code> - 29 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>hi_IN</code> - 30 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -179,8 +182,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `feature_desc_autoLikeOpenMgmtDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_autoLikeOpenMgmtDialog` | `Open dialog` |
 | `feature_btn_autoLikeOpenMgmtDialog_running` | `Opening...` |
-| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_desc_initTimeout` | `How many seconds to wait for features to initialize before considering them to likely be in an errored state` |
 | `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
+| `feature_desc_toastDuration` | `For how many seconds custom toast notifications should be shown - 0 to disable them entirely` |
 | `feature_desc_resetConfig` | `Reset all settings to their default values` |
 | `feature_btn_resetConfig` | `Reset settings` |
 | `feature_btn_resetConfig_running` | `Confirming...` |
@@ -189,7 +193,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>ja_JA</code> - 29 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>ja_JA</code> - 30 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -215,8 +219,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `feature_desc_autoLikeOpenMgmtDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_autoLikeOpenMgmtDialog` | `Open dialog` |
 | `feature_btn_autoLikeOpenMgmtDialog_running` | `Opening...` |
-| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_desc_initTimeout` | `How many seconds to wait for features to initialize before considering them to likely be in an errored state` |
 | `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
+| `feature_desc_toastDuration` | `For how many seconds custom toast notifications should be shown - 0 to disable them entirely` |
 | `feature_desc_resetConfig` | `Reset all settings to their default values` |
 | `feature_btn_resetConfig` | `Reset settings` |
 | `feature_btn_resetConfig_running` | `Confirming...` |
@@ -225,7 +230,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>pt_BR</code> - 29 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>pt_BR</code> - 30 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -251,8 +256,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `feature_desc_autoLikeOpenMgmtDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_autoLikeOpenMgmtDialog` | `Open dialog` |
 | `feature_btn_autoLikeOpenMgmtDialog_running` | `Opening...` |
-| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_desc_initTimeout` | `How many seconds to wait for features to initialize before considering them to likely be in an errored state` |
 | `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
+| `feature_desc_toastDuration` | `For how many seconds custom toast notifications should be shown - 0 to disable them entirely` |
 | `feature_desc_resetConfig` | `Reset all settings to their default values` |
 | `feature_btn_resetConfig` | `Reset settings` |
 | `feature_btn_resetConfig_running` | `Confirming...` |
@@ -261,7 +267,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>zh_CN</code> - 29 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>zh_CN</code> - 30 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -287,8 +293,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `feature_desc_autoLikeOpenMgmtDialog` | `Open the dialog to manage auto-liked channels` |
 | `feature_btn_autoLikeOpenMgmtDialog` | `Open dialog` |
 | `feature_btn_autoLikeOpenMgmtDialog_running` | `Opening...` |
-| `feature_desc_initTimeout` | `How long to wait for features to initialize before considering them to likely be in an errored state` |
+| `feature_desc_initTimeout` | `How many seconds to wait for features to initialize before considering them to likely be in an errored state` |
 | `feature_helptext_initTimeout` | `This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.` |
+| `feature_desc_toastDuration` | `For how many seconds custom toast notifications should be shown - 0 to disable them entirely` |
 | `feature_desc_resetConfig` | `Reset all settings to their default values` |
 | `feature_btn_resetConfig` | `Reset settings` |
 | `feature_btn_resetConfig_running` | `Confirming...` |

+ 2 - 1
assets/translations/en_US.json

@@ -250,8 +250,9 @@
     "feature_btn_checkVersionNow_running": "Checking...",
     "feature_desc_logLevel": "How much information to log to the console",
     "feature_helptext_logLevel": "Changing this is really only needed for debugging purposes as a result of experiencing a problem.\nShould you have one, you can increase the log level here, open your browser's JavaScript console (usually with Ctrl + Shift + K) and attach screenshots of that log in a GitHub issue.",
-    "feature_desc_initTimeout": "How long to wait for features to initialize before considering them to likely be in an errored state",
+    "feature_desc_initTimeout": "How many seconds to wait for features to initialize before considering them to likely be in an errored state",
     "feature_helptext_initTimeout": "This is the amount of time in milliseconds that the script will wait for features to initialize before considering them to likely be in an errored state.\nThis will not affect the script's behavior in a significant way, but if one of your plugins can't initialize in time, you should try increasing this value.",
+    "feature_desc_toastDuration": "For how many seconds custom toast notifications should be shown - 0 to disable them entirely",
     "feature_desc_resetConfig": "Reset all settings to their default values",
     "feature_btn_resetConfig": "Reset settings",
     "feature_btn_resetConfig_running": "Confirming...",

+ 7 - 2
src/components/toast.css

@@ -12,9 +12,9 @@
   z-index: 1042069;
   opacity: 0.000001;
   pointer-events: none;
-  padding: 10px 20px;
+  padding: 10px 16px;
   border-radius: 3px;
-  font-size: 14px;
+  font-size: 1.5rem;
 
   background-color: var(--bytm-toast-bg-color);
   color: var(--bytm-toast-text-color);
@@ -65,3 +65,8 @@
   align-items: center;
   gap: 10px;
 }
+
+.bytm-toast-icon.img {
+  width: 24px;
+  height: 24px;
+}

+ 39 - 17
src/components/toast.ts

@@ -1,5 +1,6 @@
 import { pauseFor } from "@sv443-network/userutils";
-import { resourceToHTMLString } from "../utils";
+import { info, resourceToHTMLString } from "../utils";
+import { getFeature } from "../config";
 import type { ResourceKey } from "../types";
 import "./toast.css";
 
@@ -18,27 +19,42 @@ type ToastProps = {
   }
 );
 
-type IconToastProps = ToastProps & {
-  icon: ResourceKey;
-};
+type IconToastProps = ToastProps & (
+  | {
+    icon: ResourceKey;
+  }
+  | {
+    iconSrc: string | Promise<string>;
+  }
+);
 
 let timeout: NodeJS.Timeout | undefined;
 
 /** Shows a toast message with an icon */
 export async function showIconToast({
-  icon,
-  duration = 3000,
+  duration = getFeature("toastDuration"),
   position = "tr",
   ...rest
 }: IconToastProps) {
+  if(duration <= 0)
+    return info("Toast duration is <= 0, so it won't be shown");
   const toastWrapper = document.createElement("div");
   toastWrapper.classList.add("bytm-toast-flex-wrapper");
 
-  const toastIcon = document.createElement("div");
-  toastIcon.classList.add("bytm-toast-icon");
-  const iconHtml = await resourceToHTMLString(icon);
-  if(iconHtml)
-    toastIcon.innerHTML = iconHtml;
+  if("iconSrc" in rest) {
+    const toastIcon = document.createElement("img");
+    toastIcon.classList.add("bytm-toast-icon", "img");
+    toastIcon.src = rest.iconSrc instanceof Promise ? await rest.iconSrc : rest.iconSrc;
+    toastWrapper.appendChild(toastIcon);
+  }
+  else {
+    const toastIcon = document.createElement("div");
+    toastIcon.classList.add("bytm-toast-icon");
+    const iconHtml = await resourceToHTMLString(rest.icon);
+    if(iconHtml)
+      toastIcon.innerHTML = iconHtml;
+    toastWrapper.appendChild(toastIcon);
+  }
 
   const toastMessage = document.createElement("div");
   toastMessage.classList.add("bytm-toast-message");
@@ -47,7 +63,6 @@ export async function showIconToast({
   else
     toastMessage.appendChild(rest.element);
 
-  toastWrapper.appendChild(toastIcon);
   toastWrapper.appendChild(toastMessage);
 
   await showToast({
@@ -60,10 +75,12 @@ export async function showIconToast({
 
 /** Shows a toast message in the bottom left corner of the screen by default */
 export async function showToast({
-  duration = 3000,
+  duration = getFeature("toastDuration"),
   position = "tr",
   ...rest
 }: ToastProps) {
+  if(duration <= 0)
+    return info("Toast duration is <= 0, so it won't be shown");
   const toastEl = document.querySelector("#bytm-toast");
   if(toastEl)
     await closeToast();
@@ -71,7 +88,7 @@ export async function showToast({
   const toastElem = document.createElement("div");
   toastElem.id = "bytm-toast";
   toastElem.role = "alert";
-  toastElem.ariaLive = "assertive";
+  toastElem.ariaLive = "polite";
   toastElem.ariaAtomic = "true";
 
   toastElem.addEventListener("click", async () => await closeToast(), { once: true });
@@ -94,12 +111,17 @@ export async function showToast({
 
 /** Closes the currently open toast */
 export async function closeToast() {
-  const toastEl = document.querySelector("#bytm-toast");
   timeout && clearTimeout(timeout);
-  if(toastEl) {
+
+  const toastEls = document.querySelectorAll("#bytm-toast");
+  if(toastEls.length === 0)
+    return;
+
+  await Promise.allSettled(Array.from(toastEls).map(async (toastEl) => {
     toastEl.classList.remove("visible");
 
     await pauseFor(300);
     toastEl.remove();
-  }
+    await pauseFor(100);
+  }));
 }

+ 1 - 1
src/config.ts

@@ -73,7 +73,7 @@ export const migrations: DataMigrationsDict = {
       "autoLikeChannels", "autoLikeChannelToggleBtn",
       "autoLikePlayerBarToggleBtn", "autoLikeTimeout",
       "autoLikeShowToast", "autoLikeOpenMgmtDialog",
-      "toastTimeout", "initTimeout",
+      "toastDuration", "initTimeout",
     ]), [
       { key: "rememberSongTimeSites", oldDefault: "ytm" },
       { key: "volumeSliderScrollStep", oldDefault: 10 },

+ 4 - 2
src/features/index.ts

@@ -619,7 +619,7 @@ export const featInfo = {
     advanced: true,
     textAdornment: () => combineAdornments([adornments.advanced, adornments.reloadRequired]),
   },
-  toastTimeout: {
+  toastDuration: {
     type: "slider",
     category: "general",
     min: 0,
@@ -628,9 +628,11 @@ export const featInfo = {
     step: 0.5,
     unit: "s",
     reloadRequired: false,
+    advanced: true,
+    textAdornment: adornments.advanced,
     enable: noop,
     change: () => showIconToast({
-      duration: getFeatures().toastTimeout * 1000,
+      duration: getFeatures().toastDuration * 1000,
       message: "Example",
       iconSrc: getResourceUrl(`img-logo${mode === "development" ? "_dev" : ""}`),
     }),

+ 2 - 0
src/types.ts

@@ -460,6 +460,8 @@ export interface FeatureConfig {
   logLevel: LogLevel;
   /** Amount of seconds until the feature initialization times out */
   initTimeout: number;
+  /** Amount of seconds to show BYTM's toasts for */
+  toastDuration: number;
   /** Button that resets the config to the default state */
   resetConfig: undefined;
   /** Whether to show advanced settings in the config menu */