Skip to content

Commit d47a02a

Browse files
committed
feat: add a timer on cards
1 parent 7c42cfe commit d47a02a

File tree

4 files changed

+168
-157
lines changed

4 files changed

+168
-157
lines changed

components/galgame/Card.tsx

Lines changed: 87 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,87 @@
1-
'use client'
2-
3-
import { useState } from 'react'
4-
import { Card, CardBody, CardFooter, CardHeader } from '@heroui/card'
5-
import { Chip } from '@heroui/chip'
6-
import { Image } from '@heroui/image'
7-
import { KunCardStats } from '~/components/kun/CardStats'
8-
import Link from 'next/link'
9-
import { KunPatchAttribute } from '~/components/kun/PatchAttribute'
10-
import { cn } from '~/utils/cn'
11-
import { GALGAME_AGE_LIMIT_MAP } from '~/constants/galgame'
12-
13-
interface Props {
14-
patch: GalgameCard
15-
}
16-
17-
export const GalgameCard = ({ patch }: Props) => {
18-
const [imageLoaded, setImageLoaded] = useState(false)
19-
20-
return (
21-
<Card
22-
isPressable
23-
as={Link}
24-
href={`/patch/${patch.id}/introduction`}
25-
className="w-full border border-default-100 dark:border-default-200"
26-
>
27-
<CardHeader className="p-0">
28-
<div className="relative w-full mx-auto overflow-hidden text-center rounded-t-lg opacity-90">
29-
<div
30-
className={cn(
31-
'absolute inset-0 animate-pulse bg-default-100',
32-
imageLoaded ? 'opacity-0' : 'opacity-90',
33-
'transition-opacity duration-300'
34-
)}
35-
style={{ aspectRatio: '16/9' }}
36-
/>
37-
<Image
38-
radius="none"
39-
alt={patch.name}
40-
className={cn(
41-
'size-full object-cover transition-all duration-300',
42-
imageLoaded ? 'scale-100 opacity-90' : 'scale-105 opacity-0'
43-
)}
44-
removeWrapper={true}
45-
src={
46-
patch.banner
47-
? patch.banner.replace(/\.avif$/, '-mini.avif')
48-
: '/kungalgame.avif'
49-
}
50-
style={{ aspectRatio: '16/9' }}
51-
onLoad={() => setImageLoaded(true)}
52-
/>
53-
54-
<div className="absolute z-10 rounded-full bg-background left-2 top-2">
55-
<Chip
56-
color={patch.content_limit === 'sfw' ? 'success' : 'danger'}
57-
variant="flat"
58-
>
59-
{GALGAME_AGE_LIMIT_MAP[patch.content_limit]}
60-
</Chip>
61-
</div>
62-
</div>
63-
</CardHeader>
64-
<CardBody className="justify-between space-y-2">
65-
<h2 className="font-semibold transition-colors text-medium sm:text-lg line-clamp-2 hover:text-primary-500">
66-
{patch.name}
67-
</h2>
68-
<KunCardStats patch={patch} />
69-
</CardBody>
70-
<CardFooter className="pt-0">
71-
<KunPatchAttribute
72-
types={patch.type}
73-
languages={patch.language}
74-
platforms={patch.platform}
75-
size="sm"
76-
/>
77-
</CardFooter>
78-
</Card>
79-
)
80-
}
1+
'use client'
2+
3+
import { useState } from 'react'
4+
import { Card, CardBody, CardFooter, CardHeader } from '@heroui/card'
5+
import { Chip } from '@heroui/chip'
6+
import { Image } from '@heroui/image'
7+
import { KunCardStats } from '~/components/kun/CardStats'
8+
import Link from 'next/link'
9+
import { KunPatchAttribute } from '~/components/kun/PatchAttribute'
10+
import { cn } from '~/utils/cn'
11+
import { GALGAME_AGE_LIMIT_MAP } from '~/constants/galgame'
12+
import { formatDistanceToNow } from '~/utils/formatDistanceToNow'
13+
14+
interface Props {
15+
patch: GalgameCard
16+
}
17+
18+
export const GalgameCard = ({ patch }: Props) => {
19+
const [imageLoaded, setImageLoaded] = useState(false)
20+
21+
return (
22+
<Card
23+
isPressable
24+
as={Link}
25+
href={`/patch/${patch.id}/introduction`}
26+
className="w-full border border-default-100 dark:border-default-200"
27+
>
28+
<CardHeader className="p-0">
29+
<div className="relative w-full mx-auto overflow-hidden text-center rounded-t-lg opacity-90">
30+
<div
31+
className={cn(
32+
'absolute inset-0 animate-pulse bg-default-100',
33+
imageLoaded ? 'opacity-0' : 'opacity-90',
34+
'transition-opacity duration-300'
35+
)}
36+
style={{ aspectRatio: '16/9' }}
37+
/>
38+
<Image
39+
radius="none"
40+
alt={patch.name}
41+
className={cn(
42+
'size-full object-cover transition-all duration-300',
43+
imageLoaded ? 'scale-100 opacity-90' : 'scale-105 opacity-0'
44+
)}
45+
removeWrapper={true}
46+
src={
47+
patch.banner
48+
? patch.banner.replace(/\.avif$/, '-mini.avif')
49+
: '/kungalgame.avif'
50+
}
51+
style={{ aspectRatio: '16/9' }}
52+
onLoad={() => setImageLoaded(true)}
53+
/>
54+
55+
<div className="absolute z-10 rounded-full bg-background left-2 top-2">
56+
<Chip
57+
color={patch.content_limit === 'sfw' ? 'success' : 'danger'}
58+
variant="flat"
59+
>
60+
{GALGAME_AGE_LIMIT_MAP[patch.content_limit]}
61+
</Chip>
62+
</div>
63+
64+
<div className="absolute z-10 rounded-full bg-background right-2 bottom-2">
65+
<Chip size="sm" variant="flat">
66+
{formatDistanceToNow(patch.created)}
67+
</Chip>
68+
</div>
69+
</div>
70+
</CardHeader>
71+
<CardBody className="justify-between space-y-2">
72+
<h2 className="font-semibold transition-colors text-medium sm:text-lg line-clamp-2 hover:text-primary-500">
73+
{patch.name}
74+
</h2>
75+
<KunCardStats patch={patch} />
76+
</CardBody>
77+
<CardFooter className="pt-0">
78+
<KunPatchAttribute
79+
types={patch.type}
80+
languages={patch.language}
81+
platforms={patch.platform}
82+
size="sm"
83+
/>
84+
</CardFooter>
85+
</Card>
86+
)
87+
}

