refactor(ui): redesign SearchBar with compact mode and add home screen tabs
Refactor SearchBar component to support compact mode with transparent styling, reduced padding, and smaller icons. Add home screen tab navigation for switching between home feed and market view with animated tab indicator. Also adjust PostDetailScreen action button sizing and CommentItem margins for better spacing.
This commit is contained in:
@@ -37,12 +37,22 @@ import { useDifferentialPosts } from '../../hooks/useDifferentialPosts';
|
||||
import { postSyncService } from '@/services/post';
|
||||
import { SearchScreen } from './SearchScreen';
|
||||
import { CreatePostScreen } from '../create/CreatePostScreen';
|
||||
import { MarketView } from './MarketView';
|
||||
import { CreateTradeScreen } from '../trade/CreateTradeScreen';
|
||||
import type { TradeCategory } from '../../types/trade';
|
||||
import { ALL_TRADE_CATEGORIES } from '../../types/trade';
|
||||
import * as hrefs from '../../navigation/hrefs';
|
||||
import { blurActiveElement } from '../../infrastructure/platform';
|
||||
|
||||
const SORT_OPTIONS = ['关注', '推荐', '最新'];
|
||||
const SORT_ICONS = ['account-heart', 'fire', 'clock-outline'];
|
||||
const SORT_TYPES: PostType[] = ['follow', 'hot', 'latest'];
|
||||
|
||||
const MARKET_FILTER_OPTIONS = [
|
||||
{ key: 'all' as const, label: '全部', icon: 'view-grid-outline' },
|
||||
{ key: 'sell' as const, label: '出售', icon: 'tag-outline' },
|
||||
{ key: 'buy' as const, label: '收购', icon: 'hand-coin-outline' },
|
||||
];
|
||||
const DEFAULT_PAGE_SIZE = 20;
|
||||
const MOBILE_TAB_BAR_HEIGHT = 64;
|
||||
const MOBILE_TAB_FLOATING_MARGIN = 12;
|
||||
@@ -56,7 +66,7 @@ type ViewMode = 'list' | 'grid';
|
||||
type PostType = 'follow' | 'hot' | 'latest';
|
||||
type LatestCapsule = { id: string; name: string };
|
||||
|
||||
function createHomeStyles(colors: AppColors) {
|
||||
function createHomeStyles(colors: AppColors, responsivePadding: number) {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
@@ -66,13 +76,45 @@ function createHomeStyles(colors: AppColors) {
|
||||
backgroundColor: colors.background.paper,
|
||||
},
|
||||
searchWrapper: {
|
||||
paddingTop: spacing.lg,
|
||||
paddingTop: spacing.sm,
|
||||
paddingBottom: spacing.xs,
|
||||
shadowColor: 'transparent',
|
||||
shadowOffset: { width: 0, height: 0 },
|
||||
shadowOpacity: 0,
|
||||
shadowRadius: 0,
|
||||
elevation: 0,
|
||||
},
|
||||
homeTabSwitcher: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginTop: spacing.xs,
|
||||
marginBottom: spacing.xs,
|
||||
paddingHorizontal: responsivePadding + 4,
|
||||
},
|
||||
homeTabSwitcherLeft: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 20,
|
||||
},
|
||||
homeTabSwitcherRight: {
|
||||
flex: 1,
|
||||
marginLeft: 16,
|
||||
},
|
||||
homeTabItem: {
|
||||
paddingVertical: spacing.sm,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderBottomWidth: 2,
|
||||
borderBottomColor: 'transparent',
|
||||
},
|
||||
homeTabItemActive: {
|
||||
borderBottomColor: colors.text.primary,
|
||||
},
|
||||
homeTabText: {
|
||||
fontSize: 20,
|
||||
fontWeight: '400',
|
||||
color: colors.text.hint,
|
||||
},
|
||||
homeTabTextActive: {
|
||||
fontSize: 20,
|
||||
fontWeight: '700',
|
||||
color: colors.text.primary,
|
||||
},
|
||||
homeTabBar: {
|
||||
marginTop: spacing.sm,
|
||||
@@ -89,7 +131,6 @@ function createHomeStyles(colors: AppColors) {
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingVertical: spacing.xs,
|
||||
backgroundColor: colors.background.paper,
|
||||
},
|
||||
sortBarCapsuleScroll: {
|
||||
flex: 1,
|
||||
@@ -182,21 +223,22 @@ export const HomeScreen: React.FC = () => {
|
||||
const hasFetchedVerification = useVerificationStore((s) => s.hasFetchedStatus);
|
||||
const colors = useAppColors();
|
||||
const resolvedScheme = useResolvedColorScheme();
|
||||
const styles = useMemo(() => createHomeStyles(colors), [colors]);
|
||||
const statusBarStyle = resolvedScheme === 'dark' ? 'light-content' : 'dark-content';
|
||||
|
||||
// 使用响应式 hook
|
||||
const {
|
||||
width,
|
||||
isMobile,
|
||||
isTablet,
|
||||
isDesktop,
|
||||
const {
|
||||
width,
|
||||
isMobile,
|
||||
isTablet,
|
||||
isDesktop,
|
||||
isWideScreen,
|
||||
} = useResponsive();
|
||||
|
||||
|
||||
// 响应式间距
|
||||
const responsiveGap = useResponsiveSpacing({ xs: 4, sm: 6, md: 8, lg: 12, xl: 16 });
|
||||
const responsivePadding = useResponsiveSpacing({ xs: 8, sm: 12, md: 16, lg: 24, xl: 32 });
|
||||
|
||||
const styles = useMemo(() => createHomeStyles(colors, responsivePadding), [colors, responsivePadding]);
|
||||
const statusBarStyle = resolvedScheme === 'dark' ? 'light-content' : 'dark-content';
|
||||
|
||||
const [sortIndex, setSortIndex] = useState(0);
|
||||
const [viewMode, setViewMode] = useState<ViewMode>('list');
|
||||
@@ -214,6 +256,14 @@ export const HomeScreen: React.FC = () => {
|
||||
// 发帖弹窗状态
|
||||
const [showCreatePost, setShowCreatePost] = useState(false);
|
||||
|
||||
// 广场/市集 Tab
|
||||
const [homeTab, setHomeTab] = useState<'square' | 'market'>('square');
|
||||
const [showCreateTrade, setShowCreateTrade] = useState(false);
|
||||
|
||||
// 市集筛选状态
|
||||
const [marketFilterType, setMarketFilterType] = useState<'all' | 'sell' | 'buy'>('all');
|
||||
const [marketCategory, setMarketCategory] = useState<TradeCategory | 'all'>('all');
|
||||
|
||||
// 分享面板状态
|
||||
const [showShareSheet, setShowShareSheet] = useState(false);
|
||||
const [sharePost, setSharePost] = useState<Post | null>(null);
|
||||
@@ -530,6 +580,13 @@ export const HomeScreen: React.FC = () => {
|
||||
setSortIndex(nextIndex);
|
||||
}, [sortIndex]);
|
||||
|
||||
const cycleMarketFilter = useCallback(() => {
|
||||
setMarketFilterType(prev => {
|
||||
const idx = MARKET_FILTER_OPTIONS.findIndex(f => f.key === prev);
|
||||
return MARKET_FILTER_OPTIONS[(idx + 1) % MARKET_FILTER_OPTIONS.length].key;
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const loadChannels = async () => {
|
||||
const list = await channelService.list();
|
||||
@@ -856,18 +913,42 @@ export const HomeScreen: React.FC = () => {
|
||||
|
||||
{/* 顶部Header */}
|
||||
<View style={styles.header}>
|
||||
{/* 搜索栏 */}
|
||||
<View style={[styles.searchWrapper, { paddingHorizontal: responsivePadding }]}>
|
||||
<SearchBar
|
||||
value=""
|
||||
onChangeText={() => {}}
|
||||
onSubmit={handleSearchPress}
|
||||
onFocus={handleSearchPress}
|
||||
placeholder="搜索帖子、用户"
|
||||
/>
|
||||
{/* 广场/市集切换 */}
|
||||
<View style={styles.homeTabSwitcher}>
|
||||
<View style={styles.homeTabSwitcherLeft}>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
style={[styles.homeTabItem, homeTab === 'square' && styles.homeTabItemActive]}
|
||||
onPress={() => setHomeTab('square')}
|
||||
>
|
||||
<Text style={homeTab === 'square' ? styles.homeTabTextActive : styles.homeTabText}>
|
||||
广场
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
style={[styles.homeTabItem, homeTab === 'market' && styles.homeTabItemActive]}
|
||||
onPress={() => setHomeTab('market')}
|
||||
>
|
||||
<Text style={homeTab === 'market' ? styles.homeTabTextActive : styles.homeTabText}>
|
||||
市集
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.homeTabSwitcherRight}>
|
||||
<SearchBar
|
||||
value=""
|
||||
onChangeText={() => {}}
|
||||
onSubmit={handleSearchPress}
|
||||
onFocus={handleSearchPress}
|
||||
placeholder="搜索"
|
||||
compact
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 排序筛选 + 频道 */}
|
||||
|
||||
{/* 排序筛选 + 频道(仅广场模式显示) */}
|
||||
{homeTab === 'square' && (
|
||||
<View style={styles.sortBar}>
|
||||
<TouchableOpacity onPress={toggleViewMode} style={styles.viewToggleBtn}>
|
||||
<MaterialCommunityIcons
|
||||
@@ -894,9 +975,56 @@ export const HomeScreen: React.FC = () => {
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 市集分类 + 筛选(仅市集模式显示) */}
|
||||
{homeTab === 'market' && (
|
||||
<View style={styles.sortBar}>
|
||||
<FlashList
|
||||
horizontal
|
||||
data={[{ key: 'all', label: '全部' }, ...ALL_TRADE_CATEGORIES]}
|
||||
renderItem={({ item }: { item: { key: string; label: string } }) => (
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
style={[
|
||||
styles.capsuleItem,
|
||||
marketCategory === item.key && { backgroundColor: `${colors.primary.main}18` },
|
||||
]}
|
||||
onPress={() => setMarketCategory(item.key as TradeCategory | 'all')}
|
||||
>
|
||||
<Text style={[
|
||||
styles.capsuleText,
|
||||
marketCategory === item.key ? styles.capsuleTextActive : {},
|
||||
]}>
|
||||
{item.label}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
keyExtractor={(item: { key: string; label: string }) => item.key}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={styles.sortBarCapsuleContent}
|
||||
style={styles.sortBarCapsuleScroll}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
onPress={cycleMarketFilter}
|
||||
style={styles.sortTrigger}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
name={(MARKET_FILTER_OPTIONS.find(f => f.key === marketFilterType)?.icon || 'view-grid-outline') as any}
|
||||
size={18}
|
||||
color={colors.text.secondary}
|
||||
/>
|
||||
<Text style={styles.sortTriggerText}>
|
||||
{MARKET_FILTER_OPTIONS.find(f => f.key === marketFilterType)?.label || '全部'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 帖子列表 */}
|
||||
{/* 内容区域 */}
|
||||
{homeTab === 'square' ? (
|
||||
<View style={styles.contentContainer}>
|
||||
{isInitialLoading ? (
|
||||
<Loading fullScreen />
|
||||
@@ -906,8 +1034,17 @@ export const HomeScreen: React.FC = () => {
|
||||
renderResponsiveGrid()
|
||||
)}
|
||||
</View>
|
||||
) : (
|
||||
<MarketView
|
||||
onCreateTrade={() => setShowCreateTrade(true)}
|
||||
filterType={marketFilterType}
|
||||
onFilterTypeChange={setMarketFilterType}
|
||||
selectedCategory={marketCategory}
|
||||
onSelectedCategoryChange={setMarketCategory}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 漂浮发帖按钮 */}
|
||||
{/* 漂浮发帖/发布按钮 */}
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.floatingButton,
|
||||
@@ -915,7 +1052,11 @@ export const HomeScreen: React.FC = () => {
|
||||
isWideScreen && styles.floatingButtonWide,
|
||||
floatingButtonBottom !== undefined && { bottom: floatingButtonBottom },
|
||||
]}
|
||||
onPress={handleCreatePost}
|
||||
onPress={homeTab === 'market' ? () => {
|
||||
if (!isAuthenticated) { router.push('/login'); return; }
|
||||
if (!isVerified) { router.push(hrefs.hrefVerificationGuide()); return; }
|
||||
setShowCreateTrade(true);
|
||||
} : handleCreatePost}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<MaterialCommunityIcons name="plus" size={28} color={colors.text.inverse} />
|
||||
@@ -945,6 +1086,18 @@ export const HomeScreen: React.FC = () => {
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
{/* 发布交易弹窗 */}
|
||||
<Modal
|
||||
visible={showCreateTrade}
|
||||
animationType="slide"
|
||||
presentationStyle="pageSheet"
|
||||
onRequestClose={() => setShowCreateTrade(false)}
|
||||
>
|
||||
<CreateTradeScreen
|
||||
onClose={() => setShowCreateTrade(false)}
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
{/* 分享面板 */}
|
||||
<ShareSheet
|
||||
visible={showShareSheet}
|
||||
|
||||
223
src/screens/home/MarketView.tsx
Normal file
223
src/screens/home/MarketView.tsx
Normal file
@@ -0,0 +1,223 @@
|
||||
import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||
import { View, StyleSheet, RefreshControl, Pressable } from 'react-native';
|
||||
import { FlashList, FlashListRef } from '@shopify/flash-list';
|
||||
import type { ListRenderItem } from '@shopify/flash-list';
|
||||
import { useAppColors, type AppColors } from '../../theme';
|
||||
import { Text, Loading, EmptyState } from '../../components/common';
|
||||
import { TradeCard } from '../../components/business/TradeCard/TradeCard';
|
||||
import { tradeService } from '../../services/trade/tradeService';
|
||||
import { useIsAuthenticated } from '../../stores/auth';
|
||||
import type {
|
||||
TradeItemDTO,
|
||||
TradeCategory,
|
||||
TradeType,
|
||||
} from '../../types/trade';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { useResponsive, useResponsiveSpacing } from '../../hooks/useResponsive';
|
||||
|
||||
type TradeFilterType = 'all' | 'sell' | 'buy';
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
|
||||
function createMarketStyles(colors: AppColors, gap: number, padding: number) {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: colors.background.default,
|
||||
},
|
||||
listContent: {
|
||||
paddingHorizontal: padding,
|
||||
paddingTop: gap,
|
||||
paddingBottom: 80,
|
||||
},
|
||||
columnWrapper: {
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
interface MarketViewProps {
|
||||
onCreateTrade: () => void;
|
||||
filterType?: TradeFilterType;
|
||||
onFilterTypeChange?: (type: TradeFilterType) => void;
|
||||
selectedCategory?: TradeCategory | 'all';
|
||||
onSelectedCategoryChange?: (cat: TradeCategory | 'all') => void;
|
||||
}
|
||||
|
||||
export function MarketView({
|
||||
onCreateTrade,
|
||||
filterType: filterTypeProp,
|
||||
onFilterTypeChange,
|
||||
selectedCategory: selectedCategoryProp,
|
||||
onSelectedCategoryChange,
|
||||
}: MarketViewProps) {
|
||||
const colors = useAppColors();
|
||||
const router = useRouter();
|
||||
const isAuth = useIsAuthenticated();
|
||||
const { width, isMobile } = useResponsive();
|
||||
|
||||
const gap = useResponsiveSpacing({ xs: 6, sm: 8, md: 10, lg: 12, xl: 16 });
|
||||
const padding = useResponsiveSpacing({ xs: 8, sm: 10, md: 12, lg: 16, xl: 20 });
|
||||
const styles = useMemo(() => createMarketStyles(colors, gap, padding), [colors, gap, padding]);
|
||||
|
||||
const [items, setItems] = useState<TradeItemDTO[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
const [cursor, setCursor] = useState<string | undefined>();
|
||||
const [filterTypeLocal, setFilterTypeLocal] = useState<TradeFilterType>('all');
|
||||
const [selectedCategoryLocal, setSelectedCategoryLocal] = useState<TradeCategory | 'all'>('all');
|
||||
|
||||
const filterType = filterTypeProp ?? filterTypeLocal;
|
||||
const selectedCategory = selectedCategoryProp ?? selectedCategoryLocal;
|
||||
const setFilterType = onFilterTypeChange ?? setFilterTypeLocal;
|
||||
const setSelectedCategory = onSelectedCategoryChange ?? setSelectedCategoryLocal;
|
||||
|
||||
const flashListRef = useRef<any>(null);
|
||||
|
||||
// 网格列数:移动端2列,平板3列,桌面4列
|
||||
const numColumns = useMemo(() => {
|
||||
if (width >= 1200) return 4;
|
||||
if (width >= 768) return 3;
|
||||
return 2;
|
||||
}, [width]);
|
||||
|
||||
// 计算卡片宽度(用于固定宽高比)
|
||||
const cardWidth = useMemo(() => {
|
||||
const totalGap = gap * (numColumns - 1);
|
||||
return Math.floor((width - padding * 2 - totalGap) / numColumns);
|
||||
}, [width, padding, gap, numColumns]);
|
||||
|
||||
const fetchItems = useCallback(async (isRefresh = false) => {
|
||||
try {
|
||||
if (isRefresh) {
|
||||
setIsRefreshing(true);
|
||||
} else if (!isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tradeType = filterType === 'all' ? undefined : (filterType as TradeType);
|
||||
const category = selectedCategory === 'all' ? undefined : (selectedCategory as TradeCategory);
|
||||
|
||||
const res = await tradeService.getTradeItems({
|
||||
trade_type: tradeType,
|
||||
category,
|
||||
page_size: PAGE_SIZE,
|
||||
});
|
||||
|
||||
setItems(res.list || []);
|
||||
setCursor(res.next_cursor);
|
||||
setHasMore(res.has_more);
|
||||
} catch (e) {
|
||||
console.error('Failed to fetch trade items:', e);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
setIsRefreshing(false);
|
||||
}
|
||||
}, [filterType, selectedCategory]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
setCursor(undefined);
|
||||
fetchItems(true);
|
||||
}, [filterType, selectedCategory]);
|
||||
|
||||
const loadMore = useCallback(async () => {
|
||||
if (isLoadingMore || !hasMore || !cursor) return;
|
||||
setIsLoadingMore(true);
|
||||
try {
|
||||
const tradeType = filterType === 'all' ? undefined : (filterType as TradeType);
|
||||
const category = selectedCategory === 'all' ? undefined : (selectedCategory as TradeCategory);
|
||||
const res = await tradeService.getTradeItems({
|
||||
trade_type: tradeType,
|
||||
category,
|
||||
cursor,
|
||||
page_size: PAGE_SIZE,
|
||||
});
|
||||
setItems(prev => [...prev, ...(res.list || [])]);
|
||||
setCursor(res.next_cursor);
|
||||
setHasMore(res.has_more);
|
||||
} catch (e) {
|
||||
console.error('Failed to load more trade items:', e);
|
||||
} finally {
|
||||
setIsLoadingMore(false);
|
||||
}
|
||||
}, [isLoadingMore, hasMore, cursor, filterType, selectedCategory]);
|
||||
|
||||
const handlePressItem = useCallback((id: string) => {
|
||||
router.push(`/trade/${id}` as any);
|
||||
}, [router]);
|
||||
|
||||
const handleFavorite = useCallback(async (id: string) => {
|
||||
if (!isAuth) return;
|
||||
try {
|
||||
const item = items.find(i => i.id === id);
|
||||
if (!item) return;
|
||||
if (item.is_favorited) {
|
||||
await tradeService.unfavorite(id);
|
||||
} else {
|
||||
await tradeService.favorite(id);
|
||||
}
|
||||
setItems(prev =>
|
||||
prev.map(i =>
|
||||
i.id === id
|
||||
? { ...i, is_favorited: !i.is_favorited, favorites_count: i.favorites_count + (i.is_favorited ? -1 : 1) }
|
||||
: i
|
||||
)
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('Favorite failed:', e);
|
||||
}
|
||||
}, [items, isAuth]);
|
||||
|
||||
const renderItem = useCallback<ListRenderItem<TradeItemDTO>>(({ item }) => (
|
||||
<View style={{ width: cardWidth, marginBottom: gap }}>
|
||||
<TradeCard
|
||||
item={item}
|
||||
variant="grid"
|
||||
onPress={handlePressItem}
|
||||
onFavorite={handleFavorite}
|
||||
/>
|
||||
</View>
|
||||
), [handlePressItem, handleFavorite, cardWidth, gap]);
|
||||
|
||||
const keyExtractor = useCallback((item: TradeItemDTO) => item.id, []);
|
||||
|
||||
if (isLoading) {
|
||||
return <Loading fullScreen />;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<FlashList
|
||||
ref={flashListRef as any}
|
||||
data={items}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={keyExtractor}
|
||||
numColumns={numColumns}
|
||||
key={`market_${numColumns}`}
|
||||
contentContainerStyle={styles.listContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={isRefreshing}
|
||||
onRefresh={() => fetchItems(true)}
|
||||
colors={[colors.primary.main]}
|
||||
tintColor={colors.primary.main}
|
||||
/>
|
||||
}
|
||||
onEndReached={loadMore}
|
||||
onEndReachedThreshold={0.3}
|
||||
ListEmptyComponent={
|
||||
<EmptyState
|
||||
title="暂无商品"
|
||||
description="还没有人发布商品,快来发布第一条吧"
|
||||
/>
|
||||
}
|
||||
ListFooterComponent={isLoadingMore ? <Loading size="sm" /> : null}
|
||||
drawDistance={250}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -1472,7 +1472,7 @@ export const PostDetailScreen: React.FC = () => {
|
||||
<TouchableOpacity style={styles.bottomActionItem} onPress={handleLike}>
|
||||
<MaterialCommunityIcons
|
||||
name={post?.is_liked ? 'thumb-up' : 'thumb-up-outline'}
|
||||
size={isDesktop ? 23 : 21}
|
||||
size={isDesktop ? 26 : 24}
|
||||
color={post?.is_liked ? colors.primary.main : colors.text.secondary}
|
||||
/>
|
||||
<Text variant="caption" style={styles.bottomActionCount}>
|
||||
@@ -1483,7 +1483,7 @@ export const PostDetailScreen: React.FC = () => {
|
||||
<TouchableOpacity style={styles.bottomActionItem} onPress={handleFavorite}>
|
||||
<MaterialCommunityIcons
|
||||
name={post?.is_favorited ? 'star' : 'star-outline'}
|
||||
size={isDesktop ? 23 : 21}
|
||||
size={isDesktop ? 26 : 24}
|
||||
color={post?.is_favorited ? colors.warning.main : colors.text.secondary}
|
||||
/>
|
||||
<Text variant="caption" style={styles.bottomActionCount}>
|
||||
@@ -1492,7 +1492,7 @@ export const PostDetailScreen: React.FC = () => {
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={styles.bottomActionItem} onPress={handleShare}>
|
||||
<MaterialCommunityIcons name="share-outline" size={isDesktop ? 23 : 21} color={colors.text.secondary} />
|
||||
<MaterialCommunityIcons name="share-outline" size={isDesktop ? 26 : 24} color={colors.text.secondary} />
|
||||
<Text variant="caption" style={styles.bottomActionCount}>
|
||||
{formatNumber(post?.shares_count || 0)}
|
||||
</Text>
|
||||
@@ -2153,7 +2153,7 @@ function createPostDetailStyles(colors: AppColors) {
|
||||
borderRadius: 20,
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingVertical: spacing.sm + 2,
|
||||
minHeight: 40,
|
||||
minHeight: 44,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
inputTriggerText: {
|
||||
@@ -2163,14 +2163,14 @@ function createPostDetailStyles(colors: AppColors) {
|
||||
bottomComposerRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.xs + 2,
|
||||
gap: spacing.xs,
|
||||
},
|
||||
bottomActionItem: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: 2,
|
||||
paddingHorizontal: spacing.sm + 1,
|
||||
marginLeft: spacing.xs,
|
||||
paddingHorizontal: spacing.sm,
|
||||
marginLeft: 0,
|
||||
},
|
||||
bottomActionCount: {
|
||||
marginTop: 1,
|
||||
|
||||
Reference in New Issue
Block a user