feat(listings): 新增我的足迹浏览记录与收藏账号页
This commit is contained in:
@@ -13,6 +13,11 @@ const ListingDetailPage = lazy(() =>
|
||||
default: module.ListingDetailPage,
|
||||
}))
|
||||
)
|
||||
const ListingCollectionsPage = lazy(() =>
|
||||
import('@/features/listings/ListingCollectionsPage').then(module => ({
|
||||
default: module.ListingCollectionsPage,
|
||||
}))
|
||||
)
|
||||
const SellerListingsPage = lazy(() =>
|
||||
import('@/features/seller/SellerListingsPage').then(module => ({
|
||||
default: module.SellerListingsPage,
|
||||
@@ -481,6 +486,7 @@ export function AppRouter() {
|
||||
<Routes>
|
||||
<Route element={<StorefrontLayout />}>
|
||||
<Route index element={<ListingListPage />} />
|
||||
<Route path="listings/collections" element={<ListingCollectionsPage />} />
|
||||
<Route path="listings/:id" element={<ListingDetailPage />} />
|
||||
<Route path="orders" element={<OrderListPage />} />
|
||||
<Route path="orders/:id" element={<OrderDetailPage />} />
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
import { useState } from 'react'
|
||||
import { App, Button, Card, Empty, Segmented, Space, Tag, Typography } from 'antd'
|
||||
import { DeleteOutlined, StarFilled, StarOutlined } from '@ant-design/icons'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
import {
|
||||
useListingCollections,
|
||||
type CollectionItem,
|
||||
} from '@/features/listings/collections'
|
||||
import { formatDateTime, formatMoney } from '@/shared/utils/format'
|
||||
|
||||
type TabKey = 'history' | 'favorites'
|
||||
|
||||
function timeText(item: CollectionItem, tab: TabKey) {
|
||||
return formatDateTime(tab === 'favorites' ? item.favorited_at : item.viewed_at)
|
||||
}
|
||||
|
||||
export function ListingCollectionsPage() {
|
||||
const navigate = useNavigate()
|
||||
const { message, modal } = App.useApp()
|
||||
const { history, favorites, isFavorite, toggleFavorite, removeHistory, removeFavorite, clearHistory } =
|
||||
useListingCollections()
|
||||
const [tab, setTab] = useState<TabKey>('history')
|
||||
|
||||
const items = tab === 'favorites' ? favorites : history
|
||||
|
||||
const onClear = () => {
|
||||
modal.confirm({
|
||||
title: '清空浏览记录',
|
||||
content: '确认清空全部浏览记录吗?收藏的账号不受影响。',
|
||||
okText: '清空',
|
||||
okButtonProps: { danger: true },
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
clearHistory()
|
||||
message.success('浏览记录已清空')
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const onToggle = (item: CollectionItem) => {
|
||||
const added = toggleFavorite(item.listing)
|
||||
message.success(added ? '已收藏' : '已取消收藏')
|
||||
}
|
||||
|
||||
const onRemove = (item: CollectionItem) => {
|
||||
if (tab === 'favorites') {
|
||||
removeFavorite(item.listing.id)
|
||||
message.success('已取消收藏')
|
||||
return
|
||||
}
|
||||
removeHistory(item.listing.id)
|
||||
message.success('已移除记录')
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="collections-page">
|
||||
<header className="collections-page__head">
|
||||
<div>
|
||||
<span className="collections-page__eyebrow">ACCOUNT MEMORY</span>
|
||||
<Typography.Title level={2} className="brand-title">
|
||||
我的足迹
|
||||
</Typography.Title>
|
||||
<Typography.Paragraph type="secondary">
|
||||
找回看过和收藏过的账号,数据保存在当前浏览器。
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
{tab === 'history' && history.length > 0 ? (
|
||||
<Button icon={<DeleteOutlined />} onClick={onClear}>
|
||||
清空记录
|
||||
</Button>
|
||||
) : null}
|
||||
</header>
|
||||
|
||||
<Segmented
|
||||
className="collections-page__tabs"
|
||||
value={tab}
|
||||
onChange={value => setTab(value as TabKey)}
|
||||
options={[
|
||||
{ label: `浏览记录 ${history.length}`, value: 'history' },
|
||||
{ label: `收藏账号 ${favorites.length}`, value: 'favorites' },
|
||||
]}
|
||||
/>
|
||||
|
||||
{items.length === 0 ? (
|
||||
<Card className="collections-page__empty">
|
||||
<Empty
|
||||
description={tab === 'favorites' ? '暂无收藏账号' : '暂无浏览记录'}
|
||||
>
|
||||
<Button type="primary" onClick={() => navigate('/')}>
|
||||
去逛柜选
|
||||
</Button>
|
||||
</Empty>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="collections-list">
|
||||
{items.map(item => (
|
||||
<Card key={item.listing.id} className="collections-item" hoverable={false}>
|
||||
<div className="collections-item__time">{timeText(item, tab)}</div>
|
||||
<div className="collections-item__body">
|
||||
<button
|
||||
type="button"
|
||||
className="collections-item__cover"
|
||||
onClick={() => navigate(`/listings/${item.listing.id}`)}
|
||||
>
|
||||
{item.listing.cover_url ? (
|
||||
<img src={item.listing.cover_url} alt={item.listing.title} loading="lazy" />
|
||||
) : (
|
||||
<span>JIEYOU</span>
|
||||
)}
|
||||
</button>
|
||||
|
||||
<div className="collections-item__main">
|
||||
<Typography.Text className="collections-item__no">
|
||||
{item.listing.listing_no}
|
||||
</Typography.Text>
|
||||
<Typography.Title
|
||||
level={4}
|
||||
className="collections-item__title"
|
||||
ellipsis={{ rows: 2 }}
|
||||
onClick={() => navigate(`/listings/${item.listing.id}`)}
|
||||
>
|
||||
{item.listing.title}
|
||||
</Typography.Title>
|
||||
<Space size={6} wrap>
|
||||
<Tag bordered={false}>{item.listing.server_region || '区服待定'}</Tag>
|
||||
<Tag bordered={false}>{item.listing.login_platform || '登录方式待定'}</Tag>
|
||||
{item.listing.rank_level ? (
|
||||
<Tag bordered={false}>{item.listing.rank_level}</Tag>
|
||||
) : null}
|
||||
<Tag color={item.listing.in_transaction ? 'default' : 'green'} bordered={false}>
|
||||
{item.listing.in_transaction ? '租赁中' : '可租'}
|
||||
</Tag>
|
||||
</Space>
|
||||
<div className="collections-item__meta">
|
||||
<span>哈夫币 {item.listing.haf_coin_amount?.toLocaleString() ?? '—'}</span>
|
||||
<span>押金 {formatMoney(item.listing.deposit_amount_cent)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="collections-item__side">
|
||||
<strong className="collections-item__price">
|
||||
{formatMoney(item.listing.price_cent)}
|
||||
</strong>
|
||||
<Space size={8} wrap>
|
||||
<Button
|
||||
size="small"
|
||||
icon={isFavorite(item.listing.id) ? <StarFilled /> : <StarOutlined />}
|
||||
onClick={() => onToggle(item)}
|
||||
>
|
||||
{isFavorite(item.listing.id) ? '已收藏' : '收藏'}
|
||||
</Button>
|
||||
<Button size="small" type="text" onClick={() => onRemove(item)}>
|
||||
移除
|
||||
</Button>
|
||||
</Space>
|
||||
<Button type="primary" onClick={() => navigate(`/listings/${item.listing.id}`)}>
|
||||
立即租用
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import {
|
||||
Alert,
|
||||
App,
|
||||
@@ -20,12 +20,15 @@ import {
|
||||
ArrowLeftOutlined,
|
||||
SafetyCertificateOutlined,
|
||||
ShoppingOutlined,
|
||||
StarFilled,
|
||||
StarOutlined,
|
||||
WalletOutlined,
|
||||
} from '@ant-design/icons'
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom'
|
||||
|
||||
import { BrandLogo } from '@/components/BrandLogo'
|
||||
import { useListingDetail } from '@/features/listings/api'
|
||||
import { recordListingView, useListingCollections } from '@/features/listings/collections'
|
||||
import {
|
||||
createOrder,
|
||||
useOrderAgreements,
|
||||
@@ -60,8 +63,10 @@ function galleryImages(item: Listing) {
|
||||
export function ListingDetailPage() {
|
||||
const { id } = useParams()
|
||||
const navigate = useNavigate()
|
||||
const { message } = App.useApp()
|
||||
const { modal } = App.useApp()
|
||||
const { data, isPending, isError, refetch } = useListingDetail(id)
|
||||
const { isFavorite, toggleFavorite } = useListingCollections()
|
||||
const user = useSessionStore(state => state.user)
|
||||
const token = useSessionStore(state => state.token)
|
||||
const agreements = useOrderAgreements()
|
||||
@@ -73,6 +78,10 @@ export function ListingDetailPage() {
|
||||
const [agreementTitle, setAgreementTitle] = useState('')
|
||||
const [agreementContent, setAgreementContent] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
if (data) recordListingView(data)
|
||||
}, [data])
|
||||
|
||||
const showAgreement = (title: string, content?: string) => {
|
||||
setAgreementTitle(title)
|
||||
setAgreementContent(content || '暂无内容')
|
||||
@@ -206,9 +215,21 @@ export function ListingDetailPage() {
|
||||
<Card className="listing-buy-card">
|
||||
<div className="listing-buy-card__top">
|
||||
<Typography.Text className="listing-card__no">{data.listing_no}</Typography.Text>
|
||||
<Tag color={data.in_transaction ? 'default' : 'green'} bordered={false}>
|
||||
{data.in_transaction ? '租赁中' : '可租'}
|
||||
</Tag>
|
||||
<Space size={8}>
|
||||
<Tag color={data.in_transaction ? 'default' : 'green'} bordered={false}>
|
||||
{data.in_transaction ? '租赁中' : '可租'}
|
||||
</Tag>
|
||||
<Button
|
||||
size="small"
|
||||
icon={isFavorite(data.id) ? <StarFilled /> : <StarOutlined />}
|
||||
onClick={() => {
|
||||
const added = toggleFavorite(data)
|
||||
message.success(added ? '已收藏账号' : '已取消收藏')
|
||||
}}
|
||||
>
|
||||
{isFavorite(data.id) ? '已收藏' : '收藏'}
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
<Typography.Title level={2} className="brand-title listing-buy-card__title">
|
||||
{data.title}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import type { Listing } from '@/shared/api/types'
|
||||
|
||||
const HISTORY_KEY = 'jieyou.listing.view.history'
|
||||
const FAVORITE_KEY = 'jieyou.listing.favorites'
|
||||
const MAX_HISTORY = 80
|
||||
const SYNC_EVENT = 'jieyou:listing-collections'
|
||||
|
||||
/** 足迹只保存展示所需的字段快照,避免商品下线后列表整块空白。 */
|
||||
export interface ListingSnapshot {
|
||||
id: number
|
||||
listing_no: string
|
||||
title: string
|
||||
cover_url: string
|
||||
price_cent: number
|
||||
deposit_amount_cent: number
|
||||
haf_coin_amount: number
|
||||
server_region: string
|
||||
login_platform: string
|
||||
rank_level: string
|
||||
in_transaction: boolean
|
||||
status: string
|
||||
}
|
||||
|
||||
export interface CollectionItem {
|
||||
listing: ListingSnapshot
|
||||
viewed_at?: string
|
||||
favorited_at?: string
|
||||
}
|
||||
|
||||
function toSnapshot(listing: Listing): ListingSnapshot {
|
||||
return {
|
||||
id: listing.id,
|
||||
listing_no: listing.listing_no,
|
||||
title: listing.title,
|
||||
cover_url: listing.cover_url,
|
||||
price_cent: listing.price_cent,
|
||||
deposit_amount_cent: listing.deposit_amount_cent,
|
||||
haf_coin_amount: listing.haf_coin_amount,
|
||||
server_region: listing.server_region,
|
||||
login_platform: listing.login_platform,
|
||||
rank_level: listing.rank_level,
|
||||
in_transaction: listing.in_transaction,
|
||||
status: listing.status,
|
||||
}
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null
|
||||
}
|
||||
|
||||
function normalizeItem(value: unknown): CollectionItem | null {
|
||||
if (!isRecord(value) || !isRecord(value.listing)) return null
|
||||
const listing = value.listing as unknown as ListingSnapshot
|
||||
const id = Number(listing.id)
|
||||
if (!Number.isFinite(id) || id <= 0) return null
|
||||
return {
|
||||
listing: {
|
||||
...listing,
|
||||
id,
|
||||
title: typeof listing.title === 'string' ? listing.title : '',
|
||||
listing_no: typeof listing.listing_no === 'string' ? listing.listing_no : '',
|
||||
cover_url: typeof listing.cover_url === 'string' ? listing.cover_url : '',
|
||||
},
|
||||
viewed_at: typeof value.viewed_at === 'string' ? value.viewed_at : undefined,
|
||||
favorited_at: typeof value.favorited_at === 'string' ? value.favorited_at : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
function readItems(key: string): CollectionItem[] {
|
||||
if (typeof localStorage === 'undefined') return []
|
||||
try {
|
||||
const raw = localStorage.getItem(key)
|
||||
if (!raw) return []
|
||||
const parsed = JSON.parse(raw) as unknown
|
||||
if (!Array.isArray(parsed)) return []
|
||||
return parsed
|
||||
.map(normalizeItem)
|
||||
.filter((item): item is CollectionItem => Boolean(item))
|
||||
} catch {
|
||||
localStorage.removeItem(key)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
function writeItems(key: string, items: CollectionItem[]) {
|
||||
if (typeof localStorage === 'undefined') return
|
||||
localStorage.setItem(key, JSON.stringify(items))
|
||||
window.dispatchEvent(new Event(SYNC_EVENT))
|
||||
}
|
||||
|
||||
export function recordListingView(listing: Listing) {
|
||||
const items = readItems(HISTORY_KEY).filter(item => item.listing.id !== listing.id)
|
||||
writeItems(
|
||||
HISTORY_KEY,
|
||||
[{ listing: toSnapshot(listing), viewed_at: new Date().toISOString() }, ...items].slice(
|
||||
0,
|
||||
MAX_HISTORY
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export function toggleListingFavorite(listing: Listing | ListingSnapshot) {
|
||||
const favorites = readItems(FAVORITE_KEY)
|
||||
const exists = favorites.some(item => item.listing.id === listing.id)
|
||||
if (exists) {
|
||||
writeItems(
|
||||
FAVORITE_KEY,
|
||||
favorites.filter(item => item.listing.id !== listing.id)
|
||||
)
|
||||
return false
|
||||
}
|
||||
const snapshot = 'owner_id' in listing ? toSnapshot(listing) : listing
|
||||
writeItems(
|
||||
FAVORITE_KEY,
|
||||
[
|
||||
{ listing: snapshot, favorited_at: new Date().toISOString() },
|
||||
...favorites.filter(item => item.listing.id !== listing.id),
|
||||
].slice(0, MAX_HISTORY)
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
export function removeHistoryItem(listingID: number) {
|
||||
writeItems(
|
||||
HISTORY_KEY,
|
||||
readItems(HISTORY_KEY).filter(item => item.listing.id !== listingID)
|
||||
)
|
||||
}
|
||||
|
||||
export function removeFavoriteItem(listingID: number) {
|
||||
writeItems(
|
||||
FAVORITE_KEY,
|
||||
readItems(FAVORITE_KEY).filter(item => item.listing.id !== listingID)
|
||||
)
|
||||
}
|
||||
|
||||
export function clearListingHistory() {
|
||||
writeItems(HISTORY_KEY, [])
|
||||
}
|
||||
|
||||
export function useListingCollections() {
|
||||
const [history, setHistory] = useState<CollectionItem[]>([])
|
||||
const [favorites, setFavorites] = useState<CollectionItem[]>([])
|
||||
|
||||
const sync = useCallback(() => {
|
||||
setHistory(readItems(HISTORY_KEY))
|
||||
setFavorites(readItems(FAVORITE_KEY))
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
sync()
|
||||
window.addEventListener(SYNC_EVENT, sync)
|
||||
window.addEventListener('storage', sync)
|
||||
return () => {
|
||||
window.removeEventListener(SYNC_EVENT, sync)
|
||||
window.removeEventListener('storage', sync)
|
||||
}
|
||||
}, [sync])
|
||||
|
||||
const favoriteIDs = new Set(favorites.map(item => item.listing.id))
|
||||
|
||||
return {
|
||||
history,
|
||||
favorites,
|
||||
isFavorite: (id: number) => favoriteIDs.has(id),
|
||||
recordView: recordListingView,
|
||||
toggleFavorite: toggleListingFavorite,
|
||||
removeHistory: removeHistoryItem,
|
||||
removeFavorite: removeFavoriteItem,
|
||||
clearHistory: clearListingHistory,
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { App, Avatar, Button, Card, Col, Descriptions, Row, Space, Tag, Typograp
|
||||
import {
|
||||
ArrowRightOutlined,
|
||||
BellOutlined,
|
||||
HistoryOutlined,
|
||||
IdcardOutlined,
|
||||
MessageOutlined,
|
||||
ProfileOutlined,
|
||||
@@ -25,6 +26,7 @@ const realnameMeta: Record<string, { label: string; color: string }> = {
|
||||
}
|
||||
|
||||
const quickEntries = [
|
||||
{ key: 'collections', label: '我的足迹', hint: '浏览记录与收藏账号', icon: <HistoryOutlined />, to: '/listings/collections' },
|
||||
{ key: 'orders', label: '我的订单', hint: '查看租号进度与交接记录', icon: <ProfileOutlined />, to: '/orders' },
|
||||
{ key: 'messages', label: '消息中心', hint: '账号群聊与客服会话', icon: <MessageOutlined />, to: '/messages' },
|
||||
{ key: 'wallet', label: '我的钱包', hint: '余额、流水与提现', icon: <WalletOutlined />, to: '/wallet' },
|
||||
|
||||
@@ -54,6 +54,11 @@ export function StorefrontLayout() {
|
||||
label: '实名认证',
|
||||
onClick: () => navigate('/realname'),
|
||||
},
|
||||
{
|
||||
key: 'collections',
|
||||
label: '我的足迹',
|
||||
onClick: () => navigate('/listings/collections'),
|
||||
},
|
||||
{
|
||||
key: 'orders',
|
||||
label: '我的订单',
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
@import './mobile-chat.css';
|
||||
@import './pc-messages.css';
|
||||
@import './pc-account.css';
|
||||
@import './pc-collections.css';
|
||||
@import './seller.css';
|
||||
@import './mobile-seller.css';
|
||||
@import './components.css';
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/* PC 我的足迹(浏览记录 / 收藏账号) */
|
||||
.collections-page {
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
padding: 32px 24px 56px;
|
||||
}
|
||||
|
||||
.collections-page__head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
padding: 28px 32px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 18px;
|
||||
background: linear-gradient(135deg, rgba(166, 67, 50, 0.05), rgba(30, 77, 66, 0.06));
|
||||
}
|
||||
|
||||
.collections-page__eyebrow {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.24em;
|
||||
color: var(--ink-muted);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.collections-page__head h2 {
|
||||
margin: 6px 0 4px;
|
||||
}
|
||||
|
||||
.collections-page__tabs {
|
||||
margin: 20px 0 16px;
|
||||
padding: 4px;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
border: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.collections-page__empty {
|
||||
border-radius: 16px;
|
||||
border-color: var(--line);
|
||||
background: var(--paper-warm);
|
||||
padding: 32px 0;
|
||||
}
|
||||
|
||||
.collections-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.collections-item {
|
||||
border-radius: 16px;
|
||||
border-color: var(--line);
|
||||
background: var(--paper-warm);
|
||||
}
|
||||
|
||||
.collections-item .ant-card-body {
|
||||
padding: 16px 20px 18px;
|
||||
}
|
||||
|
||||
.collections-item__time {
|
||||
font-size: 12px;
|
||||
color: var(--ink-muted);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.collections-item__body {
|
||||
display: grid;
|
||||
grid-template-columns: 132px minmax(0, 1fr) 168px;
|
||||
gap: 18px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.collections-item__cover {
|
||||
width: 132px;
|
||||
height: 92px;
|
||||
padding: 0;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background: rgba(30, 77, 66, 0.06);
|
||||
color: var(--ink-muted);
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.16em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collections-item__cover img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.collections-item__no {
|
||||
font-size: 12px;
|
||||
color: var(--ink-muted);
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.collections-item__title {
|
||||
margin: 2px 0 8px !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collections-item__title:hover {
|
||||
color: var(--brand-seal);
|
||||
}
|
||||
|
||||
.collections-item__meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
margin-top: 10px;
|
||||
font-size: 12px;
|
||||
color: var(--ink-secondary);
|
||||
}
|
||||
|
||||
.collections-item__side {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.collections-item__price {
|
||||
font-size: 22px;
|
||||
color: var(--brand-seal);
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.collections-item__body {
|
||||
grid-template-columns: 96px minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.collections-item__cover {
|
||||
width: 96px;
|
||||
height: 72px;
|
||||
}
|
||||
|
||||
.collections-item__side {
|
||||
grid-column: 1 / -1;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.collections-page {
|
||||
padding: 20px 16px 40px;
|
||||
}
|
||||
|
||||
.collections-page__head {
|
||||
flex-direction: column;
|
||||
padding: 22px;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user