Skip to content

Commit

Permalink
Pando conditional UI (#2422)
Browse files Browse the repository at this point in the history
* rudimentary conditional UI

* setConditional

* todo go-next

* minor refactor
  • Loading branch information
frzyc authored Aug 31, 2024
1 parent ef0348b commit 88bb289
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 26 deletions.
1 change: 1 addition & 0 deletions apps/gi-frontend/src/app/teams/[teamId]/TalentContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ function SkillDisplayCard({
document={doc}
collapse
// hideHeader={hideHeader}
setConditional={() => {}} // TODO: frzyc setConditional
/>
))}
</CardContent>
Expand Down
127 changes: 115 additions & 12 deletions libs/pando/ui-sheet/src/components/DocumentDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,39 @@
import type { CardBackgroundColor } from '@genshin-optimizer/common/ui'
import { CardHeaderCustom, CardThemed } from '@genshin-optimizer/common/ui'
import { evalIfFunc } from '@genshin-optimizer/common/util'
import { read } from '@genshin-optimizer/pando/engine'
import CheckBoxIcon from '@mui/icons-material/CheckBox'
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'
import { Box, Collapse, Divider } from '@mui/material'
import { Box, Button, Collapse, Divider } from '@mui/material'
import { useContext, useState } from 'react'
import { CalcContext } from '../context'
import type { Document, FieldsDocument, Header, TextDocument } from '../types'
import type {
Conditional,
Document,
FieldsDocument,
Header,
TextDocument,
} from '../types'
import { FieldsDisplay } from './FieldDisplay'

type SetConditionalFunc = (
srcKey: string,
sheetKey: string,
condKey: string,
value: number
) => void

export function DocumentDisplay({
document,
bgt = 'normal',
collapse = false,
setConditional,
}: {
document: Document
bgt?: CardBackgroundColor
collapse?: boolean
setConditional: SetConditionalFunc
}) {
switch (document.type) {
case 'fields':
Expand All @@ -28,16 +46,16 @@ export function DocumentDisplay({
<TextSectionDisplay textDocument={document} />
)
case 'conditional':
return null //TODO:
// return (
// <ConditionalDisplay
// conditional={document}
// hideDesc={hideDesc}
// hideHeader={hideHeader}
// disabled={disabled}
// bgt={bgt}
// />
// )
return (
<ConditionalDisplay
conditional={document.conditional}
setConditional={setConditional}
// hideDesc={hideDesc}
// hideHeader={hideHeader}
// disabled={disabled}
bgt={bgt}
/>
)
default:
return null
}
Expand Down Expand Up @@ -136,3 +154,88 @@ export function HeaderDisplay({
</>
)
}

function ConditionalDisplay({
conditional,
bgt = 'normal',
setConditional,
}: {
conditional: Conditional
bgt?: CardBackgroundColor
setConditional: SetConditionalFunc
}) {
const { header, fields } = conditional
return (
<CardThemed bgt={bgt}>
{!!header && <HeaderDisplay header={header} />}
<ConditionalSelector
conditional={conditional}
setConditional={setConditional}
/>
{!!fields && <FieldsDisplay bgt={bgt} fields={fields} />}
</CardThemed>
)
}
function ConditionalSelector({
conditional,
setConditional,
}: {
conditional: Conditional
setConditional: SetConditionalFunc
}) {
switch (conditional.metadata.type) {
case 'bool':
return (
<BoolConditional
conditional={conditional}
setConditional={setConditional}
/>
)
//TODO: case 'list' and 'num'
default:
return null
}
}
function BoolConditional({
conditional,
setConditional,
}: {
conditional: Conditional
setConditional: SetConditionalFunc
}) {
const calc = useContext(CalcContext)
const { label, badge } = conditional
const { sheet: sheetKey, name: condKey } = conditional.metadata
if (!sheetKey || !condKey) throw new Error('metadata missing')
const srcKey = 'all'
const conditionalValue = calc?.compute(
read(
{
et: 'own',
qt: 'cond',
sheet: sheetKey,
q: condKey,
src: srcKey,
dst: calc.cache.tag.src,
},
'max'
)
).val
return (
<Button
fullWidth
size="small"
sx={{ borderRadius: 0 }}
color={conditionalValue ? 'success' : 'primary'}
onClick={() =>
setConditional(srcKey, sheetKey, condKey, +!conditionalValue)
}
// disabled={disabled}
startIcon={
conditionalValue ? <CheckBoxIcon /> : <CheckBoxOutlineBlankIcon />
}
>
{label} {badge}
</Button>
)
}
14 changes: 11 additions & 3 deletions libs/pando/ui-sheet/src/types/conditional.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import type { Tag } from '@genshin-optimizer/pando/engine'
import type { ReactNode } from 'react'
import type { Field } from './field'
import type { Header } from './header'

export type Conditional = {
tag: Tag
fields: Field[]
metadata: {
// TODO: hoist IConditionalData of gi/sr meta.ts to be accessible here
type: 'bool' | 'list' | 'num'
[x: string]: string | null
}
label: ReactNode
badge?: ReactNode
header?: Header
fields?: Field[]
}
2 changes: 1 addition & 1 deletion libs/sr/assets/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
import chars from './gen/chars'
import lightCones from './gen/lightCones'
import relics from './gen/relics'
type characterAssetKey = 'icon' | 'basic_0'
type characterAssetKey = 'icon' | 'basic_0' | 'skill_0'
export function characterAsset(
ck: NonTrailblazerCharacterKey | TrailblazerGenderedKey,
asset: characterAssetKey
Expand Down
10 changes: 5 additions & 5 deletions libs/sr/db/src/Types/conditional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import type {
RelicSetKey,
} from '@genshin-optimizer/sr/consts'

export type CondKey = CharacterKey | RelicSetKey | LightConeKey
type SheetKey = CharacterKey | RelicSetKey | LightConeKey
// Stored per-char loadout, so the dst is assumed to be the owning char
// CharKey is the srcKey
// CondKey is the SheetKey
// key is the condKey
// CharKey|'all' is the srcKey
// SheetKey is the SheetKey
// condkey is the condKey
// value is the condValue
export type ConditionalValues = Partial<
Record<
CharacterKey | 'all',
Partial<Record<CondKey, { [key: string]: string }>>
Partial<Record<SheetKey, { [condkey: string]: number }>>
>
>
32 changes: 31 additions & 1 deletion libs/sr/formula-ui/src/char/sheets/RuanMei.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ImgIcon, SqBadge } from '@genshin-optimizer/common/ui'
import type { UISheet } from '@genshin-optimizer/pando/ui-sheet'
import { characterAsset } from '@genshin-optimizer/sr/assets'
import type { CharacterKey } from '@genshin-optimizer/sr/consts'
import { formulas, own } from '@genshin-optimizer/sr/formula'
import { conditionals, formulas, own } from '@genshin-optimizer/sr/formula'
import { getInterpolateObject } from '@genshin-optimizer/sr/stats'
import { trans } from '../../util'
import type { TalentSheetElementKey } from '../consts'
Expand Down Expand Up @@ -33,6 +34,35 @@ const sheet: UISheet<TalentSheetElementKey> = {
},
],
},
skill: {
name: chg('abilities.skill.0.name'),
img: characterAsset(key, 'skill_0'),
documents: [
{
type: 'text',
text: (calculator) => {
const basicLevel = calculator.compute(own.char.basic).val
return chg(
`abilities.skill.0.fullDesc`,
getInterpolateObject(key, 'skill', basicLevel)
)
},
},
{
type: 'conditional',
conditional: {
header: {
icon: <ImgIcon src={characterAsset(key, 'skill_0')} />,
text: 'skill active',
additional: <SqBadge>Skill</SqBadge>,
},
metadata: conditionals.RuanMei.skillOvertone,
label: 'Overtone',
fields: [{ title: 'Duration', fieldValue: 3 }],
},
},
],
},
}

