tabcss
This commit is contained in:
parent
32ff57f523
commit
f5c3639a0b
|
|
@ -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,14 +527,23 @@ 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}
|
||||||
|
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 }} />
|
<Ionicons color="black" name="search" size={20} style={{ marginRight: 8 }} />
|
||||||
<TextInput
|
<TextInput
|
||||||
autoFocus
|
autoFocus
|
||||||
|
|
@ -549,12 +559,22 @@ const SearchOverlay = memo<SearchOverlayProps>(function SearchOverlay({ isOpen,
|
||||||
value={searchText}
|
value={searchText}
|
||||||
/>
|
/>
|
||||||
</Block>
|
</Block>
|
||||||
<Block
|
</ParallelogramShape>
|
||||||
className="items-center justify-center border-[3px] border-black bg-accent shadow-[4px_4px_0px_#000]"
|
</Block>
|
||||||
onClick={handleClose}
|
|
||||||
style={{ width: 48, height: 48, transform: [{ skewX: '-6deg' }] }}
|
{/* 关闭按钮平行四边形 */}
|
||||||
|
<Block className="relative" style={{ width: closeSize, height: closeSize }} onClick={handleClose}>
|
||||||
|
<ParallelogramShape
|
||||||
|
width={closeSize}
|
||||||
|
height={closeSize}
|
||||||
|
fillColor="#FFE500"
|
||||||
|
padding={padding}
|
||||||
|
skewOffset={skewOffset}
|
||||||
>
|
>
|
||||||
<Ionicons color="black" name="close" size={24} style={{ transform: [{ skewX: '6deg' }] }} />
|
<Block className="absolute inset-0 items-center justify-center">
|
||||||
|
<Ionicons color="black" name="close" size={24} />
|
||||||
|
</Block>
|
||||||
|
</ParallelogramShape>
|
||||||
</Block>
|
</Block>
|
||||||
</Block>
|
</Block>
|
||||||
)
|
)
|
||||||
|
|
@ -569,24 +589,61 @@ 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"
|
||||||
|
style={{ width, height }}
|
||||||
onClick={onAddGoo}
|
onClick={onAddGoo}
|
||||||
>
|
>
|
||||||
<Text className="text-[12px] font-black text-accent">{gooPoints}</Text>
|
<ParallelogramShape
|
||||||
<Ionicons color="#FFE500" name="add" size={12} style={{ fontWeight: 'bold' }} />
|
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" />}
|
{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
|
<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>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue