Преглед на файлове

feat: toast improvements

Sv443 преди 7 месеца
родител
ревизия
c73c18dac7
променени са 9 файла, в които са добавени 122 реда и са изтрити 62 реда
  1. 37 23
      assets/translations/README.md
  2. 3 1
      assets/translations/en_US.json
  3. 24 14
      contributing.md
  4. 6 0
      dist/BetterYTM.css
  5. 6 0
      src/components/toast.css
  6. 10 1
      src/components/toast.ts
  7. 9 5
      src/config.ts
  8. 22 16
      src/features/index.ts
  9. 5 2
      src/utils/logging.ts

+ 37 - 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) | 294 (default locale) |  |
-| ‼️ | [`de_DE`](./de_DE.json) | `202/294` (68.7%) | ─ |
-| ─ | [`en_UK`](./en_UK.json) | `294` (100%) | `en_US` |
-| ‼️ | [`es_ES`](./es_ES.json) | `202/294` (68.7%) | ─ |
-| ‼️ | [`fr_FR`](./fr_FR.json) | `202/294` (68.7%) | ─ |
-| ‼️ | [`hi_IN`](./hi_IN.json) | `202/294` (68.7%) | ─ |
-| ‼️ | [`ja_JA`](./ja_JA.json) | `202/294` (68.7%) | ─ |
-| ‼️ | [`pt_BR`](./pt_BR.json) | `202/294` (68.7%) | ─ |
-| ‼️ | [`zh_CN`](./zh_CN.json) | `202/294` (68.7%) | ─ |
+| ─ | [`en_US`](./en_US.json) | 296 (default locale) |  |
+| ‼️ | [`de_DE`](./de_DE.json) | `202/296` (68.2%) | ─ |
+| ─ | [`en_UK`](./en_UK.json) | `296` (100%) | `en_US` |
+| ‼️ | [`es_ES`](./es_ES.json) | `202/296` (68.2%) | ─ |
+| ‼️ | [`fr_FR`](./fr_FR.json) | `202/296` (68.2%) | ─ |
+| ‼️ | [`hi_IN`](./hi_IN.json) | `202/296` (68.2%) | ─ |
+| ‼️ | [`ja_JA`](./ja_JA.json) | `202/296` (68.2%) | ─ |
+| ‼️ | [`pt_BR`](./pt_BR.json) | `202/296` (68.2%) | ─ |
+| ‼️ | [`zh_CN`](./zh_CN.json) | `202/296` (68.2%) | ─ |
 
 <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> - 92 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>de_DE</code> - 94 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -67,7 +67,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `new_entry_tooltip` | `Click to create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
-| `generic_error_toast` | `Encountered %1` |
+| `example_toast` | `Example Toast` |
+| `generic_error_toast_encountered_error_type` | `Encountered %1` |
+| `generic_error_toast_click_for_details` | `Click for details` |
 | `error` | `Error` |
 | `generic_error_dialog_message` | `Encountered an error.` |
 | `generic_error_dialog_open_console_note` | `Please open the JavaScript console (usually with Ctrl + Shift + K) and attach a screenshot of the error starting with "BetterYTM" to a [GitHub issue.](%1)` |
@@ -144,7 +146,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>es_ES</code> - 92 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>es_ES</code> - 94 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -166,7 +168,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `new_entry_tooltip` | `Click to create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
-| `generic_error_toast` | `Encountered %1` |
+| `example_toast` | `Example Toast` |
+| `generic_error_toast_encountered_error_type` | `Encountered %1` |
+| `generic_error_toast_click_for_details` | `Click for details` |
 | `error` | `Error` |
 | `generic_error_dialog_message` | `Encountered an error.` |
 | `generic_error_dialog_open_console_note` | `Please open the JavaScript console (usually with Ctrl + Shift + K) and attach a screenshot of the error starting with "BetterYTM" to a [GitHub issue.](%1)` |
