[website] Custom tags (#409)
* feat: change tags component and add util to get color with opacity * feat: change some tags for the example purpose * fix: some issues and code organization * feat: removes complexity from the code and uses css color-mix function
This commit is contained in:
parent
eb5cbcdda3
commit
36538591ce
|
@ -133,7 +133,7 @@ const ChartComponent = (props: Props): JSX.Element => {
|
||||||
return {
|
return {
|
||||||
dy: '.33em',
|
dy: '.33em',
|
||||||
fill: '#A1ABBD',
|
fill: '#A1ABBD',
|
||||||
fontFamily: 'Inter, sans-serif',
|
fontFamily: 'Menlo',
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
textAnchor,
|
textAnchor,
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,7 @@ const ChartComponent = (props: Props): JSX.Element => {
|
||||||
{...tickProps}
|
{...tickProps}
|
||||||
fill="#A1ABBD"
|
fill="#A1ABBD"
|
||||||
fontSize={11}
|
fontSize={11}
|
||||||
|
fontFamily="Menlo"
|
||||||
textAnchor="middle"
|
textAnchor="middle"
|
||||||
dx="-1em"
|
dx="-1em"
|
||||||
>
|
>
|
||||||
|
|
|
@ -56,41 +56,6 @@ const DATA = [
|
||||||
open_issues: 10,
|
open_issues: 10,
|
||||||
closed_issues: 130,
|
closed_issues: 130,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
date: '2022-02-04',
|
|
||||||
open_issues: 10,
|
|
||||||
closed_issues: 140,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '2022-02-05',
|
|
||||||
open_issues: 10,
|
|
||||||
closed_issues: 150,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '2022-02-06',
|
|
||||||
open_issues: 10,
|
|
||||||
closed_issues: 160,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '2022-02-07',
|
|
||||||
open_issues: 10,
|
|
||||||
closed_issues: 180,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '2022-02-08',
|
|
||||||
open_issues: 10,
|
|
||||||
closed_issues: 190,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '2022-02-09',
|
|
||||||
open_issues: 10,
|
|
||||||
closed_issues: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
date: '2022-02-10',
|
|
||||||
open_issues: 0,
|
|
||||||
closed_issues: 220,
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -126,20 +91,20 @@ export const EpicOverview = (props: Props) => {
|
||||||
{description}
|
{description}
|
||||||
</Text>
|
</Text>
|
||||||
<div className="flex py-3">
|
<div className="flex py-3">
|
||||||
<Tag size={24} label="E:CommunitiesProtocol" />
|
<Tag size={24} label="E:CommunitiesProtocol" color="$blue-50" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Chart data={DATA} height={300} isLoading={isLoading} />
|
<Chart data={DATA} height={300} isLoading={isLoading} />
|
||||||
|
|
||||||
<div className="flex justify-between pt-3">
|
<div className="flex justify-between pt-3">
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
<Tag size={24} label="Communities" />
|
<Tag size={24} label="Communities" color="#FF7D46" icon="🧙♂️" />
|
||||||
<Tag size={24} label="Wallet" />
|
<Tag size={24} label="Wallet" color="#7140FD" icon="🎎" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
<Tag size={24} label="M:0.11.0" />
|
<Tag size={24} label="M:0.11.0" color="$danger-50" />
|
||||||
<Tag size={24} label="M:0.12.0" />
|
<Tag size={24} label="M:0.12.0" color="$success-50" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -56,10 +56,10 @@ export const TableIssues = () => {
|
||||||
|
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
<Tag size={24} label="E:Syncing" />
|
<Tag size={24} label="E:Syncing" color="$orange-50" />
|
||||||
<Tag size={24} label="E:Wallet" />
|
<Tag size={24} label="E:Wallet" color="$green-50" />
|
||||||
<Tag size={24} label="Feature" />
|
<Tag size={24} label="Feature" color="$pink-50" />
|
||||||
<Tag size={24} label="Web" />
|
<Tag size={24} label="Web" color="$purple-50" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Tag size={24} label="9435" />
|
<Tag size={24} label="9435" />
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { getColorWithOpacity } from '../../utils/get-color-with-opacity'
|
||||||
|
import { tokens } from '../tokens'
|
||||||
|
|
||||||
|
import type { TagProps } from './tag'
|
||||||
|
import type { ColorTokens, StackStyleProps } from '@tamagui/core'
|
||||||
|
|
||||||
|
// TypeGuard for ColorTokens
|
||||||
|
function isColorTokens(
|
||||||
|
value: `#${string}` | ColorTokens
|
||||||
|
): value is ColorTokens {
|
||||||
|
return typeof value === 'string' && value.startsWith('$')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the styles for the custom tag
|
||||||
|
* @param props - the props of the tag
|
||||||
|
* @returns the styles for the custom tag or null if no color is provided
|
||||||
|
**/
|
||||||
|
const getCustomStyles = (props: TagProps): StackStyleProps | null => {
|
||||||
|
const { color: colorFromProps, icon } = props
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icon) {
|
||||||
|
return {
|
||||||
|
borderColor: getColorWithOpacity(color!, 0.2),
|
||||||
|
backgroundColor: getColorWithOpacity(color!, 0.1),
|
||||||
|
pressStyle: {
|
||||||
|
backgroundColor: getColorWithOpacity(color, 0.2),
|
||||||
|
borderColor: getColorWithOpacity(color, 0.3),
|
||||||
|
},
|
||||||
|
hoverStyle: {
|
||||||
|
backgroundColor: getColorWithOpacity(color, 0.2),
|
||||||
|
borderColor: getColorWithOpacity(color, 0.3),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
borderColor: getColorWithOpacity(color, 0.2),
|
||||||
|
pressStyle: {
|
||||||
|
borderColor: getColorWithOpacity(color, 0.3),
|
||||||
|
backgroundColor: getColorWithOpacity(color, 0.1),
|
||||||
|
},
|
||||||
|
hoverStyle: {
|
||||||
|
borderColor: getColorWithOpacity(color, 0.3),
|
||||||
|
backgroundColor: getColorWithOpacity(color, 0.1),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getCustomStyles }
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { NftIcon } from '@status-im/icons'
|
||||||
import { Stack } from '@tamagui/core'
|
import { Stack } from '@tamagui/core'
|
||||||
|
|
||||||
import { Tag } from './tag'
|
import { Tag } from './tag'
|
||||||
|
@ -26,6 +27,7 @@ export const Default: Story = {
|
||||||
<Tag icon="🐷" label="Tag" size={32} selected />
|
<Tag icon="🐷" label="Tag" size={32} selected />
|
||||||
<Tag icon="🐷" label="Tag" size={32} disabled />
|
<Tag icon="🐷" label="Tag" size={32} disabled />
|
||||||
<Tag icon="🐷" size={32} />
|
<Tag icon="🐷" size={32} />
|
||||||
|
<Tag icon={NftIcon} size={32} label="bajoras" />
|
||||||
|
|
||||||
<Tag icon="🐷" label="Tag" size={24} />
|
<Tag icon="🐷" label="Tag" size={24} />
|
||||||
<Tag icon="🐷" size={24} />
|
<Tag icon="🐷" size={24} />
|
||||||
|
@ -37,6 +39,19 @@ export const Default: Story = {
|
||||||
<Tag label="Tag" size={32} disabled />
|
<Tag label="Tag" size={32} disabled />
|
||||||
|
|
||||||
<Tag label="Tag" size={24} />
|
<Tag label="Tag" size={24} />
|
||||||
|
<Tag label="New tag" size={24} disabled selected />
|
||||||
|
<Tag label="New tag" size={24} color="#FF7D46" />
|
||||||
|
|
||||||
|
<Tag label="New tag #7140FD" size={24} color="#BA34F5" />
|
||||||
|
<Tag label="New tag #7140FD" size={24} color="#7140FD" icon="🧙♂️" />
|
||||||
|
|
||||||
|
<Tag
|
||||||
|
label="custom color purple"
|
||||||
|
size={24}
|
||||||
|
icon="🐷"
|
||||||
|
color="$purple-50"
|
||||||
|
/>
|
||||||
|
<Tag label="New tag with icon" size={24} color="#FF7D46" icon="🥷🏾" />
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,9 +3,11 @@ import { createElement } from 'react'
|
||||||
import { Stack, styled } from '@tamagui/core'
|
import { Stack, styled } from '@tamagui/core'
|
||||||
|
|
||||||
import { Text } from '../text'
|
import { Text } from '../text'
|
||||||
|
import { getCustomStyles } from './get-custom-styles'
|
||||||
|
|
||||||
import type { TextProps } from '../text'
|
import type { TextProps } from '../text'
|
||||||
import type { IconProps } from '@status-im/icons'
|
import type { IconProps } from '@status-im/icons'
|
||||||
|
import type { ColorTokens } from '@tamagui/core'
|
||||||
import type { ComponentType } from 'react'
|
import type { ComponentType } from 'react'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -14,6 +16,8 @@ type Props = {
|
||||||
label?: string
|
label?: string
|
||||||
selected?: boolean
|
selected?: boolean
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
|
onPress?: () => void
|
||||||
|
color?: ColorTokens | `#${string}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const textSizes: Record<NonNullable<Props['size']>, TextProps['size']> = {
|
const textSizes: Record<NonNullable<Props['size']>, TextProps['size']> = {
|
||||||
|
@ -27,7 +31,7 @@ const iconSizes: Record<NonNullable<Props['size']>, IconProps['size']> = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tag = (props: Props) => {
|
const Tag = (props: Props) => {
|
||||||
const { size, icon, label, selected, disabled } = props
|
const { size, icon, label, selected, disabled, onPress, color } = props
|
||||||
|
|
||||||
const renderIcon = () => {
|
const renderIcon = () => {
|
||||||
if (!icon) {
|
if (!icon) {
|
||||||
|
@ -47,10 +51,12 @@ const Tag = (props: Props) => {
|
||||||
selected={selected}
|
selected={selected}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
iconOnly={Boolean(icon && !label)}
|
iconOnly={Boolean(icon && !label)}
|
||||||
|
onPress={() => onPress?.()}
|
||||||
|
{...getCustomStyles(props)}
|
||||||
>
|
>
|
||||||
{renderIcon()}
|
{renderIcon()}
|
||||||
{label && (
|
{label && (
|
||||||
<Text size={textSizes[size]} weight="medium">
|
<Text size={textSizes[size]} weight="medium" {...(color && { color })}>
|
||||||
{label}
|
{label}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
@ -62,6 +68,10 @@ export { Tag }
|
||||||
export type { Props as TagProps }
|
export type { Props as TagProps }
|
||||||
|
|
||||||
const Base = styled(Stack, {
|
const Base = styled(Stack, {
|
||||||
|
tag: 'tag',
|
||||||
|
name: 'Tag',
|
||||||
|
accessibilityRole: 'button',
|
||||||
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
@ -71,6 +81,18 @@ const Base = styled(Stack, {
|
||||||
borderRadius: '$full',
|
borderRadius: '$full',
|
||||||
backgroundColor: '$white-100',
|
backgroundColor: '$white-100',
|
||||||
|
|
||||||
|
animation: 'fast',
|
||||||
|
cursor: 'pointer',
|
||||||
|
|
||||||
|
hoverStyle: {
|
||||||
|
borderColor: '$neutral-30',
|
||||||
|
backgroundColor: '$neutral-5',
|
||||||
|
},
|
||||||
|
pressStyle: {
|
||||||
|
borderColor: '$neutral-30',
|
||||||
|
backgroundColor: '$neutral-5',
|
||||||
|
},
|
||||||
|
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
32: {
|
32: {
|
||||||
|
@ -86,11 +108,19 @@ const Base = styled(Stack, {
|
||||||
gap: 5,
|
gap: 5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
selected: {
|
selected: {
|
||||||
true: {
|
true: {
|
||||||
backgroundColor: '$primary-50-opa-10',
|
backgroundColor: '$primary-50-opa-10',
|
||||||
borderColor: '$primary-50',
|
borderColor: '$primary-50',
|
||||||
|
|
||||||
|
hoverStyle: {
|
||||||
|
backgroundColor: '$primary-50-opa-20',
|
||||||
|
borderColor: '$primary-60',
|
||||||
|
},
|
||||||
|
pressStyle: {
|
||||||
|
backgroundColor: '$primary-50-opa-20',
|
||||||
|
borderColor: '$primary-60',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ type Weight = NonNullable<Variants['weight']>
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
color?: ColorTokens
|
color?: ColorTokens | string
|
||||||
truncate?: boolean
|
truncate?: boolean
|
||||||
wrap?: false
|
wrap?: false
|
||||||
} & (
|
} & (
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/**
|
||||||
|
* Gets the color with opacity based on the original color and opacity value
|
||||||
|
* @param color - the original color
|
||||||
|
* @param opacity - the opacity value
|
||||||
|
* @returns the color with opacity
|
||||||
|
**/
|
||||||
|
|
||||||
|
function getColorWithOpacity(color: string, opacity: number): string {
|
||||||
|
// Ensure the opacity value is within the valid range of 0 to 1
|
||||||
|
const clampedOpacity = Math.max(0, Math.min(1, opacity)) * 100
|
||||||
|
|
||||||
|
// Construct the color string with opacity using CSS color-mix function
|
||||||
|
const newColor = `color-mix(in srgb, ${color} ${clampedOpacity}%, transparent);`
|
||||||
|
|
||||||
|
return newColor
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getColorWithOpacity }
|
Loading…
Reference in New Issue