Compare commits

...

2 Commits

Author SHA1 Message Date
817b1dd8a0 feat: 轮播图 2025-07-22 14:32:44 +08:00
bc73f5c52c feat: 个人中心排版 2025-07-22 11:34:17 +08:00
9 changed files with 81 additions and 65 deletions

View File

@ -1,15 +1,14 @@
import ComeinSvg from '@/assets/icons/svg/comein.svg';
import ConversationsSvg from '@/assets/icons/svg/conversations.svg';
import PointsSvg from '@/assets/icons/svg/points.svg';
import StoriesSvg from '@/assets/icons/svg/stories.svg';
import UsedStorageSvg from '@/assets/icons/svg/usedStorage.svg';
import AskNavbar from '@/components/layout/ask';
import AlbumComponent from '@/components/owner/album';
import CarouselComponent from '@/components/owner/carousel';
import CreateCountComponent from '@/components/owner/createCount';
import Ranking from '@/components/owner/ranking';
import ResourceComponent from '@/components/owner/resource';
import SettingModal from '@/components/owner/setting';
import UserInfo from '@/components/owner/userName';
import { ThemedText } from '@/components/ThemedText';
import { checkAuthStatus } from '@/lib/auth';
import { fetchApi } from '@/lib/server-api-util';
import { CountData, UserInfoDetails } from '@/types/user';
@ -86,13 +85,16 @@ export default function OwnerPage() {
{/* 资源数据 */}
<View style={styles.resourceContainer}>
<View style={{ gap: 16 }}>
<ResourceComponent title={t("generalSetting.usedStorage", { ns: "personal" })} data={{ all: userInfoDetails.total_bytes, used: countData.used_bytes }} icon={<UsedStorageSvg />} isFormatBytes={true} />
<ResourceComponent title={t("generalSetting.remainingPoints", { ns: "personal" })} data={{ all: userInfoDetails.total_points, used: userInfoDetails.remain_points }} icon={<PointsSvg />} />
<View style={{ gap: 4 }}>
<ThemedText style={styles.text}>{t("generalSetting.premium", { ns: "personal" })}</ThemedText>
<ThemedText style={styles.secondText}>{t("generalSetting.unlock", { ns: "personal" })}</ThemedText>
</View>
<ComeinSvg width={24} height={24} />
</View>
{/* 分类 */}
<CarouselComponent data={userInfoDetails?.material_counter} />
<View style={{ marginHorizontal: -16 }}>
<CarouselComponent data={userInfoDetails?.material_counter} />
</View>
{/* 作品数据 */}
<View className='flex flex-row justify-between gap-[1rem]'>
@ -127,11 +129,20 @@ const styles = StyleSheet.create({
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
gap: 16,
backgroundColor: "#FAF9F6",
padding: 16,
backgroundColor: "#4C320C",
paddingVertical: 8,
paddingHorizontal: 32,
borderRadius: 18,
paddingTop: 20
},
text: {
fontSize: 12,
fontWeight: '700',
color: '#FFB645',
},
secondText: {
fontSize: 16,
fontWeight: '700',
color: '#fff',
},
userInfo: {
flexDirection: 'row',

View File

@ -0,0 +1,3 @@
<svg width="11" height="20" viewBox="0 0 11 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.0002 1L9.77832 9.77812L1.0002 18.5562" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 235 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 0C8 0 8.4414 5.71995 10.1607 7.43927C11.88 9.1586 16 9.6 16 9.6C16 9.6 11.88 10.0414 10.1607 11.7607C8.4414 13.4801 8 16 8 16C8 16 7.5586 13.4801 5.83927 11.7607C4.11995 10.0414 0 9.6 0 9.6C0 9.6 4.11995 9.1586 5.83927 7.43927C7.5586 5.71995 8 0 8 0Z" fill="#FFB645"/>
</svg>

After

Width:  |  Height:  |  Size: 384 B

View File

@ -11,10 +11,10 @@ const AlbumComponent = ({ setModalVisible, style }: CategoryProps) => {
const { t } = useTranslation();
return (
<View style={[styles.container, style]}>
<TouchableOpacity style={{ flex: 3, opacity: 0 }}>
<TouchableOpacity style={{ flex: 3 }}>
<ThemedText style={styles.text}>{t('generalSetting.album', { ns: 'personal' })}</ThemedText>
</TouchableOpacity>
<TouchableOpacity style={{ flex: 3, opacity: 0 }}>
<TouchableOpacity style={{ flex: 3 }}>
<ThemedText style={styles.text}>{t('generalSetting.shareProfile', { ns: 'personal' })}</ThemedText>
</TouchableOpacity>
<TouchableOpacity onPress={() => setModalVisible(true)} style={[styles.text, { flex: 1, alignItems: "center", paddingVertical: 6 }]}>

View File

@ -3,10 +3,7 @@ import UserinfoTotalSvg from "@/assets/icons/svg/userinfoTotal.svg";
import { Counter, UserCountData } from "@/types/user";
import * as React from "react";
import { Dimensions, StyleSheet, View, ViewStyle } from "react-native";
import { useSharedValue } from "react-native-reanimated";
import Carousel, {
ICarouselInstance
} from "react-native-reanimated-carousel";
import Carousel from "react-native-reanimated-carousel";
import { ThemedText } from "../ThemedText";
import { formatDuration } from "../utils/time";
import CategoryComponent from "./category";
@ -23,9 +20,6 @@ const width = Dimensions.get("window").width;
function CarouselComponent(props: Props) {
const { data } = props;
const ref = React.useRef<ICarouselInstance>(null);
const progress = useSharedValue<number>(0);
const [carouselDataValue, setCarouselDataValue] = React.useState<CarouselData[]>([]);
const dataHandle = () => {
const carouselData = { ...data?.category_count, total_count: data?.total_count }
@ -56,8 +50,8 @@ function CarouselComponent(props: Props) {
</View>
))}
<View style={styles.image}>
<UserinfoTotalSvg />
<View style={{ position: 'absolute', bottom: -5, right: 0, left: 0, justifyContent: 'center', alignItems: 'center' }}><HandersSvg /></View>
<UserinfoTotalSvg width={width * 0.8} />
<View style={{ position: 'absolute', bottom: 5, right: 0, left: 0, justifyContent: 'center', alignItems: 'center' }}><HandersSvg /></View>
</View>
</View>
}
@ -69,27 +63,30 @@ function CarouselComponent(props: Props) {
}, [data]);
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<View style={{ flex: 1 }}>
<Carousel
ref={ref}
width={width * 0.8}
height={width * 0.8}
width={width}
height={width * 0.75}
data={carouselDataValue || []}
mode="parallax"
onProgressChange={progress}
defaultIndex={carouselDataValue?.findIndex((item) => item?.key === 'total_count') - 1 || 0}
modeConfig={{
parallaxScrollingScale: 1,
parallaxScrollingOffset: 180,
parallaxAdjacentItemScale: 0.7
}}
renderItem={({ item, index }) => {
const style: ViewStyle = {
marginHorizontal: 10,
width: '92%',
height: '92%',
width: width,
height: width * 0.8,
alignItems: "center",
};
return (
<View key={index} style={style}>
{item?.key === 'total_count' ? (
totleItem(item.value)
) : (
<View style={{ flex: 1 }}>
<View style={{ flex: 1, width: width * 0.65 }}>
{CategoryComponent({
title: item?.key,
data: [
@ -116,12 +113,13 @@ const styles = StyleSheet.create({
borderRadius: 16,
display: "flex",
flexDirection: "column",
height: '100%',
position: 'relative',
width: width * 0.6,
height: '85%'
},
image: {
position: 'absolute',
bottom: 0,
bottom: -10,
right: 0,
left: 0,
width: '100%',

View File

@ -27,7 +27,8 @@ const Ranking = ({ data }: { data: TitleRankings[] }) => {
renderItem={({ item }) => (
<View style={styles.item}>
<ThemedText style={styles.rank}>No.{item.ranking}</ThemedText>
<ThemedText style={styles.title}>{item.region}{item.display_name}</ThemedText>
<ThemedText style={[styles.title]}>{item.display_name}</ThemedText>
<ThemedText style={styles.title}>{item.region}</ThemedText>
</View>
)}
/>

View File

@ -1,15 +1,31 @@
import UserSvg from '@/assets/icons/svg/ataver.svg';
import StarSvg from '@/assets/icons/svg/star.svg';
import { ThemedText } from '@/components/ThemedText';
import { UserInfoDetails } from '@/types/user';
import { useState } from 'react';
import { Image, ScrollView, View } from 'react-native';
import CopyButton from '../copy';
export default function UserInfo({ userInfo }: { userInfo: UserInfoDetails }) {
// 添加状态来跟踪图片加载状态
const [imageError, setImageError] = useState(false);
return (
<View className='flex flex-row justify-between items-center mt-[1rem] gap-[1rem] w-full'>
{/* 头像 */}
<View className='w-auto'>
{userInfo?.user_info?.avatar_file_url && !imageError ? (
<Image
source={{ uri: userInfo.user_info.avatar_file_url }}
style={{ width: 70, height: 70, borderRadius: 40 }}
onError={() => {
setImageError(true);
}}
/>
) : (
<UserSvg width={70} height={70} />
)}
</View>
{/* 用户名 */}
<View className='flex flex-col gap-4 w-[75%]'>
<View className='flex flex-col w-[75%] gap-1'>
<View className='flex flex-row items-center justify-between w-full'>
<View className='flex flex-row items-center gap-2 w-full'>
<ThemedText
@ -39,38 +55,18 @@ export default function UserInfo({ userInfo }: { userInfo: UserInfoDetails }) {
))
}
</ScrollView>
<View className='flex flex-row items-center gap-2 border border-bgPrimary px-2 py-1 rounded-full'>
<StarSvg />
<ThemedText style={{ color: 'bgPrimary', fontSize: 14, fontWeight: '700' }}>{userInfo?.remain_points}</ThemedText>
</View>
</View>
</View>
<View>
<ScrollView
className='max-w-[85%]'
horizontal // 水平滚动
showsHorizontalScrollIndicator={false} // 隐藏滚动条
contentContainerStyle={{
flexDirection: 'row',
gap: 8 // 间距
}}
>
<ThemedText style={{ color: '#AC7E35', fontSize: 12, fontWeight: '600' }}>User ID {userInfo?.user_info?.user_id}</ThemedText>
</ScrollView>
{/* <CopyButton textToCopy={userInfo?.user_info?.user_id || ""} /> */}
<View style={{ display: "flex", flexDirection: "row", gap: 2, alignItems: "center" }}>
<ThemedText style={{ color: '#AC7E35', fontSize: 12, fontWeight: '600' }}>User ID{userInfo?.user_info?.user_id}</ThemedText>
<CopyButton textToCopy={userInfo?.user_info?.user_id || ""} />
</View>
</View>
</View>
{/* 头像 */}
<View className='w-auto'>
{userInfo?.user_info?.avatar_file_url && !imageError ? (
<Image
source={{ uri: userInfo.user_info.avatar_file_url }}
style={{ width: 80, height: 80, borderRadius: 40 }}
onError={() => {
setImageError(true);
}}
/>
) : (
<UserSvg width={80} height={80} />
)}
</View>
</View >
);
}

View File

@ -83,6 +83,8 @@
"videoLength": "Video Duration",
"storiesCreated": "Stories Created",
"conversationsWithMemo": "Conversations with Memo",
"setting": "Settings"
"setting": "Settings",
"premium": "Upgrade to Premium",
"unlock": "Unlock more memory magic"
}
}

View File

@ -83,6 +83,8 @@
"videoLength": "视频时长",
"storiesCreated": "创作视频",
"conversationsWithMemo": "Memo对话",
"setting": "设置"
"setting": "设置",
"premium": "升级至会员",
"unlock": "解锁更多记忆魔法"
}
}