mirror of https://github.com/halo-dev/halo-admin
feat: add space component and test case
Signed-off-by: Ryan Wang <i@ryanc.cc>pull/581/head
parent
19c74b3cde
commit
d35c973f0c
|
@ -0,0 +1,65 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { Align, Direction, Spacing } from "./interface";
|
||||||
|
import { SpacingSize } from "./interface";
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
spacing: {
|
||||||
|
type: String as PropType<Spacing>,
|
||||||
|
default: "xs",
|
||||||
|
},
|
||||||
|
direction: {
|
||||||
|
type: String as PropType<Direction>,
|
||||||
|
default: "row",
|
||||||
|
},
|
||||||
|
align: {
|
||||||
|
type: String as PropType<Align>,
|
||||||
|
default: "center",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const wrapperClasses = computed(() => {
|
||||||
|
const { direction, align } = props;
|
||||||
|
return [`space-direction-${direction}`, `space-align-${align}`];
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="space-wrapper"
|
||||||
|
:class="wrapperClasses"
|
||||||
|
:style="`gap: ${SpacingSize[spacing]}px`"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style lang="scss">
|
||||||
|
.space-wrapper {
|
||||||
|
@apply inline-flex;
|
||||||
|
@apply box-border;
|
||||||
|
|
||||||
|
&.space-direction-row {
|
||||||
|
@apply flex-row;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.space-direction-column {
|
||||||
|
@apply flex-col;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.space-align-center {
|
||||||
|
@apply items-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.space-align-start {
|
||||||
|
@apply items-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.space-align-end {
|
||||||
|
@apply items-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.space-align-stretch {
|
||||||
|
@apply items-stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { VSpace } from "../index";
|
||||||
|
import { mount } from "@vue/test-utils";
|
||||||
|
import { SpacingSize } from "../interface";
|
||||||
|
|
||||||
|
describe("Space", () => {
|
||||||
|
it("should render", function () {
|
||||||
|
expect(VSpace).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should work with spacing prop", function () {
|
||||||
|
Object.keys(SpacingSize).forEach((key: string) => {
|
||||||
|
const wrapper = mount(VSpace, {
|
||||||
|
propsData: {
|
||||||
|
spacing: key,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.attributes()["style"]).toContain(
|
||||||
|
`gap: ${SpacingSize[key]}px`
|
||||||
|
);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should work with direction prop", function () {
|
||||||
|
["row", "column"].forEach((direction: string) => {
|
||||||
|
const wrapper = mount(VSpace, {
|
||||||
|
propsData: {
|
||||||
|
direction: direction,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.classes()).toContain(`space-direction-${direction}`);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should work with align prop", function () {
|
||||||
|
["center", "start", "end", "stretch"].forEach((align: string) => {
|
||||||
|
const wrapper = mount(VSpace, {
|
||||||
|
propsData: {
|
||||||
|
align: align,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.classes()).toContain(`space-align-${align}`);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as VSpace } from "./Space.vue";
|
|
@ -0,0 +1,9 @@
|
||||||
|
export type Spacing = "xs" | "sm" | "md" | "lg";
|
||||||
|
export type Direction = "row" | "column";
|
||||||
|
export type Align = "start" | "end" | "center" | "stretch";
|
||||||
|
export const SpacingSize: Record<string, number> = {
|
||||||
|
xs: 10,
|
||||||
|
sm: 12,
|
||||||
|
md: 16,
|
||||||
|
lg: 20,
|
||||||
|
};
|
|
@ -22,6 +22,8 @@ import IconSettings from "~icons/ri/settings-4-line";
|
||||||
import IconPlug from "~icons/ri/plug-2-line";
|
import IconPlug from "~icons/ri/plug-2-line";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import IconEye from "~icons/ri/eye-line";
|
import IconEye from "~icons/ri/eye-line";
|
||||||
|
// @ts-ignore
|
||||||
|
import IconFolder from "~icons/ri/folder-2-line";
|
||||||
export {
|
export {
|
||||||
IconDashboard,
|
IconDashboard,
|
||||||
IconArrowRight,
|
IconArrowRight,
|
||||||
|
@ -35,4 +37,5 @@ export {
|
||||||
IconSettings,
|
IconSettings,
|
||||||
IconPlug,
|
IconPlug,
|
||||||
IconEye,
|
IconEye,
|
||||||
|
IconFolder,
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
IconPlug,
|
IconPlug,
|
||||||
IconSettings,
|
IconSettings,
|
||||||
IconUserSettings,
|
IconUserSettings,
|
||||||
|
IconFolder,
|
||||||
} from "@/core/icons";
|
} from "@/core/icons";
|
||||||
import type { Component } from "vue";
|
import type { Component } from "vue";
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ export const menus: MenuGroupType[] = [
|
||||||
{
|
{
|
||||||
name: "附件",
|
name: "附件",
|
||||||
path: "/attachment",
|
path: "/attachment",
|
||||||
icon: IconDashboard,
|
icon: IconFolder,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,76 +5,89 @@
|
||||||
<h1 class="text-xl font-bold mb-2">Button</h1>
|
<h1 class="text-xl font-bold mb-2">Button</h1>
|
||||||
<h2 class="mb-1">Type:</h2>
|
<h2 class="mb-1">Type:</h2>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<VButton class="mr-2" type="primary">Primary</VButton>
|
<VSpace>
|
||||||
<VButton class="mr-2" type="secondary">Secondary</VButton>
|
<VButton type="primary">Primary</VButton>
|
||||||
<VButton class="mr-2" type="danger">Danger</VButton>
|
<VButton type="secondary">Secondary</VButton>
|
||||||
<VButton type="default">Default</VButton>
|
<VButton type="danger">Danger</VButton>
|
||||||
|
<VButton type="default">Default</VButton>
|
||||||
|
</VSpace>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="mb-1">Size:</h2>
|
<h2 class="mb-1">Size:</h2>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<VButton class="mr-2" size="lg" type="secondary">Large</VButton>
|
<VSpace>
|
||||||
<VButton class="mr-2" type="secondary"> Default</VButton>
|
<VButton size="lg" type="secondary">Large</VButton>
|
||||||
<VButton class="mr-2" size="sm" type="secondary"> sm</VButton>
|
<VButton type="secondary"> Default</VButton>
|
||||||
<VButton size="xs" type="secondary"> xs</VButton>
|
<VButton size="sm" type="secondary"> sm</VButton>
|
||||||
|
<VButton size="xs" type="secondary"> xs</VButton>
|
||||||
|
</VSpace>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="mb-1">Circle:</h2>
|
<h2 class="mb-1">Circle:</h2>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<VButton circle class="mr-2" size="lg" type="secondary"> lg</VButton>
|
<VSpace>
|
||||||
<VButton circle class="mr-2" type="secondary"> d</VButton>
|
<VButton circle size="lg" type="secondary"> lg</VButton>
|
||||||
<VButton circle class="mr-2" size="sm" type="secondary"> sm</VButton>
|
<VButton circle type="secondary"> d</VButton>
|
||||||
<VButton circle size="xs" type="secondary"> xs</VButton>
|
<VButton circle size="sm" type="secondary"> sm</VButton>
|
||||||
|
<VButton circle size="xs" type="secondary"> xs</VButton>
|
||||||
|
</VSpace>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="mb-1">Block:</h2>
|
<h2 class="mb-1">Block:</h2>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<VButton block class="mb-2" type="primary"> Primary</VButton>
|
<VSpace direction="column" class="w-full">
|
||||||
<VButton block class="mb-2" type="secondary"> Secondary</VButton>
|
<VButton block type="primary"> Primary</VButton>
|
||||||
<VButton block type="danger"> Danger</VButton>
|
<VButton block type="secondary"> Secondary</VButton>
|
||||||
|
<VButton block type="danger"> Danger</VButton>
|
||||||
|
</VSpace>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="mb-1">Disabled:</h2>
|
<h2 class="mb-1">Disabled:</h2>
|
||||||
<div>
|
<div>
|
||||||
<VButton class="mr-2" disabled type="primary"> Primary</VButton>
|
<VSpace>
|
||||||
<VButton class="mr-2" disabled type="secondary"> Secondary</VButton>
|
<VButton disabled type="primary"> Primary</VButton>
|
||||||
<VButton disabled type="danger"> Danger</VButton>
|
<VButton disabled type="secondary"> Secondary</VButton>
|
||||||
|
<VButton disabled type="danger"> Danger</VButton>
|
||||||
|
</VSpace>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="mb-1">Loading:</h2>
|
<h2 class="mb-1">Loading:</h2>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<VButton class="mr-2" type="primary" :loading="buttonLoading">
|
<VSpace>
|
||||||
Primary
|
<VButton type="default" @click="buttonLoading = !buttonLoading">
|
||||||
</VButton>
|
{{ buttonLoading ? "停止" : "启动" }}
|
||||||
<VButton class="mr-2" type="secondary" :loading="buttonLoading">
|
</VButton>
|
||||||
Secondary
|
<VButton type="primary" :loading="buttonLoading"> Primary </VButton>
|
||||||
</VButton>
|
<VButton type="secondary" :loading="buttonLoading">
|
||||||
<VButton class="mr-2" type="danger" :loading="buttonLoading">
|
Secondary
|
||||||
Danger
|
</VButton>
|
||||||
</VButton>
|
<VButton type="danger" :loading="buttonLoading"> Danger </VButton>
|
||||||
<VButton type="default" :loading="buttonLoading"> Default </VButton>
|
<VButton type="default" :loading="buttonLoading"> Default </VButton>
|
||||||
|
</VSpace>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="mb-1">Icon:</h2>
|
<h2 class="mb-1">Icon:</h2>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<VButton class="mr-2" size="lg" type="secondary">
|
<VSpace>
|
||||||
<template #icon>
|
<VButton size="lg" type="secondary">
|
||||||
<IconSettings />
|
<template #icon>
|
||||||
</template>
|
<IconSettings />
|
||||||
Large
|
</template>
|
||||||
</VButton>
|
Large
|
||||||
<VButton class="mr-2" type="secondary">
|
</VButton>
|
||||||
<template #icon>
|
<VButton type="secondary">
|
||||||
<IconSettings />
|
<template #icon>
|
||||||
</template>
|
<IconSettings />
|
||||||
Default
|
</template>
|
||||||
</VButton>
|
Default
|
||||||
<VButton class="mr-2" size="sm" type="secondary">
|
</VButton>
|
||||||
<template #icon>
|
<VButton size="sm" type="secondary">
|
||||||
<IconSettings />
|
<template #icon>
|
||||||
</template>
|
<IconSettings />
|
||||||
sm
|
</template>
|
||||||
</VButton>
|
sm
|
||||||
<VButton size="xs" type="secondary">
|
</VButton>
|
||||||
<template #icon>
|
<VButton size="xs" type="secondary">
|
||||||
<IconSettings />
|
<template #icon>
|
||||||
</template>
|
<IconSettings />
|
||||||
xs
|
</template>
|
||||||
</VButton>
|
xs
|
||||||
|
</VButton>
|
||||||
|
</VSpace>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="box border-2 rounded p-2 mb-3">
|
<section class="box border-2 rounded p-2 mb-3">
|
||||||
|
@ -193,6 +206,44 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section class="box border-2 rounded p-2 mb-3">
|
||||||
|
<h1 class="text-xl font-bold mb-2">Space</h1>
|
||||||
|
<div class="mb-3">
|
||||||
|
<VRadio
|
||||||
|
v-for="(option, index) in ['row', 'column']"
|
||||||
|
:key="index"
|
||||||
|
v-model="spaceState.direction"
|
||||||
|
:label="option"
|
||||||
|
:value="option"
|
||||||
|
name="direction"
|
||||||
|
></VRadio>
|
||||||
|
<VRadio
|
||||||
|
v-for="(option, index) in ['start', 'center', 'end', 'stretch']"
|
||||||
|
:key="index"
|
||||||
|
v-model="spaceState.align"
|
||||||
|
:label="option"
|
||||||
|
:value="option"
|
||||||
|
name="align"
|
||||||
|
></VRadio>
|
||||||
|
<VRadio
|
||||||
|
v-for="(option, index) in ['xs', 'sm', 'md', 'lg']"
|
||||||
|
:key="index"
|
||||||
|
v-model="spaceState.spacing"
|
||||||
|
:label="option"
|
||||||
|
:value="option"
|
||||||
|
name="spacing"
|
||||||
|
></VRadio>
|
||||||
|
<VSpace
|
||||||
|
:direction="spaceState.direction"
|
||||||
|
:spacing="spaceState.spacing"
|
||||||
|
:align="spaceState.align"
|
||||||
|
>
|
||||||
|
<div>Control:</div>
|
||||||
|
<VButton type="primary">确定</VButton>
|
||||||
|
<VButton>取消</VButton>
|
||||||
|
</VSpace>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</FilledLayout>
|
</FilledLayout>
|
||||||
</template>
|
</template>
|
||||||
|
@ -206,7 +257,13 @@ import { VOption, VSelect } from "@/components/base/select";
|
||||||
import { VTextarea } from "@/components/base/textarea";
|
import { VTextarea } from "@/components/base/textarea";
|
||||||
import { VRadio, VRadioGroup } from "@/components/base/radio";
|
import { VRadio, VRadioGroup } from "@/components/base/radio";
|
||||||
import { VCheckbox, VCheckboxGroup } from "@/components/base/checkbox";
|
import { VCheckbox, VCheckboxGroup } from "@/components/base/checkbox";
|
||||||
import { ref } from "vue";
|
import { VSpace } from "@/components/base/space";
|
||||||
|
import { reactive, ref } from "vue";
|
||||||
|
import type {
|
||||||
|
Align,
|
||||||
|
Direction,
|
||||||
|
Spacing,
|
||||||
|
} from "@/components/base/space/interface";
|
||||||
|
|
||||||
const buttonLoading = ref(true);
|
const buttonLoading = ref(true);
|
||||||
const inputValue = ref();
|
const inputValue = ref();
|
||||||
|
@ -215,6 +272,16 @@ const radioValue = ref("apple");
|
||||||
const checkboxValue = ref(false);
|
const checkboxValue = ref(false);
|
||||||
const checkboxGroupValue = ref(["apple"]);
|
const checkboxGroupValue = ref(["apple"]);
|
||||||
|
|
||||||
|
const spaceState = reactive<{
|
||||||
|
direction: Direction;
|
||||||
|
spacing: Spacing;
|
||||||
|
align: Align;
|
||||||
|
}>({
|
||||||
|
direction: "row",
|
||||||
|
spacing: "xs",
|
||||||
|
align: "center",
|
||||||
|
});
|
||||||
|
|
||||||
const selectData = [
|
const selectData = [
|
||||||
{
|
{
|
||||||
value: "1",
|
value: "1",
|
||||||
|
|
Loading…
Reference in New Issue