Skip to content

Commit

Permalink
Merge pull request #324 from matematikk-mooc/Therese-Persen-KURSP-890…
Browse files Browse the repository at this point in the history
…-create-reusable-modal-component

Therese persen kursp 890 create reusable modal component
  • Loading branch information
madsenandreas authored Oct 19, 2023
2 parents 76dc878 + b7715f2 commit 73c2243
Show file tree
Hide file tree
Showing 8 changed files with 343 additions and 7 deletions.
9 changes: 8 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{
"presets": ["@babel/preset-env"],
"plugins": ["handlebars-inline-precompile"]
"plugins": ["handlebars-inline-precompile",
[
"@vue/babel-plugin-jsx",
{
"mergeProps": false
}
]
]
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"@storybook/testing-library": "^0.2.0",
"@storybook/vue3": "^7.4.0",
"@storybook/vue3-webpack5": "^7.4.0",
"@vue/babel-helper-vue-jsx-merge-props": "^1.4.0",
"@vue/babel-plugin-jsx": "^1.1.5",
"@vue/cli": "^5.0.8",
"@vue/compiler-sfc": "^3.3.4",
"babel-loader": "^9.1.2",
Expand Down
8 changes: 4 additions & 4 deletions src/vue/components/icon-button/IconButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ const handleClick = () => {
background-color: map-get($color-palette-peach,background, 400);
color: $color-black;
border: none;
padding: 0.25rem;
font-size: 1.5rem;
height: 2rem;
width: 2rem;
padding: 0.125rem;
font-size: 1rem;
height: 1.25rem;
width: 1.25rem;
cursor: pointer;
transition: all 0.2s ease;
border-radius: 70%;
Expand Down
99 changes: 99 additions & 0 deletions src/vue/components/modal/Modal.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import Modal from './Modal.vue';
import Button from '../Button.vue';

export default {
title: 'Components/Modal',
component: Modal,
};

const Template = (args) => ({
components: { Modal, Button },
setup() {
return () => (
<Modal {...args}>
{{
header: () => <h2>This is the header content</h2>,
main: () => <div>This is the main content</div>,
actions: () => (
<>
<Button type="filled">Hello</Button>
<Button type="outlined">Goodbye</Button>
</>
),
}}
</Modal>
);
},
});

const TemplateWithoutHeader = (args) => ({
components: { Modal, Button },
setup() {
return () => (
<Modal {...args}>
{{
main: () => <div>This is the main content</div>,
actions: () => (
<>
<Button type="filled">Hello</Button>
<Button type="outlined">Goodbye</Button>
</>
),
}}
</Modal>
);
},
});

const TemplateWithoutActions = (args) => ({
components: { Modal, Button },
setup() {
return () => (
<Modal {...args}>
{{
header: () => <h2>This is the header content</h2>,
main: () => <div>This is the main content</div>,
}}
</Modal>
);
},
});

const TemplateWithoutMainContent = (args) => ({
components: { Modal, Button },
setup() {
return () => (
<Modal {...args}>
{{
header: () => <h2>This is the header content</h2>,
actions: () => (
<>
<Button type="filled">Hello</Button>
<Button type="outlined">Goodbye</Button>
</>
),
}}
</Modal>
);
},
});

export const Default = Template.bind({});
Default.args = {
isOpen: true,
};

export const WithoutHeader =TemplateWithoutHeader.bind({});
WithoutHeader.args = {
isOpen: true,
};

export const WithoutActions =TemplateWithoutActions.bind({});
WithoutActions.args = {
isOpen: true,
};

export const WithoutMainContent =TemplateWithoutMainContent.bind({});
WithoutMainContent.args = {
isOpen: true,
};
107 changes: 107 additions & 0 deletions src/vue/components/modal/Modal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<template>
<Transition name="fade" mode="out-in">
<div v-if="isOpen" :key="isOpen ? 'visible' : 'hidden'" class="backdrop" >

<div class="modal">
<div class="modal__close-button">
<IconButton @click="closeModal" />
</div>
<div class="modal__header">
<slot name="header" v-if="$slots.header" >
</slot>
</div>

<div class="modal__body" v-if="$slots.main" >
<slot name="main" >

</slot>
</div>

<div class="modal__actions" v-if="$slots.actions" >
<slot name="actions">
</slot>
</div>
</div>
</div>
</Transition>
</template>

<script setup>
import IconButton from '../icon-button/IconButton.vue';
import { ref, defineProps, defineEmits } from 'vue'
const { isOpen } = defineProps(['isOpen'])
const emit = defineEmits()
const closeModal = () => {
emit('close')
}
</script>

<style lang="scss">
@import "../../design/colors.scss";
.backdrop{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: $color-grey-100;
display: flex;
justify-content: center;
align-items: center;
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to, .fade-leave-active {
opacity: 0;
}
.modal{
position: relative;
background-color: $color-white;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
position: relative;
min-width: 30rem;
padding: 0 0.5rem 0.5rem 0.5rem;
&__close-button{
position:absolute;
right: 0.5rem;
top: 0.5rem;
}
&__header, h1, h2, h3 {
position:relative;
left: 0;
top:0;
color:$color-black;
font-size: 1.125rem;
font-family: Montserrat;
font-weight: 500;
word-wrap: break-word;
width: calc(100% - 1.25rem);
}
&__body, p {
color: $color-black;
font-size: 1rem;
font-family: Roboto;
font-weight: 400;
line-height: 1.25rem;
margin-bottom: 1rem;
word-wrap: break-word;
padding:0.5rem 0 0.5rem 0;
}
&__actions {
position: relative;
width: 100%;
display:flex;
justify-content:flex-end;
> * { margin: 0 0.125rem; }
}
}
</style>
37 changes: 37 additions & 0 deletions src/vue/components/modal/ModalExample.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import ModalExample from './ModalExample.vue';
import { defineComponent, ref } from 'vue';

export default {
title: 'Example/ModalExample',
component: ModalExample,
};


const Template = (args) =>
defineComponent({
components: { ModalExample },
setup() {
const modalOpen = ref(false);

const openModal = () => {
modalOpen.value = true;
};

const closeModal = () => {
modalOpen.value = false;
};

return {
modalOpen,
openModal,
closeModal,
};
},
template: `
<ModalExample />
`,
});

// Export the Template as a Story
export const Default = Template.bind({});
Default.args = {};
49 changes: 49 additions & 0 deletions src/vue/components/modal/ModalExample.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<template>
<div class="background">
<Button @click="openModal">Open Modal</Button>
<Modal :is-open="modalOpen" @close="closeModal">
<template v-slot:header>
<h2>This is the header content</h2>
</template>
<template v-slot:main>
<div>This is the main content</div>
</template>
<template v-slot:actions>
<Button type="filled">Hello</Button>
<Button type="outlined" @click="closeModal">Goodbye</Button>
</template>
</Modal>
</div>
</template>

<script setup>
import Modal from './Modal.vue'
import Button from '../Button.vue'
import { ref } from 'vue'
const modalOpen = ref(false)
const openModal = () => {
modalOpen.value = true
}
const closeModal = () => {
modalOpen.value = false
}
</script>

<style lang="scss">
@import "../../design/colors.scss";
.background{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: $color-grey-100;
display: flex;
justify-content: center;
align-items: center;
}
</style>
Loading

0 comments on commit 73c2243

Please sign in to comment.