You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

250 lines
6.6 KiB

<template>
<NotificationGroup group="customModal">
<div class="fixed z-[100] top-0 inset-x-0 w-full">
<Notification
v-slot="{ notifications, close }"
enter="transform ease-out duration-300 transition"
enter-from="translate-y-2 opacity-0 sm:translate-y-4"
enter-to="translate-y-0 opacity-100 sm:translate-y-0"
leave="transition ease-in duration-500"
leave-from="opacity-100"
leave-to="opacity-0"
move="transition duration-500"
move-delay="delay-300"
>
<div
v-for="notification in notifications"
:key="notification.id"
class="w-full"
role="alert"
>
<div :class="overlayClasses">
<div :class="modalContainerClasses">
<div :class="modalContentClasses">
<span :class="titleClasses">{{ title }}</span>
<p :class="textClasses">{{ text }}</p>
<button
:class="option1ButtonClasses"
@click="handleOption1(close)"
>
{{ option1Text }}
</button>
<button
:class="option2ButtonClasses"
@click="handleOption2(close)"
>
{{ option2Text }}
</button>
<button
:class="option3ButtonClasses"
@click="handleOption3(close)"
>
{{ option3Text }}
</button>
<button
:class="cancelButtonClasses"
@click="handleCancel(close)"
>
Cancel
</button>
</div>
</div>
</div>
</div>
</Notification>
</div>
</NotificationGroup>
</template>
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
/**
* ChoiceButtonDialog Component
*
* A modal dialog component that displays a custom notification with multiple
* action buttons. This component uses the notification system to display
* a modal overlay with custom content and button handlers.
*
* Features:
* - Custom modal overlay with backdrop
* - Up to 3 action buttons with custom text and handlers
* - Cancel button with optional handler
* - Responsive design with proper z-indexing
* - Smooth enter/leave animations
*/
@Component
export default class PromptDialog extends Vue {
$notify!: (notification: unknown, timeout?: number) => void;
notify!: ReturnType<typeof createNotifyHelpers>;
title = "";
text = "";
option1Text = "";
option2Text = "";
option3Text = "";
onOption1?: () => void;
onOption2?: () => void;
onOption3?: () => void;
onCancel?: () => Promise<void>;
created() {
this.notify = createNotifyHelpers(this.$notify);
}
/**
* CSS classes for the modal overlay backdrop
*/
get overlayClasses(): string {
return "absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50";
}
/**
* CSS classes for the modal container
*/
get modalContainerClasses(): string {
return "flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg";
}
/**
* CSS classes for the modal content area
*/
get modalContentClasses(): string {
return "w-full px-6 py-6 text-slate-900 text-center";
}
/**
* CSS classes for the modal title
*/
get titleClasses(): string {
return "font-semibold text-lg";
}
/**
* CSS classes for the modal text content
*/
get textClasses(): string {
return "text-sm mb-2";
}
/**
* CSS classes for the primary action button (option 1)
*/
get option1ButtonClasses(): string {
return "block w-full text-center text-md font-bold capitalize bg-blue-800 text-white px-2 py-2 rounded-md mb-2";
}
/**
* CSS classes for the secondary action button (option 2)
*/
get option2ButtonClasses(): string {
return "block w-full text-center text-md font-bold capitalize bg-blue-700 text-white px-2 py-2 rounded-md mb-2";
}
/**
* CSS classes for the tertiary action button (option 3)
*/
get option3ButtonClasses(): string {
return "block w-full text-center text-md font-bold capitalize bg-blue-600 text-white px-2 py-2 rounded-md mb-2";
}
/**
* CSS classes for the cancel button
*/
get cancelButtonClasses(): string {
return "block w-full text-center text-md font-bold capitalize bg-slate-600 text-white px-2 py-2 rounded-md";
}
/**
* Opens the choice button dialog with the specified options
*
* @param options - Configuration object containing dialog content and handlers
*/
open(options: {
title: string;
text: string;
option1Text?: string;
option2Text?: string;
option3Text?: string;
onOption1?: () => void;
onOption2?: () => void;
onOption3?: () => void;
onCancel?: () => Promise<void>;
}) {
this.title = options.title;
this.text = options.text;
this.option1Text = options.option1Text || "";
this.option2Text = options.option2Text || "";
this.option3Text = options.option3Text || "";
this.onOption1 = options.onOption1;
this.onOption2 = options.onOption2;
this.onOption3 = options.onOption3;
this.onCancel = options.onCancel;
// Use customModal notification type instead of confirm
this.$notify(
{
group: "customModal",
type: "custom",
title: this.title,
text: this.text,
id: "choice-button-dialog",
},
TIMEOUTS.MODAL,
);
}
/**
* Handles the primary action button click
*
* @param close - Function to close the notification
*/
handleOption1(close: (id: string) => void) {
if (this.onOption1) {
this.onOption1();
}
close("string that does not matter");
}
/**
* Handles the secondary action button click
*
* @param close - Function to close the notification
*/
handleOption2(close: (id: string) => void) {
if (this.onOption2) {
this.onOption2();
}
close("string that does not matter");
}
/**
* Handles the tertiary action button click
*
* @param close - Function to close the notification
*/
handleOption3(close: (id: string) => void) {
if (this.onOption3) {
this.onOption3();
}
close("string that does not matter");
}
/**
* Handles the cancel button click
*
* @param close - Function to close the notification
*/
handleCancel(close: (id: string) => void) {
if (this.onCancel) {
this.onCancel();
}
close("string that does not matter");
}
}
</script>