Explorar o código

feat: autoLike export dialog stuff

Sv443 hai 10 meses
pai
achega
18f6d7c88d

+ 30 - 16
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) | 259 (default locale) |  |
-| ‼️ | [`de_DE`](./de_DE.json) | `210/259` (81.1%) | ─ |
-| ─ | [`en_UK`](./en_UK.json) | `259` (100%) | `en_US` |
-| ‼️ | [`es_ES`](./es_ES.json) | `210/259` (81.1%) | ─ |
-| ‼️ | [`fr_FR`](./fr_FR.json) | `210/259` (81.1%) | ─ |
-| ‼️ | [`hi_IN`](./hi_IN.json) | `210/259` (81.1%) | ─ |
-| ‼️ | [`ja_JA`](./ja_JA.json) | `210/259` (81.1%) | ─ |
-| ‼️ | [`pt_BR`](./pt_BR.json) | `210/259` (81.1%) | ─ |
-| ‼️ | [`zh_CN`](./zh_CN.json) | `210/259` (81.1%) | ─ |
+| ─ | [`en_US`](./en_US.json) | 261 (default locale) |  |
+| ‼️ | [`de_DE`](./de_DE.json) | `210/261` (80.5%) | ─ |
+| ─ | [`en_UK`](./en_UK.json) | `261` (100%) | `en_US` |
+| ‼️ | [`es_ES`](./es_ES.json) | `210/261` (80.5%) | ─ |
+| ‼️ | [`fr_FR`](./fr_FR.json) | `210/261` (80.5%) | ─ |
+| ‼️ | [`hi_IN`](./hi_IN.json) | `210/261` (80.5%) | ─ |
+| ‼️ | [`ja_JA`](./ja_JA.json) | `210/261` (80.5%) | ─ |
+| ‼️ | [`pt_BR`](./pt_BR.json) | `210/261` (80.5%) | ─ |
+| ‼️ | [`zh_CN`](./zh_CN.json) | `210/261` (80.5%) | ─ |
 
 <sub>
 ✅ - Fully translated
@@ -45,10 +45,12 @@ This means to figure out which keys are untranslated, you will need to manually
 
 ### Missing keys:
 
-<details><summary><code>de_DE</code> - 49 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>de_DE</code> - 51 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `export_import` | `Export/Import` |
+| `close_tooltip` | `Click to close` |
 | `create_new_entry` | `Create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
@@ -101,10 +103,12 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>es_ES</code> - 49 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>es_ES</code> - 51 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `export_import` | `Export/Import` |
+| `close_tooltip` | `Click to close` |
 | `create_new_entry` | `Create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
@@ -157,10 +161,12 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>fr_FR</code> - 49 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>fr_FR</code> - 51 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `export_import` | `Export/Import` |
+| `close_tooltip` | `Click to close` |
 | `create_new_entry` | `Create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
@@ -213,10 +219,12 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>hi_IN</code> - 49 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>hi_IN</code> - 51 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `export_import` | `Export/Import` |
+| `close_tooltip` | `Click to close` |
 | `create_new_entry` | `Create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
@@ -269,10 +277,12 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>ja_JA</code> - 49 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>ja_JA</code> - 51 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `export_import` | `Export/Import` |
+| `close_tooltip` | `Click to close` |
 | `create_new_entry` | `Create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
@@ -325,10 +335,12 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>pt_BR</code> - 49 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>pt_BR</code> - 51 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `export_import` | `Export/Import` |
+| `close_tooltip` | `Click to close` |
 | `create_new_entry` | `Create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |
@@ -381,10 +393,12 @@ This means to figure out which keys are untranslated, you will need to manually
 
 <br></details>
 
-<details><summary><code>zh_CN</code> - 49 missing keys <i>(click to show)</i></summary><br>
+<details><summary><code>zh_CN</code> - 51 missing keys <i>(click to show)</i></summary><br>
 
 | Key | English text |
 | --- | ------------ |
+| `export_import` | `Export/Import` |
+| `close_tooltip` | `Click to close` |
 | `create_new_entry` | `Create a new entry` |
 | `remove_entry` | `Remove this entry` |
 | `edit_entry` | `Edit this entry` |

+ 2 - 0
assets/translations/en_US.json

@@ -12,6 +12,7 @@
     "reload_tooltip": "Reload the page",
     "feature_requires_reload": "Changing this feature requires a page reload",
     "version_tooltip": "Version %1 (build %2) - click to open the changelog",
+    "export_import": "Export/Import",
     "export": "Export",
     "export_hint": "Copy the following text to export your configuration.\nWarning: it may contain sensitive data.",
     "click_to_reveal_sensitive_info": "(click to reveal sensitive information)",
@@ -40,6 +41,7 @@
 
     "reset": "Reset",
     "close": "Close",
+    "close_tooltip": "Click to close",
     "log_level_debug": "Debug (most)",
     "log_level_info": "Info (only important)",
     "toggled_on": "On",

+ 5 - 0
dist/BetterYTM.css