components/kun/top-bar/UserDropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
} from 'lucide-react'
2828
import { useUserStore } from '~/store/userStore'
2929
import { useState } from 'react'
30-
import { useRouter } from 'next/navigation'
30+
import { useRouter } from '@bprogress/next'
3131
import { kunFetchPost } from '~/utils/kunFetch'
3232
import toast from 'react-hot-toast'
3333
import { showKunSooner } from '~/components/kun/Sooner'
Lines changed: 74 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,74 @@
1-
import Link from 'next/link'
2-
import { Card, CardBody } from '@heroui/card'
3-
import { Chip } from '@heroui/chip'
4-
import { Download, Heart } from 'lucide-react'
5-
import { formatDistanceToNow } from '~/utils/formatDistanceToNow'
6-
import { KunPatchAttribute } from '~/components/kun/PatchAttribute'
7-
import { KunUser } from '../kun/floating-card/KunUser'
8-
import type { PatchResource } from '~/types/api/resource'
9-
10-
interface Props {
11-
resource: PatchResource
12-
}
13-
14-
export const ResourceCard = ({ resource }: Props) => {
15-
return (
16-
<Card
17-
isPressable
18-
as={Link}
19-
href={`/patch/${resource.patchId}/resource`}
20-
className="w-full"
21-
>
22-
<CardBody className="flex flex-col justify-between space-y-2">
23-
<div className="flex">
24-
<KunUser
25-
user={resource.user}
26-
userProps={{
27-
name: resource.user.name,
28-
description: `${formatDistanceToNow(resource.created)} • 已发布补丁 ${resource.user.patchCount} 个`,
29-
avatarProps: {
30-
showFallback: true,
31-
src: resource.user.avatar,
32-
name: resource.user.name.charAt(0).toUpperCase()
33-
}
34-
}}
35-
/>
36-
</div>
37-
38-
<h2 className="text-lg font-semibold transition-colors line-clamp-2 hover:text-primary-500">
39-
{resource.patchName}
40-
</h2>
41-
42-
{(resource.name || resource.note) && (
43-
<p className="break-all truncate whitespace-pre-wrap text-small text-default-500 line-clamp-2">
44-
{resource.name ? resource.name : resource.note}
45-
</p>
46-
)}
47-
48-
<KunPatchAttribute
49-
types={resource.type}
50-
languages={resource.language}
51-
platforms={resource.platform}
52-
modelName={resource.modelName}
53-
size="sm"
54-
/>
55-
56-
<div className="flex items-center justify-between text-small text-default-500">
57-
<div className="flex gap-4">
58-
<div className="flex items-center gap-1">
59-
<Heart size={16} />
60-
{resource.likeCount}
61-
</div>
62-
<div className="flex items-center gap-1">
63-
<Download size={16} />
64-
{resource.download}
65-
</div>
66-
</div>
67-
<Chip size="sm" variant="flat">
68-
{resource.size}
69-
</Chip>
70-
</div>
71-
</CardBody>
72-
</Card>
73-
)
74-
}
1+
import Link from 'next/link'
2+
import { Card, CardBody } from '@heroui/card'
3+
import { Chip } from '@heroui/chip'
4+
import { Download, Heart } from 'lucide-react'
5+
import { KunPatchAttribute } from '~/components/kun/PatchAttribute'
6+
import { KunUser } from '../kun/floating-card/KunUser'
7+
import { formatDate } from '~/utils/time'
8+
import type { PatchResource } from '~/types/api/resource'
9+
10+
interface Props {
11+
resource: PatchResource
12+
}
13+
14+
export const ResourceCard = ({ resource }: Props) => {
15+
return (
16+
<Card
17+
isPressable
18+
as={Link}
19+
href={`/patch/${resource.patchId}/resource`}
20+
className="w-full"
21+
>
22+
<CardBody className="flex flex-col justify-between space-y-2">
23+
<div className="flex">
24+
<KunUser
25+
user={resource.user}
26+
userProps={{
27+
name: resource.user.name,
28+
description: `发布于 ${formatDate(resource.created, { isShowYear: true, isPrecise: true })} • 已发布补丁 ${resource.user.patchCount} 个`,
29+
avatarProps: {
30+
showFallback: true,
31+
src: resource.user.avatar,
32+
name: resource.user.name.charAt(0).toUpperCase()
33+
}
34+
}}
35+
/>
36+
</div>
37+
38+
<h2 className="text-lg font-semibold transition-colors line-clamp-2 hover:text-primary-500">
39+
{resource.patchName}
40+
</h2>
41+
42+
{(resource.name || resource.note) && (
43+
<p className="break-all truncate whitespace-pre-wrap text-small text-default-500 line-clamp-2">
44+
{resource.name ? resource.name : resource.note}
45+
</p>
46+
)}
47+
48+
<KunPatchAttribute
49+
types={resource.type}
50+
languages={resource.language}
51+
platforms={resource.platform}
52+
modelName={resource.modelName}
53+
size="sm"
54+
/>
55+
56+
<div className="flex items-center justify-between text-small text-default-500">
57+
<div className="flex gap-4">
58+
<div className="flex items-center gap-1">
59+
<Heart size={16} />
60+
{resource.likeCount}
61+
</div>
62+
<div className="flex items-center gap-1">
63+
<Download size={16} />
64+
{resource.download}
65+
</div>
66+
</div>
67+
<Chip size="sm" variant="flat">
68+
{resource.size}
69+
</Chip>
70+
</div>
71+
</CardBody>
72+
</Card>
73+
)
74+
}

