mirror of https://github.com/halo-dev/halo-admin
Merge branch 'next' of github.com:halo-dev/halo-admin into next
commit
a49d03d025
|
@ -18,3 +18,4 @@ export * from "./components/dialog";
|
|||
export * from "./components/pagination";
|
||||
export * from "./components/codemirror";
|
||||
export * from "./components/empty";
|
||||
export * from "./components/status";
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<script lang="ts" setup>
|
||||
import StatusDot from "./StatusDot.vue";
|
||||
import { VSpace } from "../space";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story title="StatusDot">
|
||||
<Variant title="State">
|
||||
<template #default>
|
||||
<VSpace direction="column">
|
||||
<StatusDot state="default" text="默认" />
|
||||
|
||||
<StatusDot state="success" text="成功" />
|
||||
|
||||
<StatusDot state="warning" text="警告" />
|
||||
|
||||
<StatusDot state="error" text="错误" />
|
||||
</VSpace>
|
||||
</template>
|
||||
</Variant>
|
||||
<Variant title="Animate">
|
||||
<template #default>
|
||||
<VSpace direction="column">
|
||||
<StatusDot state="default" text="默认" animate />
|
||||
|
||||
<StatusDot state="success" text="成功" animate />
|
||||
|
||||
<StatusDot state="warning" text="警告" animate />
|
||||
|
||||
<StatusDot state="error" text="错误" animate />
|
||||
</VSpace>
|
||||
</template>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
|
@ -0,0 +1,92 @@
|
|||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import type { State } from "./interface";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
state?: State;
|
||||
animate?: boolean;
|
||||
text?: string;
|
||||
}>(),
|
||||
{ state: "success", animate: false, text: undefined }
|
||||
);
|
||||
|
||||
const classes = computed(() => {
|
||||
return [`status-dot-${props.state}`, { "status-dot-animate": props.animate }];
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="status-dot-wrapper" :class="classes">
|
||||
<div class="status-dot-body">
|
||||
<span class="status-dot-inner"></span>
|
||||
</div>
|
||||
<slot v-if="$slots.text || text" name="text">
|
||||
<span class="status-dot-text">{{ text }}</span>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.status-dot-wrapper {
|
||||
@apply flex items-center gap-2;
|
||||
|
||||
.status-dot-body {
|
||||
@apply inline-flex h-2 w-2 items-center justify-center rounded-full;
|
||||
}
|
||||
|
||||
.status-dot-inner {
|
||||
@apply inline-block h-1.5 w-1.5 rounded-full;
|
||||
}
|
||||
|
||||
.status-dot-text {
|
||||
@apply text-gray-500;
|
||||
}
|
||||
|
||||
&.status-dot-animate {
|
||||
.status-dot-inner {
|
||||
@apply animate-ping;
|
||||
}
|
||||
}
|
||||
|
||||
&.status-dot-default {
|
||||
.status-dot-body {
|
||||
@apply bg-gray-300;
|
||||
}
|
||||
|
||||
.status-dot-inner {
|
||||
@apply bg-gray-300;
|
||||
}
|
||||
}
|
||||
|
||||
&.status-dot-success {
|
||||
.status-dot-body {
|
||||
@apply bg-green-600;
|
||||
}
|
||||
|
||||
.status-dot-inner {
|
||||
@apply bg-green-600;
|
||||
}
|
||||
}
|
||||
|
||||
&.status-dot-warning {
|
||||
.status-dot-body {
|
||||
@apply bg-yellow-600;
|
||||
}
|
||||
|
||||
.status-dot-inner {
|
||||
@apply bg-yellow-600;
|
||||
}
|
||||
}
|
||||
|
||||
&.status-dot-error {
|
||||
.status-dot-body {
|
||||
@apply bg-red-600;
|
||||
}
|
||||
|
||||
.status-dot-inner {
|
||||
@apply bg-red-600;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,31 @@
|
|||
import { mount } from "@vue/test-utils";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { VStatusDot } from "../index";
|
||||
|
||||
describe("StatusDot", () => {
|
||||
it("should render", () => {
|
||||
expect(mount(VStatusDot)).toBeDefined();
|
||||
});
|
||||
|
||||
it("should match snapshot", () => {
|
||||
const wrapper = mount(VStatusDot);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should work with state prop", () => {
|
||||
["default", "success", "warning", "error"].forEach((state) => {
|
||||
const wrapper = mount(VStatusDot, { props: { state } });
|
||||
expect(wrapper.classes()).toContain(`status-dot-${state}`);
|
||||
});
|
||||
});
|
||||
|
||||
it("should work with animate prop", () => {
|
||||
const wrapper = mount(VStatusDot, { props: { animate: true } });
|
||||
expect(wrapper.classes()).toContain("status-dot-animate");
|
||||
});
|
||||
|
||||
it("should work with text prop", () => {
|
||||
const wrapper = mount(VStatusDot, { props: { text: "text" } });
|
||||
expect(wrapper.find(".status-dot-text").text()).toBe("text");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
// Vitest Snapshot v1
|
||||
|
||||
exports[`StatusDot > should match snapshot 1`] = `
|
||||
"<div class=\\"status-dot-wrapper status-dot-success\\">
|
||||
<div class=\\"status-dot-body\\"><span class=\\"status-dot-inner\\"></span></div>
|
||||
<!--v-if-->
|
||||
</div>"
|
||||
`;
|
|
@ -0,0 +1 @@
|
|||
export { default as VStatusDot } from "./StatusDot.vue";
|
|
@ -0,0 +1 @@
|
|||
export type State = "default" | "success" | "warning" | "error";
|
|
@ -16,6 +16,7 @@ import {
|
|||
VEmpty,
|
||||
IconCloseCircle,
|
||||
IconFolder,
|
||||
VStatusDot,
|
||||
} from "@halo-dev/components";
|
||||
import LazyImage from "@/components/image/LazyImage.vue";
|
||||
import UserDropdownSelector from "@/components/dropdown-selector/UserDropdownSelector.vue";
|
||||
|
@ -617,14 +618,11 @@ onMounted(() => {
|
|||
</EntityField>
|
||||
<EntityField v-if="attachment.metadata.deletionTimestamp">
|
||||
<template #description>
|
||||
<div
|
||||
<VStatusDot
|
||||
v-tooltip="`删除中`"
|
||||
class="inline-flex h-1.5 w-1.5 rounded-full bg-red-600"
|
||||
>
|
||||
<span
|
||||
class="inline-block h-1.5 w-1.5 animate-ping rounded-full bg-red-600"
|
||||
></span>
|
||||
</div>
|
||||
state="warning"
|
||||
animate
|
||||
/>
|
||||
</template>
|
||||
</EntityField>
|
||||
<EntityField
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
useDialog,
|
||||
VEmpty,
|
||||
VAvatar,
|
||||
VStatusDot,
|
||||
} from "@halo-dev/components";
|
||||
import SinglePageSettingModal from "./components/SinglePageSettingModal.vue";
|
||||
import UserDropdownSelector from "@/components/dropdown-selector/UserDropdownSelector.vue";
|
||||
|
@ -360,13 +361,7 @@ const handleSelectUser = (user?: User) => {
|
|||
}"
|
||||
class="flex items-center"
|
||||
>
|
||||
<div
|
||||
class="inline-flex h-1.5 w-1.5 rounded-full bg-orange-600"
|
||||
>
|
||||
<span
|
||||
class="inline-block h-1.5 w-1.5 animate-ping rounded-full bg-orange-600"
|
||||
></span>
|
||||
</div>
|
||||
<VStatusDot state="success" animate />
|
||||
</RouterLink>
|
||||
</template>
|
||||
</EntityField>
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
VPagination,
|
||||
VSpace,
|
||||
VAvatar,
|
||||
VStatusDot,
|
||||
} from "@halo-dev/components";
|
||||
import UserDropdownSelector from "@/components/dropdown-selector/UserDropdownSelector.vue";
|
||||
import PostSettingModal from "./components/PostSettingModal.vue";
|
||||
|
@ -768,13 +769,7 @@ function handleContributorFilterItemChange(user?: User) {
|
|||
}"
|
||||
class="flex items-center"
|
||||
>
|
||||
<div
|
||||
class="inline-flex h-1.5 w-1.5 rounded-full bg-orange-600"
|
||||
>
|
||||
<span
|
||||
class="inline-block h-1.5 w-1.5 animate-ping rounded-full bg-orange-600"
|
||||
></span>
|
||||
</div>
|
||||
<VStatusDot state="success" animate />
|
||||
</RouterLink>
|
||||
<PostTag
|
||||
v-for="(tag, tagIndex) in post.tags"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts" setup>
|
||||
import { IconList, VButton } from "@halo-dev/components";
|
||||
import { IconList, VButton, VStatusDot } from "@halo-dev/components";
|
||||
import Draggable from "vuedraggable";
|
||||
import type { CategoryTree } from "../utils";
|
||||
import { ref } from "vue";
|
||||
|
@ -68,14 +68,7 @@ function onDelete(category: CategoryTree) {
|
|||
<template #end>
|
||||
<EntityField v-if="category.metadata.deletionTimestamp">
|
||||
<template #description>
|
||||
<div
|
||||
v-tooltip="`删除中`"
|
||||
class="inline-flex h-1.5 w-1.5 rounded-full bg-red-600"
|
||||
>
|
||||
<span
|
||||
class="inline-block h-1.5 w-1.5 animate-ping rounded-full bg-red-600"
|
||||
></span>
|
||||
</div>
|
||||
<VStatusDot v-tooltip="`删除中`" state="warning" animate />
|
||||
</template>
|
||||
</EntityField>
|
||||
<EntityField
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
VEmpty,
|
||||
VPageHeader,
|
||||
VSpace,
|
||||
VStatusDot,
|
||||
} from "@halo-dev/components";
|
||||
import TagEditingModal from "./components/TagEditingModal.vue";
|
||||
import PostTag from "./components/PostTag.vue";
|
||||
|
@ -187,14 +188,7 @@ onMounted(async () => {
|
|||
<template #end>
|
||||
<EntityField v-if="tag.metadata.deletionTimestamp">
|
||||
<template #description>
|
||||
<div
|
||||
v-tooltip="`删除中`"
|
||||
class="inline-flex h-1.5 w-1.5 rounded-full bg-red-600"
|
||||
>
|
||||
<span
|
||||
class="inline-block h-1.5 w-1.5 animate-ping rounded-full bg-red-600"
|
||||
></span>
|
||||
</div>
|
||||
<VStatusDot v-tooltip="`删除中`" state="warning" animate />
|
||||
</template>
|
||||
</EntityField>
|
||||
<EntityField
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts" setup>
|
||||
import { IconList, VButton, VTag } from "@halo-dev/components";
|
||||
import { IconList, VButton, VTag, VStatusDot } from "@halo-dev/components";
|
||||
import Draggable from "vuedraggable";
|
||||
import { ref } from "vue";
|
||||
import type { MenuTreeItem } from "@/modules/interface/menus/utils";
|
||||
|
@ -89,14 +89,7 @@ function getMenuItemRefDisplayName(menuItem: MenuTreeItem) {
|
|||
<template #end>
|
||||
<EntityField v-if="menuItem.metadata.deletionTimestamp">
|
||||
<template #description>
|
||||
<div
|
||||
v-tooltip="`删除中`"
|
||||
class="inline-flex h-1.5 w-1.5 rounded-full bg-red-600"
|
||||
>
|
||||
<span
|
||||
class="inline-block h-1.5 w-1.5 animate-ping rounded-full bg-red-600"
|
||||
></span>
|
||||
</div>
|
||||
<VStatusDot v-tooltip="`删除中`" state="warning" animate />
|
||||
</template>
|
||||
</EntityField>
|
||||
</template>
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
VCard,
|
||||
VEmpty,
|
||||
VSpace,
|
||||
VStatusDot,
|
||||
} from "@halo-dev/components";
|
||||
import MenuEditingModal from "./MenuEditingModal.vue";
|
||||
import { defineExpose, onMounted, ref } from "vue";
|
||||
|
@ -156,14 +157,7 @@ defineExpose({
|
|||
<template #end>
|
||||
<EntityField v-if="menu.metadata.deletionTimestamp">
|
||||
<template #description>
|
||||
<div
|
||||
v-tooltip="`删除中`"
|
||||
class="inline-flex h-1.5 w-1.5 rounded-full bg-red-600"
|
||||
>
|
||||
<span
|
||||
class="inline-block h-1.5 w-1.5 animate-ping rounded-full bg-red-600"
|
||||
></span>
|
||||
</div>
|
||||
<VStatusDot v-tooltip="`删除中`" state="warning" animate />
|
||||
</template>
|
||||
</EntityField>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
<script lang="ts" setup>
|
||||
import { VButton, VSpace, VSwitch, VTag } from "@halo-dev/components";
|
||||
import {
|
||||
VButton,
|
||||
VSpace,
|
||||
VSwitch,
|
||||
VTag,
|
||||
VStatusDot,
|
||||
} from "@halo-dev/components";
|
||||
import Entity from "@/components/entity/Entity.vue";
|
||||
import EntityField from "@/components/entity/EntityField.vue";
|
||||
import { toRefs } from "vue";
|
||||
|
@ -54,14 +60,11 @@ const { isStarted, changeStatus, uninstall } = usePluginLifeCycle(plugin);
|
|||
<template #end>
|
||||
<EntityField v-if="plugin?.status?.phase === 'FAILED'">
|
||||
<template #description>
|
||||
<div
|
||||
<VStatusDot
|
||||
v-tooltip="`${plugin?.status?.reason}:${plugin?.status?.message}`"
|
||||
class="inline-flex h-1.5 w-1.5 rounded-full bg-red-600"
|
||||
>
|
||||
<span
|
||||
class="inline-block h-1.5 w-1.5 animate-ping rounded-full bg-red-600"
|
||||
></span>
|
||||
</div>
|
||||
state="error"
|
||||
animate
|
||||
/>
|
||||
</template>
|
||||
</EntityField>
|
||||
<EntityField>
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
VPagination,
|
||||
VSpace,
|
||||
VTag,
|
||||
VStatusDot,
|
||||
} from "@halo-dev/components";
|
||||
import RoleEditingModal from "./components/RoleEditingModal.vue";
|
||||
import Entity from "@/components/entity/Entity.vue";
|
||||
|
@ -227,14 +228,7 @@ const handleDelete = async (role: Role) => {
|
|||
<template #end>
|
||||
<EntityField v-if="role.metadata.deletionTimestamp">
|
||||
<template #description>
|
||||
<div
|
||||
v-tooltip="`删除中`"
|
||||
class="inline-flex h-1.5 w-1.5 rounded-full bg-red-600"
|
||||
>
|
||||
<span
|
||||
class="inline-block h-1.5 w-1.5 animate-ping rounded-full bg-red-600"
|
||||
></span>
|
||||
</div>
|
||||
<VStatusDot v-tooltip="`删除中`" state="warning" animate />
|
||||
</template>
|
||||
</EntityField>
|
||||
<EntityField description="0 个用户" />
|
||||
|
|
Loading…
Reference in New Issue