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