[website] Add Jobs page (#433)

* add jobs route

* implement jobs page

* imlement jobs detail page

* remove vertical padding from feature list

* fix field

* fix button pressing

* fix feature list

* fix tag

---------

Co-authored-by: Jakub Kotula <520927+jkbktl@users.noreply.github.com>
This commit is contained in:
Pavel 2023-06-29 17:48:48 +01:00 committed by GitHub
parent 6dd97428c7
commit cadab15871
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 492 additions and 66 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -7,7 +7,7 @@ import type { illustrations } from '@/config/illustrations'
type Item = { type Item = {
title: string title: string
description: string description: string
image: (typeof illustrations)[keyof typeof illustrations] icon: (typeof illustrations)[keyof typeof illustrations]
} }
type Props = { type Props = {
@ -18,15 +18,15 @@ type Props = {
export const FeatureList = (props: Props) => { export const FeatureList = (props: Props) => {
const { list, dark = false } = props const { list, dark = false } = props
return ( return (
<div className="container pb-24 pt-12 lg:m-auto lg:gap-10"> <div className="container lg:m-auto lg:gap-10">
<div className="grid grid-cols-1 gap-12 sm:grid-cols-2 lg:-ml-10 lg:grid-cols-3"> <div className="grid grid-cols-1 gap-12 sm:grid-cols-2 lg:-ml-10 lg:grid-cols-3">
{list.map(({ title, image, description }, i) => ( {list.map(({ title, icon, description }, i) => (
<div key={title} className="flex flex-col"> <div key={title} className="flex flex-col">
<Image {...image} alt={image.alt} className="mb-4 ml-10" /> <Image {...icon} alt={icon.alt} className="mb-4 ml-10" />
<div <div
className={cx( className={cx(
'flex flex-col border-dashed lg:border-l-[1px] lg:pl-10', 'flex flex-col border-dashed lg:pl-10',
(i === 0 || i === 3) && 'lg:border-l-0', i % 3 === 0 ? 'lg:border-l-0' : 'lg:border-l-[1px]',
dark ? 'border-l-neutral-70' : 'border-l-neutral-30' dark ? 'border-l-neutral-70' : 'border-l-neutral-30'
)} )}
> >

View File

@ -38,7 +38,7 @@ export const ROUTES = {
{ name: 'Blog', href: '/blog' }, { name: 'Blog', href: '/blog' },
{ name: 'Translations', href: '/' }, { name: 'Translations', href: '/' },
// { name: 'Community groups', href: '/' }, // { name: 'Community groups', href: '/' },
{ name: 'Jobs', href: '/' }, { name: 'Jobs', href: '/jobs' },
], ],
Developers: [ Developers: [
{ name: 'Repos', href: 'https://github.com/status-im' }, { name: 'Repos', href: 'https://github.com/status-im' },

View File

@ -35,37 +35,37 @@ const FEATURE_LIST = [
title: 'Decentralized', title: 'Decentralized',
description: description:
'Communities are literally powered by their members running the Status Desktop app.', 'Communities are literally powered by their members running the Status Desktop app.',
image: illustrations.doge, icon: illustrations.doge,
}, },
{ {
title: 'Permissionless', title: 'Permissionless',
description: description:
'Nobody can stop you creating a community, because nobody controls Status p2p network.', 'Nobody can stop you creating a community, because nobody controls Status p2p network.',
image: illustrations.mushroom, icon: illustrations.mushroom,
}, },
{ {
title: 'Self-sovereign', title: 'Self-sovereign',
description: description:
'Each community can set its own rules, whatever they are. And is responsible for its own actions. ', 'Each community can set its own rules, whatever they are. And is responsible for its own actions. ',
image: illustrations.hand, icon: illustrations.hand,
}, },
{ {
title: '100% Free to use', title: '100% Free to use',
description: description:
'No paid tier. No artificially imposed limits. No commission charged on community token sales.', 'No paid tier. No artificially imposed limits. No commission charged on community token sales.',
image: illustrations.duck, icon: illustrations.duck,
}, },
{ {
title: '100% Open source', title: '100% Open source',
description: description:
'Status itself is a community project. Anyone can build, contribute to and fork its source code.', 'Status itself is a community project. Anyone can build, contribute to and fork its source code.',
image: illustrations.flower, icon: illustrations.flower,
}, },
{ {
title: '100% Freedom', title: '100% Freedom',
description: description:
'Statuss mission is to protect free speech, uphold human rights and defend privacy.', 'Statuss mission is to protect free speech, uphold human rights and defend privacy.',
image: illustrations.megaphone, icon: illustrations.megaphone,
}, },
] ]

View File

@ -0,0 +1,154 @@
import { Button, Tag, Text } from '@status-im/components'
import { cx } from 'class-variance-authority'
import { Breadcrumbs } from '@/components/breadcrumbs'
import { AppLayout, Content } from '@/layouts/app-layout'
import type { BreadcrumbsProps } from '@/components/breadcrumbs'
import type { GetStaticPaths, GetStaticProps, Page } from 'next'
import type React from 'react'
type Params = { slug: string }
const SLUG = 'senior-react-native-ui-developer'
export const getStaticPaths: GetStaticPaths<Params> = async () => {
return {
paths: [
{
params: {
slug: SLUG,
},
},
],
fallback: false,
}
}
export const getStaticProps: GetStaticProps<Props, Params> = async () => {
// root
const breadcrumbs = [
{
label: 'Jobs',
// TODO: typesafe
href: '/jobs',
},
{
label: 'Senior React Native UI Developer',
href: `/jobs/${SLUG}`,
},
]
return {
props: {
breadcrumbs,
},
}
}
type Props = {
breadcrumbs: BreadcrumbsProps['items']
}
const JobsDetailPage: Page<Props> = props => {
const { breadcrumbs } = props
return (
<Content>
<Breadcrumbs items={breadcrumbs} />
<div className="mx-auto max-w-[742px] px-5">
<div className="flex flex-col items-start gap-4 pb-6 pt-12 lg:pt-20">
<Tag size={24} label="Mobile" />
<h1 className="text-40 lg:text-64">
Senior React Native UI Developer
</h1>
<Text size={19} color="$neutral-50">
Full time, Remote (Worldwide)
</Text>
</div>
{/* CONTENT */}
<div className="pb-12 pt-6 lg:pb-20">
<Text size={19}>
The role Were growing our mobile development team. Join us in
building a fully decentralized, censorship resistant, privacy first
group chat platform that leverages the Ethereum blockchain to enable
individuals and groups worldwide to communicate and transact with
one another freely without restriction. Status is looking for an UI
Engineer to join our mobile development team who will work closely
with Design to transform UI specifications into beautiful, smooth,
performant and near pixel perfect interactive interfaces. The ideal
person will be comfortable working on features end-to-end, has an
eye for design and visual detail, enjoys working with designers as
well as developers, and who can transform reused UI patterns such as
list items into reusable UI components.
<br />
<br />
The ideal candidate will love finessing UI implementations to the
highest levels of quality and will care deeply about things like
code cleanliness, reusability, maintainability, performance, and UI
layout accuracy - as well as doing whatever needed to create a
best-in-class user experience for Statuss users. Willingness to
both learn and share your knowledge with others,
product-orientation, and making sure all team members are aligned
when developing new features, will make you successful in the role.
Status is a fast-paced, flat organization, working on cutting edge
blockchain and decentralized messaging technologies in a dynamic
landscape. We look forward to meeting you!
</Text>
<Text size={19}>
The role Were growing our mobile development team. Join us in
building a fully decentralized, censorship resistant, privacy first
group chat platform that leverages the Ethereum blockchain to enable
individuals and groups worldwide to communicate and transact with
one another freely without restriction. Status is looking for an UI
Engineer to join our mobile development team who will work closely
with Design to transform UI specifications into beautiful, smooth,
performant and near pixel perfect interactive interfaces. The ideal
person will be comfortable working on features end-to-end, has an
eye for design and visual detail, enjoys working with designers as
well as developers, and who can transform reused UI patterns such as
list items into reusable UI components.
<br />
<br />
The ideal candidate will love finessing UI implementations to the
highest levels of quality and will care deeply about things like
code cleanliness, reusability, maintainability, performance, and UI
layout accuracy - as well as doing whatever needed to create a
best-in-class user experience for Statuss users. Willingness to
both learn and share your knowledge with others,
product-orientation, and making sure all team members are aligned
when developing new features, will make you successful in the role.
Status is a fast-paced, flat organization, working on cutting edge
blockchain and decentralized messaging technologies in a dynamic
landscape. We look forward to meeting you!
</Text>
</div>
{/* FOOTER */}
<div
className={cx(
'border-dashed-default -mx-5 flex flex-col items-start gap-4 border-t px-5 pb-24 pt-6',
'md:mx-0 md:flex-row md:items-center md:justify-between md:px-0 md:pb-40'
)}
>
<div className="flex flex-col">
<Text size={19} weight="semibold">
Apply for this job
</Text>
<Text size={15}>Submit your application here</Text>
</div>
<Button size={32}>Apply now</Button>
</div>
</div>
</Content>
)
}
JobsDetailPage.getLayout = function getLayout(page) {
return <AppLayout>{page}</AppLayout>
}
export default JobsDetailPage

View File

@ -0,0 +1,276 @@
import { useRef } from 'react'
// import codexImage from '@assets/jobs/codex.png'
import logosImage from '@assets/jobs/logos.png'
// import nimbusImage from '@assets/jobs/nimbus.png'
// import vacImage from '@assets/jobs/vac.png'
// import wakuImage from '@assets/jobs/waku.png'
import { Button, Tag, Text } from '@status-im/components'
import { ArrowDownIcon, ArrowRightIcon, ExternalIcon } from '@status-im/icons'
import Image from 'next/image'
import Link from 'next/link'
import { FeatureList } from '@/components/feature-list'
import { illustrations } from '@/config/illustrations'
import { AppLayout, Content } from '@/layouts/app-layout'
import type { Page } from 'next'
// TODO FIX PHOTOS
// TODO FIX FEATURE LIST
// TODO ADD CIRCLES
// TODO CONNECT TO GREENHOUSE API (https://developers.greenhouse.io/job-board.html#retrieve-job-board)
const OPEN_JOBS = 82
const JobsPage: Page = () => {
const openRolesRef = useRef<HTMLDivElement>(null)
const handleScrollToOpenings = () => {
openRolesRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' })
}
return (
<Content>
<div className="container flex flex-col items-start pb-6 pt-16 lg:pb-20 lg:pt-40">
<div className="mb-4">
<Tag size={32} label="Jobs" />
</div>
<h1 className="mb-6 text-48 lg:mb-8 lg:text-88">
Join the
<br />
decentralized
<br />
movement
</h1>
<div className="flex w-full max-w-[462px] flex-col justify-between gap-3 rounded-2xl border border-dashed border-neutral-80/20 p-3 md:flex-row md:gap-10 lg:items-center lg:p-2 lg:pl-3">
<div className="flex flex-col">
<Text size={13} weight="semibold">
Were hiring!
</Text>
<Text size={13}>{OPEN_JOBS} remote openings</Text>
</div>
<Button
variant="outline"
iconAfter={<ArrowDownIcon size={20} />}
onPress={handleScrollToOpenings}
>
View openings
</Button>
</div>
</div>
{/* PHOTOS */}
<div className="container grid grid-cols-2 gap-4 pb-12 pt-6 lg:pb-20 lg:pt-10">
<img
src="https://images.pexels.com/photos/16972528/pexels-photo-16972528/free-photo-of-sea-flight-bird-beach.jpeg?auto=compress&cs=tinysrgb&w=750&h=750&dpr=2"
className="aspect-square rounded-3xl object-cover"
/>
<div className="grid grid-rows-2 gap-4">
<div className="grid grid-cols-2 gap-4">
<img
src="https://images.pexels.com/photos/17162015/pexels-photo-17162015/free-photo-of-street-field-school-park.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2"
className="aspect-square rounded-3xl object-cover"
/>
<img
src="https://images.pexels.com/photos/17162015/pexels-photo-17162015/free-photo-of-street-field-school-park.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2"
className="aspect-square rounded-3xl object-cover"
/>
</div>
<img
src="https://images.pexels.com/photos/17162015/pexels-photo-17162015/free-photo-of-street-field-school-park.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2"
className="aspect-[2.060] rounded-3xl object-cover"
/>
</div>
</div>
<section className="border-b border-dashed border-neutral-80/20 pb-24 pt-12 lg:pb-40 lg:pt-20">
<div className="mx-auto max-w-[740px] px-5">
<Text size={19}>
Status strives to develop open source software that can be used as a
secure communication tool that upholds human rights. We are building
the tools and infrastructure for the advancement of a secure,
private, and open web3. Our core software, Status, is an open
source, Ethereum-based software that gives users the power to chat,
transact, and access a revolutionary world of DApps on the
decentralized web. With the high level goals of preserving the right
to privacy, protecting messages from third parties, and safely
sending, storing and receiving cryptocurrencies with you being the
only one who holds the keys to your funds, Status is providing the
tools and infrastructure to facilitate the creation of communities,
where anyone is welcome to create, join and contribute.
<br />
<br />
150+ passionate individuals (known as core-contributors) work
together all around the world to facilitate Status mission. We care
deeply about our mission, so we have created an environment which
allows core-contributors to complete their work with freedom and
flexibility. We regularly survey the core contributors to gather
insights on their satisfaction with contributing to Status & the
most common answers regarding why theyre satisfied are: our
mission, values, flexibility, friendly environment, non-corporate
culture and our entrepreneurial spirit.
</Text>
</div>
</section>
<div className="border-b border-dashed border-neutral-80/20 py-24 lg:py-40">
<div className="container mb-12 lg:mb-20">
<h2 className="text-40 lg:text-64">Perks and benefits</h2>
</div>
<FeatureList list={PERKS} />
</div>
<div className="container py-24 lg:py-40" ref={openRolesRef}>
<div className="mb-12 lg:mb-20">
<h2 className="text-40 lg:text-64">Open roles</h2>
</div>
<div className="grid gap-12 lg:gap-16">
{/* JOB GROUPS */}
{[1, 2, 3].map(i => (
<div
key={i}
className="border-b border-dashed border-neutral-80/20"
>
<div>
<h3 className="mb-3 text-27">Design</h3>
</div>
<div className="divide-y divide-dashed divide-neutral-80/20">
{[
'Product designer',
'Visual designer',
'Motion designer',
'Illustrator',
].map(position => (
// TODO: discuss hover state
<Link
href="/jobs/senior-react-native-ui-developer"
key={position}
className="flex items-center justify-between py-5"
>
<Text size={19} weight="semibold">
{position}
</Text>
<div className="flex items-center gap-6">
<Text size={19}>Full-time</Text>
<Button
variant="outline"
size={40}
icon={<ArrowRightIcon size={20} />}
/>
</div>
</Link>
))}
</div>
</div>
))}
</div>
</div>
{/* TODO FIX TEXTURE */}
<div className="rounded-[40px] bg-[#F5F6FD]">
<div className="container py-24 lg:py-40">
<div className="mb-20">
<h3 className="text-40">
Open roles
<br />
in our network
</h3>
</div>
<div className="grid gap-12">
{['Logos', 'Codex', 'Waku', 'Nimbus', 'Vac'].map(name => (
<div key={name} className="grid gap-4">
<div className="flex items-center gap-2">
<Image
src={logosImage}
width={24}
height={24}
alt={`${name} logo`}
/>
<Text size={19} weight="semibold">
{name}
</Text>
</div>
{[1, 2, 3, 4, 5, 6].map(i => (
<Link
key={i}
href="https://google.com"
className="group flex items-center"
>
<Text size={15} weight="medium">
Protocol Research Engineer
</Text>
<ExternalIcon
size={16}
className="transition-transform group-hover:translate-x-[2px] group-hover:translate-y-[-2px]"
/>
</Link>
))}
</div>
))}
</div>
</div>
</div>
</Content>
)
}
const PERKS = [
{
title: 'Fully remote',
description: 'Work from wherever you want, whenever you want. ',
icon: illustrations.doge,
},
{
title: 'Unlimited vacation',
description:
'Take all the time off you need. We need you in your best self.',
icon: illustrations.doge,
},
{
title: 'Paid team offsites',
description: 'We meet at least once a year somewhere across the world. ',
icon: illustrations.doge,
},
{
title: 'Hardware stipend',
description: 'Need a laptop to work? We got you covered.',
icon: illustrations.doge,
},
{
title: 'Co-working stipend',
description:
'We offer a $250 stipend for you to work from a co-working space.',
icon: illustrations.doge,
},
{
title: 'Get paid in crypto',
description: 'We offer to pay salaries in SNT, ETH, USDC or fiat.',
icon: illustrations.doge,
},
{
title: 'SNT Bonus',
description: 'We reward hard work and longevity with a bonus in SNT. ',
icon: illustrations.doge,
},
{
title: 'Referral fee',
description:
'We offer a $5000 SNT referral fee so bring your friends aboard.',
icon: illustrations.doge,
},
{
title: 'Headspace subscription',
description:
'Take care of your mind with a premium headspace account, for free.',
icon: illustrations.doge,
},
]
JobsPage.getLayout = function getLayout(page) {
return <AppLayout>{page}</AppLayout>
}
export default JobsPage

View File

@ -132,36 +132,36 @@ const FEATURE_LIST = [
title: 'Top tier security', title: 'Top tier security',
description: description:
'Our hardware security successfully passed Common Criteria EAL6+ certification ', 'Our hardware security successfully passed Common Criteria EAL6+ certification ',
image: illustrations.doge, icon: illustrations.doge,
}, },
{ {
title: 'Keys stored in the card', title: 'Keys stored in the card',
description: description:
'Its impossible for Status or any government to extract your private keys from keycard', 'Its impossible for Status or any government to extract your private keys from keycard',
image: illustrations.mushroom, icon: illustrations.mushroom,
}, },
{ {
title: 'Feature 3', title: 'Feature 3',
description: description:
'Here will say something more about security and how kc is revolutionary when it comes to security', 'Here will say something more about security and how kc is revolutionary when it comes to security',
image: illustrations.hand, icon: illustrations.hand,
}, },
{ {
title: 'Mobile friendly', title: 'Mobile friendly',
description: description:
'Keycard is using NFC which is natively embedded in all mobile phones', 'Keycard is using NFC which is natively embedded in all mobile phones',
image: illustrations.duck, icon: illustrations.duck,
}, },
{ {
title: 'No need to charge', title: 'No need to charge',
description: 'Keycard has no battery so its always ready to go.', description: 'Keycard has no battery so its always ready to go.',
image: illustrations.flower, icon: illustrations.flower,
}, },
{ {
title: 'Easy to carry around', title: 'Easy to carry around',
description: description:
'Its credit card form factor is small and convenient to fit in any wallet.', 'Its credit card form factor is small and convenient to fit in any wallet.',
image: illustrations.megaphone, icon: illustrations.megaphone,
}, },
] ]

View File

@ -6,6 +6,9 @@
.container { .container {
@apply mx-auto max-w-[1504px] px-5 lg:px-40; @apply mx-auto max-w-[1504px] px-5 lg:px-40;
} }
.border-dashed-default {
@apply border-dashed border-neutral-80/20;
}
} }
@keyframes gradient { @keyframes gradient {

View File

@ -1,14 +1,13 @@
import { cloneElement, forwardRef } from 'react' import { cloneElement, forwardRef } from 'react'
import { styled } from '@tamagui/core' import { styled } from '@tamagui/core'
import { Pressable } from 'react-native' import { View } from 'react-native'
import { Text } from '../text' import { Text } from '../text'
import type { TextProps } from '../text' import type { TextProps } from '../text'
import type { GetVariants, MapVariant, PressableProps } from '../types' import type { GetVariants, MapVariant, PressableProps } from '../types'
import type { Ref } from 'react' import type { Ref } from 'react'
import type { View } from 'react-native'
type Variants = GetVariants<typeof Base> type Variants = GetVariants<typeof Base>
@ -94,10 +93,9 @@ const _Button = forwardRef(Button)
export { _Button as Button } export { _Button as Button }
export type { Props as ButtonProps } export type { Props as ButtonProps }
const Base = styled(Pressable, { const Base = styled(View, {
tag: 'button',
name: 'Button', name: 'Button',
accessibilityRole: 'button', role: 'button',
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',

View File

@ -2,7 +2,7 @@ import { forwardRef } from 'react'
import { ArrowDownIcon, MentionIcon } from '@status-im/icons' import { ArrowDownIcon, MentionIcon } from '@status-im/icons'
import { styled } from '@tamagui/core' import { styled } from '@tamagui/core'
import { Pressable } from 'react-native' import { View } from 'react-native'
import { Shadow } from '../shadow' import { Shadow } from '../shadow'
import { Text } from '../text' import { Text } from '../text'
@ -10,7 +10,6 @@ import { Text } from '../text'
import type { GetVariants, PressableProps } from '../types' import type { GetVariants, PressableProps } from '../types'
import type { ColorTokens } from '@tamagui/core' import type { ColorTokens } from '@tamagui/core'
import type { Ref } from 'react' import type { Ref } from 'react'
import type { View } from 'react-native'
type Variants = GetVariants<typeof Button> type Variants = GetVariants<typeof Button>
@ -50,10 +49,9 @@ const _DynamicButton = forwardRef(DynamicButton)
export { _DynamicButton as DynamicButton } export { _DynamicButton as DynamicButton }
export type { Props as DynamicButtonProps } export type { Props as DynamicButtonProps }
const Button = styled(Pressable, { const Button = styled(View, {
name: 'DynamicButton', name: 'DynamicButton',
tag: 'button', role: 'button',
accessibilityRole: 'button',
cursor: 'pointer', cursor: 'pointer',
userSelect: 'none', userSelect: 'none',

View File

@ -1,7 +1,6 @@
import { useState } from 'react' import { useState } from 'react'
import type { PressableProps } from '../types' import type { PressableProps } from '../types'
import type { MouseEvent } from 'react-native'
import type { ColorTokens } from 'tamagui' import type { ColorTokens } from 'tamagui'
type Config = { type Config = {
@ -49,20 +48,20 @@ export const usePressableColors = (
return { return {
color: styles[key], color: styles[key],
pressableProps: { pressableProps: {
onHoverIn: event => { onHoverIn: (...args) => {
props.onHoverIn?.(event as unknown as MouseEvent) props.onHoverIn?.(...args)
setHovered(true) setHovered(true)
}, },
onHoverOut: event => { onHoverOut: (...args) => {
props.onHoverOut?.(event as unknown as MouseEvent) props.onHoverOut?.(...args)
setHovered(false) setHovered(false)
}, },
onPressIn: event => { onPressIn: (...args) => {
props.onPressIn?.(event) props.onPressIn?.(...args)
setPressed(true) setPressed(true)
}, },
onPressOut: event => { onPressOut: (...args) => {
props.onPressOut?.(event) props.onPressOut?.(...args)
setPressed(false) setPressed(false)
}, },
} as const, } as const,

View File

@ -1,13 +1,12 @@
import { cloneElement, forwardRef } from 'react' import { cloneElement, forwardRef } from 'react'
import { Pressable } from 'react-native' import { View } from 'react-native'
import { styled } from 'tamagui' import { styled } from 'tamagui'
import { usePressableColors } from '../hooks/use-pressable-colors' import { usePressableColors } from '../hooks/use-pressable-colors'
import type { GetVariants, PressableProps } from '../types' import type { GetVariants, PressableProps } from '../types'
import type { Ref } from 'react' import type { Ref } from 'react'
import type { View } from 'react-native'
type Variants = GetVariants<typeof Base> type Variants = GetVariants<typeof Base>
@ -63,10 +62,9 @@ const _IconButton = forwardRef(IconButton)
export { _IconButton as IconButton } export { _IconButton as IconButton }
export type { Props as IconButtonProps } export type { Props as IconButtonProps }
const Base = styled(Pressable, { const Base = styled(View, {
name: 'IconButton', name: 'IconButton',
tag: 'button', role: 'button',
accessibilityRole: 'button',
cursor: 'pointer', cursor: 'pointer',
userSelect: 'none', userSelect: 'none',

View File

@ -106,7 +106,6 @@ const _Input = (props: Props, ref: Ref<TextInput>) => {
{Boolean(onClear) && !!value && ( {Boolean(onClear) && !!value && (
<Stack <Stack
role="button" role="button"
accessibilityRole="button"
pr={4} pr={4}
onPress={onClear} onPress={onClear}
cursor="pointer" cursor="pointer"

View File

@ -10,14 +10,13 @@ import {
ThumbsUpIcon, ThumbsUpIcon,
} from '@status-im/icons' } from '@status-im/icons'
import { styled } from '@tamagui/core' import { styled } from '@tamagui/core'
import { Pressable } from 'react-native' import { View } from 'react-native'
import { Text } from '../text' import { Text } from '../text'
import type { ReactionType } from '../messages/types' import type { ReactionType } from '../messages/types'
import type { PressableProps } from '../types' import type { PressableProps } from '../types'
import type { Ref } from 'react' import type { Ref } from 'react'
import type { View } from 'react-native'
export const REACTIONS_ICONS = { export const REACTIONS_ICONS = {
love: LoveIcon, love: LoveIcon,
@ -63,10 +62,9 @@ const _ReactButton = forwardRef(ReactButton)
export { _ReactButton as ReactButton } export { _ReactButton as ReactButton }
export type { Props as ReactButtonProps } export type { Props as ReactButtonProps }
const Button = styled(Pressable, { const Button = styled(View, {
name: 'ReactButton', name: 'ReactButton',
tag: 'button', role: 'button',
accessibilityRole: 'button',
cursor: 'pointer', cursor: 'pointer',
userSelect: 'none', userSelect: 'none',

View File

@ -2,7 +2,7 @@ import { Children, cloneElement, forwardRef } from 'react'
import { Content, List, Root, Trigger } from '@radix-ui/react-tabs' import { Content, List, Root, Trigger } from '@radix-ui/react-tabs'
import { Stack } from '@tamagui/web' import { Stack } from '@tamagui/web'
import { Pressable } from 'react-native' import { View } from 'react-native'
import { styled } from 'tamagui' import { styled } from 'tamagui'
import { Counter } from '../counter' import { Counter } from '../counter'
@ -12,7 +12,6 @@ import { Text } from '../text'
import type { TextProps } from '../text' import type { TextProps } from '../text'
import type { GetVariants } from '../types' import type { GetVariants } from '../types'
import type { Ref } from 'react' import type { Ref } from 'react'
import type { View } from 'react-native'
type Variants = GetVariants<typeof TriggerBase> type Variants = GetVariants<typeof TriggerBase>
@ -117,8 +116,9 @@ Tabs.Content = Content
export { Tabs } export { Tabs }
export type { Props as TabsProps } export type { Props as TabsProps }
const TriggerBase = styled(Pressable, { const TriggerBase = styled(View, {
tag: 'button', name: 'Trigger',
role: 'button',
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',

View File

@ -1,6 +1,7 @@
import { createElement } from 'react' import { createElement } from 'react'
import { Stack, styled } from '@tamagui/core' import { styled } from '@tamagui/core'
import { View } from 'react-native'
import { Text } from '../text' import { Text } from '../text'
import { getCustomStyles } from './get-custom-styles' import { getCustomStyles } from './get-custom-styles'
@ -9,6 +10,7 @@ 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 { ColorTokens } from '@tamagui/core'
import type { ComponentType } from 'react' import type { ComponentType } from 'react'
import type { PressableProps } from 'react-native'
type Props = { type Props = {
size: 32 | 24 size: 32 | 24
@ -16,7 +18,7 @@ type Props = {
label?: string label?: string
selected?: boolean selected?: boolean
disabled?: boolean disabled?: boolean
onPress?: () => void onPress?: PressableProps['onPress']
color?: ColorTokens | `#${string}` color?: ColorTokens | `#${string}`
} }
@ -54,8 +56,11 @@ const Tag = (props: Props) => {
selected={selected} selected={selected}
disabled={disabled} disabled={disabled}
iconOnly={Boolean(icon && !label)} iconOnly={Boolean(icon && !label)}
onPress={() => onPress?.()}
{...getCustomStyles(props)} {...getCustomStyles(props)}
{...(onPress && {
role: 'button',
onPress,
})}
> >
{renderIcon()} {renderIcon()}
{label && ( {label && (
@ -70,11 +75,10 @@ const Tag = (props: Props) => {
export { Tag } export { Tag }
export type { Props as TagProps } export type { Props as TagProps }
const Base = styled(Stack, { const Base = styled(View, {
tag: 'tag',
name: 'Tag', name: 'Tag',
accessibilityRole: 'button',
userSelect: 'none',
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
@ -85,7 +89,6 @@ const Base = styled(Stack, {
backgroundColor: '$white-100', backgroundColor: '$white-100',
animation: 'fast', animation: 'fast',
cursor: 'pointer',
hoverStyle: { hoverStyle: {
borderColor: '$neutral-30', borderColor: '$neutral-30',

View File

@ -8,12 +8,12 @@ import type {
import type { PressableProps as NativePressableProps } from 'react-native' import type { PressableProps as NativePressableProps } from 'react-native'
type PressableProps = { type PressableProps = {
onHoverIn?: Exclude<NativePressableProps['onHoverIn'], null> onHoverIn?: VoidFunction
onHoverOut?: NativePressableProps['onHoverOut'] onHoverOut?: VoidFunction
onPress?: NativePressableProps['onPress'] onPress?: VoidFunction
onPressIn?: NativePressableProps['onPressIn'] onPressIn?: VoidFunction
onPressOut?: NativePressableProps['onPressOut'] onPressOut?: VoidFunction
onLongPress?: NativePressableProps['onLongPress'] onLongPress?: VoidFunction
delayHoverIn?: NativePressableProps['delayHoverIn'] delayHoverIn?: NativePressableProps['delayHoverIn']
delayHoverOut?: NativePressableProps['delayHoverOut'] delayHoverOut?: NativePressableProps['delayHoverOut']
delayLongPress?: NativePressableProps['delayLongPress'] delayLongPress?: NativePressableProps['delayLongPress']