组件归类

This commit is contained in:
Rewrite0
2023-05-31 22:04:22 +08:00
parent c0f23adb44
commit 94d23a3f4d
30 changed files with 62 additions and 116 deletions

View File

@@ -0,0 +1,22 @@
import type { Meta, StoryObj } from '@storybook/vue3';
import AbAdd from './ab-add.vue';
const meta: Meta<typeof AbAdd> = {
title: 'basic/ab-add',
component: AbAdd,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof AbAdd>;
export const Template: Story = {
render: (args) => ({
components: { AbAdd },
setup() {
return { args };
},
template: '<ab-add v-bind="args"></ab-add>',
}),
};

View File

@@ -0,0 +1,41 @@
<script lang="ts" setup>
defineEmits(['click']);
</script>
<template>
<button
rounded="1/2"
wh-36px
f-cer
rel
transition-colors
class="box"
@click="$emit('click')"
>
<div class="line" abs></div>
<div class="line" abs rotate-90></div>
</button>
</template>
<style lang="scss" scoped>
$normal: #493475;
$hover: #756596;
.box {
background: $normal;
&:hover {
background: $hover;
}
&:active {
background: $normal;
}
}
.line {
width: 6px;
height: 18px;
background: #fff;
}
</style>

View File

@@ -0,0 +1,32 @@
import type { Meta, StoryObj } from '@storybook/vue3';
import AbButton from './ab-button.vue';
const meta: Meta<typeof AbButton> = {
title: 'basic/ab-button',
component: AbButton,
tags: ['autodocs'],
argTypes: {
type: {
control: { type: 'select' },
options: ['primary', 'warn'],
},
size: {
control: { type: 'select' },
options: ['big', 'normal', 'small'],
},
},
};
export default meta;
type Story = StoryObj<typeof AbButton>;
export const Template: Story = {
render: (args) => ({
components: { AbButton },
setup() {
return { args };
},
template: '<ab-button v-bind="args">button</ab-button>',
}),
};

View File

@@ -0,0 +1,70 @@
<script lang="ts" setup>
import { NSpin } from 'naive-ui';
const props = withDefaults(
defineProps<{
type?: 'primary' | 'warn';
size?: 'big' | 'normal' | 'small';
link?: string | null;
loading?: boolean;
}>(),
{
type: 'primary',
size: 'normal',
link: null,
loading: false,
}
);
defineEmits(['click']);
const buttonSize = computed(() => {
switch (props.size) {
case 'big':
return 'rounded-10px text-h1 w-276px h-55px text-h1';
case 'normal':
return 'rounded-6px w-170px h-36px';
case 'small':
return 'rounded-6px w-86px h-28px text-main';
}
});
const loadingSize = computed(() => {
switch (props.size) {
case 'big':
return 'large';
case 'normal':
return 'small';
case 'small':
return 18;
}
});
</script>
<template>
<Component
:is="link !== null ? 'a' : 'button'"
:href="link"
text-white
outline-none
f-cer
:class="[`type-${type}`, buttonSize]"
@click="$emit('click')"
>
<NSpin :show="loading" :size="loadingSize">
<slot></slot>
</NSpin>
</Component>
</template>
<style lang="scss" scoped>
.type {
&-primary {
@include bg-mouse-event(#4e3c94, #281e52, #8e8a9c);
}
&-warn {
@include bg-mouse-event(#943c61, #521e2a, #9c8a93);
}
}
</style>

View File

@@ -0,0 +1,22 @@
import type { Meta, StoryObj } from '@storybook/vue3';
import AbCheckbox from './ab-checkbox.vue';
const meta: Meta<typeof AbCheckbox> = {
title: 'basic/ab-checkbox',
component: AbCheckbox,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof AbCheckbox>;
export const Template: Story = {
render: (args) => ({
components: { AbCheckbox },
setup() {
return { args };
},
template: '<ab-checkbox v-bind="args" />',
}),
};

View File

@@ -0,0 +1,45 @@
<script lang="ts" setup>
import { Switch } from '@headlessui/vue';
withDefaults(
defineProps<{
small?: boolean;
}>(),
{
small: false,
}
);
const checked = defineModel<boolean>({ default: false });
</script>
<template>
<Switch v-model="checked" as="template">
<div flex items-center space-x-8px is-btn>
<slot name="before"></slot>
<div
rounded-4px
rel
f-cer
bg-white
border="3px #3c239f"
:class="[small ? 'wh-16px' : 'wh-32px', !checked && 'group']"
>
<div
rounded-2px
transition-all
duration-300
:class="[
small ? 'wh-8px' : 'wh-16px',
checked ? 'bg-[#3c239f]' : 'bg-transparent',
]"
group-hover:bg="#cccad4"
group-active:bg="#3c239f"
></div>
</div>
<slot name="after"></slot>
</div>
</Switch>
</template>

View File

@@ -0,0 +1,22 @@
import type { Meta, StoryObj } from '@storybook/vue3';
import AbPageTitle from './ab-page-title.vue';
const meta: Meta<typeof AbPageTitle> = {
title: 'basic/ab-PageTitle',
component: AbPageTitle,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof AbPageTitle>;
export const Template: Story = {
render: (args) => ({
components: { AbPageTitle },
setup() {
return { args };
},
template: '<ab-page-title v-bind="args" />',
}),
};

View File

@@ -0,0 +1,17 @@
<script lang="ts" setup>
withDefaults(
defineProps<{
title: string;
}>(),
{
title: 'title',
}
);
</script>
<template>
<div fx-cer space-x-12px>
<div text-h1>{{ title }}</div>
<div w-160px h-3px bg-theme-row rounded-full></div>
</div>
</template>

View File

@@ -0,0 +1,22 @@
import type { Meta, StoryObj } from '@storybook/vue3';
import AbSearch from './ab-search.vue';
const meta: Meta<typeof AbSearch> = {
title: 'basic/ab-search',
component: AbSearch,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof AbSearch>;
export const Template: Story = {
render: (args) => ({
components: { AbSearch },
setup() {
return { args };
},
template: '<ab-search v-bind="args" />',
}),
};

View File

@@ -0,0 +1,58 @@
<script lang="ts" setup>
import { Search } from '@icon-park/vue-next';
const props = withDefaults(
defineProps<{
value?: string;
placeholder?: string;
}>(),
{
value: '',
placeholder: '',
}
);
const emit = defineEmits(['update:value', 'click-search']);
function onInput(e: Event) {
const input = e.target as HTMLInputElement;
emit('update:value', input.value);
}
function onSearch() {
emit('click-search', props.value);
}
</script>
<template>
<div
bg="#7752B4"
text-white
fx-cer
rounded-12px
h-36px
px-12px
space-x-12px
w-276px
focus-within:w-396px
transition-width
>
<Search
theme="outline"
size="24"
fill="#fff"
is-btn
btn-click
@click="onSearch"
/>
<input
type="text"
:value="value"
:placeholder="placeholder"
input-reset
@input="onInput"
@keyup.enter="onSearch"
/>
</div>
</template>

View File

@@ -0,0 +1,22 @@
import type { Meta, StoryObj } from '@storybook/vue3';
import AbSelect from './ab-select.vue';
const meta: Meta<typeof AbSelect> = {
title: 'basic/ab-select',
component: AbSelect,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof AbSelect>;
export const Template: Story = {
render: (args) => ({
components: { AbSelect },
setup() {
return { args };
},
template: '<ab-select v-bind="args" />',
}),
};

View File

@@ -0,0 +1,111 @@
<script lang="ts" setup>
import {
Listbox,
ListboxButton,
ListboxOption,
ListboxOptions,
} from '@headlessui/vue';
import { Down, Up } from '@icon-park/vue-next';
import { isObject, isString } from 'lodash';
import type { SelectItem } from '#/components';
const props = withDefaults(
defineProps<{
modelValue?: SelectItem | string;
items: Array<SelectItem | string>;
}>(),
{}
);
const emit = defineEmits(['update:modelValue']);
const selected = ref<SelectItem | string>(
props.modelValue || (props.items?.[0] ?? '')
);
const otherItems = computed(() => {
return (
props.items.filter((e) => {
if (isString(e) && isString(selected.value)) {
return e !== selected.value;
} else if (isObject(e) && isObject(selected.value)) {
return e.id !== selected.value.id;
} else {
return false;
}
}) ?? []
);
});
const label = computed(() => {
if (isString(selected.value)) {
return selected.value;
} else {
return selected.value.label ?? selected.value.value;
}
});
function getLabel(item: SelectItem | string) {
if (isString(item)) {
return item;
} else {
return item.label ?? item.value;
}
}
function getDisabled(item: SelectItem | string) {
return isString(item) ? false : item.disabled;
}
watchEffect(() => {
emit('update:modelValue', selected.value);
});
</script>
<template>
<Listbox v-slot="{ open }" v-model="selected">
<div
rel
flex="inline col"
rounded-6px
border="1px black"
text-main
py-4px
px-12px
>
<ListboxButton bg-transparent fx-cer justify-between space-x-24px>
<div>
{{ label }}
</div>
<div :class="[{ hidden: open }]">
<Down />
</div>
</ListboxButton>
<ListboxOptions mt-8px>
<div flex="~ items-end" justify-between space-x-24px>
<div flex="~ col" space-y-8px>
<ListboxOption
v-for="item in otherItems"
v-slot="{ active }"
:key="isString(item) ? item : item.id"
:value="item"
:disabled="getDisabled(item)"
>
<div
:class="[
{ 'text-primary': active },
getDisabled(item) ? 'is-disabled' : 'is-btn',
]"
>
{{ getLabel(item) }}
</div>
</ListboxOption>
</div>
<div :class="[{ hidden: !open }]"><Up /></div>
</div>
</ListboxOptions>
</div>
</Listbox>
</template>

View File

@@ -0,0 +1,22 @@
import type { Meta, StoryObj } from '@storybook/vue3';
import AbStatus from './ab-status.vue';
const meta: Meta<typeof AbStatus> = {
title: 'basic/ab-status',
component: AbStatus,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof AbStatus>;
export const Template: Story = {
render: (args) => ({
components: { AbStatus },
setup() {
return { args };
},
template: '<ab-status v-bind="args" />',
}),
};

View File

@@ -0,0 +1,23 @@
<script lang="ts" setup>
withDefaults(
defineProps<{
running: boolean;
}>(),
{
running: false,
}
);
</script>
<template>
<div wh-24px f-cer>
<div rounded="1/2" f-cer border="2px solid white" wh-22px>
<div
:class="[running ? 'bg-running' : 'bg-stopped']"
rounded="1/2"
wh-10px
transition-colors
></div>
</div>
</div>
</template>

View File

@@ -0,0 +1,22 @@
import type { Meta, StoryObj } from '@storybook/vue3';
import AbSwitch from './ab-switch.vue';
const meta: Meta<typeof AbSwitch> = {
title: 'basic/ab-switch',
component: AbSwitch,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof AbSwitch>;
export const Template: Story = {
render: (args) => ({
components: { AbSwitch },
setup() {
return { args };
},
template: '<ab-switch v-bind="args" />',
}),
};

View File

@@ -0,0 +1,74 @@
<script lang="ts" setup>
import { Switch } from '@headlessui/vue';
const checked = defineModel<boolean>('checked', {
default: false,
});
</script>
<template>
<Switch v-model="checked" as="template">
<div
is-btn
w-48px
h-28px
rounded-full
rel
flex="inline items-center"
transition-colors
duration-300
p-3px
shadow="~ inset"
class="box"
:class="{ checked }"
>
<div
wh-22px
rounded="1/2"
transition-all
duration-300
class="slider"
:class="{ checked, 'translate-x-20px': checked }"
></div>
</div>
</Switch>
</template>
<style lang="scss" scope>
$bg-unchecked: #929292;
$bg-checked: #e7e7e7;
$slider-unchecked: #ececef;
$slider-unchecked-hover: #dbd8ec;
$slider-checked: #1c1259;
$slider-checked-hover: #62589e;
.box {
background: $bg-unchecked;
&.checked {
background: $bg-checked;
}
&:hover .slider {
&:not(.checked) {
background: $slider-unchecked-hover;
}
&.checked {
background: $slider-checked-hover;
}
}
}
.slider {
&:not(.checked) {
background: $slider-unchecked;
}
&.checked {
background: $slider-checked;
}
}
</style>