@mui/icons-material#Lock TypeScript Examples
The following examples show how to use
@mui/icons-material#Lock.
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: ArtifactFilterDisplay.tsx From genshin-optimizer with MIT License | 5 votes |
export default function ArtifactFilterDisplay({ filterOption, filterOptionDispatch, }: { filterOption: FilterOption, filterOptionDispatch: (any) => void }) {
const { t } = useTranslation(["artifact", "ui"]);
const { artSetKeys = [], mainStatKeys = [], rarity = [], slotKeys = [], levelLow, levelHigh, substats = [],
location = "", exclusion = ["excluded", "included"], locked = ["locked", "unlocked"] } = filterOption
return <Grid container spacing={1}>
{/* left */}
<Grid item xs={12} md={6} display="flex" flexDirection="column" gap={1}>
{/* Artifact stars filter */}
<SolidToggleButtonGroup fullWidth onChange={(e, newVal) => filterOptionDispatch({ rarity: newVal })} value={rarity} size="small">
{allArtifactRarities.map(star => <ToggleButton key={star} value={star}><Stars stars={star} /></ToggleButton>)}
</SolidToggleButtonGroup>
{/* Artifact Slot */}
<SolidToggleButtonGroup fullWidth onChange={(e, newVal) => filterOptionDispatch({ slotKeys: newVal })} value={slotKeys} size="small">
{allSlotKeys.map(slotKey => <ToggleButton key={slotKey} value={slotKey}>{artifactSlotIcon(slotKey)}</ToggleButton>)}
</SolidToggleButtonGroup>
{/* exclusion + locked */}
<Box display="flex" gap={1}>
<SolidToggleButtonGroup fullWidth value={exclusion} onChange={(e, newVal) => filterOptionDispatch({ exclusion: newVal })} size="small">
<ToggleButton value="excluded" sx={{ display: "flex", gap: 1 }}>
<FontAwesomeIcon icon={faBan} /><Trans i18nKey={"exclusion.excluded"} t={t} />
</ToggleButton>
<ToggleButton value="included" sx={{ display: "flex", gap: 1 }}>
<FontAwesomeIcon icon={faChartLine} /><Trans i18nKey={"exclusion.included"} t={t} />
</ToggleButton>
</SolidToggleButtonGroup>
<SolidToggleButtonGroup fullWidth value={locked} onChange={(e, newVal) => filterOptionDispatch({ locked: newVal })} size="small">
<ToggleButton value="locked" sx={{ display: "flex", gap: 1 }}>
<Lock /><Trans i18nKey={"ui:locked"} t={t} />
</ToggleButton>
<ToggleButton value="unlocked" sx={{ display: "flex", gap: 1 }}>
<LockOpen /><Trans i18nKey={"ui:unlocked"} t={t} />
</ToggleButton>
</SolidToggleButtonGroup>
</Box>
{/* Artiface level filter */}
<ArtifactLevelSlider showLevelText levelLow={levelLow} levelHigh={levelHigh}
setLow={levelLow => filterOptionDispatch({ levelLow })}
setHigh={levelHigh => filterOptionDispatch({ levelHigh })}
setBoth={(levelLow, levelHigh) => filterOptionDispatch({ levelLow, levelHigh })} />
<Grid container display="flex" gap={1}>
<Grid item flexGrow={1}>
{/* location */}
<CharacterAutocomplete
value={location}
onChange={location => filterOptionDispatch({ location })}
placeholderText={t("artifact:filterLocation.any")}
defaultText={t("artifact:filterLocation.any")}
labelText={t("artifact:filterLocation.location")}
showDefault
showInventory
showEquipped
/>
</Grid>
</Grid>
</Grid>
{/* right */}
<Grid item xs={12} md={6} display="flex" flexDirection="column" gap={1}>
{/* Artifact Set */}
<ArtifactSetMultiAutocomplete artSetKeys={artSetKeys} setArtSetKeys={artSetKeys => filterOptionDispatch({ artSetKeys })} />
<ArtifactMainStatMultiAutocomplete mainStatKeys={mainStatKeys} setMainStatKeys={mainStatKeys => filterOptionDispatch({ mainStatKeys })} />
<ArtifactSubstatMultiAutocomplete substatKeys={substats} setSubstatKeys={substats => filterOptionDispatch({ substats })} />
</Grid>
</Grid>
}
Example #2
Source File: ArtifactCard.tsx From genshin-optimizer with MIT License | 4 votes |
export default function ArtifactCard({ artifactId, artifactObj, onClick, onDelete, mainStatAssumptionLevel = 0, effFilter = allSubstatFilter, probabilityFilter, disableEditSetSlot = false, editor = false, canExclude = false, canEquip = false, extraButtons }: Data): JSX.Element | null { const { t } = useTranslation(["artifact", "ui"]); const { database } = useContext(DatabaseContext) const databaseArtifact = useArtifact(artifactId) const sheet = usePromise(ArtifactSheet.get((artifactObj ?? databaseArtifact)?.setKey), [artifactObj, databaseArtifact]) const equipOnChar = (charKey: CharacterKey | "") => database.setArtLocation(artifactId!, charKey) const editable = !artifactObj const [showEditor, setshowEditor] = useState(false) const onHideEditor = useCallback(() => setshowEditor(false), [setshowEditor]) const onShowEditor = useCallback(() => editable && setshowEditor(true), [editable, setshowEditor]) const wrapperFunc = useCallback(children => <CardActionArea onClick={() => artifactId && onClick?.(artifactId)} sx={{ flexGrow: 1, display: "flex", flexDirection: "column" }} >{children}</CardActionArea>, [onClick, artifactId],) const falseWrapperFunc = useCallback(children => <Box sx={{ flexGrow: 1, display: "flex", flexDirection: "column" }} >{children}</Box>, []) const art = artifactObj ?? databaseArtifact if (!art) return null const { id, lock, slotKey, rarity, level, mainStatKey, substats, exclude, location = "" } = art const mainStatLevel = Math.max(Math.min(mainStatAssumptionLevel, rarity * 4), level) const mainStatUnit = KeyMap.unit(mainStatKey) const levelVariant = "roll" + (Math.floor(Math.max(level, 0) / 4) + 1) const { currentEfficiency, maxEfficiency } = Artifact.getArtifactEfficiency(art, effFilter) const artifactValid = maxEfficiency !== 0 const slotName = sheet?.getSlotName(slotKey) || "Unknown Piece Name" const slotDesc = sheet?.getSlotDesc(slotKey) const slotDescTooltip = slotDesc && <InfoTooltip title={<Box> <Typography variant='h6'>{slotName}</Typography> <Typography>{slotDesc}</Typography> </Box>} /> const setEffects = sheet?.setEffects const setDescTooltip = sheet && setEffects && <InfoTooltip title={ <span> {Object.keys(setEffects).map(setNumKey => <span key={setNumKey}> <Typography variant="h6"><SqBadge color="success">{t(`artifact:setEffectNum`, { setNum: setNumKey })}</SqBadge></Typography> <Typography>{sheet.setEffectDesc(setNumKey as any)}</Typography> </span>)} </span> } /> return <Suspense fallback={<Skeleton variant="rectangular" sx={{ width: "100%", height: "100%", minHeight: 350 }} />}> {editor && <Suspense fallback={false}> <ArtifactEditor artifactIdToEdit={showEditor ? artifactId : ""} cancelEdit={onHideEditor} disableEditSetSlot={disableEditSetSlot} /> </Suspense>} <CardLight sx={{ height: "100%", display: "flex", flexDirection: "column" }}> <ConditionalWrapper condition={!!onClick} wrapper={wrapperFunc} falseWrapper={falseWrapperFunc}> <Box className={`grad-${rarity}star`} sx={{ position: "relative", width: "100%" }}> {!onClick && <IconButton color="primary" disabled={!editable} onClick={() => database.updateArt({ lock: !lock }, id)} sx={{ position: "absolute", right: 0, bottom: 0, zIndex: 2 }}> {lock ? <Lock /> : <LockOpen />} </IconButton>} <Box sx={{ pt: 2, px: 2, position: "relative", zIndex: 1 }}> {/* header */} <Box component="div" sx={{ display: "flex", alignItems: "center", gap: 1, mb: 1 }}> <Chip size="small" label={<strong>{` +${level}`}</strong>} color={levelVariant as any} /> <Typography component="span" noWrap sx={{ backgroundColor: "rgba(100,100,100,0.35)", borderRadius: "1em", px: 1 }}><strong>{slotName}</strong></Typography> <Box flexGrow={1} sx={{ textAlign: "right" }}> {slotDescTooltip} </Box> </Box> <Typography color="text.secondary" variant="body2"> <SlotNameWithIcon slotKey={slotKey} /> </Typography> <Typography variant="h6" color={`${KeyMap.getVariant(mainStatKey)}.main`}> <span>{StatIcon[mainStatKey]} {KeyMap.get(mainStatKey)}</span> </Typography> <Typography variant="h5"> <strong> <ColorText color={mainStatLevel !== level ? "warning" : undefined}>{cacheValueString(Artifact.mainStatValue(mainStatKey, rarity, mainStatLevel) ?? 0, KeyMap.unit(mainStatKey))}{mainStatUnit}</ColorText> </strong> </Typography> <Stars stars={rarity} colored /> {/* {process.env.NODE_ENV === "development" && <Typography color="common.black">{id || `""`} </Typography>} */} </Box> <Box sx={{ height: "100%", position: "absolute", right: 0, top: 0 }}> <Box component="img" src={sheet?.slotIcons[slotKey] ?? ""} width="auto" height="100%" sx={{ float: "right" }} /> </Box> </Box> <CardContent sx={{ flexGrow: 1, display: "flex", flexDirection: "column", pt: 1, pb: 0, width: "100%" }}> {substats.map((stat: ICachedSubstat) => <SubstatDisplay key={stat.key} stat={stat} effFilter={effFilter} rarity={rarity} />)} <Box sx={{ display: "flex", my: 1 }}> <Typography color="text.secondary" component="span" variant="caption" sx={{ flexGrow: 1 }}>{t`artifact:editor.curSubEff`}</Typography> <PercentBadge value={currentEfficiency} max={900} valid={artifactValid} /> </Box> {currentEfficiency !== maxEfficiency && <Box sx={{ display: "flex", mb: 1 }}> <Typography color="text.secondary" component="span" variant="caption" sx={{ flexGrow: 1 }}>{t`artifact:editor.maxSubEff`}</Typography> <PercentBadge value={maxEfficiency} max={900} valid={artifactValid} /> </Box>} <Box flexGrow={1} /> {probabilityFilter && <strong>Probability: {(probability(art, probabilityFilter) * 100).toFixed(2)}%</strong>} <Typography color="success.main">{sheet?.name ?? "Artifact Set"} {setDescTooltip}</Typography> </CardContent> </ConditionalWrapper> <Box sx={{ p: 1, display: "flex", gap: 1, justifyContent: "space-between", alignItems: "center" }}> {editable && canEquip ? <CharacterAutocomplete sx={{ flexGrow: 1 }} size="small" showDefault defaultIcon={<BusinessCenter />} defaultText={t("ui:inventory")} value={location} onChange={equipOnChar} /> : <LocationName location={location} />} {editable && <ButtonGroup sx={{ height: "100%" }}> {editor && <Tooltip title={<Typography>{t`artifact:edit`}</Typography>} placement="top" arrow> <Button color="info" size="small" onClick={onShowEditor} > <FontAwesomeIcon icon={faEdit} className="fa-fw" /> </Button> </Tooltip>} {canExclude && <Tooltip title={<Typography>{t`artifact:excludeArtifactTip`}</Typography>} placement="top" arrow> <Button onClick={() => database.updateArt({ exclude: !exclude }, id)} color={exclude ? "error" : "success"} size="small" > <FontAwesomeIcon icon={exclude ? faBan : faChartLine} className="fa-fw" /> </Button> </Tooltip>} {!!onDelete && <Button color="error" size="small" onClick={() => onDelete(id)} disabled={lock}> <FontAwesomeIcon icon={faTrashAlt} className="fa-fw" /> </Button>} {extraButtons} </ButtonGroup>} </Box> </CardLight > </Suspense> }
Example #3
Source File: ArtifactFilter.tsx From genshin-optimizer with MIT License | 4 votes |
export function ArtifactRedButtons({ artifactIds, filterOption }:
{ artifactIds: string[], filterOption: FilterOption }) {
const { t } = useTranslation(["artifact", "ui"]);
const { database } = useContext(DatabaseContext)
const { numDelete, numUnequip, numExclude, numInclude, numUnlock, numLock } = useMemo(() => {
const artifacts = artifactIds.map(id => database._getArt(id)) as ICachedArtifact[]
const numUnlock = artifacts.reduce((a, art) => a + (art.lock ? 0 : 1), 0)
const numLock = artifacts.length - numUnlock
const numDelete = numUnlock
const numUnequip = artifacts.reduce((a, art) => a + (art.location ? 1 : 0), 0)
const numExclude = artifacts.reduce((a, art) => a + (art.exclude ? 1 : 0), 0)
const numInclude = artifacts.length - numExclude
return { numDelete, numUnequip, numExclude, numInclude, numUnlock, numLock }
}, [artifactIds, database])
const unequipArtifacts = () =>
window.confirm(`Are you sure you want to unequip ${numUnequip} artifacts currently equipped on characters?`) &&
artifactIds.map(id => database.setArtLocation(id, ""))
const deleteArtifacts = () =>
window.confirm(`Are you sure you want to delete ${numDelete} artifacts?`) &&
artifactIds.map(id => !database._getArt(id)?.lock && database.removeArt(id))
const excludeArtifacts = () =>
window.confirm(`Are you sure you want to exclude ${numInclude} artifacts from build generations?`) &&
artifactIds.map(id => database.updateArt({ exclude: true }, id))
const includeArtifacts = () =>
window.confirm(`Are you sure you want to include ${numExclude} artifacts in build generations?`) &&
artifactIds.map(id => database.updateArt({ exclude: false }, id))
const lockArtifacts = () =>
window.confirm(`Are you sure you want to lock ${numUnlock} artifacts?`) &&
artifactIds.map(id => database.updateArt({ lock: true }, id))
const unlockArtifacts = () =>
window.confirm(`Are you sure you want to unlock ${numLock} artifacts?`) &&
artifactIds.map(id => database.updateArt({ lock: false }, id))
return <Grid container spacing={1} alignItems="center">
<Grid item xs={12} sm={6} md={3}>
<Button fullWidth color="error" disabled={!numUnequip} onClick={unequipArtifacts} startIcon={<FontAwesomeIcon icon={faUserSlash} />}>
<Trans t={t} i18nKey="button.unequipArtifacts" >Unequip Artifacts</Trans>
<SqBadge sx={{ ml: 1 }} color={numUnequip ? "success" : "secondary"}>{numUnequip}</SqBadge>
</Button>
</Grid>
<Grid item xs={12} sm={6} md={3}>
<Button fullWidth color="error" disabled={!numDelete} onClick={deleteArtifacts} startIcon={<FontAwesomeIcon icon={faTrash} />}>
<Trans t={t} i18nKey="button.deleteArtifacts" >Delete Artifacts</Trans>
<SqBadge sx={{ ml: 1 }} color={numDelete ? "success" : "secondary"}>{numDelete}</SqBadge>
</Button>
</Grid>
<Grid item xs={12} sm={6} md={3}>
<Button fullWidth color="error" disabled={!numInclude} onClick={excludeArtifacts} startIcon={<FontAwesomeIcon icon={faBan} />}>
<Trans t={t} i18nKey="button.excludeArtifacts" >Exclude Artifacts</Trans>
<SqBadge sx={{ ml: 1 }} color={numInclude ? "success" : "secondary"}>{numInclude}</SqBadge>
</Button>
</Grid>
<Grid item xs={12} sm={6} md={3}>
<Button fullWidth color="error" disabled={!numExclude} onClick={includeArtifacts} startIcon={<FontAwesomeIcon icon={faChartLine} />}>
<Trans t={t} i18nKey="button.includeArtifacts" >Include Artifacts</Trans>
<SqBadge sx={{ ml: 1 }} color={numExclude ? "success" : "secondary"}>{numExclude}</SqBadge>
</Button>
</Grid>
<Grid item xs={12} sm={6} md={3}>
<Button fullWidth color="error" disabled={!numLock} onClick={unlockArtifacts} startIcon={<LockOpen />}>
<Trans t={t} i18nKey="button.unlockrtifacts" >Unlock Artifacts</Trans>
<SqBadge sx={{ ml: 1 }} color={numLock ? "success" : "secondary"}>{numLock}</SqBadge>
</Button>
</Grid>
<Grid item xs={12} sm={6} md={3}>
<Button fullWidth color="error" disabled={!numUnlock} onClick={lockArtifacts} startIcon={<Lock />}>
<Trans t={t} i18nKey="button.lockArtifacts" >Lock Artifacts</Trans>
<SqBadge sx={{ ml: 1 }} color={numUnlock ? "success" : "secondary"}>{numUnlock}</SqBadge>
</Button>
</Grid>
<Grid item xs={12} sm={12} md={6} display="flex" justifyContent="space-around">
<Typography variant="caption" color="text.secondary"><Trans t={t} i18nKey="buttonHint">Note: the red buttons above only applies to <b>currently filtered artifacts</b></Trans></Typography>
</Grid>
</Grid>
}
Example #4
Source File: WeaponCard.tsx From genshin-optimizer with MIT License | 4 votes |
export default function WeaponCard({ weaponId, onClick, onEdit, onDelete, canEquip = false, extraButtons }: WeaponCardProps) { const { t } = useTranslation(["page_weapon", "ui"]); const { database } = useContext(DatabaseContext) const databaseWeapon = useWeapon(weaponId) const weapon = databaseWeapon const weaponSheet = usePromise(weapon?.key ? WeaponSheet.get(weapon.key) : undefined, [weapon?.key]) const filter = useCallback( (cs: CharacterSheet) => cs.weaponTypeKey === weaponSheet?.weaponType, [weaponSheet], ) const wrapperFunc = useCallback(children => <CardActionArea onClick={() => onClick?.(weaponId)} >{children}</CardActionArea>, [onClick, weaponId],) const falseWrapperFunc = useCallback(children => <Box >{children}</Box>, []) const equipOnChar = useCallback((charKey: CharacterKey | "") => database.setWeaponLocation(weaponId, charKey), [database, weaponId],) const UIData = useMemo(() => weaponSheet && weapon && computeUIData([weaponSheet.data, dataObjForWeapon(weapon)]), [weaponSheet, weapon]) if (!weapon || !weaponSheet || !UIData) return null; const { level, ascension, refinement, id, location = "", lock } = weapon const weaponTypeKey = UIData.get(input.weapon.type).value! const stats = [input.weapon.main, input.weapon.sub, input.weapon.sub2].map(x => UIData.get(x)) const img = ascension < 2 ? weaponSheet?.img : weaponSheet?.imgAwaken return <Suspense fallback={<Skeleton variant="rectangular" sx={{ width: "100%", height: "100%", minHeight: 300 }} />}> <CardLight sx={{ height: "100%", display: "flex", flexDirection: "column", justifyContent: "space-between" }}> <ConditionalWrapper condition={!!onClick} wrapper={wrapperFunc} falseWrapper={falseWrapperFunc}> <Box className={`grad-${weaponSheet.rarity}star`} sx={{ position: "relative", pt: 2, px: 2, }}> {!onClick && <IconButton color="primary" onClick={() => database.updateWeapon({ lock: !lock }, id)} sx={{ position: "absolute", right: 0, bottom: 0, zIndex: 2 }}> {lock ? <Lock /> : <LockOpen />} </IconButton>} <Box sx={{ position: "relative", zIndex: 1 }}> <Box component="div" sx={{ display: "flex", alignItems: "center", gap: 1, mb: 1 }}> <ImgIcon sx={{ fontSize: "1.5em" }} src={Assets.weaponTypes?.[weaponTypeKey]} /> <Typography noWrap sx={{ textAlign: "center", backgroundColor: "rgba(100,100,100,0.35)", borderRadius: "1em", px: 1 }}><strong>{weaponSheet.name}</strong></Typography> </Box> <Typography component="span" variant="h5">Lv. {level}</Typography> <Typography component="span" variant="h5" color="text.secondary">/{ascensionMaxLevel[ascension]}</Typography> <Typography variant="h6">Refinement <strong>{refinement}</strong></Typography> <Typography><Stars stars={weaponSheet.rarity} colored /></Typography> </Box> <Box sx={{ height: "100%", position: "absolute", right: 0, top: 0 }}> <Box component="img" src={img ?? ""} width="auto" height="100%" sx={{ float: "right" }} /> </Box> </Box> <CardContent> {stats.map(node => { if (!node.info.key) return null const displayVal = valueString(node.value, node.unit, !node.unit ? 0 : undefined) return <Box key={node.info.key} sx={{ display: "flex" }}> <Typography flexGrow={1}>{StatIcon[node.info.key!]} {KeyMap.get(node.info.key)}</Typography> <Typography>{displayVal}</Typography> </Box> })} </CardContent> </ConditionalWrapper> <Box sx={{ p: 1, display: "flex", gap: 1, justifyContent: "space-between", alignItems: "center" }}> {canEquip ? <CharacterAutocomplete size="small" sx={{ flexGrow: 1 }} showDefault defaultIcon={<BusinessCenter />} defaultText={t("inventory")} value={location} onChange={equipOnChar} filter={filter} /> : <LocationName location={location} />} <ButtonGroup> {!!onEdit && <Tooltip title={<Typography>{t`page_weapon:edit`}</Typography>} placement="top" arrow> <Button color="info" onClick={() => onEdit(id)} > <FontAwesomeIcon icon={faEdit} className="fa-fw" /> </Button> </Tooltip>} {!!onDelete && <Button color="error" onClick={() => onDelete(id)} disabled={!!location || lock} > <FontAwesomeIcon icon={faTrashAlt} className="fa-fw" /> </Button>} {extraButtons} </ButtonGroup> </Box> </CardLight> </Suspense> }
Example #5
Source File: WeaponEditor.tsx From genshin-optimizer with MIT License | 4 votes |
export default function WeaponEditor({
weaponId: propWeaponId,
footer = false,
onClose,
extraButtons
}: WeaponStatsEditorCardProps) {
const { t } = useTranslation("ui")
const { data } = useContext(DataContext)
const { database } = useContext(DatabaseContext)
const weapon = useWeapon(propWeaponId)
const { key = "", level = 0, refinement = 0, ascension = 0, lock, location = "", id } = weapon ?? {}
const weaponSheet = usePromise(WeaponSheet.get(key), [key])
const weaponDispatch = useCallback((newWeapon: Partial<ICachedWeapon>) => {
database.updateWeapon(newWeapon, propWeaponId)
}, [propWeaponId, database])
const setLevel = useCallback(level => {
level = clamp(level, 1, 90)
const ascension = ascensionMaxLevel.findIndex(ascenML => level <= ascenML)
weaponDispatch({ level, ascension })
}, [weaponDispatch])
const setAscension = useCallback(() => {
const lowerAscension = ascensionMaxLevel.findIndex(ascenML => level !== 90 && level === ascenML)
if (ascension === lowerAscension) weaponDispatch({ ascension: ascension + 1 })
else weaponDispatch({ ascension: lowerAscension })
}, [weaponDispatch, ascension, level])
const characterSheet = usePromise(location ? CharacterSheet.get(location) : undefined, [location])
const weaponFilter = characterSheet ? (ws) => ws.weaponType === characterSheet.weaponTypeKey : undefined
const initialWeaponFilter = characterSheet && characterSheet.weaponTypeKey
const equipOnChar = useCallback((charKey: CharacterKey | "") => id && database.setWeaponLocation(id, charKey), [database, id])
const filter = useCallback(
(cs: CharacterSheet) => cs.weaponTypeKey === weaponSheet?.weaponType,
[weaponSheet],
)
const [showModal, setshowModal] = useState(false)
const img = ascension < 2 ? weaponSheet?.img : weaponSheet?.imgAwaken
//check the levels when switching from a 5* to a 1*, for example.
useEffect(() => {
if (!weaponSheet || !weaponDispatch || weaponSheet.key !== weapon?.key) return
if (weaponSheet.rarity <= 2 && (level > 70 || ascension > 4)) {
const [level, ascension] = lowRarityMilestoneLevels[0]
weaponDispatch({ level, ascension })
}
}, [weaponSheet, weapon, weaponDispatch, level, ascension])
const weaponUIData = useMemo(() => weaponSheet && weapon && computeUIData([weaponSheet.data, dataObjForWeapon(weapon)]), [weaponSheet, weapon])
return <ModalWrapper open={!!propWeaponId} onClose={onClose} containerProps={{ maxWidth: "md" }}><CardLight>
<WeaponSelectionModal show={showModal} onHide={() => setshowModal(false)} onSelect={k => weaponDispatch({ key: k })} filter={weaponFilter} weaponFilter={initialWeaponFilter} />
<CardContent >
{weaponSheet && weaponUIData && <Grid container spacing={1.5}>
<Grid item xs={12} sm={3}>
<Grid container spacing={1.5}>
<Grid item xs={6} sm={12}>
<Box component="img" src={img} className={`grad-${weaponSheet.rarity}star`} sx={{ maxWidth: 256, width: "100%", height: "auto", borderRadius: 1 }} />
</Grid>
<Grid item xs={6} sm={12}>
<Typography><small>{weaponSheet.description}</small></Typography>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} sm={9} sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
<Box display="flex" gap={1} flexWrap="wrap" justifyContent="space-between">
<ButtonGroup>
<Button onClick={() => setshowModal(true)} >{weaponSheet?.name ?? "Select a Weapon"}</Button>
{weaponSheet?.hasRefinement && <DropdownButton title={`Refinement ${refinement}`}>
<MenuItem>Select Weapon Refinement</MenuItem>
<Divider />
{[...Array(5).keys()].map(key =>
<MenuItem key={key} onClick={() => weaponDispatch({ refinement: key + 1 })} selected={refinement === (key + 1)} disabled={refinement === (key + 1)}>
{`Refinement ${key + 1}`}
</MenuItem>)}
</DropdownButton>}
{extraButtons}
</ButtonGroup>
</Box>
<Box display="flex" gap={1} flexWrap="wrap" justifyContent="space-between">
<ButtonGroup sx={{ bgcolor: t => t.palette.contentLight.main }} >
<CustomNumberInputButtonGroupWrapper >
<CustomNumberInput onChange={setLevel} value={level}
startAdornment="Lv. "
inputProps={{ min: 1, max: 90, sx: { textAlign: "center" } }}
sx={{ width: "100%", height: "100%", pl: 2 }}
/>
</CustomNumberInputButtonGroupWrapper>
{weaponSheet && <Button sx={{ pl: 1 }} disabled={!weaponSheet.ambiguousLevel(level)} onClick={setAscension}><strong>/ {ascensionMaxLevel[ascension]}</strong></Button>}
{weaponSheet && <DropdownButton title={"Select Level"} >
{weaponSheet.milestoneLevels.map(([lv, as]) => {
const sameLevel = lv === ascensionMaxLevel[as]
const lvlstr = sameLevel ? `Lv. ${lv}` : `Lv. ${lv}/${ascensionMaxLevel[as]}`
const selected = lv === level && as === ascension
return <MenuItem key={`${lv}/${as}`} selected={selected} disabled={selected} onClick={() => weaponDispatch({ level: lv, ascension: as })}>{lvlstr}</MenuItem>
})}
</DropdownButton>}
</ButtonGroup>
<Button color="error" onClick={() => id && database.updateWeapon({ lock: !lock }, id)} startIcon={lock ? <Lock /> : <LockOpen />}>
{lock ? "Locked" : "Unlocked"}
</Button>
</Box>
<Typography><Stars stars={weaponSheet.rarity} /></Typography>
<Typography variant="subtitle1"><strong>{weaponSheet.passiveName}</strong></Typography>
<Typography gutterBottom>{weaponSheet.passiveName && weaponSheet.passiveDescription(weaponUIData.get(input.weapon.refineIndex).value)}</Typography>
<Box display="flex" flexDirection="column" gap={1}>
<CardDark >
<CardHeader title={"Main Stats"} titleTypographyProps={{ variant: "subtitle2" }} />
<Divider />
<FieldDisplayList>
{[input.weapon.main, input.weapon.sub, input.weapon.sub2].map((node, i) => {
const n = weaponUIData.get(node)
if (n.isEmpty || !n.value) return null
return <NodeFieldDisplay key={n.info.key} node={n} component={ListItem} />
})}
</FieldDisplayList>
</CardDark>
{data && weaponSheet.document && <DocumentDisplay sections={weaponSheet.document} />}
</Box>
</Grid>
</Grid>}
</CardContent>
{footer && id && <CardContent sx={{ py: 1 }}>
<Grid container spacing={1}>
<Grid item flexGrow={1}>
<CharacterAutocomplete showDefault defaultIcon={<BusinessCenter />} defaultText={t("inventory")} value={location} onChange={equipOnChar} filter={filter} />
</Grid>
{!!onClose && <Grid item><CloseButton sx={{ height: "100%" }} large onClick={onClose} /></Grid>}
</Grid>
</CardContent>}
</CardLight ></ModalWrapper>
}
Example #6
Source File: Plugins.tsx From NekoMaid with MIT License | 4 votes |
Plugins: React.FC = () => {
const plugin = usePlugin()
const theme = useTheme()
const { canLoadPlugin } = useGlobalData()
const [plugins, setPlugins] = useState<Plugin[]>([])
useEffect(() => {
const offList = plugin.on('plugins:list', (plugins: Plugin[]) => {
const arr: Plugin[] = []
setPlugins(plugins.filter(it => {
const res = canPluginBeDisabled(it.name)
if (res) arr.push(it)
return !res
}).concat(arr))
})
plugin.emit('plugins:fetch')
return () => {
offList()
}
}, [])
const map: Record<string, number> = { }
let id = 0
const data = plugins.map(it => {
map[it.name] = id
return { id: id++, name: it.name, category: 1 - (it.enabled as any) }
})
const links: Array<{ source: number, target: number }> = []
plugins.forEach(it => {
const source = map[it.name]
it.depends.forEach(dep => {
if (!(dep in map)) {
map[dep] = id
data.push({ id: id++, name: dep, category: 3 })
}
links.push({ source, target: map[dep] })
})
it.softDepends.forEach(dep => {
if (!(dep in map)) {
map[dep] = id
data.push({ id: id++, name: dep, category: 2 })
}
links.push({ source, target: map[dep] })
})
})
return <Box sx={{ minHeight: '100%', py: 3 }}>
<Toolbar />
<Container maxWidth={false}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Card>
<CardHeader title={lang.plugins.title} />
<Divider />
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell sx={{ paddingRight: 0 }}>{lang.plugins.enable}</TableCell>
<TableCell>{lang.plugins.name}</TableCell>
<TableCell>{lang.plugins.version}</TableCell>
<TableCell>{lang.plugins.author}</TableCell>
<TableCell>{lang.plugins.description}</TableCell>
<TableCell align='right'>{lang.operations}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{plugins.map(it => {
const canBeDisabled = canPluginBeDisabled(it.name)
const disabledForever = it.file.endsWith('.disabled')
return <TableRow key={it.name}>
<TableCell padding='checkbox'>
<Checkbox
color='primary'
checked={it.enabled}
disabled={disabledForever || canBeDisabled}
onChange={() => plugin.emit('plugins:enable', it.file, it.name, action)
} />
</TableCell>
<TableCell><Tooltip title={it.file}><span>{it.name}</span></Tooltip></TableCell>
<TableCell>{it.website
? <Link underline='hover' rel='noopener' target='_blank' href={it.website}>{it.version}</Link>
: it.version
}</TableCell>
<TableCell>{it.author}</TableCell>
<TableCell>{it.description}</TableCell>
<TableCell align='right' sx={{ whiteSpace: 'nowrap' }}>
<Tooltip title={lang.plugins[disabledForever ? 'enablePlugin' : 'disableForever']}><span>
<IconButton
disabled={it.enabled || (it.loaded && !canLoadPlugin)}
onClick={() => plugin.emit('plugins:disableForever', it.file, action)}
>{disabledForever ? <LockOpen /> : <Lock />}</IconButton>
</span></Tooltip>
{disabledForever && <Tooltip title={lang.plugins.delete}><span>
<IconButton
color='error'
disabled={canBeDisabled}
onClick={() => dialog({
okButton: { color: 'error' },
content: <>{lang.plugins.confirmDelete(<span className='bold'>{it.file.replace(/\.disabled$/, '')}</span>)}
<span className='bold' style={{ color: theme.palette.error.main }}>({lang.unrecoverable})</span></>
}).then(res => res && plugin.emit('plugins:delete', it.file, action))}
><DeleteForever /></IconButton>
</span></Tooltip>}
</TableCell>
</TableRow>
})}
</TableBody>
</Table>
</TableContainer>
</Card>
</Grid>
<Grid item xs={12}>
<Card>
<CardHeader title={lang.plugins.dependency} />
<Divider />
<ReactECharts style={{ marginTop: theme.spacing(1), height: 450 }} theme={theme.palette.mode === 'dark' ? 'dark' : undefined} option={{
backgroundColor: 'rgba(0, 0, 0, 0)',
legend: { data: lang.plugins.categories },
series: [
{
edgeSymbol: ['none', 'arrow'],
symbolSize: 13,
type: 'graph',
layout: 'force',
data,
links,
categories: lang.plugins.categories.map(name => ({ name, base: name })),
roam: true,
label: {
show: true,
position: 'right',
formatter: '{b}'
},
labelLayout: {
hideOverlap: true
}
}
]
}} />
</Card>
</Grid>
</Grid>
</Container>
</Box>
}