Skip to content

Commit e1cf75f

Browse files
Merge upstream develop
2 parents f2cc434 + 74843e2 commit e1cf75f

34 files changed

Lines changed: 242 additions & 265 deletions

README.md

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,39 @@
1515

1616
> :warning: **We're working on this.**
1717
18-
You will need [just](https://github.com/casey/just), Docker, and pnpm.
18+
You will need:
1919

20-
1. **Build rs-core for all platforms:** `just packages/rs-core/build-all`
21-
2. **Install dependencies:** `pnpm install`
22-
3. **Run the app:** `pnpm:run web`, `pnpm run:ios`, or `pnpm run:android`
20+
- [Node.js](https://nodejs.org), version pinned in `.nvmrc`
21+
- [pnpm](https://pnpm.io)
22+
- [Rust toolchain](https://rustup.rs)
23+
- [`protoc`](https://github.com/protocolbuffers/protobuf)
24+
- [`docker compose`](https://github.com/docker/compose)
2325

24-
## Development
26+
The following commands will get you up and running:
27+
```sh
28+
# Use node version manager to install the pinned version of node
29+
nvm install
2530

26-
- `pnpm dev` builds all SDKs in watch mode.
31+
# Add the WASM target to the rust toolchain
32+
rustup target add wasm32-unknown-unknown
33+
34+
# Build the frontend and core binaries
35+
pnpm install
36+
pnpm build
37+
38+
# Start the server process
39+
docker compose up -d --build
40+
41+
# Apply the database schema if it has changed
42+
docker compose run --rm server /app/migration fresh
43+
44+
# Start the frontend dev server
45+
pnpm dev
46+
```
47+
48+
If you're using Podman, ensure `docker compose` resolves to Compose v2.
49+
50+
To run the server from source instead, see [`services/server/README.md`](services/server/README.md).
2751

2852
## Project Structure
2953

@@ -34,10 +58,11 @@ You will need [just](https://github.com/casey/just), Docker, and pnpm.
3458
| `packages/js-core` | Core JavaScript library containing the main Polycentric protocol logic |
3559
| `packages/js-browser` | Browser SDK using SQLite WASM for local storage |
3660
| `packages/js-node` | Node.js SDK using sqlite3 for local storage |
61+
| `packages/js-storage-sqlite` | Shared SQLite (Drizzle ORM) storage layer for the JS SDKs |
3762
| `packages/react-native` | React Native SDK for mobile applications |
63+
| `packages/rs-common` | Shared Rust code used by rs-core |
3864
| `packages/rs-core` | Rust core library - the underlying protocol implementation |
39-
| `packages/rs-core-wasm-browser` | Rust core compiled to WebAssembly for browser environments |
40-
| `packages/rs-core-wasm-node` | Rust core compiled to WebAssembly for Node.js environments |
65+
| `packages/rs-core-uniffi-web` | rs-core on WASM with `uniffi-bindgen-react-native` bindings |
4166

4267
### Apps
4368

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { PaletteColorToken, useTheme } from '@/src/common/theme';
2+
import {
3+
Ionicons,
4+
MaterialCommunityIcons,
5+
MaterialIcons,
6+
} from '@expo/vector-icons';
7+
import { ComponentProps, ComponentType, ReactNode } from 'react';
8+
9+
function defineIcon<G extends string>(
10+
IconSet: ComponentType<any> & { glyphMap: Record<G, number | string> },
11+
name: NoInfer<G>,
12+
) {
13+
return {
14+
iconSet: IconSet,
15+
name,
16+
render: (p: object) => <IconSet name={name} {...p} />,
17+
};
18+
}
19+
20+
/**
21+
* Map of icon names to their icon set definitions
22+
*/
23+
export const IconsMap = {
24+
add: defineIcon(Ionicons, 'add-circle'),
25+
addOutline: defineIcon(Ionicons, 'add-circle-outline'),
26+
arrowBack: defineIcon(Ionicons, 'arrow-back'),
27+
ban: defineIcon(Ionicons, 'ban'),
28+
camera: defineIcon(Ionicons, 'camera-outline'),
29+
checkmark: defineIcon(Ionicons, 'checkmark'),
30+
checkmarkCircle: defineIcon(Ionicons, 'checkmark-circle'),
31+
checkmarkSharp: defineIcon(Ionicons, 'checkmark-sharp'),
32+
chevronBack: defineIcon(Ionicons, 'chevron-back'),
33+
chevronDown: defineIcon(Ionicons, 'chevron-down'),
34+
chevronForward: defineIcon(Ionicons, 'chevron-forward'),
35+
close: defineIcon(Ionicons, 'close'),
36+
closeSharp: defineIcon(Ionicons, 'close-sharp'),
37+
copy: defineIcon(Ionicons, 'copy-outline'),
38+
dotsVertical: defineIcon(MaterialCommunityIcons, 'dots-vertical'),
39+
emoji: defineIcon(MaterialIcons, 'emoji-emotions'),
40+
flag: defineIcon(Ionicons, 'flag-outline'),
41+
home: defineIcon(Ionicons, 'home-outline'),
42+
image: defineIcon(Ionicons, 'image-outline'),
43+
images: defineIcon(Ionicons, 'images-outline'),
44+
more: defineIcon(Ionicons, 'ellipsis-horizontal'),
45+
personAdd: defineIcon(Ionicons, 'person-add'),
46+
personAddOutline: defineIcon(Ionicons, 'person-add-outline'),
47+
personOutline: defineIcon(Ionicons, 'person-outline'),
48+
personRemove: defineIcon(Ionicons, 'person-remove'),
49+
quote: defineIcon(Ionicons, 'create'),
50+
reaction: defineIcon(Ionicons, 'heart'),
51+
reactionOutline: defineIcon(Ionicons, 'heart-outline'),
52+
remove: defineIcon(Ionicons, 'remove-circle-outline'),
53+
reply: defineIcon(Ionicons, 'chatbubble-outline'),
54+
repost: defineIcon(Ionicons, 'repeat'),
55+
search: defineIcon(Ionicons, 'search'),
56+
searchOutline: defineIcon(Ionicons, 'search-outline'),
57+
settings: defineIcon(Ionicons, 'settings-outline'),
58+
share: defineIcon(Ionicons, 'share-social-outline'),
59+
themeDark: defineIcon(Ionicons, 'moon'),
60+
themeLight: defineIcon(Ionicons, 'sunny'),
61+
time: defineIcon(Ionicons, 'time-outline'),
62+
trash: defineIcon(Ionicons, 'trash-outline'),
63+
trashBin: defineIcon(Ionicons, 'trash-bin'),
64+
};
65+
66+
export type IconName = keyof typeof IconsMap;
67+
68+
/** A palette token (resolved against the theme) or any raw color string. */
69+
type IconColor = PaletteColorToken | (string & {});
70+
71+
type IconProps = Omit<
72+
ComponentProps<typeof Ionicons>,
73+
'name' | 'color' | 'size'
74+
> & {
75+
name: IconName;
76+
size?: number;
77+
/** Palette token (resolved against the active theme) or a raw color string. */
78+
color?: IconColor;
79+
};
80+
81+
export default function Icon({
82+
name,
83+
size = 16,
84+
color = 'neutral_1000',
85+
...rest
86+
}: IconProps): ReactNode {
87+
const { theme } = useTheme();
88+
89+
// Palette tokens resolve against the theme; anything else is passed through as
90+
// a literal color (e.g. a resolved color injected via render-prop / cloneElement).
91+
const resolvedColor =
92+
color in theme.palette ? theme.palette[color as PaletteColorToken] : color;
93+
94+
return IconsMap[name].render({ size, color: resolvedColor, ...rest });
95+
}

apps/polycentric/src/common/components/composites/BackButton.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { IconButton } from '@/src/common/components/primitives';
2-
import { Ionicons } from '@expo/vector-icons';
2+
import Icon from '@/src/common/components/Icon';
33

44
interface BackButtonProps {
55
onPress: () => void;
@@ -8,7 +8,7 @@ interface BackButtonProps {
88
export function BackButton({ onPress }: BackButtonProps) {
99
return (
1010
<IconButton
11-
icon={(props) => <Ionicons name="arrow-back" {...props} />}
11+
icon={(props) => <Icon name="arrowBack" {...props} />}
1212
onPress={onPress}
1313
/>
1414
);

apps/polycentric/src/common/components/composites/CloseButton.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { IconButton } from '@/src/common/components/primitives';
2-
import { Ionicons } from '@expo/vector-icons';
2+
import Icon from '@/src/common/components/Icon';
33

44
interface CloseButtonProps {
55
onPress: () => void;
@@ -8,7 +8,7 @@ interface CloseButtonProps {
88
export function CloseButton({ onPress }: CloseButtonProps) {
99
return (
1010
<IconButton
11-
icon={(props) => <Ionicons name="close" {...props} />}
11+
icon={(props) => <Icon name="close" {...props} />}
1212
onPress={onPress}
1313
/>
1414
);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { PillButton } from '@/src/common/components/primitives';
2-
import { Ionicons } from '@expo/vector-icons';
2+
import Icon from '@/src/common/components/Icon';
33

44
export function EditButton() {
55
return (
66
<PillButton
77
onPress={() => {}}
88
title="Edit"
99
variant="primary"
10-
icon={(props) => <Ionicons name="settings-outline" {...props} />}
10+
icon={(props) => <Icon name="settings" {...props} />}
1111
/>
1212
);
1313
}

apps/polycentric/src/common/components/composites/SocialButton.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { PillButton } from '@/src/common/components/primitives';
2-
import { Ionicons } from '@expo/vector-icons';
2+
import Icon, { IconName } from '@/src/common/components/Icon';
33

44
type SocialAction = 'follow' | 'unfollow' | 'block' | 'unblock';
55

@@ -12,18 +12,18 @@ const CONFIG: Record<
1212
SocialAction,
1313
{
1414
title: string;
15-
icon: keyof typeof Ionicons.glyphMap;
15+
icon: IconName;
1616
variant: 'primary' | 'secondary' | 'destructive';
1717
}
1818
> = {
1919
follow: {
2020
title: 'Follow',
21-
icon: 'person-add',
21+
icon: 'personAdd',
2222
variant: 'primary',
2323
},
2424
unfollow: {
2525
title: 'Unfollow',
26-
icon: 'person-remove',
26+
icon: 'personRemove',
2727
variant: 'primary',
2828
},
2929
block: {
@@ -33,7 +33,7 @@ const CONFIG: Record<
3333
},
3434
unblock: {
3535
title: 'Unblock',
36-
icon: 'checkmark-circle',
36+
icon: 'checkmarkCircle',
3737
variant: 'secondary',
3838
},
3939
};
@@ -46,7 +46,7 @@ export function SocialButton({ action, onPress }: SocialButtonProps) {
4646
onPress={onPress}
4747
title={title}
4848
variant={variant}
49-
icon={(props) => <Ionicons name={icon} {...props} />}
49+
icon={(props) => <Icon name={icon} {...props} />}
5050
/>
5151
);
5252
}

apps/polycentric/src/common/components/layout/Layout.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import {
1919
} from 'react-native';
2020
import { useSafeAreaInsets } from 'react-native-safe-area-context';
2121

22+
import Icon from '@/src/common/components/Icon';
2223
import { IdentityFooter } from '@/src/features/core/identity/IdentityFooter';
23-
import { Ionicons } from '@expo/vector-icons';
2424
import BLUE_LOGO from '../../assets/images/polycentric-logo-blue-256.png';
2525
import WHITE_LOGO from '../../assets/images/polycentric-logo-white-256.png';
2626
import { FUTO_URL, openCompose } from '../../constants';
@@ -261,7 +261,7 @@ export const LeftSidebar = memo(function LeftSidebar({
261261
size="md"
262262
fullWidth={!narrowSidebar}
263263
icon={({ size, color }) => (
264-
<Ionicons name="add-circle" size={size} color={color} />
264+
<Icon name="add" size={size} color={color} />
265265
)}
266266
onPress={() => openCompose()}
267267
/>
@@ -350,10 +350,10 @@ export const RightSidebar = memo(function RightSidebar({
350350
onPress={toggleTheme}
351351
style={({ pressed }) => [pressed && { opacity: 0.65 }]}
352352
>
353-
<Ionicons
354-
name={theme.name === 'dark' ? 'moon' : 'sunny'}
353+
<Icon
354+
name={theme.name === 'dark' ? 'themeDark' : 'themeLight'}
355355
size={typography.fontSize.sm}
356-
color={theme.palette.neutral_500}
356+
color="neutral_500"
357357
/>
358358
</Pressable>
359359
{LINKS.map(({ text, href }) => (

apps/polycentric/src/common/components/layout/Topbar.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Link, router, useSegments } from 'expo-router';
22
import { Pressable, View } from 'react-native';
33
import { Atoms, Spacing, useTheme, withHexOpacity } from '../../theme';
44
import { Image } from 'expo-image';
5-
import { Ionicons } from '@expo/vector-icons';
5+
import Icon from '@/src/common/components/Icon';
66
import BLUE_LOGO from '../../assets/images/polycentric-logo-blue-256.png';
77
import WHITE_LOGO from '../../assets/images/polycentric-logo-white-256.png';
88
import { ProfileAvatar, Text } from '../primitives';
@@ -64,11 +64,7 @@ function Topbar({ title, center, right }: TopbarProps) {
6464
hitSlop={Spacing['lg']}
6565
style={({ pressed }) => [pressed && { opacity: 0.5 }]}
6666
>
67-
<Ionicons
68-
name="chevron-back"
69-
size={24}
70-
color={theme.palette.neutral_900}
71-
/>
67+
<Icon name="chevronBack" size={24} color="neutral_900" />
7268
</Pressable>
7369
) : (
7470
<ProfileAvatar

apps/polycentric/src/common/components/layout/nav/NavItem.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010

1111
import { Pressable, Text, useWindowDimensions, View } from 'react-native';
1212

13-
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
1413
import { Atoms, Breakpoints, useTheme } from '@/src/common/theme';
1514
import { flattenHref } from '@/src/utils/router';
1615

apps/polycentric/src/common/components/layout/nav/VerticalNav.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Atoms } from '@/src/common/theme';
22
import { ComponentProps } from 'react';
33

44
import { useCurrentIdentity } from '@/src/common/lib/polycentric-hooks';
5-
import { Ionicons } from '@expo/vector-icons';
5+
import Icon from '@/src/common/components/Icon';
66
import { View } from 'react-native';
77
import { NavItem } from './NavItem';
88

@@ -23,18 +23,18 @@ export function VerticalNav({ style }: VerticalNavProps) {
2323
>
2424
<NavItem
2525
label="Home"
26-
icon={<Ionicons name="home-outline" size={24} />}
26+
icon={<Icon name="home" size={24} />}
2727
href="/feed"
2828
/>
2929
<NavItem
3030
label="Explore"
31-
icon={<Ionicons name="search-outline" size={24} />}
31+
icon={<Icon name="searchOutline" size={24} />}
3232
href="/explore"
3333
/>
3434
{identity?.identityKey && (
3535
<NavItem
3636
label="Profile"
37-
icon={<Ionicons name="person-outline" size={24} />}
37+
icon={<Icon name="personOutline" size={24} />}
3838
href={{
3939
pathname: '/[identityId]',
4040
params: { identityId: identity?.identityKey },
@@ -44,7 +44,7 @@ export function VerticalNav({ style }: VerticalNavProps) {
4444

4545
<NavItem
4646
label="Settings"
47-
icon={<Ionicons name="settings-outline" size={24} />}
47+
icon={<Icon name="settings" size={24} />}
4848
href="/settings"
4949
/>
5050
</View>

0 commit comments

Comments
 (0)