Skip to content

Commit

Permalink
pkp/pkp-lib#10444 Change Dialog component styling
Browse files Browse the repository at this point in the history
  • Loading branch information
blesildaramirez committed Sep 25, 2024
1 parent 1bdd39c commit ebb1132
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 22 deletions.
8 changes: 8 additions & 0 deletions src/components/Modal/Dialog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ Dialog purpose is to display simple feedback like success and error messages. Or

Dialog are opened via method `openDialog` from [useModal](../?path=/docs/composables-usemodal--docs#opensidemodal) composable. Check out the props description for details.

## Styling

The style of the modal can be changed by passing the prop `type`. It accepts the following values:

- **`default`**: The standard modal style that uses primary color styling. This serves as the default value for the modal type.
- **`negative`**: Indicates a negative state, typically for error messages or alerts.
- **`success`**: Represents a positive state, often used for success notifications.

## Accessibility

To correctly handle accessibility (title, description) and focus management - [headless-ui](https://headlessui.com) library is used.
Expand Down
81 changes: 81 additions & 0 deletions src/components/Modal/Dialog.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,84 @@ export const DialogComplex = {
await user.click(canvas.getByText('Full Example'));
},
};

const ErrorBodyComponent = {
template: `
<span>Cancelling the invitation sent to Emma Stone will deactivate the acceptance link sent to her via email. Here are the invitation details:</span>
<ul class="list-disc ms-7">
<li>
<strong>Email Address:</strong> {email address}
</li>
<li>
<strong>Role:</strong> Reviewer
</li>
<li>
<strong>Status</strong> Invited on 17.05.2023
</li>
<li>
<strong>Affiliate:</strong> Stanford University
</li>
</ul>
`,
props: {
failedDoiActions: {type: Array, required: true},
},
};

export const NegativeState = {
args: {
buttonName: 'Show modal',
name: 'error',
title: 'Cancel Invitation',
bodyComponent: ErrorBodyComponent,
actions: [
{
label: 'Cancel Invitation',
isPrimary: true,
callback: (close) => {
// Simulate a server request
setTimeout(() => close(), 2000);
},
},
{
label: 'Cancel',
isWarnable: true,
callback: (close) => close(),
},
],
close: () => console.log('closed full example dialog'), // eslint-disable-line,
type: 'negative',
},
play: async ({canvasElement}) => {
// Assigns canvas to the component root element
const canvas = within(canvasElement);
const user = userEvent.setup();

await user.click(canvas.getByText('Show modal'));
},
};

export const SuccessState = {
args: {
buttonName: 'Show modal',
name: 'error',
title: "You've been added as a section editor in OJS",
message:
'Congratulations! As a section editor you might get access to more options in OJS. If you need any assistance in understanding the system, please click on "Help" buttons throughout the system to guide you through the interface.',
actions: [
{
label: 'View All Submissions',
callback: (close) => close(),
},
],
close: () => console.log('closed full example dialog'), // eslint-disable-line,
type: 'success',
},
play: async ({canvasElement}) => {
// Assigns canvas to the component root element
const canvas = within(canvasElement);
const user = userEvent.setup();

await user.click(canvas.getByText('Show modal'));
},
};
69 changes: 47 additions & 22 deletions src/components/Modal/Dialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,44 +27,39 @@
leave-from="opacity-100 translate-y-0 sm:scale-100"
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<DialogPanel
class="modal__panel modal__panel--dialog relative mx-3 w-10/12 max-w-3xl transform overflow-hidden rounded bg-secondary text-start shadow transition-all sm:my-8"
>
<DialogPanel :class="styles">
<div class="flex min-h-12 items-center">
<DialogTitle
v-if="title"
class="m-0 min-w-[1px] overflow-x-hidden overflow-ellipsis whitespace-nowrap px-4 py-2 text-xl-bold"
class="m-0 inline-flex min-w-[1px] items-center overflow-x-hidden overflow-ellipsis whitespace-nowrap px-8 pt-12 text-4xl-bold"
:class="icon ? 'pb-5' : 'pb-8'"
>
{{ title }}
<div v-if="icon" :class="iconStyles">
<Icon
:icon="icon"
:inline="true"
class="h-11 w-11 text-on-dark"
></Icon>
</div>
<span class="px-4">{{ title }}</span>
</DialogTitle>
<button
class="me-2 ms-auto cursor-pointer border-0 bg-transparent text-center"
@click="onClose"
>
<Icon
class="h-6 w-6 text-negative"
icon="Cancel"
:aria-hidden="true"
/>
<span class="-screenReader">
{{ t('common.close') }}
</span>
</button>
</div>
<div class="modal-content p-4">
<div class="modal-content" :class="icon ? 'px-24' : 'pt- px-12'">
<div v-html="message" />
<component
:is="bodyComponent"
v-if="bodyComponent"
v-bind="bodyProps"
/>
</div>
<div class="flex items-center justify-end p-4">
<div
class="flex items-center gap-x-4"
:class="icon ? 'p-10 ps-24' : 'p-12'"
>
<Spinner v-if="isLoading" />
<PkpButton
v-for="action in actions"
:key="action.label"
class="ms-2"
:element="action.element || 'button'"
:href="action.href || null"
:is-primary="action.isPrimary || null"
Expand All @@ -86,7 +81,7 @@
</template>

<script setup>
import {ref} from 'vue';
import {ref, computed} from 'vue';
import PkpButton from '@/components/Button/Button.vue';
import Spinner from '@/components/Spinner/Spinner.vue';
Expand Down Expand Up @@ -115,8 +110,38 @@ const props = defineProps({
actions: {type: Array, default: () => []},
/** Callback when dialog is being closed by close button or clicking outside of the modal */
close: {type: Function, default: null},
/** Defines the visual style of the modal: 'default' (primary color), 'negative', or 'success'. */
type: {
type: String,
default: () => 'default',
validator: (value) => ['default', 'negative', 'success'].includes(value),
},
});
const styles = computed(() => ({
'modal__panel modal__panel--dialog relative mx-3 w-10/12 max-w-3xl transform overflow-hidden rounded bg-secondary text-start shadow transition-all sm:my-8': true,
'border-s-[14px] border-primary': props.type === 'default',
'border-s-[14px] border-success': props.type === 'success',
'border-s-[14px] border-negative': props.type === 'negative',
}));
const icon = computed(() => {
switch (props.type) {
case 'negative':
return 'Cancel';
case 'success':
return 'Complete';
default:
return null;
}
});
const iconStyles = computed(() => ({
'flex h-12 w-12 items-center justify-center rounded-full': true,
'bg-success': props.type === 'success',
'bg-negative': props.type === 'negative',
}));
const emit = defineEmits(['close']);
const isLoading = ref(false);
Expand Down

0 comments on commit ebb1132

Please sign in to comment.