@@ -243,7 +247,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>fr_FR</code> - 92 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>fr_FR</code> - 94 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -265,7 +269,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `new_entry_tooltip` | `Click to create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
-| `generic_error_toast` | `Encountered %1` |
+| `example_toast` | `Example Toast` |
+| `generic_error_toast_encountered_error_type` | `Encountered %1` |
+| `generic_error_toast_click_for_details` | `Click for details` |
 | `error` | `Error` |
 | `generic_error_dialog_message` | `Encountered an error.` |
 | `generic_error_dialog_open_console_note` | `Please open the JavaScript console (usually with Ctrl + Shift + K) and attach a screenshot of the error starting with "BetterYTM" to a [GitHub issue.](%1)` |
@@ -342,7 +348,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>hi_IN</code> - 92 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>hi_IN</code> - 94 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -364,7 +370,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `new_entry_tooltip` | `Click to create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
-| `generic_error_toast` | `Encountered %1` |
+| `example_toast` | `Example Toast` |
+| `generic_error_toast_encountered_error_type` | `Encountered %1` |
+| `generic_error_toast_click_for_details` | `Click for details` |
 | `error` | `Error` |
 | `generic_error_dialog_message` | `Encountered an error.` |
 | `generic_error_dialog_open_console_note` | `Please open the JavaScript console (usually with Ctrl + Shift + K) and attach a screenshot of the error starting with "BetterYTM" to a [GitHub issue.](%1)` |
@@ -441,7 +449,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>ja_JA</code> - 92 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>ja_JA</code> - 94 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -463,7 +471,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `new_entry_tooltip` | `Click to create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
-| `generic_error_toast` | `Encountered %1` |
+| `example_toast` | `Example Toast` |
+| `generic_error_toast_encountered_error_type` | `Encountered %1` |
+| `generic_error_toast_click_for_details` | `Click for details` |
 | `error` | `Error` |
 | `generic_error_dialog_message` | `Encountered an error.` |
 | `generic_error_dialog_open_console_note` | `Please open the JavaScript console (usually with Ctrl + Shift + K) and attach a screenshot of the error starting with "BetterYTM" to a [GitHub issue.](%1)` |
@@ -540,7 +550,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>pt_BR</code> - 92 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>pt_BR</code> - 94 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -562,7 +572,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `new_entry_tooltip` | `Click to create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
-| `generic_error_toast` | `Encountered %1` |
+| `example_toast` | `Example Toast` |
+| `generic_error_toast_encountered_error_type` | `Encountered %1` |
+| `generic_error_toast_click_for_details` | `Click for details` |
 | `error` | `Error` |
 | `generic_error_dialog_message` | `Encountered an error.` |
 | `generic_error_dialog_open_console_note` | `Please open the JavaScript console (usually with Ctrl + Shift + K) and attach a screenshot of the error starting with "BetterYTM" to a [GitHub issue.](%1)` |
