welcome.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import { getResourceUrl, initTranslations, setInnerHtml, setLocale, t, warn, type TrLocale } from "../utils/index.js";
  2. import { BytmDialog } from "../components/index.js";
  3. import { openCfgMenu } from "../menu/menu_old.js";
  4. import { mode, scriptInfo } from "../constants.js";
  5. import { getFeature, getFeatures, setFeatures } from "../config.js";
  6. import { getChangelogDialog } from "./index.js";
  7. import pkg from "../../package.json" with { type: "json" };
  8. import locales from "../../assets/locales.json" with { type: "json" };
  9. let welcomeDialog: BytmDialog | null = null;
  10. /** Creates and/or returns the import dialog */
  11. export async function getWelcomeDialog() {
  12. if(!welcomeDialog) {
  13. welcomeDialog = new BytmDialog({
  14. id: "welcome",
  15. width: 700,
  16. height: 500,
  17. closeBtnEnabled: true,
  18. closeOnBgClick: true,
  19. closeOnEscPress: true,
  20. destroyOnClose: true,
  21. renderHeader,
  22. renderBody,
  23. renderFooter,
  24. });
  25. welcomeDialog.on("render", retranslateWelcomeMenu);
  26. }
  27. return welcomeDialog;
  28. }
  29. async function renderHeader() {
  30. const titleWrapperElem = document.createElement("div");
  31. titleWrapperElem.id = "bytm-welcome-menu-title-wrapper";
  32. const titleLogoElem = document.createElement("img");
  33. titleLogoElem.id = "bytm-welcome-menu-title-logo";
  34. titleLogoElem.classList.add("bytm-no-select");
  35. titleLogoElem.src = await getResourceUrl(mode === "development" ? "img-logo_dev" : "img-logo");
  36. const titleElem = document.createElement("h2");
  37. titleElem.id = "bytm-welcome-menu-title";
  38. titleElem.classList.add("bytm-dialog-title");
  39. titleElem.role = "heading";
  40. titleElem.ariaLevel = "1";
  41. titleElem.tabIndex = 0;
  42. titleWrapperElem.appendChild(titleLogoElem);
  43. titleWrapperElem.appendChild(titleElem);
  44. return titleWrapperElem;
  45. }
  46. async function renderBody() {
  47. const contentWrapper = document.createElement("div");
  48. contentWrapper.id = "bytm-welcome-menu-content-wrapper";
  49. // locale switcher
  50. const localeCont = document.createElement("div");
  51. localeCont.id = "bytm-welcome-menu-locale-cont";
  52. const localeImg = document.createElement("img");
  53. localeImg.id = "bytm-welcome-menu-locale-img";
  54. localeImg.classList.add("bytm-no-select");
  55. localeImg.src = await getResourceUrl("icon-globe");
  56. const localeSelectElem = document.createElement("select");
  57. localeSelectElem.id = "bytm-welcome-menu-locale-select";
  58. for(const [locale, { name }] of Object.entries(locales)) {
  59. const localeOptionElem = document.createElement("option");
  60. localeOptionElem.value = locale;
  61. localeOptionElem.textContent = name;
  62. localeSelectElem.appendChild(localeOptionElem);
  63. }
  64. localeSelectElem.value = getFeature("locale");
  65. localeSelectElem.addEventListener("change", async () => {
  66. const selectedLocale = localeSelectElem.value;
  67. const feats = Object.assign({}, getFeatures());
  68. feats.locale = selectedLocale as TrLocale;
  69. setFeatures(feats);
  70. await initTranslations(selectedLocale as TrLocale);
  71. setLocale(selectedLocale as TrLocale);
  72. retranslateWelcomeMenu();
  73. });
  74. localeCont.appendChild(localeImg);
  75. localeCont.appendChild(localeSelectElem);
  76. contentWrapper.appendChild(localeCont);
  77. // text
  78. const textCont = document.createElement("div");
  79. textCont.id = "bytm-welcome-menu-text-cont";
  80. const textElem = document.createElement("p");
  81. textElem.id = "bytm-welcome-menu-text";
  82. const textElems = [] as HTMLElement[];
  83. const line1Elem = document.createElement("span");
  84. line1Elem.id = "bytm-welcome-text-line1";
  85. line1Elem.tabIndex = 0;
  86. textElems.push(line1Elem);
  87. const br1Elem = document.createElement("br");
  88. textElems.push(br1Elem);
  89. const line2Elem = document.createElement("span");
  90. line2Elem.id = "bytm-welcome-text-line2";
  91. line2Elem.tabIndex = 0;
  92. textElems.push(line2Elem);
  93. const br2Elem = document.createElement("br");
  94. textElems.push(br2Elem);
  95. const br3Elem = document.createElement("br");
  96. textElems.push(br3Elem);
  97. const line3Elem = document.createElement("span");
  98. line3Elem.id = "bytm-welcome-text-line3";
  99. line3Elem.tabIndex = 0;
  100. textElems.push(line3Elem);
  101. const br4Elem = document.createElement("br");
  102. textElems.push(br4Elem);
  103. const line4Elem = document.createElement("span");
  104. line4Elem.id = "bytm-welcome-text-line4";
  105. line4Elem.tabIndex = 0;
  106. textElems.push(line4Elem);
  107. const br5Elem = document.createElement("br");
  108. textElems.push(br5Elem);
  109. const br6Elem = document.createElement("br");
  110. textElems.push(br6Elem);
  111. const line5Elem = document.createElement("span");
  112. line5Elem.id = "bytm-welcome-text-line5";
  113. line5Elem.tabIndex = 0;
  114. textElems.push(line5Elem);
  115. textElems.forEach((elem) => textElem.appendChild(elem));
  116. textCont.appendChild(textElem);
  117. contentWrapper.appendChild(textCont);
  118. return contentWrapper;
  119. }
  120. /** Retranslates all elements inside the welcome menu */
  121. function retranslateWelcomeMenu() {
  122. const getLink = (href: string): [string, string] => {
  123. return [`<a href="${href}" class="bytm-link" target="_blank" rel="noopener noreferrer">`, "</a>"];
  124. };
  125. const changes = {
  126. "#bytm-welcome-menu-title": (e: HTMLElement) => e.textContent = e.ariaLabel = t("welcome_menu_title", scriptInfo.name),
  127. "#bytm-welcome-menu-title-close": (e: HTMLElement) => e.ariaLabel = e.title = t("close_menu_tooltip"),
  128. "#bytm-welcome-menu-open-cfg": (e: HTMLElement) => {
  129. e.textContent = e.ariaLabel = t("config_menu");
  130. e.ariaLabel = e.title = t("open_config_menu_tooltip");
  131. },
  132. "#bytm-welcome-menu-open-changelog": (e: HTMLElement) => {
  133. e.textContent = e.ariaLabel = t("open_changelog");
  134. e.ariaLabel = e.title = t("open_changelog_tooltip");
  135. },
  136. "#bytm-welcome-menu-footer-close": (e: HTMLElement) => {
  137. e.textContent = e.ariaLabel = t("close");
  138. e.ariaLabel = e.title = t("close_menu_tooltip");
  139. },
  140. "#bytm-welcome-text-line1": (e: HTMLElement) => setInnerHtml(e, e.ariaLabel = t("welcome_text_line_1")),
  141. "#bytm-welcome-text-line2": (e: HTMLElement) => setInnerHtml(e, e.ariaLabel = t("welcome_text_line_2", scriptInfo.name)),
  142. "#bytm-welcome-text-line3": (e: HTMLElement) => setInnerHtml(e, e.ariaLabel = t("welcome_text_line_3", scriptInfo.name, ...getLink(`${pkg.hosts.greasyfork}/feedback`), ...getLink(pkg.hosts.openuserjs))),
  143. "#bytm-welcome-text-line4": (e: HTMLElement) => setInnerHtml(e, e.ariaLabel = t("welcome_text_line_4", ...getLink(pkg.funding.url))),
  144. "#bytm-welcome-text-line5": (e: HTMLElement) => setInnerHtml(e, e.ariaLabel = t("welcome_text_line_5", ...getLink(pkg.bugs.url))),
  145. };
  146. for(const [selector, fn] of Object.entries(changes)) {
  147. const el = document.querySelector<HTMLElement>(selector);
  148. if(!el) {
  149. warn(`Couldn't find element in welcome menu with selector '${selector}'`);
  150. continue;
  151. }
  152. fn(el);
  153. }
  154. }
  155. async function renderFooter() {
  156. const footerCont = document.createElement("div");
  157. footerCont.id = "bytm-welcome-menu-footer-cont";
  158. const openCfgElem = document.createElement("button");
  159. openCfgElem.id = "bytm-welcome-menu-open-cfg";
  160. openCfgElem.classList.add("bytm-btn");
  161. openCfgElem.addEventListener("click", () => {
  162. welcomeDialog?.close();
  163. openCfgMenu();
  164. });
  165. const openChangelogElem = document.createElement("button");
  166. openChangelogElem.id = "bytm-welcome-menu-open-changelog";
  167. openChangelogElem.classList.add("bytm-btn");
  168. openChangelogElem.addEventListener("click", async () => {
  169. const dlg = await getChangelogDialog();
  170. await dlg.mount();
  171. welcomeDialog?.close();
  172. await dlg.open();
  173. });
  174. const closeBtnElem = document.createElement("button");
  175. closeBtnElem.id = "bytm-welcome-menu-footer-close";
  176. closeBtnElem.classList.add("bytm-btn");
  177. closeBtnElem.addEventListener("click", async () => {
  178. welcomeDialog?.close();
  179. });
  180. const leftButtonsCont = document.createElement("div");
  181. leftButtonsCont.id = "bytm-menu-footer-left-buttons-cont";
  182. leftButtonsCont.appendChild(openCfgElem);
  183. leftButtonsCont.appendChild(openChangelogElem);
  184. footerCont.appendChild(leftButtonsCont);
  185. footerCont.appendChild(closeBtnElem);
  186. return footerCont;
  187. }