This commit is contained in:
郭文文 2026-01-29 11:53:55 +08:00
parent 32ff57f523
commit f5c3639a0b
1 changed files with 114 additions and 56 deletions

View File

@ -18,6 +18,8 @@ import { useLikesTemplates } from '@/hooks/data/use-likes-templates'
import { userBalanceStore, userStore } from '@/stores' import { userBalanceStore, userStore } from '@/stores'
import { screenWidth, storage } from '@/utils' import { screenWidth, storage } from '@/utils'
import { cn } from '@/utils/cn' import { cn } from '@/utils/cn'
import ParallelogramButton from '@/components/ParallelogramButton'
import ParallelogramShape from '@/components/ParallelogramShape'
const CATEGORY_ID = process.env.EXPO_PUBLIC_INDEX_GROUP_ID const CATEGORY_ID = process.env.EXPO_PUBLIC_INDEX_GROUP_ID
const ITEM_WIDTH = Math.floor((screenWidth - 24 - 12 * 2) / 3) const ITEM_WIDTH = Math.floor((screenWidth - 24 - 12 * 2) / 3)
@ -38,8 +40,7 @@ type MediaItem = {
authorName?: string authorName?: string
isLiked?: boolean isLiked?: boolean
} }
type ActiveTab = 'gen' | '' | 'new' | 'like' type ActiveTab = 'gen' | 'HOT' | 'NEW' | 'LIKE'
/** ========================= /** =========================
* Entry page * Entry page
* ========================= */ * ========================= */
@ -53,7 +54,7 @@ const Index = observer(function Index() {
/** ================= 状态 ================= */ /** ================= 状态 ================= */
const [activeTab, setActiveTab] = useState<ActiveTab>('') const [activeTab, setActiveTab] = useState<ActiveTab>('HOT')
const [isSearchOpen, setIsSearchOpen] = useState(false) const [isSearchOpen, setIsSearchOpen] = useState(false)
const [allItems, setAllItems] = useState<MediaItem[]>([]) const [allItems, setAllItems] = useState<MediaItem[]>([])
@ -142,7 +143,7 @@ const Index = observer(function Index() {
const { page, pageSize, search, tab } = queryRef.current const { page, pageSize, search, tab } = queryRef.current
let newItems: MediaItem[] = [] let newItems: MediaItem[] = []
if (tab === 'like') { if (tab === 'LIKE') {
console.log('加载收藏列表isAuthenticated=', isLogin) console.log('加载收藏列表isAuthenticated=', isLogin)
if (!isLogin) { if (!isLogin) {
setHasMore(false) setHasMore(false)
@ -155,7 +156,7 @@ const Index = observer(function Index() {
.map((f) => transformTemplateToMediaItem(f.template as TemplateData)) || [] .map((f) => transformTemplateToMediaItem(f.template as TemplateData)) || []
} }
} else { } else {
const sortBy = tab === 'new' ? 'createdAt' : 'likeCount' const sortBy = tab === 'NEW' ? 'createdAt' : 'likeCount'
const { data } = await loadTemplates({ const { data } = await loadTemplates({
page, page,
limit: pageSize, limit: pageSize,
@ -357,7 +358,7 @@ const Index = observer(function Index() {
} }
const renderListEmpty = () => { const renderListEmpty = () => {
if (activeTab === 'like' && !isLogin) { if (activeTab === 'LIKE' && !isLogin) {
return ( return (
<Block className="mt-[40px] items-center justify-center gap-[16px] py-[60px]"> <Block className="mt-[40px] items-center justify-center gap-[16px] py-[60px]">
<Block className="size-[80px] items-center justify-center rounded-full border-4 border-white/20 bg-white/10"> <Block className="size-[80px] items-center justify-center rounded-full border-4 border-white/20 bg-white/10">
@ -526,35 +527,54 @@ const SearchOverlay = memo<SearchOverlayProps>(function SearchOverlay({ isOpen,
onSearch('') onSearch('')
onClose?.() onClose?.()
}, [onClose, onSearch]) }, [onClose, onSearch])
const searchHeight = 48
const closeSize = 48
const skewOffset = 8 // 统一所有平行四边形的倾斜角度
const padding = 2
const searchWidth = screenWidth - 40 - 8 - closeSize
if (!isOpen) return null if (!isOpen) return null
return ( return (
<Block className="absolute inset-x-0 top-0 z-50 mt-[24px] flex-row items-center gap-[8px] px-[20px]"> <Block className="absolute inset-x-0 top-0 z-50 mt-[24px] flex-row items-center gap-[8px] px-[20px]">
<Block <Block className="relative flex-1" style={{ height: searchHeight }}>
className="flex-1 flex-row items-center border-[3px] border-black bg-white px-[12px] shadow-[4px_4px_0px_#000]" <ParallelogramShape
style={{ height: 48, transform: [{ skewX: '-6deg' }] }} width={searchWidth}
> height={searchHeight}
<Ionicons color="black" name="search" size={20} style={{ marginRight: 8 }} /> fillColor="#FFFFFF"
<TextInput padding={padding}
autoFocus skewOffset={skewOffset}
onChangeText={handleTextChange} >
placeholder="搜索作品 / 用户..." <Block className="absolute inset-0 flex-row items-center px-[18px]">
placeholderTextColor="#9CA3AF" <Ionicons color="black" name="search" size={20} style={{ marginRight: 8 }} />
style={{ <TextInput
flex: 1, autoFocus
fontSize: 14, onChangeText={handleTextChange}
fontWeight: 'bold', placeholder="搜索作品 / 用户..."
color: 'black', placeholderTextColor="#9CA3AF"
}} style={{
value={searchText} flex: 1,
/> fontSize: 14,
fontWeight: 'bold',
color: 'black',
}}
value={searchText}
/>
</Block>
</ParallelogramShape>
</Block> </Block>
<Block
className="items-center justify-center border-[3px] border-black bg-accent shadow-[4px_4px_0px_#000]" {/* 关闭按钮平行四边形 */}
onClick={handleClose} <Block className="relative" style={{ width: closeSize, height: closeSize }} onClick={handleClose}>
style={{ width: 48, height: 48, transform: [{ skewX: '-6deg' }] }} <ParallelogramShape
> width={closeSize}
<Ionicons color="black" name="close" size={24} style={{ transform: [{ skewX: '6deg' }] }} /> height={closeSize}
fillColor="#FFE500"
padding={padding}
skewOffset={skewOffset}
>
<Block className="absolute inset-0 items-center justify-center">
<Ionicons color="black" name="close" size={24} />
</Block>
</ParallelogramShape>
</Block> </Block>
</Block> </Block>
) )
@ -569,26 +589,63 @@ const GooActions = observer<GooActionsProps>(function GooActions({ gooPoints, on
const { isPolling } = userBalanceStore const { isPolling } = userBalanceStore
const isDev = __DEV__ const isDev = __DEV__
const isLogin = userStore.isLogin const isLogin = userStore.isLogin
const width = 100
const height = 32
const skewOffset = 8 // 统一所有平行四边形的倾斜角度
const padding = 2
const addWidth = 40
const addHeight = height
const addSkewOffset = 8 // 统一所有平行四边形的倾斜角度
return ( return (
<Block> <Block>
<Block className="mt-[12px] flex-row items-center gap-[8px]"> <Block className="mt-[12px] flex-row items-center gap-[8px]">
{!!isLogin && ( {!!isLogin && (
<Block <Block
className="flex-row items-center gap-[4px] rounded-full border-[3px] border-white bg-black px-[12px] py-[8px] shadow-[3px_3px_0px_rgba(0,0,0,0.5)]" className="relative"
onClick={onAddGoo} style={{ width, height }}
> onClick={onAddGoo}
<Text className="text-[12px] font-black text-accent">{gooPoints}</Text> >
<Ionicons color="#FFE500" name="add" size={12} style={{ fontWeight: 'bold' }} /> <ParallelogramShape
{isDev && isPolling && <Block className="ml-[4px] size-[6px] rounded-full bg-green-500" />} width={width}
</Block> height={height}
)} fillColor="#FFFFFF"
strokeWidth={2}
padding={padding}
skewOffset={skewOffset}
>
<Block className="absolute inset-0 flex-row items-center gap-[4px] pl-[12px]">
{isDev && isPolling && <Block className="ml-[4px] size-[6px] rounded-full bg-green-500" />}
<Text className="text-[12px] font-black text-accent">{gooPoints}</Text>
<Block className="ml-auto h-full relative" style={{ width: addWidth }}>
<ParallelogramShape
width={addWidth}
height={addHeight}
fillColor="#FAE307"
strokeWidth={1}
padding={padding}
skewOffset={addSkewOffset}
showShadow={false}
>
<Block className="absolute inset-0 items-center justify-center">
<Ionicons color="#323232" name="add" size={12} style={{ fontWeight: 'bold' }} />
</Block>
</ParallelogramShape>
</Block>
</Block>
</ParallelogramShape>
</Block>
)}
<Block <Block
className="size-[48px] items-center justify-center rounded-full border-[3px] border-black bg-white shadow-[4px_4px_0px_#000]" className="size-[40px] items-center justify-center rounded-full border-[2px] border-black bg-white shadow-[4px_4px_0px_#000]"
onClick={onOpenSearch} onClick={onOpenSearch}
> >
<Ionicons color="black" name="search" size={22} /> <Ionicons color="black" name="search" size={20} />
</Block> </Block>
</Block> </Block>
</Block> </Block>
) )
}) })
@ -656,29 +713,30 @@ type FilterSectionProps = {
const FilterSection = memo<FilterSectionProps>(function FilterSection({ activeTab, onChange }) { const FilterSection = memo<FilterSectionProps>(function FilterSection({ activeTab, onChange }) {
const tabs = useMemo( const tabs = useMemo(
() => [ () => [
{ label: '最热', state: '' as const }, { label: '最热', state: 'HOT' as const },
{ label: '最新', state: 'new' as const }, { label: '最新', state: 'NEW' as const },
{ label: '喜欢', state: 'like' as const }, { label: '喜欢', state: 'LIKE' as const },
], ],
[], [],
) )
return ( return (
<Block className="mt-[12px] flex-row items-end justify-between"> <Block className="mt-[12px] flex-row items-end justify-between">
<Block className="flex-row gap-[8px]"> <Block className="flex-row gap-[4px]">
{tabs.map(({ label, state }) => { {tabs.map(({ label, state }) => {
const isActive = activeTab === state const isActive = activeTab === state
const buttonWidth = Math.max(label.length * 13 + 12, 66) // 最小宽度 70适应13px字体
const buttonHeight = 30 // 稍微增加高度以适应13px字体
return ( return (
<Block <ParallelogramButton
className={`border-2 border-black px-[16px] py-[4px] ${isActive ? 'bg-accent' : 'bg-white'}`}
key={state} key={state}
onClick={() => onChange(state)} label={label}
style={{ state={state}
transform: [{ skewX: '-6deg' }], isActive={isActive}
}} onPress={() => onChange(state)}
> width={buttonWidth}
<Text className={`text-[10px] font-[900] ${isActive ? 'text-black' : 'text-gray-500'}`}>{label}</Text> height={buttonHeight}
</Block> />
) )
})} })}
</Block> </Block>