mirror of https://github.com/halo-dev/halo
parent
3853d55fd1
commit
c0e6267ccc
|
@ -0,0 +1,21 @@
|
|||
<script lang="ts" setup>
|
||||
import { VButton } from "@/components/base/button";
|
||||
import { VModal } from "@/components/base/modal";
|
||||
|
||||
function initState() {
|
||||
return {
|
||||
visible: false,
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Story title="Modal" :init-state="initState">
|
||||
<template #default="{ state }">
|
||||
<VButton type="secondary" @click="state.visible = true">打开</VButton>
|
||||
<VModal v-model:visible="state.visible" title="测试">
|
||||
Hello World
|
||||
<VButton type="secondary" @click="state.visible = false">关闭</VButton>
|
||||
</VModal>
|
||||
</template>
|
||||
</Story>
|
||||
</template>
|
|
@ -0,0 +1,161 @@
|
|||
<script lang="ts" setup>
|
||||
import { VButton } from "../button";
|
||||
import { computed } from "vue";
|
||||
import { IconClose } from "@/core/icons";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 500,
|
||||
},
|
||||
fullscreen: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
||||
const wrapperClasses = computed(() => {
|
||||
return {
|
||||
"modal-wrapper-fullscreen": props.fullscreen,
|
||||
};
|
||||
});
|
||||
|
||||
const contentStyles = computed(() => {
|
||||
return {
|
||||
maxWidth: props.width + "px",
|
||||
};
|
||||
});
|
||||
|
||||
function handleClose() {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<transition
|
||||
enter-active-class="ease-out"
|
||||
enter-from-class="opacity-0"
|
||||
enter-to-class="opacity-100"
|
||||
leave-active-class="ease-in"
|
||||
leave-from-class="opacity-100"
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<div
|
||||
v-show="visible"
|
||||
:class="wrapperClasses"
|
||||
aria-modal="true"
|
||||
class="modal-wrapper transform transition-all duration-200"
|
||||
role="dialog"
|
||||
tabindex="0"
|
||||
@keyup.esc="handleClose()"
|
||||
>
|
||||
<div class="modal-layer" @click="handleClose()" />
|
||||
<div :style="contentStyles" class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="modal-header-title">{{ title }}</div>
|
||||
<div class="modal-header-actions">
|
||||
<div class="modal-header-action" @click="handleClose()">
|
||||
<IconClose />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<slot />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<slot name="footer">
|
||||
<VButton @click="handleClose">关闭</VButton>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.modal-wrapper {
|
||||
@apply fixed;
|
||||
@apply top-0 left-0;
|
||||
@apply w-full h-full;
|
||||
@apply flex flex-row;
|
||||
@apply items-center justify-center;
|
||||
z-index: 99999;
|
||||
|
||||
.modal-layer {
|
||||
@apply flex-none;
|
||||
@apply absolute;
|
||||
@apply top-0 left-0;
|
||||
@apply w-full h-full;
|
||||
background: #9e9eaa;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply relative;
|
||||
@apply bg-white;
|
||||
@apply items-stretch;
|
||||
@apply shadow-xl;
|
||||
width: calc(100vw - 20px);
|
||||
max-height: calc(100vh - 20px);
|
||||
border-radius: 4px;
|
||||
|
||||
.modal-header {
|
||||
@apply flex;
|
||||
@apply justify-between;
|
||||
@apply border-b;
|
||||
|
||||
.modal-header-title {
|
||||
@apply self-center;
|
||||
@apply text-base;
|
||||
@apply font-bold;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.modal-header-actions {
|
||||
@apply self-center;
|
||||
@apply h-full;
|
||||
.modal-header-action {
|
||||
@apply cursor-pointer;
|
||||
padding: 12px 16px;
|
||||
|
||||
&:hover {
|
||||
@apply bg-gray-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
@apply overflow-x-hidden overflow-y-auto;
|
||||
word-wrap: break-word;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
@apply border-t;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&.modal-wrapper-fullscreen {
|
||||
.modal-content {
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
height: 100vh !important;
|
||||
max-height: 100vh !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,8 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { VModal } from "../index";
|
||||
|
||||
describe("Modal", () => {
|
||||
it("should render", () => {
|
||||
expect(VModal).toBeDefined();
|
||||
});
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
export { default as VModal } from "./Modal.vue";
|
|
@ -26,6 +26,9 @@ import IconEye from "~icons/ri/eye-line";
|
|||
import IconFolder from "~icons/ri/folder-2-line";
|
||||
// @ts-ignore
|
||||
import IconMore from "~icons/ri/more-line";
|
||||
// @ts-ignore
|
||||
import IconClose from "~icons/ri/close-line";
|
||||
|
||||
export {
|
||||
IconDashboard,
|
||||
IconArrowRight,
|
||||
|
@ -41,4 +44,5 @@ export {
|
|||
IconEye,
|
||||
IconFolder,
|
||||
IconMore,
|
||||
IconClose,
|
||||
};
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
<template>
|
||||
<FilledLayout> </FilledLayout>
|
||||
<FilledLayout>
|
||||
<VModal v-model:visible="visible" title="登录">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<VButton type="secondary" @click="visible = false">关闭</VButton>
|
||||
</div>
|
||||
<div>
|
||||
<VButton type="secondary" @click="visible = true">打开</VButton>
|
||||
</div>
|
||||
</div>
|
||||
</VModal>
|
||||
<VButton type="secondary" @click="visible = true">打开</VButton>
|
||||
</FilledLayout>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { FilledLayout } from "@/layouts";
|
||||
import { VModal } from "@/components/base/modal";
|
||||
import { VButton } from "@/components/base/button";
|
||||
import { ref } from "vue";
|
||||
const visible = ref(false);
|
||||
</script>
|
||||
|
|
Loading…
Reference in New Issue