UI boiler plate 만들기
baseDialog.vue
<template>
<teleport to="body">
<div v-if="show" @click="tryClose" class="backdrop"></div>
<transition name="dialog">
<dialog open v-if="show">
<header>
<slot name="header">
<h2>{{ title }}</h2>
</slot>
</header>
<section>
<slot></slot>
</section>
<menu v-if="!fixed">
<slot name="actions">
<base-button @click="tryClose">Close</base-button>
</slot>
</menu>
</dialog>
</transition>
</teleport>
</template>
<script>
export default {
props: {
show: {
type: Boolean,
required: true,
},
title: {
type: String,
required: false,
},
fixed: {
type: Boolean,
required: false,
default: false,
},
},
emits: ['close'],
methods: {
tryClose() {
if (this.fixed) {
return;
}
this.$emit('close');
},
},
};
</script>
<template>
<button v-if="!link" :class="mode">
<slot></slot>
</button>
<router-link v-else :to="to" :class="mode">
<slot></slot>
</router-link>
</template>
<script>
export default {
props: {
mode: {
type: String,
required: false,
default: null
},
link: {
type: Boolean,
required: false,
default: false
},
to: {
type: String,
required: false,
default: '/'
}
}
}
</script>
- <base-button link to='url'> 이런식으로 쓰이도록 만들었다.
baseSpinner.vue
<template>
<div class="spinner">
<div class="lds-roller">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</template>
<style scoped>
.spinner {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
}
.lds-roller {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.lds-roller div {
animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
transform-origin: 40px 40px;
}
.lds-roller div:after {
content: " ";
display: block;
position: absolute;
width: 7px;
height: 7px;
border-radius: 50%;
background: #3d008d;
margin: -4px 0 0 -4px;
}
.lds-roller div:nth-child(1) {
animation-delay: -0.036s;
}
.lds-roller div:nth-child(1):after {
top: 63px;
left: 63px;
}
.lds-roller div:nth-child(2) {
animation-delay: -0.072s;
}
.lds-roller div:nth-child(2):after {
top: 68px;
left: 56px;
}
.lds-roller div:nth-child(3) {
animation-delay: -0.108s;
}
.lds-roller div:nth-child(3):after {
top: 71px;
left: 48px;
}
.lds-roller div:nth-child(4) {
animation-delay: -0.144s;
}
.lds-roller div:nth-child(4):after {
top: 72px;
left: 40px;
}
.lds-roller div:nth-child(5) {
animation-delay: -0.18s;
}
.lds-roller div:nth-child(5):after {
top: 71px;
left: 32px;
}
.lds-roller div:nth-child(6) {
animation-delay: -0.216s;
}
.lds-roller div:nth-child(6):after {
top: 68px;
left: 24px;
}
.lds-roller div:nth-child(7) {
animation-delay: -0.252s;
}
.lds-roller div:nth-child(7):after {
top: 63px;
left: 17px;
}
.lds-roller div:nth-child(8) {
animation-delay: -0.288s;
}
.lds-roller div:nth-child(8):after {
top: 56px;
left: 12px;
}
@keyframes lds-roller {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>