Przeglądaj źródła

feat: lots of prompt dialog improvements

Sv443 7 miesięcy temu
rodzic
commit
b7f2d7b829

+ 19 - 3
contributing.md

@@ -1981,9 +1981,15 @@ Functions marked with 🔒 need to be passed a per-session and per-plugin authen
 > Additionally, the property `defaultValue` can be used to set the preset value for the input field.  
 >   
 > Properties:  
-> - `message: string` - The message to show in the prompt
+> - `message: string | ((type: string) => string | Promise<string>)` - The message to show in the prompt
 > - `type: "confirm" | "alert" | "prompt"` - The type of the prompt. Can be "confirm", "alert" or "prompt"
-> - `defaultValue?: string` - The default value for the input field (only when using type "prompt")
+> - for type "prompt" only:
+>   - `defaultValue?: string` - The default value for the input field (only has an effect when using type "prompt")
+> - for overriding button text and tooltips:
+>   - `confirmBtnText?: string | ((type: string) => string | Promise<string>)` - Text for the confirm button (only when using type "confirm" or "prompt")
+>   - `confirmBtnTooltip?: string | ((type: string) => string | Promise<string>)` - Tooltip for the confirm button (only when using type "confirm" or "prompt")
+>   - `denyBtnText?: string | ((type: string) => string | Promise<string>)` - Text for the deny button (shows up for all types)
+>   - `denyBtnTooltip?: string | ((type: string) => string | Promise<string>)` - Tooltip for the deny button (shows up for all types)
 >   
 > <details><summary><b>Example <i>(click to expand)</i></b></summary>
 > 
@@ -1991,19 +1997,29 @@ Functions marked with 🔒 need to be passed a per-session and per-plugin authen
 > const itemName = await unsafeWindow.BYTM.showPrompt({
 >   type: "prompt",
 >   message: "Enter the name of the item to delete:",
+>   // default value for the input field:
 >   defaultValue: "My Item",
 > });
 > 
 > const confirmed = itemName && await unsafeWindow.BYTM.showPrompt({
 >   type: "confirm",
 >   message: "Are you sure you want to delete this?",
+>   confirmBtnText: "Yes, delete",
+>   denyBtnText: "No, cancel",
+>   // can also be sync or async functions:
+>   confirmBtnTooltip: () => "Click to confirm the deletion",
+>   // and the type parameter can be used for further customization:
+>   denyBtnTooltip: async (type: "confirm" | "alert" | "prompt") => await getText(`prompts.${type}.cancel_deletion`),
 > });
 > 
 > if(confirmed && itemName) {
 >   await deleteItem(itemName);
 >   unsafeWindow.BYTM.showPrompt({
 >     type: "alert",
->     message: `Deleted "${itemName}" successfully.`,
+>     message: () => `Deleted "${itemName}" successfully.`,
+>     // only the deny button is shown in alerts:
+>     denyBtnText: "Sure thing",
+>     denyBtnTooltip: "Click to close the dialog, bud",
 >   });
 > }
 > else

+ 8 - 0
dist/BetterYTM.css

@@ -370,6 +370,10 @@
     var(--bytm-dialog-border-radius);
 }
 
+.bytm-dialog-footer-cont.small {
+  padding: 15px;
+}
+
 .bytm-dialog-footer-buttons-cont button:not(:last-of-type) {
   margin-right: 15px;
 }
@@ -917,6 +921,10 @@ body .bytm-ripple.slower {
   gap: 15px;
 }
 
+#bytm-prompt-dialog-buttons-cont button {
+  cursor: pointer;
+}
+
 .bytm-prompt-dialog-button {
   padding: 2px 6px;
   font-size: 1.45rem;

+ 4 - 0
src/components/BytmDialog.css

@@ -194,6 +194,10 @@
     var(--bytm-dialog-border-radius);
 }
 
+.bytm-dialog-footer-cont.small {
+  padding: 15px;
+}
+
 .bytm-dialog-footer-buttons-cont button:not(:last-of-type) {
   margin-right: 15px;
 }

+ 1 - 0
src/components/BytmDialog.ts

@@ -383,6 +383,7 @@ export class BytmDialog extends NanoEmitter<BytmDialogEvents> {
     if(footer) {
       const footerWrapper = document.createElement("div");
       footerWrapper.classList.add("bytm-dialog-footer-cont");
+      this.options.small && footerWrapper.classList.add("small");
       dialogWrapperEl.appendChild(footerWrapper);
       footerWrapper.appendChild(footer instanceof Promise ? await footer : footer);
     }

+ 4 - 0
src/dialogs/prompt.css

@@ -37,6 +37,10 @@
   gap: 15px;
 }
 
