mirror of
https://github.com/status-im/wakuconnect-chat-sdk.git
synced 2025-02-21 16:28:25 +00:00
feat: adds all input variants and stars building filters for table issues
This commit is contained in:
parent
8ec5bf3bc5
commit
20f9f11fbf
@ -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'
|
import Link from 'next/link'
|
||||||
|
|
||||||
const issues = [
|
const issues = [
|
||||||
{
|
{
|
||||||
id: 5154,
|
id: 5154,
|
||||||
title: 'Add support for encrypted communities',
|
title: 'Add support for encrypted communities',
|
||||||
status: 'Open',
|
status: 'open',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 5155,
|
id: 5155,
|
||||||
title: 'Add support for encrypted communities',
|
title: 'Add support for encrypted communities',
|
||||||
status: 'Open',
|
status: 'open',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
id: 4,
|
||||||
title: 'Add support for encrypted communities',
|
title: 'Add support for encrypted communities',
|
||||||
status: 'Open',
|
status: 'open',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4324,
|
id: 4324,
|
||||||
title: 'Add support for encrypted communities',
|
title: 'Add support for encrypted communities',
|
||||||
status: 'Open',
|
status: 'open',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 876,
|
id: 134,
|
||||||
title: 'Add support for encrypted communities',
|
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 = () => {
|
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 (
|
return (
|
||||||
<div className="border-neutral-10 overflow-hidden rounded-2xl border">
|
<div className="border-neutral-10 overflow-hidden rounded-2xl border">
|
||||||
<div className="bg-neutral-5 border-neutral-10 border-b p-3">
|
<div className="bg-neutral-5 border-neutral-10 flex border-b p-3">
|
||||||
<Text size={15} weight="medium">
|
<div className="flex">
|
||||||
|
<div className="pr-3">
|
||||||
|
<Button
|
||||||
|
size={32}
|
||||||
|
variant={activeTab === 'open' ? 'darkGrey' : 'grey'}
|
||||||
|
onPress={() => setActiveTab('open')}
|
||||||
|
icon={<OpenIcon size={20} />}
|
||||||
|
>
|
||||||
784 Open
|
784 Open
|
||||||
</Text>
|
</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>
|
||||||
|
|
||||||
<div className="divide-neutral-10 divide-y">
|
<div className="divide-neutral-10 divide-y">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { cloneElement, forwardRef } from 'react'
|
import { cloneElement, forwardRef } from 'react'
|
||||||
|
|
||||||
import { Stack, styled } from 'tamagui'
|
import { Stack, styled } from '@tamagui/core'
|
||||||
|
|
||||||
import { usePressableColors } from '../hooks/use-pressable-colors'
|
import { usePressableColors } from '../hooks/use-pressable-colors'
|
||||||
|
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import { SearchIcon } from '@status-im/icons'
|
||||||
|
|
||||||
import { Input } from './input'
|
import { Input } from './input'
|
||||||
|
|
||||||
import type { Meta, StoryObj } from '@storybook/react'
|
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
|
export default meta
|
||||||
|
@ -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 { focusableInputHOC } from '@tamagui/focusable'
|
||||||
import { TextInput } from 'react-native'
|
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 { GetProps } from '@tamagui/core'
|
||||||
|
import type { Ref } from 'react'
|
||||||
|
|
||||||
setupReactNative({
|
setupReactNative({
|
||||||
TextInput,
|
TextInput,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const InputFrame = styled(
|
const InputFrame = styled(
|
||||||
TextInput,
|
TextInput,
|
||||||
{
|
{
|
||||||
tag: 'input',
|
tag: 'input',
|
||||||
name: 'Input',
|
name: 'Input',
|
||||||
|
|
||||||
borderWidth: 1,
|
|
||||||
outlineWidth: 0,
|
outlineWidth: 0,
|
||||||
borderColor: 'rgba(0, 200, 0, 1)',
|
borderColor: '$neutral-20',
|
||||||
|
|
||||||
paddingHorizontal: 30,
|
color: '$neutral-100',
|
||||||
color: 'hsla(218, 51%, 7%, 1)',
|
|
||||||
placeholderTextColor: '$placeHolderColor',
|
placeholderTextColor: '$placeHolderColor',
|
||||||
|
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
|
|
||||||
height: 32,
|
|
||||||
borderRadius: '$12',
|
|
||||||
|
|
||||||
animation: 'fast',
|
|
||||||
|
|
||||||
// this fixes a flex bug where it overflows container
|
// this fixes a flex bug where it overflows container
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
|
|
||||||
hoverStyle: {
|
|
||||||
borderColor: '$beigeHover',
|
|
||||||
},
|
|
||||||
|
|
||||||
focusStyle: {
|
|
||||||
borderColor: '$blueHover',
|
|
||||||
},
|
|
||||||
|
|
||||||
variants: {
|
variants: {
|
||||||
blurred: {
|
blurred: {
|
||||||
true: {
|
true: {
|
||||||
placeholderTextColor: '$placeHolderColorBlurred',
|
placeholderTextColor: '$placeHolderColorBlurred',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
} as const,
|
||||||
|
|
||||||
defaultVariants: {
|
|
||||||
blurred: '$false',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isInput: true,
|
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 }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user