export default sheet
29 changes: 25 additions & 4 deletions libs/sr/page-team/src/TeammateDisplay/Tabs/TalentContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
DropdownButton,
NextImage,
} from '@genshin-optimizer/common/ui'
import { range } from '@genshin-optimizer/common/util'
import { layeredAssignment, range } from '@genshin-optimizer/common/util'
import type { UISheetElement } from '@genshin-optimizer/pando/ui-sheet'
import { DocumentDisplay } from '@genshin-optimizer/pando/ui-sheet'
import { maxEidolonCount } from '@genshin-optimizer/sr/consts'
Expand All @@ -14,7 +14,11 @@ import {
useSrCalcContext,
type TalentSheetElementKey,
} from '@genshin-optimizer/sr/formula-ui'
import { useLoadoutContext } from '@genshin-optimizer/sr/ui'
import {
LoadoutContext,
useDatabaseContext,
useLoadoutContext,
} from '@genshin-optimizer/sr/ui'
import {
Box,
CardActionArea,
Expand All @@ -26,7 +30,7 @@ import {
useTheme,
} from '@mui/material'
import type { ReactNode } from 'react'
import { useCallback } from 'react'
import { useCallback, useContext } from 'react'
import { useTranslation } from 'react-i18next'

const talentSpacing = {
Expand Down Expand Up @@ -86,7 +90,6 @@ export default function CharacterTalentPane() {
// ]
// )
const characterSheet = uiSheets[characterKey]
console.log({ characterSheet, calc })
if (!characterSheet || !calc) return
return (
<>
Expand Down Expand Up @@ -278,6 +281,23 @@ function SkillDisplayCard({
// return false
// }

const { loadoutId } = useContext(LoadoutContext)
const { database } = useDatabaseContext()
const setConditional = useCallback(
(srcKey: string, sheetKey: string, condKey: string, condValue: number) => {
database.loadouts.set(loadoutId, (loadout) => {
loadout = structuredClone(loadout)
layeredAssignment(
loadout.conditional,
[srcKey, sheetKey, condKey],
condValue
)
return loadout
})
},
[database, loadoutId]
)

return (
<CardThemed bgt="light" sx={{ height: '100%' }}>
{header}
Expand Down Expand Up @@ -307,6 +327,7 @@ function SkillDisplayCard({
document={doc}
collapse
// hideHeader={hideHeader}
setConditional={setConditional}
/>
))}
</CardContent>
Expand Down

0 comments on commit 88bb289

Please sign in to comment.