@@ -639,7 +651,7 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>zh_CN</code> - 92 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>zh_CN</code> - 94 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
@@ -661,7 +673,9 @@ This means to figure out which keys are untranslated, you will need to manually
 | `new_entry_tooltip` | `Click to create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
-| `generic_error_toast` | `Encountered %1` |
+| `example_toast` | `Example Toast` |
+| `generic_error_toast_encountered_error_type` | `Encountered %1` |
+| `generic_error_toast_click_for_details` | `Click for details` |
 | `error` | `Error` |
 | `generic_error_dialog_message` | `Encountered an error.` |
 | `generic_error_dialog_open_console_note` | `Please open the JavaScript console (usually with Ctrl + Shift + K) and attach a screenshot of the error starting with "BetterYTM" to a [GitHub issue.](%1)` |

+ 3 - 1
assets/translations/en_US.json

@@ -72,7 +72,9 @@
     "volume_tooltip": "Volume: %1% (Sensitivity: %2%)",
     "volume_shared_tooltip": "Volume level is shared between tabs - disable in the configuration menu",
     "middle_click_open_tab": "Middle-click to open in a new tab",
-    "generic_error_toast": "Encountered %1",
+    "example_toast": "Example Toast",
+    "generic_error_toast_encountered_error_type": "Encountered %1",
+    "generic_error_toast_click_for_details": "Click for details",
     "error": "Error",
     "generic_error_dialog_message": "Encountered an error.",
     "generic_error_dialog_open_console_note": "Please open the JavaScript console (usually with Ctrl + Shift + K) and attach a screenshot of the error starting with \"BetterYTM\" to a [GitHub issue.](%1)",

+ 24 - 14
contributing.md

@@ -1830,11 +1830,16 @@ Functions marked with 🔒 need to be passed a per-session and per-plugin authen
 > If the second overload is used, the duration will default to the value of the `toastDuration` option in the feature config.  
 >   
 > Properties for first overload:
-> - either of:
->   - `message: string` - The message to show in the toast
->   - `element: HTMLElement` and `title: string` - The element to show in the toast and the hover and accessibility title of the toast
-> - `duration?: number` - Duration in milliseconds to show the toast for (defaults to what is set in the feature config) - use `Infinity` for a persistent toast and `0` to not show it at all
-> - `position?: "tl" | "tr" | "bl" | "br"` - Which corner of the screen the toast should show up in (defaults to "tr")
+> - either:
+>   - for showing a string:
+>     - `message: string` - The message to show in the toast
+>     - `subtitle?: string` - An optional subtitle to show below the message
+>   - for showing a generic element:
+>     - `element: HTMLElement` - The element to show in the toast
+>     - `title: string` - The hover and accessibility title of the toast
+> - and any of:
+>   - `duration?: number` - Duration in milliseconds to show the toast for (defaults to what is set in the feature config) - use `Infinity` for a persistent toast and `0` to not show it at all
+>   - `position?: ToastPos` - Corner position of the toast on the screen. Can be `"tl"`, `"tr"`, `"bl"` or `"br"` (defaults to `"tr"`)
 > 
 > <details><summary><b>Example <i>(click to expand)</i></b></summary>
 > 
@@ -1859,17 +1864,22 @@ Functions marked with 🔒 need to be passed a per-session and per-plugin authen
 > If a toast is already shown, it will be immediately closed and the new one will be shown shortly afterwards.  
 >   
 > Properties:
-> - either of:
->   - `message: string` - The message to show in the toast
->   - `element: HTMLElement` and `title: string` - The element to show in the toast and the hover and accessibility title of the toast
-> - either of:
->   - `iconSrc: string | Promise<string>` - URL of the image to use as the icon
->   - or:
->     - `icon: string` - An SVG resource name starting with `icon-` to use as the icon (see [`assets/resources.json`](assets/resources.json))
+> - either:
+>   - for showing a string:
+>     - `message: string` - The message to show in the toast
+>     - `subtitle?: string` - An optional subtitle to show below the message
+>   - for showing a generic element:
+>     - `element: HTMLElement` - The element to show in the toast
+>     - `title: string` - The hover and accessibility title of the toast
+> - and either:
+>   - for using an &lt;img&gt; with a URL:
+>     - `iconSrc: string | Promise<string>` - URL to the image file to use as the icon
+>   - or when using a BYTM SVG resource:
+>     - `icon: string` - Any SVG resource name (has to start with `icon-`!) to use as the icon (see [`assets/resources.json`](assets/resources.json))
 >     - `iconFill?: string` - CSS color value to set the icon's &lt;path&gt; elements' `fill` property to
-> - any or none of:
+> - and any of:
 >   - `duration?: number` - Duration in milliseconds to show the toast for (defaults to what is set in the feature config)
->   - `position?: "tl" | "tr" | "bl" | "br"` - Position of the toast on the screen. Can be "tl", "tr", "bl" or "br" (defaults to "tr")
+>   - `position?: ToastPos` - Corner position of the toast on the screen. Can be `"tl"`, `"tr"`, `"bl"` or `"br"` (defaults to `"tr"`)
 > 
 > <details><summary><b>Example <i>(click to expand)</i></b></summary>
 > 

+ 6 - 0
dist/BetterYTM.css

@@ -792,6 +792,12 @@ body .bytm-ripple.slower {
   fill: var(--toast-icon-fill, #fff);
 }
 
+.bytm-toast-subtitle {
+  color: #ccc;
+  font-size: 1.2rem;
+  font-weight: 400;
+}
+
 .bytm-toggle-input-wrapper {
   --toggle-height: 20px;
   --toggle-width: 40px;

+ 6 - 0
src/components/toast.css

@@ -80,3 +80,9 @@
 .bytm-toast-icon path {
   fill: var(--toast-icon-fill, #fff);
 }
+
+.bytm-toast-subtitle {
+  color: #ccc;
+  font-size: 1.2rem;
+  font-weight: 400;
+}

+ 10 - 1
src/components/toast.ts

@@ -17,6 +17,8 @@ export type ToastProps = {
   | {
     /** Message (plus title) for the toast */
     message: string;
+    /** Optional subtitle for the toast */
+    subtitle?: string;
   }
   | {
     /** Element to be shown in the toast */
@@ -82,8 +84,15 @@ export async function showIconToast({
 
   const toastMessage = document.createElement("div");
   toastMessage.classList.add("bytm-toast-message");
-  if("message" in rest)
+  if("message" in rest) {
     toastMessage.textContent = rest.message;
+    if("subtitle" in rest && rest.subtitle) {
+      const subtitleEl = document.createElement("div");
+      subtitleEl.classList.add("bytm-toast-subtitle");
+      subtitleEl.textContent = rest.subtitle;
+      toastMessage.appendChild(subtitleEl);
+    }
+  }
   else
     toastMessage.appendChild(rest.element);
 

+ 9 - 5
src/config.ts

@@ -83,7 +83,7 @@ export const migrations: DataMigrationsDict = {
       ]), [
         { key: "rememberSongTimeSites", oldDefault: "ytm" },
         { key: "volumeSliderScrollStep", oldDefault: 10 },
-      ],
+      ]
     );
     "removeUpgradeTab" in newData && delete newData.removeUpgradeTab;
     "advancedLyricsFilter" in newData && delete newData.advancedLyricsFilter;
@@ -94,10 +94,14 @@ export const migrations: DataMigrationsDict = {
   // TODO(v2.2): set autoLikeChannels to true on migration once feature is fully implemented
 
   // 6 -> 7 (v2.2)
-  7: (oldData: FeatureConfig) => useDefaultConfig(oldData, [
-    "showToastOnGenericError", "sponsorBlockIntegration",
-    "themeSongIntegration", "themeSongLightness",
-  ]),
+  7: (oldData: FeatureConfig) => useNewDefaultIfUnchanged(
+    useDefaultConfig(oldData, [
+      "showToastOnGenericError", "sponsorBlockIntegration",
+      "themeSongIntegration", "themeSongLightness",
+    ]), [
+      { key: "toastDuration", oldDefault: 3 },
+    ]
+  ),
 } as const satisfies DataMigrationsDict;
 
 /** Uses the default config as the base, then overwrites all values with the passed {@linkcode baseData}, then sets all passed {@linkcode resetKeys} to their default values */

+ 22 - 16
src/features/index.ts

@@ -9,6 +9,8 @@ import { getAutoLikeDialog } from "../dialogs/index.js";
 import { showIconToast } from "../components/index.js";
 import { mode } from "../constants.js";
 
+//#region re-exports
+
 export * from "./layout.js";
 export * from "./behavior.js";
 export * from "./input.js";
@@ -19,17 +21,12 @@ export * from "./songLists.js";
 export * from "./versionCheck.js";
 export * from "./volume.js";
 
-interface SelectOption<TValue = number | string> {
-  value: TValue;
-  label: string;
-}
+//#region adornments
 
 type AdornmentFunc =
   | ((...args: any[]) => Promise<string | undefined>)
   | Promise<string | undefined>;
 
-//#region dependencies
-
 /** Decoration elements that can be added next to the label */
 const adornments = {
   advanced: async () => getAdornHtml("bytm-advanced-mode-icon", t("advanced_mode"), "icon-advanced_mode"),
@@ -74,6 +71,13 @@ const combineAdornments = (
   }
 );
 
+//#region select options
+
+interface SelectOption<TValue = number | string> {
+  value: TValue;
+  label: string;
+}
+
 /** Common options for config items of type "select" */
 const options = {
   siteSelection: (): SelectOption<SiteSelection>[] => [
@@ -102,6 +106,8 @@ const options = {
   ],
 };
 
+//#region rendering
+
 /** Renders a long number with a thousands separator */
 function renderLongNumberValue(val: string, maximumFractionDigits = 0) {
   return Number(val).toLocaleString(
@@ -152,7 +158,7 @@ function renderLongNumberValue(val: string, maximumFractionDigits = 0) {
  * TODO: go through all features and set as many as possible to reloadRequired = false
  */
 export const featInfo = {
-  //#region layout
+  //#region cat:layout
   watermarkEnabled: {
     type: "toggle",
     category: "layout",
@@ -286,7 +292,7 @@ export const featInfo = {
   //   textAdornment: adornments.reloadRequired,
   // },
 
-  //#region volume
+  //#region cat:volume
   volumeSliderLabel: {
     type: "toggle",
     category: "volume",
@@ -350,7 +356,7 @@ export const featInfo = {
     enable: noop,
   },
 
-  //#region song lists
+  //#region cat:song lists
   lyricsQueueButton: {
     type: "toggle",
     category: "songLists",
@@ -387,7 +393,7 @@ export const featInfo = {
     textAdornment: adornments.reloadRequired,
   },
 
-  //#region behavior
+  //#region cat:behavior
   disableBeforeUnloadPopup: {
     type: "toggle",
     category: "behavior",
@@ -459,7 +465,7 @@ export const featInfo = {
     enable: noop,
   },
 
-  //#region input
+  //#region cat:input
   arrowKeySupport: {
     type: "toggle",
     category: "input",
@@ -560,7 +566,7 @@ export const featInfo = {
     click: () => getAutoLikeDialog().then(d => d.open()),
   },
 
-  //#region lyrics
+  //#region cat:lyrics
   geniusLyrics: {
     type: "toggle",
     category: "lyrics",
@@ -638,7 +644,7 @@ export const featInfo = {
   //   enable: noop,
   // },
 
-  //#region integrations
+  //#region cat:integrations
   disableDarkReaderSites: {
     type: "select",
     category: "integrations",
@@ -667,7 +673,7 @@ export const featInfo = {
     textAdornment: adornments.reloadRequired,
   },
 
-  //#region general
+  //#region cat:general
   locale: {
     type: "select",
     category: "general",
@@ -719,7 +725,7 @@ export const featInfo = {
     category: "general",
     min: 0,
     max: 15,
-    default: 3,
+    default: 4,
     step: 0.5,
     unit: "s",
     reloadRequired: false,
@@ -727,7 +733,7 @@ export const featInfo = {
     textAdornment: adornments.advanced,
     enable: noop,
     change: () => showIconToast({
-      message: "Example",
+      message: t("example_toast"),
       iconSrc: getResourceUrl(`img-logo${mode === "development" ? "_dev" : ""}`),
     }),
   },

+ 5 - 2
src/utils/logging.ts

@@ -72,7 +72,9 @@ function getErrorDialog(errName: string, args: unknown[]) {
       header.textContent = header.ariaLabel = errName;
       return header;
     },
-    body: `${args.length > 0 ? args.join(" ") : t("generic_error_dialog_message")}\n\n${t("generic_error_dialog_open_console_note", packageJson.bugs.url)}`,
+    body: `\
+${args.length > 0 ? args.join(" ") : t("generic_error_dialog_message")}  
+${t("generic_error_dialog_open_console_note", packageJson.bugs.url)}`,
   });
 }
 
@@ -83,7 +85,8 @@ export function error(...args: unknown[]): void {
   if(getFeature("showToastOnGenericError")) {
     const errName = args.find(a => a instanceof Error)?.name ?? t("error");
     debounce(() => showIconToast({
-      message: t("generic_error_toast", errName),
+      message: t("generic_error_toast_encountered_error_type", errName),
+      subtitle: t("generic_error_toast_click_for_details"),
       icon: "icon-error",
       iconFill: "var(--bytm-error-col)",
       onClick: () => getErrorDialog(errName, Array.isArray(args) ? args : []).open(),