basic components

This commit is contained in:
Rewrite0
2023-05-13 15:07:19 +08:00
parent 736375f6bd
commit 235d2bdb8d
22 changed files with 6528 additions and 598 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>',
}),
};

41
src/basic/ab-add.vue Normal file
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>',
}),
};

59
src/basic/ab-button.vue Normal file
View File

@@ -0,0 +1,59 @@
<script lang="ts" setup>
const props = withDefaults(
defineProps<{
type?: 'primary' | 'warn';
size?: 'big' | 'normal' | 'small';
}>(),
{
type: 'primary',
size: 'normal',
}
);
defineEmits(['click']);
</script>
<template>
<button
text-white
outline-none
:class="[`type-${type}`, `size-${size}`]"
@click="$emit('click')"
>
<slot></slot>
</button>
</template>
<style lang="scss" scoped>
.type {
&-primary {
@include bg-mouse-event(#4e3c94, #281e52, #8e8a9c);
}
&-warn {
@include bg-mouse-event(#943c61, #521e2a, #9c8a93);
}
}
.size {
&-normal {
border-radius: 6px;
width: 171px;
height: 36px;
}
&-big {
font-size: 24px;
border-radius: 10px;
width: 276px;
height: 55px;
}
&-small {
font-size: 12px;
border-radius: 6px;
width: 86px;
height: 28px;
}
}
</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" />',
}),
};

52
src/basic/ab-checkbox.vue Normal file
View File

@@ -0,0 +1,52 @@
<script lang="ts" setup>
import { Switch } from '@headlessui/vue';
const props = withDefaults(
defineProps<{
modelValue: boolean;
small?: boolean;
}>(),
{
modelValue: false,
small: false,
}
);
const emit = defineEmits(['update:modelValue']);
const checked = ref(props.modelValue);
watchEffect(() => {
emit('update:modelValue', checked.value);
});
</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,17 @@
<script lang="ts" setup>
const props = 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>

54
src/basic/ab-search.vue Normal file
View File

@@ -0,0 +1,54 @@
<script lang="ts" setup>
import { Search } from '@icon-park/vue-next';
const props = withDefaults(
defineProps<{
value?: string;
}>(),
{
value: '',
}
);
const emit = defineEmits(['update:value', 'click-search']);
const onInput = (e: Event) => {
const input = e.target as HTMLInputElement;
emit('update:value', input.value);
};
const onSearch = () => {
emit('click-search', props.value);
};
</script>
<template>
<div
bg="#7752B4"
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"
@click="onSearch"
is-btn
btn-click
/>
<input
type="text"
:value="value"
@input="onInput"
@keyup.enter="onSearch"
input-reset
/>
</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" />',
}),
};

84
src/basic/ab-select.vue Normal file
View File

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

23
src/basic/ab-status.vue Normal file
View File

@@ -0,0 +1,23 @@
<script lang="ts" setup>
const props = 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" />',
}),
};

86
src/basic/ab-switch.vue Normal file
View File

@@ -0,0 +1,86 @@
<script lang="ts" setup>
import { Switch } from '@headlessui/vue';
const props = withDefaults(
defineProps<{
modelValue: boolean;
}>(),
{
modelValue: false,
}
);
const emit = defineEmits(['update:modelValue']);
const checked = ref(props.modelValue);
watchEffect(() => {
emit('update:modelValue', checked.value);
});
</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>