Browse Source

feat: fix version notif dialog

Sv443 1 year ago
parent
commit
18d5a67eed

+ 86 - 10
assets/translations/README.md

@@ -6,15 +6,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) | 126 (default locale) |  |
-| [`de_DE`](./de_DE.json) | ✅ `126/126` (100.0%) | ─ |
-| [`en_UK`](./en_UK.json) | ✅ `126/126` (100.0%) | `en_US` |
-| [`es_ES`](./es_ES.json) | ✅ `126/126` (100.0%) | ─ |
-| [`fr_FR`](./fr_FR.json) | ✅ `126/126` (100.0%) | ─ |
-| [`hi_IN`](./hi_IN.json) | ✅ `126/126` (100.0%) | ─ |
-| [`ja_JA`](./ja_JA.json) | ✅ `126/126` (100.0%) | ─ |
-| [`pt_BR`](./pt_BR.json) | ✅ `126/126` (100.0%) | ─ |
-| [`zh_CN`](./zh_CN.json) | ✅ `126/126` (100.0%) | ─ |
+| [`en_US`](./en_US.json) | 129 (default locale) |  |
+| [`de_DE`](./de_DE.json) | 🚫 `125/129` (96.9%) | ─ |
+| [`en_UK`](./en_UK.json) | ✅ `129/129` (100.0%) | `en_US` |
+| [`es_ES`](./es_ES.json) | 🚫 `125/129` (96.9%) | ─ |
+| [`fr_FR`](./fr_FR.json) | 🚫 `125/129` (96.9%) | ─ |
+| [`hi_IN`](./hi_IN.json) | 🚫 `125/129` (96.9%) | ─ |
+| [`ja_JA`](./ja_JA.json) | 🚫 `125/129` (96.9%) | ─ |
+| [`pt_BR`](./pt_BR.json) | 🚫 `125/129` (96.9%) | ─ |
+| [`zh_CN`](./zh_CN.json) | 🚫 `125/129` (96.9%) | ─ |
 
 <br>
 
@@ -24,4 +24,80 @@ This means you need to manually check against the base translations for missing
 <br>
 
 ### Missing keys:
-No missing keys
+
+<details><summary><code>de_DE</code> - 4 missing keys <i>(click to show)</i></summary><br>
+
+| Key | English text |
+| --- | ------------ |
+| `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3\n\nDo you want to open %4 to install it manually?` |
+| `open_update_page` | `Open %1` |
+| `disable_update_check` | `Disable automatic update checks` |
+| `ignore_for_24h` | `Ignore for 24h` |
+
+<br></details>
+
+<details><summary><code>es_ES</code> - 4 missing keys <i>(click to show)</i></summary><br>
+
+| Key | English text |
+| --- | ------------ |
+| `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3\n\nDo you want to open %4 to install it manually?` |
+| `open_update_page` | `Open %1` |
+| `disable_update_check` | `Disable automatic update checks` |
+| `ignore_for_24h` | `Ignore for 24h` |
+
+<br></details>
+
+<details><summary><code>fr_FR</code> - 4 missing keys <i>(click to show)</i></summary><br>
+
+| Key | English text |
+| --- | ------------ |
+| `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3\n\nDo you want to open %4 to install it manually?` |
+| `open_update_page` | `Open %1` |
+| `disable_update_check` | `Disable automatic update checks` |
+| `ignore_for_24h` | `Ignore for 24h` |
+
+<br></details>
+
+<details><summary><code>hi_IN</code> - 4 missing keys <i>(click to show)</i></summary><br>
+
+| Key | English text |
+| --- | ------------ |
+| `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3\n\nDo you want to open %4 to install it manually?` |
+| `open_update_page` | `Open %1` |
+| `disable_update_check` | `Disable automatic update checks` |
+| `ignore_for_24h` | `Ignore for 24h` |
+
+<br></details>
+
+<details><summary><code>ja_JA</code> - 4 missing keys <i>(click to show)</i></summary><br>
+
+| Key | English text |
+| --- | ------------ |
+| `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3\n\nDo you want to open %4 to install it manually?` |
+| `open_update_page` | `Open %1` |
+| `disable_update_check` | `Disable automatic update checks` |
+| `ignore_for_24h` | `Ignore for 24h` |
+
+<br></details>
+
+<details><summary><code>pt_BR</code> - 4 missing keys <i>(click to show)</i></summary><br>
+
+| Key | English text |
+| --- | ------------ |
+| `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3\n\nDo you want to open %4 to install it manually?` |
+| `open_update_page` | `Open %1` |
+| `disable_update_check` | `Disable automatic update checks` |
+| `ignore_for_24h` | `Ignore for 24h` |
+
+<br></details>
+
+<details><summary><code>zh_CN</code> - 4 missing keys <i>(click to show)</i></summary><br>
+
+| Key | English text |
+| --- | ------------ |
+| `new_version_available` | `A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3\n\nDo you want to open %4 to install it manually?` |
+| `open_update_page` | `Open %1` |
+| `disable_update_check` | `Disable automatic update checks` |
+| `ignore_for_24h` | `Ignore for 24h` |
+
+<br></details>