+#bytm-prompt-dialog-buttons-cont button {
+  cursor: pointer;
+}
+
 .bytm-prompt-dialog-button {
   padding: 2px 6px;
   font-size: 1.45rem;

+ 23 - 9
src/dialogs/prompt.ts

@@ -4,8 +4,12 @@ import { getOS, resourceAsString, setInnerHtml, t } from "../utils/index.js";
 import { BytmDialog, type BytmDialogEvents } from "../components/index.js";
 import "./prompt.css";
 
+type PromptStringGen = Stringifiable | ((type: PromptType) => Stringifiable | Promise<Stringifiable>);
+
 export type PromptDialogRenderProps = ConfirmRenderProps | AlertRenderProps | PromptRenderProps;
 
+export type PromptType = PromptDialogRenderProps["type"];
+
 type ConfirmRenderProps = BaseRenderProps & {
   type: "confirm";
 };
@@ -20,7 +24,11 @@ type PromptRenderProps = BaseRenderProps & {
 };
 
 type BaseRenderProps = {
-  message: Stringifiable;
+  message: PromptStringGen;
+  confirmBtnText?: PromptStringGen;
+  confirmBtnTooltip?: PromptStringGen;
+  denyBtnText?: PromptStringGen;
+  denyBtnTooltip?: PromptStringGen;
 };
 
 export type ShowPromptProps = Partial<PromptDialogRenderProps> & Required<Pick<PromptDialogRenderProps, "message">>;
@@ -48,7 +56,7 @@ class PromptDialog extends BytmDialog {
     });
   }
 
-  async renderHeader({ type }: PromptDialogRenderProps) {
+  protected async renderHeader({ type }: PromptDialogRenderProps) {
     const headerEl = document.createElement("div");
     headerEl.id = "bytm-prompt-dialog-header";
     const iconSvg = await resourceAsString(type === "alert" ? "icon-alert" : "icon-confirm");
@@ -58,7 +66,7 @@ class PromptDialog extends BytmDialog {
     return headerEl;
   }
 
-  async renderBody({ type, message, ...rest }: PromptDialogRenderProps) {
+  protected async renderBody({ type, message, ...rest }: PromptDialogRenderProps) {
     const contElem = document.createElement("div");
     contElem.classList.add(`bytm-prompt-type-${type}`);
 
@@ -88,7 +96,7 @@ class PromptDialog extends BytmDialog {
     return contElem;
   }
 
-  async renderFooter({ type }: PromptDialogRenderProps) {
+  protected async renderFooter({ type, ...rest }: PromptDialogRenderProps) {
     const resolve = (val: boolean | string | null) => (this.events as PromptDialogEmitter).emit("resolve", val);
 
     const buttonsWrapper = document.createElement("div");
@@ -102,8 +110,8 @@ class PromptDialog extends BytmDialog {
       confirmBtn = document.createElement("button");
       confirmBtn.id = "bytm-prompt-dialog-confirm";
       confirmBtn.classList.add("bytm-prompt-dialog-button");
-      confirmBtn.textContent = t("prompt_confirm");
-      confirmBtn.ariaLabel = confirmBtn.title = t("click_to_confirm_tooltip");
+      confirmBtn.textContent = await this.consumePromptStringGen(type, rest.confirmBtnText, t("prompt_confirm"));
+      confirmBtn.ariaLabel = confirmBtn.title = await this.consumePromptStringGen(type, rest.confirmBtnTooltip, t("click_to_confirm_tooltip"));
       confirmBtn.tabIndex = 0;
       confirmBtn.autofocus = type === "confirm";
       confirmBtn.addEventListener("click", () => {
@@ -115,13 +123,13 @@ class PromptDialog extends BytmDialog {
     const closeBtn = document.createElement("button");
     closeBtn.id = "bytm-prompt-dialog-close";
     closeBtn.classList.add("bytm-prompt-dialog-button");
-    closeBtn.textContent = t(type === "alert" ? "prompt_close" : "prompt_cancel");
-    closeBtn.ariaLabel = closeBtn.title = t(type === "alert" ? "click_to_close_tooltip" : "click_to_cancel_tooltip");
+    closeBtn.textContent = await this.consumePromptStringGen(type, rest.denyBtnText, t(type === "alert" ? "prompt_close" : "prompt_cancel"));
+    closeBtn.ariaLabel = closeBtn.title = await this.consumePromptStringGen(type, rest.denyBtnTooltip, t(type === "alert" ? "click_to_close_tooltip" : "click_to_cancel_tooltip"));
     closeBtn.tabIndex = 0;
     if(type === "alert")
       closeBtn.autofocus = true;
     closeBtn.addEventListener("click", () => {
-      const resVals: Record<PromptDialogRenderProps["type"], boolean | null> = {
+      const resVals: Record<PromptType, boolean | null> = {
         alert: true,
         confirm: false,
         prompt: null,
@@ -138,6 +146,12 @@ class PromptDialog extends BytmDialog {
 
     return buttonsWrapper;
   }
+
+  protected async consumePromptStringGen(type: PromptType, txtGen?: PromptStringGen, fallback?: Stringifiable): Promise<string> {
+    if(typeof txtGen === "function")
+      return await txtGen(type);
+    return String(txtGen ?? fallback);
+  }
 }
 
 /** Shows a confirm() or alert() prompt dialog of the specified type and resolves true if the user confirms it or false if they cancel it - always resolves true with type "alert" */