This commit is contained in:
oneao committed 2026-04-16 17:31:03 +08:00
1 parent 230f3bdf5c
commit 6300778150
36 files changed
+867 -322

No files matched your search

+9 -6
View File
@@ -1,19 +1,22 @@
{
"Print React Native Component (NativeWind)": {
"Print LayoutView Scroll Example (NativeWind)": {
"scope": "typescriptreact,javascriptreact",
"prefix": "rn",
"body": [
"import React from \"react\";",
"import { View, Text } from \"react-native\";",
"import LayoutView from \"@/components/layout/view\";",
"import { Text } from \"react-native\";",
"",
"export default function ${1/(.*)/${1:/pascalcase}/}() {",
" return (",
" <View className=\"flex-1\">",
" <Text className=\"text-base text-black\">${2:Hello RN}</Text>",
" </View>",
" <LayoutView>",
" <LayoutView.ScrollView>",
" <Text className=\"text-base text-black\">${2:Hello}</Text>",
" </LayoutView.ScrollView>",
" </LayoutView>",
" );",
"}"
],
"description": "React Native NativeWind 函数组件模板"
"description": "LayoutView + ScrollView 结构组件模板"
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"symbol_url": "//at.alicdn.com/t/c/font_5161133_ylxxigmqv3.js",
"symbol_url": "//at.alicdn.com/t/c/font_5161133_jurut6g45n9.js",
"use_typescript": true,
"save_dir": "./src/components/iconfont",
"trim_icon_prefix": "icon",
+4 -4
View File
@@ -5,8 +5,8 @@ import {
HomeIcon,
MessageCircleIcon,
UserRoundIcon,
StarIcon,
LayoutGridIcon,
EarthIcon,
} from "lucide-react-native";
export const unstable_settings = {
@@ -31,9 +31,9 @@ const tabs: TabbarItem[] = [
isCenter: true,
},
{
id: "/star",
title: "收藏",
icon: StarIcon,
id: "/space",
title: "空间",
icon: EarthIcon,
},
{
id: "/my",
+30 -40
View File
@@ -1,46 +1,36 @@
import { ScrollShadow, Surface } from "heroui-native";
import { LinearGradient } from "expo-linear-gradient";
import { FlatList, ScrollView, Text, View } from "react-native";
import { Button, Dialog } from "heroui-native";
import { View } from "react-native";
import { useState } from "react";
export default function ScrollShadowExample() {
const horizontalData = Array.from({ length: 10 }, (_, i) => ({
id: i,
title: `Card ${i + 1}`,
}));
export default function DialogExample() {
const [isOpen, setIsOpen] = useState(false);
return (
<View className="flex-1 bg-background">
<Text className="px-5 py-3 text-lg font-semibold">Horizontal List</Text>
<ScrollShadow LinearGradientComponent={LinearGradient}>
<FlatList
data={horizontalData}
horizontal
renderItem={({ item }) => (
<Surface variant="2" className="w-32 h-24 justify-center px-4">
<Text>{item.title}</Text>
</Surface>
)}
showsHorizontalScrollIndicator={false}
contentContainerClassName="p-5 gap-4"
/>
</ScrollShadow>
<>
<Button variant="primary" onPress={() => {
setIsOpen(true)
}}>Open Dialog</Button>
<Text className="px-5 py-3 text-lg font-semibold">Vertical Content</Text>
<ScrollShadow size={80} className="h-48" LinearGradientComponent={LinearGradient}>
<ScrollView contentContainerClassName="p-5" showsVerticalScrollIndicator={false}>
<Text className="mb-4 text-2xl font-bold">Long Content</Text>
<Text className="mb-4 text-base leading-6">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris.
</Text>
<Text className="mb-4 text-base leading-6">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque
laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae.
</Text>
</ScrollView>
</ScrollShadow>
</View>
<Dialog isOpen={isOpen} onOpenChange={setIsOpen}>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Close variant="ghost" />
<View className="mb-5 gap-1.5">
<Dialog.Title>Confirm Action</Dialog.Title>
<Dialog.Description>
Are you sure you want to proceed with this action? This cannot be undone.
</Dialog.Description>
</View>
<View className="flex-row justify-end gap-3">
<Button variant="ghost" size="sm" onPress={() => setIsOpen(false)}>
Cancel
</Button>
<Button size="sm">Confirm</Button>
</View>
</Dialog.Content>
</Dialog.Portal>
</Dialog>
</>
);
}
+18 -42
View File
@@ -1,49 +1,25 @@
import { ScrollShadow } from "heroui-native";
import { LinearGradient } from "expo-linear-gradient";
import { ScrollView, Text, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import React from "react";
import LayoutView from "@/components/layout/view";
import EmptyState from "@/components/EmptyStatus";
export default function Home() {
// const [dailyData, setDailyData] = useState<any>(null);
export default function ScrollShadowExample() {
const list = Array.from({ length: 20 }, (_, i) => i.toString());
const items = [];
for (let i = 0; i < list.length; i++) {
items.push(
<Text key={list[i]} className="py-2 text-base">
{list[i]}
</Text>,
);
}
// useEffect(() => {
// fetchDailyInfo()
// .then((res: any) => {
// if (res?.code === "1") {
// console.log(res);
// setDailyData(res);
// }
// })
// .catch(() => {});
// }, []);
return (
<View className="flex-1 bg-background">
<LayoutView.ScrollView
contentContainerStyle={{
paddingTop: 0,
}}
>
<Text className="mb-4 text-2xl font-bold">Long Content</Text>
{items}
<LayoutView>
<LayoutView.ScrollView>
<EmptyState type="loading" />
</LayoutView.ScrollView>
{/* <View style={{ flex: 1, overflow: "hidden" }}>
<ScrollShadow className="flex-1" size={300} LinearGradientComponent={LinearGradient}>
<ScrollView
showsVerticalScrollIndicator={false}
contentContainerStyle={{
padding: 16,
paddingBottom: TABBAR_HEIGHT + insets.bottom + 40,
paddingTop: NAVBAR_HEIGHT + insets.top + 20,
zIndex: 1,
}}
>
<Text className="mb-4 text-2xl font-bold">Long Content</Text>
{items}
</ScrollView>
</ScrollShadow>
</View> */}
</View>
</LayoutView>
);
}
+104 -2
View File
@@ -1,8 +1,110 @@
import { View } from "react-native";
import React, { useState } from "react";
import LayoutView from "@/components/layout/view";
import { Text, View } from "react-native";
import { Avatar } from "heroui-native";
import { ChevronRightIcon } from "lucide-react-native";
import { ListGroup, PressableFeedback, Dialog, Button } from "heroui-native";
import { Ionicons } from "@expo/vector-icons";
import { withUniwind } from "uniwind";
import { useUserStore } from "@/store";
import { useRouter } from "expo-router";
const StyledIonicons = withUniwind(Ionicons);
export default function My() {
const router = useRouter();
const userStore = useUserStore();
const [openLogout, setOpenLogout] = useState(false);
function handleLogout() {
setOpenLogout(false);
requestAnimationFrame(() => {
userStore.clear();
router.replace("/auth/login");
});
}
return (
<View className="flex-1 bg-background"></View>
<LayoutView>
<LayoutView.ScrollView>
<View className="flex-row items-center">
<Avatar alt="">
<Avatar.Image source={{ uri: "https://example.com/avatar.jpg" }} />
<Avatar.Fallback className="text-sm">JD</Avatar.Fallback>
</Avatar>
<View className="ml-3 mr-1">
<Text className="text-xl font-semibold text-foreground">JD</Text>
</View>
<ChevronRightIcon size={18} color="#c7c7cc" />
</View>
<View className="justify-center mt-4">
<Text className="text-sm text-muted mb-2 ml-2">账户</Text>
<ListGroup className="mb-6">
<PressableFeedback>
<ListGroup.Item onPress={() => {}}>
<ListGroup.ItemPrefix>
<StyledIonicons name="person-outline" size={22} className="text-foreground" />
</ListGroup.ItemPrefix>
<ListGroup.ItemContent>
<ListGroup.ItemTitle>个人信息</ListGroup.ItemTitle>
</ListGroup.ItemContent>
<ListGroup.ItemSuffix />
</ListGroup.Item>
<PressableFeedback.Ripple />
</PressableFeedback>
</ListGroup>
<ListGroup>
<PressableFeedback
onPress={() => {
setOpenLogout(true);
}}
>
<ListGroup.Item>
<ListGroup.ItemPrefix>
<StyledIonicons name="exit-outline" size={22} className="text-foreground" />
</ListGroup.ItemPrefix>
<ListGroup.ItemContent>
<ListGroup.ItemTitle>退出登录</ListGroup.ItemTitle>
</ListGroup.ItemContent>
<ListGroup.ItemSuffix />
</ListGroup.Item>
<PressableFeedback.Ripple />
</PressableFeedback>
</ListGroup>
</View>
<Dialog isOpen={openLogout} onOpenChange={setOpenLogout}>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<View className="flex-row items-center justify-between">
<Dialog.Title>提示</Dialog.Title>
<Dialog.Close variant="ghost" />
</View>
<View className="my-2 gap-1.5">
<Dialog.Description>确认退出当前登录账号么?</Dialog.Description>
</View>
<View className="flex-row justify-end gap-3">
<Button variant="ghost" size="sm" onPress={() => setOpenLogout(false)}>
取消
</Button>
<Button size="sm" onPress={handleLogout}>
确认
</Button>
</View>
</Dialog.Content>
</Dialog.Portal>
</Dialog>
</LayoutView.ScrollView>
</LayoutView>
);
}
@@ -0,0 +1,13 @@
import React from "react";
import LayoutView from "@/components/layout/view";
import { Text } from "react-native";
export default function Space() {
return (
<LayoutView>
<LayoutView.ScrollView>
<Text className="text-base text-black">我的空间</Text>
</LayoutView.ScrollView>
</LayoutView>
);
}
+31
View File
@@ -0,0 +1,31 @@
import { Stack } from "expo-router";
import EmptyState from "@/components/EmptyStatus";
import { Button } from "heroui-native";
import { useRouter } from "expo-router";
export default function NotFound() {
const router = useRouter();
return (
<>
<Stack.Screen options={{ headerShown: false }} />
<EmptyState
type="404"
title="(´・ω・`) 页面走丢了~"
description="回首页看看吧!"
footer={
<Button
className="mt-4"
onPress={() => {
requestAnimationFrame(() => {
router.replace("/home");
});
}}
>
返回首页
</Button>
}
/>
</>
);
}
+9 -7
View File
@@ -31,14 +31,16 @@ export default function Login() {
setLoading(true);
setTimeout(() => {
userStore.setUserInfo({
id: 1,
token: "123",
nickname: "Zhang",
avatar: "",
});
requestAnimationFrame(() => {
userStore.setUserInfo({
id: 1,
token: "123",
nickname: "Zhang",
avatar: "",
});
router.replace("/(tabs)/home");
router.replace("/(tabs)/home");
});
setLoading(false);
}, 2000);
+6 -2
View File
@@ -10,9 +10,13 @@ export default function Index() {
useEffect(() => {
const run = async () => {
if (!userStore.isLogged()) {
router.replace("/auth/login");
requestAnimationFrame(() => {
router.replace("/auth/login");
});
} else {
router.replace("/(tabs)/home");
requestAnimationFrame(() => {
router.replace("/(tabs)/home");
});
}
await SplashScreen.hideAsync();
@@ -1,27 +1,24 @@
import React from "react";
import { View, Text, ScrollView } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import React, { useState } from "react";
import LayoutView from "@/components/layout/view";
import { Text } from "react-native";
import EmptyState from "@/components/EmptyStatus";
export default function Home() {
const insets = useSafeAreaInsets();
const [dataList, setDataList] = useState<any>([]);
return (
<View className="flex-1">
<ScrollView
className="flex-1 px-4 py-2"
contentContainerStyle={{
paddingTop: 56 + insets.top + 20,
paddingBottom: 56 + insets.bottom + 20,
}}
<LayoutView>
<LayoutView.SectionView<any>
sections={dataList}
keyExtractor={(item) => item.id.toString()}
stickySectionHeadersEnabled={true}
showsVerticalScrollIndicator={false}
ListEmptyComponent={() => (
<EmptyState type="empty" title="暂无记账记录" description="快去添加你的第一笔记账吧" />
)}
>
<Text className="text-xl font-semibold mb-4">Money Home</Text>
{Array.from({ length: 30 }).map((_, i) => (
<View key={i} className="p-4 mb-3 rounded-xl bg-gray-100">
<Text className="text-black">这是第 {i + 1} 条内容</Text>
</View>
))}
</ScrollView>
</View>
<Text className="text-base text-black">Hello</Text>
</LayoutView.SectionView>
</LayoutView>
);
}
+124 -10
View File
@@ -1,18 +1,132 @@
import React from "react";
import LayoutView from "@/components/layout/view";
import { SearchField, CloseButton, ListGroup, PressableFeedback, Separator } from "heroui-native";
import { View, Text } from "react-native";
import { Stack } from "expo-router";
import { Stack, useRouter } from "expo-router";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { getGroupedApps } from "@/configs/pages";
import { useState, useMemo, useRef } from "react";
import AZIndex from "@/components/AZIndex";
import type { LegendListRef } from "@legendapp/list";
import { AppListItem } from "@/configs/pages";
import EmptyState from "@/components/EmptyStatus";
export default function Tools() {
const router = useRouter();
const safeAreaInsets = useSafeAreaInsets();
const listRef = useRef<LegendListRef>(null);
const [keyword, setKeyword] = useState("");
const data = useMemo(() => getGroupedApps(keyword), [keyword]);
const scrollToLetter = (letter: string) => {
const index = data.findIndex((item) => item.type === "header" && item.title === letter);
if (index === -1) return;
listRef.current?.scrollToIndex({
index,
animated: true,
viewOffset: safeAreaInsets.top + 56,
});
setTimeout(() => {
listRef.current?.scrollToIndex({
index,
animated: true,
viewOffset: safeAreaInsets.top + 56,
});
}, 100);
};
export default function Layout() {
return (
<View className="flex-1">
<Stack.Screen
options={{
animation: "slide_from_bottom",
headerShown: false,
<LayoutView>
<Stack.Screen options={{ animation: "slide_from_bottom" }} />
<LayoutView.LegendList<AppListItem>
ref={listRef}
data={data}
keyExtractor={(item, i) => String(i)}
estimatedItemSize={120}
recycleItems
initialContainerPoolRatio={20}
contentContainerStyle={{
paddingTop: safeAreaInsets.top + 60,
paddingBottom: safeAreaInsets.bottom + 100,
paddingRight: 32,
}}
ListEmptyComponent={<EmptyState />}
renderItem={({ item }: { item: AppListItem }) => {
if (item.type === "header") {
return <Text className="text-xs text-gray-400 mb-2 px-2">{item.title}</Text>;
}
return (
<View className="mb-6">
<ListGroup>
{item.data.map((subItem, index) => {
const Icon = subItem.icon;
return (
<PressableFeedback
key={subItem.id}
onPress={() => {
router.navigate(subItem.id as any);
}}
>
<ListGroup.Item>
<ListGroup.ItemPrefix>
<Icon size={22} />
</ListGroup.ItemPrefix>
<ListGroup.ItemContent>
<ListGroup.ItemTitle>{subItem.title}</ListGroup.ItemTitle>
{subItem.description && (
<ListGroup.ItemDescription>
{subItem.description}
</ListGroup.ItemDescription>
)}
</ListGroup.ItemContent>
<ListGroup.ItemSuffix />
</ListGroup.Item>
{index !== item.data.length - 1 && <Separator className="mx-4" />}
<PressableFeedback.Ripple />
</PressableFeedback>
);
})}
</ListGroup>
</View>
);
}}
/>
<Text className="text-base text-black">Hello222 RN</Text>
</View>
<View
className="absolute top-0 left-0 right-0 px-4"
style={{
paddingTop: safeAreaInsets.top,
paddingRight: 32,
}}
>
<SearchField value={keyword} onChange={setKeyword}>
<SearchField.Group>
<SearchField.SearchIcon />
<SearchField.Input placeholder="搜索工具" />
</SearchField.Group>
</SearchField>
</View>
<AZIndex onSelect={scrollToLetter} />
<View className="absolute bottom-6 left-0 right-0 items-center">
<CloseButton
onPress={() => router.back()}
iconProps={{ size: 28 }}
style={{ padding: 24 }}
/>
</View>
</LayoutView>
);
}
@@ -0,0 +1,46 @@
import React, { useState } from "react";
import { View, Text, Pressable } from "react-native";
const LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
type Props = {
onSelect?: (letter: string) => void;
};
export default function AZIndex({ onSelect }: Props) {
const [active, setActive] = useState<string | null>(null);
function handlePress(letter: string) {
setActive(letter);
onSelect?.(letter);
}
return (
<View className="absolute right-1 top-1/2 -translate-y-1/2 items-center">
{LETTERS.map((l) => {
const isActive = active === l;
return (
<Pressable
key={l}
onPress={() => handlePress(l)}
className="py-0.5 px-1 items-center"
style={({ pressed }) => ({
opacity: pressed ? 0.4 : 1,
})}
>
<Text
className={`${
isActive
? "text-accent text-[16px] font-semibold"
: "text-foreground/60 text-[12px]"
}`}
>
{l}
</Text>
</Pressable>
);
})}
</View>
);
}
@@ -0,0 +1,58 @@
import { ScrollView, Text, Image } from "react-native";
interface EmptyStateProps {
type?: "empty" | "error" | "404" | "network" | "loading";
title?: string;
description?: string;
footer?: React.ReactNode;
}
const images = {
empty: require("@/static/images/status/记录空空的.png"),
error: require("@/static/images/status/图片加载失败.png"),
"404": require("@/static/images/status/404黑洞.png"),
network: require("@/static/images/status/网络加载异常.png"),
loading: require("@/static/images/status/正在紧急开发.png"),
};
const defaultTitles = {
empty: "记录空空的",
error: "加载失败",
"404": "页面走丢了",
network: "网络异常",
loading: "正在紧急开发",
};
export default function EmptyState({
type = "empty",
title,
description,
footer,
}: EmptyStateProps) {
const finalTitle = title ?? defaultTitles[type];
return (
<ScrollView
contentContainerStyle={{
flexGrow: 1,
justifyContent: "center",
alignItems: "center",
padding: 16,
}}
showsVerticalScrollIndicator={false}
>
{/* image */}
<Image source={images[type]} style={{ width: 224, height: 224, resizeMode: "contain" }} />
{/* title */}
<Text className="text-xl font-semibold text-foreground text-center mt-4">{finalTitle}</Text>
{/* description */}
{description && (
<Text className="text-sm text-foreground/60 text-center mt-2 leading-6">{description}</Text>
)}
{footer}
</ScrollView>
);
}
@@ -0,0 +1,72 @@
/* eslint-disable */
/* tslint:disable */
import React from 'react';
import type { FunctionComponent } from 'react';
import type { ViewProps } from 'react-native';
import { Svg, GProps, Path } from 'react-native-svg';
import { getIconColor } from './helper';
interface Props extends Omit<GProps, 'color'>, ViewProps {
size?: number;
color?: string | string[];
}
const IconAppClothes: FunctionComponent<Props> = ({
size = 18,
color,
...rest
}) => {
return (
<Svg viewBox="0 0 1024 1024" width={size} height={size} {...rest}>
<Path
d="M796.36555852 399.53294222c-4.56324741 12.51252148-8.61677037 25.19495111-11.86929777 37.79242667-0.08495408 0.3155437-0.15777185 0.6432237-0.24272593 0.95876741-0.0121363 0.0121363-0.0121363 0.0121363-0.0121363 0.02427259v0.02427259c-0.07281778 0.26699852-0.13349925 0.53399703-0.20631704 0.81313185-0.03640889 0.10922667-0.06068148 0.21845333-0.08495407 0.32768-3.03407408 12.40329482-5.47346963 30.35287703-7.42741333 52.21034667l-7.5730489-45.06206815 0.40049779-6.45650963 27.01539555-40.63232zM944.90168889 604.28439703c-0.06068148 0-0.10922667 0.0121363-0.16990814 0.0121363-9.63621925 0.78885925-16.95440592 8.8594963-16.95440593 18.39862519 0 0.43690667 0.0121363 0.87381333 0.04854518 1.3228563 3.5923437 50.26853925 6.2137837 92.23585185 6.46864592 110.27038815 0.0121363 0.78885925 0.02427259 3.90788741 0.0242726 7.39100444l-109.4693926-73.93431704-14.52714667-86.37402074a18.48357925 18.48357925 0 0 0-1.72335407-5.24288c1.9539437-57.48963555 5.46133333-105.34305185 11.43239112-128.70542222 14.93978075-58.60617482 49.98940445-121.49646222 70.85169778-155.68440889 6.06814815 13.50769778 12.22125037 31.15387259 14.10237629 50.09863111 2.03889778 20.37684148 27.19744 91.49553778 32.11264 147.28609185 0.80099555 10.12167111 5.20647111 86.03420445 5.64337778 85.98565927 0.74031408 9.87894518 1.46849185 19.62439111 2.16026074 29.17565628z"
fill={getIconColor(color, 0, '#FFFBC4')}
/>
<Path
d="M938.25099852 942.36520297h-67.23508149l-46.14219851-274.40165927 109.4572563 75.22076445c0 1.11653925 0.0121363 2.23307852 0 3.3010726-0.0121363 0.35195259-0.0121363 0.70390518 0 1.06799407 0 0.10922667 0.0121363 0.21845333 0.01213629 0.33981629v0.21845334c0 2.47580445 0 4.40547555-0.01213629 4.84238222-0.02427259 1.17722075 0.04854518 2.29376 0.20631703 3.34961778 0.89808592 40.18327703 3.2889363 173.36699259 3.71370667 186.06155852z"
fill={getIconColor(color, 1, '#FF524E')}
/>
<Path
d="M722.49192297 150.38691555c2.69425778 10.13380741 4.56324741 26.45712592-7.74295705 34.67339853l-129.87050667 45.41402074c40.46241185-46.03297185 69.4560237-103.04929185 84.06812445-135.39252149 24.68522667 23.99345778 48.14468741 47.88982518 53.54533927 55.30510222z"
fill={getIconColor(color, 2, '#FFD630')}
/>
<Path
d="M770.5273837 860.86997333c-139.00913778-9.36922075-143.1840237-149.74976-143.1840237-149.74976H396.58382222s-4.17488592 140.38053925-143.1840237 149.74976c-0.52186075 35.06176-1.14081185 63.76410075-1.57771852 81.50736592h520.28302222c-0.43690667-17.75540148-1.05585778-46.45774222-1.57771852-81.50736592z"
fill={getIconColor(color, 3, '#FF524E')}
/>
<Path
d="M751.38844445 199.52677925c-4.16274963 6.33514667-9.58767408 11.8086163-16.22622815 16.23836445-14.61210075 9.74544592-60.05039408 25.59544889-106.61736297 39.87986963V488.33422222c0 23.70218667-36.91861333 23.73859555-36.91861333 0V266.59195259c-23.72645925 6.80846222-45.5596563 12.59747555-61.19120592 16.27477333l-18.47144297 0.0121363-18.47144296-0.0121363c-15.63154963-3.67729778-37.46474667-9.46631111-61.19120593-16.27477333V488.33422222c0 23.73859555-36.91861333 23.70218667-36.91861333 0V255.64501333c-46.56696889-14.28442075-92.00526222-30.1344237-106.61736297-39.87986963-6.63855408-4.42974815-12.06347852-9.90321778-16.22622814-16.23836445l-114.29963853 62.58688c16.76022518 26.48139852 48.5087763 80.20878222 69.38320593 137.38287408l19.84284445 92.28439704c6.25019259 70.24488297 7.40314075 180.72158815 6.90555259 276.93814518l-0.3034074 39.90414223c-0.18204445 18.47144297-0.41263408 36.0326637-0.6674963 52.23461925 139.00913778-9.36922075 143.1840237-149.74976 143.1840237-149.74976h230.75953778s4.17488592 140.38053925 143.1840237 149.74976c-0.25486222-16.20195555-0.48545185-33.7631763-0.66749629-52.23461925l-0.30340741-39.90414223c-0.49758815-96.21655703 0.65536-206.69326222 6.90555259-276.93814518l19.84284444-92.28439704c20.87442963-57.17409185 52.62298075-110.90147555 69.38320594-137.38287408l-114.29963852-62.58688z"
fill={getIconColor(color, 4, '#FFFBC4')}
/>
<Path
d="M570.56976592 188.20361482l23.90850371-32.54954667c17.67044741-27.8406637 31.28737185-55.14733037 39.94055112-74.01927112H389.58117925c8.66531555 18.88407703 22.30651259 46.23928889 40.0012326 74.11636149 10.55857778 16.62672592 22.56137482 33.44763259 35.82634667 48.76363851 14.17519408 16.384 29.78247111 31.05678222 46.59124148 41.94304 16.82090667-10.89839408 32.44032-25.58331259 46.61551408-41.97944888 13.27710815-15.32814222 25.30417778-32.17332148 35.86275555-48.82432l-23.90850371 32.54954667z"
fill={getIconColor(color, 5, '#83499B')}
/>
<Path
d="M439.12154075 230.46219852L309.25103408 185.04817778c-12.31834075-8.2041363-10.44935111-24.53959111-7.74295705-34.66126223 5.40065185-7.42741333 28.86011259-31.31164445 53.53320297-55.31723852 14.62423703 32.35536592 43.61784889 89.37168592 84.08026075 135.39252149z"
fill={getIconColor(color, 6, '#FFD630')}
/>
<Path
d="M215.40105482 576.12818963c-0.81313185 1.61412741-1.39567408 3.37389037-1.72335407 5.24288l-14.52714667 86.38615704-109.39657483 73.87363555c-0.0121363-0.84954075-0.03640889-1.67480889-0.04854517-2.48794074-0.80099555-41.36049778 24.17550222-346.10289778 29.30915555-397.30593185 1.86898963-18.81125925 8.04636445-36.49384297 14.12664889-50.05008593 20.86229333 34.20008297 55.89978075 97.06609778 70.83956148 155.63586371 5.95892148 23.37450667 9.46631111 71.21578667 11.42025482 128.70542222z"
fill={getIconColor(color, 7, '#FFFBC4')}
/>
<Path
d="M199.11414518 667.97568l-46.13006221 274.40165925h-67.23508149c1.44421925-43.67853037 4.69674667-150.04103111 4.02925037-199.25371258l109.33589333-75.14794667z"
fill={getIconColor(color, 8, '#FF524E')}
/>
<Path
d="M939.58599111 523.67511703c-11.38384592 0.94663111-20.6317037 10.8013037-20.6317037 22.37933038 0 12.23338667 10.25517037 22.47642075 22.46428444 22.47642074 0.54613333 0 1.08013037-0.0121363 1.6141274-0.07281778 11.1532563-0.81313185 20.31616-10.13380741 20.81374816-21.42056296 0.55826963-12.54893037-9.8182637-23.44732445-22.41573926-23.44732444-0.63108741 0-1.23790222 0.03640889-1.84471704 0.08495406z"
fill={getIconColor(color, 9, '#3D125E')}
/>
<Path
d="M971.16463408 732.07959703l-0.0364089-1.51703703c-0.52186075-20.77733925-3.07048297-61.47034075-6.48078221-109.17812148-0.72817778-10.18235259-9.58767408-17.84035555-19.74575408-17.10004149-0.06068148 0-0.10922667 0.0121363-0.16990814 0.0121363-9.63621925 0.78885925-16.95440592 8.8594963-16.95440593 18.39862519 0 0.43690667 0.0121363 0.87381333 0.04854518 1.3228563 2.87630222 40.25609482 5.13365333 75.17221925 6.04387555 96.75055407l-113.18309925-77.78152297-10.36439705-61.61597629a18.48357925 18.48357925 0 0 0-1.72335407-5.24288c1.9539437-57.48963555 5.46133333-105.34305185 11.43239112-128.70542222 14.93978075-58.60617482 49.98940445-121.49646222 70.85169778-155.68440889 6.06814815 13.50769778 12.22125037 31.15387259 14.10237629 50.09863111 2.03889778 20.37684148 6.75991703 62.2713363 12.22125038 130.36809482 0.81313185 10.15808 9.69690075 17.73112889 19.85498073 16.91799703h0.03640889c9.64835555-0.78885925 16.94226963-8.8594963 16.94226963-18.3622163 0-0.49758815-0.02427259-0.9951763-0.06068148-1.49276443-5.64337778-70.42692741-10.51003259-113.65641482-12.25765927-131.0962726-2.54862222-25.48622222-9.85467259-49.98940445-21.49338073-72.70855112-3.6166163-7.06332445-6.85700741-12.77952-13.93246815-19.6365274-7.14827852-6.91768889-12.20911408-10.29157925-19.10253037-14.06596741-13.21642667-7.23323259-26.43285333-14.46646518-39.6371437-21.71183407-15.47377778-8.47113482-30.94755555-16.94226963-46.40919705-25.41340445-11.23821037-6.15310222-22.47642075-12.30620445-33.7024948-18.45930667-2.02676148-1.10440297-4.04138667-2.20880592-6.06814815-3.32534518-0.13349925-7.88859259-1.43208297-16.18981925-3.9564326-24.75804444-1.45635555-4.9273363-4.16274963-14.09024-82.25981629-88.31582816-3.37389037-3.19184592-8.08277333-5.07297185-12.73097482-5.07297184H361.5827437c-4.66033778 0-9.33281185 1.85685333-12.70670222 5.07297184-78.10920297 74.22558815-80.81559703 83.38849185-82.27195259 88.31582816-2.52434963 8.58036148-3.82293333 16.86945185-3.95643259 24.75804444-9.59981037 5.2550163-19.21175703 10.52216889-28.81156741 15.77718518-19.50302815 10.67994075-38.99392 21.35988148-58.49694814 32.02768594-10.41294222 5.70405925-21.2870637 11.39598222-31.78496 17.24567703-7.88859259 4.39333925-15.0611437 9.24785778-22.9982815 17.31849482-6.61428148 6.72350815-12.31834075 13.39847111-16.48109036 21.68756148-7.43954963 14.80628148-13.45915259 30.40142222-17.45199407 46.49415111-2.02676148 8.14345482-3.51952592 16.42040889-4.35693037 24.75804444-4.29624889 43.02317037-30.36501333 356.29738667-29.46692742 401.68713482 1.12867555 57.62313482-4.53897482 218.70819555-4.58752 220.32232296-0.36408889 10.30371555 8.13131852 19.10253037 18.44717038 19.10253037h101.94488889c9.00513185 0 16.6995437-6.50505482 18.20444445-15.3888237l30.52278517-181.53472-0.10922667 14.49073778-2.79134814 163.65795555c-0.16990815 10.1702163 8.28909037 18.77485037 18.45930667 18.77485037h558.22108444c10.15808 0 18.62921482-8.60463408 18.45930667-18.77485037l-2.77921186-163.75504593c-0.04854518-4.75742815-0.08495408-9.55126518-0.12136295-14.4057837l30.52278517 181.53472c1.50490075 8.89590518 9.19931259 15.40096 18.20444445 15.40096h101.94488889c10.31585185 0 18.81125925-8.79881482 18.44717038-19.11466667-0.0121363-0.30340741-3.41029925-183.58575408-4.62392889-228.0774163zM668.9465837 95.08181333c24.68522667 24.00559408 48.14468741 47.88982518 53.54533927 55.30510222 2.69425778 10.13380741 4.56324741 26.45712592-7.74295705 34.67339853l-129.87050667 45.41402074c40.46241185-46.04510815 69.4560237-103.06142815 84.06812445-135.39252149z m-34.52776295-13.45915258c-8.65317925 18.87194075-22.2701037 46.17860741-39.94055112 74.0192711-10.55857778 16.65099852-22.58564741 33.49617778-35.86275555 48.82432-14.17519408 16.3961363-29.79460741 31.08105482-46.61551408 41.9794489-16.80877037-10.88625778-32.41604741-25.55904-46.59124148-41.94304-13.26497185-15.31600592-25.26776889-32.13691259-35.82634667-48.76363853-17.69472-27.87707259-31.33591703-55.23228445-40.0012326-74.11636147h244.8376415z m-332.91074372 68.7642548c5.40065185-7.42741333 28.86011259-31.31164445 53.53320297-55.31723852 14.62423703 32.34322963 43.61784889 89.37168592 84.08026075 135.38038519L309.25103408 185.04817778c-12.31834075-8.2041363-10.44935111-24.53959111-7.74295705-34.66126223zM152.98408297 942.36520297h-67.23508149c1.25003852-37.95019852 3.87147852-123.2198163 4.10206815-177.21419852l105.06391704-72.21096297-41.9309037 249.42516149z m60.69361778-360.99413334l-10.36439705 61.61597629-113.18309925 77.79365926c3.31320889-78.36406518 24.2361837-332.5830637 28.88438518-378.94371555 1.86898963-18.81125925 8.04636445-36.49384297 14.12664889-50.05008593 20.86229333 34.20008297 55.89978075 97.06609778 70.83956148 155.63586371 5.95892148 23.36237037 9.46631111 71.21578667 11.42025482 128.70542222a19.00544 19.00544 0 0 0-1.72335407 5.24288z m316.8180148 360.99413334H251.82208c0.35195259-14.33296592 0.82526815-35.82634667 1.26217482-62.04074667 0.53399703-0.03640889 1.08013037-0.06068148 1.6141274-0Line truncated
fill={getIconColor(color, 10, '#3D125E')}
/>
</Svg>
);
};
export default React.memo(IconAppClothes);
@@ -0,0 +1,56 @@
/* eslint-disable */
/* tslint:disable */
import React from 'react';
import type { FunctionComponent } from 'react';
import type { ViewProps } from 'react-native';
import { Svg, GProps, Path } from 'react-native-svg';
import { getIconColor } from './helper';
interface Props extends Omit<GProps, 'color'>, ViewProps {
size?: number;
color?: string | string[];
}
const IconAppFinance: FunctionComponent<Props> = ({
size = 18,
color,
...rest
}) => {
return (
<Svg viewBox="0 0 1024 1024" width={size} height={size} {...rest}>
<Path
d="M870.24071147 512c-83.30808853-69.17688853-212.62791147-113.77777813-358.24071147-113.77777813-145.6128 0-274.93262187 44.60088853-358.24071147 113.77777813H56.88888853v182.0444448c0 163.38488853 203.7532448 295.82222187 455.11111147 295.82222187s455.11111147-132.43733333 455.11111147-295.82222187v-182.0444448h-96.8704z"
fill={getIconColor(color, 0, '#FFE930')}
/>
<Path
d="M512 466.48888853c123.0620448 0 240.68551147 36.6364448 314.64106667 98.03093334l18.95537813 15.7468448H898.8444448v113.77777813c0 123.35786667-177.152 227.5555552-386.8444448 227.5555552S125.1555552 817.40231147 125.1555552 694.0444448v-113.75502293h53.248l18.95537813-15.74684374C271.29173333 503.14808853 388.9152 466.48888853 512 466.48888853m0-68.26666666c-145.6128 0-274.93262187 44.60088853-358.24071147 113.77777813H56.88888853v182.0444448c0 163.38488853 203.7532448 295.82222187 455.11111147 295.82222187s455.11111147-132.43733333 455.11111147-295.82222187v-182.0444448h-96.8704c-83.30808853-69.15413333-212.62791147-113.77777813-358.24071147-113.77777813z"
fill={getIconColor(color, 1, '#4C4C4C')}
/>
<Path
d="M870.24071147 329.9555552c-83.30808853-69.17688853-212.62791147-113.77777813-358.24071147-113.77777707-145.6128 0-274.93262187 44.60088853-358.24071147 113.77777707H56.88888853v182.0444448c0 163.38488853 203.7532448 295.82222187 455.11111147 295.82222187s455.11111147-132.43733333 455.11111147-295.82222187v-182.0444448h-96.8704z"
fill={getIconColor(color, 2, '#99E2C5')}
/>
<Path
d="M512 284.4444448c123.0620448 0 240.68551147 36.6364448 314.64106667 98.03093333l18.95537813 15.74684374H898.8444448v113.77777813c0 123.35786667-177.152 227.5555552-386.8444448 227.5555552S125.1555552 635.35786667 125.1555552 512v-113.77777813h53.248l18.95537813-15.74684374C271.29173333 321.08088853 388.9152 284.4444448 512 284.4444448m0-68.26666667c-145.6128 0-274.93262187 44.60088853-358.24071147 113.77777707H56.88888853v182.0444448c0 163.38488853 203.7532448 295.82222187 455.11111147 295.82222187s455.11111147-132.43733333 455.11111147-295.82222187v-182.0444448h-96.8704c-83.30808853-69.17688853-212.62791147-113.77777813-358.24071147-113.77777707z"
fill={getIconColor(color, 3, '#4C4C4C')}
/>
<Path
d="M56.88888853 329.9555552a455.11111147 295.82222187 0 1 0 910.22222294 0 455.11111147 295.82222187 0 1 0-910.22222294 0Z"
fill={getIconColor(color, 4, '#FFE930')}
/>
<Path
d="M512 102.4c209.6924448 0 386.8444448 104.2204448 386.8444448 227.5555552s-177.152 227.5555552-386.8444448 227.55555627S125.1555552 453.29066667 125.1555552 329.9555552 302.3075552 102.4 512 102.4m0-68.26666667C260.64213333 34.13333333 56.88888853 166.57066667 56.88888853 329.9555552s203.7532448 295.82222187 455.11111147 295.82222293 455.11111147-132.43733333 455.11111147-295.82222293S763.35786667 34.13333333 512 34.13333333z"
fill={getIconColor(color, 5, '#4C4C4C')}
/>
<Path
d="M653.0844448 193.42222187H580.26666667l-68.26666667 109.22666666-68.26666667-109.22666666h-72.81777813l79.6444448 127.43111146h-56.88888853v36.40888854h81.92v18.2044448h-81.92v36.40888853h81.92V466.48888853h72.81777706v-54.61333333h81.92V375.46666667h-81.92v-18.2044448h81.92v-36.40888854h-56.88888853z"
fill={getIconColor(color, 6, '#4C4C4C')}
/>
</Svg>
);
};
export default React.memo(IconAppFinance);
@@ -4,12 +4,16 @@
import React, { FunctionComponent } from 'react';
import { ViewProps } from 'react-native';
import { GProps } from 'react-native-svg';
import IconAppFinance from './IconAppFinance';
import IconAppClothes from './IconAppClothes';
import IconWeixin from './IconWeixin';
import IconQq from './IconQq';
export { default as IconAppFinance } from './IconAppFinance';
export { default as IconAppClothes } from './IconAppClothes';
export { default as IconWeixin } from './IconWeixin';
export { default as IconQq } from './IconQq';
export type IconNames = 'weixin' | 'QQ';
export type IconNames = 'app_finance' | 'app_clothes' | 'weixin' | 'QQ';
interface Props extends GProps, ViewProps {
name: IconNames;
@@ -19,10 +23,14 @@ interface Props extends GProps, ViewProps {
let IconFont: FunctionComponent<Props> = ({ name, ...rest }) => {
switch (name) {
case 'app_finance':
return <IconAppFinance key="1" {...rest} />;
case 'app_clothes':
return <IconAppClothes key="2" {...rest} />;
case 'weixin':
return <IconWeixin key="1" {...rest} />;
return <IconWeixin key="3" {...rest} />;
case 'QQ':
return <IconQq key="2" {...rest} />;
return <IconQq key="4" {...rest} />;
}
return null;
@@ -1,40 +0,0 @@
import { useSafeAreaInsets } from "react-native-safe-area-context";
import React, { ReactNode } from "react";
import { View } from "react-native";
import Tabbar from "./tabbar";
import { TabbarItem } from "./tabbar";
import Navbar from "./navbar";
interface LayoutProps {
tabs: TabbarItem[];
children: ReactNode;
}
export default function Layout({ tabs, children }: LayoutProps) {
const insets = useSafeAreaInsets();
return (
<View className="flex-1 bg-white">
<View
className="flex-1"
style={{
paddingTop: insets.top + 44,
paddingBottom: insets.bottom + 56,
}}
>
{children}
</View>
<Navbar title="123" style={{ paddingTop: insets.top }} />
<View
className="absolute left-0 right-0 bottom-0"
style={{ paddingBottom: insets.bottom + 8 }}
>
<Tabbar tabs={tabs} />
</View>
</View>
);
}
@@ -74,8 +74,8 @@ export default function Navbar({
<AnimatedView style={backAnimatedStyle}>
<Shadow
distance={20}
startColor="rgba(0,0,0,0.04)"
endColor="rgba(0,0,0,0)"
startColor="rgba(248,248,248,1)"
endColor="rgba(248,248,248,0)"
offset={[0, 0]}
paintInside={false}
safeRender
@@ -90,8 +90,8 @@ export default function Navbar({
{title && (
<Shadow
distance={20}
startColor="rgba(0,0,0,0.04)"
endColor="rgba(0,0,0,0)"
startColor="rgba(248,248,248,1)"
endColor="rgba(248,248,248,0)"
offset={[0, 0]}
paintInside={false}
safeRender
@@ -121,8 +121,8 @@ export default function Navbar({
<Shadow
distance={20}
startColor="rgba(0,0,0,0.04)"
endColor="rgba(0,0,0,0)"
startColor="rgba(248,248,248,1)"
endColor="rgba(248,248,248,0)"
offset={[0, 0]}
paintInside={false}
safeRender
@@ -141,8 +141,8 @@ export default function Navbar({
</AnimatedView>
</Pressable>
<View className="w-[1px] h-4 bg-black/10" />
<View className="w-px h-4 bg-black/10" />
<Pressable
onPress={onClose}
onPressIn={() => {
@@ -31,8 +31,8 @@ export default function Tabbar({ tabs, value, onChange, className, style }: Tabb
<View className={cn("m-3", className)} style={style}>
<Shadow
distance={20}
startColor="rgba(0,0,0,0.04)"
endColor="rgba(0,0,0,0)"
startColor="rgba(248,248,248,1)"
endColor="rgba(248,248,248,0)"
style={styles.tabbarShadow}
>
<View className="w-full flex-row items-center justify-between">
@@ -140,7 +140,7 @@ function CenterButton({ tab, onPress }: { tab: TabbarItem; onPress?: () => void
> */}
<Shadow
distance={6}
startColor="rgba(0,0,0,0.06)"
startColor="rgba(0,0,0,0.03)"
endColor="rgba(0,0,0,0)"
offset={[0, 2]}
style={[styles.centerButtonShadown]}
@@ -161,8 +161,8 @@ const styles = StyleSheet.create({
borderRadius: 999,
alignItems: "center",
justifyContent: "center",
borderWidth: 1,
borderColor: "rgba(0,0,0,0.03)",
borderWidth: 0.5,
borderColor: "rgba(255,255,255,0.6)",
backgroundColor: "#22C55E",
},
tabbarShadow: {
+131 -71
View File
@@ -1,116 +1,176 @@
import React from "react";
import { ScrollView, SectionList, FlatList, View } from "react-native";
import React, { forwardRef } from "react";
import {
ScrollView,
SectionList,
FlatList,
View,
ViewProps,
StyleProp,
ViewStyle,
} from "react-native";
import { ScrollShadow } from "heroui-native";
import { LinearGradient } from "expo-linear-gradient";
import { LegendList } from "@legendapp/list";
import { useSafeAreaInsets } from "react-native-safe-area-context";
/**
* 固定额外间距(你可以随便调)
*/
const TOP_EXTRA_PADDING = 60;
const BOTTOM_EXTRA_PADDING = 80;
import { cn } from "@/utils/cn";
/* ========================= */
type LayoutConfig = {
topExtraPadding?: number;
bottomExtraPadding?: number;
};
/**
* Wrapper
*/
function Wrapper({ children }: { children: React.ReactNode }) {
return <View style={{ flex: 1, overflow: "hidden" }}>{children}</View>;
}
/**
* Shadow(只封装一次 ScrollShadow)
*/
function Shadow({ children }: { children: React.ReactElement }) {
return (
<ScrollShadow className="flex-1" size={300} LinearGradientComponent={LinearGradient}>
<ScrollShadow className="flex-1" size={120} LinearGradientComponent={LinearGradient}>
{children}
</ScrollShadow>
);
}
/**
* 统一 padding 计算
*/
function useContentPadding() {
function useContentPadding(config?: LayoutConfig) {
const insets = useSafeAreaInsets();
return {
paddingTop: insets.top + TOP_EXTRA_PADDING,
paddingBottom: insets.bottom + BOTTOM_EXTRA_PADDING,
paddingTop: insets.top + (config?.topExtraPadding ?? 50),
paddingBottom: insets.bottom + (config?.bottomExtraPadding ?? 80),
paddingHorizontal: 16,
};
}
/**
* LayoutView
*/
const LayoutView = (props: { children?: React.ReactNode }) => {
return <View style={{ flex: 1 }}>{props.children}</View>;
/* ========================= Root ========================= */
type LayoutViewProps = ViewProps &
LayoutConfig & {
className?: string;
style?: StyleProp<ViewStyle>;
children?: React.ReactNode;
};
const LayoutView = ({ className, style, children, ...rest }: LayoutViewProps) => {
return (
<View {...rest} className={cn("flex-1 bg-background", className)} style={style}>
{children}
</View>
);
};
/**
* ScrollView
*/
LayoutView.ScrollView = (props: React.ComponentProps<typeof ScrollView>) => {
const padding = useContentPadding();
/* ========================= ScrollView ========================= */
LayoutView.ScrollView = forwardRef<
ScrollView,
React.ComponentProps<typeof ScrollView> & LayoutConfig
>(({ topExtraPadding, bottomExtraPadding, contentContainerStyle, ...props }, ref) => {
const padding = useContentPadding({ topExtraPadding, bottomExtraPadding });
return (
<Wrapper>
<Shadow>
<ScrollView
ref={ref}
{...props}
showsVerticalScrollIndicator={false}
contentContainerStyle={[padding, props.contentContainerStyle]}
contentContainerStyle={[padding, contentContainerStyle]}
/>
</Shadow>
</Wrapper>
);
};
});
/**
* SectionList
*/
LayoutView.SectionView = <T,>(props: React.ComponentProps<typeof SectionList<T>>) => {
const padding = useContentPadding();
/* ========================= SectionList ========================= */
return (
<Wrapper>
<Shadow>
<SectionList {...props} contentContainerStyle={[padding, props.contentContainerStyle]} />
</Shadow>
</Wrapper>
);
};
LayoutView.SectionView = forwardRef(
<T,>(
{
topExtraPadding,
bottomExtraPadding,
contentContainerStyle,
...props
}: React.ComponentProps<typeof SectionList<T>> & LayoutConfig,
ref: React.Ref<SectionList<T>>,
) => {
const padding = useContentPadding({ topExtraPadding, bottomExtraPadding });
/**
* FlatList
*/
LayoutView.FastList = <T,>(props: React.ComponentProps<typeof FlatList<T>>) => {
const padding = useContentPadding();
return (
<Wrapper>
<Shadow>
<SectionList
ref={ref}
{...props}
contentContainerStyle={[padding, contentContainerStyle]}
/>
</Shadow>
</Wrapper>
);
},
) as <T>(
props: React.ComponentProps<typeof SectionList<T>> &
LayoutConfig & { ref?: React.Ref<SectionList<T>> },
) => React.ReactElement;
return (
<Wrapper>
<Shadow>
<FlatList {...props} contentContainerStyle={[padding, props.contentContainerStyle]} />
</Shadow>
</Wrapper>
);
};
/* ========================= FlatList ========================= */
/**
* LegendList
*/
LayoutView.LegendList = <T,>(props: React.ComponentProps<typeof LegendList<T>>) => {
const padding = useContentPadding();
LayoutView.FlatList = forwardRef(
<T,>(
{
topExtraPadding,
bottomExtraPadding,
contentContainerStyle,
...props
}: React.ComponentProps<typeof FlatList<T>> & LayoutConfig,
ref: React.Ref<FlatList<T>>,
) => {
const padding = useContentPadding({ topExtraPadding, bottomExtraPadding });
return (
<Wrapper>
<Shadow>
<LegendList<T> {...props} contentContainerStyle={[padding, props.contentContainerStyle]} />
</Shadow>
</Wrapper>
);
};
return (
<Wrapper>
<Shadow>
<FlatList ref={ref} {...props} contentContainerStyle={[padding, contentContainerStyle]} />
</Shadow>
</Wrapper>
);
},
) as <T>(
props: React.ComponentProps<typeof FlatList<T>> & LayoutConfig & { ref?: React.Ref<FlatList<T>> },
) => React.ReactElement;
/* ========================= LegendList ========================= */
LayoutView.LegendList = forwardRef(
<T,>(
{
topExtraPadding,
bottomExtraPadding,
contentContainerStyle,
...props
}: React.ComponentProps<typeof LegendList<T>> & LayoutConfig,
ref: React.Ref<any>,
) => {
const padding = useContentPadding({ topExtraPadding, bottomExtraPadding });
return (
<Wrapper>
<Shadow>
<LegendList
ref={ref}
{...props}
contentContainerStyle={[padding, contentContainerStyle]}
/>
</Shadow>
</Wrapper>
);
},
) as <T>(
props: React.ComponentProps<typeof LegendList<T>> & LayoutConfig & { ref?: React.Ref<any> },
) => React.ReactElement;
/* ========================= */
export default LayoutView;
+59 -39
View File
@@ -1,50 +1,70 @@
import { LucideIcon } from "lucide-react-native";
import { IconAppFinance, IconAppClothes } from "@/components/iconfont";
import {
StarIcon,
HouseIcon,
LayoutGridIcon,
UserRoundIcon,
MessageCircleIcon,
} from "lucide-react-native";
export interface NavItem {
export interface SubAppItem {
id: string;
title: string;
icon?: LucideIcon;
isCenter?: boolean;
children?: NavItem[];
icon: any;
group: string;
description?: string;
}
// 主
export const MainRoutes: NavItem[] = [
type HeaderItem = {
type: "header";
title: string;
};
type GroupItem = {
type: "group";
title: string;
data: SubAppItem[];
};
export type AppListItem = HeaderItem | GroupItem;
export const SUB_APPS: SubAppItem[] = [
{
id: "/",
title: "首页",
icon: HouseIcon,
id: "/money/home",
title: "记账",
icon: IconAppFinance,
group: "J",
description: "记录日常收支,管理你的每一笔钱",
},
{
id: "/star",
title: "关注",
icon: StarIcon,
},
{
id: "/app",
title: "",
icon: LayoutGridIcon,
isCenter: true,
},
{
id: "/chat",
title: "聊天",
icon: MessageCircleIcon,
},
{
id: "/my",
title: "我的",
icon: UserRoundIcon,
id: "/clothes/home",
title: "衣服搭配",
icon: IconAppClothes,
group: "Y",
description: "帮你整理每日穿搭灵感",
},
];
// 子
export function getGroupedApps(keyword?: string): AppListItem[] {
let list = SUB_APPS;
if (keyword && keyword.trim()) {
const lower = keyword.toLowerCase();
list = SUB_APPS.filter((item) => item.title.toLowerCase().includes(lower));
}
const map: Record<string, SubAppItem[]> = {};
list.forEach((item) => {
if (!map[item.group]) map[item.group] = [];
map[item.group].push(item);
});
const sortedKeys = Object.keys(map).sort((a, b) => {
if (a === "#") return 1;
if (b === "#") return -1;
return a.localeCompare(b);
});
const data: AppListItem[] = [];
sortedKeys.forEach((key) => {
data.push({ type: "header", title: key });
data.push({ type: "group", title: key, data: map[key] });
});
return data;
}
+16 -3
View File
@@ -2,7 +2,7 @@ import React from "react";
import { View, BackHandler } from "react-native";
import { Slot, useRouter, usePathname } from "expo-router";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useMemo } from "react";
import { useMemo, useRef } from "react";
import Tabbar, { TabbarItem } from "@/components/layout/tabbar";
import Navbar from "@/components/layout/navbar";
@@ -11,9 +11,22 @@ export default function AppLayout({ tabs }: { tabs: TabbarItem[] }) {
const insets = useSafeAreaInsets();
const pathname = usePathname();
const lastValidTabRef = useRef<TabbarItem | undefined>(undefined);
const activeTabItem = useMemo(() => {
return tabs.find((t) => t.id === pathname);
}, [pathname]);
const found = tabs.find((t) => t.id === pathname);
if (found?.isCenter) {
return lastValidTabRef.current;
}
if (found) {
lastValidTabRef.current = found;
return found;
}
return lastValidTabRef.current;
}, [pathname, tabs]);
function handleClose() {
BackHandler.exitApp();
+21 -16
View File
@@ -3,16 +3,29 @@ import Tabbar, { TabbarItem } from "@/components/layout/tabbar";
import Navbar from "@/components/layout/navbar";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Slot, useRouter, usePathname } from "expo-router";
import { useMemo } from "react";
import { useMemo, useRef } from "react";
export default function ModuleLayout({ tabs }: { tabs: TabbarItem[] }) {
const router = useRouter();
const insets = useSafeAreaInsets();
const pathname = usePathname();
const lastValidTabRef = useRef<TabbarItem | undefined>(undefined);
const activeTabItem = useMemo(() => {
return tabs.find((t) => t.id === pathname);
}, [pathname]);
const found = tabs.find((t) => t.id === pathname);
if (found?.isCenter) {
return lastValidTabRef.current;
}
if (found) {
lastValidTabRef.current = found;
return found;
}
return lastValidTabRef.current;
}, [pathname, tabs]);
function handleClose() {
router.replace("/(tabs)/home");
@@ -33,11 +46,7 @@ export default function ModuleLayout({ tabs }: { tabs: TabbarItem[] }) {
zIndex: 10,
}}
>
<View
style={{
paddingTop: insets.top,
}}
>
<View style={{ paddingTop: insets.top }}>
<Navbar
title={activeTabItem?.title}
titleIcon={activeTabItem?.icon}
@@ -52,17 +61,13 @@ export default function ModuleLayout({ tabs }: { tabs: TabbarItem[] }) {
position: "absolute",
left: 0,
right: 0,
bottom: insets.bottom + 16,
bottom: 0,
zIndex: 10,
}}
>
<Tabbar
tabs={tabs}
value={activeTabItem?.id}
onChange={(id) => {
router.push(id as any);
}}
/>
<View style={{ paddingBottom: insets.bottom }}>
<Tabbar tabs={tabs} value={activeTabItem?.id} onChange={(id) => router.push(id as any)} />
</View>
</View>
</View>
);
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="862.70323" height="644.78592" viewBox="0 0 862.70323 644.78592" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" artist="Katerina Limpitsouni" source="https://undraw.co/"><polygon points="629.943 612.644 612.777 612.644 604.608 546.435 629.943 546.435 629.943 612.644" fill="#9e616a"/><path d="M807.65107,769.99215H795.34112l-2.19727-11.62205-5.62754,11.62205H754.86738A7.33919,7.33919,0,0,1,750.697,756.6135l26.07247-18.00658v-11.7495l27.42368,1.63683Z" transform="translate(-168.64838 -127.60704)" fill="#2f2e41"/><polygon points="731.923 590.981 718.148 601.224 672.085 552.969 692.415 537.851 731.923 590.981" fill="#9e616a"/><path d="M925.58816,737.04791,915.71,744.39344l-8.69827-8.015,2.41922,12.68419-26.19923,19.48211a7.33918,7.33918,0,0,1-11.32976-8.24721l10.17712-30.00728-7.0111-9.42842,22.98294-15.05066Z" transform="translate(-168.64838 -127.60704)" fill="#2f2e41"/><path d="M818.57583,398.64705s32.56879,28.13791,17.542,108.35207l-18.3454,78.59653,59.8294,99.2561-19.07664,23.20771-77.77961-107.4334-28.18529-66.11365L744.6516,416.843Z" transform="translate(-168.64838 -127.60704)" fill="#2f2e41"/><polygon points="599.447 425.746 597.488 456.084 603.483 585.365 631.692 580.452 637.083 488.406 599.447 425.746" fill="#2f2e41"/><polygon points="237.445 628.211 252.796 628.21 260.098 569.001 237.443 569.002 237.445 628.211" fill="#ffb6b6"/><path d="M402.178,750.80612l4.32074-.00018,16.86888-6.86018,9.0412,6.85913H432.41A19.26648,19.26648,0,0,1,451.67546,770.07v.62605l-49.49658.00183Z" transform="translate(-168.64838 -127.60704)" fill="#2f2e41"/><polygon points="296.932 618.538 311.905 621.918 332.071 565.772 309.972 560.782 296.932 618.538" fill="#ffb6b6"/><path d="M462.86463,740.39329l4.21465.9516,17.96568-2.97583,7.3082,8.68223.0012.00027a19.26648,19.26648,0,0,1,14.54854,23.03569l-.1379.61067L458.48379,759.7967Z" transform="translate(-168.64838 -127.60704)" fill="#2f2e41"/><path d="M386.6516,393.843c-7.19708,21.70636-6.43618,45.268,1.72992,70.55606l3.49087,142.37821S386.67128,700.146,403.4543,733.00177h24.34l12.05112-134.75129,1.5133-90.44591,52.18244,76.30583L460.30462,730.79868l29.9568,2.678,53.93408-159.1909L477.6516,419.843Z" transform="translate(-168.64838 -127.60704)" fill="#2f2e41"/><path d="M667.346,332.01487c18.61732-16.77656,46.30893-25.21208,69.53714-15.805a115.466,115.466,0,0,0-51.888,59.93484c-3.6979,9.83846-6.78644,21.16623-15.88188,26.43349-5.65933,3.27753-12.70027,3.4377-19.04568,1.85557-6.34568-1.58237-12.16226-4.75415-17.89913-7.89422l-1.63218-.03691C637.86406,372.53682,648.72872,348.79142,667.346,332.01487Z" transform="translate(-168.64838 -127.60704)" fill="#e6e6e6"/><path d="M736.75328,316.71942A98.69239,98.69239,0,0,0,681.847,342.64994a42.50049,42.50049,0,0,0-8.34534,10.37667,24.37584,24.37584,0,0,0-2.81751,12.51568c.10054,4.05833.67335,8.19792-.21438,12.21a14.92537,14.92537,0,0,1-7.42454,9.68865c-4.54586,2.613-9.7595,3.43673-14.886,4.0651-5.692.69769-11.61526,1.33219-16.54238,4.5248-.597.38683-1.16231-.56211-.56622-.94836,8.57235-5.5546,19.41969-3.5335,28.63724-7.24065,4.30108-1.72983,8.10691-4.76631,9.454-9.35719,1.17794-4.01452.5909-8.2838.45359-12.39207a26.01068,26.01068,0,0,1,2.299-12.34028,39.29038,39.29038,0,0,1,7.9156-10.65924,95.74917,95.74917,0,0,1,24.3333-17.41978A100.44256,100.44256,0,0,1,736.743,315.61475c.70319-.09065.70886,1.01461.01026,1.10467Z" transform="translate(-168.64838 -127.60704)" fill="#fff"/><path d="M686.44718,337.79134a14.807,14.807,0,0,1,1.63241-19.1039c.50628-.49873,1.30506.26457.79811.764a13.71094,13.71094,0,0,0-1.48216,17.77371c.41512.5769-.53561,1.13983-.94836.56623Z" transform="translate(-168.64838 -127.60704)" fill="#fff"/><path d="M670.36216,363.49127a28.53932,28.53932,0,0,0,20.3938-4.08346c.59834-.38471,1.16384.56412.56622.94836a29.68517,29.68517,0,0,1-21.23023,4.20607c-.70085-.12626-.42683-1.19655.27021-1.071Z" transform="translate(-168.64838 -127.60704)" fill="#fff"/><path d="M714.44656,321.9478a8.38148,8.38148,0,0,0,6.2686,4.89443c.7021.11732.42732,1.18753-.27021,1.071a9.39213,9.39213,0,0,1-6.94675-5.39917.57084.57084,0,0,1,.19107-.7573.55506.55506,0,0,1,.75729.19107Z" transform="translate(-168.64838 -127.60704)" fill="#fff"/><path d="M762.46124,397.11454c-.44048-.06079-.881-.12157-1.32791-.1756a110.37862,110.37862,0,0,0-17.88208-.90839c-.46221.00673-.93053.02051-1.39159.0405a116.3646,116.3646,0,0,0-41.75015,9.61014,113.00482,113.00482,0,0,0-15.16291,8.0555c-6.68773,4.23438-13.602,9.35764-21.078,11.08459a19.38584,19.38584,0,0,1-2.36217.42086l-30.88864-26.74546c-.03969-.096-.0858-.18531-.12584-.28162l-1.28212-1.01147c.23872-.17556.49008-.35251.72879-.52808.138-.10241.283-.19887.421-.30128.09422-.06639.18881-.13253.27-.19782.03128-.02222.0629-.04413.08811-.05934.08122-.06529.1636-.11732.23871-.17556q2.10345-1.4895,4.23516-2.95463c.00611-.007.00611-.007.0191-.00815a166.15689,166.15689,0,0,1,34.601-18.59939c.36686-.13859.73948-.28453,1.12045-.4109a107.831,107.831,0,0,1,16.93919-4.76651,95.32878,95.328Line truncated

Before

Width:  |  Height:  |  Size: 21 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1119.60911" height="699" viewBox="0 0 1119.60911 699" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" artist="Katerina Limpitsouni" source="https://undraw.co/"><title>server down</title><circle cx="292.60911" cy="213" r="213" fill="#f2f2f2"/><path d="M31.39089,151.64237c0,77.49789,48.6181,140.20819,108.70073,140.20819" transform="translate(-31.39089 -100.5)" fill="#2f2e41"/><path d="M140.09162,291.85056c0-78.36865,54.255-141.78356,121.30372-141.78356" transform="translate(-31.39089 -100.5)" fill="#6c63ff"/><path d="M70.77521,158.66768c0,73.61476,31.00285,133.18288,69.31641,133.18288" transform="translate(-31.39089 -100.5)" fill="#6c63ff"/><path d="M140.09162,291.85056c0-100.13772,62.7103-181.16788,140.20819-181.16788" transform="translate(-31.39089 -100.5)" fill="#2f2e41"/><path d="M117.22379,292.83905s15.41555-.47479,20.06141-3.783,23.713-7.2585,24.86553-1.95278,23.16671,26.38821,5.76263,26.5286-40.43935-2.711-45.07627-5.53549S117.22379,292.83905,117.22379,292.83905Z" transform="translate(-31.39089 -100.5)" fill="#a8a8a8"/><path d="M168.224,311.78489c-17.40408.14042-40.43933-2.71094-45.07626-5.53548-3.53126-2.151-4.93843-9.86945-5.40926-13.43043-.32607.014-.51463.02-.51463.02s.97638,12.43276,5.61331,15.2573,27.67217,5.67589,45.07626,5.53547c5.02386-.04052,6.7592-1.82793,6.66391-4.47526C173.87935,310.756,171.96329,311.75474,168.224,311.78489Z" transform="translate(-31.39089 -100.5)" opacity="0.2"/><ellipse cx="198.60911" cy="424.5" rx="187" ry="25.43993" fill="#3f3d56"/><ellipse cx="198.60911" cy="424.5" rx="157" ry="21.35866" opacity="0.1"/><ellipse cx="836.60911" cy="660.5" rx="283" ry="38.5" fill="#3f3d56"/><ellipse cx="310.60911" cy="645.5" rx="170" ry="23.12721" fill="#3f3d56"/><path d="M494,726.5c90,23,263-30,282-90" transform="translate(-31.39089 -100.5)" fill="none" stroke="#2f2e41" stroke-miterlimit="10" stroke-width="2"/><path d="M341,359.5s130-36,138,80-107,149-17,172" transform="translate(-31.39089 -100.5)" fill="none" stroke="#2f2e41" stroke-miterlimit="10" stroke-width="2"/><path d="M215.40233,637.78332s39.0723-10.82,41.47675,24.04449-32.15951,44.78287-5.10946,51.69566" transform="translate(-31.39089 -100.5)" fill="none" stroke="#2f2e41" stroke-miterlimit="10" stroke-width="2"/><path d="M810.09554,663.73988,802.218,714.03505s-38.78182,20.60284-11.51335,21.20881,155.73324,0,155.73324,0,24.84461,0-14.54318-21.81478l-7.87756-52.719Z" transform="translate(-31.39089 -100.5)" fill="#2f2e41"/><path d="M785.21906,734.69812c6.193-5.51039,16.9989-11.252,16.9989-11.252l7.87756-50.2952,113.9216.10717,7.87756,49.582c9.185,5.08711,14.8749,8.987,18.20362,11.97818,5.05882-1.15422,10.58716-5.44353-18.20362-21.38921l-7.87756-52.719-113.9216,3.02983L802.218,714.03506S769.62985,731.34968,785.21906,734.69812Z" transform="translate(-31.39089 -100.5)" opacity="0.1"/><rect x="578.43291" y="212.68859" width="513.25314" height="357.51989" rx="18.04568" fill="#2f2e41"/><rect x="595.70294" y="231.77652" width="478.71308" height="267.83694" fill="#3f3d56"/><circle cx="835.05948" cy="223.29299" r="3.02983" fill="#f2f2f2"/><path d="M1123.07694,621.32226V652.6628a18.04341,18.04341,0,0,1-18.04568,18.04568H627.86949A18.04341,18.04341,0,0,1,609.8238,652.6628V621.32226Z" transform="translate(-31.39089 -100.5)" fill="#2f2e41"/><polygon points="968.978 667.466 968.978 673.526 642.968 673.526 642.968 668.678 643.417 667.466 651.452 645.651 962.312 645.651 968.978 667.466" fill="#2f2e41"/><path d="M1125.828,762.03359c-.59383,2.539-2.83591,5.21743-7.90178,7.75032-18.179,9.08949-55.1429-2.42386-55.1429-2.42386s-28.4804-4.84773-28.4804-17.573a22.72457,22.72457,0,0,1,2.49658-1.48459c7.64294-4.04351,32.98449-14.02122,77.9177.42248a18.73921,18.73921,0,0,1,8.54106,5.59715C1125.07908,756.45353,1126.50669,759.15715,1125.828,762.03359Z" transform="translate(-31.39089 -100.5)" fill="#2f2e41"/><path d="M1125.828,762.03359c-22.251,8.526-42.0843,9.1622-62.43871-4.975-10.26507-7.12617-19.59089-8.88955-26.58979-8.75618,7.64294-4.04351,32.98449-14.02122,77.9177.42248a18.73921,18.73921,0,0,1,8.54106,5.59715C1125.07908,756.45353,1126.50669,759.15715,1125.828,762.03359Z" transform="translate(-31.39089 -100.5)" opacity="0.1"/><ellipse cx="1066.53846" cy="654.13477" rx="7.87756" ry="2.42386" fill="#f2f2f2"/><circle cx="835.05948" cy="545.66686" r="11.51335" fill="#f2f2f2"/><polygon points="968.978 667.466 968.978 673.526 642.968 673.526 642.968 668.678 643.417 667.466 968.978 667.466" opacity="0.1"/><rect x="108.60911" y="159" width="208" height="242" fill="#2f2e41"/><rect x="87.60911" y="135" width="250" height="86" fill="#3f3d56"/><rect x="87.60911" y="237" width="250" height="86" fill="#3f3d56"/><rect x="87.60911" y="339" width="250" height="86" fill="#3f3d56"/><rect x="271.60911" y="150" width="16" height="16" fill="#6c63ff" opacity="0.4"/><rect x="294.60911" y="150" width="16" height="16" fill="#6c63ff" opacity="0.8"/><rect x="317.60911" y="150" width="16" height="16" fill="#6c63ff"/><rect x="271Line truncated

Before

Width:  |  Height:  |  Size: 6.4 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="860.13137" height="571.14799" viewBox="0 0 860.13137 571.14799" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" artist="Katerina Limpitsouni" source="https://undraw.co/"><path d="M605.66974,324.95306c-7.66934-12.68446-16.7572-26.22768-30.98954-30.36953-16.482-4.7965-33.4132,4.73193-47.77473,14.13453a1392.15692,1392.15692,0,0,0-123.89338,91.28311l.04331.49238q46.22556-3.1878,92.451-6.37554c22.26532-1.53546,45.29557-3.2827,64.97195-13.8156,7.46652-3.99683,14.74475-9.33579,23.20555-9.70782,10.51175-.46217,19.67733,6.87923,26.8802,14.54931,42.60731,45.371,54.937,114.75409,102.73817,154.61591A1516.99453,1516.99453,0,0,0,605.66974,324.95306Z" transform="translate(-169.93432 -164.42601)" fill="#f2f2f2"/><path d="M867.57068,709.78146c-4.71167-5.94958-6.6369-7.343-11.28457-13.34761q-56.7644-73.41638-106.70791-151.79237-33.92354-53.23-64.48275-108.50439-14.54864-26.2781-28.29961-52.96872-10.67044-20.6952-20.8646-41.63793c-1.94358-3.98782-3.8321-7.99393-5.71122-12.00922-4.42788-9.44232-8.77341-18.93047-13.43943-28.24449-5.31686-10.61572-11.789-21.74485-21.55259-28.877a29.40493,29.40493,0,0,0-15.31855-5.89458c-7.948-.51336-15.28184,2.76855-22.17568,6.35295-50.43859,26.301-97.65922,59.27589-140.3696,96.79771A730.77816,730.77816,0,0,0,303.32241,496.24719c-1.008,1.43927-3.39164.06417-2.37419-1.38422q6.00933-8.49818,12.25681-16.81288A734.817,734.817,0,0,1,500.80465,303.06436q18.24824-11.82581,37.18269-22.54245c6.36206-3.60275,12.75188-7.15967,19.25136-10.49653,6.37146-3.27274,13.13683-6.21547,20.41563-6.32547,24.7701-.385,37.59539,27.66695,46.40506,46.54248q4.15283,8.9106,8.40636,17.76626,16.0748,33.62106,33.38729,66.628,10.68453,20.379,21.83683,40.51955,34.7071,62.71816,73.77854,122.897c34.5059,53.1429,68.73651,100.08874,108.04585,149.78472C870.59617,709.21309,868.662,711.17491,867.57068,709.78146Z" transform="translate(-169.93432 -164.42601)" fill="#e4e4e4"/><path d="M414.91613,355.804c-1.43911-1.60428-2.86927-3.20856-4.31777-4.81284-11.42244-12.63259-23.6788-25.11847-39.3644-32.36067a57.11025,57.11025,0,0,0-23.92679-5.54622c-8.56213.02753-16.93178,2.27348-24.84306,5.41792-3.74034,1.49427-7.39831,3.1902-11.00078,4.99614-4.11634,2.07182-8.15927,4.28118-12.1834,6.50883q-11.33112,6.27044-22.36816,13.09089-21.9606,13.57221-42.54566,29.21623-10.67111,8.11311-20.90174,16.75788-9.51557,8.03054-18.64618,16.492c-1.30169,1.20091-3.24527-.74255-1.94358-1.94347,1.60428-1.49428,3.22691-2.97938,4.84955-4.44613q6.87547-6.21546,13.9712-12.19257,12.93921-10.91827,26.54851-20.99312,21.16293-15.67614,43.78288-29.22541,11.30361-6.76545,22.91829-12.96259c2.33794-1.24675,4.70318-2.466,7.09572-3.6211a113.11578,113.11578,0,0,1,16.86777-6.86632,60.0063,60.0063,0,0,1,25.476-2.50265,66.32706,66.32706,0,0,1,23.50512,8.1314c15.40091,8.60812,27.34573,21.919,38.97,34.90915C418.03337,355.17141,416.09875,357.12405,414.91613,355.804Z" transform="translate(-169.93432 -164.42601)" fill="#e4e4e4"/><path d="M730.47659,486.71092l36.90462-13.498,18.32327-6.70183c5.96758-2.18267,11.92082-4.66747,18.08988-6.23036a28.53871,28.53871,0,0,1,16.37356.20862,37.73753,37.73753,0,0,1,12.771,7.91666,103.63965,103.63965,0,0,1,10.47487,11.18643c3.98932,4.79426,7.91971,9.63877,11.86772,14.46706q24.44136,29.89094,48.56307,60.04134,24.12117,30.14991,47.91981,60.556,23.85681,30.48041,47.38548,61.21573,2.88229,3.76518,5.75966,7.53415c1.0598,1.38809,3.44949.01962,2.37472-1.38808Q983.582,650.9742,959.54931,620.184q-24.09177-30.86383-48.51647-61.46586-24.42421-30.60141-49.17853-60.93743-6.16706-7.55761-12.35445-15.09858c-3.47953-4.24073-6.91983-8.52718-10.73628-12.47427-7.00539-7.24516-15.75772-13.64794-26.23437-13.82166-6.15972-.10214-12.121,1.85248-17.844,3.92287-6.16968,2.232-12.32455,4.50571-18.48633,6.75941l-37.16269,13.59243-9.29067,3.3981c-1.64875.603-.93651,3.2619.73111,2.652Z" transform="translate(-169.93432 -164.42601)" fill="#e4e4e4"/><path d="M366.37741,334.52609c-18.75411-9.63866-42.77137-7.75087-60.00508,4.29119a855.84708,855.84708,0,0,1,97.37056,22.72581C390.4603,353.75916,380.07013,341.5635,366.37741,334.52609Z" transform="translate(-169.93432 -164.42601)" fill="#f2f2f2"/><path d="M306.18775,338.7841l-3.61042,2.93462c1.22123-1.02713,2.4908-1.99013,3.795-2.90144C306.31073,338.80665,306.24935,338.79473,306.18775,338.7841Z" transform="translate(-169.93432 -164.42601)" fill="#f2f2f2"/><path d="M831.54929,486.84576c-3.6328-4.42207-7.56046-9.05222-12.99421-10.84836l-5.07308.20008A575.436,575.436,0,0,0,966.74929,651.418Q899.14929,569.13192,831.54929,486.84576Z" transform="translate(-169.93432 -164.42601)" fill="#f2f2f2"/><path d="M516.08388,450.36652A37.4811,37.4811,0,0,0,531.015,471.32518c2.82017,1.92011,6.15681,3.76209,7.12158,7.03463a8.37858,8.37858,0,0,1-.87362,6.1499,24.88351,24.88351,0,0,1-3.86126,5.04137l-.13667.512c-6.99843-4.14731-13.65641-9.3934-17.52227-16.55115s-4.40553-16.53895.34116-23.14544" transform="translate(-169.93432 -164.42601)" fill="#f2f2f2"/><path d="M749.08388,653.36652A37.4811,37.4811,0,0,0,76Line truncated

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

+18
View File
@@ -0,0 +1,18 @@
import { axiosRequestAdapter } from "@alova/adapter-axios";
import { createAlova } from "alova";
export const alovaInstance = createAlova({
requestAdapter: axiosRequestAdapter(),
responded: {
onSuccess: async (response) => response.data,
onError: (err) => Promise.reject(err),
},
});
// ======================
// 地区和天气
// ======================
export const fetchDailyInfo = () => {
return alovaInstance.Get("https://60s.aa1.cn/60s-api/new/api/weather/");
};