+ 0 - 2
assets/translations/de_DE.json

@@ -83,8 +83,6 @@
     "remember_song_time_sites_all": "Beide Seiten",
     "remember_song_time_sites_yt": "Nur YouTube",
     "remember_song_time_sites_ytm": "Nur YouTube Music",
-    "new_version_available": "Eine neue Version von %1 ist verfügbar!\nAktuell installiert: %2 - neue Version: %3\n(Du kannst diese Benachrichtigung im Einstellungsmenü deaktivieren)\n\nMöchtest du %4 öffnen, um es manuell zu installieren?",
-
     "feature_category_layout": "Layout",
     "feature_category_songLists": "Songlisten",
     "feature_category_behavior": "Verhalten",

+ 4 - 1
assets/translations/en_US.json

@@ -86,7 +86,10 @@
     "remember_song_time_sites_yt": "Only YouTube",
     "remember_song_time_sites_ytm": "Only YouTube Music",
 
-    "new_version_available": "A new version of %1 is available!\nCurrently installed: %2 - new version: %3\n(You can disable this notification in the config menu)\n\nDo you want to open %4 to install it manually?",
+    "new_version_available": "A new version of %1 is available!\nYou currently have version %2 installed and you can update to version %3\n\nDo you want to open %4 to install it manually?",
+    "open_update_page": "Open %1",
+    "disable_update_check": "Disable automatic update checks",
+    "ignore_for_24h": "Ignore for 24h",
 
     "feature_category_layout": "Layout",
     "feature_category_songLists": "Song Lists",

+ 0 - 2
assets/translations/es_ES.json

@@ -83,8 +83,6 @@
     "remember_song_time_sites_all": "Ambos sitios",
     "remember_song_time_sites_yt": "Solo YouTube",
     "remember_song_time_sites_ytm": "Solo YouTube Music",
-    "new_version_available": "¡Una nueva versión de %1 está disponible!\nActualmente instalado: %2 - nueva versión: %3\n(Puede desactivar esta notificación en el menú de configuración)\n\n¿Quieres abrir %4 para instalarlo manualmente?",
-
     "feature_category_layout": "Diseño",
     "feature_category_songLists": "Listas de canciones",
     "feature_category_behavior": "Comportamiento",

+ 0 - 2
assets/translations/fr_FR.json

@@ -83,8 +83,6 @@
     "remember_song_time_sites_all": "Les deux sites",
     "remember_song_time_sites_yt": "Seulement YouTube",
     "remember_song_time_sites_ytm": "Seulement YouTube Music",
-    "new_version_available": "Une nouvelle version de %1 est disponible!\nActuellement installée: %2 - nouvelle version: %3\n(Vous pouvez désactiver cette notification dans le menu de configuration)\n\nVoulez-vous ouvrir",
-
     "feature_category_layout": "Disposition",
     "feature_category_songLists": "Listes de chansons",
     "feature_category_behavior": "Comportement",

+ 0 - 2
assets/translations/hi_IN.json

@@ -83,8 +83,6 @@
     "remember_song_time_sites_all": "दोनों साइटें",
     "remember_song_time_sites_yt": "केवल YouTube",
     "remember_song_time_sites_ytm": "केवल YouTube Music",
-    "new_version_available": "एक नया संस्करण %1 उपलब्ध है!\nवर्तमान में स्थापित: %2 - नया संस्करण: %3\n(आप इस सूचना को कॉन्फ़िग मेनू में अक्षम कर सकते हैं)\n\nक्या आप %4 को खोलकर इसे मैन्युअल रूप से स्थापित करना चाहते हैं?",
-
     "feature_category_layout": "लेआउट",
     "feature_category_songLists": "गीत सूचियाँ",
     "feature_category_behavior": "व्यवहार",

+ 0 - 2
assets/translations/ja_JA.json

@@ -83,8 +83,6 @@
     "remember_song_time_sites_all": "すべてのサイト",
     "remember_song_time_sites_yt": "YouTube のみ",
     "remember_song_time_sites_ytm": "YouTube Music のみ",
