diff --git a/apps/mobile/App.tsx b/apps/mobile/App.tsx
index f3c73f6..d600682 100644
--- a/apps/mobile/App.tsx
+++ b/apps/mobile/App.tsx
@@ -15,7 +15,7 @@ import {
} from '@status-im/components'
import { Stack, TamaguiProvider } from '@tamagui/core'
import { useFonts } from 'expo-font'
-import { SafeAreaView, TouchableOpacity } from 'react-native'
+import { SafeAreaView, ScrollView, TouchableOpacity } from 'react-native'
import tamaguiConfig from './tamagui.config'
@@ -37,51 +37,51 @@ export default function App() {
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')}
+
+
+
+
- Toogle theme
-
-
+
+ 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')}
+ >
+ Toogle theme
+
+
+
)
diff --git a/apps/vite/styles/app.css b/apps/vite/styles/app.css
index 49572f6..50e912b 100644
--- a/apps/vite/styles/app.css
+++ b/apps/vite/styles/app.css
@@ -16,8 +16,12 @@ body,
grid-template-rows: 56px 1fr 100px;
}
-#sidebar,
#main,
#main > div {
border: 1px solid rgba(0, 0, 0, 0.1);
}
+
+#sidebar {
+ overflow: auto;
+ height: 100vh;
+}
diff --git a/packages/components/package.json b/packages/components/package.json
index 3cade0b..b34be96 100644
--- a/packages/components/package.json
+++ b/packages/components/package.json
@@ -43,6 +43,7 @@
"@tamagui/vite-plugin": "1.0.15",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-native-svg": "^13.7.0",
"react-native-web": "^0.18.0",
"storybook": "^7.0.0-beta.21",
"storybook-addon-designs": "^7.0.0-beta.2",
diff --git a/packages/components/src/accordion/accordion.tsx b/packages/components/src/accordion/accordion.tsx
new file mode 100644
index 0000000..3848bbf
--- /dev/null
+++ b/packages/components/src/accordion/accordion.tsx
@@ -0,0 +1,111 @@
+import React from 'react'
+
+import { Stack } from '@tamagui/core'
+import { AnimatePresence } from 'tamagui'
+
+import { Chevron } from '../icon'
+import { Label, Paragraph } from '../typography'
+
+import type { GetProps } from '@tamagui/core'
+
+type BaseProps = GetProps
+
+type Props = {
+ children: React.ReactElement[] | React.ReactElement
+ isExpanded: boolean
+ onToggle?: () => void
+ title: string
+ numberOfNewMessages?: number
+ showNotifications?: boolean
+} & BaseProps
+
+const Accordion = ({
+ children,
+ isExpanded,
+ onToggle,
+ title,
+ numberOfNewMessages,
+ showNotifications,
+}: Props) => {
+ return (
+
+
+
+
+
+
+
+
+
+ {title}
+
+
+
+ {showNotifications && numberOfNewMessages && (
+
+
+
+
+
+ )}
+
+
+
+ {isExpanded && (
+ {children}
+ )}
+
+
+
+
+ )
+}
+
+export { Accordion }
diff --git a/packages/components/src/accordion/accordionItem.tsx b/packages/components/src/accordion/accordionItem.tsx
new file mode 100644
index 0000000..92defe6
--- /dev/null
+++ b/packages/components/src/accordion/accordionItem.tsx
@@ -0,0 +1,115 @@
+import { Stack } from '@tamagui/core'
+
+import { Muted } from '../icon'
+import { Label, Paragraph } from '../typography'
+
+import type { GetProps } from '@tamagui/core'
+
+type BaseProps = GetProps
+
+type Props = {
+ isSelected?: boolean
+ onToggle?: () => void
+ title: string
+ channelStatus?: 'muted' | 'normal' | 'withMessages' | 'withMentions'
+ icon?: React.ReactNode
+ numberOfMessages?: number
+} & BaseProps
+
+const textColor = {
+ muted: '$neutral-40',
+ normal: '$neutral-50',
+ withMessages: '$neutral-100',
+ withMentions: '$neutral-100',
+}
+
+const AccordionItem = ({
+ icon,
+ isSelected,
+ title,
+ channelStatus = 'normal',
+ numberOfMessages,
+ ...rest
+}: Props) => {
+ return (
+
+
+ {icon && <>{icon}>}
+
+ {title}
+
+
+ {channelStatus !== 'normal' && (
+
+ {channelStatus === 'withMentions' && (
+
+
+
+
+
+ )}
+ {channelStatus === 'withMessages' && (
+
+
+
+ )}
+ {channelStatus === 'muted' && }
+
+ )}
+
+ )
+}
+
+export { AccordionItem }
diff --git a/packages/components/src/animations.native.ts b/packages/components/src/animations.native.ts
new file mode 100644
index 0000000..c5ffb92
--- /dev/null
+++ b/packages/components/src/animations.native.ts
@@ -0,0 +1,18 @@
+import { createAnimations } from '@tamagui/animations-react-native'
+
+export const animations = createAnimations({
+ fast: {
+ damping: 20,
+ mass: 1.2,
+ stiffness: 250,
+ },
+ medium: {
+ damping: 10,
+ mass: 0.9,
+ stiffness: 100,
+ },
+ slow: {
+ damping: 20,
+ stiffness: 60,
+ },
+})
diff --git a/packages/components/src/animations.ts b/packages/components/src/animations.ts
index cb721cd..d489ff4 100644
--- a/packages/components/src/animations.ts
+++ b/packages/components/src/animations.ts
@@ -1,27 +1,6 @@
-import { createAnimations as createAnimationsCSS } from '@tamagui/animations-css'
-import { createAnimations } from '@tamagui/animations-react-native'
+import { createAnimations } from '@tamagui/animations-css'
export const animations = createAnimations({
- bouncy: {
- type: 'spring',
- damping: 10,
- mass: 0.9,
- stiffness: 100,
- },
- lazy: {
- type: 'spring',
- damping: 20,
- stiffness: 60,
- },
- quick: {
- type: 'spring',
- damping: 20,
- mass: 1.2,
- stiffness: 250,
- },
-})
-
-export const animationsCSS = createAnimationsCSS({
fast: 'ease-in 150ms',
medium: 'ease-in 300ms',
slow: 'ease-in 450ms',
diff --git a/packages/components/src/avatar/avatar.tsx b/packages/components/src/avatar/avatar.tsx
index 5420ee2..10c3c81 100644
--- a/packages/components/src/avatar/avatar.tsx
+++ b/packages/components/src/avatar/avatar.tsx
@@ -18,7 +18,9 @@ const Base = styled(Stack, {
display: 'inline-flex',
position: 'relative',
overflow: 'hidden',
- backgroundColor: 'rgb(255,255,255)',
+ backgroundColor: '$white-100',
+ justifyContent: 'center',
+ alignItems: 'center',
variants: {
size: {
@@ -55,6 +57,12 @@ const Base = styled(Stack, {
borderRadius: 16,
},
},
+ withOutline: {
+ true: {
+ borderWidth: 2,
+ borderColor: '$white-100',
+ },
+ },
} as const,
})
@@ -69,12 +77,13 @@ interface Props {
size: NonNullable
indicator?: 'online' | 'offline'
shape?: 'circle' | 'rounded'
+ withOutline?: boolean
}
type ImageLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error'
const Avatar = (props: Props) => {
- const { src, size, shape = 'circle' } = props
+ const { src, size, shape = 'circle', withOutline } = props
const [status, setStatus] = useState('idle')
@@ -83,7 +92,7 @@ const Avatar = (props: Props) => {
}, [JSON.stringify(src)])
return (
-
+
{
onLoad={() => setStatus('loaded')}
onError={() => setStatus('error')}
/>
-
- PP
-
+ {status === 'error' && (
+
+ PP
+
+ )}
)
}
diff --git a/packages/components/src/button/button.tsx b/packages/components/src/button/button.tsx
index 8bb88fc..23d7f0d 100644
--- a/packages/components/src/button/button.tsx
+++ b/packages/components/src/button/button.tsx
@@ -1,9 +1,8 @@
-import { styled, Text } from '@tamagui/core'
-import { ButtonFrame } from 'tamagui'
+import { Stack, styled, Text } from '@tamagui/core'
import type { GetProps } from '@tamagui/core'
-const Base = styled(ButtonFrame, {
+const Base = styled(Stack, {
// tag: 'button',
cursor: 'pointer',
@@ -31,24 +30,22 @@ const Base = styled(ButtonFrame, {
const ButtonText = styled(Text, {
fontFamily: '$inter',
textAlign: 'center',
- color: '$white',
+ color: '$white-100',
})
type BaseProps = GetProps
-interface Props {
+type Props = {
type?: BaseProps['type']
children: string
onPress?: () => void
-}
+} & Omit
const Button = (props: Props) => {
- const { type = 'primary', children, onPress } = props
- console.log(onPress)
+ const { type = 'primary', children, onPress, ...rest } = props
- console.log('Button', type)
return (
-
+
{children}
)
diff --git a/packages/components/src/emoji/EmojiProps.ts b/packages/components/src/emoji/EmojiProps.ts
new file mode 100644
index 0000000..79f18c2
--- /dev/null
+++ b/packages/components/src/emoji/EmojiProps.ts
@@ -0,0 +1,9 @@
+import type { SizeTokens, StyleObject } from '@tamagui/core'
+import type { SvgProps } from 'react-native-svg'
+
+export type EmojiProps = SvgProps & {
+ size?: number | SizeTokens
+ style?: StyleObject
+ sizeBackground?: number
+ hasBackground?: boolean
+}
diff --git a/packages/components/src/emoji/emojis/basketball.tsx b/packages/components/src/emoji/emojis/basketball.tsx
new file mode 100644
index 0000000..de031c9
--- /dev/null
+++ b/packages/components/src/emoji/emojis/basketball.tsx
@@ -0,0 +1,44 @@
+import { memo } from 'react'
+
+import { Defs, Image, Path, Pattern, Svg, Use } from 'react-native-svg'
+
+import { themed } from '../themed'
+
+import type { EmojiProps } from '../EmojiProps'
+
+const Emoji = (props: EmojiProps) => {
+ const { size = 16, ...otherProps } = props
+
+ return (
+
+ )
+}
+
+Emoji.displayName = 'Basketball'
+
+export const Basketball = memo(themed(Emoji))
diff --git a/packages/components/src/emoji/emojis/collaboration.tsx b/packages/components/src/emoji/emojis/collaboration.tsx
new file mode 100644
index 0000000..1eca8de
--- /dev/null
+++ b/packages/components/src/emoji/emojis/collaboration.tsx
@@ -0,0 +1,42 @@
+import { memo } from 'react'
+
+import { Path, Svg } from 'react-native-svg'
+
+import { themed } from '../themed'
+
+import type { EmojiProps } from '../EmojiProps'
+
+const Emoji = (props: EmojiProps) => {
+ const { size = 16, ...otherProps } = props
+
+ return (
+
+ )
+}
+
+Emoji.displayName = 'Collaboration'
+
+export const Collaboration = memo(themed(Emoji))
diff --git a/packages/components/src/emoji/emojis/fire.tsx b/packages/components/src/emoji/emojis/fire.tsx
new file mode 100644
index 0000000..a341ca8
--- /dev/null
+++ b/packages/components/src/emoji/emojis/fire.tsx
@@ -0,0 +1,43 @@
+import { memo } from 'react'
+
+import { Defs, Image, Path, Pattern, Svg, Use } from 'react-native-svg'
+
+import { themed } from '../themed'
+
+import type { EmojiProps } from '../EmojiProps'
+
+const Emoji = (props: EmojiProps) => {
+ const { size = 16, ...otherProps } = props
+
+ return (
+
+ )
+}
+
+Emoji.displayName = 'Fire'
+
+export const Fire = memo(themed(Emoji))
diff --git a/packages/components/src/emoji/emojis/peach.tsx b/packages/components/src/emoji/emojis/peach.tsx
new file mode 100644
index 0000000..fd009f7
--- /dev/null
+++ b/packages/components/src/emoji/emojis/peach.tsx
@@ -0,0 +1,57 @@
+import { memo } from 'react'
+
+import {
+ ClipPath,
+ Defs,
+ G,
+ Image,
+ Path,
+ Pattern,
+ Svg,
+ Use,
+} from 'react-native-svg'
+
+import { themed } from '../themed'
+
+import type { EmojiProps } from '../EmojiProps'
+
+const Emoji = (props: EmojiProps) => {
+ const { size = 16, ...otherProps } = props
+
+ return (
+
+ )
+}
+
+Emoji.displayName = 'Peach'
+
+export const Peach = memo(themed(Emoji))
diff --git a/packages/components/src/emoji/emojis/play.tsx b/packages/components/src/emoji/emojis/play.tsx
new file mode 100644
index 0000000..bbe7513
--- /dev/null
+++ b/packages/components/src/emoji/emojis/play.tsx
@@ -0,0 +1,46 @@
+import { memo } from 'react'
+
+import { Path, Svg } from 'react-native-svg'
+
+import { themed } from '../themed'
+
+import type { EmojiProps } from '../EmojiProps'
+
+const Emoji = (props: EmojiProps) => {
+ const { size = 16, ...otherProps } = props
+
+ return (
+
+ )
+}
+
+Emoji.displayName = 'Play'
+
+export const Play = memo(themed(Emoji))
diff --git a/packages/components/src/emoji/emojis/unicorn.tsx b/packages/components/src/emoji/emojis/unicorn.tsx
new file mode 100644
index 0000000..f96db2b
--- /dev/null
+++ b/packages/components/src/emoji/emojis/unicorn.tsx
@@ -0,0 +1,57 @@
+import { memo } from 'react'
+
+import {
+ ClipPath,
+ Defs,
+ G,
+ Image,
+ Path,
+ Pattern,
+ Svg,
+ Use,
+} from 'react-native-svg'
+
+import { themed } from '../themed'
+
+import type { EmojiProps } from '../EmojiProps'
+
+const Emoji = (props: EmojiProps) => {
+ const { size = 16, ...otherProps } = props
+
+ return (
+
+ )
+}
+
+Emoji.displayName = 'Unicorn'
+
+export const Unicorn = memo(themed(Emoji))
diff --git a/packages/components/src/emoji/index.tsx b/packages/components/src/emoji/index.tsx
new file mode 100644
index 0000000..75639ca
--- /dev/null
+++ b/packages/components/src/emoji/index.tsx
@@ -0,0 +1,6 @@
+export { Basketball } from './emojis/basketball'
+export { Collaboration } from './emojis/collaboration'
+export { Fire } from './emojis/fire'
+export { Peach } from './emojis/peach'
+export { Play } from './emojis/play'
+export { Unicorn } from './emojis/unicorn'
diff --git a/packages/components/src/emoji/themed.tsx b/packages/components/src/emoji/themed.tsx
new file mode 100644
index 0000000..bbd49ca
--- /dev/null
+++ b/packages/components/src/emoji/themed.tsx
@@ -0,0 +1,27 @@
+import { Stack } from '@tamagui/core'
+
+import type { EmojiProps } from './EmojiProps'
+import type React from 'react'
+
+export function themed(Component: React.ElementType) {
+ const useWrapped = (props: EmojiProps) => {
+ const { size, hasBackground, sizeBackground = 24, ...rest } = props
+
+ if (hasBackground) {
+ return (
+
+
+
+ )
+ }
+ return
+ }
+ return useWrapped
+}
diff --git a/packages/components/src/icon/IconProps.ts b/packages/components/src/icon/IconProps.ts
new file mode 100644
index 0000000..b7cc9c1
--- /dev/null
+++ b/packages/components/src/icon/IconProps.ts
@@ -0,0 +1,18 @@
+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/icons/chevron.tsx b/packages/components/src/icon/icons/chevron.tsx
new file mode 100644
index 0000000..da6b2e9
--- /dev/null
+++ b/packages/components/src/icon/icons/chevron.tsx
@@ -0,0 +1,27 @@
+import { memo } from 'react'
+
+import { Path, Svg } from 'react-native-svg'
+
+import { themed } from '../themed'
+
+import type { IconProps } from '../IconProps'
+
+const Icon = (props: IconProps) => {
+ const { color, size = 16, ...otherProps } = props
+
+ return (
+
+ )
+}
+
+Icon.displayName = 'Chevron'
+
+export const Chevron = memo(themed(Icon))
diff --git a/packages/components/src/icon/icons/group.tsx b/packages/components/src/icon/icons/group.tsx
new file mode 100644
index 0000000..87c59ed
--- /dev/null
+++ b/packages/components/src/icon/icons/group.tsx
@@ -0,0 +1,39 @@
+import { memo } from 'react'
+
+import { Path, Svg } from 'react-native-svg'
+
+import { themed } from '../themed'
+
+import type { IconProps } from '../IconProps'
+
+const Icon = (props: IconProps) => {
+ const { color, size = 16, ...otherProps } = props
+
+ return (
+
+ )
+}
+
+Icon.displayName = 'Group'
+
+export const Group = memo(themed(Icon))
diff --git a/packages/components/src/icon/icons/muted.tsx b/packages/components/src/icon/icons/muted.tsx
new file mode 100644
index 0000000..bb2763b
--- /dev/null
+++ b/packages/components/src/icon/icons/muted.tsx
@@ -0,0 +1,32 @@
+import { memo } from 'react'
+
+import { Path, Svg } from 'react-native-svg'
+
+import { themed } from '../themed'
+
+import type { IconProps } from '../IconProps'
+
+const Icon = (props: IconProps) => {
+ const { color, size = 16, ...otherProps } = props
+
+ return (
+
+ )
+}
+
+Icon.displayName = 'Muted'
+
+export const Muted = memo(themed(Icon))
diff --git a/packages/components/src/icon/index.tsx b/packages/components/src/icon/index.tsx
new file mode 100644
index 0000000..c83fd46
--- /dev/null
+++ b/packages/components/src/icon/index.tsx
@@ -0,0 +1,3 @@
+export { Chevron } from './icons/chevron'
+export { Group } from './icons/group'
+export { Muted } from './icons/muted'
diff --git a/packages/components/src/icon/themed.tsx b/packages/components/src/icon/themed.tsx
new file mode 100644
index 0000000..1d0e7fb
--- /dev/null
+++ b/packages/components/src/icon/themed.tsx
@@ -0,0 +1,15 @@
+import { useCurrentColor } from 'tamagui'
+
+import type { IconProps } from './IconProps'
+import type React from 'react'
+
+export function themed(Component: React.ElementType) {
+ const useWrapped = (props: IconProps) => {
+ const { size, color: colorToken = '$neutral-100', ...rest } = props
+
+ const color = useCurrentColor(colorToken)
+
+ return
+ }
+ return useWrapped
+}
diff --git a/packages/components/src/input/input.tsx b/packages/components/src/input/input.tsx
index 7e6be2e..266cbb1 100644
--- a/packages/components/src/input/input.tsx
+++ b/packages/components/src/input/input.tsx
@@ -1,4 +1,6 @@
-import { setupReactNative, Stack, styled } from '@tamagui/core'
+// eslint-disable-next-line eslint-comments/disable-enable-pair
+/* eslint-disable import/namespace */
+import { setupReactNative, styled } from '@tamagui/core'
// import { focusableInputHOC } from '@tamagui/focusable'
import { TextInput } from 'react-native'
@@ -43,7 +45,7 @@ export const InputFrame = styled(
// },/
// focusStyle: {
- // // borderColor: '$borderColorFocus',
+
// borderWidth: 2,
// marginHorizontal: -1,
// },
diff --git a/packages/components/src/sidebar/sidebar.tsx b/packages/components/src/sidebar/sidebar.tsx
index c34fd07..899ad79 100644
--- a/packages/components/src/sidebar/sidebar.tsx
+++ b/packages/components/src/sidebar/sidebar.tsx
@@ -1,7 +1,13 @@
+import { useState } from 'react'
+
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'
@@ -11,35 +17,259 @@ interface Props {
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[]
+)
+
const _Sidebar = (props: Props) => {
const { name, description, membersCount } = props
+ const [isExpanded, setIsExpanded] = useState({
+ ...COMMUNITIES_EXPAND_CONTROL,
+ welcome: true,
+ })
+
+ const [selectedChannel, setSelectedChannel] = useState('welcome')
+
+ const handleToggle = (id: string) => {
+ setIsExpanded(prev => ({
+ ...prev,
+ [id]: !prev[id as keyof typeof isExpanded],
+ }))
+ }
return (
-
+
-
-
+
+
+
+
+ {name}
+ {description}
+
+
+ {membersCount}
+
- {name}
- {description}
- {membersCount}
-
+ {COMMUNITIES.map(community => (
+ handleToggle(community.id)}
+ title={community.title}
+ numberOfNewMessages={community.numberOfNewMessages}
+ showNotifications={
+ !isExpanded[community.id as keyof typeof isExpanded]
+ }
+ >
+ {community.channels.map(channel => (
+ setSelectedChannel(channel.id)}
+ />
+ ))}
+
+ ))}
+
+ {/* */}
)
diff --git a/packages/components/src/tamagui.config.ts b/packages/components/src/tamagui.config.ts
index 7e083d6..345c6e1 100644
--- a/packages/components/src/tamagui.config.ts
+++ b/packages/components/src/tamagui.config.ts
@@ -3,7 +3,7 @@ import { createInterFont } from '@tamagui/font-inter'
import { createMedia } from '@tamagui/react-native-media-driver'
import { shorthands } from '@tamagui/shorthands'
-import { animations, animationsCSS } from './animations'
+import { animations } from './animations'
import { themes } from './themes'
import { tokens } from './tokens'
@@ -106,8 +106,5 @@ export const config = createTamagui({
pointerCoarse: { pointer: 'coarse' },
}),
shorthands,
- animations: {
- ...animations,
- ...animationsCSS,
- },
+ animations,
})
diff --git a/packages/components/src/themes.ts b/packages/components/src/themes.ts
index 4d895ca..1b7c31f 100644
--- a/packages/components/src/themes.ts
+++ b/packages/components/src/themes.ts
@@ -35,7 +35,10 @@ const light = createTheme({
beigeHover: tokens.color['beige-60'],
})
-const dark = createTheme({
+// note: we set up a single consistent base type to validate the rest:
+type BaseTheme = typeof light
+
+const dark: BaseTheme = createTheme({
background: tokens.color['neutral-95'],
textPrimary: tokens.color['white-100'],
primary: tokens.color['primary-60'],
@@ -68,7 +71,15 @@ const dark = createTheme({
beigeHover: tokens.color['beige-50'],
})
-export const themes = {
+const allThemes = {
light,
dark,
}
+
+type ThemeName = keyof typeof allThemes
+
+type Themes = {
+ [key in ThemeName]: BaseTheme
+}
+
+export const themes: Themes = allThemes
diff --git a/yarn.lock b/yarn.lock
index fc7a5a0..c214640 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8488,7 +8488,26 @@ css-select@^4.1.3, css-select@^4.2.0:
domutils "^2.8.0"
nth-check "^2.0.1"
-css-what@^6.0.1:
+css-select@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6"
+ integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==
+ dependencies:
+ boolbase "^1.0.0"
+ css-what "^6.1.0"
+ domhandler "^5.0.2"
+ domutils "^3.0.1"
+ nth-check "^2.0.1"
+
+css-tree@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
+ integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
+ dependencies:
+ mdn-data "2.0.14"
+ source-map "^0.6.1"
+
+css-what@^6.0.1, css-what@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
@@ -8880,12 +8899,21 @@ dom-serializer@^1.0.1:
domhandler "^4.2.0"
entities "^2.0.0"
+dom-serializer@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
+ integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
+ dependencies:
+ domelementtype "^2.3.0"
+ domhandler "^5.0.2"
+ entities "^4.2.0"
+
dom-walk@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84"
integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==
-domelementtype@^2.0.1, domelementtype@^2.2.0:
+domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
@@ -8897,6 +8925,13 @@ domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1:
dependencies:
domelementtype "^2.2.0"
+domhandler@^5.0.1, domhandler@^5.0.2:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
+ integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
+ dependencies:
+ domelementtype "^2.3.0"
+
domutils@^2.5.2, domutils@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
@@ -8906,6 +8941,15 @@ domutils@^2.5.2, domutils@^2.8.0:
domelementtype "^2.2.0"
domhandler "^4.2.0"
+domutils@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c"
+ integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==
+ dependencies:
+ dom-serializer "^2.0.0"
+ domelementtype "^2.3.0"
+ domhandler "^5.0.1"
+
dot-case@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
@@ -9001,6 +9045,11 @@ entities@^2.0.0:
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
+entities@^4.2.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174"
+ integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==
+
env-editor@^0.4.1:
version "0.4.2"
resolved "https://registry.yarnpkg.com/env-editor/-/env-editor-0.4.2.tgz#4e76568d0bd8f5c2b6d314a9412c8fe9aa3ae861"
@@ -13300,6 +13349,11 @@ mdast-util-to-string@^1.0.0:
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz#27055500103f51637bd07d01da01eb1967a43527"
integrity sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==
+mdn-data@2.0.14:
+ version "2.0.14"
+ resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
+ integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
+
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@@ -14079,7 +14133,6 @@ node-fetch-native@^1.0.1:
node-fetch@2.6.7, node-fetch@^2.2.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.x.x:
version "2.6.7"
- uid "1b5d62978f2ed07b99444f64f0df39f960a6d34d"
resolved "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz#1b5d62978f2ed07b99444f64f0df39f960a6d34d"
node-forge@^1.1.0, node-forge@^1.2.1, node-forge@^1.3.1:
@@ -15374,6 +15427,14 @@ 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-svg@^13.7.0:
+ version "13.7.0"
+ resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-13.7.0.tgz#be2ffb935e996762543dd7376bdc910722f7a43c"
+ integrity sha512-WR5CIURvee5cAfvMhmdoeOjh1SC8KdLq5u5eFsz4pbYzCtIFClGSkLnNgkMSDMVV5LV0qQa4jeIk75ieIBzaDA==
+ dependencies:
+ css-select "^5.1.0"
+ css-tree "^1.1.3"
+
react-native-web-internals@^1.0.15:
version "1.0.15"
resolved "https://registry.yarnpkg.com/react-native-web-internals/-/react-native-web-internals-1.0.15.tgz#8c4367e2461edf5bab4abab71471b351a08cb19f"