Browse Source

搜索页样式调整

main
Mac 2 months ago
parent
commit
093461c258
  1. 18
      app/components/SearchIcon.tsx
  2. 2
      app/i18n/index.ts
  3. 39
      app/screens/ProductDetailScreen.tsx
  4. 384
      app/screens/SearchResultScreen.tsx
  5. 6
      app/screens/SearchScreen.tsx
  6. 6
      app/types/svg.d.ts
  7. 7
      app/utils/isSmallScreen.ts
  8. BIN
      assets/ 2/5000 favorable.png
  9. BIN
      assets/back.png
  10. BIN
      assets/camera.png
  11. BIN
      assets/vip.png
  12. 811
      package-lock.json
  13. 2
      package.json
  14. 1103
      yarn.lock

18
app/components/SearchIcon.tsx

@ -0,0 +1,18 @@
import { Svg, Path, G, ClipPath, Rect, Defs } from 'react-native-svg';
const SearchIcon = ({ color = "#373737", size = 20 }) => (
<Svg width={size} height={size} viewBox="0 0 20 20" fill="none">
<Defs>
<ClipPath id="clip0_121_22">
<Rect width="20" height="20" fill="white" />
</ClipPath>
</Defs>
<G clipPath="url(#clip0_121_22)">
<Path
d="M15.13 16.91C11.44 19.73 6.13 19.46 2.76 16.08C-0.92 12.4 -0.92 6.44 2.76 2.76C6.44 -0.92 12.4 -0.92 16.08 2.76C19.46 6.14 19.73 11.44 16.91 15.13L19.63 17.85C20.1 18.36 20.08 19.15 19.57 19.63C19.09 20.08 18.34 20.08 17.85 19.63L15.13 16.91ZM4.53 14.3C7.23 17 11.6 17 14.3 14.3C17 11.6 17 7.23 14.3 4.53C11.6 1.83 7.23 1.83 4.53 4.53C1.83 7.23 1.84 11.61 4.53 14.3Z"
fill={color}
/>
</G>
</Svg>
);
export default SearchIcon;

2
app/i18n/index.ts