@@ -782,6 +782,11 @@ body .bytm-ripple.slower {
 .bytm-toggle-input input[data-toggled="true"] .bytm-toggle-input-knob {
   left: calc(var(--toggle-width) - var(--toggle-knob-offset) - var(--toggle-knob-calc-width));
 }
+.bytm-auto-like-channels-footer-wrapper {
+  display: flex;
+  justify-content: space-between;
+}
+
 :root {
   --bytm-menu-bg-highlight: #252525;
 }

+ 71 - 0
src/components/ImportExportDialog.ts

@@ -0,0 +1,71 @@
+import { BytmDialog, type BytmDialogOptions } from "./BytmDialog.js";
+import type { TrKey } from "../utils/translations.js";
+
+type ImportExportDialogOpts =
+  Omit<BytmDialogOptions, "renderHeader" | "renderBody" | "renderFooter">
+  & {
+    /** The data to export (or a function that returns the data as string, sync or async) */
+    exportData: string | (() => string | Promise<string>);
+    /** Optional variant of the data, used for special cases like when shift-clicking the copy button */
+    exportDataSpecial?: string | (() => string | Promise<string>);
+    /** Function that gets called when the user imports data */
+    onImport: (data: string) => void;
+    /** Translation key for the dialog title */
+    trKeyTitle: TrKey;
+    /** Translation key for the dialog description when importing */
+    trKeyDescImport: TrKey;
+    /** Translation key for the dialog description when exporting */
+    trKeyDescExport: TrKey;
+    /** Whether the data should be hidden by default when exporting and importing */
+    dataHidden?: boolean;
+  };
+
+/** Generic dialog for importing and exporting any string of data */
+export class ImportExportDialog extends BytmDialog {
+  constructor(options: ImportExportDialogOpts) {
+    super({
+      renderHeader: () => ImportExportDialog.renderHeader(options),
+      renderBody: () => ImportExportDialog.renderBody(options),
+      renderFooter: () => ImportExportDialog.renderFooter(options),
+      closeOnBgClick: true,
+      closeOnEscPress: true,
+      closeBtnEnabled: true,
+      destroyOnClose: true,
+      small: true,
+      ...options,
+    });
+  }
+
+  static async renderHeader(_options: ImportExportDialogOpts): Promise<HTMLElement> {
+    // TODO:
+    // render header with trKeyTitle
+
+    return document.createElement("div");
+  }
+
+  static async renderBody(_opts: ImportExportDialogOpts): Promise<HTMLElement> {
+    // TODO:
+    // two horizontal tabs:
+    // - export:
+    //   - description element with trKeyDescExport
+    //   - textarea with data, if dataHidden is true, show a button to reveal it
+    //   - button to copy the data to clipboard
+    // - import:
+    //   - description element with trKeyDescImport
+    //   - textarea for user to paste data, if dataHidden is true, use password masking
+
+    return document.createElement("div");
+  }
+
+  static async renderFooter(_options: ImportExportDialogOpts): Promise<HTMLElement> {
+    // TODO:
+    // - when export:
+    //   - copy button
+    //     - on click, copy exportData to clipboard
+    //     - on shift-click, copy exportDataSpecial to clipboard, fall back to exportData
+    // - when import:
+    //   - import button
+
+    return document.createElement("div");
+  }
+}

+ 4 - 0
src/dialogs/autoLike.css

@@ -0,0 +1,4 @@
+.bytm-auto-like-channels-footer-wrapper {
+  display: flex;
+  justify-content: space-between;
+}

+ 28 - 0
src/dialogs/autoLike.ts

@@ -3,6 +3,7 @@ import { getDomain, log, onInteraction, parseChannelIdFromUrl, t } from "../util
 import { BytmDialog, createCircularBtn, createToggleInput } from "../components/index.js";
 import { autoLikeStore, initAutoLikeStore } from "../features/index.js";
 import { siteEvents } from "../siteEvents.js";
+import "./autoLike.css";
 
 let autoLikeDialog: BytmDialog | null = null;
 
@@ -22,6 +23,7 @@ export async function getAutoLikeDialog() {
       small: true,
       renderHeader,
       renderBody,
+      renderFooter,
     });
 
     siteEvents.on("autoLikeChannelsUpdated", async () => {
@@ -225,6 +227,32 @@ async function renderBody() {
   return contElem;
 }
 
+function renderFooter() {
+  const wrapperEl = document.createElement("div");
+  wrapperEl.classList.add("bytm-auto-like-channels-footer-wrapper");
+
+  const importExportBtnElem = document.createElement("button");
+  importExportBtnElem.classList.add("bytm-btn");
+  importExportBtnElem.textContent = t("export_import");
+  importExportBtnElem.ariaLabel = importExportBtnElem.title = t("TODO:auto_like_import_or_export_tooltip");
+  wrapperEl.appendChild(importExportBtnElem);
+
+  const closeBtnElem = document.createElement("button");
+  closeBtnElem.classList.add("bytm-btn");
+  closeBtnElem.textContent = t("close");
+  closeBtnElem.ariaLabel = closeBtnElem.title = t("close_tooltip");
+  wrapperEl.appendChild(closeBtnElem);
+
+  onInteraction(importExportBtnElem, openImportExportAutoLikeChannelsDialog);
+  onInteraction(closeBtnElem, () => autoLikeDialog?.close());
+
+  return wrapperEl;
+}
+
+function openImportExportAutoLikeChannelsDialog() {
+  void "TODO: ImportExportDialog stuff";
+}
+
 function getChannelIdFromPrompt(promptStr: string) {
   const isId = promptStr.match(/^@?.+$/);
   const isUrl = promptStr.match(/^(?:https?:\/\/)?(?:www\.)?(?:music\.)?youtube\.com\/(?:channel\/|@)([a-zA-Z0-9_-]+)/);