mirror of
https://github.com/EstrellaXD/Auto_Bangumi.git
synced 2026-04-10 22:19:10 +08:00
basic components
This commit is contained in:
22
src/basic/ab-add.stories.ts
Normal file
22
src/basic/ab-add.stories.ts
Normal 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
41
src/basic/ab-add.vue
Normal 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>
|
||||
32
src/basic/ab-button.stories.ts
Normal file
32
src/basic/ab-button.stories.ts
Normal 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
59
src/basic/ab-button.vue
Normal 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>
|
||||
22
src/basic/ab-checkbox.stories.ts
Normal file
22
src/basic/ab-checkbox.stories.ts
Normal 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
52
src/basic/ab-checkbox.vue
Normal 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>
|
||||
17
src/basic/ab-page-title.vue
Normal file
17
src/basic/ab-page-title.vue
Normal 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
54
src/basic/ab-search.vue
Normal 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>
|
||||
22
src/basic/ab-select.stories.ts
Normal file
22
src/basic/ab-select.stories.ts
Normal 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
84
src/basic/ab-select.vue
Normal 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
23
src/basic/ab-status.vue
Normal 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>
|
||||
22
src/basic/ab-switch.stories.ts
Normal file
22
src/basic/ab-switch.stories.ts
Normal 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
86
src/basic/ab-switch.vue
Normal 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>
|
||||
Reference in New Issue
Block a user