Add mobile navigation & Composer (#333)

* feat: add composer component

* feat: complete composer component and few minor fixes

* feat: add several improvements and new features

* fix: change icon button in composer
This commit is contained in:
marcelines 2023-01-20 14:06:26 +00:00 committed by GitHub
parent 067389a3f5
commit 33eef5c2aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 884 additions and 392 deletions

View File

@ -2,27 +2,26 @@
/* eslint-disable import/namespace */ /* eslint-disable import/namespace */
import 'expo-dev-client' import 'expo-dev-client'
import { useState } from 'react' import { useMemo, useState } from 'react'
import { import { createNativeStackNavigator } from '@react-navigation/native-stack'
Code, import { Heading } from '@status-im/components'
Heading, import { Avatar } from '@status-im/components/src/avatar'
Label, import { Stack as View, TamaguiProvider } from '@tamagui/core'
Messages,
Paragraph,
Shape,
Sidebar,
} from '@status-im/components'
import { Stack, TamaguiProvider } from '@tamagui/core'
import { useFonts } from 'expo-font' import { useFonts } from 'expo-font'
import { SafeAreaView, ScrollView, TouchableOpacity } from 'react-native' import { SafeAreaProvider } from 'react-native-safe-area-context'
import { AnimatePresence } from 'tamagui'
import { NavigationProvider } from './navigation/provider'
import { ChannelScreen } from './screens/channel'
import { HomeScreen } from './screens/home'
import tamaguiConfig from './tamagui.config' import tamaguiConfig from './tamagui.config'
type ThemeVars = 'light' | 'dark' const Stack = createNativeStackNavigator()
export default function App() { export default function App() {
const [theme, setTheme] = useState<ThemeVars>('light') const [position, setPosition] = useState(0)
const [loaded] = useFonts({ const [loaded] = useFonts({
Inter: require('@tamagui/font-inter/otf/Inter-Medium.otf'), Inter: require('@tamagui/font-inter/otf/Inter-Medium.otf'),
InterBold: require('@tamagui/font-inter/otf/Inter-Bold.otf'), InterBold: require('@tamagui/font-inter/otf/Inter-Bold.otf'),
@ -30,56 +29,95 @@ export default function App() {
UbuntuMono: require('./assets/fonts/UbuntuMono.ttf'), UbuntuMono: require('./assets/fonts/UbuntuMono.ttf'),
}) })
const onScroll = event => {
if (event.nativeEvent.contentOffset.y > 90) {
setPosition(event.nativeEvent.contentOffset.y)
} else {
setPosition(0)
}
}
const showMinimizedHeader = useMemo(() => {
return position > 90
}, [position])
if (!loaded) { if (!loaded) {
return null return null
} }
return ( return (
<TamaguiProvider config={tamaguiConfig} defaultTheme={theme}> <TamaguiProvider config={tamaguiConfig} defaultTheme="light">
<SafeAreaView> <NavigationProvider>
<ScrollView> <SafeAreaProvider>
<Sidebar <Stack.Navigator>
name="Rarible" <Stack.Screen
description="Multichain community-centric NFT marketplace. Create, buy and sell your NFTs." name="Home"
membersCount={123} options={{
/> headerBlurEffect: 'systemUltraThinMaterialLight',
<Stack headerTransparent: true,
flexDirection="column" headerShadowVisible: true,
justifyContent="center" header: () => (
alignItems="center" <View
paddingTop={20} height={100}
paddingHorizontal={12} animation="fast"
width="100%" backgroundColor={
backgroundColor="$background" showMinimizedHeader ? '$background' : 'transparent'
> }
<Heading weight="semibold" marginBottom={12}> padding={16}
Communities paddingTop={48}
</Heading> flexDirection="row"
<Heading heading="h2" marginBottom={12}> justifyContent="space-between"
This is an Heading 2 alignItems="center"
</Heading> >
<Paragraph weight="semibold" marginBottom={12} uppercase> <AnimatePresence>
Paragraph uppercased and bolded {showMinimizedHeader && (
</Paragraph> <View
<Paragraph marginBottom={12} uppercase> key="header"
This is a paragraph animation={[
</Paragraph> 'fast',
<Label marginBottom={12}>This is a label</Label> {
<Code marginBottom={12}>This is a code line</Code> opacity: {
<Paragraph fontWeight="400">0x213abc190 ... 121ah4a9e</Paragraph> overshootClamping: true,
<Shape marginVertical={20} /> },
},
<Paragraph>Theme selected - {theme}</Paragraph> ]}
<TouchableOpacity enterStyle={{ opacity: 0 }}
onPress={() => setTheme(theme === 'dark' ? 'light' : 'dark')} exitStyle={{ opacity: 0 }}
opacity={1}
flexDirection="row"
alignItems="center"
justifyContent="space-between"
width="100%"
>
<Heading color="$textPrimary">Rarible</Heading>
<Avatar
withOutline
src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fi.seadn.io%2Fgae%2FFG0QJ00fN3c_FWuPeUr9-T__iQl63j9hn5d6svW8UqOmia5zp3lKHPkJuHcvhZ0f_Pd6P2COo9tt9zVUvdPxG_9BBw%3Fw%3D500%26auto%3Dformat&f=1&nofb=1&ipt=c177cd71d8d0114080cfc6efd3f9e098ddaeb1b347919bd3089bf0aacb003b3e&ipo=images"
size={48}
/>
</View>
)}
</AnimatePresence>
</View>
),
}}
> >
<Paragraph>Toogle theme</Paragraph> {props => (
</TouchableOpacity> <HomeScreen
{...props}
<Messages /> onScroll={onScroll}
</Stack> isMinimized={showMinimizedHeader}
</ScrollView> />
</SafeAreaView> )}
</Stack.Screen>
<Stack.Screen
name="Channel"
component={ChannelScreen}
options={{ title: 'Messages' }}
/>
</Stack.Navigator>
</SafeAreaProvider>
</NavigationProvider>
</TamaguiProvider> </TamaguiProvider>
) )
} }

View File

@ -0,0 +1,9 @@
import { NavigationContainer } from '@react-navigation/native'
export function NavigationProvider({
children,
}: {
children: React.ReactNode
}) {
return <NavigationContainer>{children}</NavigationContainer>
}

View File

@ -10,6 +10,8 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.9", "@babel/runtime": "^7.18.9",
"@react-navigation/native": "^6.1.2",
"@react-navigation/native-stack": "^6.9.8",
"@status-im/components": "*", "@status-im/components": "*",
"expo": "^47.0.12", "expo": "^47.0.12",
"expo-constants": "^14.0.2", "expo-constants": "^14.0.2",
@ -21,6 +23,8 @@
"react": "18.1.0", "react": "18.1.0",
"react-dom": "^18.1.0", "react-dom": "^18.1.0",
"react-native": "0.70.5", "react-native": "0.70.5",
"react-native-safe-area-context": "4.4.1",
"react-native-screens": "~3.18.0",
"react-native-web": "~0.18.7" "react-native-web": "~0.18.7"
}, },
"devDependencies": { "devDependencies": {

View File

@ -0,0 +1,34 @@
// eslint-disable-next-line eslint-comments/disable-enable-pair
/* eslint-disable import/namespace */
import { Composer, Messages } from '@status-im/components'
import { Stack, useTheme } from '@tamagui/core'
import {
Keyboard,
KeyboardAvoidingView,
Platform,
TouchableWithoutFeedback,
} from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { ScrollView } from 'tamagui'
export const ChannelScreen = () => {
const insets = useSafeAreaInsets()
const theme = useTheme()
return (
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={Platform.select({ ios: 60 })}
style={{ height: '100%', flex: 1, backgroundColor: theme.background.val }}
>
<ScrollView paddingHorizontal={12} width="100%">
<Messages py={20} />
</ScrollView>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<Stack pb={insets.bottom}>
<Composer />
</Stack>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
)
}

View File

@ -0,0 +1,34 @@
// eslint-disable-next-line eslint-comments/disable-enable-pair
/* eslint-disable import/namespace */
import { useState } from 'react'
import { Sidebar } from '@status-im/components'
import { Stack } from '@tamagui/core'
import { StatusBar } from 'expo-status-bar'
import { ScrollView } from 'tamagui'
export const HomeScreen = ({ navigation, onScroll, isMinimized }) => {
const [selectedChannel, setSelectedChannel] = useState<string>('welcome')
const onChannelPress = (id: string) => {
setSelectedChannel(id)
navigation.navigate('Channel')
}
return (
<Stack flex={1} backgroundColor="$background">
<StatusBar style={isMinimized ? 'dark' : 'light'} animated />
<ScrollView onScroll={onScroll} scrollEventThrottle={16} flex={1}>
<Stack pb={40}>
<Sidebar
name="Rarible"
description="Multichain community-centric NFT marketplace. Create, buy and sell your NFTs."
membersCount={123}
onChannelPress={onChannelPress}
selectedChannel={selectedChannel}
/>
</Stack>
</ScrollView>
</Stack>
)
}

View File

@ -3,6 +3,7 @@ import { useState } from 'react'
import { import {
Button, Button,
Code, Code,
Composer,
Heading, Heading,
Label, Label,
Messages, Messages,
@ -10,17 +11,41 @@ import {
Shape, Shape,
Sidebar, Sidebar,
} from '@status-im/components' } from '@status-im/components'
import { Stack, TamaguiProvider } from '@tamagui/core' import { Stack, styled, TamaguiProvider } from '@tamagui/core'
import { AnimatePresence } from 'tamagui'
import tamaguiConfig from '../tamagui.config' import tamaguiConfig from '../tamagui.config'
import { Topbar } from './components/topbar' import { Topbar } from './components/topbar'
type ThemeVars = 'light' | 'dark' type ThemeVars = 'light' | 'dark'
const AnimatableDrawer = styled(Stack, {
variants: {
fromRight: {
true: {
x: 500,
width: 0,
},
},
fromLeft: {
true: {
x: 500,
width: 250,
},
},
},
})
function App() { function App() {
const [theme, setTheme] = useState<ThemeVars>('light') const [theme, setTheme] = useState<ThemeVars>('light')
const [showMembers, setShowMembers] = useState(false) const [showMembers, setShowMembers] = useState(false)
const [selectedChannel, setSelectedChannel] = useState<string>('welcome')
const onChannelPress = (id: string) => {
setSelectedChannel(id)
}
return ( return (
<TamaguiProvider config={tamaguiConfig} defaultTheme={theme}> <TamaguiProvider config={tamaguiConfig} defaultTheme={theme}>
<div id="app"> <div id="app">
@ -29,9 +54,10 @@ function App() {
name="Rarible" name="Rarible"
description="Multichain community-centric NFT marketplace. Create, buy and sell your NFTs." description="Multichain community-centric NFT marketplace. Create, buy and sell your NFTs."
membersCount={123} membersCount={123}
onChannelPress={onChannelPress}
selectedChannel={selectedChannel}
/> />
</div> </div>
<main id="main"> <main id="main">
<Topbar <Topbar
membersVisisble={showMembers} membersVisisble={showMembers}
@ -71,16 +97,30 @@ function App() {
</Stack> </Stack>
</Stack> </Stack>
</div> </div>
<Stack <Composer />
backgroundColor="$background"
justifyContent="center"
alignItems="center"
>
<Paragraph weight="semibold">Composer</Paragraph>
</Stack>
</main> </main>
{showMembers && <div id="members">members</div>} <AnimatePresence>
{showMembers && (
<AnimatableDrawer
id="members"
key="members"
animation={[
'fast',
{
opacity: {
overshootClamping: true,
},
},
]}
enterStyle={{ opacity: 0 }}
exitStyle={{ opacity: 0 }}
opacity={1}
>
members
</AnimatableDrawer>
)}
</AnimatePresence>
</div> </div>
</TamaguiProvider> </TamaguiProvider>
) )

View File

@ -1,5 +1,8 @@
import '../styles/reset.css' import '../styles/reset.css'
import '../styles/app.css' import '../styles/app.css'
import '@tamagui/core/reset.css'
import '@tamagui/font-inter/css/400.css'
import '@tamagui/font-inter/css/700.css'
import React from 'react' import React from 'react'

View File

@ -15,13 +15,9 @@ body,
display: grid; display: grid;
grid-template-rows: 56px 1fr 100px; grid-template-rows: 56px 1fr 100px;
height: 100vh; height: 100vh;
} overflow: hidden;
#main,
#sidebar,
#members,
#main > div {
border: 1px solid rgba(0, 0, 0, 0.1); border: 1px solid rgba(0, 0, 0, 0.1);
border-width: 0 1px;
} }
#sidebar { #sidebar {

View File

@ -1,9 +1,9 @@
import React from 'react' import React from 'react'
import { ChevronIcon } from '@status-im/icons'
import { Stack } from '@tamagui/core' import { Stack } from '@tamagui/core'
import { AnimatePresence } from 'tamagui' import { AnimatePresence } from 'tamagui'
import { Chevron } from '../icon'
import { Label, Paragraph } from '../typography' import { Label, Paragraph } from '../typography'
import type { GetProps } from '@tamagui/core' import type { GetProps } from '@tamagui/core'
@ -48,9 +48,17 @@ const Accordion = ({
<Stack flexDirection="row" alignItems="center"> <Stack flexDirection="row" alignItems="center">
<Stack <Stack
animation="fast" animation="fast"
transform={[{ rotateZ: isExpanded ? '90deg' : '0deg' }]} justifyContent="center"
transform={[
{
rotateZ: isExpanded ? '90deg' : '0deg',
},
{
translateY: isExpanded ? -4 : 0,
},
]}
> >
<Chevron color="$neutral-50" size={16} /> <ChevronIcon color="$neutral-50" size={16} />
</Stack> </Stack>
<Paragraph <Paragraph
marginLeft={4} marginLeft={4}

View File

@ -1,6 +1,6 @@
import { MutedIcon } from '@status-im/icons'
import { Stack } from '@tamagui/core' import { Stack } from '@tamagui/core'
import { Muted } from '../icon'
import { Label, Paragraph } from '../typography' import { Label, Paragraph } from '../typography'
import type { GetProps } from '@tamagui/core' import type { GetProps } from '@tamagui/core'
@ -42,7 +42,10 @@ const AccordionItem = ({
}, },
}, },
]} ]}
backgroundColor={isSelected ? '$turquoise-50-opa-10' : 'transparent'} backgroundColor={isSelected ? '$primary-50-opa-10' : 'transparent'}
hoverStyle={{
backgroundColor: '$primary-50-opa-5',
}}
borderRadius="$4" borderRadius="$4"
padding={8} padding={8}
width="100%" width="100%"
@ -105,7 +108,9 @@ const AccordionItem = ({
/> />
</Stack> </Stack>
)} )}
{channelStatus === 'muted' && <Muted size={20} color="$neutral-40" />} {channelStatus === 'muted' && (
<MutedIcon size={20} color="$neutral-40" />
)}
</Stack> </Stack>
)} )}
</Stack> </Stack>

View File

@ -24,6 +24,11 @@ const Base = styled(Stack, {
variants: { variants: {
size: { size: {
80: {
width: 80,
height: 80,
borderRadius: 80 / 2,
},
56: { 56: {
width: 56, width: 56,
height: 56, height: 56,
@ -80,10 +85,15 @@ const Indicator = styled(Stack, {
variants: { variants: {
size: { size: {
80: {
width: 10,
height: 10,
borderRadius: '50%',
},
56: { 56: {
width: 10, width: 10,
height: 10, height: 10,
borderRadius: 10 / 2, borderRadius: '50%',
}, },
// FIXME: use catch all variant // FIXME: use catch all variant
52: { 52: {

View File

@ -24,6 +24,7 @@ const ChatMessage = (props: Props) => {
space={10} space={10}
position="relative" position="relative"
alignItems="flex-start" alignItems="flex-start"
justifyContent="center"
paddingHorizontal={8} paddingHorizontal={8}
paddingVertical={12} paddingVertical={12}
borderRadius={16} borderRadius={16}
@ -50,7 +51,7 @@ const ChatMessage = (props: Props) => {
<Paragraph weight="semibold" color="$neutral-100"> <Paragraph weight="semibold" color="$neutral-100">
Alisher Yakupov Alisher Yakupov
</Paragraph> </Paragraph>
<Paragraph fontFamily="$mono" color="$neutral-50" fontSize={11}> <Paragraph color="$neutral-50" fontSize={11}>
zQ3...9d4Gs0 zQ3...9d4Gs0
</Paragraph> </Paragraph>
<Paragraph color="$neutral-50" variant={11}> <Paragraph color="$neutral-50" variant={11}>

View File

@ -3,7 +3,7 @@ import { Stack } from 'tamagui'
import { Paragraph } from '../../typography' import { Paragraph } from '../../typography'
interface Props { interface Props {
onClick: VoidFunction onClick?: VoidFunction
} }
export const Actions = (_props: Props) => { export const Actions = (_props: Props) => {

View File

@ -1,10 +1,16 @@
import { Stack } from '@tamagui/core'
import { ChatMessage } from './chat-message' import { ChatMessage } from './chat-message'
import type { GetProps } from '@tamagui/core'
export * from './chat-message' export * from './chat-message'
export const Messages = () => { type BaseProps = GetProps<typeof Stack>
export const Messages = (props: BaseProps) => {
return ( return (
<> <Stack {...props}>
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" /> <ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" /> <ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" /> <ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
@ -21,6 +27,6 @@ export const Messages = () => {
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" /> <ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" /> <ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
<ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" /> <ChatMessage text="fsdjkf kasldjf ksdlfjksdlfj asdklfj sdkljf" />
</> </Stack>
) )
} }

View File

@ -0,0 +1,52 @@
import {
AudioIcon,
FormatIcon,
ImageIcon,
ReactionIcon,
} from '@status-im/icons'
import { Stack, XStack, YStack } from 'tamagui'
import { IconButton } from '../icon-button'
import { Input } from '../input'
import type { GetProps } from '@tamagui/core'
type BaseProps = GetProps<typeof YStack>
const Composer = (props: BaseProps) => {
return (
<YStack
backgroundColor="$background"
shadowColor="rgba(9, 16, 28, 0.08)"
shadowOffset={{ width: 0, height: -4 }}
shadowRadius={20}
borderTopLeftRadius={20}
borderTopRightRadius={20}
elevation={0}
px={16}
pt={8}
pb={12}
width="100%"
{...props}
>
<YStack>
<Input
elevation={10}
placeholder="Type something..."
borderWidth={0}
px={0}
/>
</YStack>
<XStack alignItems="center" justifyContent="space-between" pt={8}>
<Stack space={12} flexDirection="row">
<IconButton noBackground icon={<ImageIcon />} />
<IconButton noBackground icon={<ReactionIcon />} />
<IconButton noBackground icon={<FormatIcon />} />
</Stack>
<IconButton noBackground icon={<AudioIcon />} />
</XStack>
</YStack>
)
}
export { Composer }

View File

@ -0,0 +1 @@
export { Composer } from './composer'

View File

@ -13,9 +13,10 @@ const Base = styled(Stack, {
display: 'inline-flex', display: 'inline-flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
animation: 'fast',
width: 31, width: 30,
height: 31, height: 30,
borderWidth: 1, borderWidth: 1,
backgroundColor: '$neutral-10', backgroundColor: '$neutral-10',
borderColor: '$neutral-10', borderColor: '$neutral-10',
@ -24,7 +25,27 @@ const Base = styled(Stack, {
backgroundColor: '$neutral-20', backgroundColor: '$neutral-20',
}, },
pressStyle: {
backgroundColor: '$neutral-20',
},
variants: { variants: {
noBackground: {
true: {
backgroundColor: 'transparent',
borderColor: '$neutral-20',
hoverStyle: {
backgroundColor: 'transparent',
borderColor: '$neutral-30',
},
pressStyle: {
backgroundColor: 'transparent',
borderColor: '$neutral-30',
},
},
},
selected: { selected: {
true: { true: {
backgroundColor: '$neutral-30', backgroundColor: '$neutral-30',
@ -56,14 +77,17 @@ interface Props {
icon: React.ReactElement icon: React.ReactElement
onPress?: () => void onPress?: () => void
selected?: boolean selected?: boolean
noBackground?: boolean
} }
const IconButton = (props: Props) => { const IconButton = (props: Props) => {
const { icon, selected, onPress } = props const { icon, noBackground, selected, onPress } = props
return ( return (
<Base selected={selected} onPress={onPress}> <Base selected={selected} onPress={onPress} noBackground={noBackground}>
<Icon selected={selected}>{icon}</Icon> <Icon selected={selected} pointerEvents="none">
{icon}
</Icon>
</Base> </Base>
) )
} }

View File

@ -1,18 +0,0 @@
import type {
SizeTokens,
StyleObject,
ThemeParsed,
Tokens,
} from '@tamagui/core'
import type { SvgProps } from 'react-native-svg'
type GetTokenString<A> = A extends string ? `$${A}` : `$${string}`
export type ColorTokens =
| GetTokenString<keyof Tokens['color']>
| GetTokenString<keyof ThemeParsed>
export type IconProps = SvgProps & {
size?: number | SizeTokens
color?: ColorTokens
style?: StyleObject
}

View File

@ -1,3 +0,0 @@
export { Chevron } from './icons/chevron'
export { Group } from './icons/group'
export { Muted } from './icons/muted'

View File

@ -1,6 +1,8 @@
/* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/ban-ts-comment */
import * as icons from '@status-im/icons' import * as icons from '@status-im/icons'
import { Text } from '../typography' import { Paragraph } from '../typography'
import type { IconProps } from '@status-im/icons' import type { IconProps } from '@status-im/icons'
import type { Meta, StoryObj } from '@storybook/react' import type { Meta, StoryObj } from '@storybook/react'
@ -35,8 +37,8 @@ export const All: Story = {
key={name} key={name}
style={{ display: 'flex', flexDirection: 'column' }} style={{ display: 'flex', flexDirection: 'column' }}
> >
<Icon color="black" /> <Icon color="$background" />
<Text>{unpascal(name)}</Text> <Paragraph>{unpascal(name)}</Paragraph>
</div> </div>
) )
})} })}

View File

@ -1,5 +1,6 @@
export * from './button' export * from './button'
export * from './chat-message' export * from './chat-message'
export * from './composer'
export * from './divider' export * from './divider'
export * from './icon-button' export * from './icon-button'
export * from './image' export * from './image'

View File

@ -0,0 +1,177 @@
import { Basketball, Collaboration, Fire, Peach, Play, Unicorn } from '../emoji'
interface Channels {
id: string
title: string
icon?: React.ReactNode
channelStatus?: 'muted' | 'normal' | 'withMessages' | 'withMentions'
numberOfMessages?: number
}
export interface CommunityProps {
id: string
title: string
numberOfNewMessages?: number
channels: Channels[]
}
// MOCK DATA
export const COMMUNITIES: CommunityProps[] = [
{
id: 'welcome',
title: 'Welcome',
numberOfNewMessages: 3,
channels: [
{
id: 'welcome',
title: '# welcome',
icon: <Collaboration hasBackground />,
},
{
id: 'general-welcome',
title: '# general',
icon: <Play hasBackground />,
},
{
id: 'random',
title: '# random',
icon: <Fire hasBackground />,
},
{
id: 'onboarding',
title: '# onboarding',
icon: <Unicorn hasBackground />,
channelStatus: 'withMentions',
numberOfMessages: 3,
},
],
},
{
id: 'community',
title: 'Community',
numberOfNewMessages: 5,
channels: [
{
id: 'announcements',
title: '# announcements',
icon: <Peach hasBackground />,
},
{
id: 'jobs',
title: '# jobs',
channelStatus: 'withMentions',
numberOfMessages: 3,
icon: <Play hasBackground />,
},
{
id: 'events',
title: '# events',
channelStatus: 'withMentions',
numberOfMessages: 2,
icon: <Fire hasBackground />,
},
{
id: 'meetups',
title: '# meetups',
icon: <Unicorn hasBackground />,
},
],
},
{
id: 'design',
title: 'Design',
channels: [
{
id: 'design',
title: '# design',
icon: <Collaboration hasBackground />,
},
{
id: 'ux',
title: '# ux',
icon: <Play hasBackground />,
},
{
id: 'ui',
title: '# ui',
icon: <Fire hasBackground />,
},
{
id: 'figma',
title: '# figma',
icon: <Unicorn hasBackground />,
},
],
},
{
id: 'General',
title: 'General',
channels: [
{
id: 'general',
title: '# general',
icon: <Collaboration hasBackground />,
},
{
id: 'people-ops',
title: '# people-ops',
icon: <Basketball hasBackground />,
},
],
},
{
id: 'Frontend',
title: 'Frontend',
channels: [
{
id: 'react',
title: '# react',
icon: <Collaboration hasBackground />,
channelStatus: 'withMessages',
},
{
id: 'vue',
title: '# vue',
icon: <Play hasBackground />,
},
{
id: 'angular',
title: '# angular',
channelStatus: 'muted',
icon: <Fire hasBackground />,
},
{
id: 'svelte',
title: '# svelte',
icon: <Unicorn hasBackground />,
},
],
},
{
id: 'Backend',
title: 'Backend',
channels: [
{
id: 'node',
title: '# node',
icon: <Collaboration hasBackground />,
},
{
id: 'python',
title: '# python',
icon: <Play hasBackground />,
},
{
id: 'ruby',
title: '# ruby',
icon: <Fire hasBackground />,
},
{
id: 'php',
title: '# php',
channelStatus: 'muted',
icon: <Unicorn hasBackground />,
},
],
},
]

View File

@ -1,212 +1,52 @@
import { useState } from 'react' import { useState } from 'react'
import { GroupIcon } from '@status-im/icons'
import { Stack } from '@tamagui/core' import { Stack } from '@tamagui/core'
import { Accordion } from '../accordion/accordion' import { Accordion } from '../accordion/accordion'
import { AccordionItem } from '../accordion/accordionItem' import { AccordionItem } from '../accordion/accordionItem'
import { Avatar } from '../avatar' import { Avatar } from '../avatar'
import { Button } from '../button' import { Button } from '../button'
// import { Button } from '../button'
import { Basketball, Collaboration, Fire, Peach, Play, Unicorn } from '../emoji'
import { Group } from '../icon'
import { Image } from '../image' import { Image } from '../image'
import { Heading, Paragraph } from '../typography' import { Heading, Paragraph } from '../typography'
import { COMMUNITIES } from './mock-data'
interface Props { import type { CommunityProps } from './mock-data'
import type { GetProps } from '@tamagui/core'
type BaseProps = GetProps<typeof Stack>
type Props = {
name: string name: string
description: string description: string
membersCount: number membersCount: number
} selectedChannel?: string
communities?: CommunityProps[]
interface Channels { onChannelPress: (channelId: string) => void
id: string } & BaseProps
title: string
icon?: React.ReactNode
channelStatus?: 'muted' | 'normal' | 'withMessages' | 'withMentions'
numberOfMessages?: number
}
interface CommunitiesProps {
id: string
title: string
numberOfNewMessages?: number
channels: Channels[]
}
// MOCK DATA
const COMMUNITIES: CommunitiesProps[] = [
{
id: 'welcome',
title: 'Welcome',
numberOfNewMessages: 3,
channels: [
{
id: 'welcome',
title: '# welcome',
icon: <Collaboration hasBackground />,
},
{
id: 'general-welcome',
title: '# general',
icon: <Play hasBackground />,
},
{
id: 'random',
title: '# random',
icon: <Fire hasBackground />,
},
{
id: 'onboarding',
title: '# onboarding',
icon: <Unicorn hasBackground />,
channelStatus: 'withMentions',
numberOfMessages: 3,
},
],
},
{
id: 'community',
title: 'Community',
numberOfNewMessages: 5,
channels: [
{
id: 'announcements',
title: '# announcements',
icon: <Peach hasBackground />,
},
{
id: 'jobs',
title: '# jobs',
channelStatus: 'withMentions',
numberOfMessages: 3,
icon: <Play hasBackground />,
},
{
id: 'events',
title: '# events',
channelStatus: 'withMentions',
numberOfMessages: 2,
icon: <Fire hasBackground />,
},
{
id: 'meetups',
title: '# meetups',
icon: <Unicorn hasBackground />,
},
],
},
{
id: 'Design',
title: 'Design',
channels: [
{
id: 'design',
title: '# design',
icon: <Collaboration hasBackground />,
},
{
id: 'ux',
title: '# ux',
icon: <Play hasBackground />,
},
{
id: 'ui',
title: '# ui',
icon: <Fire hasBackground />,
},
{
id: 'figma',
title: '# figma',
icon: <Unicorn hasBackground />,
},
],
},
{
id: 'General',
title: 'General',
channels: [
{
id: 'general',
title: '# general',
icon: <Collaboration hasBackground />,
},
{
id: 'people-ops',
title: '# people-ops',
icon: <Basketball hasBackground />,
},
],
},
{
id: 'Frontend',
title: 'Frontend',
channels: [
{
id: 'react',
title: '# react',
icon: <Collaboration hasBackground />,
channelStatus: 'withMessages',
},
{
id: 'vue',
title: '# vue',
icon: <Play hasBackground />,
},
{
id: 'angular',
title: '# angular',
channelStatus: 'muted',
icon: <Fire hasBackground />,
},
{
id: 'svelte',
title: '# svelte',
icon: <Unicorn hasBackground />,
},
],
},
{
id: 'Backend',
title: 'Backend',
channels: [
{
id: 'node',
title: '# node',
icon: <Collaboration hasBackground />,
},
{
id: 'python',
title: '# python',
icon: <Play hasBackground />,
},
{
id: 'ruby',
title: '# ruby',
icon: <Fire hasBackground />,
},
{
id: 'php',
title: '# php',
channelStatus: 'muted',
icon: <Unicorn hasBackground />,
},
],
},
]
const COMMUNITIES_EXPAND_CONTROL = COMMUNITIES.reduce(
(o, key) => ({ ...o, [key.id]: false }),
{} as Record<string, boolean>[]
)
const Sidebar = (props: Props) => { const Sidebar = (props: Props) => {
const { name, description, membersCount } = props const {
const [isExpanded, setIsExpanded] = useState({ name,
...COMMUNITIES_EXPAND_CONTROL, description,
welcome: true, membersCount,
}) communities = COMMUNITIES,
selectedChannel,
onChannelPress,
} = props
const [selectedChannel, setSelectedChannel] = useState('welcome') const communitiesExpandControl = communities.reduce(
(o, key) => ({ ...o, [key.id]: false }),
{} as Record<string, boolean>[]
)
const [isExpanded, setIsExpanded] = useState({
...communitiesExpandControl,
welcome: true,
community: true,
design: true,
})
const handleToggle = (id: string) => { const handleToggle = (id: string) => {
setIsExpanded(prev => ({ setIsExpanded(prev => ({
@ -231,23 +71,23 @@ const Sidebar = (props: Props) => {
zIndex={10} zIndex={10}
> >
<Stack paddingHorizontal={16} paddingBottom={16}> <Stack paddingHorizontal={16} paddingBottom={16}>
<Stack marginTop={-32} marginBottom={12}> <Stack marginTop={-40} marginBottom={12}>
<Avatar <Avatar
withOutline withOutline
src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fi.seadn.io%2Fgae%2FFG0QJ00fN3c_FWuPeUr9-T__iQl63j9hn5d6svW8UqOmia5zp3lKHPkJuHcvhZ0f_Pd6P2COo9tt9zVUvdPxG_9BBw%3Fw%3D500%26auto%3Dformat&f=1&nofb=1&ipt=c177cd71d8d0114080cfc6efd3f9e098ddaeb1b347919bd3089bf0aacb003b3e&ipo=images" src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fi.seadn.io%2Fgae%2FFG0QJ00fN3c_FWuPeUr9-T__iQl63j9hn5d6svW8UqOmia5zp3lKHPkJuHcvhZ0f_Pd6P2COo9tt9zVUvdPxG_9BBw%3Fw%3D500%26auto%3Dformat&f=1&nofb=1&ipt=c177cd71d8d0114080cfc6efd3f9e098ddaeb1b347919bd3089bf0aacb003b3e&ipo=images"
size={56} size={80}
/> />
</Stack> </Stack>
<Heading marginBottom={16}>{name}</Heading> <Heading marginBottom={16}>{name}</Heading>
<Paragraph marginBottom={12}>{description}</Paragraph> <Paragraph marginBottom={12}>{description}</Paragraph>
<Stack flexDirection="row" alignItems="center" mb={12}> <Stack flexDirection="row" alignItems="center" mb={12}>
<Group color="$neutral-100" size={16} /> <GroupIcon color="$neutral-100" size={16} />
<Paragraph ml={8}>{membersCount}</Paragraph> <Paragraph ml={8}>{membersCount}</Paragraph>
</Stack> </Stack>
<Button>Join community</Button> <Button>Join community</Button>
</Stack> </Stack>
{COMMUNITIES.map(community => ( {communities.map(community => (
<Accordion <Accordion
key={community.id} key={community.id}
isExpanded={!!isExpanded[community.id as keyof typeof isExpanded]} isExpanded={!!isExpanded[community.id as keyof typeof isExpanded]}
@ -258,17 +98,22 @@ const Sidebar = (props: Props) => {
!isExpanded[community.id as keyof typeof isExpanded] !isExpanded[community.id as keyof typeof isExpanded]
} }
> >
{community.channels.map(channel => ( {community.channels.map((channel, index) => {
<AccordionItem const isLastChannelOfTheList =
key={channel.id} index === community.channels.length - 1
icon={channel.icon} return (
title={channel.title} <AccordionItem
channelStatus={channel.channelStatus} key={channel.id}
numberOfMessages={channel.numberOfMessages} icon={channel.icon}
isSelected={selectedChannel === channel.id} title={channel.title}
onPress={() => setSelectedChannel(channel.id)} channelStatus={channel.channelStatus}
/> numberOfMessages={channel.numberOfMessages}
))} isSelected={selectedChannel === channel.id}
onPress={() => onChannelPress(channel.id)}
mb={isLastChannelOfTheList ? 8 : 0}
/>
)
})}
</Accordion> </Accordion>
))} ))}
<Stack borderBottomColor="$neutral-10" borderBottomWidth={1} /> <Stack borderBottomColor="$neutral-10" borderBottomWidth={1} />

View File

@ -0,0 +1,30 @@
import { memo } from 'react'
import { Path, Svg } from 'react-native-svg'
import { themed } from './themed'
import type { IconProps } from './types'
function Icon(props: IconProps) {
const { color, size = 20, ...rest } = props
return (
<Svg
width={size}
height={size}
viewBox={`0 0 ${size} ${size}`}
fill="none"
{...rest}
>
<Path
fillRule="evenodd"
clipRule="evenodd"
d="M10 2.35A3.65 3.65 0 0 0 6.35 6v3a3.65 3.65 0 0 0 7.3 0V6A3.65 3.65 0 0 0 10 2.35ZM7.65 6a2.35 2.35 0 1 1 4.7 0v3a2.35 2.35 0 0 1-4.7 0V6Zm-2.5 1.5V9a4.85 4.85 0 1 0 9.7 0V7.5h1.3V9a6.15 6.15 0 0 1-5.5 6.116v1.234H12v1.3H8v-1.3h1.35v-1.234A6.15 6.15 0 0 1 3.85 9V7.5h1.3Z"
fill={color}
/>
</Svg>
)
}
export const AudioIcon = memo<IconProps>(themed(Icon))

View File

@ -1,12 +1,11 @@
import { memo } from 'react' import { memo } from 'react'
import { themed } from '@status-im/icons/src/themed'
import { Path, Svg } from 'react-native-svg' import { Path, Svg } from 'react-native-svg'
import { themed } from '../themed' import type { IconProps } from './types'
import type { IconProps } from '../IconProps' function Icon(props: IconProps) {
const Icon = (props: IconProps) => {
const { color, size = 16, ...otherProps } = props const { color, size = 16, ...otherProps } = props
return ( return (
@ -22,6 +21,4 @@ const Icon = (props: IconProps) => {
) )
} }
Icon.displayName = 'Chevron' export const ChevronIcon = memo<IconProps>(themed(Icon))
export const Chevron = memo<IconProps>(themed(Icon))

View File

@ -0,0 +1,32 @@
import { memo } from 'react'
import { ClipPath, Defs, G, Path, Svg } from 'react-native-svg'
import { themed } from './themed'
import type { IconProps } from './types'
function Icon(props: IconProps) {
const { color, size = 20, ...rest } = props
return (
<Svg
width={size}
height={size}
viewBox={`0 0 ${size} ${size}`}
fill="none"
{...rest}
>
<G clipPath="url(#format-icon-a)" fill={color}>
<Path d="M4.343 14.047a.858.858 0 1 1-1.622-.558l2.575-7.314a1.493 1.493 0 0 1 2.817 0l2.578 7.314a.858.858 0 1 1-1.621.559L6.753 7.15a.051.051 0 0 0-.098 0l-2.312 6.896Zm-.137-2.434c0-.38.308-.688.688-.688h3.61a.688.688 0 0 1 0 1.376h-3.61a.688.688 0 0 1-.688-.688ZM13.82 14.823c-.449 0-.857-.085-1.223-.254a2.1 2.1 0 0 1-.872-.744c-.216-.326-.324-.72-.324-1.181 0-.407.08-.736.24-.988.16-.256.374-.456.642-.6.268-.145.563-.253.886-.324.327-.073.654-.132.984-.175.43-.055.78-.097 1.048-.125.27-.03.467-.081.59-.152.127-.07.19-.194.19-.37v-.036c0-.456-.125-.81-.374-1.062-.246-.252-.62-.379-1.122-.379-.52 0-.928.114-1.223.342-.13.1-.244.204-.34.311-.193.213-.49.344-.76.248-.303-.108-.457-.453-.275-.717.133-.192.285-.355.456-.488.311-.243.65-.413 1.016-.508.37-.099.732-.148 1.09-.148.227 0 .489.028.784.083.299.053.586.162.863.328.28.166.513.417.697.752.185.336.277.785.277 1.349v4.127c0 .3-.244.544-.544.544h-.065a.48.48 0 0 1-.48-.48v-.446a.034.034 0 0 0-.034-.034.035.035 0 0 0-.03.02 1.96 1.96 0 0 1-.36.474 2.131 2.131 0 0 1-.689.448c-.286.123-.635.185-1.048.185Zm.167-.98c.43 0 .794-.084 1.09-.253a1.729 1.729 0 0 0 .904-1.5v-.653c0-.117-.193-.225-.305-.192a5.124 5.124 0 0 1-.535.115 24.109 24.109 0 0 1-1.044.139 4.158 4.158 0 0 0-.794.18c-.243.08-.44.201-.59.364-.148.16-.222.379-.222.656 0 .379.14.665.42.859.283.19.642.286 1.076.286Z" />
</G>
<Defs>
<ClipPath id="format-icon-a">
<Path d="M0 0h20v20H0z" />
</ClipPath>
</Defs>
</Svg>
)
}
export const FormatIcon = memo<IconProps>(themed(Icon))

View File

@ -1,12 +1,11 @@
import { memo } from 'react' import { memo } from 'react'
import { themed } from '@status-im/icons/src/themed'
import { Path, Svg } from 'react-native-svg' import { Path, Svg } from 'react-native-svg'
import { themed } from '../themed' import type { IconProps } from './types'
import type { IconProps } from '../IconProps' function Icon(props: IconProps) {
const Icon = (props: IconProps) => {
const { color, size = 16, ...otherProps } = props const { color, size = 16, ...otherProps } = props
return ( return (
@ -24,16 +23,14 @@ const Icon = (props: IconProps) => {
fillRule="evenodd" fillRule="evenodd"
clipRule="evenodd" clipRule="evenodd"
d="M4.6 5a1.9 1.9 0 1 1 3.8 0 1.9 1.9 0 0 1-3.8 0Zm1.9-3.1a3.1 3.1 0 1 0 0 6.2 3.1 3.1 0 0 0 0-6.2ZM5 8.9a3.6 3.6 0 0 0-3.6 3.6A1.6 1.6 0 0 0 3 14.1h6a1.6 1.6 0 0 0 1.6-1.6A3.6 3.6 0 0 0 7 8.9H5Zm-2.4 3.6A2.4 2.4 0 0 1 5 10.1h2a2.4 2.4 0 0 1 2.4 2.4.4.4 0 0 1-.4.4H3a.4.4 0 0 1-.4-.4Z" d="M4.6 5a1.9 1.9 0 1 1 3.8 0 1.9 1.9 0 0 1-3.8 0Zm1.9-3.1a3.1 3.1 0 1 0 0 6.2 3.1 3.1 0 0 0 0-6.2ZM5 8.9a3.6 3.6 0 0 0-3.6 3.6A1.6 1.6 0 0 0 3 14.1h6a1.6 1.6 0 0 0 1.6-1.6A3.6 3.6 0 0 0 7 8.9H5Zm-2.4 3.6A2.4 2.4 0 0 1 5 10.1h2a2.4 2.4 0 0 1 2.4 2.4.4.4 0 0 1-.4.4H3a.4.4 0 0 1-.4-.4Z"
fill={`${color}`} fill={color}
/> />
<Path <Path
d="M10 3.1a1.9 1.9 0 0 1 0 3.8v1.2a3.1 3.1 0 0 0 0-6.2v1.2ZM11 10.1h.5a2.4 2.4 0 0 1 2.4 2.4.4.4 0 0 1-.4.4h-2v1.2h2a1.6 1.6 0 0 0 1.6-1.6 3.6 3.6 0 0 0-3.6-3.6H11v1.2Z" d="M10 3.1a1.9 1.9 0 0 1 0 3.8v1.2a3.1 3.1 0 0 0 0-6.2v1.2ZM11 10.1h.5a2.4 2.4 0 0 1 2.4 2.4.4.4 0 0 1-.4.4h-2v1.2h2a1.6 1.6 0 0 0 1.6-1.6 3.6 3.6 0 0 0-3.6-3.6H11v1.2Z"
fill={`${color}`} fill={color}
/> />
</Svg> </Svg>
) )
} }
Icon.displayName = 'Group' export const GroupIcon = memo<IconProps>(themed(Icon))
export const Group = memo<IconProps>(themed(Icon))

View File

@ -0,0 +1,24 @@
import { memo } from 'react'
import { Path, Svg } from 'react-native-svg'
import { themed } from './themed'
import type { IconProps } from './types'
function Icon(props: IconProps) {
const { color, size = 20, ...rest } = props
return (
<Svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} {...rest}>
<Path
fillRule="evenodd"
clipRule="evenodd"
d="M9.9 2.85h-.029c-1.096 0-1.958 0-2.651.057-.707.057-1.296.177-1.831.45a4.65 4.65 0 0 0-2.032 2.032c-.273.535-.393 1.124-.45 1.83-.057.694-.057 1.556-.057 2.652v.258c0 1.096 0 1.958.057 2.651.057.707.177 1.296.45 1.831a4.65 4.65 0 0 0 2.032 2.032c.535.273 1.124.393 1.83.45.694.057 1.556.057 2.652.057h.258c1.096 0 1.958 0 2.651-.057.707-.057 1.296-.177 1.831-.45a4.65 4.65 0 0 0 2.032-2.032c.273-.535.393-1.124.45-1.83.057-.694.057-1.556.057-2.652V9.87c0-1.096 0-1.958-.057-2.651-.057-.707-.177-1.296-.45-1.831a4.65 4.65 0 0 0-2.032-2.032c-.535-.273-1.124-.393-1.83-.45-.694-.057-1.556-.057-2.652-.057H9.9ZM5.98 4.515c.32-.163.719-.261 1.346-.313.634-.051 1.443-.052 2.574-.052h.2c1.13 0 1.94 0 2.574.052.627.052 1.026.15 1.347.313a3.35 3.35 0 0 1 1.464 1.464c.163.321.261.72.313 1.347.052.634.052 1.443.052 2.574v.2c0 1.13 0 1.94-.052 2.574a8.05 8.05 0 0 1-.024.243 5.089 5.089 0 0 0-2.754-.549 5.197 5.197 0 0 0-2.284.763 8.646 8.646 0 0 0-6.58-4.703c.007-.424.02-.785.046-1.102.052-.627.15-1.026.313-1.347A3.35 3.35 0 0 1 5.98 4.515Zm5.256 9.841c.155.483.268.98.336 1.487.424-.006.785-.02 1.102-.045.627-.052 1.026-.15 1.347-.313a3.35 3.35 0 0 0 1.372-1.296 3.818 3.818 0 0 0-2.263-.525 3.936 3.936 0 0 0-1.894.692Zm-3.039-2.553a7.35 7.35 0 0 1 2.063 4.047H9.9c-1.13 0-1.94 0-2.574-.052-.627-.052-1.026-.15-1.347-.313a3.35 3.35 0 0 1-1.464-1.464c-.163-.321-.261-.72-.313-1.347-.051-.634-.052-1.443-.052-2.574v-.36a7.35 7.35 0 0 1 4.047 2.063ZM11.15 8a.85.85 0 1 1 1.7 0 .85.85 0 0 1-1.7 0ZM12 5.85a2.15 2.15 0 1 0 0 4.3 2.15 2.15 0 0 0 0-4.3Z"
fill={color}
/>
</Svg>
)
}
export const ImageIcon = memo<IconProps>(themed(Icon))

View File

@ -1,4 +1,11 @@
export { AudioIcon } from './audio-icon'
export { ChevronIcon } from './chevron-icon'
export { FormatIcon } from './format-icon'
export { GroupIcon } from './group-icon'
export { ImageIcon } from './image-icon'
export { LockedIcon } from './lock-icon' export { LockedIcon } from './lock-icon'
export { MembersIcon } from './members-icon' export { MembersIcon } from './members-icon'
export { MutedIcon } from './muted-icon'
export { OptionsIcon } from './options-icon' export { OptionsIcon } from './options-icon'
export { ReactionIcon } from './reaction-icon'
export type { IconProps } from './types' export type { IconProps } from './types'

View File

@ -1,24 +1,25 @@
import { memo } from 'react'
import { Path, Svg } from 'react-native-svg'
import { themed } from './themed'
import type { IconProps } from './types' import type { IconProps } from './types'
export function LockedIcon(props: IconProps) { function Icon(props: IconProps) {
const { color = 'currentColor', size = 20, ...rest } = props const { color = 'currentColor', size = 20, ...rest } = props
// FIXME: not need to differentiate sizes in the designs // FIXME: not need to differentiate sizes in the designs
return ( return (
<svg <Svg width={size} height={size} viewBox="0 0 16 16" fill="none" {...rest}>
width={size} <Path
height={size}
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...rest}
>
<path
fillRule="evenodd" fillRule="evenodd"
clipRule="evenodd" clipRule="evenodd"
d="M8 .9h-.012c-.081 0-.137 0-.186.002a3 3 0 00-2.9 2.9c-.002.05-.002.105-.002.186v1.175a3.6 3.6 0 00-2.127 2.405c-.123.46-.123.998-.123 1.832v.2c0 .834 0 1.373.123 1.832a3.6 3.6 0 002.545 2.545c.46.123.998.123 1.832.123H8.85c.834 0 1.373 0 1.832-.123a3.6 3.6 0 002.545-2.545c.123-.46.123-.998.123-1.832v-.2c0-.834 0-1.373-.123-1.832A3.6 3.6 0 0011.1 5.163V3.988c0-.081 0-.137-.002-.186A3 3 0 008.012.9H8zm.75 5.2h-1.5c-.969 0-1.335.005-1.621.082a2.4 2.4 0 00-1.697 1.697c-.077.286-.082.652-.082 1.621s.005 1.335.082 1.621a2.4 2.4 0 001.697 1.697c.286.077.652.082 1.621.082h1.5c.969 0 1.335-.005 1.621-.082a2.4 2.4 0 001.697-1.697c.077-.286.082-.652.082-1.621s-.005-1.335-.082-1.621a2.4 2.4 0 00-1.697-1.697C10.085 6.105 9.72 6.1 8.75 6.1zm.288-1.2H9.9V4v-.159a1.8 1.8 0 00-1.741-1.74 5.726 5.726 0 00-.318 0 1.8 1.8 0 00-1.74 1.74V4.9H9.037zM7.4 8.25h1.2v2.5H7.4v-2.5z" d="M8 .9h-.012c-.081 0-.137 0-.186.002a3 3 0 00-2.9 2.9c-.002.05-.002.105-.002.186v1.175a3.6 3.6 0 00-2.127 2.405c-.123.46-.123.998-.123 1.832v.2c0 .834 0 1.373.123 1.832a3.6 3.6 0 002.545 2.545c.46.123.998.123 1.832.123H8.85c.834 0 1.373 0 1.832-.123a3.6 3.6 0 002.545-2.545c.123-.46.123-.998.123-1.832v-.2c0-.834 0-1.373-.123-1.832A3.6 3.6 0 0011.1 5.163V3.988c0-.081 0-.137-.002-.186A3 3 0 008.012.9H8zm.75 5.2h-1.5c-.969 0-1.335.005-1.621.082a2.4 2.4 0 00-1.697 1.697c-.077.286-.082.652-.082 1.621s.005 1.335.082 1.621a2.4 2.4 0 001.697 1.697c.286.077.652.082 1.621.082h1.5c.969 0 1.335-.005 1.621-.082a2.4 2.4 0 001.697-1.697c.077-.286.082-.652.082-1.621s-.005-1.335-.082-1.621a2.4 2.4 0 00-1.697-1.697C10.085 6.105 9.72 6.1 8.75 6.1zm.288-1.2H9.9V4v-.159a1.8 1.8 0 00-1.741-1.74 5.726 5.726 0 00-.318 0 1.8 1.8 0 00-1.74 1.74V4.9H9.037zM7.4 8.25h1.2v2.5H7.4v-2.5z"
fill={color} fill={color}
/> />
</svg> </Svg>
) )
} }
export const LockedIcon = memo<IconProps>(themed(Icon))

View File

@ -1,29 +1,30 @@
import { memo } from 'react'
import { Path, Svg } from 'react-native-svg'
import { themed } from './themed'
import type { IconProps } from './types' import type { IconProps } from './types'
export function MembersIcon(props: IconProps) { function Icon(props: IconProps) {
const { color = 'currentColor', size = 20, ...rest } = props const { color = 'currentColor', size = 20, ...rest } = props
return ( return (
<svg <Svg width={size} height={size} viewBox="0 0 20 20" fill="none" {...rest}>
width={size} <Path
height={size}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...rest}
>
<path
fillRule="evenodd" fillRule="evenodd"
clipRule="evenodd" clipRule="evenodd"
d="M6.15 6a1.85 1.85 0 113.7 0 1.85 1.85 0 01-3.7 0zM8 2.85a3.15 3.15 0 100 6.3 3.15 3.15 0 000-6.3zm-1.25 7.5a4.4 4.4 0 00-4.4 4.4c0 1.049.85 1.9 1.9 1.9h7.5a1.9 1.9 0 001.9-1.9 4.4 4.4 0 00-4.4-4.4h-2.5zm-3.1 4.4a3.1 3.1 0 013.1-3.1h2.5a3.1 3.1 0 013.1 3.1.6.6 0 01-.6.6h-7.5a.6.6 0 01-.6-.6z" d="M6.15 6a1.85 1.85 0 113.7 0 1.85 1.85 0 01-3.7 0zM8 2.85a3.15 3.15 0 100 6.3 3.15 3.15 0 000-6.3zm-1.25 7.5a4.4 4.4 0 00-4.4 4.4c0 1.049.85 1.9 1.9 1.9h7.5a1.9 1.9 0 001.9-1.9 4.4 4.4 0 00-4.4-4.4h-2.5zm-3.1 4.4a3.1 3.1 0 013.1-3.1h2.5a3.1 3.1 0 013.1 3.1.6.6 0 01-.6.6h-7.5a.6.6 0 01-.6-.6z"
fill={color} fill={color}
/> />
<path <Path
d="M13.5 11h.25a3.75 3.75 0 013.75 3.75v0c0 .69-.56 1.25-1.25 1.25H14.5M11.809 8c1.153 0 2.087-.895 2.087-2s-.934-2-2.087-2" d="M13.5 11h.25a3.75 3.75 0 013.75 3.75v0c0 .69-.56 1.25-1.25 1.25H14.5M11.809 8c1.153 0 2.087-.895 2.087-2s-.934-2-2.087-2"
stroke={color} stroke={color}
strokeWidth={1.3} strokeWidth={1.3}
strokeLinejoin="round" strokeLinejoin="round"
/> />
</svg> </Svg>
) )
} }
export const MembersIcon = memo<IconProps>(themed(Icon))

View File

@ -1,12 +1,11 @@
import { memo } from 'react' import { memo } from 'react'
import { themed } from '@status-im/icons/src/themed'
import { Path, Svg } from 'react-native-svg' import { Path, Svg } from 'react-native-svg'
import { themed } from '../themed' import type { IconProps } from './types'
import type { IconProps } from '../IconProps' function Icon(props: IconProps) {
const Icon = (props: IconProps) => {
const { color, size = 16, ...otherProps } = props const { color, size = 16, ...otherProps } = props
return ( return (
@ -27,6 +26,4 @@ const Icon = (props: IconProps) => {
) )
} }
Icon.displayName = 'Muted' export const MutedIcon = memo<IconProps>(themed(Icon))
export const Muted = memo<IconProps>(themed(Icon))

View File

@ -1,20 +1,21 @@
import { memo } from 'react'
import { Circle, Svg } from 'react-native-svg'
import { themed } from './themed'
import type { IconProps } from './types' import type { IconProps } from './types'
export function OptionsIcon(props: IconProps) { function Icon(props: IconProps) {
const { color = 'currentColor', size = 20, ...rest } = props const { color = 'currentColor', size = 20, ...rest } = props
return ( return (
<svg <Svg width={size} height={size} viewBox="0 0 20 20" fill="none" {...rest}>
width={size} <Circle cx={4.5} cy={10} r={1.5} fill={color} />
height={size} <Circle cx={10} cy={10} r={1.5} fill={color} />
viewBox="0 0 20 20" <Circle cx={15.5} cy={10} r={1.5} fill={color} />
fill="none" </Svg>
xmlns="http://www.w3.org/2000/svg"
{...rest}
>
<circle cx={4.5} cy={10} r={1.5} fill={color} />
<circle cx={10} cy={10} r={1.5} fill={color} />
<circle cx={15.5} cy={10} r={1.5} fill={color} />
</svg>
) )
} }
export const OptionsIcon = memo<IconProps>(themed(Icon))

View File

@ -0,0 +1,32 @@
import { memo } from 'react'
import { Circle, Path, Svg } from 'react-native-svg'
import { themed } from './themed'
import type { IconProps } from './types'
export function Icon(props: IconProps) {
const { color = 'currentColor', size = 20, ...rest } = props
return (
<Svg
width={size}
height={size}
viewBox={`0 0 ${size} ${size}`}
fill="none"
{...rest}
>
<Circle cx="10" cy="10" r="6.75" stroke={color} strokeWidth="1.3" />
<Path
d="M7.525 12a3.5 3.5 0 0 0 4.95 0"
stroke={color}
strokeWidth="1.3"
/>
<Circle cx="8" cy="8.5" r="1" fill={color} />
<Circle cx="12" cy="8.5" r="1" fill={color} />
</Svg>
)
}
export const ReactionIcon = memo<IconProps>(themed(Icon))

View File

@ -1,6 +1,6 @@
import { useCurrentColor } from 'tamagui' import { useCurrentColor } from 'tamagui'
import type { IconProps } from './IconProps' import type { IconProps } from './types'
import type React from 'react' import type React from 'react'
export function themed(Component: React.ElementType) { export function themed(Component: React.ElementType) {

View File

@ -1,9 +1,18 @@
import type { SVGAttributes } from 'react' import type {
SizeTokens,
StyleObject,
ThemeParsed,
Tokens,
} from '@tamagui/core'
import type { SvgProps } from 'react-native-svg'
export interface IconProps extends SVGAttributes<SVGElement> { type GetTokenString<A> = A extends string ? `$${A}` : `$${string}`
children?: never export type ColorTokens =
width?: never | GetTokenString<keyof Tokens['color']>
height?: never | GetTokenString<keyof ThemeParsed>
color?: string
size?: number export type IconProps = SvgProps & {
size?: number | SizeTokens
color?: ColorTokens
style?: StyleObject
} }

101
yarn.lock
View File

@ -4421,6 +4421,48 @@
resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa" resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa"
integrity sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ== integrity sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==
"@react-navigation/core@^6.4.6":
version "6.4.6"
resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-6.4.6.tgz#b0738667dec5927b01c4c496c2f4c73ef8a5e4dd"
integrity sha512-6zaAgUT5k4vhJlddUk2l52RZyMkMelHdrRv1cL57ALi2RZzERdgmbiMKhJerxFLn9S8E3PUe8vwxHzjHOZKG4w==
dependencies:
"@react-navigation/routers" "^6.1.6"
escape-string-regexp "^4.0.0"
nanoid "^3.1.23"
query-string "^7.1.3"
react-is "^16.13.0"
use-latest-callback "^0.1.5"
"@react-navigation/elements@^1.3.13":
version "1.3.13"
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.13.tgz#5105fa26df8d32810cd9f14d6ec5a3d2c2bb26d2"
integrity sha512-LqqK5s2ZfYHn2cQ376jC5V9dQztLH5ixkkJj9WR7JY2g4SghDd39WJhL3Jillw1Mu3F3b9sZwvAK+QkXhnDeAA==
"@react-navigation/native-stack@^6.9.8":
version "6.9.8"
resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.8.tgz#c953a169918a4bdde56f7d2dc1073da4726b4cb7"
integrity sha512-74dje939lflsTXJQwCAdznbJ4B6V8sA5CSzuHwbiogL8B6EVXNa/qliXtB7DBAvzeyWDWT3u+gM2vOYJOeXYhA==
dependencies:
"@react-navigation/elements" "^1.3.13"
warn-once "^0.1.0"
"@react-navigation/native@^6.1.2":
version "6.1.2"
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.1.2.tgz#6fffbf4787c233687fff8fe9ce7364ffce696d38"
integrity sha512-qLUe0asHofr5EhxKjvUBJ9DrPPmR4535IEwmW3oU4DRb3cLbNysjajJKHL8kcYtqPvn9Bx9QZG2x0PMb2vN23A==
dependencies:
"@react-navigation/core" "^6.4.6"
escape-string-regexp "^4.0.0"
fast-deep-equal "^3.1.3"
nanoid "^3.1.23"
"@react-navigation/routers@^6.1.6":
version "6.1.6"
resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-6.1.6.tgz#f57f2a73855d329255aa225fdad75ae8e7700c6d"
integrity sha512-Z5DeCW3pUvMafbU9Cjy1qJYC2Bvl8iy3+PfsB0DsAwQ6zZ3WAXW5FTMX4Gb9H+Jg6qHWGbMFFwlYpS3UJ3tlVQ==
dependencies:
nanoid "^3.1.23"
"@rollup/pluginutils@^4.2.0", "@rollup/pluginutils@^4.2.1": "@rollup/pluginutils@^4.2.0", "@rollup/pluginutils@^4.2.1":
version "4.2.1" version "4.2.1"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
@ -8636,7 +8678,7 @@ decamelize@^5.0.0:
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.1.tgz#db11a92e58c741ef339fb0a2868d8a06a9a7b1e9" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.1.tgz#db11a92e58c741ef339fb0a2868d8a06a9a7b1e9"
integrity sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA== integrity sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==
decode-uri-component@^0.2.0: decode-uri-component@^0.2.0, decode-uri-component@^0.2.2:
version "0.2.2" version "0.2.2"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
@ -10734,6 +10776,11 @@ fill-range@^7.0.1:
dependencies: dependencies:
to-regex-range "^5.0.1" to-regex-range "^5.0.1"
filter-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b"
integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==
finalhandler@1.1.2: finalhandler@1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
@ -13980,7 +14027,7 @@ nanoid@^3.0.2:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35"
integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==
nanoid@^3.3.1, nanoid@^3.3.4: nanoid@^3.1.23, nanoid@^3.3.1, nanoid@^3.3.4:
version "3.3.4" version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
@ -15281,6 +15328,16 @@ qs@6.11.0, qs@^6.10.0, qs@^6.4.0:
dependencies: dependencies:
side-channel "^1.0.4" side-channel "^1.0.4"
query-string@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328"
integrity sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==
dependencies:
decode-uri-component "^0.2.2"
filter-obj "^1.1.0"
split-on-first "^1.0.0"
strict-uri-encode "^2.0.0"
querystringify@^2.1.1: querystringify@^2.1.1:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
@ -15387,6 +15444,11 @@ react-element-to-jsx-string@^15.0.0:
is-plain-object "5.0.0" is-plain-object "5.0.0"
react-is "18.1.0" react-is "18.1.0"
react-freeze@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/react-freeze/-/react-freeze-1.0.3.tgz#5e3ca90e682fed1d73a7cb50c2c7402b3e85618d"
integrity sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g==
react-inspector@^6.0.0: react-inspector@^6.0.0:
version "6.0.1" version "6.0.1"
resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-6.0.1.tgz#1a37f0165d9df81ee804d63259eaaeabe841287d" resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-6.0.1.tgz#1a37f0165d9df81ee804d63259eaaeabe841287d"
@ -15402,7 +15464,7 @@ react-is@18.1.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
react-is@^16.13.1: react-is@^16.13.0, react-is@^16.13.1:
version "16.13.1" version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@ -15427,6 +15489,19 @@ react-native-gradle-plugin@^0.70.3:
resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz#cbcf0619cbfbddaa9128701aa2d7b4145f9c4fc8" resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz#cbcf0619cbfbddaa9128701aa2d7b4145f9c4fc8"
integrity sha512-oOanj84fJEXUg9FoEAQomA8ISG+DVIrTZ3qF7m69VQUJyOGYyDZmPqKcjvRku4KXlEH6hWO9i4ACLzNBh8gC0A== integrity sha512-oOanj84fJEXUg9FoEAQomA8ISG+DVIrTZ3qF7m69VQUJyOGYyDZmPqKcjvRku4KXlEH6hWO9i4ACLzNBh8gC0A==
react-native-safe-area-context@4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.4.1.tgz#239c60b8a9a80eac70a38a822b04c0f1d15ffc01"
integrity sha512-N9XTjiuD73ZpVlejHrUWIFZc+6Z14co1K/p1IFMkImU7+avD69F3y+lhkqA2hN/+vljdZrBSiOwXPkuo43nFQA==
react-native-screens@~3.18.0:
version "3.18.2"
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-3.18.2.tgz#d7ab2d145258d3db9fa630fa5379dc4474117866"
integrity sha512-ANUEuvMUlsYJ1QKukEhzhfrvOUO9BVH9Nzg+6eWxpn3cfD/O83yPBOF8Mx6x5H/2+sMy+VS5x/chWOOo/U7QJw==
dependencies:
react-freeze "^1.0.0"
warn-once "^0.1.0"
react-native-svg@^13.7.0: react-native-svg@^13.7.0:
version "13.7.0" version "13.7.0"
resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-13.7.0.tgz#be2ffb935e996762543dd7376bdc910722f7a43c" resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-13.7.0.tgz#be2ffb935e996762543dd7376bdc910722f7a43c"
@ -16566,6 +16641,11 @@ spdx-license-ids@^3.0.0:
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95"
integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==
split-on-first@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
split-string@^3.0.1, split-string@^3.0.2: split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
@ -16658,6 +16738,11 @@ stream-transform@^2.1.3:
dependencies: dependencies:
mixme "^0.5.1" mixme "^0.5.1"
strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==
string-argv@^0.3.1: string-argv@^0.3.1:
version "0.3.1" version "0.3.1"
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da"
@ -17866,6 +17951,11 @@ use-isomorphic-layout-effect@^1.1.1:
resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
use-latest-callback@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/use-latest-callback/-/use-latest-callback-0.1.5.tgz#a4a836c08fa72f6608730b5b8f4bbd9c57c04f51"
integrity sha512-HtHatS2U4/h32NlkhupDsPlrbiD27gSH5swBdtXbCAlc6pfOFzaj0FehW/FO12rx8j2Vy4/lJScCiJyM01E+bQ==
use-sidecar@^1.0.1: use-sidecar@^1.0.1:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.5.tgz#ffff2a17c1df42e348624b699ba6e5c220527f2b" resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.5.tgz#ffff2a17c1df42e348624b699ba6e5c220527f2b"
@ -18081,6 +18171,11 @@ walker@^1.0.7, walker@^1.0.8:
dependencies: dependencies:
makeerror "1.0.12" makeerror "1.0.12"
warn-once@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/warn-once/-/warn-once-0.1.1.tgz#952088f4fb56896e73fd4e6a3767272a3fccce43"
integrity sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==
watchpack@^2.2.0: watchpack@^2.2.0:
version "2.4.0" version "2.4.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"