diff --git a/src/components/ui/search-input/SearchInput.stories.ts b/src/components/ui/search-input/SearchInput.stories.ts new file mode 100644 index 0000000000..3adf7af3e0 --- /dev/null +++ b/src/components/ui/search-input/SearchInput.stories.ts @@ -0,0 +1,159 @@ +import type { + ComponentPropsAndSlots, + Meta, + StoryObj +} from '@storybook/vue3-vite' + +import { ref } from 'vue' + +import SearchInput from './SearchInput.vue' +import { searchInputStoryConfig } from './searchInput.variants' + +const { sizes } = searchInputStoryConfig + +const meta: Meta> = { + title: 'Components/Input/SearchInput', + component: SearchInput, + tags: ['autodocs'], + argTypes: { + modelValue: { control: 'text' }, + placeholder: { control: 'text' }, + icon: { control: 'text' }, + debounceTime: { control: 'number' }, + autofocus: { control: 'boolean' }, + loading: { control: 'boolean' }, + size: { + control: { type: 'select' }, + options: sizes + }, + 'onUpdate:modelValue': { action: 'update:modelValue' }, + onSearch: { action: 'search' } + }, + args: { + modelValue: '', + size: 'md', + loading: false, + autofocus: false + } +} + +export default meta +type Story = StoryObj + +export const Default: Story = { + render: (args) => ({ + components: { SearchInput }, + setup() { + const searchText = ref(args.modelValue ?? '') + return { searchText, args } + }, + template: ` +
+ +
+ ` + }) +} + +export const AllSizes: Story = { + render: () => ({ + components: { SearchInput }, + setup() { + const sm = ref('') + const md = ref('') + const lg = ref('') + const xl = ref('') + return { sm, md, lg, xl } + }, + template: ` +
+
sm — icon: size-3 (12px)
+ +
md — icon: size-4 (16px, capped)
+ +
lg — icon: size-4 (16px, capped)
+ +
xl — icon: size-4 (16px, capped)
+ +
+ ` + }) +} + +export const WithValue: Story = { + render: (args) => ({ + components: { SearchInput }, + setup() { + const searchText = ref('neural network') + return { searchText, args } + }, + template: ` +
+ +
+ ` + }) +} + +export const Loading: Story = { + render: (args) => ({ + components: { SearchInput }, + setup() { + const searchText = ref('') + return { searchText, args } + }, + template: ` +
+ +
+ ` + }) +} + +export const CustomPlaceholder: Story = { + ...Default, + args: { + placeholder: 'Find a workflow...' + } +} + +export const CustomIcon: Story = { + ...Default, + args: { + icon: 'icon-[lucide--filter]' + } +} + +export const CustomBackground: Story = { + render: (args) => ({ + components: { SearchInput }, + setup() { + const searchText = ref('') + return { searchText, args } + }, + template: ` +
+ +
+ ` + }) +} + +export const Disabled: Story = { + render: (args) => ({ + components: { SearchInput }, + setup() { + const searchText = ref('') + return { searchText, args } + }, + template: ` +
+ +
+ ` + }) +} diff --git a/src/components/ui/search-input/SearchInput.vue b/src/components/ui/search-input/SearchInput.vue new file mode 100644 index 0000000000..3a548a9183 --- /dev/null +++ b/src/components/ui/search-input/SearchInput.vue @@ -0,0 +1,132 @@ + + + diff --git a/src/components/ui/search-input/searchInput.variants.ts b/src/components/ui/search-input/searchInput.variants.ts new file mode 100644 index 0000000000..2a31fd5026 --- /dev/null +++ b/src/components/ui/search-input/searchInput.variants.ts @@ -0,0 +1,54 @@ +import type { VariantProps } from 'cva' +import { cva } from 'cva' + +export const searchInputVariants = cva({ + base: 'relative flex w-full cursor-text items-center rounded-lg bg-secondary-background text-base-foreground', + variants: { + size: { + sm: 'h-6 p-1', + md: 'h-8 px-2 py-1.5', + lg: 'h-10 px-2 py-2', + xl: 'h-12 px-2 py-2' + } + }, + defaultVariants: { size: 'md' } +}) + +export type SearchInputVariants = VariantProps + +export const searchInputSizeConfig = { + sm: { + icon: 'size-3', + iconPos: 'left-2', + inputPl: 'pl-6', + inputText: 'text-xs', + clearPos: 'left-1' + }, + md: { + icon: 'size-4', + iconPos: 'left-2.5', + inputPl: 'pl-8', + inputText: 'text-xs', + clearPos: 'left-2.5' + }, + lg: { + icon: 'size-4', + iconPos: 'left-2.5', + inputPl: 'pl-8', + inputText: 'text-xs', + clearPos: 'left-2.5' + }, + xl: { + icon: 'size-4', + iconPos: 'left-2.5', + inputPl: 'pl-8', + inputText: 'text-xs', + clearPos: 'left-2' + } +} as const + +const sizes = ['sm', 'md', 'lg', 'xl'] as const satisfies Array< + SearchInputVariants['size'] +> + +export const searchInputStoryConfig = { sizes } as const