components/user/Profile.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import { Button } from '@heroui/button'
66
import { Chip } from '@heroui/chip'
77
import { Divider } from '@heroui/divider'
88
import { Progress } from '@heroui/progress'
9-
import { formatDistanceToNow } from '~/utils/formatDistanceToNow'
109
import { Calendar, Link as LinkIcon, MessageCircle } from 'lucide-react'
1110
import { UserFollow } from './follow/Follow'
1211
import { Stats } from './follow/Stats'
1312
import { SelfButton } from './SelfButton'
1413
import { USER_ROLE_MAP } from '~/constants/user'
1514
import { useRouter } from 'next/navigation'
1615
import { generatePrivateRoomLink } from '~/utils/generatePrivateRoomLink'
16+
import { formatDate } from '~/utils/time'
1717
import type { UserInfo } from '~/types/api/user'
1818

1919
export const UserProfile = ({ user }: { user: UserInfo }) => {
@@ -68,7 +68,11 @@ export const UserProfile = ({ user }: { user: UserInfo }) => {
6868
<div className="flex items-center gap-2">
6969
<Calendar className="size-4 text-default-400" />
7070
<span className="text-small text-default-500">
71-
加入于 {formatDistanceToNow(user.registerTime)}
71+
加入于{' '}
72+
{formatDate(user.registerTime, {
73+
isShowYear: true,
74+
isPrecise: true
75+
})}
7276
</span>
7377
</div>
7478
</div>

0 commit comments

Comments
 (0)