Skip to content

Commit

Permalink
feat: New UI for game details page
Browse files Browse the repository at this point in the history
  • Loading branch information
ximu3 committed Jan 10, 2025
1 parent c77d866 commit 99dfc96
Show file tree
Hide file tree
Showing 15 changed files with 247 additions and 290 deletions.
21 changes: 13 additions & 8 deletions src/renderer/src/components/Game/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { cn } from '~/utils'
import { useDBSyncedState } from '~/hooks'
import { Button } from '@ui/button'
import { GameImage } from '@ui/game-image'
// import { Badge } from '@ui/badge'
import {
Select,
Expand All @@ -15,6 +16,7 @@ import { Input } from '@ui/input'
import { Config } from './Config'
import { StartGame } from './StartGame'
import { StopGame } from './StopGame'
import { Record } from './Overview/Record'
import { toast } from 'sonner'
import { useState } from 'react'
import { useRunningGames } from '~/pages/Library/store'
Expand Down Expand Up @@ -71,21 +73,24 @@ export function Header({ gameId, className }: { gameId: string; className?: stri
toast.success('评分已保存')
}
return (
<div
className={cn(
'h-16 bg-gradient-to-b bg-background/80 absolute flex-row flex justify-between items-center pl-7 pr-7',
className
)}
>
<div className={cn('flex flex-row gap-3 grow overflow-hidden')}>
<div className={cn('bg-gradient-to-b bg-background/70 flex-col flex gap-5', className)}>
<GameImage
gameId={gameId}
type="cover"
shadow
className={cn('object-cover w-auto h-[200px] rounded-[0.3rem]', '3xl:h-[250px]')}
fallback={<div className={cn('w-full h-full', 'bg-background/15')} />}
/>
<div className={cn('flex flex-row gap-3 grow overflow-hidden items-end justify-between')}>
<div className={cn('truncate')}>
<span className={cn('font-bold text-2xl text-accent-foreground')}>{name}</span>
{showOriginalNameInGameHeader && originalName && originalName !== name && (
<span className={cn('font-bold text-accent-foreground ml-3')}>{originalName}</span>
)}
</div>
</div>
<div className={cn('flex flex-row gap-3 justify-center items-center', '3xl:gap-5')}>
<Record gameId={gameId} />
<div className={cn('flex flex-row gap-3', '3xl:gap-5')}>
{runningGames.includes(gameId) ? (
<StopGame gameId={gameId} className={cn('')} />
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Card, CardContent, CardHeader, CardTitle } from '@ui/card'
import { Separator } from '@ui/separator'
import { cn } from '~/utils'
import { useDBSyncedState } from '~/hooks'
import { InformationDialog } from './InformationDialog'
Expand All @@ -18,82 +18,71 @@ export function InformationCard({
const [releaseDate] = useDBSyncedState('', `games/${gameId}/metadata.json`, ['releaseDate'])
const [genres] = useDBSyncedState([''], `games/${gameId}/metadata.json`, ['genres'])
return (
<Card className={cn(className, 'group')}>
<CardHeader>
<CardTitle>
<div className={cn('flex flex-row justify-between items-center')}>
<div className={cn('')}>基本信息</div>
<InformationDialog gameId={gameId} />
</div>
</CardTitle>
</CardHeader>
<CardContent>
<div className={cn('flex flex-col gap-2 text-sm')}>
<div className={cn('flex flex-row gap-3 items-center justify-start')}>
<div className={cn('whitespace-nowrap')}>原名</div>
<div className={cn('max-w-[160px] truncate', '3xl:max-w-[250px]')}>
{originalName === '' ? '暂无' : originalName}
</div>
</div>
<div className={cn('flex flex-row gap-3 items-center justify-start')}>
<div className={cn('whitespace-nowrap')}>开发商</div>
<div className={cn('max-w-[160px] truncate', '3xl:max-w-[250px]')}>
{developers.join(',') === ''
? '暂无'
: developers.map((developer, index) => (
<React.Fragment key={developer}>
<FilterAdder filed="developers" value={developer} className={cn('')} />
{index < developers.length - 1 && (
<span className="text-primary">{', '}</span>
)}
</React.Fragment>
))}
</div>
<div className={cn(className, 'group')}>
<div className={cn('flex flex-row justify-between items-center')}>
<div className={cn('font-bold')}>基本信息</div>
<InformationDialog gameId={gameId} />
</div>
<Separator className={cn('my-3 bg-primary')} />
<div className={cn('flex flex-col gap-2 text-sm')}>
<div className={cn('flex flex-row gap-3 items-center justify-start')}>
<div className={cn('whitespace-nowrap')}>原名</div>
<div className={cn('truncate')}>{originalName === '' ? '暂无' : originalName}</div>
</div>
<div className={cn('flex flex-row gap-3 items-center justify-start')}>
<div className={cn('whitespace-nowrap')}>开发商</div>
<div className={cn('truncate')}>
{developers.join(',') === ''
? '暂无'
: developers.map((developer, index) => (
<React.Fragment key={developer}>
<FilterAdder filed="developers" value={developer} className={cn('')} />
{index < developers.length - 1 && <span className="text-primary">{', '}</span>}
</React.Fragment>
))}
</div>
<div className={cn('flex flex-row gap-3 items-center justify-start')}>
<div className={cn('whitespace-nowrap')}>发行商</div>
<div className={cn('max-w-[160px] truncate', '3xl:max-w-[250px]')}>
{publishers.join(',') === ''
? '暂无'
: publishers.map((publisher, index) => (
<React.Fragment key={publisher}>
<FilterAdder filed="publishers" value={publisher} className={cn('')} />
{index < publishers.length - 1 && (
<span className="text-primary">{', '}</span>
)}
</React.Fragment>
))}
</div>
</div>
<div className={cn('flex flex-row gap-3 items-center justify-start')}>
<div className={cn('whitespace-nowrap')}>发行商</div>
<div className={cn('truncate')}>
{publishers.join(',') === ''
? '暂无'
: publishers.map((publisher, index) => (
<React.Fragment key={publisher}>
<FilterAdder filed="publishers" value={publisher} className={cn('')} />
{index < publishers.length - 1 && <span className="text-primary">{', '}</span>}
</React.Fragment>
))}
</div>
<div className={cn('flex flex-row gap-3 items-center justify-center')}>
<div className={cn('whitespace-nowrap')}>发行日期</div>
<div className={cn('grow')}>
{releaseDate === '' ? (
'暂无'
) : (
<FilterAdder
filed="releaseDate"
className={cn('hover:no-underline')}
value={releaseDate}
/>
)}
</div>
</div>
<div className={cn('flex flex-row gap-3 items-center justify-center')}>
<div className={cn('whitespace-nowrap')}>发行日期</div>
<div className={cn('grow')}>
{releaseDate === '' ? (
'暂无'
) : (
<FilterAdder
filed="releaseDate"
className={cn('hover:no-underline')}
value={releaseDate}
/>
)}
</div>
<div className={cn('flex flex-row gap-3 items-center justify-start')}>
<div className={cn('whitespace-nowrap')}>类型</div>
<div className={cn('max-w-[160px] truncate', '3xl:max-w-[250px]')}>
{genres.join(',') === ''
? '暂无'
: genres.map((genre, index) => (
<React.Fragment key={genre}>
<FilterAdder filed="genres" value={genre} />
{index < genres.length - 1 && <span className="text-primary">{', '}</span>}
</React.Fragment>
))}
</div>
</div>
<div className={cn('flex flex-row gap-3 items-center justify-start')}>
<div className={cn('whitespace-nowrap')}>类型</div>
<div className={cn('truncate')}>
{genres.join(',') === ''
? '暂无'
: genres.map((genre, index) => (
<React.Fragment key={genre}>
<FilterAdder filed="genres" value={genre} />
{index < genres.length - 1 && <span className="text-primary">{', '}</span>}
</React.Fragment>
))}
</div>
</div>
</CardContent>
</Card>
</div>
</div>
)
}
29 changes: 15 additions & 14 deletions src/renderer/src/components/Game/Overview/Record/RecordCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Card, CardContent, CardHeader, CardTitle } from '@ui/card'
import { cn } from '~/utils'
import { Separator } from '@ui/separator'

export function RecordCard({
title,
Expand All @@ -13,18 +13,19 @@ export function RecordCard({
className?: string
}): JSX.Element {
return (
<Card className={cn(className, 'h-[96px]')}>
<CardHeader className={cn('-mt-1')}>
<CardTitle>
<div className={cn('flex flex-row justify-between items-center')}>
<div className={cn('font-normal text-sm')}>{title}</div>
<span className={cn('w-3 h-3', icon)}></span>
</div>
</CardTitle>
</CardHeader>
<CardContent className={cn('-mt-4')}>
<div className={cn('text-xl font-bold')}>{content}</div>
</CardContent>
</Card>
<div className={cn('flex flex-row justify-center items-center', className)}>
<div
className={cn(
'flex flex-col gap-1 text-xs text-accent-foreground/90 justify-center items-center'
)}
>
<div className={cn('font-bold text-accent-foreground self-center')}>{title}</div>
<div className={cn('flex flex-row gap-1 items-center justify-start text-center')}>
<span className={cn(icon)}></span>
<div>{content}</div>
</div>
</div>
<Separator orientation="vertical" className={cn('mx-5 bg-primary h-7 self-center')} />
</div>
)
}
50 changes: 25 additions & 25 deletions src/renderer/src/components/Game/Overview/Record/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,31 @@ export function Record({ gameId }: { gameId: string }): JSX.Element {
const [score] = useDBSyncedState(-1, `games/${gameId}/record.json`, ['score'])
const [playingTime] = useDBSyncedState(0, `games/${gameId}/record.json`, ['playingTime'])
return (
<div className={cn('flex gap-5', '3xl:gap-7')}>
<div className={cn('w-3/4 grid grid-cols-3 gap-5', '3xl:gap-7')}>
<RecordCard
title="游玩时间"
content={playingTime !== 0 ? formatTimeToChinese(playingTime) : '暂无'}
icon="icon-[mdi--timer-outline] w-[20px] h-[20px]"
/>
<RecordCard
title="最后运行日期"
content={lastRunDate ? formatDateToISO(lastRunDate) : '从未运行'}
icon="icon-[mdi--calendar-blank-multiple] w-[18px] h-[18px]"
/>
<RecordCard
title="状态"
content={formatPlayStatusToChinese(playStatus)}
icon="icon-[mdi--bookmark-outline] w-[20px] h-[20px]"
/>
</div>
<div className={cn('w-1/4')}>
<RecordCard
title="我的评分"
content={formatScoreToChinese(score)}
icon="icon-[mdi--starburst-outline] w-[18px] h-[18px]"
/>
</div>
<div className={cn('flex flex-row')}>
<RecordCard
className={cn('')}
title="游玩时间"
content={playingTime !== 0 ? formatTimeToChinese(playingTime) : '暂无'}
icon="icon-[mdi--timer-outline] w-[16px] h-[16px]"
/>
<RecordCard
className={cn('')}
title="最后运行日期"
content={lastRunDate ? formatDateToISO(lastRunDate) : '从未运行'}
icon="icon-[mdi--calendar-blank-multiple] w-[16px] h-[16px]"
/>
<RecordCard
className={cn('')}
title="游玩状态"
content={formatPlayStatusToChinese(playStatus)}
icon="icon-[mdi--bookmark-outline] w-[16px] h-[16px]"
/>
<RecordCard
className={cn('')}
title="我的评分"
content={formatScoreToChinese(score)}
icon="icon-[mdi--starburst-outline] w-[16px] h-[16px]"
/>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { cn } from '~/utils'
import { Link } from '@ui/link'
import { Card, CardContent, CardHeader, CardTitle } from '@ui/card'
import { Separator } from '@ui/separator'
import { useDBSyncedState } from '~/hooks'
import { RelatedSitesDialog } from './RelatedSitesDialog'
import { isEqual } from 'lodash'
Expand All @@ -18,33 +18,23 @@ export function RelatedSitesCard({
['relatedSites']
)
return (
<Card className={cn(className, 'group')}>
<CardHeader>
<CardTitle>
<div className={cn('flex flex-row justify-between items-center')}>
<div>相关网站</div>
<RelatedSitesDialog gameId={gameId} />
</div>
</CardTitle>
</CardHeader>
<CardContent>
<div
className={cn(
'flex flex-col text-sm justify-start items-start overflow-auto scrollbar-base max-h-[220px]',
'3xl:max-h-[408px] sm:max-h-[3vh] '
)}
>
{isEqual(relatedSites, []) || isEqual(relatedSites, [{ label: '', url: '' }])
? '暂无相关网站'
: relatedSites.map((site, index) => (
<Link
key={`${gameId}-${site.label}-${site.url}-${index}`}
name={site.label}
url={site.url}
/>
))}
</div>
</CardContent>
</Card>
<div className={cn(className, 'group')}>
<div className={cn('flex flex-row justify-between items-center')}>
<div className={cn('font-bold')}>相关网站</div>
<RelatedSitesDialog gameId={gameId} />
</div>
<Separator className={cn('my-3 bg-primary')} />
<div className={cn('flex flex-col text-sm justify-start items-start')}>
{isEqual(relatedSites, []) || isEqual(relatedSites, [{ label: '', url: '' }])
? '暂无相关网站'
: relatedSites.map((site, index) => (
<Link
key={`${gameId}-${site.label}-${site.url}-${index}`}
name={site.label}
url={site.url}
/>
))}
</div>
</div>
)
}
Loading

0 comments on commit 99dfc96

Please sign in to comment.