refactor: use next/image

This commit is contained in:
sk1982 2024-04-10 03:58:27 -04:00
parent 169ea3c566
commit 0b8201b01f
8 changed files with 53 additions and 26 deletions

View File

@ -7,6 +7,7 @@ import { ChuniDifficultyContainer } from '@/components/chuni/difficulty-containe
import { Tooltip } from '@nextui-org/react'; import { Tooltip } from '@nextui-org/react';
import { ChuniLevelBadge } from '@/components/chuni/level-badge'; import { ChuniLevelBadge } from '@/components/chuni/level-badge';
import Link from 'next/link'; import Link from 'next/link';
import Image from 'next/image';
export type ChuniTopRatingProps = { export type ChuniTopRatingProps = {
className?: string, className?: string,
@ -18,7 +19,8 @@ export const ChuniTopRating = ({ rating, className }: ChuniTopRatingProps) => {
{rating.map((music, i) => <div key={i} className="flex py-2 h-28 border-b border-gray-500"> {rating.map((music, i) => <div key={i} className="flex py-2 h-28 border-b border-gray-500">
<ChuniDifficultyContainer difficulty={music.chartId ?? 0} className="flex-shrink-0 w-20 mr-2 self-center"> <ChuniDifficultyContainer difficulty={music.chartId ?? 0} className="flex-shrink-0 w-20 mr-2 self-center">
<Link className="p-1 block" href={`/chuni/music/${music.songId}`}> <Link className="p-1 block" href={`/chuni/music/${music.songId}`}>
<img className="aspect-square rounded overflow-hidden" src={getJacketUrl(`chuni/jacket/${music.jacketPath}`)} <Image className="aspect-square rounded overflow-hidden w-full h-full" width={72} height={72}
src={getJacketUrl(`chuni/jacket/${music.jacketPath}`)}
alt={music.title ?? ''} /> alt={music.title ?? ''} />
</Link> </Link>
<ChuniLevelBadge className="w-11 absolute -right-0.5 -bottom-0.5" music={music} /> <ChuniLevelBadge className="w-11 absolute -right-0.5 -bottom-0.5" music={music} />

View File

@ -10,6 +10,7 @@ import { ChuniLevelBadge } from '@/components/chuni/level-badge';
import { ChuniScoreBadge, ChuniLampSuccessBadge, getVariantFromRank, ChuniLampComboBadge } from '@/components/chuni/score-badge'; import { ChuniScoreBadge, ChuniLampSuccessBadge, getVariantFromRank, ChuniLampComboBadge } from '@/components/chuni/score-badge';
import { ChuniRating } from '@/components/chuni/rating'; import { ChuniRating } from '@/components/chuni/rating';
import Link from 'next/link'; import Link from 'next/link';
import Image from 'next/image';
import { HeartIcon as OutlineHeartIcon, Squares2X2Icon } from '@heroicons/react/24/outline'; import { HeartIcon as OutlineHeartIcon, Squares2X2Icon } from '@heroicons/react/24/outline';
import { HeartIcon as SolidHeartIcon } from '@heroicons/react/24/solid'; import { HeartIcon as SolidHeartIcon } from '@heroicons/react/24/solid';
import { Ticker, TickerHoverProvider } from '@/components/ticker'; import { Ticker, TickerHoverProvider } from '@/components/ticker';
@ -84,7 +85,9 @@ const MusicGrid = ({ music, size, setMusicList, fullMusicList }: ChuniMusicListP
onMouseLeave={() => setHover(false)}> onMouseLeave={() => setHover(false)}>
<div className="aspect-square w-full p-[0.2rem] relative"> <div className="aspect-square w-full p-[0.2rem] relative">
<Link href={`/chuni/music/${item.songId}`}> <Link href={`/chuni/music/${item.songId}`}>
<img src={getJacketUrl(`chuni/jacket/${item.jacketPath}`)} alt={item.title ?? 'Music'} className="rounded" /> <Image width={100} height={100}
src={getJacketUrl(`chuni/jacket/${item.jacketPath}`)}
alt={item.title ?? 'Music'} className="rounded w-full h-full" />
</Link> </Link>
{item.rating && !item.worldsEndTag && <div className={`${size === 'lg' ? 'text-2xl' : ''} absolute bottom-0.5 left-0.5 bg-gray-200/60 backdrop-blur-sm moz-no-backdrop-blur px-0.5 rounded`}> {item.rating && !item.worldsEndTag && <div className={`${size === 'lg' ? 'text-2xl' : ''} absolute bottom-0.5 left-0.5 bg-gray-200/60 backdrop-blur-sm moz-no-backdrop-blur px-0.5 rounded`}>
<ChuniRating rating={+item.rating * 100} className="-my-0.5"> <ChuniRating rating={+item.rating * 100} className="-my-0.5">

View File

@ -15,6 +15,7 @@ import { SaveIcon } from '@/components/save-icon';
import { useAudio } from '@/helpers/use-audio'; import { useAudio } from '@/helpers/use-audio';
import { Entries } from 'type-fest'; import { Entries } from 'type-fest';
import { useErrorModal } from '@/components/error-modal'; import { useErrorModal } from '@/components/error-modal';
import Image from 'next/image';
export type ChuniUserboxProps = { export type ChuniUserboxProps = {
profile: ChuniUserData, profile: ChuniUserData,
@ -128,7 +129,7 @@ export const ChuniUserbox = ({ profile, userboxItems }: ChuniUserboxProps) => {
const renderItem = (item: { name: string | undefined | null }, image: string, textClass='', containerClass='') => ( const renderItem = (item: { name: string | undefined | null }, image: string, textClass='', containerClass='') => (
<div className={`w-full h-full flex flex-col border border-gray-500 rounded-2xl shadow-inner ${containerClass}`}> <div className={`w-full h-full flex flex-col border border-gray-500 rounded-2xl shadow-inner ${containerClass}`}>
<img alt={item.name ?? ''} className={`w-full ${textClass}`} src={image} /> <Image width={100} height={100} alt={item.name ?? ''} className={`w-full h-auto ${textClass}`} src={image} />
<div className={textClass}>{ item.name }</div> <div className={textClass}>{ item.name }</div>
</div> </div>
); );
@ -240,7 +241,7 @@ export const ChuniUserbox = ({ profile, userboxItems }: ChuniUserboxProps) => {
<div className="flex w-full flex-col sm:flex-row items-center px-2 sm:px-4 sm:pb-4 h-full"> <div className="flex w-full flex-col sm:flex-row items-center px-2 sm:px-4 sm:pb-4 h-full">
<div className="flex flex-col"> <div className="flex flex-col">
<img className="w-80 max-w-full" <Image className="w-80 max-w-full" width={320} height={204} priority
alt={equipped.systemVoice.name ?? ''} src={getImageUrl(`chuni/system-voice-icon/${equipped.systemVoice.imagePath}`)} /> alt={equipped.systemVoice.name ?? ''} src={getImageUrl(`chuni/system-voice-icon/${equipped.systemVoice.imagePath}`)} />
<span className="text-center">{ equipped.systemVoice.name }</span> <span className="text-center">{ equipped.systemVoice.name }</span>
</div> </div>
@ -297,7 +298,7 @@ export const ChuniUserbox = ({ profile, userboxItems }: ChuniUserboxProps) => {
<Divider className="mb-4 hidden sm:block" /> <Divider className="mb-4 hidden sm:block" />
<img className="w-52 max-w-full -mt-2" <Image className="w-52 max-w-full -mt-2" width={208} height={208} priority
alt={equipped.mapIcon.name ?? ''} src={getImageUrl(`chuni/map-icon/${equipped.mapIcon.imagePath}`)} /> alt={equipped.mapIcon.name ?? ''} src={getImageUrl(`chuni/map-icon/${equipped.mapIcon.imagePath}`)} />
<span className="text-center mb-2">{ equipped.mapIcon.name }</span> <span className="text-center mb-2">{ equipped.mapIcon.name }</span>
<div className="px-2 w-full flex justify-center"> <div className="px-2 w-full flex justify-center">

View File

@ -1,4 +1,5 @@
import { getImageUrl } from '@/helpers/assets'; import { getImageUrl } from '@/helpers/assets';
import Image from 'next/image';
export type ChuniAvatarProps = { export type ChuniAvatarProps = {
wear: string | null, wear: string | null,
@ -12,45 +13,58 @@ export type ChuniAvatarProps = {
export const ChuniAvatar = ({ wear, head, face, skin, item, back, className }: ChuniAvatarProps) => { export const ChuniAvatar = ({ wear, head, face, skin, item, back, className }: ChuniAvatarProps) => {
return (<div className={`aspect-[544/588] relative overflow-hidden ${className ?? ''}`}> return (<div className={`aspect-[544/588] relative overflow-hidden ${className ?? ''}`}>
<img src={getImageUrl(`chuni/avatar/${back}`)} className="w-full h-full absolute inset-0" alt="" /> <Image width={544} height={588} priority
src={getImageUrl(`chuni/avatar/${back}`)} className="w-full h-full absolute inset-0" alt="" />
{head?.includes('CHU_UI_Avatar_Tex_01200001') && <div className="absolute aspect-[100/160] w-[16%] left-[40%] top-[3%] overflow-hidden"> {head?.includes('CHU_UI_Avatar_Tex_01200001') && <div className="absolute aspect-[100/160] w-[16%] left-[40%] top-[3%] overflow-hidden">
<img className="w-[522.44897%] max-w-none aspect-square absolute left-0 -top-[100%]" <Image width={512} height={512} priority
className="w-[522.44897%] max-w-none aspect-square absolute left-0 -top-[100%]"
src={getImageUrl(`chuni/avatar/CHU_UI_Common_Avatar_body_00`)} alt="" /> src={getImageUrl(`chuni/avatar/CHU_UI_Common_Avatar_body_00`)} alt="" />
</div>} </div>}
<div className="aspect-[256/104] overflow-hidden w-[44%] absolute left-[35.5%] top-[81%]"> <div className="aspect-[256/104] overflow-hidden w-[44%] absolute left-[35.5%] top-[81%]">
<img src={getImageUrl(`chuni/avatar/${skin}`)} className="w-full absolute bottom-0" alt="" /> <Image width={256} height={512} priority
src={getImageUrl(`chuni/avatar/${skin}`)} className="w-full absolute bottom-0" alt="" />
</div> </div>
<div className="aspect-[256/406] overflow-hidden w-[44%] absolute left-[28.5%] top-[22%]"> <div className="aspect-[256/406] overflow-hidden w-[44%] absolute left-[28.5%] top-[22%]">
<img src={getImageUrl(`chuni/avatar/${skin}`)} className="w-full" alt="" /> <Image width={256} height={512} priority
src={getImageUrl(`chuni/avatar/${skin}`)} className="w-full" alt="" />
</div> </div>
<div className="absolute aspect-[98/130] w-[16%] left-[42.25%] top-[25%] overflow-hidden"> <div className="absolute aspect-[98/130] w-[16%] left-[42.25%] top-[25%] overflow-hidden">
<img className="w-[522.44897%] max-w-none aspect-square absolute -left-[190%] -top-[75%]" <Image width={512} height={512} priority
className="w-[522.44897%] max-w-none aspect-square absolute -left-[190%] -top-[75%]"
src={getImageUrl(`chuni/avatar/CHU_UI_Common_Avatar_body_00`)} alt="" /> src={getImageUrl(`chuni/avatar/CHU_UI_Common_Avatar_body_00`)} alt="" />
</div> </div>
<div className="absolute aspect-[235/136] w-[35%] left-[33.75%] top-[26%] overflow-hidden"> <div className="absolute aspect-[235/136] w-[35%] left-[33.75%] top-[26%] overflow-hidden">
<img className="w-[435.74468%] max-w-none aspect-square absolute" <Image width={1024} height={1024} priority
className="w-[435.74468%] max-w-none aspect-square absolute"
src={getImageUrl(`chuni/avatar/CHU_UI_Common_Avatar_face_00`)} alt="" /> src={getImageUrl(`chuni/avatar/CHU_UI_Common_Avatar_face_00`)} alt="" />
</div> </div>
<div className="absolute aspect-[79/153] w-[13%] left-[22%] top-[48%] overflow-hidden origin-top-right rotate-[10deg]"> <div className="absolute aspect-[79/153] w-[13%] left-[22%] top-[48%] overflow-hidden origin-top-right rotate-[10deg]">
<img className="w-[648.10126%] max-w-none aspect-square absolute" <Image width={512} height={512} priority
className="w-[648.10126%] max-w-none aspect-square absolute"
src={getImageUrl(`chuni/avatar/CHU_UI_Common_Avatar_body_00`)} alt="" /> src={getImageUrl(`chuni/avatar/CHU_UI_Common_Avatar_body_00`)} alt="" />
</div> </div>
<div className="absolute aspect-[79/153] w-[13%] left-[52.5%] top-[48%] overflow-hidden origin-top-right -rotate-[10deg] -scale-x-100"> <div className="absolute aspect-[79/153] w-[13%] left-[52.5%] top-[48%] overflow-hidden origin-top-right -rotate-[10deg] -scale-x-100">
<img className="w-[648.10126%] max-w-none aspect-square absolute" <Image width={512} height={512} priority
className="w-[648.10126%] max-w-none aspect-square absolute"
src={getImageUrl(`chuni/avatar/CHU_UI_Common_Avatar_body_00`)} alt="" /> src={getImageUrl(`chuni/avatar/CHU_UI_Common_Avatar_body_00`)} alt="" />
</div> </div>
<img className="absolute aspect-[232/208] w-[38%] left-[31%] top-[24%]" <Image width={233} height={208} priority
className="absolute aspect-[232/208] w-[38%] left-[31%] top-[24%]"
src={getImageUrl(`chuni/avatar/${face}`)} alt=""/> src={getImageUrl(`chuni/avatar/${face}`)} alt=""/>
<img className="absolute aspect-[516/436] w-[87%] left-[6.75%] top-[27%]" <Image width={516} height={436} priority
className="absolute aspect-[516/436] w-[87%] left-[6.75%] top-[27%]"
src={getImageUrl(`chuni/avatar/${wear}`)} alt="" /> src={getImageUrl(`chuni/avatar/${wear}`)} alt="" />
<img className="absolute aspect-[4/3] w-[72.25%] left-[14.65%] top-[1%]" <Image width={256} height={192} priority
className="absolute aspect-[4/3] w-[72.25%] left-[14.65%] top-[1%]"
src={getImageUrl(`chuni/avatar/${head}`)} alt=""/> src={getImageUrl(`chuni/avatar/${head}`)} alt=""/>
<div className="absolute aspect-[200/544] w-[30%] top-[14%] left-[8%] overflow-hidden origin-[42.5%_67%]"> <div className="absolute aspect-[200/544] w-[30%] top-[14%] left-[8%] overflow-hidden origin-[42.5%_67%]">
<img className="absolute aspect-[400/544] w-[200%] left-0 top-0 max-w-none" <Image width={400} height={544} priority
className="absolute aspect-[400/544] w-[200%] left-0 top-0 max-w-none"
src={getImageUrl(`chuni/avatar/${item}`)} alt=""/> src={getImageUrl(`chuni/avatar/${item}`)} alt=""/>
</div> </div>
<div className="absolute aspect-[200/544] w-[30%] top-[14%] left-[62%] overflow-hidden origin-[57.5%_67%]"> <div className="absolute aspect-[200/544] w-[30%] top-[14%] left-[62%] overflow-hidden origin-[57.5%_67%]">
<img className="absolute aspect-[400/544] w-[200%] right-0 top-0 max-w-none" <Image width={400} height={544} priority
className="absolute aspect-[400/544] w-[200%] right-0 top-0 max-w-none"
src={getImageUrl(`chuni/avatar/${item}`)} alt=""/> src={getImageUrl(`chuni/avatar/${item}`)} alt=""/>
</div> </div>
</div>) </div>)

View File

@ -4,6 +4,7 @@ import { ChuniTrophy } from '@/components/chuni/trophy';
import { PickNullable } from '@/types/pick-nullable'; import { PickNullable } from '@/types/pick-nullable';
import { ChuniRating } from '@/components/chuni/rating'; import { ChuniRating } from '@/components/chuni/rating';
import { formatJst } from '@/helpers/format-jst'; import { formatJst } from '@/helpers/format-jst';
import Image from 'next/image';
export const CHUNI_NAMEPLATE_PROFILE_KEYS = [ export const CHUNI_NAMEPLATE_PROFILE_KEYS = [
'trophyName', 'trophyRareType', 'nameplateImage', 'nameplateName', 'teamName', 'characterId', 'level', 'trophyName', 'trophyRareType', 'nameplateImage', 'nameplateName', 'teamName', 'characterId', 'level',
@ -63,12 +64,13 @@ export const ChuniNameplate = ({ className, profile }: ChuniNameplateProps) => {
</div> </div>
</div> </div>
</div> </div>
<img className="ml-auto aspect-square h-full bg-gray-200 border-2 border-black" alt="Character" src={profile.characterId !== null ? getImageUrl( <Image className="ml-auto aspect-square h-full w-auto bg-gray-200 border-2 border-black" alt="Character" width={135} height={135} src={profile.characterId !== null ? getImageUrl(
`chuni/character/CHU_UI_Character_${Math.floor(profile.characterId / 10).toString() `chuni/character/CHU_UI_Character_${Math.floor(profile.characterId / 10).toString()
.padStart(4, '0')}_${(profile.characterId % 10).toString().padStart(2, '0')}_02`) : ''}/> .padStart(4, '0')}_${(profile.characterId % 10).toString().padStart(2, '0')}_02`) : ''}/>
</div> </div>
</div> </div>
<img src={getImageUrl(`chuni/name-plate/${profile.nameplateImage}`)} title={profile.nameplateName ?? 'Nameplate'} <Image width={576} height={228} priority
src={getImageUrl(`chuni/name-plate/${profile.nameplateImage}`)} title={profile.nameplateName ?? 'Nameplate'}
alt={profile.nameplateName ?? 'Nameplate'} className="absolute inset-0 w-full h-full" /> alt={profile.nameplateName ?? 'Nameplate'} className="absolute inset-0 w-full h-full" />
</div> </div>
</div>) </div>)

View File

@ -10,6 +10,7 @@ import { ChuniDifficultyContainer } from '@/components/chuni/difficulty-containe
import { formatJst } from '@/helpers/format-jst'; import { formatJst } from '@/helpers/format-jst';
import { Ticker, TickerHoverProvider } from '@/components/ticker'; import { Ticker, TickerHoverProvider } from '@/components/ticker';
import { Divider } from '@nextui-org/react'; import { Divider } from '@nextui-org/react';
import Image from 'next/image';
export type ChuniPlaylogCardProps = { export type ChuniPlaylogCardProps = {
playlog: ChuniPlaylog['data'][number], playlog: ChuniPlaylog['data'][number],
@ -38,7 +39,7 @@ export const ChuniPlaylogCard = ({ playlog, className, badgeClass, showDetails }
<ChuniDifficultyContainer difficulty={playlog.chartId ?? 0} className="w-28 aspect-square relative p-1"> <ChuniDifficultyContainer difficulty={playlog.chartId ?? 0} className="w-28 aspect-square relative p-1">
<ChuniLevelBadge className="absolute -bottom-1.5 -right-1.5 w-12" music={playlog} /> <ChuniLevelBadge className="absolute -bottom-1.5 -right-1.5 w-12" music={playlog} />
<Link href={`/chuni/music/${playlog.songId}`}> <Link href={`/chuni/music/${playlog.songId}`}>
<img className="aspect-square w-full rounded overflow-hidden" <Image className="aspect-square w-full rounded overflow-hidden" width={100} height={100}
src={getJacketUrl(`chuni/jacket/${playlog.jacketPath}`)} src={getJacketUrl(`chuni/jacket/${playlog.jacketPath}`)}
alt={playlog.title ?? ''} /> alt={playlog.title ?? ''} />
</Link> </Link>

View File

@ -1,3 +1,4 @@
import Image from 'next/image';
import { getImageUrl } from '@/helpers/assets'; import { getImageUrl } from '@/helpers/assets';
const TROPHY_TYPES = { const TROPHY_TYPES = {
@ -29,10 +30,11 @@ export const ChuniTrophy = ({ name, rarity, className }: ChuniTrophyProps) => {
</div> </div>
</div> </div>
<div className="w-[129.51%] aspect-[768/1024] relative"> <div className="w-[129.51%] aspect-[768/1024] relative">
<img src={getImageUrl('chuni/trophy/CHU_UI_title_rank_00_v10')} <Image width={593} height={62} priority
alt={name ?? 'Trophy'} title={name ?? 'Trophy'} src={getImageUrl('chuni/trophy/CHU_UI_title_rank_00_v10')}
className="w-full absolute left-[-0.78125%]" style={{ alt={name ?? 'Trophy'} title={name ?? 'Trophy'}
top: `-${TROPHY_Y[TROPHY_TYPES[rarity as keyof typeof TROPHY_TYPES]]}%` className="w-full absolute h-auto left-[-0.78125%]" style={{
top: `-${TROPHY_Y[TROPHY_TYPES[rarity as keyof typeof TROPHY_TYPES]]}%`
}}/> }}/>
</div> </div>
</div>) </div>)

View File

@ -4,6 +4,7 @@ import { Button, Card, CardBody, Slider } from '@nextui-org/react';
import { PauseCircleIcon, PlayCircleIcon } from '@heroicons/react/24/solid'; import { PauseCircleIcon, PlayCircleIcon } from '@heroicons/react/24/solid';
import { ReactNode, useEffect, useState } from 'react'; import { ReactNode, useEffect, useState } from 'react';
import { useAudio } from '@/helpers/use-audio'; import { useAudio } from '@/helpers/use-audio';
import Image from 'next/image';
export type MusicPlayerProps = { export type MusicPlayerProps = {
audio: string, audio: string,
@ -55,7 +56,8 @@ export const MusicPlayer = ({ audio, image, children, className }: MusicPlayerPr
<CardBody className="sm:rounded-2xl sm:p-4 bg-content1 sm:bg-content2"> <CardBody className="sm:rounded-2xl sm:p-4 bg-content1 sm:bg-content2">
<div className="grid grid-cols-12"> <div className="grid grid-cols-12">
<div className="col-span-full sm:col-span-4 h-full flex items-center justify-center sm:justify-start"> <div className="col-span-full sm:col-span-4 h-full flex items-center justify-center sm:justify-start">
<img src={image} alt="" className="aspect-square rounded-md shadow-2xl max-w-56 w-full border border-gray-500 sm:border-0" /> <Image src={image} alt="Jacket" width={224} height={224}
className="aspect-square rounded-md shadow-2xl max-w-56 w-full border border-gray-500 sm:border-0" />
</div> </div>
<div className="col-span-full sm:col-span-8 h-full flex flex-col pt-4 sm:pt-0 sm:pl-4 text-xl"> <div className="col-span-full sm:col-span-8 h-full flex flex-col pt-4 sm:pt-0 sm:pl-4 text-xl">
<div className="mb-2 sm:my-auto flex flex-col gap-1 items-center sm:items-start overflow-hidden"> <div className="mb-2 sm:my-auto flex flex-col gap-1 items-center sm:items-start overflow-hidden">