Merge pull request #416 from marcelines/feat/table-filters
[website]: Table filters
This commit is contained in:
commit
2b6ef64fdd
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -1,2 +1,4 @@
|
||||||
export { Breadcrumbs } from './breadcrumbs/breadcrumbs'
|
export { Breadcrumbs } from './breadcrumbs/breadcrumbs'
|
||||||
|
export { EpicOverview } from './epic-overview'
|
||||||
export { SideBar } from './side-bar/side-bar'
|
export { SideBar } from './side-bar/side-bar'
|
||||||
|
export { TableIssues } from './table-issues/table-issues'
|
||||||
|
|
|
@ -55,7 +55,7 @@ const FloatingMenu = (): JSX.Element => {
|
||||||
}}
|
}}
|
||||||
className={cx([
|
className={cx([
|
||||||
'fixed left-1/2 top-1 z-10 flex -translate-x-1/2 flex-col items-center justify-between p-2 pb-0 lg:hidden',
|
'fixed left-1/2 top-1 z-10 flex -translate-x-1/2 flex-col items-center justify-between p-2 pb-0 lg:hidden',
|
||||||
'bg-blur-neutral-80/80 border-neutral-80/5 rounded-2xl border backdrop-blur-md',
|
'rounded-2xl border border-neutral-80/5 bg-blur-neutral-80/80 backdrop-blur-md',
|
||||||
' w-[calc(100%-24px)]',
|
' w-[calc(100%-24px)]',
|
||||||
' opacity-0 transition-opacity data-[visible=true]:opacity-100',
|
' opacity-0 transition-opacity data-[visible=true]:opacity-100',
|
||||||
'z-10',
|
'z-10',
|
||||||
|
@ -69,8 +69,8 @@ const FloatingMenu = (): JSX.Element => {
|
||||||
}}
|
}}
|
||||||
className={cx([
|
className={cx([
|
||||||
'fixed left-1/2 top-5 z-10 w-max min-w-[746px] -translate-x-1/2 overflow-hidden',
|
'fixed left-1/2 top-5 z-10 w-max min-w-[746px] -translate-x-1/2 overflow-hidden',
|
||||||
'bg-blur-neutral-80/80 border-neutral-80/5 rounded-2xl border backdrop-blur-md',
|
'rounded-2xl border border-neutral-80/5 bg-blur-neutral-80/80 backdrop-blur-md',
|
||||||
'md-lg:block hidden',
|
'hidden md-lg:block',
|
||||||
])}
|
])}
|
||||||
>
|
>
|
||||||
<FloatingDesktop visible={visible} />
|
<FloatingDesktop visible={visible} />
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
import { Avatar, Button, Tag, Text } from '@status-im/components'
|
|
||||||
import Link from 'next/link'
|
|
||||||
|
|
||||||
const issues = [
|
|
||||||
{
|
|
||||||
id: 5154,
|
|
||||||
title: 'Add support for encrypted communities',
|
|
||||||
status: 'Open',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5155,
|
|
||||||
title: 'Add support for encrypted communities',
|
|
||||||
status: 'Open',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
title: 'Add support for encrypted communities',
|
|
||||||
status: 'Open',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4324,
|
|
||||||
title: 'Add support for encrypted communities',
|
|
||||||
status: 'Open',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 876,
|
|
||||||
title: 'Add support for encrypted communities',
|
|
||||||
status: 'Open',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export const TableIssues = () => {
|
|
||||||
return (
|
|
||||||
<div className="overflow-hidden rounded-2xl border border-neutral-10">
|
|
||||||
<div className="border-b border-neutral-10 bg-neutral-5 p-3">
|
|
||||||
<Text size={15} weight="medium">
|
|
||||||
784 Open
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="divide-y divide-neutral-10">
|
|
||||||
{issues.map(issue => (
|
|
||||||
<Link
|
|
||||||
key={issue.id}
|
|
||||||
href={`https://github.com/status-im/status-react/issues/${issue.id}`}
|
|
||||||
className="flex items-center justify-between px-4 py-3 transition-colors duration-200 hover:bg-neutral-5"
|
|
||||||
>
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<Text size={15} weight="medium">
|
|
||||||
{issue.title}
|
|
||||||
</Text>
|
|
||||||
<Text size={13} color="$neutral-50">
|
|
||||||
#9667 • Opened 2 days ago by slaedjenic
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex gap-3">
|
|
||||||
<div className="flex gap-1">
|
|
||||||
<Tag size={24} label="E:Syncing" color="$orange-50" />
|
|
||||||
<Tag size={24} label="E:Wallet" color="$green-50" />
|
|
||||||
<Tag size={24} label="Feature" color="$pink-50" />
|
|
||||||
<Tag size={24} label="Web" color="$purple-50" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Tag size={24} label="9435" />
|
|
||||||
|
|
||||||
<Avatar
|
|
||||||
type="user"
|
|
||||||
size={24}
|
|
||||||
name="jkbktl"
|
|
||||||
src="https://images.unsplash.com/photo-1552058544-f2b08422138a?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1299&q=80"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-3">
|
|
||||||
<Button size={40} variant="outline">
|
|
||||||
Show more 10
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { tokens } from '@status-im/components/src/tokens'
|
||||||
|
|
||||||
|
import type { ColorTokens } from '@tamagui/core'
|
||||||
|
|
||||||
|
// TypeGuard for ColorTokens
|
||||||
|
function isColorTokens(
|
||||||
|
value: `#${string}` | ColorTokens
|
||||||
|
): value is ColorTokens {
|
||||||
|
return typeof value === 'string' && value.startsWith('$')
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColorCircle = ({
|
||||||
|
color: colorFromProps,
|
||||||
|
opacity = 40,
|
||||||
|
size = 16,
|
||||||
|
}: {
|
||||||
|
color: ColorTokens | `#${string}`
|
||||||
|
opacity?: number
|
||||||
|
size?: number
|
||||||
|
}) => {
|
||||||
|
if (!colorFromProps) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
let color: ColorTokens | string = colorFromProps
|
||||||
|
|
||||||
|
if (isColorTokens(colorFromProps)) {
|
||||||
|
const colorToken = colorFromProps.replace(
|
||||||
|
'$',
|
||||||
|
''
|
||||||
|
) as keyof typeof tokens.color
|
||||||
|
color = tokens.color[colorToken]?.val || colorFromProps
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="rounded-full"
|
||||||
|
style={{
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
backgroundColor: `color-mix(in srgb, ${color} ${opacity}%, transparent)`,
|
||||||
|
border: `1px solid ${color}`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ColorCircle }
|
|
@ -0,0 +1,140 @@
|
||||||
|
import { cloneElement, useState } from 'react'
|
||||||
|
|
||||||
|
import { Avatar, Button, Input, Text } from '@status-im/components'
|
||||||
|
import { DropdownMenu } from '@status-im/components/src/dropdown-menu'
|
||||||
|
import { DropdownIcon, SearchIcon } from '@status-im/icons'
|
||||||
|
import Image from 'next/image'
|
||||||
|
|
||||||
|
import { useCurrentBreakpoint } from '@/hooks/use-current-breakpoint'
|
||||||
|
|
||||||
|
import { ColorCircle } from './components/color-circle'
|
||||||
|
|
||||||
|
import type { ColorTokens } from '@tamagui/core'
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
avatar?: string | React.ReactElement
|
||||||
|
color?: ColorTokens | `#${string}`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
data: Data[]
|
||||||
|
label: string
|
||||||
|
placeholder?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const isAvatar = (value: unknown): value is string => {
|
||||||
|
return typeof value === 'string' && value !== null
|
||||||
|
}
|
||||||
|
|
||||||
|
const RenderIcon = (props: Data) => {
|
||||||
|
if (props.color) {
|
||||||
|
return <ColorCircle color={props.color} />
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!props.avatar) {
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAvatar(props.avatar)) {
|
||||||
|
return <Avatar src={props.avatar} size={16} name={props.name} type="user" />
|
||||||
|
}
|
||||||
|
|
||||||
|
return cloneElement(props.avatar) || <></>
|
||||||
|
}
|
||||||
|
|
||||||
|
const DropdownFilter = (props: Props) => {
|
||||||
|
const { data, label, placeholder } = props
|
||||||
|
|
||||||
|
const [filterText, setFilterText] = useState('')
|
||||||
|
|
||||||
|
// TODO - this will be improved by having a debounced search and use memoization
|
||||||
|
const filteredData = data.filter(label =>
|
||||||
|
label.name.toLowerCase().includes(filterText.toLowerCase())
|
||||||
|
)
|
||||||
|
|
||||||
|
const [selectedValues, setSelectedValues] = useState<number[]>([])
|
||||||
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
|
|
||||||
|
const currentBreakpoint = useCurrentBreakpoint()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<DropdownMenu onOpenChange={() => setIsOpen(!isOpen)}>
|
||||||
|
<Button
|
||||||
|
size={32}
|
||||||
|
variant="outline"
|
||||||
|
iconAfter={
|
||||||
|
<div
|
||||||
|
className={`transition-transform ${
|
||||||
|
isOpen ? 'rotate-180' : 'rotate-0'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<DropdownIcon size={20} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Button>
|
||||||
|
<DropdownMenu.Content
|
||||||
|
sideOffset={10}
|
||||||
|
align={currentBreakpoint === '2xl' ? 'end' : 'start'}
|
||||||
|
>
|
||||||
|
<div className="p-2 px-1">
|
||||||
|
<Input
|
||||||
|
placeholder={placeholder || 'Search'}
|
||||||
|
icon={<SearchIcon size={20} />}
|
||||||
|
size={32}
|
||||||
|
value={filterText}
|
||||||
|
onChangeText={setFilterText}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{filteredData.map(filtered => {
|
||||||
|
return (
|
||||||
|
<DropdownMenu.CheckboxItem
|
||||||
|
key={filtered.id}
|
||||||
|
icon={<RenderIcon {...filtered} />}
|
||||||
|
label={filtered.name}
|
||||||
|
checked={selectedValues.includes(filtered.id)}
|
||||||
|
onSelect={() => {
|
||||||
|
if (selectedValues.includes(filtered.id)) {
|
||||||
|
setSelectedValues(
|
||||||
|
selectedValues.filter(id => id !== filtered.id)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
setSelectedValues([...selectedValues, filtered.id])
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
{filteredData.length === 0 && (
|
||||||
|
<div className="flex flex-col items-center justify-center p-2 py-1">
|
||||||
|
<Image
|
||||||
|
className="pb-3 invert"
|
||||||
|
alt="No results"
|
||||||
|
src={'/assets/filters/empty.png'}
|
||||||
|
width={80}
|
||||||
|
height={80}
|
||||||
|
/>
|
||||||
|
<div className="pb-[2px]">
|
||||||
|
<Text size={15} weight="semibold">
|
||||||
|
No options found
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className="text-center">
|
||||||
|
<Text size={13}>
|
||||||
|
We didn't find results that match your search
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { DropdownFilter }
|
||||||
|
export type { Props as DropdownFilterProps }
|
|
@ -0,0 +1,72 @@
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
import { IconButton, Text } from '@status-im/components'
|
||||||
|
import { DropdownMenu } from '@status-im/components/src/dropdown-menu'
|
||||||
|
import { SortIcon } from '@status-im/icons'
|
||||||
|
import Image from 'next/image'
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
data: Data[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const DropdownSort = (props: Props) => {
|
||||||
|
const { data } = props
|
||||||
|
|
||||||
|
const [selectedValue, setSelectedValue] = useState<number>()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<DropdownMenu>
|
||||||
|
<div className="relative">
|
||||||
|
<IconButton icon={<SortIcon size={20} />} variant="outline" />
|
||||||
|
</div>
|
||||||
|
<DropdownMenu.Content sideOffset={10} align="end">
|
||||||
|
<div className="p-2">
|
||||||
|
<Text size={13} color="$neutral-80">
|
||||||
|
Sort by
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
{data.map(option => {
|
||||||
|
return (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
key={option.id}
|
||||||
|
label={option.name}
|
||||||
|
onSelect={() => {
|
||||||
|
setSelectedValue(option.id)
|
||||||
|
}}
|
||||||
|
selected={selectedValue === option.id}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
{data.length === 0 && (
|
||||||
|
<div className="flex flex-col items-center justify-center p-2 py-1">
|
||||||
|
<Image
|
||||||
|
className="pb-3 invert"
|
||||||
|
alt="No results"
|
||||||
|
src={'/assets/filters/empty.png'}
|
||||||
|
width={80}
|
||||||
|
height={80}
|
||||||
|
/>
|
||||||
|
<div className="pb-[2px]">
|
||||||
|
<Text size={15} weight="semibold">
|
||||||
|
No options found
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className="text-center">
|
||||||
|
<Text size={13}>We didn't find any results</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { DropdownSort }
|
||||||
|
export type { Props as DropdownSortProps }
|
|
@ -0,0 +1,3 @@
|
||||||
|
export { DropdownFilter } from './dropdown-filter'
|
||||||
|
export { DropdownSort } from './dropdown-sort'
|
||||||
|
export { Tabs } from './tabs'
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
import { DoneIcon, OpenIcon } from '@status-im/icons'
|
||||||
|
|
||||||
|
const Tabs = (): JSX.Element => {
|
||||||
|
const [activeTab, setActiveTab] = useState<'open' | 'closed'>('open')
|
||||||
|
|
||||||
|
const isOpen = activeTab === 'open'
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex">
|
||||||
|
<div className="flex items-center pr-4">
|
||||||
|
<button
|
||||||
|
className={`flex cursor-pointer flex-row items-center transition-colors ${
|
||||||
|
isOpen ? 'text-neutral-100' : 'text-neutral-50'
|
||||||
|
}`}
|
||||||
|
onClick={() => setActiveTab('open')}
|
||||||
|
>
|
||||||
|
<OpenIcon size={20} color={isOpen ? '$neutral-100' : '$neutral-50'} />
|
||||||
|
<span className="pl-1 text-[15px]">784 Open</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center pr-3">
|
||||||
|
<button
|
||||||
|
className={`flex cursor-pointer flex-row items-center transition-colors ${
|
||||||
|
!isOpen ? 'text-neutral-100' : 'text-neutral-50'
|
||||||
|
}`}
|
||||||
|
onClick={() => setActiveTab('closed')}
|
||||||
|
>
|
||||||
|
<DoneIcon
|
||||||
|
size={20}
|
||||||
|
color={!isOpen ? '$neutral-100' : '$neutral-50'}
|
||||||
|
/>
|
||||||
|
<span className="pl-1 text-[15px]">1012 Closed</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Tabs }
|
|
@ -0,0 +1 @@
|
||||||
|
export { TableIssues } from './table-issues'
|
|
@ -0,0 +1,324 @@
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
import { Avatar, Button, Input, Tag, Text } from '@status-im/components'
|
||||||
|
import { ProfileIcon, SearchIcon } from '@status-im/icons'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
import { useCurrentBreakpoint } from '@/hooks/use-current-breakpoint'
|
||||||
|
|
||||||
|
import { DropdownFilter, DropdownSort, Tabs } from './filters'
|
||||||
|
|
||||||
|
import type { DropdownFilterProps } from './filters/dropdown-filter'
|
||||||
|
import type { DropdownSortProps } from './filters/dropdown-sort'
|
||||||
|
|
||||||
|
const issues = [
|
||||||
|
{
|
||||||
|
id: 5154,
|
||||||
|
title: 'Add support for encrypted communities',
|
||||||
|
status: 'open',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5155,
|
||||||
|
title: 'Add support for encrypted communities',
|
||||||
|
status: 'open',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
title: 'Add support for encrypted communities',
|
||||||
|
status: 'open',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4324,
|
||||||
|
title: 'Add support for encrypted communities',
|
||||||
|
status: 'open',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 134,
|
||||||
|
title: 'Add support for encrypted communities',
|
||||||
|
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: DropdownFilterProps['data'] = [
|
||||||
|
{
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const epics: DropdownFilterProps['data'] = [
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: 'E:ActivityCenter',
|
||||||
|
color: '$orange-60',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: 'E:Keycard',
|
||||||
|
color: '$purple-60',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: 'E:Wallet',
|
||||||
|
color: '$pink-60',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: 'E:Chat',
|
||||||
|
color: '$beige-60',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const labels: DropdownFilterProps['data'] = [
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: 'Mobile',
|
||||||
|
color: '$blue-60',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: 'Frontend',
|
||||||
|
color: '$brown-50',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: 'Backend',
|
||||||
|
color: '$red-60',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: 'Desktop',
|
||||||
|
color: '$green-60',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const assignees: DropdownFilterProps['data'] = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Unassigned',
|
||||||
|
avatar: <ProfileIcon size={16} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const repositories: DropdownFilterProps['data'] = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'status-mobile',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'status-desktop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'status-web',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: 'status-go',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: 'nwaku',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: 'go-waku',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: 'js-waku',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
name: 'nimbus-eth2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
name: 'help.status.im',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const sortOptions: DropdownSortProps['data'] = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Default',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Alphabetical',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Creation date',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: 'Updated',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: 'Completion',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const TableIssues = () => {
|
||||||
|
const [issuesSearchText, setIssuesSearchText] = useState('')
|
||||||
|
|
||||||
|
const currentBreakpoint = useCurrentBreakpoint()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="overflow-hidden rounded-2xl border border-neutral-10">
|
||||||
|
<div className="flex border-b border-neutral-10 bg-neutral-5 p-3">
|
||||||
|
<div className="flex w-full flex-col 2xl:flex-row 2xl:justify-between">
|
||||||
|
<Tabs />
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center 2xl:justify-end">
|
||||||
|
<div className="flex w-full justify-between pt-4 2xl:justify-end 2xl:pt-0">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<div className="transition-all">
|
||||||
|
<Input
|
||||||
|
placeholder="Find Author"
|
||||||
|
icon={<SearchIcon size={20} />}
|
||||||
|
size={32}
|
||||||
|
value={issuesSearchText}
|
||||||
|
onChangeText={setIssuesSearchText}
|
||||||
|
variant="retractable"
|
||||||
|
direction={currentBreakpoint === '2xl' ? 'rtl' : 'ltr'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DropdownFilter
|
||||||
|
data={authors}
|
||||||
|
label="Author"
|
||||||
|
placeholder="Find author"
|
||||||
|
/>
|
||||||
|
<DropdownFilter
|
||||||
|
data={epics}
|
||||||
|
label="Epics"
|
||||||
|
placeholder="Find epic"
|
||||||
|
/>
|
||||||
|
<DropdownFilter
|
||||||
|
data={labels}
|
||||||
|
label="Labels"
|
||||||
|
placeholder="Find label"
|
||||||
|
/>
|
||||||
|
<DropdownFilter
|
||||||
|
data={assignees}
|
||||||
|
label="Assignee"
|
||||||
|
placeholder="Find assignee"
|
||||||
|
/>
|
||||||
|
<DropdownFilter
|
||||||
|
data={repositories}
|
||||||
|
label="Repos"
|
||||||
|
placeholder="Find repo"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="pl-2">
|
||||||
|
<DropdownSort data={sortOptions} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="divide-y divide-neutral-10">
|
||||||
|
{issues.map(issue => (
|
||||||
|
<Link
|
||||||
|
key={issue.id}
|
||||||
|
href={`https://github.com/status-im/status-react/issues/${issue.id}`}
|
||||||
|
className="flex items-center justify-between px-4 py-3 transition-colors duration-200 hover:bg-neutral-5"
|
||||||
|
>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<Text size={15} weight="medium">
|
||||||
|
{issue.title}
|
||||||
|
</Text>
|
||||||
|
<Text size={13} color="$neutral-50">
|
||||||
|
#9667 • Opened 2 days ago by slaedjenic
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex gap-3">
|
||||||
|
<div className="flex gap-1">
|
||||||
|
<Tag size={24} label="E:Syncing" color="$orange-50" />
|
||||||
|
<Tag size={24} label="E:Wallet" color="$green-50" />
|
||||||
|
<Tag size={24} label="Feature" color="$pink-50" />
|
||||||
|
<Tag size={24} label="Web" color="$purple-50" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tag size={24} label="9435" />
|
||||||
|
|
||||||
|
<Avatar
|
||||||
|
type="user"
|
||||||
|
size={24}
|
||||||
|
name="jkbktl"
|
||||||
|
src="https://images.unsplash.com/photo-1552058544-f2b08422138a?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1299&q=80"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-3">
|
||||||
|
<Button size={40} variant="outline">
|
||||||
|
Show more 10
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { TableIssues }
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import defaultTheme from 'tailwindcss/defaultTheme'
|
||||||
|
|
||||||
|
// If we had custom breakpoints, we could use this to get the current breakpoint but we will use the default breakpoints for now
|
||||||
|
// import resolveConfig from 'tailwindcss/resolveConfig'
|
||||||
|
// import tailwindConfig from '../../tailwind.config'
|
||||||
|
|
||||||
|
// const fullConfig = resolveConfig(tailwindConfig)
|
||||||
|
|
||||||
|
type Breakpoint = keyof (typeof defaultTheme)['screens']
|
||||||
|
|
||||||
|
export function useCurrentBreakpoint(): Breakpoint {
|
||||||
|
const [breakpoint, setBreakpoint] = useState<Breakpoint>('sm')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
const screenWidth = window.innerWidth
|
||||||
|
const breakpoints = Object.entries(defaultTheme.screens) as [
|
||||||
|
Breakpoint,
|
||||||
|
string
|
||||||
|
][]
|
||||||
|
|
||||||
|
for (let i = breakpoints.length - 1; i >= 0; i--) {
|
||||||
|
const [breakpoint, minWidth] = breakpoints[i]
|
||||||
|
|
||||||
|
const convertedMinWidth = parseInt(minWidth, 10)
|
||||||
|
|
||||||
|
if (screenWidth >= convertedMinWidth) {
|
||||||
|
setBreakpoint(breakpoint)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleResize()
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', handleResize)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return breakpoint
|
||||||
|
}
|
|
@ -1,6 +1,4 @@
|
||||||
import { Breadcrumbs } from '@/components'
|
import { Breadcrumbs, EpicOverview, TableIssues } from '@/components'
|
||||||
import { EpicOverview } from '@/components/epic-overview'
|
|
||||||
import { TableIssues } from '@/components/table-issues'
|
|
||||||
import { InsightsLayout } from '@/layouts/insights-layout'
|
import { InsightsLayout } from '@/layouts/insights-layout'
|
||||||
|
|
||||||
import type { Page } from 'next'
|
import type { Page } from 'next'
|
||||||
|
@ -11,13 +9,14 @@ const EpicsDetailPage: Page = () => {
|
||||||
<div className="border-b border-neutral-10 px-5 py-3">
|
<div className="border-b border-neutral-10 px-5 py-3">
|
||||||
<Breadcrumbs />
|
<Breadcrumbs />
|
||||||
</div>
|
</div>
|
||||||
<div className="px-10 py-6">
|
<div className="border-b border-neutral-10 px-10 py-6">
|
||||||
<EpicOverview
|
<EpicOverview
|
||||||
title="Communities protocol"
|
title="Communities protocol"
|
||||||
description="Detecting keycard reader removal for the beginning of each flow"
|
description="Detecting keycard reader removal for the beginning of each flow"
|
||||||
fullscreen
|
fullscreen
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="border-b border-neutral-10 px-10 py-6">
|
||||||
<div role="separator" className="-mx-6 my-6 h-px bg-neutral-10" />
|
<div role="separator" className="-mx-6 my-6 h-px bg-neutral-10" />
|
||||||
|
|
||||||
<TableIssues />
|
<TableIssues />
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Text } from '@status-im/components'
|
import { Text } from '@status-im/components'
|
||||||
|
|
||||||
import { TableIssues } from '@/components/table-issues'
|
import { TableIssues } from '@/components'
|
||||||
import { InsightsLayout } from '@/layouts/insights-layout'
|
import { InsightsLayout } from '@/layouts/insights-layout'
|
||||||
|
|
||||||
import type { Page } from 'next'
|
import type { Page } from 'next'
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Text } from '@status-im/components'
|
import { Shadow, Text } from '@status-im/components'
|
||||||
|
import { OpenIcon, UnlockedIcon } from '@status-im/icons'
|
||||||
|
|
||||||
import { Link } from '@/components/link'
|
import { Link } from '@/components/link'
|
||||||
import { InsightsLayout } from '@/layouts/insights-layout'
|
import { InsightsLayout } from '@/layouts/insights-layout'
|
||||||
|
@ -30,6 +31,24 @@ const repos = [
|
||||||
issues: 10,
|
issues: 10,
|
||||||
stars: 5,
|
stars: 5,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'nim-waku',
|
||||||
|
description: 'a free (libre) open source, mobile OS for Ethereum.',
|
||||||
|
issues: 10,
|
||||||
|
stars: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'go-waku',
|
||||||
|
description: 'a free (libre) open source, mobile OS for Ethereum.',
|
||||||
|
issues: 10,
|
||||||
|
stars: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'js-waku',
|
||||||
|
description: 'a free (libre) open source, mobile OS for Ethereum.',
|
||||||
|
issues: 10,
|
||||||
|
stars: 5,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'nimbus-eth2',
|
name: 'nimbus-eth2',
|
||||||
description: 'a free (libre) open source, mobile OS for Ethereum.',
|
description: 'a free (libre) open source, mobile OS for Ethereum.',
|
||||||
|
@ -55,30 +74,48 @@ const ReposPage: Page = () => {
|
||||||
|
|
||||||
<div className="grid grid-cols-3 gap-5">
|
<div className="grid grid-cols-3 gap-5">
|
||||||
{repos.map(repo => (
|
{repos.map(repo => (
|
||||||
<Link
|
<Shadow key={repo.name}>
|
||||||
key={repo.name}
|
<Link
|
||||||
href={`https://github.com/status-im/${repo.name}`}
|
href={`https://github.com/status-im/${repo.name}`}
|
||||||
className="flex h-[124px] flex-col rounded-2xl border border-neutral-10 px-4 py-3 transition-colors duration-200 hover:border-neutral-40"
|
className="flex h-[124px] flex-col justify-between rounded-2xl border border-neutral-10 px-4 py-3 transition-colors duration-200 hover:border-neutral-40"
|
||||||
>
|
>
|
||||||
<Text size={15} weight="semibold">
|
<div className="flex flex-col">
|
||||||
{repo.name}
|
<Text size={15} weight="semibold">
|
||||||
</Text>
|
{repo.name}
|
||||||
<Text size={15} color="$neutral-50">
|
</Text>
|
||||||
{repo.description}
|
<Text size={15} color="$neutral-50">
|
||||||
</Text>
|
{repo.description}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-3 pt-4">
|
<div className="flex gap-3 pt-4">
|
||||||
<Text size={13} weight="medium" color="$neutral-50">
|
<div className="flex items-center">
|
||||||
Public
|
<div className="pr-1">
|
||||||
</Text>
|
<UnlockedIcon size={12} color="$neutral-50" />
|
||||||
<Text size={13} weight="medium" color="$neutral-50">
|
</div>
|
||||||
42 Issues
|
<Text size={13} weight="medium" color="$neutral-100">
|
||||||
</Text>
|
Public
|
||||||
<Text size={13} weight="medium" color="$neutral-50">
|
</Text>
|
||||||
32
|
</div>
|
||||||
</Text>
|
<div className="flex items-center">
|
||||||
</div>
|
<div className="pr-1">
|
||||||
</Link>
|
<OpenIcon size={12} color="$neutral-50" />
|
||||||
|
</div>
|
||||||
|
<Text size={13} weight="medium" color="$neutral-100">
|
||||||
|
42 issues
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<div className="pr-1">
|
||||||
|
<OpenIcon size={12} color="$neutral-50" />
|
||||||
|
</div>
|
||||||
|
<Text size={13} weight="medium" color="$neutral-100">
|
||||||
|
32
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</Shadow>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import { Breadcrumbs } from '@/components'
|
import { Breadcrumbs, EpicOverview, TableIssues } from '@/components'
|
||||||
import { EpicOverview } from '@/components/epic-overview'
|
|
||||||
import { TableIssues } from '@/components/table-issues'
|
|
||||||
import { InsightsLayout } from '@/layouts/insights-layout'
|
import { InsightsLayout } from '@/layouts/insights-layout'
|
||||||
|
|
||||||
import type { Page } from 'next'
|
import type { Page } from 'next'
|
||||||
|
@ -11,13 +9,14 @@ const WorkstreamDetailPage: Page = () => {
|
||||||
<div className="border-b border-neutral-10 px-5 py-3">
|
<div className="border-b border-neutral-10 px-5 py-3">
|
||||||
<Breadcrumbs />
|
<Breadcrumbs />
|
||||||
</div>
|
</div>
|
||||||
<div className="px-10 py-6">
|
<div className="border-b border-neutral-10 px-10 py-6">
|
||||||
<EpicOverview
|
<EpicOverview
|
||||||
title="Communities protocol"
|
title="Communities protocol"
|
||||||
description="Detecting keycard reader removal for the beginning of each flow"
|
description="Detecting keycard reader removal for the beginning of each flow"
|
||||||
fullscreen
|
fullscreen
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="border-b border-neutral-10 px-10 py-6">
|
||||||
<div role="separator" className="-mx-6 my-6 h-px bg-neutral-10" />
|
<div role="separator" className="-mx-6 my-6 h-px bg-neutral-10" />
|
||||||
|
|
||||||
<TableIssues />
|
<TableIssues />
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/react-accordion": "^1.1.1",
|
"@radix-ui/react-accordion": "^1.1.1",
|
||||||
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
"@radix-ui/react-dialog": "^1.0.3",
|
"@radix-ui/react-dialog": "^1.0.3",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.0.4",
|
"@radix-ui/react-dropdown-menu": "^2.0.4",
|
||||||
"@radix-ui/react-popover": "^1.0.5",
|
"@radix-ui/react-popover": "^1.0.5",
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
import { Checkbox } from './checkbox'
|
||||||
|
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
|
const meta: Meta<typeof Checkbox> = {
|
||||||
|
component: Checkbox,
|
||||||
|
argTypes: {},
|
||||||
|
parameters: {
|
||||||
|
design: {
|
||||||
|
type: 'figma',
|
||||||
|
url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=180-9685&t=tDEqIV09qddTZgXF-4',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof Checkbox>
|
||||||
|
|
||||||
|
const CheckBoxWithHookFilled = () => {
|
||||||
|
const [checked, setChecked] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Checkbox
|
||||||
|
id="checkbox"
|
||||||
|
selected={checked}
|
||||||
|
onCheckedChange={() => setChecked(!checked)}
|
||||||
|
variant="filled"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CheckBoxWithHookOutlined = () => {
|
||||||
|
const [checked, setChecked] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Checkbox
|
||||||
|
id="checkbox"
|
||||||
|
selected={checked}
|
||||||
|
onCheckedChange={() => setChecked(!checked)}
|
||||||
|
variant="outline"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Filled: Story = {
|
||||||
|
render: () => {
|
||||||
|
return <CheckBoxWithHookFilled />
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Outlined: Story = {
|
||||||
|
render: () => {
|
||||||
|
return <CheckBoxWithHookOutlined />
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default meta
|
|
@ -0,0 +1,124 @@
|
||||||
|
import { Indicator as _Indicator, Root } from '@radix-ui/react-checkbox'
|
||||||
|
import { CheckIcon } from '@status-im/icons'
|
||||||
|
import { styled } from '@tamagui/core'
|
||||||
|
|
||||||
|
import type { GetVariants } from '../types'
|
||||||
|
import type { IconProps } from '@status-im/icons'
|
||||||
|
import type { ColorTokens } from '@tamagui/core'
|
||||||
|
|
||||||
|
type Variants = GetVariants<typeof Base>
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
selected?: boolean
|
||||||
|
onCheckedChange?: (checked: boolean) => void
|
||||||
|
id: string
|
||||||
|
size?: 32 | 20
|
||||||
|
variant?: Variants['variant']
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconColor: Record<Variants['variant'], ColorTokens> = {
|
||||||
|
filled: '$neutral-50',
|
||||||
|
outline: '$white-100',
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconSize: Record<Variants['size'], IconProps['size']> = {
|
||||||
|
32: 20,
|
||||||
|
20: 16,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Checkbox = (props: Props) => {
|
||||||
|
const { id, selected, onCheckedChange, size = 20, variant = 'filled' } = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Base
|
||||||
|
id={id}
|
||||||
|
selected={selected ? variant : undefined}
|
||||||
|
size={size}
|
||||||
|
onCheckedChange={onCheckedChange}
|
||||||
|
variant={variant}
|
||||||
|
checked={selected}
|
||||||
|
>
|
||||||
|
<Indicator>
|
||||||
|
<CheckIcon size={iconSize[size]} color={iconColor[variant]} />
|
||||||
|
</Indicator>
|
||||||
|
</Base>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Checkbox }
|
||||||
|
export type { Props as CheckboxProps }
|
||||||
|
|
||||||
|
const Base = styled(Root, {
|
||||||
|
name: 'Checkbox',
|
||||||
|
tag: 'span',
|
||||||
|
accessibilityRole: 'checkbox',
|
||||||
|
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
borderRadius: '$2',
|
||||||
|
|
||||||
|
cursor: 'pointer',
|
||||||
|
animation: 'fast',
|
||||||
|
|
||||||
|
height: 32,
|
||||||
|
width: 32,
|
||||||
|
borderWidth: 1,
|
||||||
|
|
||||||
|
variants: {
|
||||||
|
size: {
|
||||||
|
32: {
|
||||||
|
height: 32,
|
||||||
|
width: 32,
|
||||||
|
},
|
||||||
|
20: {
|
||||||
|
height: 20,
|
||||||
|
width: 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
filled: {
|
||||||
|
backgroundColor: '$neutral-20',
|
||||||
|
|
||||||
|
hoverStyle: { backgroundColor: '$neutral-30' },
|
||||||
|
pressStyle: { backgroundColor: '$neutral-30' },
|
||||||
|
},
|
||||||
|
outline: {
|
||||||
|
borderColor: '$neutral-20',
|
||||||
|
|
||||||
|
hoverStyle: { borderColor: '$neutral-30' },
|
||||||
|
pressStyle: { borderColor: '$neutral-30' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
selected: {
|
||||||
|
filled: {
|
||||||
|
hoverStyle: { backgroundColor: '$primary-60' },
|
||||||
|
pressStyle: { backgroundColor: '$primary-60' },
|
||||||
|
},
|
||||||
|
outline: {
|
||||||
|
backgroundColor: '$primary-50',
|
||||||
|
borderColor: '$primary-50',
|
||||||
|
|
||||||
|
hoverStyle: {
|
||||||
|
backgroundColor: '$primary-60',
|
||||||
|
},
|
||||||
|
pressStyle: {
|
||||||
|
backgroundColor: '$primary-60',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
disabled: {
|
||||||
|
true: {
|
||||||
|
opacity: 0.3,
|
||||||
|
cursor: 'default',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const,
|
||||||
|
})
|
||||||
|
|
||||||
|
const Indicator = styled(_Indicator, {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
})
|
|
@ -0,0 +1 @@
|
||||||
|
export { Checkbox } from './checkbox'
|
|
@ -1,6 +1,7 @@
|
||||||
import { cloneElement } from 'react'
|
import { cloneElement, forwardRef } from 'react'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
CheckboxItem,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
|
@ -8,8 +9,10 @@ import {
|
||||||
Root,
|
Root,
|
||||||
Trigger,
|
Trigger,
|
||||||
} from '@radix-ui/react-dropdown-menu'
|
} from '@radix-ui/react-dropdown-menu'
|
||||||
import { styled } from '@tamagui/core'
|
import { CheckIcon } from '@status-im/icons'
|
||||||
|
import { Stack, styled } from '@tamagui/core'
|
||||||
|
|
||||||
|
import { Checkbox } from '../checkbox'
|
||||||
import { Text } from '../text'
|
import { Text } from '../text'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -32,28 +35,64 @@ const DropdownMenu = (props: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DropdownMenuItemProps {
|
interface DropdownMenuItemProps {
|
||||||
icon: React.ReactElement
|
icon?: React.ReactElement
|
||||||
label: string
|
label: string
|
||||||
onSelect: () => void
|
onSelect: () => void
|
||||||
|
selected?: boolean
|
||||||
danger?: boolean
|
danger?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const MenuItem = (props: DropdownMenuItemProps) => {
|
const MenuItem = (props: DropdownMenuItemProps) => {
|
||||||
const { icon, label, onSelect, danger } = props
|
const { icon, label, onSelect, danger, selected } = props
|
||||||
|
|
||||||
const iconColor = danger ? '$danger-50' : '$neutral-50'
|
const iconColor = danger ? '$danger-50' : '$neutral-50'
|
||||||
const textColor = danger ? '$danger-50' : '$neutral-100'
|
const textColor = danger ? '$danger-50' : '$neutral-100'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemBase onSelect={onSelect}>
|
<ItemBase onSelect={onSelect}>
|
||||||
{cloneElement(icon, { color: iconColor })}
|
<Stack flexDirection="row" gap={8} alignItems="center">
|
||||||
<Text size={15} weight="medium" color={textColor}>
|
{icon && cloneElement(icon, { color: iconColor })}
|
||||||
{label}
|
<Text size={15} weight="medium" color={textColor}>
|
||||||
</Text>
|
{label}
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
{selected && <CheckIcon size={20} color={iconColor} />}
|
||||||
</ItemBase>
|
</ItemBase>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface DropdownMenuCheckboxItemProps {
|
||||||
|
icon?: React.ReactElement
|
||||||
|
label: string
|
||||||
|
onSelect: () => void
|
||||||
|
checked?: boolean
|
||||||
|
danger?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const DropdownMenuCheckboxItem = forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
DropdownMenuCheckboxItemProps
|
||||||
|
>(function _DropdownMenuCheckboxItem(props, forwardedRef) {
|
||||||
|
const { checked, label, icon, onSelect } = props
|
||||||
|
|
||||||
|
const handleSelect = (event: Event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
onSelect()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ItemBaseCheckbox {...props} ref={forwardedRef} onSelect={handleSelect}>
|
||||||
|
<Stack flexDirection="row" gap={8} alignItems="center">
|
||||||
|
{icon && cloneElement(icon)}
|
||||||
|
<Text size={15} weight="medium" color="$neutral-100">
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
<Checkbox id={label} selected={checked} variant="outline" />
|
||||||
|
</ItemBaseCheckbox>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
const Content = styled(DropdownMenuContent, {
|
const Content = styled(DropdownMenuContent, {
|
||||||
name: 'DropdownMenuContent',
|
name: 'DropdownMenuContent',
|
||||||
acceptsClassName: true,
|
acceptsClassName: true,
|
||||||
|
@ -74,6 +113,32 @@ const ItemBase = styled(DropdownMenuItem, {
|
||||||
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
|
||||||
|
height: 32,
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
borderRadius: '$10',
|
||||||
|
cursor: 'pointer',
|
||||||
|
userSelect: 'none',
|
||||||
|
gap: 8,
|
||||||
|
|
||||||
|
hoverStyle: {
|
||||||
|
backgroundColor: '$neutral-5',
|
||||||
|
},
|
||||||
|
|
||||||
|
pressStyle: {
|
||||||
|
backgroundColor: '$neutral-10',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const ItemBaseCheckbox = styled(CheckboxItem, {
|
||||||
|
name: 'DropdownMenuCheckboxItem',
|
||||||
|
acceptsClassName: true,
|
||||||
|
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
|
||||||
height: 32,
|
height: 32,
|
||||||
paddingHorizontal: 8,
|
paddingHorizontal: 8,
|
||||||
borderRadius: '$10',
|
borderRadius: '$10',
|
||||||
|
@ -104,6 +169,7 @@ const Separator = styled(DropdownMenuSeparator, {
|
||||||
DropdownMenu.Content = Content
|
DropdownMenu.Content = Content
|
||||||
DropdownMenu.Item = MenuItem
|
DropdownMenu.Item = MenuItem
|
||||||
DropdownMenu.Separator = Separator
|
DropdownMenu.Separator = Separator
|
||||||
|
DropdownMenu.CheckboxItem = DropdownMenuCheckboxItem
|
||||||
|
|
||||||
export { DropdownMenu }
|
export { DropdownMenu }
|
||||||
export type DropdownMenuProps = Omit<Props, 'children'>
|
export type DropdownMenuProps = Omit<Props, 'children'>
|
||||||
|
|
|
@ -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'
|
||||||
|
|
||||||
|
@ -93,8 +93,8 @@ const Base = styled(Stack, {
|
||||||
|
|
||||||
outline: {
|
outline: {
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
borderColor: '$neutral-20',
|
borderColor: '$neutral-30',
|
||||||
hoverStyle: { borderColor: '$neutral-30' },
|
hoverStyle: { borderColor: '$neutral-40' },
|
||||||
pressStyle: {
|
pressStyle: {
|
||||||
borderColor: '$neutral-20',
|
borderColor: '$neutral-20',
|
||||||
backgroundColor: '$neutral-10',
|
backgroundColor: '$neutral-10',
|
||||||
|
|
|
@ -2,11 +2,13 @@ export * from './anchor-actions'
|
||||||
export * from './avatar'
|
export * from './avatar'
|
||||||
export * from './button'
|
export * from './button'
|
||||||
export * from './calendar'
|
export * from './calendar'
|
||||||
|
export * from './checkbox'
|
||||||
export * from './community'
|
export * from './community'
|
||||||
export * from './composer'
|
export * from './composer'
|
||||||
export * from './context-tag'
|
export * from './context-tag'
|
||||||
export * from './counter'
|
export * from './counter'
|
||||||
export * from './dividers'
|
export * from './dividers'
|
||||||
|
export * from './dropdown-menu'
|
||||||
export * from './dynamic-button'
|
export * from './dynamic-button'
|
||||||
export * from './gap-messages'
|
export * from './gap-messages'
|
||||||
export * from './icon-button'
|
export * from './icon-button'
|
||||||
|
|
|
@ -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'
|
||||||
|
@ -14,7 +18,70 @@ type Story = StoryObj<typeof Input>
|
||||||
export const Primary: Story = {
|
export const Primary: Story = {
|
||||||
args: {
|
args: {
|
||||||
placeholder: 'Type something...',
|
placeholder: 'Type something...',
|
||||||
// children: 'Click me',
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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!'),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputSearchMinimzed = () => {
|
||||||
|
const [value, setValue] = useState('')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Input
|
||||||
|
placeholder="Please type something..."
|
||||||
|
value={value}
|
||||||
|
onChangeText={setValue}
|
||||||
|
icon={<SearchIcon size={20} />}
|
||||||
|
onClear={() => setValue('')}
|
||||||
|
size={32}
|
||||||
|
direction="rtl"
|
||||||
|
variant="retractable"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Minimized: Story = {
|
||||||
|
render: () => <InputSearchMinimzed />,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CompleteExample: Story = {
|
||||||
|
render: () => <InputSearch />,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WithError: Story = {
|
||||||
|
args: {
|
||||||
|
placeholder: 'Type something...',
|
||||||
|
error: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,62 +1,229 @@
|
||||||
import { setupReactNative, styled } from '@tamagui/core'
|
import { cloneElement, forwardRef, useRef, useState } from 'react'
|
||||||
|
|
||||||
|
import { composeRefs } from '@radix-ui/react-compose-refs'
|
||||||
|
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 { 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(
|
type Props = GetProps<typeof InputFrame> & {
|
||||||
|
button?: {
|
||||||
|
label: string
|
||||||
|
onPress: () => void
|
||||||
|
}
|
||||||
|
endLabel?: string
|
||||||
|
icon?: React.ReactElement
|
||||||
|
label?: string
|
||||||
|
onClear?: () => void
|
||||||
|
variant?: 'default' | 'retractable'
|
||||||
|
size?: 40 | 32
|
||||||
|
error?: boolean
|
||||||
|
direction?: 'ltr' | 'rtl'
|
||||||
|
}
|
||||||
|
|
||||||
|
const _Input = (props: Props, ref: Ref<TextInput>) => {
|
||||||
|
const {
|
||||||
|
button,
|
||||||
|
color = '$neutral-50',
|
||||||
|
endLabel,
|
||||||
|
error,
|
||||||
|
icon,
|
||||||
|
label,
|
||||||
|
onClear,
|
||||||
|
size = 40,
|
||||||
|
placeholder,
|
||||||
|
value,
|
||||||
|
direction = 'ltr',
|
||||||
|
variant = 'default',
|
||||||
|
...rest
|
||||||
|
} = props
|
||||||
|
|
||||||
|
const [isMinimized, setIsMinimized] = useState(variant === 'retractable')
|
||||||
|
|
||||||
|
const isRetractable = variant === 'retractable'
|
||||||
|
|
||||||
|
const inputRef = useRef<TextInput>(null)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack flexDirection={direction === 'ltr' ? 'row' : 'row-reverse'}>
|
||||||
|
{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}
|
||||||
|
error={error}
|
||||||
|
minimized={isMinimized}
|
||||||
|
onPress={event => {
|
||||||
|
event.stopPropagation()
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
if (isRetractable && isMinimized) {
|
||||||
|
setIsMinimized(false)
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore ref is not inferred correctly here
|
||||||
|
inputRef?.current?.focus()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{icon ? (
|
||||||
|
<Stack flexShrink={0}>{cloneElement(icon, { color })}</Stack>
|
||||||
|
) : null}
|
||||||
|
<InputBase
|
||||||
|
value={value}
|
||||||
|
placeholder={isMinimized && !value ? '' : placeholder}
|
||||||
|
flex={1}
|
||||||
|
ref={composeRefs(ref, inputRef)}
|
||||||
|
onBlur={() => {
|
||||||
|
if (!value && isRetractable && !isMinimized) {
|
||||||
|
setIsMinimized(true)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
<Stack flexDirection="row" alignItems="center">
|
||||||
|
{Boolean(onClear) && !!value && (
|
||||||
|
<Stack
|
||||||
|
role="button"
|
||||||
|
accessibilityRole="button"
|
||||||
|
pr={4}
|
||||||
|
onPress={onClear}
|
||||||
|
cursor="pointer"
|
||||||
|
hoverStyle={{ opacity: 0.6 }}
|
||||||
|
animation="fast"
|
||||||
|
>
|
||||||
|
<ClearIcon size={20} />
|
||||||
|
</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 }
|
||||||
|
|
||||||
|
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 InputBase = focusableInputHOC(InputFrame)
|
||||||
|
|
||||||
export const Input = focusableInputHOC(InputFrame)
|
const InputContainer = styled(Stack, {
|
||||||
|
name: 'InputContainer',
|
||||||
|
tag: 'div',
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 8,
|
||||||
|
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: '$neutral-30',
|
||||||
|
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
|
||||||
|
animation: 'fast',
|
||||||
|
width: '100%',
|
||||||
|
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
minimized: {
|
||||||
|
true: {
|
||||||
|
width: 32,
|
||||||
|
paddingHorizontal: 0,
|
||||||
|
paddingLeft: 5,
|
||||||
|
|
||||||
|
cursor: 'pointer',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
true: {
|
||||||
|
borderColor: '$danger-50-opa-40',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
disabled: {
|
||||||
|
true: {
|
||||||
|
opacity: 0.3,
|
||||||
|
cursor: 'default',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const,
|
||||||
|
})
|
||||||
|
|
|
@ -42,7 +42,7 @@ export const Default: Story = {
|
||||||
<Tag label="New tag" size={24} disabled selected />
|
<Tag label="New tag" size={24} disabled selected />
|
||||||
<Tag label="New tag" size={24} color="#FF7D46" />
|
<Tag label="New tag" size={24} color="#FF7D46" />
|
||||||
|
|
||||||
<Tag label="New tag #7140FD" size={24} color="#BA34F5" />
|
<Tag label="New tag #BA34F5" size={24} color="#BA34F5" />
|
||||||
<Tag label="New tag #7140FD" size={24} color="#7140FD" icon="🧙♂️" />
|
<Tag label="New tag #7140FD" size={24} color="#7140FD" icon="🧙♂️" />
|
||||||
|
|
||||||
<Tag
|
<Tag
|
||||||
|
|
98
yarn.lock
98
yarn.lock
|
@ -4167,6 +4167,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/primitive@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd"
|
||||||
|
integrity sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
"@radix-ui/react-accordion@^1.1.1":
|
"@radix-ui/react-accordion@^1.1.1":
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-accordion/-/react-accordion-1.1.1.tgz#fa1ab1b5c6a29aa75aefaf306a9e72fe3a482dbc"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-accordion/-/react-accordion-1.1.1.tgz#fa1ab1b5c6a29aa75aefaf306a9e72fe3a482dbc"
|
||||||
|
@ -4191,6 +4198,21 @@
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
"@radix-ui/react-primitive" "1.0.2"
|
"@radix-ui/react-primitive" "1.0.2"
|
||||||
|
|
||||||
|
"@radix-ui/react-checkbox@^1.0.4":
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-checkbox/-/react-checkbox-1.0.4.tgz#98f22c38d5010dd6df4c5744cac74087e3275f4b"
|
||||||
|
integrity sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/primitive" "1.0.1"
|
||||||
|
"@radix-ui/react-compose-refs" "1.0.1"
|
||||||
|
"@radix-ui/react-context" "1.0.1"
|
||||||
|
"@radix-ui/react-presence" "1.0.1"
|
||||||
|
"@radix-ui/react-primitive" "1.0.3"
|
||||||
|
"@radix-ui/react-use-controllable-state" "1.0.1"
|
||||||
|
"@radix-ui/react-use-previous" "1.0.1"
|
||||||
|
"@radix-ui/react-use-size" "1.0.1"
|
||||||
|
|
||||||
"@radix-ui/react-collapsible@1.0.2":
|
"@radix-ui/react-collapsible@1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-1.0.2.tgz#0583470c7caa8cd1ab6f606416288d19b3baf777"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-1.0.2.tgz#0583470c7caa8cd1ab6f606416288d19b3baf777"
|
||||||
|
@ -4224,6 +4246,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-compose-refs@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989"
|
||||||
|
integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
"@radix-ui/react-context@1.0.0":
|
"@radix-ui/react-context@1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.0.tgz#f38e30c5859a9fb5e9aa9a9da452ee3ed9e0aee0"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.0.tgz#f38e30c5859a9fb5e9aa9a9da452ee3ed9e0aee0"
|
||||||
|
@ -4231,6 +4260,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-context@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c"
|
||||||
|
integrity sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
"@radix-ui/react-dialog@^1.0.3":
|
"@radix-ui/react-dialog@^1.0.3":
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.3.tgz#a715bf30f35fcd80476c0a07fcc073c1968e6d3e"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.3.tgz#a715bf30f35fcd80476c0a07fcc073c1968e6d3e"
|
||||||
|
@ -4412,6 +4448,15 @@
|
||||||
"@radix-ui/react-compose-refs" "1.0.0"
|
"@radix-ui/react-compose-refs" "1.0.0"
|
||||||
"@radix-ui/react-use-layout-effect" "1.0.0"
|
"@radix-ui/react-use-layout-effect" "1.0.0"
|
||||||
|
|
||||||
|
"@radix-ui/react-presence@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba"
|
||||||
|
integrity sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/react-compose-refs" "1.0.1"
|
||||||
|
"@radix-ui/react-use-layout-effect" "1.0.1"
|
||||||
|
|
||||||
"@radix-ui/react-primitive@1.0.2":
|
"@radix-ui/react-primitive@1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.2.tgz#54e22f49ca59ba88d8143090276d50b93f8a7053"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.2.tgz#54e22f49ca59ba88d8143090276d50b93f8a7053"
|
||||||
|
@ -4420,6 +4465,14 @@
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
"@radix-ui/react-slot" "1.0.1"
|
"@radix-ui/react-slot" "1.0.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-primitive@1.0.3":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0"
|
||||||
|
integrity sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/react-slot" "1.0.2"
|
||||||
|
|
||||||
"@radix-ui/react-roving-focus@1.0.3":
|
"@radix-ui/react-roving-focus@1.0.3":
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.3.tgz#0b4f4f9bd509f4510079e9e0734a734fd17cdce3"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.3.tgz#0b4f4f9bd509f4510079e9e0734a734fd17cdce3"
|
||||||
|
@ -4444,6 +4497,14 @@
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
"@radix-ui/react-compose-refs" "1.0.0"
|
"@radix-ui/react-compose-refs" "1.0.0"
|
||||||
|
|
||||||
|
"@radix-ui/react-slot@1.0.2":
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
|
||||||
|
integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/react-compose-refs" "1.0.1"
|
||||||
|
|
||||||
"@radix-ui/react-tabs@^1.0.3":
|
"@radix-ui/react-tabs@^1.0.3":
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-tabs/-/react-tabs-1.0.3.tgz#8b4158160a7c6633c893c74641e929d2708e709a"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-tabs/-/react-tabs-1.0.3.tgz#8b4158160a7c6633c893c74641e929d2708e709a"
|
||||||
|
@ -4511,6 +4572,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-callback-ref@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a"
|
||||||
|
integrity sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
"@radix-ui/react-use-controllable-state@1.0.0":
|
"@radix-ui/react-use-controllable-state@1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz#a64deaafbbc52d5d407afaa22d493d687c538b7f"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz#a64deaafbbc52d5d407afaa22d493d687c538b7f"
|
||||||
|
@ -4519,6 +4587,14 @@
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
"@radix-ui/react-use-callback-ref" "1.0.0"
|
"@radix-ui/react-use-callback-ref" "1.0.0"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-controllable-state@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz#ecd2ced34e6330caf89a82854aa2f77e07440286"
|
||||||
|
integrity sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/react-use-callback-ref" "1.0.1"
|
||||||
|
|
||||||
"@radix-ui/react-use-escape-keydown@1.0.2":
|
"@radix-ui/react-use-escape-keydown@1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.2.tgz#09ab6455ab240b4f0a61faf06d4e5132c4d639f6"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.2.tgz#09ab6455ab240b4f0a61faf06d4e5132c4d639f6"
|
||||||
|
@ -4542,6 +4618,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-layout-effect@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz#be8c7bc809b0c8934acf6657b577daf948a75399"
|
||||||
|
integrity sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
"@radix-ui/react-use-previous@1.0.0":
|
"@radix-ui/react-use-previous@1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.0.tgz#e48a69c3a7d8078a967084038df66d0d181c56ac"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.0.tgz#e48a69c3a7d8078a967084038df66d0d181c56ac"
|
||||||
|
@ -4549,6 +4632,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-previous@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz#b595c087b07317a4f143696c6a01de43b0d0ec66"
|
||||||
|
integrity sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
|
||||||
"@radix-ui/react-use-previous@^0.1.1":
|
"@radix-ui/react-use-previous@^0.1.1":
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-0.1.1.tgz#0226017f72267200f6e832a7103760e96a6db5d0"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-0.1.1.tgz#0226017f72267200f6e832a7103760e96a6db5d0"
|
||||||
|
@ -4572,6 +4662,14 @@
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
"@radix-ui/react-use-layout-effect" "1.0.0"
|
"@radix-ui/react-use-layout-effect" "1.0.0"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-size@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz#1c5f5fea940a7d7ade77694bb98116fb49f870b2"
|
||||||
|
integrity sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.13.10"
|
||||||
|
"@radix-ui/react-use-layout-effect" "1.0.1"
|
||||||
|
|
||||||
"@radix-ui/react-visually-hidden@1.0.2":
|
"@radix-ui/react-visually-hidden@1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.2.tgz#29b117a59ef09a984bdad12cb98d81e8350be450"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.2.tgz#29b117a59ef09a984bdad12cb98d81e8350be450"
|
||||||
|
|
Loading…
Reference in New Issue