mirror of https://github.com/halo-dev/halo-admin
parent
f522c4bbde
commit
db32465a04
|
@ -0,0 +1,91 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { VAlert } from "./index";
|
||||||
|
import { VButton } from "@/components/base/button";
|
||||||
|
import { IconMessage } from "@/core/icons";
|
||||||
|
|
||||||
|
function initState() {
|
||||||
|
return {
|
||||||
|
type: "default",
|
||||||
|
title: "提示",
|
||||||
|
description: "这是一个提示",
|
||||||
|
closable: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Story title="Alert">
|
||||||
|
<Variant title="Show Cases">
|
||||||
|
<template #default>
|
||||||
|
<div class="p-3">
|
||||||
|
<VAlert type="default" title="default" />
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<VAlert type="success" title="default" />
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<VAlert type="info" title="default" />
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<VAlert type="warning" title="default" />
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<VAlert type="error" title="default" />
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<VAlert type="default" title="提示">
|
||||||
|
<template #description>
|
||||||
|
目前仅支持远程 Git 仓库和 ZIP 下载链接。更多主题可以访问:
|
||||||
|
<a href="https://halo.run/themes">https://halo.run/themes</a>
|
||||||
|
</template>
|
||||||
|
<template #actions>
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<VButton type="default">访问</VButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</VAlert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Variant>
|
||||||
|
|
||||||
|
<Variant title="Playground" :init-state="initState">
|
||||||
|
<template #default="{ state }">
|
||||||
|
<div class="p-3">
|
||||||
|
<VAlert
|
||||||
|
:type="state.type"
|
||||||
|
:title="state.title"
|
||||||
|
:description="state.description"
|
||||||
|
:closable="state.closable"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #controls="{ state }">
|
||||||
|
<HstText v-model="state.type" title="Type" />
|
||||||
|
<HstText v-model="state.title" title="Title" />
|
||||||
|
<HstText v-model="state.description" title="Description" />
|
||||||
|
<HstCheckbox v-model="state.closable" title="Closable" />
|
||||||
|
</template>
|
||||||
|
</Variant>
|
||||||
|
|
||||||
|
<Variant title="Slots">
|
||||||
|
<template #default>
|
||||||
|
<div class="p-3">
|
||||||
|
<VAlert type="default" title="你有新的消息">
|
||||||
|
<template #icon>
|
||||||
|
<IconMessage />
|
||||||
|
</template>
|
||||||
|
<template #description>
|
||||||
|
@Ryan Wang 在你的站点创建了新评论
|
||||||
|
</template>
|
||||||
|
<template #actions>
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<VButton type="default">查看</VButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</VAlert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Variant>
|
||||||
|
</Story>
|
||||||
|
</template>
|
|
@ -0,0 +1,200 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { Component, PropType } from "vue";
|
||||||
|
import { computed } from "vue";
|
||||||
|
import type { Type } from "@/components/base/alert/interface";
|
||||||
|
import {
|
||||||
|
IconCheckboxCircle,
|
||||||
|
IconClose,
|
||||||
|
IconCloseCircle,
|
||||||
|
IconErrorWarning,
|
||||||
|
IconInformation,
|
||||||
|
} from "@/core/icons";
|
||||||
|
|
||||||
|
const TypeIcons: Record<Type, Component> = {
|
||||||
|
success: IconCheckboxCircle,
|
||||||
|
info: IconInformation,
|
||||||
|
default: IconInformation,
|
||||||
|
warning: IconErrorWarning,
|
||||||
|
error: IconCloseCircle,
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
type: {
|
||||||
|
type: String as PropType<Type>,
|
||||||
|
default: "default",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
closable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["close"]);
|
||||||
|
|
||||||
|
const classes = computed(() => {
|
||||||
|
return [`alert-${props.type}`];
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
emit("close");
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="classes" class="alert-wrapper">
|
||||||
|
<div class="alert-header">
|
||||||
|
<div class="alert-icon">
|
||||||
|
<slot name="icon">
|
||||||
|
<component :is="TypeIcons[type]" />
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
<div class="alert-title">
|
||||||
|
{{ title }}
|
||||||
|
</div>
|
||||||
|
<div v-if="closable" class="alert-close" @click="handleClose">
|
||||||
|
<IconClose />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="description || $slots.description" class="alert-description">
|
||||||
|
<slot name="description">
|
||||||
|
{{ description }}
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
<div v-if="$slots.actions" class="alert-actions">
|
||||||
|
<slot name="actions" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.alert-wrapper {
|
||||||
|
@apply flex;
|
||||||
|
@apply flex-col;
|
||||||
|
@apply box-border;
|
||||||
|
@apply border;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
.alert-header {
|
||||||
|
@apply flex;
|
||||||
|
|
||||||
|
.alert-icon {
|
||||||
|
@apply self-center;
|
||||||
|
@apply mr-3;
|
||||||
|
@apply text-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-title {
|
||||||
|
@apply self-center;
|
||||||
|
@apply mr-3;
|
||||||
|
@apply flex-1;
|
||||||
|
@apply font-medium;
|
||||||
|
@apply text-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-close {
|
||||||
|
@apply self-center;
|
||||||
|
@apply cursor-pointer;
|
||||||
|
@apply rounded-full;
|
||||||
|
@apply p-0.5;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@apply transition-all;
|
||||||
|
@apply bg-gray-300;
|
||||||
|
@apply text-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-description {
|
||||||
|
@apply text-sm;
|
||||||
|
@apply mt-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-actions {
|
||||||
|
@apply border-t;
|
||||||
|
@apply pt-2 mt-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.alert-default {
|
||||||
|
@apply bg-gray-50;
|
||||||
|
@apply border-gray-300;
|
||||||
|
|
||||||
|
.alert-icon,
|
||||||
|
.alert-description {
|
||||||
|
@apply text-gray-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-close,
|
||||||
|
.alert-title {
|
||||||
|
@apply text-gray-700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.alert-success {
|
||||||
|
@apply bg-green-50;
|
||||||
|
@apply border-green-300;
|
||||||
|
|
||||||
|
.alert-icon,
|
||||||
|
.alert-description {
|
||||||
|
@apply text-green-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-close,
|
||||||
|
.alert-title {
|
||||||
|
@apply text-green-700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.alert-info {
|
||||||
|
@apply bg-sky-50;
|
||||||
|
@apply border-sky-300;
|
||||||
|
|
||||||
|
.alert-icon,
|
||||||
|
.alert-description {
|
||||||
|
@apply text-sky-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-close,
|
||||||
|
.alert-title {
|
||||||
|
@apply text-sky-700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.alert-warning {
|
||||||
|
@apply bg-orange-50;
|
||||||
|
@apply border-orange-300;
|
||||||
|
|
||||||
|
.alert-icon,
|
||||||
|
.alert-description {
|
||||||
|
@apply text-orange-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-close,
|
||||||
|
.alert-title {
|
||||||
|
@apply text-orange-700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.alert-error {
|
||||||
|
@apply bg-red-50;
|
||||||
|
@apply border-red-300;
|
||||||
|
|
||||||
|
.alert-icon,
|
||||||
|
.alert-description {
|
||||||
|
@apply text-red-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-close,
|
||||||
|
.alert-title {
|
||||||
|
@apply text-red-700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { VAlert } from "../index";
|
||||||
|
|
||||||
|
describe("Alert", () => {
|
||||||
|
it("should render", () => {
|
||||||
|
expect(VAlert).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as VAlert } from "./Alert.vue";
|
|
@ -0,0 +1 @@
|
||||||
|
export type Type = "default" | "success" | "info" | "warning" | "error";
|
|
@ -28,6 +28,14 @@ import IconFolder from "~icons/ri/folder-2-line";
|
||||||
import IconMore from "~icons/ri/more-line";
|
import IconMore from "~icons/ri/more-line";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import IconClose from "~icons/ri/close-line";
|
import IconClose from "~icons/ri/close-line";
|
||||||
|
// @ts-ignore
|
||||||
|
import IconErrorWarning from "~icons/ri/error-warning-line";
|
||||||
|
// @ts-ignore
|
||||||
|
import IconCheckboxCircle from "~icons/ri/checkbox-circle-line";
|
||||||
|
// @ts-ignore
|
||||||
|
import IconInformation from "~icons/ri/information-line";
|
||||||
|
// @ts-ignore
|
||||||
|
import IconCloseCircle from "~icons/ri/close-circle-line";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
IconDashboard,
|
IconDashboard,
|
||||||
|
@ -45,4 +53,8 @@ export {
|
||||||
IconFolder,
|
IconFolder,
|
||||||
IconMore,
|
IconMore,
|
||||||
IconClose,
|
IconClose,
|
||||||
|
IconErrorWarning,
|
||||||
|
IconCheckboxCircle,
|
||||||
|
IconInformation,
|
||||||
|
IconCloseCircle,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue