diff --git a/apps/mobile/App.tsx b/apps/mobile/App.tsx index e7ab58a6..e4242bc2 100644 --- a/apps/mobile/App.tsx +++ b/apps/mobile/App.tsx @@ -2,27 +2,26 @@ /* eslint-disable import/namespace */ import 'expo-dev-client' -import { useState } from 'react' +import { useMemo, useState } from 'react' -import { - Code, - Heading, - Label, - Messages, - Paragraph, - Shape, - Sidebar, -} from '@status-im/components' -import { Stack, TamaguiProvider } from '@tamagui/core' +import { createNativeStackNavigator } from '@react-navigation/native-stack' +import { Heading } from '@status-im/components' +import { Avatar } from '@status-im/components/src/avatar' +import { Stack as View, TamaguiProvider } from '@tamagui/core' 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' -type ThemeVars = 'light' | 'dark' +const Stack = createNativeStackNavigator() export default function App() { - const [theme, setTheme] = useState('light') + const [position, setPosition] = useState(0) + const [loaded] = useFonts({ Inter: require('@tamagui/font-inter/otf/Inter-Medium.otf'), InterBold: require('@tamagui/font-inter/otf/Inter-Bold.otf'), @@ -30,56 +29,95 @@ export default function App() { 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) { return null } return ( - - - - - - - Communities - - - This is an Heading 2 - - - Paragraph uppercased and bolded - - - This is a paragraph - - - This is a code line - 0x213abc190 ... 121ah4a9e - - - Theme selected - {theme} - setTheme(theme === 'dark' ? 'light' : 'dark')} + + + + + ( + + + {showMinimizedHeader && ( + + Rarible + + + )} + + + ), + }} > - Toogle theme - - - - - - + {props => ( + + )} + + + + + ) } diff --git a/apps/mobile/navigation/provider.tsx b/apps/mobile/navigation/provider.tsx new file mode 100644 index 00000000..65c074eb --- /dev/null +++ b/apps/mobile/navigation/provider.tsx @@ -0,0 +1,9 @@ +import { NavigationContainer } from '@react-navigation/native' + +export function NavigationProvider({ + children, +}: { + children: React.ReactNode +}) { + return {children} +} diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 4c9c086c..8fccfefa 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -10,6 +10,8 @@ }, "dependencies": { "@babel/runtime": "^7.18.9", + "@react-navigation/native": "^6.1.2", + "@react-navigation/native-stack": "^6.9.8", "@status-im/components": "*", "expo": "^47.0.12", "expo-constants": "^14.0.2", @@ -21,6 +23,8 @@ "react": "18.1.0", "react-dom": "^18.1.0", "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" }, "devDependencies": { diff --git a/apps/mobile/screens/channel.tsx b/apps/mobile/screens/channel.tsx new file mode 100644 index 00000000..a0694f9a --- /dev/null +++ b/apps/mobile/screens/channel.tsx @@ -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 ( + + + + + + + + + + + ) +} diff --git a/apps/mobile/screens/home.tsx b/apps/mobile/screens/home.tsx new file mode 100644 index 00000000..bd9a6d57 --- /dev/null +++ b/apps/mobile/screens/home.tsx @@ -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('welcome') + + const onChannelPress = (id: string) => { + setSelectedChannel(id) + navigation.navigate('Channel') + } + + return ( + + + + + + + + + ) +} diff --git a/apps/vite/src/app.tsx b/apps/vite/src/app.tsx index 7257d424..5fca5d89 100644 --- a/apps/vite/src/app.tsx +++ b/apps/vite/src/app.tsx @@ -3,6 +3,7 @@ import { useState } from 'react' import { Button, Code, + Composer, Heading, Label, Messages, @@ -10,17 +11,41 @@ import { Shape, Sidebar, } 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 { Topbar } from './components/topbar' type ThemeVars = 'light' | 'dark' +const AnimatableDrawer = styled(Stack, { + variants: { + fromRight: { + true: { + x: 500, + width: 0, + }, + }, + fromLeft: { + true: { + x: 500, + width: 250, + }, + }, + }, +}) + function App() { const [theme, setTheme] = useState('light') const [showMembers, setShowMembers] = useState(false) + const [selectedChannel, setSelectedChannel] = useState('welcome') + + const onChannelPress = (id: string) => { + setSelectedChannel(id) + } + return (
@@ -29,9 +54,10 @@ function App() { name="Rarible" description="Multichain community-centric NFT marketplace. Create, buy and sell your NFTs." membersCount={123} + onChannelPress={onChannelPress} + selectedChannel={selectedChannel} />
-
- - Composer - +
- {showMembers &&
members
} + + {showMembers && ( + + members + + )} +
) diff --git a/apps/vite/src/main.tsx b/apps/vite/src/main.tsx index 71576026..318f382c 100644 --- a/apps/vite/src/main.tsx +++ b/apps/vite/src/main.tsx @@ -1,5 +1,8 @@ import '../styles/reset.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' diff --git a/apps/vite/styles/app.css b/apps/vite/styles/app.css index afc3facd..a2a5e941 100644 --- a/apps/vite/styles/app.css +++ b/apps/vite/styles/app.css @@ -15,13 +15,9 @@ body, display: grid; grid-template-rows: 56px 1fr 100px; height: 100vh; -} - -#main, -#sidebar, -#members, -#main > div { + overflow: hidden; border: 1px solid rgba(0, 0, 0, 0.1); + border-width: 0 1px; } #sidebar { diff --git a/packages/components/src/accordion/accordion.tsx b/packages/components/src/accordion/accordion.tsx index 3848bbf2..e8a73067 100644 --- a/packages/components/src/accordion/accordion.tsx +++ b/packages/components/src/accordion/accordion.tsx @@ -1,9 +1,9 @@ import React from 'react' +import { ChevronIcon } from '@status-im/icons' import { Stack } from '@tamagui/core' import { AnimatePresence } from 'tamagui' -import { Chevron } from '../icon' import { Label, Paragraph } from '../typography' import type { GetProps } from '@tamagui/core' @@ -48,9 +48,17 @@ const Accordion = ({ - + )} - {channelStatus === 'muted' && } + {channelStatus === 'muted' && ( + + )} )} diff --git a/packages/components/src/avatar/avatar.tsx b/packages/components/src/avatar/avatar.tsx index 0e831353..b1f0600a 100644 --- a/packages/components/src/avatar/avatar.tsx +++ b/packages/components/src/avatar/avatar.tsx @@ -24,6 +24,11 @@ const Base = styled(Stack, { variants: { size: { + 80: { + width: 80, + height: 80, + borderRadius: 80 / 2, + }, 56: { width: 56, height: 56, @@ -80,10 +85,15 @@ const Indicator = styled(Stack, { variants: { size: { + 80: { + width: 10, + height: 10, + borderRadius: '50%', + }, 56: { width: 10, height: 10, - borderRadius: 10 / 2, + borderRadius: '50%', }, // FIXME: use catch all variant 52: { diff --git a/packages/components/src/chat-message/chat-message.tsx b/packages/components/src/chat-message/chat-message.tsx index 2d18a763..044d602a 100644 --- a/packages/components/src/chat-message/chat-message.tsx +++ b/packages/components/src/chat-message/chat-message.tsx @@ -24,6 +24,7 @@ const ChatMessage = (props: Props) => { space={10} position="relative" alignItems="flex-start" + justifyContent="center" paddingHorizontal={8} paddingVertical={12} borderRadius={16} @@ -50,7 +51,7 @@ const ChatMessage = (props: Props) => { Alisher Yakupov - + zQ3...9d4Gs0 diff --git a/packages/components/src/chat-message/components/actions.tsx b/packages/components/src/chat-message/components/actions.tsx index bc3e1d2d..73b44291 100644 --- a/packages/components/src/chat-message/components/actions.tsx +++ b/packages/components/src/chat-message/components/actions.tsx @@ -3,7 +3,7 @@ import { Stack } from 'tamagui' import { Paragraph } from '../../typography' interface Props { - onClick: VoidFunction + onClick?: VoidFunction } export const Actions = (_props: Props) => { diff --git a/packages/components/src/chat-message/index.tsx b/packages/components/src/chat-message/index.tsx index 1eff084f..50ad8290 100644 --- a/packages/components/src/chat-message/index.tsx +++ b/packages/components/src/chat-message/index.tsx @@ -1,10 +1,16 @@ +import { Stack } from '@tamagui/core' + import { ChatMessage } from './chat-message' +import type { GetProps } from '@tamagui/core' + export * from './chat-message' -export const Messages = () => { +type BaseProps = GetProps + +export const Messages = (props: BaseProps) => { return ( - <> + @@ -21,6 +27,6 @@ export const Messages = () => { - + ) } diff --git a/packages/components/src/composer/composer.tsx b/packages/components/src/composer/composer.tsx new file mode 100644 index 00000000..45cb8b8b --- /dev/null +++ b/packages/components/src/composer/composer.tsx @@ -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 + +const Composer = (props: BaseProps) => { + return ( + + + + + + + } /> + } /> + } /> + + } /> + + + ) +} + +export { Composer } diff --git a/packages/components/src/composer/index.tsx b/packages/components/src/composer/index.tsx new file mode 100644 index 00000000..c99ba66e --- /dev/null +++ b/packages/components/src/composer/index.tsx @@ -0,0 +1 @@ +export { Composer } from './composer' diff --git a/packages/components/src/icon-button/icon-button.tsx b/packages/components/src/icon-button/icon-button.tsx index 82e8531a..59410aad 100644 --- a/packages/components/src/icon-button/icon-button.tsx +++ b/packages/components/src/icon-button/icon-button.tsx @@ -13,9 +13,10 @@ const Base = styled(Stack, { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', + animation: 'fast', - width: 31, - height: 31, + width: 30, + height: 30, borderWidth: 1, backgroundColor: '$neutral-10', borderColor: '$neutral-10', @@ -24,7 +25,27 @@ const Base = styled(Stack, { backgroundColor: '$neutral-20', }, + pressStyle: { + backgroundColor: '$neutral-20', + }, + variants: { + noBackground: { + true: { + backgroundColor: 'transparent', + borderColor: '$neutral-20', + + hoverStyle: { + backgroundColor: 'transparent', + borderColor: '$neutral-30', + }, + + pressStyle: { + backgroundColor: 'transparent', + borderColor: '$neutral-30', + }, + }, + }, selected: { true: { backgroundColor: '$neutral-30', @@ -56,14 +77,17 @@ interface Props { icon: React.ReactElement onPress?: () => void selected?: boolean + noBackground?: boolean } const IconButton = (props: Props) => { - const { icon, selected, onPress } = props + const { icon, noBackground, selected, onPress } = props return ( - - {icon} + + + {icon} + ) } diff --git a/packages/components/src/icon/IconProps.ts b/packages/components/src/icon/IconProps.ts deleted file mode 100644 index b7cc9c19..00000000 --- a/packages/components/src/icon/IconProps.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { - SizeTokens, - StyleObject, - ThemeParsed, - Tokens, -} from '@tamagui/core' -import type { SvgProps } from 'react-native-svg' - -type GetTokenString = A extends string ? `$${A}` : `$${string}` -export type ColorTokens = - | GetTokenString - | GetTokenString - -export type IconProps = SvgProps & { - size?: number | SizeTokens - color?: ColorTokens - style?: StyleObject -} diff --git a/packages/components/src/icon/index.tsx b/packages/components/src/icon/index.tsx deleted file mode 100644 index c83fd463..00000000 --- a/packages/components/src/icon/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export { Chevron } from './icons/chevron' -export { Group } from './icons/group' -export { Muted } from './icons/muted' diff --git a/packages/components/src/icons/icons.stories.tsx b/packages/components/src/icons/icons.stories.tsx index f864d1d5..d2c18596 100644 --- a/packages/components/src/icons/icons.stories.tsx +++ b/packages/components/src/icons/icons.stories.tsx @@ -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 { Text } from '../typography' +import { Paragraph } from '../typography' import type { IconProps } from '@status-im/icons' import type { Meta, StoryObj } from '@storybook/react' @@ -35,8 +37,8 @@ export const All: Story = { key={name} style={{ display: 'flex', flexDirection: 'column' }} > - - {unpascal(name)} + + {unpascal(name)} ) })} diff --git a/packages/components/src/index.tsx b/packages/components/src/index.tsx index d76bae03..aec9c26d 100644 --- a/packages/components/src/index.tsx +++ b/packages/components/src/index.tsx @@ -1,5 +1,6 @@ export * from './button' export * from './chat-message' +export * from './composer' export * from './divider' export * from './icon-button' export * from './image' diff --git a/packages/components/src/sidebar/mock-data.tsx b/packages/components/src/sidebar/mock-data.tsx new file mode 100644 index 00000000..24f3e46a --- /dev/null +++ b/packages/components/src/sidebar/mock-data.tsx @@ -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: , + }, + { + id: 'general-welcome', + title: '# general', + icon: , + }, + { + id: 'random', + title: '# random', + icon: , + }, + { + id: 'onboarding', + title: '# onboarding', + icon: , + channelStatus: 'withMentions', + numberOfMessages: 3, + }, + ], + }, + { + id: 'community', + title: 'Community', + numberOfNewMessages: 5, + channels: [ + { + id: 'announcements', + title: '# announcements', + icon: , + }, + { + id: 'jobs', + title: '# jobs', + channelStatus: 'withMentions', + numberOfMessages: 3, + icon: , + }, + { + id: 'events', + title: '# events', + channelStatus: 'withMentions', + numberOfMessages: 2, + icon: , + }, + { + id: 'meetups', + title: '# meetups', + icon: , + }, + ], + }, + { + id: 'design', + title: 'Design', + channels: [ + { + id: 'design', + title: '# design', + icon: , + }, + { + id: 'ux', + title: '# ux', + icon: , + }, + { + id: 'ui', + title: '# ui', + icon: , + }, + { + id: 'figma', + title: '# figma', + icon: , + }, + ], + }, + { + id: 'General', + title: 'General', + channels: [ + { + id: 'general', + title: '# general', + icon: , + }, + { + id: 'people-ops', + title: '# people-ops', + icon: , + }, + ], + }, + { + id: 'Frontend', + title: 'Frontend', + channels: [ + { + id: 'react', + title: '# react', + icon: , + channelStatus: 'withMessages', + }, + { + id: 'vue', + title: '# vue', + icon: , + }, + { + id: 'angular', + title: '# angular', + channelStatus: 'muted', + icon: , + }, + { + id: 'svelte', + title: '# svelte', + icon: , + }, + ], + }, + { + id: 'Backend', + title: 'Backend', + channels: [ + { + id: 'node', + title: '# node', + icon: , + }, + { + id: 'python', + title: '# python', + icon: , + }, + { + id: 'ruby', + title: '# ruby', + icon: , + }, + { + id: 'php', + title: '# php', + channelStatus: 'muted', + icon: , + }, + ], + }, +] diff --git a/packages/components/src/sidebar/sidebar.tsx b/packages/components/src/sidebar/sidebar.tsx index 1a3005d4..2bb83a52 100644 --- a/packages/components/src/sidebar/sidebar.tsx +++ b/packages/components/src/sidebar/sidebar.tsx @@ -1,212 +1,52 @@ import { useState } from 'react' +import { GroupIcon } from '@status-im/icons' import { Stack } from '@tamagui/core' import { Accordion } from '../accordion/accordion' import { AccordionItem } from '../accordion/accordionItem' import { Avatar } from '../avatar' 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 { 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 + +type Props = { name: string description: string membersCount: number -} - -interface Channels { - id: string - 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: , - }, - { - id: 'general-welcome', - title: '# general', - icon: , - }, - { - id: 'random', - title: '# random', - icon: , - }, - { - id: 'onboarding', - title: '# onboarding', - icon: , - channelStatus: 'withMentions', - numberOfMessages: 3, - }, - ], - }, - { - id: 'community', - title: 'Community', - numberOfNewMessages: 5, - channels: [ - { - id: 'announcements', - title: '# announcements', - icon: , - }, - { - id: 'jobs', - title: '# jobs', - channelStatus: 'withMentions', - numberOfMessages: 3, - icon: , - }, - { - id: 'events', - title: '# events', - channelStatus: 'withMentions', - numberOfMessages: 2, - icon: , - }, - { - id: 'meetups', - title: '# meetups', - icon: , - }, - ], - }, - { - id: 'Design', - title: 'Design', - channels: [ - { - id: 'design', - title: '# design', - icon: , - }, - { - id: 'ux', - title: '# ux', - icon: , - }, - { - id: 'ui', - title: '# ui', - icon: , - }, - { - id: 'figma', - title: '# figma', - icon: , - }, - ], - }, - { - id: 'General', - title: 'General', - channels: [ - { - id: 'general', - title: '# general', - icon: , - }, - { - id: 'people-ops', - title: '# people-ops', - icon: , - }, - ], - }, - { - id: 'Frontend', - title: 'Frontend', - channels: [ - { - id: 'react', - title: '# react', - icon: , - channelStatus: 'withMessages', - }, - { - id: 'vue', - title: '# vue', - icon: , - }, - { - id: 'angular', - title: '# angular', - channelStatus: 'muted', - icon: , - }, - { - id: 'svelte', - title: '# svelte', - icon: , - }, - ], - }, - { - id: 'Backend', - title: 'Backend', - channels: [ - { - id: 'node', - title: '# node', - icon: , - }, - { - id: 'python', - title: '# python', - icon: , - }, - { - id: 'ruby', - title: '# ruby', - icon: , - }, - { - id: 'php', - title: '# php', - channelStatus: 'muted', - icon: , - }, - ], - }, -] - -const COMMUNITIES_EXPAND_CONTROL = COMMUNITIES.reduce( - (o, key) => ({ ...o, [key.id]: false }), - - {} as Record[] -) + selectedChannel?: string + communities?: CommunityProps[] + onChannelPress: (channelId: string) => void +} & BaseProps const Sidebar = (props: Props) => { - const { name, description, membersCount } = props - const [isExpanded, setIsExpanded] = useState({ - ...COMMUNITIES_EXPAND_CONTROL, - welcome: true, - }) + const { + name, + description, + membersCount, + communities = COMMUNITIES, + selectedChannel, + onChannelPress, + } = props - const [selectedChannel, setSelectedChannel] = useState('welcome') + const communitiesExpandControl = communities.reduce( + (o, key) => ({ ...o, [key.id]: false }), + + {} as Record[] + ) + + const [isExpanded, setIsExpanded] = useState({ + ...communitiesExpandControl, + welcome: true, + community: true, + design: true, + }) const handleToggle = (id: string) => { setIsExpanded(prev => ({ @@ -231,23 +71,23 @@ const Sidebar = (props: Props) => { zIndex={10} > - + {name} {description} - + {membersCount} - {COMMUNITIES.map(community => ( + {communities.map(community => ( { !isExpanded[community.id as keyof typeof isExpanded] } > - {community.channels.map(channel => ( - setSelectedChannel(channel.id)} - /> - ))} + {community.channels.map((channel, index) => { + const isLastChannelOfTheList = + index === community.channels.length - 1 + return ( + onChannelPress(channel.id)} + mb={isLastChannelOfTheList ? 8 : 0} + /> + ) + })} ))} diff --git a/packages/icons/src/audio-icon.tsx b/packages/icons/src/audio-icon.tsx new file mode 100644 index 00000000..166d5416 --- /dev/null +++ b/packages/icons/src/audio-icon.tsx @@ -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 ( + + + + ) +} + +export const AudioIcon = memo(themed(Icon)) diff --git a/packages/components/src/icon/icons/chevron.tsx b/packages/icons/src/chevron-icon.tsx similarity index 64% rename from packages/components/src/icon/icons/chevron.tsx rename to packages/icons/src/chevron-icon.tsx index da6b2e9a..9945d372 100644 --- a/packages/components/src/icon/icons/chevron.tsx +++ b/packages/icons/src/chevron-icon.tsx @@ -1,12 +1,11 @@ import { memo } from 'react' +import { themed } from '@status-im/icons/src/themed' import { Path, Svg } from 'react-native-svg' -import { themed } from '../themed' +import type { IconProps } from './types' -import type { IconProps } from '../IconProps' - -const Icon = (props: IconProps) => { +function Icon(props: IconProps) { const { color, size = 16, ...otherProps } = props return ( @@ -22,6 +21,4 @@ const Icon = (props: IconProps) => { ) } -Icon.displayName = 'Chevron' - -export const Chevron = memo(themed(Icon)) +export const ChevronIcon = memo(themed(Icon)) diff --git a/packages/icons/src/format-icon.tsx b/packages/icons/src/format-icon.tsx new file mode 100644 index 00000000..206db0b1 --- /dev/null +++ b/packages/icons/src/format-icon.tsx @@ -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 ( + + + + + + + + + + + ) +} + +export const FormatIcon = memo(themed(Icon)) diff --git a/packages/components/src/icon/icons/group.tsx b/packages/icons/src/group-icon.tsx similarity index 78% rename from packages/components/src/icon/icons/group.tsx rename to packages/icons/src/group-icon.tsx index 87c59ed4..8592a425 100644 --- a/packages/components/src/icon/icons/group.tsx +++ b/packages/icons/src/group-icon.tsx @@ -1,12 +1,11 @@ import { memo } from 'react' +import { themed } from '@status-im/icons/src/themed' import { Path, Svg } from 'react-native-svg' -import { themed } from '../themed' +import type { IconProps } from './types' -import type { IconProps } from '../IconProps' - -const Icon = (props: IconProps) => { +function Icon(props: IconProps) { const { color, size = 16, ...otherProps } = props return ( @@ -24,16 +23,14 @@ const Icon = (props: IconProps) => { fillRule="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" - fill={`${color}`} + fill={color} /> ) } -Icon.displayName = 'Group' - -export const Group = memo(themed(Icon)) +export const GroupIcon = memo(themed(Icon)) diff --git a/packages/icons/src/image-icon.tsx b/packages/icons/src/image-icon.tsx new file mode 100644 index 00000000..7c0cf2f3 --- /dev/null +++ b/packages/icons/src/image-icon.tsx @@ -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 ( + + + + ) +} + +export const ImageIcon = memo(themed(Icon)) diff --git a/packages/icons/src/index.tsx b/packages/icons/src/index.tsx index 6bed9823..dde15530 100644 --- a/packages/icons/src/index.tsx +++ b/packages/icons/src/index.tsx @@ -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 { MembersIcon } from './members-icon' +export { MutedIcon } from './muted-icon' export { OptionsIcon } from './options-icon' +export { ReactionIcon } from './reaction-icon' export type { IconProps } from './types' diff --git a/packages/icons/src/lock-icon.tsx b/packages/icons/src/lock-icon.tsx index bae74102..f5fc242d 100644 --- a/packages/icons/src/lock-icon.tsx +++ b/packages/icons/src/lock-icon.tsx @@ -1,24 +1,25 @@ +import { memo } from 'react' + +import { Path, Svg } from 'react-native-svg' + +import { themed } from './themed' + import type { IconProps } from './types' -export function LockedIcon(props: IconProps) { +function Icon(props: IconProps) { const { color = 'currentColor', size = 20, ...rest } = props // FIXME: not need to differentiate sizes in the designs return ( - - + - + ) } + +export const LockedIcon = memo(themed(Icon)) diff --git a/packages/icons/src/members-icon.tsx b/packages/icons/src/members-icon.tsx index 83f3a9f5..0042f5e9 100644 --- a/packages/icons/src/members-icon.tsx +++ b/packages/icons/src/members-icon.tsx @@ -1,29 +1,30 @@ +import { memo } from 'react' + +import { Path, Svg } from 'react-native-svg' + +import { themed } from './themed' + import type { IconProps } from './types' -export function MembersIcon(props: IconProps) { +function Icon(props: IconProps) { const { color = 'currentColor', size = 20, ...rest } = props return ( - - + - - + ) } + +export const MembersIcon = memo(themed(Icon)) diff --git a/packages/components/src/icon/icons/muted.tsx b/packages/icons/src/muted-icon.tsx similarity index 83% rename from packages/components/src/icon/icons/muted.tsx rename to packages/icons/src/muted-icon.tsx index bb2763bd..2158ffc3 100644 --- a/packages/components/src/icon/icons/muted.tsx +++ b/packages/icons/src/muted-icon.tsx @@ -1,12 +1,11 @@ import { memo } from 'react' +import { themed } from '@status-im/icons/src/themed' import { Path, Svg } from 'react-native-svg' -import { themed } from '../themed' +import type { IconProps } from './types' -import type { IconProps } from '../IconProps' - -const Icon = (props: IconProps) => { +function Icon(props: IconProps) { const { color, size = 16, ...otherProps } = props return ( @@ -27,6 +26,4 @@ const Icon = (props: IconProps) => { ) } -Icon.displayName = 'Muted' - -export const Muted = memo(themed(Icon)) +export const MutedIcon = memo(themed(Icon)) diff --git a/packages/icons/src/options-icon.tsx b/packages/icons/src/options-icon.tsx index 99a030c2..7e9f06d9 100644 --- a/packages/icons/src/options-icon.tsx +++ b/packages/icons/src/options-icon.tsx @@ -1,20 +1,21 @@ +import { memo } from 'react' + +import { Circle, Svg } from 'react-native-svg' + +import { themed } from './themed' + import type { IconProps } from './types' -export function OptionsIcon(props: IconProps) { +function Icon(props: IconProps) { const { color = 'currentColor', size = 20, ...rest } = props return ( - - - - - + + + + + ) } + +export const OptionsIcon = memo(themed(Icon)) diff --git a/packages/icons/src/reaction-icon.tsx b/packages/icons/src/reaction-icon.tsx new file mode 100644 index 00000000..9f972b7d --- /dev/null +++ b/packages/icons/src/reaction-icon.tsx @@ -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 ( + + + + + + + ) +} + +export const ReactionIcon = memo(themed(Icon)) diff --git a/packages/components/src/icon/themed.tsx b/packages/icons/src/themed.tsx similarity index 89% rename from packages/components/src/icon/themed.tsx rename to packages/icons/src/themed.tsx index 1d0e7fb2..b1a1e9c0 100644 --- a/packages/components/src/icon/themed.tsx +++ b/packages/icons/src/themed.tsx @@ -1,6 +1,6 @@ import { useCurrentColor } from 'tamagui' -import type { IconProps } from './IconProps' +import type { IconProps } from './types' import type React from 'react' export function themed(Component: React.ElementType) { diff --git a/packages/icons/src/types.ts b/packages/icons/src/types.ts index bff24855..b7cc9c19 100644 --- a/packages/icons/src/types.ts +++ b/packages/icons/src/types.ts @@ -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 { - children?: never - width?: never - height?: never - color?: string - size?: number +type GetTokenString = A extends string ? `$${A}` : `$${string}` +export type ColorTokens = + | GetTokenString + | GetTokenString + +export type IconProps = SvgProps & { + size?: number | SizeTokens + color?: ColorTokens + style?: StyleObject } diff --git a/yarn.lock b/yarn.lock index c2146403..9619d494 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4421,6 +4421,48 @@ resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa" 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": version "4.2.1" 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" 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" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== @@ -10734,6 +10776,11 @@ fill-range@^7.0.1: dependencies: 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: version "1.1.2" 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" 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" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== @@ -15281,6 +15328,16 @@ qs@6.11.0, qs@^6.10.0, qs@^6.4.0: dependencies: 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: version "2.2.0" 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" 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: version "6.0.1" 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" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-is@^16.13.1: +react-is@^16.13.0, react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" 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" 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: version "13.7.0" 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" 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: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -16658,6 +16738,11 @@ stream-transform@^2.1.3: dependencies: 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: version "0.3.1" 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" 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: version "1.0.5" 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: 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: version "2.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"