Skip to content

Commit abee49c

Browse files
Merge upstream develop
2 parents caf232b + e81388c commit abee49c

36 files changed

Lines changed: 1050 additions & 301 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import FeedTabScreen from '@/src/features/feed/FeedScreen';
2+
3+
export default function FeedIndexRoute() {
4+
return <FeedTabScreen />;
5+
}

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

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { Ionicons } from '@expo/vector-icons';
2828
import { FUTO_URL, openCompose } from '../../constants';
2929
import { Button } from '../primitives';
3030
import { useCurrentIdentity } from '../../lib/polycentric-hooks';
31+
import { IdentityFooter } from '@/src/features/core/identity/IdentityFooter';
3132

3233
type MainProps = {
3334
children: ReactElement | ReactElement[];
@@ -177,7 +178,13 @@ export const LeftSidebar = memo(function LeftSidebar({
177178
]}
178179
>
179180
{/* 1st section (top) */}
180-
<View>
181+
<View
182+
style={[
183+
Atoms.w_full,
184+
narrowSidebar && Atoms.align_center,
185+
Atoms.flex_col,
186+
]}
187+
>
181188
<Link
182189
href="/"
183190
style={[
@@ -196,6 +203,27 @@ export const LeftSidebar = memo(function LeftSidebar({
196203
</Link>
197204

198205
<VerticalNav />
206+
207+
<View
208+
style={[
209+
Atoms.py_md,
210+
Atoms.self_stretch,
211+
narrowSidebar && Atoms.align_center,
212+
]}
213+
>
214+
{identity && (
215+
<Button
216+
title={narrowSidebar ? '' : 'Post'}
217+
variant="primary"
218+
size="md"
219+
fullWidth={!narrowSidebar}
220+
icon={({ size, color }) => (
221+
<Ionicons name="add-circle" size={size} color={color} />
222+
)}
223+
onPress={() => openCompose()}
224+
/>
225+
)}
226+
</View>
199227
</View>
200228
{/* 2nd Section (bottom) */}
201229
<View
@@ -205,18 +233,7 @@ export const LeftSidebar = memo(function LeftSidebar({
205233
narrowSidebar && Atoms.align_center,
206234
]}
207235
>
208-
{identity && (
209-
<Button
210-
title={narrowSidebar ? '' : 'New Post'}
211-
variant="primary"
212-
size="md"
213-
fullWidth={!narrowSidebar}
214-
icon={({ size, color }) => (
215-
<Ionicons name="add-circle" size={size} color={color} />
216-
)}
217-
onPress={() => openCompose()}
218-
/>
219-
)}
236+
{identity && <IdentityFooter compact={narrowSidebar} />}
220237
</View>
221238
</View>
222239
</View>

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ export function VerticalNav({ style }: VerticalNavProps) {
2323
icon={<Ionicons name="home-outline" size={24} />}
2424
href="/feed"
2525
/>
26+
<NavItem
27+
label="Explore"
28+
icon={<Ionicons name="search-outline" size={24} />}
29+
href="/explore"
30+
/>
2631
{identity?.identityKey && (
2732
<NavItem
2833
label="Profile"

apps/polycentric/src/common/constants/routes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ export const Routes = {
1717
feed: {
1818
index: '/feed',
1919
compose: '/feed/compose',
20-
identity: '/feed/identity',
2120
},
2221
search: '/search',
2322
claims: '/claims',
23+
identitySwitch: '/identity/switch',
2424
profile: (identityId: string) => `/${identityId}` as const,
2525
editProfile: (identityId: string) => `/${identityId}/edit` as const,
2626
post: (identityId: string, postId: string) =>

apps/polycentric/src/common/lib/polycentric-hooks/PolycentricProvider.tsx

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
type ReactNode,
1616
} from 'react';
1717
import { ActivityIndicator, Platform, Text, View } from 'react-native';
18+
import useFollows from '@/src/features/follow/hooks/useFollows';
1819
import { pubkeyStr } from './helpers';
1920
import {
2021
createPolycentricStore,
@@ -33,13 +34,6 @@ export interface PolycentricContextValue {
3334
refreshCurrentIdentity: () => Promise<void>;
3435
}
3536

36-
interface FollowStatusResult {
37-
isFollowing: boolean;
38-
isLoading: boolean;
39-
toggleFollow: () => Promise<void>;
40-
refresh: () => void;
41-
}
42-
4337
const PolycentricContext = createContext<PolycentricContextValue | null>(null);
4438

4539
// Defaults for local development
@@ -134,19 +128,24 @@ export function PolycentricProvider({
134128
setClient(c);
135129
setStore(s);
136130
setCurrentIdentity(await resolveIdentity(c));
137-
setIsLoading(false);
138131

139132
// Only sync when we already have an identity to sync for.
140133
if (c.activeIdentityKey) {
141-
void c.sync().catch((syncError) => {
142-
console.warn('Initial Polycentric sync failed:', syncError);
143-
});
134+
await c
135+
.sync()
136+
.then(() => useFollows.getState().refresh(c))
137+
.catch((syncError) => {
138+
console.warn('Initial Polycentric sync failed:', syncError);
139+
});
144140
}
145141

142+
setIsLoading(false);
143+
146144
c.events.onKeyPairChanged(async () => {
147145
if (cancelled) return;
148146
setCurrentIdentity(await resolveIdentity(c));
149147
await s.getState().refreshIdentities();
148+
await useFollows.getState().refresh(c);
150149
});
151150

152151
// Identity onboarding (create / claim) publishes an Identity event,
@@ -263,17 +262,6 @@ export function useCurrentIdentity() {
263262
};
264263
}
265264

266-
export function useFollowStatus(
267-
_identityKey: string | null | undefined,
268-
): FollowStatusResult {
269-
return {
270-
isFollowing: false,
271-
isLoading: false,
272-
toggleFollow: async () => {},
273-
refresh: () => {},
274-
};
275-
}
276-
277265
export function useUsername(_identityKey: string | null | undefined): string {
278266
const name = undefined;
279267

apps/polycentric/src/common/lib/polycentric-hooks/index.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ export { useStore } from './store';
2121
export type { PolycentricStore, PolycentricStoreApi } from './store';
2222

2323
// Profile screen hooks
24-
export {
25-
useProfileScreenData,
26-
type ProfileScreenData,
27-
} from './useProfileScreenData';
2824
export {
2925
useProfileEdit,
3026
type ProfileEditState,

apps/polycentric/src/common/lib/polycentric-hooks/useProfileScreenData.ts

Lines changed: 0 additions & 71 deletions
This file was deleted.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { Avatar, Text } from '@/src/common/components/primitives';
2+
import { openCompose } from '@/src/common/constants';
3+
import {
4+
identiconUrl,
5+
useCurrentIdentity,
6+
} from '@/src/common/lib/polycentric-hooks';
7+
import { useWebHover } from '@/src/common/lib/useWebHover';
8+
import { Atoms, useTheme, withHexOpacity } from '@/src/common/theme';
9+
import { Pressable, StyleSheet, View } from 'react-native';
10+
11+
/**
12+
* A non-interactive placeholder that looks like a composer input. Tapping
13+
* anywhere on it opens the full compose modal.
14+
*/
15+
export function ComposerInput() {
16+
const { identity: currentIdentity } = useCurrentIdentity();
17+
const { theme } = useTheme();
18+
const { hovered, onHoverIn, onHoverOut } = useWebHover();
19+
20+
if (!currentIdentity?.identityKey) return null;
21+
22+
const avatarUrl = identiconUrl(currentIdentity.identityKey);
23+
24+
const hoverOverlay =
25+
theme.scheme === 'light'
26+
? withHexOpacity(theme.palette.neutral_500, '14')
27+
: withHexOpacity(theme.palette.black, '28');
28+
29+
return (
30+
<Pressable
31+
accessibilityRole="button"
32+
accessibilityLabel="New post"
33+
onPress={() => openCompose()}
34+
onHoverIn={onHoverIn}
35+
onHoverOut={onHoverOut}
36+
style={[
37+
Atoms.flex_row,
38+
Atoms.items_center,
39+
Atoms.gap_lg,
40+
Atoms.px_lg,
41+
Atoms.py_md,
42+
{
43+
borderBottomWidth: 1,
44+
borderBottomColor: withHexOpacity(theme.palette.neutral_500, '40'),
45+
backgroundColor: theme.palette.background_primary,
46+
overflow: 'hidden',
47+
},
48+
]}
49+
>
50+
<Avatar source={{ uri: avatarUrl }} size="md" />
51+
<Text variant="body" color="neutral_500" style={Atoms.flex_1}>
52+
What&apos;s on your mind?
53+
</Text>
54+
{hovered ? (
55+
<View
56+
pointerEvents="none"
57+
style={[StyleSheet.absoluteFill, { backgroundColor: hoverOverlay }]}
58+
/>
59+
) : null}
60+
</Pressable>
61+
);
62+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './ComposeSheetInner';
2+
export * from './ComposerInput';

0 commit comments

Comments
 (0)