-    "new_version_available": "新しいバージョンの %1 が利用可能です!\n現在のバージョン: %2 - 新しいバージョン: %3\n(この通知を構成メニューで無効にすることができます)\n\n%4 を開いて手動でインストールしますか?",
-
     "feature_category_layout": "レイアウト",
     "feature_category_songLists": "曲リスト",
     "feature_category_behavior": "動作",

+ 0 - 2
assets/translations/pt_BR.json

@@ -83,8 +83,6 @@
     "remember_song_time_sites_all": "Ambos os sites",
     "remember_song_time_sites_yt": "Apenas YouTube",
     "remember_song_time_sites_ytm": "Apenas YouTube Music",
-    "new_version_available": "Uma nova versão do %1 está disponível!\nAtualmente instalado: %2 - nova versão: %3\n(Você pode desativar esta notificação no menu de configuração)\n\nVocê deseja abrir %4 para instalá-lo manualmente?",
-
     "feature_category_layout": "Layout",
     "feature_category_songLists": "Listas de músicas",
     "feature_category_behavior": "Comportamento",

+ 0 - 2
assets/translations/zh_CN.json

@@ -83,8 +83,6 @@
     "remember_song_time_sites_all": "所有网站",
     "remember_song_time_sites_yt": "仅 YouTube",
     "remember_song_time_sites_ytm": "仅 YouTube Music",
-    "new_version_available": "%1 的新版本可用!\n当前安装: %2 - 新版本: %3\n(您可以在配置菜单中禁用此通知)\n\n是否要打开 %4 来手动安装它?",
-
     "feature_category_layout": "布局",
     "feature_category_songLists": "歌曲列表",
     "feature_category_behavior": "行为",

File diff suppressed because it is too large
+ 4956 - 4481
dist/BetterYTM.user.js


+ 15 - 0
src/dialogs/dialogs.css

@@ -0,0 +1,15 @@
+#bytm-version-notif-dialog-btns {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  margin-top: 20px;
+}
+
+#bytm-disable-update-check-wrapper {
+  margin-top: 15px;
+}
+
+#bytm-disable-update-check-wrapper label {
+  padding-left: 8px;
+}

+ 2 - 0
src/dialogs/index.ts

@@ -1 +1,3 @@
+import "./dialogs.css";
+
 export * from "./versionNotif";

+ 51 - 8
src/dialogs/versionNotif.ts

@@ -1,5 +1,6 @@
 import { host, scriptInfo } from "../constants";
 import { BytmDialog, getChangelogMd, parseMarkdown, t } from "../utils";
+import { getFeatures, saveFeatures } from "../config";
 import pkg from "../../package.json" assert { type: "json" };
 
 let verNotifDialog: BytmDialog | null = null;
