diff --git a/libs/gi/db/src/Database/DataManagers/BuildDataManager.ts b/libs/gi/db/src/Database/DataManagers/BuildDataManager.ts index f6fc68e950..eb6f46b969 100644 --- a/libs/gi/db/src/Database/DataManagers/BuildDataManager.ts +++ b/libs/gi/db/src/Database/DataManagers/BuildDataManager.ts @@ -9,6 +9,7 @@ import { defaultInitialWeaponKey, initialWeapon } from './WeaponDataManager' export interface Build { name: string description: string + id: string weaponId?: string artifactIds: Record @@ -29,6 +30,7 @@ export class BuildDataManager extends DataManager< } override validate(obj: unknown): Build | undefined { let { name, description, weaponId, artifactIds } = obj as Build + const { id } = obj as Build if (typeof name !== 'string') name = 'Build Name' if (typeof description !== 'string') description = '' if (weaponId && !this.database.weapons.get(weaponId)) weaponId = undefined @@ -62,6 +64,7 @@ export class BuildDataManager extends DataManager< description, weaponId, artifactIds, + id, } } diff --git a/libs/gi/localization/assets/locales/en/artifact.json b/libs/gi/localization/assets/locales/en/artifact.json index df98210d51..56d8b2fbe0 100644 --- a/libs/gi/localization/assets/locales/en/artifact.json +++ b/libs/gi/localization/assets/locales/en/artifact.json @@ -121,5 +121,8 @@ "rvSliderBtn": { "maximum": "MRV", "current": "RV" - } + }, + "builds_one": "{{count}} Build", + "builds_other": "{{count}} Builds", + "artifactUsage": "Artifact is used in the following loadouts and builds: " } diff --git a/libs/gi/ui/src/components/artifact/ArtifactCard.tsx b/libs/gi/ui/src/components/artifact/ArtifactCard.tsx index 2fb7385a78..ddc981837a 100644 --- a/libs/gi/ui/src/components/artifact/ArtifactCard.tsx +++ b/libs/gi/ui/src/components/artifact/ArtifactCard.tsx @@ -1,5 +1,6 @@ 'use client' // use client due to hydration difference between client rendering and server in translation +import { useBoolState } from '@genshin-optimizer/common/react-util' import { iconInlineProps } from '@genshin-optimizer/common/svgicons' import { BootstrapTooltip, @@ -8,13 +9,16 @@ import { ConditionalWrapper, InfoTooltip, InfoTooltipInline, + ModalWrapper, NextImage, + SqBadge, StarsDisplay, } from '@genshin-optimizer/common/ui' import { clamp, clamp01, getUnitStr } from '@genshin-optimizer/common/util' import { artifactAsset } from '@genshin-optimizer/gi/assets' import type { ArtifactRarity, + CharacterKey, LocationKey, SubstatKey, } from '@genshin-optimizer/gi/consts' @@ -23,7 +27,7 @@ import { allSubstatKeys, } from '@genshin-optimizer/gi/consts' import type { ICachedArtifact, ICachedSubstat } from '@genshin-optimizer/gi/db' -import { useArtifact } from '@genshin-optimizer/gi/db-ui' +import { useArtifact, useDatabase } from '@genshin-optimizer/gi/db-ui' import { SlotIcon, StatIcon } from '@genshin-optimizer/gi/svgicons' import { artDisplayValue, @@ -40,8 +44,13 @@ import { Button, CardActionArea, CardContent, + CardHeader, Chip, IconButton, + List, + ListItem, + ListItemIcon, + ListItemText, Skeleton, SvgIcon, Typography, @@ -49,9 +58,9 @@ import { import type { ReactNode } from 'react' import { Suspense, useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' -import { ExcludeIcon } from '../../consts' +import { CloseIcon, ExcludeIcon, LoadoutIcon } from '../../consts' import { PercentBadge } from '../PercentBadge' -import { LocationAutocomplete, LocationName } from '../character' +import { CharIconSide, LocationAutocomplete, LocationName } from '../character' import { ArtifactSetTooltipContent } from './ArtifactSetTooltip' import { ArtifactSetName, @@ -96,7 +105,7 @@ export function ArtifactCardObj({ } & Data) { const { t } = useTranslation(['artifact', 'ui']) const { t: tk } = useTranslation('statKey_gen') - + const [showUsage, onShowUsage, onHideUsage] = useBoolState(false) const wrapperFunc = useCallback( (children: ReactNode) => ( { + return database.builds.values + .filter( + ({ artifactIds }) => artifactIds[artifact.slotKey] === artifact.id + ) + .flatMap(({ id, name }) => { + const buildName = name + return database.teamChars.values + .filter(({ buildIds }) => buildIds.includes(id)) + .map(({ key, name }) => { + return { + charKey: key, + buildName, + loadoutName: name, + } + }) + }) + }, [database.builds, database.teamChars, artifact.slotKey, artifact.id]) const artifactValid = maxEfficiency !== 0 const slotName = const slotDesc = @@ -178,6 +209,14 @@ export function ArtifactCardObj({ /> } > + + + )} - + {(setKey && ) || 'Artifact Set'}{' '} {setKey && ( @@ -358,6 +405,16 @@ export function ArtifactCardObj({ title={} /> )} + + {t('builds', { count: builds.length })} + @@ -488,3 +545,58 @@ function SubstatDisplay({ ) } + +function ArtifactBuildUsageModal({ + show, + onHide, + usageText, + builds, +}: { + show: boolean + onHide: () => void + usageText: string + builds: { + loadoutName: string + buildName: string + charKey: CharacterKey + }[] +}) { + return ( + + + + {usageText} + + } + action={ + + + + } + /> + + {builds.map((build, index) => ( + + + + + + + + ))} + + + + ) +}