@ -71,7 +71,7 @@ const resources = {
tryDifferentKeywords: 'Try using different keywords or check your spelling',
loadingMore: 'Loading more...',
noMoreData: 'No more data',
monthlySales: 'Monthly Sales',
monthlySales: 'ventes',
// Search Screen
search: 'Search',
searchPlaceholder: 'Search products',

39
app/screens/ProductDetailScreen.tsx

@ -18,6 +18,7 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { RouteProp } from '@react-navigation/native';
import { productApi, ProductDetailParams } from '../services/api/productApi';
import { useTranslation } from 'react-i18next';
import isSmallScreen from '../utils/isSmallScreen';
// 获取屏幕宽度
const { width: screenWidth } = Dimensions.get('window');
@ -449,7 +450,7 @@ const styles = StyleSheet.create({
},
headerTitle: {
flex: 1,
fontSize: 16,
fontSize: isSmallScreen ? 14 : 16,
fontWeight: 'bold',
color: '#333',
textAlign: 'center',
@ -479,7 +480,7 @@ const styles = StyleSheet.create({
justifyContent: 'center',
},
imagePlaceholderText: {
fontSize: 16,
fontSize: isSmallScreen ? 14 : 16,
color: '#999',
},
paginationContainer: {
@ -514,12 +515,12 @@ const styles = StyleSheet.create({
marginBottom: 10,
},
productPrice: {
fontSize: 24,
fontSize: isSmallScreen ? 14 : 24,
fontWeight: 'bold',
color: '#ff6600',
},
originalPrice: {
fontSize: 16,
fontSize: isSmallScreen ? 12 : 16,
color: '#999',
textDecorationLine: 'line-through',
marginLeft: 8,
@ -533,7 +534,7 @@ const styles = StyleSheet.create({
},
discountText: {
color: '#fff',
fontSize: 12,
fontSize: isSmallScreen ? 12 : 16,
fontWeight: 'bold',
},
vipBadge: {
@ -549,12 +550,12 @@ const styles = StyleSheet.create({
fontWeight: 'bold',
},
productTitle: {
fontSize: 16,
fontSize: isSmallScreen ? 14 : 16,
color: '#333',
marginBottom: 8,
},
productSales: {
fontSize: 12,
fontSize: isSmallScreen ? 12 : 16,
color: '#999',
marginBottom: 15,
},
@ -562,7 +563,7 @@ const styles = StyleSheet.create({
marginTop: 15,
},
optionTitle: {
fontSize: 14,
fontSize: isSmallScreen ? 12 : 16,
fontWeight: 'bold',
color: '#333',
marginBottom: 10,
@ -593,7 +594,7 @@ const styles = StyleSheet.create({
marginRight: 6,
},
colorName: {
fontSize: 12,
fontSize: isSmallScreen ? 12 : 16,
color: '#333',
},
moreColorsButton: {
@ -607,7 +608,7 @@ const styles = StyleSheet.create({
marginBottom: 10,
},
moreColorsText: {
fontSize: 12,
fontSize: isSmallScreen ? 12 : 16,
color: '#333',
},
sizeOptions: {
@ -628,7 +629,7 @@ const styles = StyleSheet.create({
backgroundColor: '#fff8f5',
},
sizeText: {
fontSize: 12,
fontSize: isSmallScreen ? 12 : 16,
color: '#333',
},
sizeTextSelected: {
@ -656,7 +657,7 @@ const styles = StyleSheet.create({
alignItems: 'center',
},
viewAllText: {
fontSize: 12,
fontSize: isSmallScreen ? 12 : 16,
color: '#0066ff',
},
relatedProductsContainer: {
@ -676,7 +677,7 @@ const styles = StyleSheet.create({
marginBottom: 5,
},
relatedProductPrice: {
fontSize: 14,
fontSize: isSmallScreen ? 12 : 16,
fontWeight: 'bold',
color: '#ff6600',
},
@ -687,13 +688,13 @@ const styles = StyleSheet.create({
paddingVertical: 10,
},
loadMoreText: {
fontSize: 12,
fontSize: isSmallScreen ? 12 : 16,
color: '#666',
marginLeft: 8,
},
noMoreProductsText: {
textAlign: 'center',
fontSize: 12,
fontSize: isSmallScreen ? 12 : 16,
color: '#999',
paddingVertical: 10,
},
@ -721,7 +722,7 @@ const styles = StyleSheet.create({
alignItems: 'center',
},
detailPlaceholderText: {
fontSize: 16,
fontSize: isSmallScreen ? 12 : 16,
color: '#999',
},
bottomSpace: {
@ -746,7 +747,7 @@ const styles = StyleSheet.create({
marginRight: 15,
},
chatButtonText: {
fontSize: 10,
fontSize: isSmallScreen ? 10 : 16,
color: '#666',
marginTop: 2,
},
@ -781,7 +782,7 @@ const styles = StyleSheet.create({
alignItems: 'center',
},
loadingText: {
fontSize: 16,
fontSize: isSmallScreen ? 12 : 16,
color: '#666',
marginTop: 10,
},
@ -792,7 +793,7 @@ const styles = StyleSheet.create({
padding: 20,
},
errorText: {
fontSize: 18,
fontSize: isSmallScreen ? 12 : 16,
fontWeight: 'bold',
color: '#333',
marginTop: 15,

384
app/screens/SearchResultScreen.tsx

@ -23,7 +23,13 @@ import {
ProductParams,
type Product,
} from "../services/api/productApi";
import { useTranslation } from 'react-i18next';
import { useTranslation } from "react-i18next";
import isSmallScreen from "../utils/isSmallScreen";
import { Svg, Path } from 'react-native-svg';
import SearchIcon from "../components/SearchIcon";
// @ts-ignore
import vipIcon from "../../assets/vip.png";
// 图标组件 - 使用React.memo优化渲染
const IconComponent = React.memo(
@ -33,60 +39,85 @@ const IconComponent = React.memo(
}
);
// 路由参数类型
type SearchResultRouteParams = {
keyword: string;
};
// 懒加载图片组件
const LazyImage = React.memo(({ uri, style, resizeMode }: { uri: string, style: any, resizeMode: any }) => {
const [isVisible, setIsVisible] = useState(false);
const [hasError, setHasError] = useState(false);
// // 缩略图处理 - 为原图创建更低质量的缩略版本以更快加载
// const getThumbnailUrl = useCallback((originalUrl: string) => {
// // 如果有可能,使用CDN参数来获取更小的图片
// // 这里是一个简单的实现,实际上需要根据具体的CDN服务来调整
// if (originalUrl.includes('?')) {
// return `${originalUrl}&quality=10&width=100`;
// }
// return `${originalUrl}?quality=10&width=100`;
// }, []);
const onError = useCallback(() => {
setHasError(true);
}, []);
// 使用IntersectionObserver的替代方案,在组件挂载时显示图片
useEffect(() => {
// 延迟一小段时间后开始加载图片
const timer = setTimeout(() => {
const LazyImage = React.memo(
({
uri,
style,
resizeMode,
}: {
uri: string;
style: any;
resizeMode: any;
}) => {
const [isVisible, setIsVisible] = useState(false);
const [hasError, setHasError] = useState(false);
// // 缩略图处理 - 为原图创建更低质量的缩略版本以更快加载
// const getThumbnailUrl = useCallback((originalUrl: string) => {
// // 如果有可能,使用CDN参数来获取更小的图片
// // 这里是一个简单的实现,实际上需要根据具体的CDN服务来调整
// if (originalUrl.includes('?')) {
// return `${originalUrl}&quality=10&width=100`;
// }
// return `${originalUrl}?quality=10&width=100`;
// }, []);
const onError = useCallback(() => {
setHasError(true);
}, []);
// 使用IntersectionObserver的替代方案,在组件挂载时显示图片
useEffect(() => {
// 延迟一小段时间后开始加载图片
setIsVisible(true);
}, 100);
return () => clearTimeout(timer);
}, []);
return (
<View style={[style, { backgroundColor: '#f9f9f9', overflow: 'hidden' }]}>
{hasError && (
<View style={[style, { justifyContent: 'center', alignItems: 'center', backgroundColor: '#f5f5f5' }]}>
<IconComponent name="image-outline" size={24} color="#999" />
<Text style={{ fontSize: 12, color: '#999', marginTop: 4 }}></Text>
</View>
)}
{isVisible && !hasError && (
<Image
source={{ uri }}
style={style}
resizeMode={resizeMode}
onError={onError}
/>
)}
</View>
);
});
}, []);
return (
<View style={[style, { backgroundColor: "#f9f9f9", overflow: "hidden" }]}>
{hasError && (
<View
style={[
style,
{
justifyContent: "center",
alignItems: "center",
backgroundColor: "#f5f5f5",
},
]}
>
<IconComponent name="image-outline" size={24} color="#999" />
<Text
style={{
fontSize: isSmallScreen ? 12 : 14,
color: "#999",
marginTop: 4,
}}
>
</Text>
</View>
)}
{isVisible && !hasError && (
<Image
source={{ uri }}
style={style}
resizeMode={resizeMode}
onError={onError}
/>
)}
</View>
);
}
);
// 产品项组件 - 使用React.memo优化渲染
const ProductItem = React.memo(
@ -114,6 +145,10 @@ const ProductItem = React.memo(
) : (
<Text style={styles.placeholderText}>product picture</Text>
)}
<Image
source={vipIcon}
style={styles.vipIcon}
/>
</View>
{/* 产品分类 */}
<View style={styles.productInfo}>
@ -123,7 +158,8 @@ const ProductItem = React.memo(
{/* 价格信息 */}
<View style={styles.priceRow}>
<Text style={styles.currentPrice}>
{product?.min_price?.toFixed(0)} <Text style={styles.currency}>FCFA</Text>
{product?.min_price?.toFixed(0)}{" "}
<Text style={styles.currency}>FCFA</Text>
</Text>
<Text style={styles.originalPrice}>
3000<Text style={styles.currencySmall}>FCFA</Text>
@ -131,13 +167,14 @@ const ProductItem = React.memo(
</View>
{/* 销售量 */}
<Text style={styles.productSales}>
{t('monthlySales')}: {product.sold_out}
{product.sold_out}+ {t("monthlySales")}
</Text>
</View>
</TouchableOpacity>
)
);
export const SearchResultScreen = () => {
const { t } = useTranslation();
const navigation = useNavigation<NativeStackNavigationProp<any>>();
@ -154,7 +191,9 @@ export const SearchResultScreen = () => {
const [sortField, setSortField] = useState<"price" | "time">("price");
const [showBackToTop, setShowBackToTop] = useState(false);
const flatListRef = useRef<FlatList>(null);
const [activeTab, setActiveTab] = useState<"default" | "volume" | "price">("default");
const [activeTab, setActiveTab] = useState<"default" | "volume" | "price">(
"default"
);
const [searchParams, setSearchParams] = useState<ProductParams>({
keyword: route.params?.keyword || "",
@ -211,7 +250,7 @@ export const SearchResultScreen = () => {
setSortOrder(null);
// 重置到默认标签
setActiveTab("default");
const newParams = {
...searchParams,
keyword: searchText.trim(),
@ -251,11 +290,9 @@ export const SearchResultScreen = () => {
<View style={styles.emptyContainer}>
<IconComponent name="search-outline" size={48} color="#ccc" />
<Text style={styles.emptyText}>
{t('noResults')} "{searchText}"
</Text>
<Text style={styles.emptySubtext}>
{t('tryDifferentKeywords')}
{t("noResults")} "{searchText}"
</Text>
<Text style={styles.emptySubtext}>{t("tryDifferentKeywords")}</Text>
</View>
),
[searchText, t]
@ -270,7 +307,10 @@ export const SearchResultScreen = () => {
);
// 创建产品列表项的key提取器
const keyExtractor = useCallback((item: Product) => String(item.offer_id), []);
const keyExtractor = useCallback(
(item: Product) => String(item.offer_id),
[]
);
// 处理排序
const handleSort = useCallback(
@ -322,7 +362,7 @@ export const SearchResultScreen = () => {
if (!hasMore)
return (
<View style={styles.footerContainer}>
<Text style={styles.footerText}>{t('noMoreData')}</Text>
<Text style={styles.footerText}>{t("noMoreData")}</Text>
</View>
);
@ -330,7 +370,7 @@ export const SearchResultScreen = () => {
return (
<View style={styles.footerContainer}>
<ActivityIndicator size="small" color="#0066FF" />
<Text style={styles.footerText}>{t('loadingMore')}</Text>
<Text style={styles.footerText}>{t("loadingMore")}</Text>
</View>
);
@ -350,38 +390,41 @@ export const SearchResultScreen = () => {
}, []);
// 处理标签切换
const handleTabChange = useCallback((tab: "default" | "volume" | "price") => {
// 如果点击的是已经激活的价格标签,则切换排序顺序
if (tab === "price" && activeTab === "price") {
// 如果当前是价格升序,则切换为降序;如果是降序或未设置,则切换为升序
const newOrder = sortOrder === "asc" ? "desc" : "asc";
handleSort("price", newOrder);
scrollToTop();
} else {
setActiveTab(tab);
// 根据标签类型设置排序规则
if (tab === "price") {
// 默认价格从低到高
handleSort("price", "asc");
scrollToTop();
} else if (tab === "volume") {
// 按销量排序
const sortedProducts = [...originalProducts];
sortedProducts.sort((a, b) => {
const volumeA = a.sold_out || 0;
const volumeB = b.sold_out || 0;
return volumeB - volumeA; // 从高到低排序
});
setProducts(sortedProducts);
const handleTabChange = useCallback(
(tab: "default" | "volume" | "price") => {
// 如果点击的是已经激活的价格标签,则切换排序顺序
if (tab === "price" && activeTab === "price") {
// 如果当前是价格升序,则切换为降序;如果是降序或未设置,则切换为升序
const newOrder = sortOrder === "asc" ? "desc" : "asc";
handleSort("price", newOrder);
scrollToTop();
} else {
// 默认排序 - 恢复到原始数据顺序
setProducts([...originalProducts]);
scrollToTop();
setActiveTab(tab);
// 根据标签类型设置排序规则
if (tab === "price") {
// 默认价格从低到高
handleSort("price", "asc");
scrollToTop();
} else if (tab === "volume") {
// 按销量排序
const sortedProducts = [...originalProducts];
sortedProducts.sort((a, b) => {
const volumeA = a.sold_out || 0;
const volumeB = b.sold_out || 0;
return volumeB - volumeA; // 从高到低排序
});
setProducts(sortedProducts);
scrollToTop();
} else {
// 默认排序 - 恢复到原始数据顺序
setProducts([...originalProducts]);
scrollToTop();
}
}
}
}, [handleSort, activeTab, sortOrder, originalProducts, scrollToTop]);
},
[handleSort, activeTab, sortOrder, originalProducts, scrollToTop]
);
return (
<SafeAreaView style={styles.safeArea}>
@ -393,13 +436,21 @@ export const SearchResultScreen = () => {
{/* 搜索栏 */}
<View style={styles.searchHeader}>
<TouchableOpacity style={styles.backButton} onPress={goBack}>
<IconComponent name="arrow-back" size={24} color="#333" />
<Svg width="11" height="18" viewBox="0 0 11 18" fill="none">
<Path
d="M8.52018 17.1171L10.0867 15.6172L3.19348 8.93139L10.2127 2.37801L8.67501 0.848572L0.0893813 8.90185L8.52018 17.1171Z"
fill={"black"} // 动态修改颜色
/>
</Svg>
</TouchableOpacity>
<View style={styles.searchBar}>
<IconComponent name="search-outline" size={18} color="#999" />
<View style={{marginRight: 8,marginLeft: 4}}>
<SearchIcon color="#373737" size={20} />
</View>
<TextInput
style={styles.searchInput}
placeholder={t('searchProducts')}
placeholder={t("searchProducts")}
placeholderTextColor="#999"
value={searchText}
onChangeText={setSearchText}
@ -407,7 +458,7 @@ export const SearchResultScreen = () => {
onSubmitEditing={handleSearch}
/>
{searchText.length > 0 && (
<TouchableOpacity
<TouchableOpacity
onPress={() => setSearchText("")}
style={styles.clearButton}
>
@ -416,41 +467,65 @@ export const SearchResultScreen = () => {
)}
</View>
<TouchableOpacity style={styles.searchButton} onPress={handleSearch}>
<Text style={styles.searchButtonText}>{t('cancel')}</Text>
<Text style={styles.searchButtonText}>{t("cancel")}</Text>
</TouchableOpacity>
</View>
{/* 标签筛选 */}
<View style={styles.tabContainer}>
<TouchableOpacity
style={[styles.tabButton, activeTab === "default" && styles.activeTabButton]}
<TouchableOpacity
style={[
styles.tabButton,
activeTab === "default" && styles.activeTabButton,
]}
onPress={() => handleTabChange("default")}
>
<Text style={[styles.tabText, activeTab === "default" && styles.activeTabText]}>
{t('default')}
<Text
style={[
styles.tabText,
activeTab === "default" && styles.activeTabText,
]}
>
{t("default")}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.tabButton, activeTab === "volume" && styles.activeTabButton]}
<TouchableOpacity
style={[
styles.tabButton,
activeTab === "volume" && styles.activeTabButton,
]}
onPress={() => handleTabChange("volume")}
>
<Text style={[styles.tabText, activeTab === "volume" && styles.activeTabText]}>
{t('volume')}
<Text
style={[
styles.tabText,
activeTab === "volume" && styles.activeTabText,
]}
>
{t("volume")}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.tabButton, activeTab === "price" && styles.activeTabButton]}
<TouchableOpacity
style={[
styles.tabButton,
activeTab === "price" && styles.activeTabButton,
]}
onPress={() => handleTabChange("price")}
>
<View style={styles.tabButtonContent}>
<Text style={[styles.tabText, activeTab === "price" && styles.activeTabText]}>
{t('price')}
<Text
style={[
styles.tabText,
activeTab === "price" && styles.activeTabText,
]}
>
{t("price")}
</Text>
{activeTab === "price" && (
<View style={styles.tabIcon}>
<IconComponent
name={sortOrder === "desc" ? "chevron-down" : "chevron-up"}
size={16}
<IconComponent
name={sortOrder === "desc" ? "chevron-down" : "chevron-up"}
size={16}
color="#000"
/>
</View>
@ -470,7 +545,7 @@ export const SearchResultScreen = () => {
style={styles.sortScrollView}
>
<View style={styles.sortGroup}>
<Text style={styles.sortLabel}>{t('price')}:</Text>
<Text style={styles.sortLabel}>{t("price")}:</Text>
<View style={styles.sortButtons}>
<TouchableOpacity
style={[
@ -489,7 +564,7 @@ export const SearchResultScreen = () => {
: {},
]}
>
{t('lowToHigh')}
{t("lowToHigh")}
</Text>
{sortField === "price" && sortOrder === "asc" && (
<IconComponent
@ -516,7 +591,7 @@ export const SearchResultScreen = () => {
: {},
]}
>
{t('highToLow')}
{t("highToLow")}
</Text>
{sortField === "price" && sortOrder === "desc" && (
<IconComponent
@ -532,7 +607,7 @@ export const SearchResultScreen = () => {
<View style={styles.sortDivider} />
<View style={styles.sortGroup}>
<Text style={styles.sortLabel}>{t('time')}:</Text>
<Text style={styles.sortLabel}>{t("time")}:</Text>
<View style={styles.sortButtons}>
<TouchableOpacity
style={[
@ -551,7 +626,7 @@ export const SearchResultScreen = () => {
: {},
]}
>
{t('oldest')}
{t("oldest")}
</Text>
{sortField === "time" && sortOrder === "asc" && (
<IconComponent
@ -578,7 +653,7 @@ export const SearchResultScreen = () => {
: {},
]}
>
{t('newest')}
{t("newest")}
</Text>
{sortField === "time" && sortOrder === "desc" && (
<IconComponent
@ -614,7 +689,7 @@ export const SearchResultScreen = () => {
initialNumToRender={4}
maxToRenderPerBatch={8}
windowSize={3}
removeClippedSubviews={Platform.OS !== 'web'}
removeClippedSubviews={Platform.OS !== "web"}
updateCellsBatchingPeriod={50}
onEndReached={handleLoadMore}
onEndReachedThreshold={0.5}
@ -645,7 +720,7 @@ const styles = StyleSheet.create({
},
container: {
flex: 1,
backgroundColor: "#f5f5f5",
backgroundColor: "#ffffff",
},
searchHeader: {
flexDirection: "row",
@ -673,7 +748,7 @@ const styles = StyleSheet.create({
searchInput: {
flex: 1,
marginLeft: 4,
fontSize: 16,
fontSize: isSmallScreen ? 14 : 16,
color: "#333",
height: 40,
paddingRight: 32,
@ -690,7 +765,7 @@ const styles = StyleSheet.create({
paddingHorizontal: 8,
},
searchButtonText: {
fontSize: 16,
fontSize: isSmallScreen ? 14 : 16,
color: "#333",
fontWeight: "500",
},
@ -716,15 +791,15 @@ const styles = StyleSheet.create({
marginLeft: 4,
},
tabText: {
fontSize: 14,
color: "#666",
fontSize: isSmallScreen ? 12 : 16,
color: "#000",
},
activeTabText: {
color: "#000",
color: "#0933a1",
fontWeight: "bold",
},
activeTabButton: {
// borderBottomColor: "#007AFF",
// borderBottomColor: "#0933a1",
},
resultsContainer: {
flex: 1,
@ -749,17 +824,9 @@ const styles = StyleSheet.create({
backgroundColor: "#fff",
borderRadius: 8,
overflow: "hidden",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
productImageContainer: {
height: 150,
height: 190,
backgroundColor: "#f9f9f9",
alignItems: "center",
justifyContent: "center",
@ -770,49 +837,51 @@ const styles = StyleSheet.create({
},
placeholderText: {
color: "#999",
fontSize: 16,
fontSize: isSmallScreen ? 12 : 14,
},
productInfo: {
padding: 8,
},
categoryText: {
fontSize: 14,
fontSize: isSmallScreen ? 12 : 14,
color: "#000000",
fontWeight: "600",
marginBottom: 4,
fontFamily: 'PingFang SC'
fontFamily: "PingFang SC",
letterSpacing: 0,
},
priceRow: {
flexDirection: "row",
alignItems: "baseline",
marginBottom: 4,
marginBottom: 2,
},
currentPrice: {
fontSize: 24,
fontSize: isSmallScreen ? 12 : 24,
fontWeight: "600",
color: "#ff6600",
marginRight: 4,
},
currency: {
fontSize: 15,
fontSize: isSmallScreen ? 12 : 14,
fontWeight: "600",
fontFamily: 'PingFang SC',
fontFamily: "PingFang SC",
color: "#ff6600",
},
originalPrice: {
fontSize: 14,
fontSize: isSmallScreen ? 10 : 14,
color: "#999",
textDecorationLine: "line-through",
},
currencySmall: {
fontSize: 16,
color: '#9a9a9a',
fontSize: isSmallScreen ? 12 : 14,
color: "#9a9a9a",
fontWeight: "600",
fontFamily: 'PingFang SC',
fontFamily: "PingFang SC",
},
productSales: {
fontSize: 16,
fontSize: isSmallScreen ? 12 : 14,
fontWeight: "600",
fontFamily: 'PingFang SC',
fontFamily: "PingFang SC",
color: "#7c7c7c",
},
sortScrollView: {
@ -824,7 +893,7 @@ const styles = StyleSheet.create({
paddingHorizontal: 16,
},
sortLabel: {
fontSize: 14,
fontSize: isSmallScreen ? 12 : 16,
color: "#666",
marginRight: 8,
},
@ -847,7 +916,7 @@ const styles = StyleSheet.create({
backgroundColor: "#fff8f5",
},
sortButtonText: {
fontSize: 12,
fontSize: isSmallScreen ? 12 : 14,
color: "#666",
},
sortButtonTextActive: {
@ -867,7 +936,7 @@ const styles = StyleSheet.create({
justifyContent: "center",
},
footerText: {
fontSize: 14,
fontSize: isSmallScreen ? 12 : 14,
color: "#666",
marginLeft: 8,
},
@ -901,25 +970,25 @@ const styles = StyleSheet.create({
padding: 16,
},
emptyText: {
fontSize: 16,
fontSize: isSmallScreen ? 12 : 14,
fontWeight: "bold",
color: "#333",
marginTop: 16,
marginBottom: 8,
},
emptySubtext: {
fontSize: 14,
fontSize: isSmallScreen ? 12 : 14,
color: "#999",
textAlign: "center",
},
resultsTitle: {
fontSize: 16,
fontSize: isSmallScreen ? 12 : 14,
fontWeight: "bold",
color: "#333",
flex: 1,
},
resultsCount: {
fontSize: 14,
fontSize: isSmallScreen ? 12 : 14,
color: "#999",
},
filterButton: {
@ -927,8 +996,15 @@ const styles = StyleSheet.create({
padding: 4,
},
imagePlaceholder: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f5f5f5',
justifyContent: "center",
alignItems: "center",
backgroundColor: "#f5f5f5",
},
vipIcon: {
position: 'absolute',
top: 0,
right: 0,
width: 66,
height: 30,
},
});

6
app/screens/SearchScreen.tsx

@ -15,7 +15,7 @@ import Ionicons from '@expo/vector-icons/Ionicons';
import { useNavigation, useFocusEffect } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useTranslation } from 'react-i18next';
import SearchIcon from "../components/SearchIcon";
// 图标组件 - 使用React.memo优化渲染
const IconComponent = React.memo(({ name, size, color }: { name: string; size: number; color: string }) => {
const Icon = Ionicons as any;
@ -202,7 +202,9 @@ export const SearchScreen = () => {
{/* 搜索栏 */}
<View style={styles.searchHeader}>
<View style={styles.searchBar}>
<IconComponent name="search-outline" size={20} color="#777" />
<View style={{marginRight: 8,marginLeft: 4}}>
<SearchIcon color="#373737" size={20} />
</View>
<TextInput
style={styles.searchInput}
placeholder={t('searchPlaceholder')}

6
app/types/svg.d.ts vendored

@ -0,0 +1,6 @@
declare module "*.svg" {
import React from "react";
import { SvgProps } from "react-native-svg";
const content: React.FC<SvgProps>;
export default content;
}

7
app/utils/isSmallScreen.ts

@ -0,0 +1,7 @@
import { Dimensions } from 'react-native';
const { width } = Dimensions.get('window');
const isSmallScreen = width <= 375;
console.log(width);
export default isSmallScreen;

BIN
assets/ 2/5000 favorable.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
assets/back.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

BIN
assets/camera.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

BIN
assets/vip.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

811
package-lock.json generated

@ -27,6 +27,7 @@
"react-native-responsive-fontsize": "^0.5.1",
"react-native-safe-area-context": "^5.3.0",
"react-native-screens": "^4.10.0",
"react-native-svg": "^15.11.2",
"react-native-vector-icons": "^10.2.0",
"react-native-web": "~0.19.13"
},
@ -35,6 +36,7 @@
"@hancleee/babel-plugin-react-native-pxtodp": "^1.0.8",
"@types/react": "~18.3.12",
"@types/react-native-vector-icons": "^6.4.18",
"react-native-svg-transformer": "^1.5.0",
"typescript": "^5.3.3"
}
},
@ -3660,6 +3662,462 @@
"@sinonjs/commons": "^3.0.0"
}
},
"node_modules/@svgr/babel-plugin-add-jsx-attribute": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz",
"integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@svgr/babel-plugin-remove-jsx-attribute": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz",
"integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz",
"integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz",
"integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@svgr/babel-plugin-svg-dynamic-title": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz",
"integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@svgr/babel-plugin-svg-em-dimensions": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz",
"integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@svgr/babel-plugin-transform-react-native-svg": {
"version": "8.1.0",
"resolved": "https://registry.npmmirror.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz",
"integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@svgr/babel-plugin-transform-svg-component": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz",
"integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@svgr/babel-preset": {
"version": "8.1.0",
"resolved": "https://registry.npmmirror.com/@svgr/babel-preset/-/babel-preset-8.1.0.tgz",
"integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==",
"dev": true,
"license": "MIT",
"dependencies": {
"@svgr/babel-plugin-add-jsx-attribute": "8.0.0",
"@svgr/babel-plugin-remove-jsx-attribute": "8.0.0",
"@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0",
"@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0",
"@svgr/babel-plugin-svg-dynamic-title": "8.0.0",
"@svgr/babel-plugin-svg-em-dimensions": "8.0.0",
"@svgr/babel-plugin-transform-react-native-svg": "8.1.0",
"@svgr/babel-plugin-transform-svg-component": "8.0.0"
},
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@svgr/core": {
"version": "8.1.0",
"resolved": "https://registry.npmmirror.com/@svgr/core/-/core-8.1.0.tgz",
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.21.3",
"@svgr/babel-preset": "8.1.0",
"camelcase": "^6.2.0",
"cosmiconfig": "^8.1.3",
"snake-case": "^3.0.4"
},
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
}
},
"node_modules/@svgr/core/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0"
},
"node_modules/@svgr/core/node_modules/camelcase": {
"version": "6.3.0",
"resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-6.3.0.tgz",
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@svgr/core/node_modules/cosmiconfig": {
"version": "8.3.6",
"resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz",
"integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==",
"dev": true,
"license": "MIT",
"dependencies": {
"import-fresh": "^3.3.0",
"js-yaml": "^4.1.0",
"parse-json": "^5.2.0",
"path-type": "^4.0.0"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/d-fischer"
},
"peerDependencies": {
"typescript": ">=4.9.5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@svgr/core/node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
"resolve-from": "^4.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@svgr/core/node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/@svgr/core/node_modules/parse-json": {
"version": "5.2.0",
"resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.0.0",
"error-ex": "^1.3.1",
"json-parse-even-better-errors": "^2.3.0",
"lines-and-columns": "^1.1.6"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@svgr/core/node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/@svgr/hast-util-to-babel-ast": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz",
"integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.21.3",
"entities": "^4.4.0"
},
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
}
},
"node_modules/@svgr/plugin-jsx": {
"version": "8.1.0",
"resolved": "https://registry.npmmirror.com/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz",
"integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.21.3",
"@svgr/babel-preset": "8.1.0",
"@svgr/hast-util-to-babel-ast": "8.0.0",
"svg-parser": "^2.0.4"
},
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"@svgr/core": "*"
}
},
"node_modules/@svgr/plugin-svgo": {
"version": "8.1.0",
"resolved": "https://registry.npmmirror.com/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz",
"integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==",
"dev": true,
"license": "MIT",
"dependencies": {
"cosmiconfig": "^8.1.3",
"deepmerge": "^4.3.1",
"svgo": "^3.0.2"
},
"engines": {
"node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
"@svgr/core": "*"
}
},
"node_modules/@svgr/plugin-svgo/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0"
},
"node_modules/@svgr/plugin-svgo/node_modules/cosmiconfig": {
"version": "8.3.6",
"resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz",
"integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==",
"dev": true,
"license": "MIT",
"dependencies": {
"import-fresh": "^3.3.0",
"js-yaml": "^4.1.0",
"parse-json": "^5.2.0",
"path-type": "^4.0.0"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/d-fischer"
},
"peerDependencies": {
"typescript": ">=4.9.5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@svgr/plugin-svgo/node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
"resolve-from": "^4.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@svgr/plugin-svgo/node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/@svgr/plugin-svgo/node_modules/parse-json": {
"version": "5.2.0",
"resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.0.0",
"error-ex": "^1.3.1",
"json-parse-even-better-errors": "^2.3.0",
"lines-and-columns": "^1.1.6"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@svgr/plugin-svgo/node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmmirror.com/@trysound/sax/-/sax-0.2.0.tgz",
"integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmmirror.com/@types/babel__core/-/babel__core-7.20.5.tgz",
@ -4353,6 +4811,12 @@
"node": ">=0.6"
}
},
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
"license": "ISC"
},
"node_modules/bplist-creator": {
"version": "0.0.7",
"resolved": "https://registry.npmmirror.com/bplist-creator/-/bplist-creator-0.0.7.tgz",
@ -5046,6 +5510,92 @@
"hyphenate-style-name": "^1.0.3"
}
},
"node_modules/css-select": {
"version": "5.1.0",
"resolved": "https://registry.npmmirror.com/css-select/-/css-select-5.1.0.tgz",
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
"license": "BSD-2-Clause",
"dependencies": {
"boolbase": "^1.0.0",
"css-what": "^6.1.0",
"domhandler": "^5.0.2",
"domutils": "^3.0.1",
"nth-check": "^2.0.1"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/css-tree": {
"version": "1.1.3",
"resolved": "https://registry.npmmirror.com/css-tree/-/css-tree-1.1.3.tgz",
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
"license": "MIT",
"dependencies": {
"mdn-data": "2.0.14",
"source-map": "^0.6.1"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/css-tree/node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/css-what": {
"version": "6.1.0",
"resolved": "https://registry.npmmirror.com/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">= 6"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/csso": {
"version": "5.0.5",
"resolved": "https://registry.npmmirror.com/csso/-/csso-5.0.5.tgz",
"integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"css-tree": "~2.2.0"
},
"engines": {
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/csso/node_modules/css-tree": {
"version": "2.2.1",
"resolved": "https://registry.npmmirror.com/css-tree/-/css-tree-2.2.1.tgz",
"integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==",
"dev": true,
"license": "MIT",
"dependencies": {
"mdn-data": "2.0.28",
"source-map-js": "^1.0.1"
},
"engines": {
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/csso/node_modules/mdn-data": {
"version": "2.0.28",
"resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.28.tgz",
"integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
"dev": true,
"license": "CC0-1.0"
},
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz",
@ -5314,6 +5864,72 @@
"node": ">=8"
}
},
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "BSD-2-Clause"
},
"node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmmirror.com/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"license": "BSD-2-Clause",
"dependencies": {
"domelementtype": "^2.3.0"
},
"engines": {
"node": ">= 4"
},
"funding": {
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/domutils": {
"version": "3.2.2",
"resolved": "https://registry.npmmirror.com/domutils/-/domutils-3.2.2.tgz",
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
"license": "BSD-2-Clause",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/dot-case": {
"version": "3.0.4",
"resolved": "https://registry.npmmirror.com/dot-case/-/dot-case-3.0.4.tgz",
"integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
"dev": true,
"license": "MIT",
"dependencies": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
}
},
"node_modules/dotenv": {
"version": "16.4.7",
"resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.4.7.tgz",
@ -5397,6 +6013,18 @@
"once": "^1.4.0"
}
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/env-editor": {
"version": "0.4.2",
"resolved": "https://registry.npmmirror.com/env-editor/-/env-editor-0.4.2.tgz",
@ -7111,6 +7739,13 @@
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"license": "MIT"
},
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"dev": true,
"license": "MIT"
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz",
@ -7369,6 +8004,16 @@
"loose-envify": "cli.js"
}
},
"node_modules/lower-case": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/lower-case/-/lower-case-2.0.2.tgz",
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
"dev": true,
"license": "MIT",
"dependencies": {
"tslib": "^2.0.3"
}
},
"node_modules/lru-cache": {
"version": "10.4.3",
"resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz",
@ -7447,6 +8092,12 @@
"node": ">=0.10"
}
},
"node_modules/mdn-data": {
"version": "2.0.14",
"resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz",
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
"license": "CC0-1.0"
},
"node_modules/memoize-one": {
"version": "5.2.1",
"resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-5.2.1.tgz",
@ -8079,6 +8730,17 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"license": "MIT"
},
"node_modules/no-case": {
"version": "3.0.4",
"resolved": "https://registry.npmmirror.com/no-case/-/no-case-3.0.4.tgz",
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
"dev": true,
"license": "MIT",
"dependencies": {
"lower-case": "^2.0.2",
"tslib": "^2.0.3"
}
},
"node_modules/node-dir": {
"version": "0.1.17",
"resolved": "https://registry.npmmirror.com/node-dir/-/node-dir-0.1.17.tgz",
@ -8177,6 +8839,18 @@
"node": ">=8"
}
},
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"license": "BSD-2-Clause",
"dependencies": {
"boolbase": "^1.0.0"
},
"funding": {
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
"node_modules/nullthrows": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/nullthrows/-/nullthrows-1.1.1.tgz",
@ -8467,6 +9141,29 @@
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
"license": "BlueOak-1.0.0"
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
"license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/parent-module/node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-4.0.0.tgz",
@ -8511,6 +9208,13 @@
"cross-spawn": "^7.0.3"
}
},
"node_modules/path-dirname": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/path-dirname/-/path-dirname-1.0.2.tgz",
"integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==",
"dev": true,
"license": "MIT"
},
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz",
@ -9182,6 +9886,38 @@
"react-native": "*"
}
},
"node_modules/react-native-svg": {
"version": "15.11.2",
"resolved": "https://registry.npmmirror.com/react-native-svg/-/react-native-svg-15.11.2.tgz",
"integrity": "sha512-+YfF72IbWQUKzCIydlijV1fLuBsQNGMT6Da2kFlo1sh+LE3BIm/2Q7AR1zAAR6L0BFLi1WaQPLfFUC9bNZpOmw==",
"license": "MIT",
"dependencies": {
"css-select": "^5.1.0",
"css-tree": "^1.1.3",
"warn-once": "0.1.1"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-svg-transformer": {
"version": "1.5.0",
"resolved": "https://registry.npmmirror.com/react-native-svg-transformer/-/react-native-svg-transformer-1.5.0.tgz",
"integrity": "sha512-RG5fSWJT7mjCQYocgYFUo1KYPLOoypPVG5LQab+pZZO7m4ciGaQIe0mhok3W4R5jLQsEXKo0u+aQGkZV/bZG7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@svgr/core": "^8.1.0",
"@svgr/plugin-jsx": "^8.1.0",
"@svgr/plugin-svgo": "^8.1.0",
"path-dirname": "^1.0.2"
},
"peerDependencies": {
"react-native": ">=0.59.0",
"react-native-svg": ">=12.0.0"
}
},
"node_modules/react-native-vector-icons": {
"version": "10.2.0",
"resolved": "https://registry.npmmirror.com/react-native-vector-icons/-/react-native-vector-icons-10.2.0.tgz",
@ -9922,6 +10658,17 @@
"node": ">=8.0.0"
}
},
"node_modules/snake-case": {
"version": "3.0.4",
"resolved": "https://registry.npmmirror.com/snake-case/-/snake-case-3.0.4.tgz",
"integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
"dev": true,
"license": "MIT",
"dependencies": {
"dot-case": "^3.0.4",
"tslib": "^2.0.3"
}
},
"node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz",
@ -10231,6 +10978,70 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/svg-parser": {
"version": "2.0.4",
"resolved": "https://registry.npmmirror.com/svg-parser/-/svg-parser-2.0.4.tgz",
"integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==",
"dev": true,
"license": "MIT"
},
"node_modules/svgo": {
"version": "3.3.2",
"resolved": "https://registry.npmmirror.com/svgo/-/svgo-3.3.2.tgz",
"integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@trysound/sax": "0.2.0",
"commander": "^7.2.0",
"css-select": "^5.1.0",
"css-tree": "^2.3.1",
"css-what": "^6.1.0",
"csso": "^5.0.5",
"picocolors": "^1.0.0"
},
"bin": {
"svgo": "bin/svgo"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/svgo"
}
},
"node_modules/svgo/node_modules/commander": {
"version": "7.2.0",
"resolved": "https://registry.npmmirror.com/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 10"
}
},
"node_modules/svgo/node_modules/css-tree": {
"version": "2.3.1",
"resolved": "https://registry.npmmirror.com/css-tree/-/css-tree-2.3.1.tgz",
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
"dev": true,
"license": "MIT",
"dependencies": {
"mdn-data": "2.0.30",
"source-map-js": "^1.0.1"
},
"engines": {
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
}
},
"node_modules/svgo/node_modules/mdn-data": {
"version": "2.0.30",
"resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.30.tgz",
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
"dev": true,
"license": "CC0-1.0"
},
"node_modules/tar": {
"version": "6.2.1",
"resolved": "https://registry.npmmirror.com/tar/-/tar-6.2.1.tgz",

2
package.json

@ -28,6 +28,7 @@
"react-native-responsive-fontsize": "^0.5.1",
"react-native-safe-area-context": "^5.3.0",
"react-native-screens": "^4.10.0",
"react-native-svg": "^15.11.2",
"react-native-vector-icons": "^10.2.0",
"react-native-web": "~0.19.13"
},
@ -36,6 +37,7 @@
"@hancleee/babel-plugin-react-native-pxtodp": "^1.0.8",
"@types/react": "~18.3.12",
"@types/react-native-vector-icons": "^6.4.18",
"react-native-svg-transformer": "^1.5.0",
"typescript": "^5.3.3"
},
"private": true

1103
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save