@@ -19,9 +20,12 @@ export async function getVersionNotifDialog({
 
     verNotifDialog = new BytmDialog({
       id: "version-notif",
+      maxWidth: 600,
+      maxHeight: 800,
       closeOnBgClick: false,
-      closeOnEscPress: false,
+      closeOnEscPress: true,
       destroyOnClose: true,
+      smallMenu: true,
       renderBody: () => renderBody({ latestTag, changelogHtml }),
     });
   }
@@ -35,7 +39,7 @@ function renderBody({
   latestTag: string;
   changelogHtml: string;
 }) {
-  const platformNames: Record<typeof host, string> = {
+  const hostPlatformNames: Record<typeof host, string> = {
     github: "GitHub",
     greasyfork: "GreasyFork",
     openuserjs: "OpenUserJS",
@@ -47,14 +51,53 @@ function renderBody({
   const wrapperEl = document.createElement("div");
 
   const pEl = document.createElement("p");
-  pEl.textContent = t("new_version_available", scriptInfo.name, scriptInfo.version, latestTag, platformNames[host]);
+  pEl.textContent = t("new_version_available", scriptInfo.name, scriptInfo.version, latestTag, hostPlatformNames[host]);
   wrapperEl.appendChild(pEl);
 
-  const btnEl = document.createElement("button");
-  btnEl.className = "bytm-btn";
-  btnEl.textContent = t("update_now");
-  btnEl.addEventListener("click", () => window.open(pkg.updates[host]));
-  wrapperEl.appendChild(btnEl);
+  const disableUpdCheckEl = document.createElement("div");
+  disableUpdCheckEl.id = "bytm-disable-update-check-wrapper";
+
+  const checkboxEl = document.createElement("input");
+  checkboxEl.type = "checkbox";
+  checkboxEl.id = "bytm-disable-update-check-chkbox";
+  checkboxEl.checked = false;
+
+  const labelEl = document.createElement("label");
+  labelEl.htmlFor = "bytm-disable-update-check-chkbox";
+  labelEl.textContent = t("disable_update_check");
+
+  disableUpdCheckEl.appendChild(checkboxEl);
+  disableUpdCheckEl.appendChild(labelEl);
+
+  wrapperEl.appendChild(disableUpdCheckEl);
+
+  verNotifDialog!.on("close", async () => {
+    const config = getFeatures();
+    if(checkboxEl.checked)
+      config.versionCheck = false;
+    await saveFeatures(config);
+  });
+
+  const btnWrapper = document.createElement("div");
+  btnWrapper.id = "bytm-version-notif-dialog-btns";
+
+  const btnUpdate = document.createElement("button");
+  btnUpdate.className = "bytm-btn";
+  btnUpdate.textContent = t("open_update_page", hostPlatformNames[host]);
+  btnUpdate.addEventListener("click", () => {
+    window.open(pkg.updates[host]);
+    verNotifDialog!.close();
+  });
+
+  const btnIgnore = document.createElement("button");
+  btnIgnore.className = "bytm-btn";
+  btnIgnore.textContent = t("ignore_for_24h");
+  btnIgnore.addEventListener("click", () => verNotifDialog!.close());
+
+  btnWrapper.appendChild(btnUpdate);
+  btnWrapper.appendChild(btnIgnore);
+
+  wrapperEl.appendChild(btnWrapper);
 
   return wrapperEl;
 }

+ 1 - 1
src/features/behavior.ts

@@ -4,7 +4,7 @@ import { LogLevel, type FeatureConfig } from "../types";
 
 let features: FeatureConfig;
 
-export function preInitBehavior(feats: FeatureConfig) {
+export function setBehaviorConfig(feats: FeatureConfig) {
   features = feats;
 }
 

+ 1 - 1
src/features/input.ts

@@ -8,7 +8,7 @@ import { featInfo } from "./index";
 
 let features: FeatureConfig;
 
-export function preInitInput(feats: FeatureConfig) {
+export function setInputConfig(feats: FeatureConfig) {
   features = feats;
 }
 

+ 1 - 1
src/features/layout.css

@@ -143,7 +143,7 @@ button.bytm-btn {
   display: flex;
   flex-direction: row;
   align-items: center;
-  font-size: 16px;
+  font-size: 1.4rem;
   font-weight: 400;
   line-height: 24px;
   padding: var(--yt-compact-link-paper-item-padding, 0px 36px 0 16px);

+ 1 - 1
src/features/layout.ts

@@ -8,7 +8,7 @@ import "./layout.css";
 
 let features: FeatureConfig;
 
-export function preInitLayout(feats: FeatureConfig) {
+export function setLayoutConfig(feats: FeatureConfig) {
   features = feats;
 }
 

+ 1 - 1
src/features/songLists.ts

@@ -8,7 +8,7 @@ import "./songLists.css";
 
 let features: FeatureConfig;
 
-export function preInitSongLists(feats: FeatureConfig) {
+export function setSongListsConfig(feats: FeatureConfig) {
   features = feats;
 }
 

+ 2 - 1
src/features/versionCheck.ts

@@ -21,7 +21,8 @@ export async function checkVersion() {
       url: releaseURL,
     });
 
-    const latestTag = res.finalUrl.split("/").pop()?.replace(/[a-zA-Z]/g, "");
+    // const latestTag = res.finalUrl.split("/").pop()?.replace(/[a-zA-Z]/g, "");
+    const latestTag = "1.2.3";
 
     if(!latestTag)
       return;

+ 16 - 11
src/index.ts

@@ -13,21 +13,21 @@ import {
 
   // features:
   // layout
-  preInitLayout,
+  setLayoutConfig,
   addWatermark,
   removeUpgradeTab, initVolumeFeatures,
   removeShareTrackingParam, fixSpacing,
   addScrollToActiveBtn,
   // song lists
-  preInitSongLists,
+  setSongListsConfig,
   initQueueButtons,
   // behavior
-  preInitBehavior,
+  setBehaviorConfig,
   initBeforeUnloadHook, disableBeforeUnload,
   initAutoCloseToasts, initRememberSongTime,
   disableDarkReader,
   // input
-  preInitInput,
+  setInputConfig,
   initArrowKeySkip, initSiteSwitch,
   addAnchorImprovements, initNumKeysSkip,
   // lyrics
@@ -96,10 +96,10 @@ async function init() {
 
     setLogLevel(features.logLevel);
 
-    preInitLayout(features);
-    preInitBehavior(features);
-    preInitInput(features);
-    preInitSongLists(features);
+    setLayoutConfig(features);
+    setBehaviorConfig(features);
+    setInputConfig(features);
+    setSongListsConfig(features);
 
     if(features.disableBeforeUnloadPopup && domain === "ytm")
       disableBeforeUnload();
@@ -128,8 +128,7 @@ async function init() {
 
 /** Called when the DOM has finished loading and can be queried and altered by the userscript */
 async function onDomLoad() {
-  // post-build these double quotes are replaced by backticks (because if backticks are used here, the bundler converts them to double quotes)
-  addGlobalStyle("#{{GLOBAL_STYLE}}").id = "bytm-style-global";
+  insertGlobalStyle();
 
   initObservers();
   initOnSelector();
@@ -209,7 +208,7 @@ async function onDomLoad() {
   }
 }
 
-void ["TODO:", initFeatures];
+void ["TODO(v1.2):", initFeatures];
 async function initFeatures() {
   const ftInit = [] as Promise<void>[];
 
@@ -262,6 +261,12 @@ async function initFeatures() {
   });
 }
 
+/** Inserts the bundled CSS files imported throughout the script into a <style> element in the <head> */
+function insertGlobalStyle() {
+  // post-build these double quotes are replaced by backticks (because if backticks are used here, the bundler converts them to double quotes)
+  addGlobalStyle("#{{GLOBAL_STYLE}}").id = "bytm-style-global";
+}
+
 function registerMenuCommands() {
   if(mode === "development") {
     GM.registerMenuCommand("Reset config", async () => {

+ 1 - 1
src/menu/menu_old.css

@@ -223,7 +223,7 @@
   flex-direction: row;
   justify-content: space-between;
   align-items: center;
-  font-size: 1.4em;
+  font-size: 1.4rem;
   padding: 8px 20px;
   transition: background-color 0.15s ease-out;
 }

+ 404 - 0
src/utils/BytmDialog.css

@@ -0,0 +1,404 @@
+.bytm-dialog-bg {
+  --bytm-dialog-bg: #333333;
+  --bytm-dialog-bg-highlight: #252525;
+  --bytm-scroll-indicator-bg: rgba(10, 10, 10, 0.7);
+  --bytm-dialog-separator-color: #797979;
+  --bytm-dialog-border-radius: 10px;
+}
+
+#bytm-cfg-dialog-bg {
+  --bytm-dialog-height-max: 750px;
+  --bytm-dialog-width-max: 1000px;
+}
+
+#bytm-changelog-dialog-bg {
+  --bytm-dialog-height-max: 800px;
+  --bytm-dialog-width-max: 800px;
+}
+
+#bytm-export-dialog-bg, #bytm-import-dialog-bg {
+  --bytm-dialog-height-max: 500px;
+  --bytm-dialog-width-max: 600px;
+}
+
+#bytm-feat-help-dialog-bg {
+  --bytm-dialog-height-max: 400px;
+  --bytm-dialog-width-max: 600px;
+}
+
+.bytm-dialog-bg {
+  display: block;
+  position: fixed;
+  width: 100%;
+  height: 100%;
+  top: 0;
+  left: 0;
+  z-index: 5;
+  background-color: rgba(0, 0, 0, 0.6);
+}
+
+.bytm-dialog {
+  position: fixed;
+  display: flex;
+  flex-direction: column;
+  width: calc(min(100% - 60px, var(--bytm-dialog-width-max)));
+  border-radius: var(--bytm-dialog-border-radius);
+  height: auto;
+  max-height: calc(min(100% - 40px, var(--bytm-dialog-height-max)));
+  left: 50%;
+  top: 50%;
+  transform: translate(-50%, -50%);
+  z-index: 6;
+  color: #fff;
+  background-color: var(--bytm-dialog-bg);
+}
+
+.bytm-dialog-body {
+  font-size: 1.4rem;
+  padding: 20px;
+}
+
+.bytm-dialog-body.small {
+  padding: 15px;
+}
+
+.bytm-dialog-body p {
+  overflow-wrap: break-word;
+  white-space: pre-wrap;
+}
+
+#bytm-dialog-opts {
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  padding: 30px 0px;
+  overflow-y: auto;
+}
+
+.bytm-dialog-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 6px;
+  padding: 15px 20px 15px 20px;
+  background-color: var(--bytm-dialog-bg);
+  border: 2px solid var(--bytm-dialog-separator-color);
+  border-style: none none solid none;
+  border-radius: var(--bytm-dialog-border-radius) var(--bytm-dialog-border-radius) 0px 0px;
+}
+
+.bytm-dialog-header.small {
+  padding: 10px 15px;
+}
+
+.bytm-dialog-titlecont {
+  display: flex;
+  align-items: center;
+}
+
+.bytm-dialog-titlecont-no-title {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+}
+
+.bytm-dialog-title {
+  position: relative;
+  display: inline-block;
+  font-size: 22px;
+}
+
+#bytm-dialog-version {
+  position: absolute;
+  width: 100%;
+  bottom: -10px;
+  left: 0;
+  font-size: 10px;
+  font-weight: normal;
+  z-index: 7;
+}
+
+#bytm-dialog-version .bytm-link {
+  color: #c6d2db;
+}
+
+#bytm-dialog-linkscont {
+  display: flex;
+  align-items: center;
+  margin-left: 32px;
+}
+
+.bytm-dialog-link {
+  display: inline-flex;
+  align-items: center;
+  cursor: pointer;
+}
+
+.bytm-dialog-link:not(:last-of-type) {
+  margin-right: 10px;
+}
+
+.bytm-dialog-link .bytm-dialog-img {
+  position: relative;
+  border-radius: 50%;
+  bottom: 0px;
+  transition: bottom 0.15s ease-out;
+}
+
+.bytm-dialog-link:hover .bytm-dialog-img {
+  bottom: 5px;
+}
+
+.bytm-dialog-close {
+  width: 32px;
+  height: 32px;
+  cursor: pointer;
+}
+
+.bytm-dialog-close.small {
+  width: 24px;
+  height: 24px;
+}
+
+.bytm-dialog-footer {
+  font-size: 17px;
+  text-decoration: underline;
+}
+
+.bytm-dialog-footer.hidden {
+  display: none;
+}
+
+.bytm-dialog-footer-cont {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  margin-top: 6px;
+  padding: 15px 20px;
+  background: var(--bytm-dialog-bg);
+  background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, var(--bytm-dialog-bg) 30%, var(--bytm-dialog-bg) 100%);
+  border: 2px solid var(--bytm-dialog-separator-color);
+  border-style: solid none none none;
+  border-radius: 0px 0px var(--bytm-dialog-border-radius) var(--bytm-dialog-border-radius);
+}
+
+#bytm-dialog-footer-buttons-cont button:not(:last-of-type) {
+  margin-right: 15px;
+}
+
+.bytm-dialog-footer-right {
+  display: flex;
+  flex-direction: row-reverse;
+  align-items: center;
+  margin-top: 15px;
+}
+
+#bytm-dialog-footer-left-buttons-cont button:not(:last-of-type) {
+  margin-right: 15px;
+}
+
+#bytm-dialog-scroll-indicator {
+  --bytm-scroll-indicator-padding: 5px;
+  position: sticky;
+  bottom: -15px;
+  left: 50%;
+  margin-top: calc(-32px - var(--bytm-scroll-indicator-padding) * 2);
+  padding: var(--bytm-scroll-indicator-padding);
+  transform: translateX(-50%);
+  width: 32px;
+  height: 32px;
+  z-index: 7;
+  background-color: var(--bytm-scroll-indicator-bg);
+  border-radius: 50%;
+  cursor: pointer;
+}
+
+.bytm-hidden {
+  visibility: hidden !important;
+}
+
+.bytm-ftconf-category-header {
+  font-size: 18px;
+  margin-top: 32px;
+  margin-bottom: 8px;
+  padding: 0px 20px;
+}
+
+.bytm-ftconf-category-header:first-of-type {
+  margin-top: 0;
+}
+
+.bytm-ftitem {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  align-items: center;
+  font-size: 1.4em;
+  padding: 8px 20px;
+  transition: background-color 0.15s ease-out;
+}
+
+.bytm-ftitem:hover {
+  background-color: var(--bytm-dialog-bg-highlight);
+}
+
+.bytm-ftitem-leftside {
+  display: flex;
+  align-items: center;
+  min-height: 24px;
+}
+
+.bytm-ftconf-ctrl {
+  display: inline-flex;
+  align-items: center;
+  white-space: nowrap;
+  margin-left: 10px;
+}
+
+.bytm-ftconf-label {
+  user-select: none;
+}
+
+.bytm-slider-label {
+  margin-right: 10px;
+}
+
+.bytm-toggle-label {
+  padding-left: 10px;
+  padding-right: 5px;
+}
+
+.bytm-ftconf-input.bytm-hotkey-input {
+  cursor: pointer;
+  min-width: 50px;
+}
+
+.bytm-ftconf-input[type=number] {
+  width: 75px;
+}
+
+.bytm-ftconf-input[type=checkbox] {
+  margin-left: 5px;
+}
+
+#bytm-export-dialog-text, #bytm-import-dialog-text {
+  font-size: 1.6em;
+  margin-bottom: 15px;
+}
+
+.bytm-dialog-footer-copied {
+  font-size: 1.6em;
+  margin-right: 15px;
+}
+
+#bytm-changelog-dialog-body {
+  overflow-y: auto;
+}
+
+#bytm-export-dialog-textarea, #bytm-import-dialog-textarea {
+  width: 100%;
+  height: 150px;
+  resize: none;
+}
+
+.bytm-markdown-container {
+  display: flex;
+  flex-direction: column;
+  overflow-y: auto;
+  font-size: 1.5em;
+  line-height: 20px;
+}
+
+/* Markdown stuff */
+
+.bytm-markdown-container kbd {
+  --bytm-easing: cubic-bezier(0.31, 0.58, 0.24, 1.15);
+  display: inline-block;
+  vertical-align: bottom;
+  padding: 4px;
+  padding-top: 2px;
+  font-size: 0.95em;
+  line-height: 11px;
+  background-color: #222;
+  border: 1px solid #777;
+  border-radius: 5px;
+  box-shadow: inset 0 -2px 0 #515559;
+  transition: padding 0.1s var(--bytm-easing), box-shadow 0.1s var(--bytm-easing);
+}
+
+.bytm-markdown-container kbd:active {
+  padding-bottom: 2px;
+  box-shadow: inset 0 0 0 initial;
+}
+
+.bytm-markdown-container kbd::selection {
+  background: rgba(0, 0, 0, 0);
+}
+
+.bytm-markdown-container code {
+  background-color: #222;
+  border-radius: 3px;
+  padding: 1px 5px;
+}
+
+.bytm-markdown-container h2 {
+  margin-bottom: 5px;
+}
+
+.bytm-markdown-container h2:not(:first-of-type) {
+  margin-top: 30px;
+}
+
+.bytm-markdown-container ul li::before {
+  content: "• ";
+  font-weight: bolder;
+}
+
+.bytm-markdown-container ul li > ul li::before {
+  white-space: pre;
+  content: "    • ";
+  font-weight: bolder;
+}
+
+#bytm-feat-help-dialog-desc, #bytm-feat-help-dialog-text {
+  overflow-wrap: break-word;
+  white-space: pre-wrap;
+  padding: 10px 10px 15px 20px;
+  font-size: 1.5em;
+}
+
+#bytm-feat-help-dialog-desc {
+  font-size: 1.65em;
+  padding-bottom: 5px;
+}
+
+.bytm-ftitem-help-btn {
+  width: 24px !important;
+  height: 24px !important;
+}
+
+.bytm-ftitem-help-btn svg {
+  width: 18px !important;
+  height: 18px !important;
+}
+
+.bytm-ftitem-help-btn svg > path {
+  fill: #b3bec7 !important;
+}
+
+hr {
+  display: block;
+  margin: 8px 0px 12px 0px;
+  border: revert;
+}
+
+.bytm-ftitem-adornment {
+  display: inline-flex;
+  justify-content: flex-start;
+  align-items: center;
+  margin-left: 8px;
+}
+
+#bytm-ftitem-locale-adornment svg path {
+  fill: #4595c7;
+}

