fix(feed): breathing room around divider + FAB back to right/bottom corner
- PostSeparator was a bare 1px line flush against both neighbouring cards, so the seam looked like card contact instead of a real break. Wrapped it in a 12px vertical padding — now there's 12px blank above the line, 1px line, 12px blank below. Trimmed the card's own paddingVertical back down since the separator now owns the inter-post breathing room. - FAB was lifted to bottom: max(insets.bottom, 8) + 70 in the previous commit which put it far too high (a leftover from the original experiment with the absoluteFill wrapper). User wants 12px above the NavBar and 12px from the right edge. The Feed screen's container ends at the NavBar top (enforced by (app)/_layout.tsx's outer <View flex:1> + NavBar sibling), so a simple `right: 12, bottom: 12` on position:absolute lands the button exactly there on every device. Removed the now-unnecessary absoluteFill wrapper too. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -251,43 +251,29 @@ export default function FeedScreen() {
|
|||||||
contentContainerStyle={posts.length === 0 ? { flexGrow: 1 } : undefined}
|
contentContainerStyle={posts.length === 0 ? { flexGrow: 1 } : undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Floating compose button.
|
{/* Floating compose button — pinned 12px from the right edge of
|
||||||
*
|
the screen and 12px above the NavBar top. The Feed screen's
|
||||||
* Wrapped in a StyleSheet.absoluteFill container with pointerEvents
|
container ends at the NavBar top (see (app)/_layout.tsx), so
|
||||||
* "box-none" so only the FAB captures touches — taps anywhere else
|
a plain bottom: 12 measures from exactly that edge. */}
|
||||||
* pass through to the FlatList below.
|
<Pressable
|
||||||
*
|
onPress={() => router.push('/(app)/compose' as never)}
|
||||||
* Inside the wrapper, alignSelf: 'flex-end' pins to the right;
|
style={({ pressed }) => ({
|
||||||
* bottom inset leaves ~14px clearance above the NavBar (≈56px tall
|
|
||||||
* + safe-area-bottom). Explicit `right: 14` is belt-and-braces
|
|
||||||
* for RTL / platform quirks where alignSelf alone might not pin. */}
|
|
||||||
<View
|
|
||||||
pointerEvents="box-none"
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: 0, right: 0, top: 0, bottom: 0,
|
right: 12,
|
||||||
}}
|
bottom: 12,
|
||||||
|
width: 56, height: 56,
|
||||||
|
borderRadius: 28,
|
||||||
|
backgroundColor: pressed ? '#1a8cd8' : '#1d9bf0',
|
||||||
|
alignItems: 'center', justifyContent: 'center',
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: { width: 0, height: 4 },
|
||||||
|
shadowOpacity: 0.5,
|
||||||
|
shadowRadius: 6,
|
||||||
|
elevation: 8,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<Pressable
|
<Ionicons name="create-outline" size={24} color="#ffffff" />
|
||||||
onPress={() => router.push('/(app)/compose' as never)}
|
</Pressable>
|
||||||
style={({ pressed }) => ({
|
|
||||||
position: 'absolute',
|
|
||||||
right: 14,
|
|
||||||
bottom: Math.max(insets.bottom, 8) + 70,
|
|
||||||
width: 56, height: 56,
|
|
||||||
borderRadius: 28,
|
|
||||||
backgroundColor: pressed ? '#1a8cd8' : '#1d9bf0',
|
|
||||||
alignItems: 'center', justifyContent: 'center',
|
|
||||||
shadowColor: '#000',
|
|
||||||
shadowOffset: { width: 0, height: 4 },
|
|
||||||
shadowOpacity: 0.5,
|
|
||||||
shadowRadius: 6,
|
|
||||||
elevation: 8,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Ionicons name="create-outline" size={24} color="#ffffff" />
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,8 +174,7 @@ function PostCardInner({ post, likedByMe, onStatsChanged, onDeleted, compact }:
|
|||||||
style={({ pressed }) => ({
|
style={({ pressed }) => ({
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: 16,
|
||||||
paddingTop: compact ? 14 : 18,
|
paddingVertical: compact ? 10 : 12,
|
||||||
paddingBottom: compact ? 16 : 20,
|
|
||||||
backgroundColor: pressed ? '#080808' : 'transparent',
|
backgroundColor: pressed ? '#080808' : 'transparent',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
@@ -324,13 +323,20 @@ export const PostCard = React.memo(PostCardInner);
|
|||||||
* every feed surface (timeline, author, hashtag, post detail) can pass
|
* every feed surface (timeline, author, hashtag, post detail) can pass
|
||||||
* it as ItemSeparatorComponent and get identical spacing / colour.
|
* it as ItemSeparatorComponent and get identical spacing / colour.
|
||||||
*
|
*
|
||||||
* The line colour (#2a2a2a) is the minimum grey that reads on OLED
|
* Layout: 12px blank space → 1px grey line → 12px blank space. The
|
||||||
* black under mobile-bright-mode gamma — go darker and the seam vanishes.
|
* blank space on each side makes the line "float" between posts rather
|
||||||
* Height 1 is one logical px (hairline on retina). No horizontal inset:
|
* than hugging the edge of the card — gives clear visual separation
|
||||||
* Twitter runs the seam edge-to-edge and it looks cleaner than a gap.
|
* without needing big card padding everywhere.
|
||||||
|
*
|
||||||
|
* Colour #2a2a2a is the minimum grey that reads on OLED black under
|
||||||
|
* mobile-bright-mode gamma; darker and the seam vanishes.
|
||||||
*/
|
*/
|
||||||
export function PostSeparator() {
|
export function PostSeparator() {
|
||||||
return <View style={{ height: 1, backgroundColor: '#2a2a2a' }} />;
|
return (
|
||||||
|
<View style={{ paddingVertical: 12 }}>
|
||||||
|
<View style={{ height: 1, backgroundColor: '#2a2a2a' }} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Inline helpers ──────────────────────────────────────────────────────
|
// ── Inline helpers ──────────────────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user