mirror of https://github.com/halo-dev/halo-admin
parent
074d5b1fea
commit
6a960e573e
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
import type { PropType } from "vue";
|
||||
import { computed } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import type { Size } from "@/components/base/input/interface";
|
||||
|
||||
const props = defineProps({
|
||||
|
@ -65,6 +65,7 @@ function handleInput(e: Event) {
|
|||
@apply text-black;
|
||||
@apply block;
|
||||
@apply transition-all;
|
||||
@apply appearance-none;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 4px;
|
||||
|
||||
|
@ -76,6 +77,11 @@ function handleInput(e: Event) {
|
|||
border-color: #4ccba0;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
@apply opacity-50;
|
||||
@apply cursor-not-allowed;
|
||||
}
|
||||
|
||||
&.input-lg {
|
||||
@apply h-11;
|
||||
@apply px-4;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Input > should render 1`] = `
|
||||
"<div class=\\"input-wrapper\\">
|
||||
<!--v-if--><input class=\\"input-md\\" type=\\"text\\">
|
||||
<!--v-if-->
|
||||
</div>"
|
||||
`;
|
|
@ -0,0 +1,13 @@
|
|||
<script lang="ts" setup>
|
||||
defineProps({
|
||||
value: {
|
||||
type: [String, Number, Boolean],
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<option :value="value">
|
||||
<slot />
|
||||
</option>
|
||||
</template>
|
|
@ -0,0 +1,107 @@
|
|||
<script lang="ts" setup>
|
||||
import type { PropType } from "vue";
|
||||
import type { Size } from "./interface";
|
||||
import { computed } from "vue";
|
||||
import Option from "@/components/base/select/Option.vue";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<Size>,
|
||||
default: "md",
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
|
||||
const classes = computed(() => {
|
||||
return [`select-${props.size}`];
|
||||
});
|
||||
|
||||
function handleChange(e: Event) {
|
||||
const { value } = e.target as HTMLSelectElement;
|
||||
emit("update:modelValue", value);
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="select-wrapper">
|
||||
<select
|
||||
:value="modelValue"
|
||||
@change="handleChange"
|
||||
:disabled="disabled"
|
||||
:class="classes"
|
||||
>
|
||||
<option v-if="placeholder" value="" key="placeholder" disabled hidden>
|
||||
{{ placeholder }}
|
||||
</option>
|
||||
<slot />
|
||||
</select>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
.select-wrapper {
|
||||
@apply box-border;
|
||||
@apply relative;
|
||||
@apply w-full;
|
||||
@apply inline-flex;
|
||||
|
||||
select {
|
||||
@apply outline-0;
|
||||
@apply bg-white;
|
||||
@apply antialiased;
|
||||
@apply w-full;
|
||||
@apply text-black;
|
||||
@apply block;
|
||||
@apply transition-all;
|
||||
@apply appearance-none;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 4px;
|
||||
|
||||
&:active {
|
||||
border-color: #4ccba0;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: #4ccba0;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
@apply opacity-50;
|
||||
@apply cursor-not-allowed;
|
||||
}
|
||||
|
||||
&.select-lg {
|
||||
@apply h-11;
|
||||
@apply px-4;
|
||||
@apply text-lg;
|
||||
}
|
||||
|
||||
&.select-md {
|
||||
@apply h-9;
|
||||
@apply px-3;
|
||||
@apply text-sm;
|
||||
}
|
||||
|
||||
&.select-sm {
|
||||
@apply h-7;
|
||||
@apply px-3;
|
||||
@apply text-xs;
|
||||
}
|
||||
|
||||
&.select-xs {
|
||||
@apply h-6;
|
||||
@apply px-2;
|
||||
@apply text-xs;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,20 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { VSelect } from "../index";
|
||||
import { mount } from "@vue/test-utils";
|
||||
|
||||
describe("Select", () => {
|
||||
it("should render", () => {
|
||||
expect(VSelect).toBeDefined();
|
||||
expect(mount(VSelect).html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should work with size prop", function () {
|
||||
["lg", "md", "sm", "xs"].forEach((size) => {
|
||||
const select = mount(VSelect, { props: { size } });
|
||||
|
||||
expect(select.html()).toMatchSnapshot();
|
||||
expect(select.find("select").classes()).toContain(`select-${size}`);
|
||||
select.unmount();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Select > should render 1`] = `
|
||||
"<div class=\\"select-wrapper\\"><select class=\\"select-md\\">
|
||||
<!--v-if-->
|
||||
</select></div>"
|
||||
`;
|
||||
|
||||
exports[`Select > should work with size prop 1`] = `
|
||||
"<div class=\\"select-wrapper\\"><select class=\\"select-lg\\">
|
||||
<!--v-if-->
|
||||
</select></div>"
|
||||
`;
|
||||
|
||||
exports[`Select > should work with size prop 2`] = `
|
||||
"<div class=\\"select-wrapper\\"><select class=\\"select-md\\">
|
||||
<!--v-if-->
|
||||
</select></div>"
|
||||
`;
|
||||
|
||||
exports[`Select > should work with size prop 3`] = `
|
||||
"<div class=\\"select-wrapper\\"><select class=\\"select-sm\\">
|
||||
<!--v-if-->
|
||||
</select></div>"
|
||||
`;
|
||||
|
||||
exports[`Select > should work with size prop 4`] = `
|
||||
"<div class=\\"select-wrapper\\"><select class=\\"select-xs\\">
|
||||
<!--v-if-->
|
||||
</select></div>"
|
||||
`;
|
|
@ -0,0 +1,2 @@
|
|||
export { default as VSelect } from "./Select.vue";
|
||||
export { default as VOption } from "./Option.vue";
|
|
@ -0,0 +1 @@
|
|||
export type Size = "lg" | "md" | "sm" | "xs";
|
|
@ -1,82 +1,85 @@
|
|||
import type { RouteRecordRaw } from "vue-router";
|
||||
import HomeView from "../views/HomeView.vue";
|
||||
import AboutView from "../views/AboutView.vue";
|
||||
import ViewComponents from "../views/ViewComponents.vue";
|
||||
|
||||
export const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/",
|
||||
name: "Dashboard",
|
||||
component: () => import("../views/HomeView.vue"),
|
||||
component: HomeView,
|
||||
},
|
||||
{
|
||||
path: "/about",
|
||||
name: "about",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
{
|
||||
path: "/posts",
|
||||
name: "Posts",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
children: [
|
||||
{
|
||||
path: "/posts/categories",
|
||||
name: "Categories",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
{
|
||||
path: "/posts/tags",
|
||||
name: "Tags",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/sheets",
|
||||
name: "Sheets",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
{
|
||||
path: "/comment",
|
||||
name: "Comment",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
{
|
||||
path: "/attachment",
|
||||
name: "Attachment",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
{
|
||||
path: "/themes",
|
||||
name: "Themes",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
{
|
||||
path: "/menus",
|
||||
name: "Menus",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
{
|
||||
path: "/visual",
|
||||
name: "Visual",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
{
|
||||
path: "/plugins",
|
||||
name: "Plugins",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
{
|
||||
path: "/users",
|
||||
name: "Users",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
{
|
||||
path: "/settings",
|
||||
name: "Settings",
|
||||
component: () => import("../views/AboutView.vue"),
|
||||
component: AboutView,
|
||||
},
|
||||
{
|
||||
path: "/components",
|
||||
name: "Components",
|
||||
component: () => import("../views/ViewComponents.vue"),
|
||||
component: ViewComponents,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -37,29 +37,71 @@
|
|||
<VButton disabled type="danger"> Danger</VButton>
|
||||
</div>
|
||||
</section>
|
||||
<section class="box border-2 rounded p-2">
|
||||
<section class="box border-2 rounded p-2 mb-3">
|
||||
<h1 class="text-xl font-bold mb-2">Input</h1>
|
||||
<h2 class="mb-1">Size:</h2>
|
||||
<div class="mb-3">
|
||||
<VInput class="mb-2" placeholder="请输入邮箱" size="lg" />
|
||||
<VInput class="mb-2" placeholder="请输入邮箱" size="md" />
|
||||
<VInput class="mb-2" placeholder="请输入邮箱" size="sm" />
|
||||
<VInput placeholder="请输入邮箱" size="xs" />
|
||||
<VInput
|
||||
class="mb-2"
|
||||
v-model="inputValue"
|
||||
placeholder="请输入邮箱"
|
||||
size="lg"
|
||||
/>
|
||||
<VInput
|
||||
class="mb-2"
|
||||
v-model="inputValue"
|
||||
placeholder="请输入邮箱"
|
||||
size="md"
|
||||
/>
|
||||
<VInput
|
||||
class="mb-2"
|
||||
v-model="inputValue"
|
||||
placeholder="请输入邮箱"
|
||||
size="sm"
|
||||
/>
|
||||
<VInput v-model="inputValue" placeholder="请输入邮箱" size="xs" />
|
||||
</div>
|
||||
<h2 class="mb-1">With Icon:</h2>
|
||||
<!-- <h2 class="mb-1">With Icon:</h2>-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <VInput v-model="inputValue" class="mb-2" size="md">-->
|
||||
<!-- <template #prefix>-->
|
||||
<!-- <IconDashboard />-->
|
||||
<!-- </template>-->
|
||||
<!-- <template #suffix>-->
|
||||
<!-- <IconDashboard />-->
|
||||
<!-- </template>-->
|
||||
<!-- </VInput>-->
|
||||
<!-- </div>-->
|
||||
<h2 class="mb-1">Disabled:</h2>
|
||||
<div class="mb-3">
|
||||
<VInput class="mb-2" size="md">
|
||||
<template #prefix>
|
||||
<IconDashboard />
|
||||
</template>
|
||||
<template #suffix>
|
||||
<IconDashboard />
|
||||
</template>
|
||||
</VInput>
|
||||
<VInput v-model="inputValue" disabled />
|
||||
</div>
|
||||
</section>
|
||||
<section class="box border-2 rounded p-2">
|
||||
<h1 class="text-xl font-bold mb-2">Select</h1>
|
||||
<h2 class="mb-1">Size:</h2>
|
||||
<div class="mb-3">
|
||||
<VSelect v-model="selectValue">
|
||||
<VOption
|
||||
v-for="(option, index) in selectData"
|
||||
:value="option.value"
|
||||
:key="index"
|
||||
>
|
||||
{{ option.label }}
|
||||
</VOption>
|
||||
</VSelect>
|
||||
</div>
|
||||
<h2 class="mb-1">Disabled:</h2>
|
||||
<div class="mb-3">
|
||||
<VInput disabled />
|
||||
<VSelect v-model="selectValue" disabled>
|
||||
<VOption
|
||||
v-for="(option, index) in selectData"
|
||||
:value="option.value"
|
||||
:key="index"
|
||||
>
|
||||
{{ option.label }}
|
||||
</VOption>
|
||||
</VSelect>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -70,5 +112,20 @@
|
|||
import { FilledLayout } from "../layouts";
|
||||
import { VButton } from "@/components/base/button";
|
||||
import { VInput } from "@/components/base/input";
|
||||
import { IconDashboard } from "@/core/icons";
|
||||
import { VSelect, VOption } from "@/components/base/select";
|
||||
import { ref } from "vue";
|
||||
|
||||
const inputValue = ref();
|
||||
const selectValue = ref();
|
||||
|
||||
const selectData = [
|
||||
{
|
||||
value: "1",
|
||||
label: "1",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "2",
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
|
Loading…
Reference in New Issue