+ 40 - 9
src/utils/BytmDialog.ts

@@ -3,10 +3,15 @@ import { NanoEmitter } from "./NanoEmitter";
 import { clearInner, getResourceUrl, warn } from ".";
 import { t } from "./translations";
 import "./BytmDialog.css";
+import { addGlobalStyle } from "@sv443-network/userutils";
 
 export interface BytmDialogOptions {
   /** ID that gets added to child element IDs - has to be unique and conform to HTML ID naming rules! */
   id: string;
+  /** Maximum width of the dialog in pixels */
+  maxWidth: number;
+  /** Maximum height of the dialog in pixels */
+  maxHeight: number;
   /** Whether the dialog should close when the background is clicked - defaults to true */
   closeOnBgClick?: boolean;
   /** Whether the dialog should close when the escape key is pressed - defaults to true */
@@ -15,6 +20,8 @@ export interface BytmDialogOptions {
   closeBtnEnabled?: boolean;
   /** Whether the dialog should be destroyed when it's closed - defaults to false */
   destroyOnClose?: boolean;
+  /** Whether the menu should have a smaller overall appearance - defaults to false */
+  smallMenu?: boolean;
   /** Called to render the body of the dialog */
   renderBody: () => HTMLElement;
   /** Called to render the header of the dialog - leave undefined for a blank header */
@@ -54,6 +61,7 @@ export class BytmDialog extends NanoEmitter<{
       closeOnEscPress: true,
       closeBtnEnabled: true,
       destroyOnClose: false,
+      smallHeader: false,
       ...options,
     };
     this.id = options.id;
@@ -80,17 +88,30 @@ export class BytmDialog extends NanoEmitter<{
 
     this.attachListeners(bgElem);
 
+    addGlobalStyle(`\
+#bytm-${this.id}-dialog-bg {
+  --bytm-dialog-width-max: ${this.options.maxWidth}px;
+  --bytm-dialog-height-max: ${this.options.maxHeight}px;
+}`).id = `bytm-style-dialog-${this.id}`;
+
     this.events.emit("render");
+    return bgElem;
   }
 
   /** Clears all dialog contents (unmounts them from the DOM) in preparation for a new rendering call */
   public unmount() {
     this.dialogRendered = false;
 
-    const elem = document.querySelector<HTMLElement>(`#bytm-${this.id}-dialog-bg`);
-    elem && clearInner(elem);
+    const clearSelectors = [
+      `#bytm-${this.id}-dialog-bg`,
+      `#bytm-style-dialog-${this.id}`,
+    ];
 
-    document.querySelector(`#bytm-${this.id}-dialog-bg`)?.remove();
+    for(const sel of clearSelectors) {
+      const elem = document.querySelector<HTMLElement>(sel);
+      elem?.hasChildNodes() && clearInner(elem);
+      document.querySelector(sel)?.remove();
+    }
 
     this.events.emit("clear");
   }
@@ -130,6 +151,7 @@ export class BytmDialog extends NanoEmitter<{
     lastDialogId = this.id;
 
     this.events.emit("open");
+    return dialogBg;
   }
 
   /** Closes the dialog - prevents default action and immediate propagation of the passed event */
@@ -184,7 +206,7 @@ export class BytmDialog extends NanoEmitter<{
   }
 
   /** Called once to attach all generic event listeners */
-  private attachListeners(bgElem: HTMLElement) {
+  public attachListeners(bgElem: HTMLElement) {
     if(this.listenersAttached)
       return;
     this.listenersAttached = true;
@@ -217,6 +239,7 @@ export class BytmDialog extends NanoEmitter<{
 
     const headerWrapperEl = document.createElement("div");
     headerWrapperEl.classList.add("bytm-dialog-header");
+    this.options.smallMenu && headerWrapperEl.classList.add("small");
 
     if(header) {
       const headerTitleWrapperEl = document.createElement("div");
@@ -227,10 +250,13 @@ export class BytmDialog extends NanoEmitter<{
       headerTitleWrapperEl.appendChild(header);
       headerWrapperEl.appendChild(headerTitleWrapperEl);
     }
+    else
+      headerWrapperEl.appendChild(document.createElement("div"));
 
     if(this.options.closeBtnEnabled) {
       const closeBtnEl = document.createElement("img");
       closeBtnEl.classList.add("bytm-dialog-close");
+      this.options.smallMenu && closeBtnEl.classList.add("small");
       closeBtnEl.src = await getResourceUrl("img-close");
       closeBtnEl.role = "button";
       closeBtnEl.tabIndex = 0;
@@ -240,18 +266,23 @@ export class BytmDialog extends NanoEmitter<{
 
     dialogWrapperEl.appendChild(headerWrapperEl);
 
-    // TODO:
     //#SECTION body
 
-    const bodyWrapperEl = document.createElement("div");
-    bodyWrapperEl.appendChild(this.options.renderBody());
+    const menuBodyElem = document.createElement("div");
+    menuBodyElem.id = `bytm-${this.id}-dialog-body`;
+    menuBodyElem.classList.add("bytm-dialog-body");
+    this.options.smallMenu && menuBodyElem.classList.add("small");
 
-    dialogWrapperEl.appendChild(bodyWrapperEl);
+    menuBodyElem.appendChild(this.options.renderBody());
+    dialogWrapperEl.appendChild(menuBodyElem);
 
     //#SECTION footer
 
     if(footer) {
-      dialogWrapperEl.appendChild(footer);
+      const footerWrapper = document.createElement("div");
+      footerWrapper.classList.add("bytm-dialog-footer-cont");
+      dialogWrapperEl.appendChild(footerWrapper);
+      footerWrapper.appendChild(footer);
     }
 
     return dialogWrapperEl;

Some files were not shown because too many files changed in this diff