@mui/material#Pagination TypeScript Examples
The following examples show how to use
@mui/material#Pagination.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Pager.tsx From cli with Apache License 2.0 | 6 votes |
PagerRenderer: FunctionComponent<PagerProps> = (props) => {
const {controller} = props;
const [state, setState] = useState(controller.state);
useEffect(
() =>
controller.subscribe(() =>
setTimeout(() => setState(controller.state), 0)
),
[controller]
);
const setPage = (pageNumber: number) => {
controller.selectPage(pageNumber);
};
return (
<Box>
<Typography gutterBottom>Current page</Typography>
<Pagination
page={state.currentPage}
count={state.maxPage}
onChange={(e, page) => setPage(page)}
shape="rounded"
size="small"
/>
</Box>
);
}
Example #2
Source File: Dashboard.tsx From NekoMaid with MIT License | 5 votes |
Players: React.FC<{ players?: CurrentStatus['players'] }> = React.memo(({ players }) => {
const his = useHistory()
const plugin = usePlugin()
const globalData = useGlobalData()
const [page, setPage] = useState(1)
const [id, update] = useState(0)
return <Card>
<CardHeader title={lang.dashboard.onlinePlayers} />
<Divider />
<CardContent>
{players?.length === 0
? <Empty />
: <>
<List sx={{ paddingTop: 0 }}>
{players
? players.slice((page - 1) * 8, page * 8).map(p => {
const name = typeof p === 'string' ? p : p.name
return <Tooltip key={name} title={'IP: ' + ((p as any).ip || lang.unknown)}>
<ListItem
secondaryAction={<>
<IconButton
edge='end'
size='small'
onClick={() => dialog(lang.dashboard.confirmKick(<span className='bold'>{name}</span>), lang.reason)
.then(it => it != null && plugin.emit('dashboard:kick', (res: boolean) => {
action(res)
if (!players) return
players.splice(players.indexOf(it!), 1)
update(id + 1)
}, name, it || null))
}
><ExitToApp /></IconButton>
<IconButton edge='end' onClick={() => his.push('/NekoMaid/playerList/' + name)} size='small'><MoreHoriz /></IconButton>
</>
}
>
<ListItemAvatar>
<Avatar
src={getSkin(globalData, name, true)}
imgProps={{ crossOrigin: 'anonymous', onClick () { his.push('/NekoMaid/playerList/' + name) }, style: { width: 40, height: 40 } }}
sx={{ cursor: 'pointer' }}
variant='rounded'
/>
</ListItemAvatar>
<ListItemText primary={name} />
</ListItem>
</Tooltip>
})
: <LoadingList />
}
</List>
{players && <Pagination
page={page}
onChange={(_, it) => setPage(it)}
count={Math.max(Math.ceil(players.length / 8), 1)}
sx={{ display: 'flex', justifyContent: 'flex-end' }}
/>}
</>}
</CardContent>
</Card>
})
Example #3
Source File: index.tsx From genshin-optimizer with MIT License | 4 votes |
export default function PageArtifact() {
const [{ tcMode }] = useDBState("GlobalSettings", initGlobalSettings)
const { t } = useTranslation(["artifact", "ui"]);
const { database } = useContext(DatabaseContext)
const [state, setState] = useDBState("ArtifactDisplay", initialState)
const stateDispatch = useCallback(
action => {
if (action.type === "reset") setState(initialArtifactSortFilter())
else setState(action)
},
[setState],
)
const brPt = useMediaQueryUp()
const maxNumArtifactsToDisplay = numToShowMap[brPt]
const { effFilter, filterOption, ascending, probabilityFilter } = state
let { sortType } = state
const showProbability = tcMode && sortType === "probability"
//force the sortType back to a normal value after exiting TC mode
if (sortType === "probability" && !tcMode) stateDispatch({ sortType: artifactSortKeys[0] })
const [pageIdex, setpageIdex] = useState(0)
const invScrollRef = useRef<HTMLDivElement>(null)
const [dbDirty, forceUpdate] = useForceUpdate()
const effFilterSet = useMemo(() => new Set(effFilter), [effFilter]) as Set<SubstatKey>
const deleteArtifact = useCallback((id: string) => database.removeArt(id), [database])
useEffect(() => {
ReactGA.send({ hitType: "pageview", page: '/artifact' })
return database.followAnyArt(forceUpdate)
}, [database, forceUpdate])
const filterOptionDispatch = useCallback((action) => {
stateDispatch({
filterOption: {
...filterOption,
...action
}
})
}, [stateDispatch, filterOption])
const setProbabilityFilter = useCallback(probabilityFilter => stateDispatch({ probabilityFilter }), [stateDispatch],)
const noArtifact = useMemo(() => !database._getArts().length, [database])
const sortConfigs = useMemo(() => artifactSortConfigs(effFilterSet, probabilityFilter), [effFilterSet, probabilityFilter])
const filterConfigs = useMemo(() => artifactFilterConfigs(), [])
const { artifactIds, totalArtNum } = useMemo(() => {
const { sortType = artifactSortKeys[0], ascending = false, filterOption } = state
let allArtifacts = database._getArts()
const filterFunc = filterFunction(filterOption, filterConfigs)
const sortFunc = sortFunction(sortType, ascending, sortConfigs)
//in probability mode, filter out the artifacts that already reach criteria
if (showProbability) {
allArtifacts.forEach(art => (art as any).probability = probability(art, probabilityFilter))
allArtifacts = allArtifacts.filter(art => (art as any).probability && (art as any).probability !== 1)
}
const artifactIds = allArtifacts.filter(filterFunc).sort(sortFunc).map(art => art.id)
return { artifactIds, totalArtNum: allArtifacts.length, ...dbDirty }//use dbDirty to shoo away warnings!
}, [state, dbDirty, database, sortConfigs, filterConfigs, probabilityFilter, showProbability])
const { artifactIdsToShow, numPages, currentPageIndex } = useMemo(() => {
const numPages = Math.ceil(artifactIds.length / maxNumArtifactsToDisplay)
const currentPageIndex = clamp(pageIdex, 0, numPages - 1)
return { artifactIdsToShow: artifactIds.slice(currentPageIndex * maxNumArtifactsToDisplay, (currentPageIndex + 1) * maxNumArtifactsToDisplay), numPages, currentPageIndex }
}, [artifactIds, pageIdex, maxNumArtifactsToDisplay])
//for pagination
const totalShowing = artifactIds.length !== totalArtNum ? `${artifactIds.length}/${totalArtNum}` : `${totalArtNum}`
const setPage = useCallback(
(e, value) => {
invScrollRef.current?.scrollIntoView({ behavior: "smooth" })
setpageIdex(value - 1);
},
[setpageIdex, invScrollRef],
)
return <Box display="flex" flexDirection="column" gap={1} my={1}>
<InfoComponent
pageKey="artifactPage"
modalTitle={t`info.title`}
text={t("tipsOfTheDay", { returnObjects: true }) as string[]}
>
<InfoDisplay />
</InfoComponent>
{noArtifact && <Alert severity="info" variant="filled">Looks like you haven't added any artifacts yet. If you want, there are <Link color="warning.main" component={RouterLink} to="/scanner">automatic scanners</Link> that can speed up the import process!</Alert>}
<ArtifactFilter filterOption={filterOption} filterOptionDispatch={filterOptionDispatch} filterDispatch={stateDispatch}
numShowing={artifactIds.length} total={totalArtNum} />
{showProbability && <ProbabilityFilter probabilityFilter={probabilityFilter} setProbabilityFilter={setProbabilityFilter} />}
<CardDark ref={invScrollRef}>
<CardContent>
<Grid container sx={{ mb: 1 }}>
<Grid item flexGrow={1}><span><Trans t={t} i18nKey="efficiencyFilter.title">Substats to use in efficiency calculation</Trans></span></Grid>
<Grid item>
<Button size="small" color="error" onClick={() => stateDispatch({ effFilter: [...allSubstatKeys] })} startIcon={<Replay />}><Trans t={t} i18nKey="ui:reset" /></Button>
</Grid>
</Grid>
<EfficiencyFilter selectedKeys={effFilter} onChange={n => stateDispatch({ effFilter: n })} />
</CardContent>
</CardDark>
<CardDark ><CardContent>
<Grid container alignItems="center" sx={{ pb: 2 }}>
<Grid item flexGrow={1}>
<Pagination count={numPages} page={currentPageIndex + 1} onChange={setPage} />
</Grid>
<Grid item flexGrow={1}>
<ShowingArt numShowing={artifactIdsToShow.length} total={totalShowing} t={t} />
</Grid>
<Grid item xs={12} sm={6} md={4} lg={4} xl={3} display="flex">
<Box flexGrow={1} />
<SortByButton sortKeys={[...artifactSortKeys.filter(key => (artifactSortKeysTC as unknown as string[]).includes(key) ? tcMode : true)]}
value={sortType} onChange={sortType => stateDispatch({ sortType })}
ascending={ascending} onChangeAsc={ascending => stateDispatch({ ascending })}
/>
</Grid>
</Grid>
<ArtifactRedButtons artifactIds={artifactIds} filterOption={filterOption} />
</CardContent></CardDark>
<Suspense fallback={<Skeleton variant="rectangular" sx={{ width: "100%", height: "100%", minHeight: 5000 }} />}>
<Grid container spacing={1} columns={columns} >
<Grid item xs={1} >
<NewArtifactCard />
</Grid>
{artifactIdsToShow.map(artId =>
<Grid item key={artId} xs={1} >
<ArtifactCard
artifactId={artId}
effFilter={effFilterSet}
onDelete={deleteArtifact}
probabilityFilter={showProbability ? probabilityFilter : undefined}
editor
canExclude
canEquip
/>
</Grid>
)}
</Grid>
</Suspense>
{numPages > 1 && <CardDark ><CardContent>
<Grid container>
<Grid item flexGrow={1}>
<Pagination count={numPages} page={currentPageIndex + 1} onChange={setPage} />
</Grid>
<Grid item>
<ShowingArt numShowing={artifactIdsToShow.length} total={totalShowing} t={t} />
</Grid>
</Grid>
</CardContent></CardDark>}
</Box >
}
Example #4
Source File: index.tsx From genshin-optimizer with MIT License | 4 votes |
export default function PageCharacter(props) {
// TODO: #412 We shouldn't be loading all the character translation files. Should have a separate lookup file for character name.
const { t } = useTranslation(["page_character", ...allCharacterKeys.map(k => `char_${k}_gen`)])
const { database } = useContext(DatabaseContext)
const [state, stateDispatch] = useDBState("CharacterDisplay", initialState)
const [searchTerm, setSearchTerm] = useState("")
const deferredSearchTerm = useDeferredValue(searchTerm)
const [pageIdex, setpageIdex] = useState(0)
const invScrollRef = useRef<HTMLDivElement>(null)
const setPage = useCallback(
(e, value) => {
invScrollRef.current?.scrollIntoView({ behavior: "smooth" })
setpageIdex(value - 1);
},
[setpageIdex, invScrollRef],
)
const brPt = useMediaQueryUp()
const maxNumToDisplay = numToShowMap[brPt]
const [newCharacter, setnewCharacter] = useState(false)
const [dbDirty, forceUpdate] = useForceUpdate()
//set follow, should run only once
useEffect(() => {
ReactGA.send({ hitType: "pageview", page: '/characters' })
return database.followAnyChar(forceUpdate)
}, [forceUpdate, database])
const characterSheets = usePromise(CharacterSheet.getAll, [])
const deleteCharacter = useCallback(async (cKey: CharacterKey) => {
const chararcterSheet = await CharacterSheet.get(cKey)
let name = chararcterSheet?.name
//use translated string
if (typeof name === "object")
name = i18next.t(`char_${cKey}_gen:name`)
if (!window.confirm(t("removeCharacter", { value: name }))) return
database.removeChar(cKey)
}, [database, t])
const editCharacter = useCharSelectionCallback()
const navigate = useNavigate()
const { element, weaponType } = state
const sortConfigs = useMemo(() => characterSheets && characterSortConfigs(database, characterSheets), [database, characterSheets])
const filterConfigs = useMemo(() => characterSheets && characterFilterConfigs(database, characterSheets), [database, characterSheets])
const { charKeyList, totalCharNum } = useMemo(() => {
const chars = database._getCharKeys()
const totalCharNum = chars.length
if (!sortConfigs || !filterConfigs) return { charKeyList: [], totalCharNum }
const charKeyList = database._getCharKeys()
.filter(filterFunction({ element, weaponType, favorite: "yes", name: deferredSearchTerm }, filterConfigs))
.sort(sortFunction(state.sortType, state.ascending, sortConfigs))
.concat(
database._getCharKeys()
.filter(filterFunction({ element, weaponType, favorite: "no", name: deferredSearchTerm }, filterConfigs))
.sort(sortFunction(state.sortType, state.ascending, sortConfigs)))
return dbDirty && { charKeyList, totalCharNum }
},
[dbDirty, database, sortConfigs, state.sortType, state.ascending, element, filterConfigs, weaponType, deferredSearchTerm])
const { charKeyListToShow, numPages, currentPageIndex } = useMemo(() => {
const numPages = Math.ceil(charKeyList.length / maxNumToDisplay)
const currentPageIndex = clamp(pageIdex, 0, numPages - 1)
return { charKeyListToShow: charKeyList.slice(currentPageIndex * maxNumToDisplay, (currentPageIndex + 1) * maxNumToDisplay), numPages, currentPageIndex }
}, [charKeyList, pageIdex, maxNumToDisplay])
const totalShowing = charKeyList.length !== totalCharNum ? `${charKeyList.length}/${totalCharNum}` : `${totalCharNum}`
return <Box my={1} display="flex" flexDirection="column" gap={1}>
<CardDark ref={invScrollRef} ><CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
<Grid container spacing={1}>
<Grid item>
<WeaponToggle sx={{ height: "100%" }} onChange={weaponType => stateDispatch({ weaponType })} value={state.weaponType} size="small" />
</Grid>
<Grid item>
<ElementToggle sx={{ height: "100%" }} onChange={element => stateDispatch({ element })} value={state.element} size="small" />
</Grid>
<Grid item flexGrow={1}>
<TextField
autoFocus
value={searchTerm}
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => setSearchTerm(e.target.value)}
label={t("characterName")}
/>
</Grid>
<Grid item >
<SortByButton sx={{ height: "100%" }}
sortKeys={characterSortKeys} value={state.sortType} onChange={sortType => stateDispatch({ sortType })}
ascending={state.ascending} onChangeAsc={ascending => stateDispatch({ ascending })} />
</Grid>
</Grid>
<Grid container alignItems="flex-end">
<Grid item flexGrow={1}>
<Pagination count={numPages} page={currentPageIndex + 1} onChange={setPage} />
</Grid>
<Grid item>
<ShowingCharacter numShowing={charKeyListToShow.length} total={totalShowing} t={t} />
</Grid>
</Grid>
</CardContent></CardDark>
<Suspense fallback={<Skeleton variant="rectangular" sx={{ width: "100%", height: "100%", minHeight: 5000 }} />}>
<Grid container spacing={1} columns={columns}>
<Grid item xs={1} >
<CardDark sx={{ height: "100%", minHeight: 400, width: "100%", display: "flex", flexDirection: "column" }}>
<CardContent>
<Typography sx={{ textAlign: "center" }}><Trans t={t} i18nKey="addNew" /></Typography>
</CardContent>
<CharacterSelectionModal newFirst show={newCharacter} onHide={() => setnewCharacter(false)} onSelect={editCharacter} />
<Box sx={{
flexGrow: 1,
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<Button onClick={() => setnewCharacter(true)} color="info" sx={{ borderRadius: "1em" }}>
<Typography variant="h1"><FontAwesomeIcon icon={faPlus} className="fa-fw" /></Typography>
</Button>
</Box>
</CardDark>
</Grid>
{charKeyListToShow.map(charKey =>
<Grid item key={charKey} xs={1} >
<CharacterCard
characterKey={charKey}
onClick={() => navigate(`${charKey}`)}
footer={<><Divider /><Box sx={{ py: 1, px: 2, display: "flex", gap: 1, justifyContent: "space-between" }}>
<BootstrapTooltip placement="top" title={<Typography>{t("tabs.talent")}</Typography>}>
<IconButton onClick={() => navigate(`${charKey}/talent`)}>
<FactCheck />
</IconButton>
</BootstrapTooltip>
<BootstrapTooltip placement="top" title={<Typography>{t("tabs.equip")}</Typography>}>
<IconButton onClick={() => navigate(`${charKey}/equip`)} >
<Checkroom />
</IconButton>
</BootstrapTooltip>
<BootstrapTooltip placement="top" title={<Typography>{t("tabs.teambuffs")}</Typography>}>
<IconButton onClick={() => navigate(`${charKey}/teambuffs`)} >
<Groups />
</IconButton>
</BootstrapTooltip>
<BootstrapTooltip placement="top" title={<Typography>{t("tabs.optimize")}</Typography>}>
<IconButton onClick={() => navigate(`${charKey}/optimize`)} >
<Calculate />
</IconButton>
</BootstrapTooltip>
<Divider orientation="vertical" />
<BootstrapTooltip placement="top" title={<Typography>{t("delete")}</Typography>}>
<IconButton color="error" onClick={() => deleteCharacter(charKey)}>
<DeleteForever />
</IconButton>
</BootstrapTooltip>
</Box></>}
/>
</Grid>)}
</Grid>
</Suspense>
{numPages > 1 && <CardDark ><CardContent>
<Grid container alignItems="flex-end">
<Grid item flexGrow={1}>
<Pagination count={numPages} page={currentPageIndex + 1} onChange={setPage} />
</Grid>
<Grid item>
<ShowingCharacter numShowing={charKeyListToShow.length} total={totalShowing} t={t} />
</Grid>
</Grid>
</CardContent></CardDark>}
</Box>
}
Example #5
Source File: index.tsx From genshin-optimizer with MIT License | 4 votes |
export default function PageWeapon() {
const { t } = useTranslation(["page_weapon", "ui"]);
const { database } = useContext(DatabaseContext)
const [state, stateDisplatch] = useDBState("WeaponDisplay", initialState)
const [newWeaponModalShow, setnewWeaponModalShow] = useState(false)
const [dbDirty, forceUpdate] = useForceUpdate()
const invScrollRef = useRef<HTMLDivElement>(null)
const [pageIdex, setpageIdex] = useState(0)
//set follow, should run only once
useEffect(() => {
ReactGA.send({ hitType: "pageview", page: '/weapon' })
return database.followAnyWeapon(forceUpdate)
}, [forceUpdate, database])
const brPt = useMediaQueryUp()
const maxNumToDisplay = numToShowMap[brPt]
const weaponSheets = usePromise(WeaponSheet.getAll, [])
const deleteWeapon = useCallback(async (key) => {
const weapon = database._getWeapon(key)
if (!weapon) return
const name = i18next.t(`weapon_${weapon.key}_gen:name`)
if (!window.confirm(`Are you sure you want to remove ${name}?`)) return
database.removeWeapon(key)
if (state.editWeaponId === key)
stateDisplatch({ editWeaponId: "" })
}, [state.editWeaponId, stateDisplatch, database])
const editWeapon = useCallback(key => {
stateDisplatch({ editWeaponId: key })
}, [stateDisplatch])
const newWeapon = useCallback(
(weaponKey: WeaponKey) => {
editWeapon(database.createWeapon(initialWeapon(weaponKey)))
},
[database, editWeapon])
const { sortType, ascending, weaponType, rarity } = state
const sortConfigs = useMemo(() => weaponSheets && weaponSortConfigs(weaponSheets), [weaponSheets])
const filterConfigs = useMemo(() => weaponSheets && weaponFilterConfigs(weaponSheets), [weaponSheets])
const { weaponIdList, totalWeaponNum } = useMemo(() => {
const weapons = database._getWeapons()
const totalWeaponNum = weapons.length
if (!sortConfigs || !filterConfigs) return { weaponIdList: [], totalWeaponNum }
const weaponIdList = weapons.filter(filterFunction({ weaponType, rarity }, filterConfigs))
.sort(sortFunction(sortType, ascending, sortConfigs)).map(weapon => weapon.id);
return dbDirty && { weaponIdList, totalWeaponNum }
}, [dbDirty, database, sortConfigs, filterConfigs, sortType, ascending, rarity, weaponType])
const { weaponIdsToShow, numPages, currentPageIndex } = useMemo(() => {
const numPages = Math.ceil(weaponIdList.length / maxNumToDisplay)
const currentPageIndex = clamp(pageIdex, 0, numPages - 1)
return { weaponIdsToShow: weaponIdList.slice(currentPageIndex * maxNumToDisplay, (currentPageIndex + 1) * maxNumToDisplay), numPages, currentPageIndex }
}, [weaponIdList, pageIdex, maxNumToDisplay])
//for pagination
const totalShowing = weaponIdList.length !== totalWeaponNum ? `${weaponIdList.length}/${totalWeaponNum}` : `${totalWeaponNum}`
const setPage = useCallback(
(e, value) => {
invScrollRef.current?.scrollIntoView({ behavior: "smooth" })
setpageIdex(value - 1);
},
[setpageIdex, invScrollRef],
)
const resetEditWeapon = useCallback(() => stateDisplatch({ editWeaponId: "" }), [stateDisplatch])
const { editWeaponId } = state
// Validate weaponId to be an actual weapon
useEffect(() => {
if (!editWeaponId) return
if (!database._getWeapon(editWeaponId))
resetEditWeapon()
}, [database, editWeaponId, resetEditWeapon])
return <Box my={1} display="flex" flexDirection="column" gap={1}>
{/* editor/character detail display */}
<Suspense fallback={false}>
<WeaponEditor
weaponId={editWeaponId}
footer
onClose={resetEditWeapon}
/>
</Suspense>
<CardDark ref={invScrollRef} sx={{ p: 2, pb: 1 }}>
<Grid container spacing={1} sx={{ mb: 1 }}>
<Grid item>
<WeaponToggle sx={{ height: "100%" }} onChange={weaponType => stateDisplatch({ weaponType })} value={weaponType} size="small" />
</Grid>
<Grid item flexGrow={1}>
<SolidToggleButtonGroup sx={{ height: "100%" }} onChange={(e, newVal) => stateDisplatch({ rarity: newVal })} value={rarity} size="small">
{allRarities.map(star => <ToggleButton key={star} value={star}><Box display="flex" gap={1}><strong>{star}</strong><Stars stars={1} /></Box></ToggleButton>)}
</SolidToggleButtonGroup>
</Grid>
<Grid item >
<SortByButton sx={{ height: "100%" }} sortKeys={weaponSortKeys}
value={sortType} onChange={sortType => stateDisplatch({ sortType })}
ascending={ascending} onChangeAsc={ascending => stateDisplatch({ ascending })}
/>
</Grid>
</Grid>
<Grid container alignItems="flex-end">
<Grid item flexGrow={1}>
<Pagination count={numPages} page={currentPageIndex + 1} onChange={setPage} />
</Grid>
<Grid item>
<ShowingWeapon numShowing={weaponIdsToShow.length} total={totalShowing} t={t} />
</Grid>
</Grid>
</CardDark>
<Suspense fallback={<Skeleton variant="rectangular" sx={{ width: "100%", height: "100%", minHeight: 500 }} />}>
<Grid container spacing={1} columns={columns}>
<Grid item xs={1}>
<CardDark sx={{ height: "100%", width: "100%", minHeight: 300, display: "flex", flexDirection: "column" }}>
<CardContent>
<Typography sx={{ textAlign: "center" }}>Add New Weapon</Typography>
</CardContent>
<WeaponSelectionModal show={newWeaponModalShow} onHide={() => setnewWeaponModalShow(false)} onSelect={newWeapon} />
<Box sx={{
flexGrow: 1,
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<Button onClick={() => setnewWeaponModalShow(true)} color="info" sx={{ borderRadius: "1em" }}>
<Typography variant="h1"><FontAwesomeIcon icon={faPlus} className="fa-fw" /></Typography>
</Button>
</Box>
</CardDark>
</Grid>
{weaponIdsToShow.map(weaponId =>
<Grid item key={weaponId} xs={1} >
<WeaponCard
weaponId={weaponId}
onDelete={deleteWeapon}
onEdit={editWeapon}
canEquip
/>
</Grid>)}
</Grid>
</Suspense>
{numPages > 1 && <CardDark><CardContent>
<Grid container alignItems="flex-end">
<Grid item flexGrow={1}>
<Pagination count={numPages} page={currentPageIndex + 1} onChange={setPage} />
</Grid>
<Grid item>
<ShowingWeapon numShowing={weaponIdsToShow.length} total={totalShowing} t={t} />
</Grid>
</Grid>
</CardContent></CardDark>}
</Box>
}