feat: adds all input variants and stars building filters for table issues

This commit is contained in:
marcelines 2023-06-02 17:03:46 +01:00
parent 8ec5bf3bc5
commit 20f9f11fbf
No known key found for this signature in database
GPG Key ID: 56B1E53E2A3F43C7
4 changed files with 337 additions and 38 deletions

View File

@ -1,41 +1,182 @@
import { Avatar, Button, Tag, Text } from '@status-im/components'
import { useState } from 'react'
import { Avatar, Button, Input, Tag, Text } from '@status-im/components'
import { DropdownMenu } from '@status-im/components/src/dropdown-menu'
import { DropdownIcon, OpenIcon, SearchIcon } from '@status-im/icons'
import Link from 'next/link'
const issues = [
{
id: 5154,
title: 'Add support for encrypted communities',
status: 'Open',
status: 'open',
},
{
id: 5155,
title: 'Add support for encrypted communities',
status: 'Open',
status: 'open',
},
{
id: 4,
title: 'Add support for encrypted communities',
status: 'Open',
status: 'open',
},
{
id: 4324,
title: 'Add support for encrypted communities',
status: 'Open',
status: 'open',
},
{
id: 876,
id: 134,
title: 'Add support for encrypted communities',
status: 'Open',
status: 'closed',
},
{
id: 999,
title: 'Add support for encrypted communities',
status: 'closed',
},
{
id: 873,
title: 'Add support for encrypted communities',
status: 'open',
},
{
id: 123,
title: 'Add support for encrypted communities',
status: 'open',
},
]
const authors = [
{
id: 1,
name: 'Tobias',
avatar:
'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&h=500&q=80',
},
{
id: 2,
name: 'Arnold',
avatar:
'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&h=500&q=80',
},
{
id: 3,
name: 'Alisher',
avatar:
'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&h=500&q=80',
},
{
id: 4,
name: 'marcelines',
avatar: 'https://avatars.githubusercontent.com/u/29401404?v=4',
},
{
id: 5,
name: 'prichodko',
avatar: 'https://avatars.githubusercontent.com/u/14926950?v=4',
},
{
id: 6,
name: 'felicio',
avatar: 'https://avatars.githubusercontent.com/u/13265126?v=4',
},
{
id: 7,
name: 'jkbktl',
avatar: 'https://avatars.githubusercontent.com/u/520927?v=4',
},
]
export const TableIssues = () => {
const [activeTab, setActiveTab] = useState<'open' | 'closed'>('open')
const [authorFilterText, setAuthorFilterText] = useState('')
const filteredAuthors = authors.filter(author =>
author.name.toLowerCase().includes(authorFilterText.toLowerCase())
)
return (
<div className="border-neutral-10 overflow-hidden rounded-2xl border">
<div className="bg-neutral-5 border-neutral-10 border-b p-3">
<Text size={15} weight="medium">
784 Open
</Text>
<div className="bg-neutral-5 border-neutral-10 flex border-b p-3">
<div className="flex">
<div className="pr-3">
<Button
size={32}
variant={activeTab === 'open' ? 'darkGrey' : 'grey'}
onPress={() => setActiveTab('open')}
icon={<OpenIcon size={20} />}
>
784 Open
</Button>
</div>
<div className="pr-3">
<Button
size={32}
variant={activeTab === 'closed' ? 'darkGrey' : 'grey'}
onPress={() => setActiveTab('closed')}
>
1012 closed
</Button>
</div>
</div>
<div className="flex-1">
<div className="flex items-center justify-end">
<div className="pr-3">
<DropdownMenu>
<Button
size={32}
variant="outline"
iconAfter={<DropdownIcon size={20} />}
>
Author
</Button>
<DropdownMenu.Content sideOffset={10} align="end">
<div className="p-2 px-1">
<Input
placeholder="Find Author"
icon={<SearchIcon size={20} />}
size={32}
value={authorFilterText}
onChangeText={setAuthorFilterText}
/>
</div>
{filteredAuthors.map(author => (
<DropdownMenu.Item
key={author.id}
icon={
<Avatar
name={author.name}
src={author.avatar}
size={16}
type="user"
/>
}
label={author.name}
onSelect={() => alert('Author: ' + author.name)}
/>
))}
{filteredAuthors.length === 0 && (
<div className="p-2 py-1">
<Text size={13}> No authors found</Text>
</div>
)}
</DropdownMenu.Content>
</DropdownMenu>
</div>
<div className="pr-3">
<Button size={32} variant="ghost">
Filter
</Button>
</div>
<div className="pr-3">
<Button size={32} variant="ghost">
Sort
</Button>
</div>
</div>
</div>
</div>
<div className="divide-neutral-10 divide-y">

View File

@ -1,6 +1,6 @@
import { cloneElement, forwardRef } from 'react'
import { Stack, styled } from 'tamagui'
import { Stack, styled } from '@tamagui/core'
import { usePressableColors } from '../hooks/use-pressable-colors'

View File

@ -1,3 +1,7 @@
import { useEffect, useState } from 'react'
import { SearchIcon } from '@status-im/icons'
import { Input } from './input'
import type { Meta, StoryObj } from '@storybook/react'
@ -18,4 +22,46 @@ export const Primary: Story = {
},
}
const InputSearch = () => {
const [value, setValue] = useState('')
// limit input to 100 characters just for demo purposes
useEffect(() => {
if (value.length > 100) {
setValue(value.slice(0, 100))
}
}, [value])
return (
<>
<Input
placeholder="Please type something..."
value={value}
onChangeText={setValue}
icon={<SearchIcon size={20} />}
onClear={() => setValue('')}
label="Search"
endLabel={`${value.length}/100`}
size={40}
button={{
label: 'Confirm',
onPress: () => alert('Confirmed!'),
}}
/>
</>
)
}
export const CompleteExample: Story = {
render: () => <InputSearch />,
}
export const WithError: Story = {
args: {
placeholder: 'Type something...',
error: true,
// children: 'Click me',
},
}
export default meta

View File

@ -1,62 +1,174 @@
import { setupReactNative, styled } from '@tamagui/core'
import { cloneElement, forwardRef } from 'react'
import { ClearIcon } from '@status-im/icons'
import { setupReactNative, Stack, styled } from '@tamagui/core'
import { focusableInputHOC } from '@tamagui/focusable'
import { TextInput } from 'react-native'
import { Button } from '../button'
import { IconButton } from '../icon-button'
import { Text } from '../text'
import type { GetProps } from '@tamagui/core'
import type { Ref } from 'react'
setupReactNative({
TextInput,
})
export const InputFrame = styled(
const InputFrame = styled(
TextInput,
{
tag: 'input',
name: 'Input',
borderWidth: 1,
outlineWidth: 0,
borderColor: 'rgba(0, 200, 0, 1)',
borderColor: '$neutral-20',
paddingHorizontal: 30,
color: 'hsla(218, 51%, 7%, 1)',
color: '$neutral-100',
placeholderTextColor: '$placeHolderColor',
backgroundColor: 'transparent',
height: 32,
borderRadius: '$12',
animation: 'fast',
// this fixes a flex bug where it overflows container
minWidth: 0,
hoverStyle: {
borderColor: '$beigeHover',
},
focusStyle: {
borderColor: '$blueHover',
},
variants: {
blurred: {
true: {
placeholderTextColor: '$placeHolderColorBlurred',
},
},
},
defaultVariants: {
blurred: '$false',
},
} as const,
},
{
isInput: true,
}
)
export type InputProps = GetProps<typeof InputFrame>
const InputContainer = styled(Stack, {
name: 'InputContainer',
tag: 'div',
flexDirection: 'row',
alignItems: 'center',
gap: 8,
export const Input = focusableInputHOC(InputFrame)
borderWidth: 1,
borderColor: '$neutral-20',
paddingHorizontal: 12,
animation: 'fast',
hoverStyle: {
borderColor: '$neutral-40',
},
focusStyle: {
borderColor: '$neutral-40',
},
pressStyle: {
borderColor: '$neutral-40',
},
variants: {
size: {
40: {
height: 40,
paddingHorizontal: 16,
borderRadius: '$12',
},
32: {
height: 32,
paddingHorizontal: 8,
borderRadius: '$10',
},
},
error: {
true: {
borderColor: '$danger-50-opa-40',
},
},
disabled: {
true: {
opacity: 0.3,
cursor: 'default',
},
},
} as const,
})
type Props = GetProps<typeof InputFrame> & {
button?: {
label: string
onPress: () => void
}
endLabel?: string
icon?: React.ReactElement
label?: string
onClear?: () => void
size?: 40 | 32
error?: boolean
}
const InputBase = focusableInputHOC(InputFrame)
const _Input = (props: Props, ref: Ref<HTMLDivElement>) => {
const {
button,
color = '$neutral-50',
endLabel,
error,
icon,
label,
onClear,
size = 40,
value,
...rest
} = props
return (
<Stack>
{Boolean(label || endLabel) && (
<Stack flexDirection="row" justifyContent="space-between" pb={8}>
{label && (
<Text size={13} color="$neutral-50" weight="medium">
{label}
</Text>
)}
{endLabel && (
<Text size={13} color="$neutral-50">
{endLabel}
</Text>
)}
</Stack>
)}
<InputContainer size={size} ref={ref} error={error}>
{icon ? cloneElement(icon, { color }) : null}
<InputBase value={value} {...rest} flex={1} />
<Stack flexDirection="row" alignItems="center">
{Boolean(onClear) && !!value && (
<Stack pr={4}>
<IconButton
variant="ghost"
icon={<ClearIcon size={20} />}
onPress={onClear}
/>
</Stack>
)}
{button && (
<Button onPress={button.onPress} variant="outline" size={24}>
{button.label}
</Button>
)}
</Stack>
</InputContainer>
</Stack>
)
}
const Input = forwardRef(_Input)
export { Input }
export type { Props as InputProps }