@mui/material#Switch TypeScript Examples
The following examples show how to use
@mui/material#Switch.
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: TableSwitch.tsx From firecms with MIT License | 6 votes |
export function TableSwitch(props: {
error: Error | undefined;
internalValue?: boolean;
focused: boolean;
disabled: boolean;
updateValue: (newValue: (boolean | null)) => void;
}) {
const { disabled, internalValue, updateValue, focused } = props;
const ref = React.createRef<HTMLTextAreaElement>();
useEffect(() => {
if (ref.current && focused) {
ref.current.focus({ preventScroll: true });
}
}, [focused, ref]);
return (
<Switch
inputRef={ref}
color={"secondary"}
checked={Boolean(internalValue)}
disabled={disabled}
onChange={(evt) => {
const value = evt.target.checked as boolean;
updateValue(value);
}}
/>
);
}
Example #2
Source File: index.tsx From Search-Next with GNU General Public License v3.0 | 6 votes |
Beta: React.FC = () => {
const [checked, setChecked] = useState<boolean>(false);
const checkChange = (v: React.ChangeEvent<HTMLInputElement>) => {
const val = v.target.checked;
setBeta(val);
setChecked(val);
};
useEffect(() => {
setChecked(isBeta());
}, []);
return (
<div>
<ContentList>
<ContentTitle title="加入用户体验计划" />
<ItemCard
icon={<BugReportOutlined />}
title="用户体验计划"
desc="获取正在开发中功能的预览权限"
action={<Switch checked={checked} onChange={checkChange} />}
/>
<ContentTitle title="用户体验计划说明" />
<div className="p-2">
<Markdown source={Docs} />
</div>
</ContentList>
</div>
);
}
Example #3
Source File: SwitchElement.tsx From react-hook-form-mui with MIT License | 6 votes |
export default function SwitchElement({ name, control, ...other }: SwitchElementProps) {
return (
<FormControlLabel
control={
<Controller
name={name}
control={control}
render={({ field }) => <Switch {...field} checked={field.value} />}
/>
}
{...other}
/>
)
}
Example #4
Source File: Toggle.tsx From amplication with Apache License 2.0 | 6 votes |
Toggle = (props: Props) => {
const { label, onChange, onValueChange, ...rest } = props;
const handleChange = useCallback(
(event) => {
if (onChange) {
onChange(event, event.currentTarget.checked);
}
if (onValueChange) {
onValueChange(event.currentTarget.checked);
}
},
[onChange, onValueChange]
);
const switchNode = <Switch {...rest} onChange={handleChange} />;
const componentNode = !isEmpty(label) ? (
<div className={classNames(CLASS_NAME, `${CLASS_NAME}--with-label`)}>
<label className={LABEL_CLASS}>
<span className={LABEL_VALUE_CLASS}>{label}</span>
{switchNode}
</label>
</div>
) : (
<div className={CLASS_NAME}>{switchNode}</div>
);
return componentNode;
}
Example #5
Source File: SettingsModal.tsx From rewind with MIT License | 6 votes |
function BeatmapRenderSettings() {
const { beatmapRenderSettingsStore } = useCommonManagers();
const settings = useObservable(() => beatmapRenderSettingsStore.settings$, DEFAULT_BEATMAP_RENDER_SETTINGS);
return (
<Stack>
<FormGroup>
<FormControlLabel
control={
<Switch
checked={settings.sliderDevMode}
onChange={(event) => beatmapRenderSettingsStore.setSliderDevMode(event.target.checked)}
/>
}
label={"Slider Dev Mode"}
/>
</FormGroup>
{/* draw slider ends*/}
</Stack>
);
}
Example #6
Source File: SettingsModal.tsx From rewind with MIT License | 6 votes |
function AnalysisCursorSettingsSection() {
const { analysisCursorSettingsStore } = useCommonManagers();
const settings = useObservable(() => analysisCursorSettingsStore.settings$, DEFAULT_ANALYSIS_CURSOR_SETTINGS);
return (
<Paper sx={{ boxShadow: "none", p: 2 }}>
<Stack gap={1}>
<Typography variant={"h6"}>Analysis Cursor</Typography>
<FormGroup>
<FormControlLabel
control={
<Switch
checked={settings.enabled}
onChange={(event) => analysisCursorSettingsStore.setEnabled(event.target.checked)}
/>
}
label={"Enabled"}
/>
</FormGroup>
</Stack>
</Paper>
);
}
Example #7
Source File: SettingsModal.tsx From rewind with MIT License | 6 votes |
function PlaybarSettingsSection() {
const { playbarSettingsStore } = useCommonManagers();
const settings = useObservable(() => playbarSettingsStore.settings$, DEFAULT_PLAY_BAR_SETTINGS);
return (
<Paper elevation={1} sx={{ boxShadow: "none", p: 2 }}>
<Stack gap={1}>
<Typography variant={"h6"}>Playbar</Typography>
<FormGroup>
<FormControlLabel
control={
<Switch
checked={settings.difficultyGraphEnabled}
onChange={(event) =>
playbarSettingsStore.changeSettings((s) => (s.difficultyGraphEnabled = event.target.checked))
}
/>
}
label={"Show difficulty graph"}
/>
</FormGroup>
</Stack>
</Paper>
);
}
Example #8
Source File: SwitchField.tsx From firecms with MIT License | 5 votes |
SwitchFieldComponent = React.forwardRef(function({
name,
value,
setValue,
error,
showError,
autoFocus,
disabled,
touched,
property,
includeDescription,
shouldAlwaysRerender
}: SwitchFieldProps, ref) {
const classes = useStyles();
useClearRestoreValue({
property,
value,
setValue
});
const [focus, setFocus] = useState<boolean>(autoFocus);
return (
<>
<FormControl fullWidth>
<FormControlLabel
className={clsx(classes.formControl,
{
[classes.focus]: focus
})}
onClick={(e) => setFocus(true)}
labelPlacement={"start"}
checked={Boolean(value)}
inputRef={ref}
control={
<Switch
type={"checkbox"}
color={"secondary"}
autoFocus={autoFocus}
disabled={disabled}
onFocus={(e) => setFocus(true)}
onBlur={(e) => setFocus(false)}
onChange={(evt) => {
setFocus(true);
setValue(
evt.target.checked
);
}}/>
}
disabled={disabled}
label={
<Typography color={"textSecondary"}>
<LabelWithIcon
property={property}/>
</Typography>}
/>
{includeDescription &&
<FieldDescription property={property}/>}
{showError && <FormHelperText>{error}</FormHelperText>}
</FormControl>
</>
);
})
Example #9
Source File: FormSwitchWrapper.tsx From console with GNU Affero General Public License v3.0 | 5 votes |
StyledSwitch = withStyles((theme) => ({
root: {
width: 50,
height: 24,
padding: 0,
margin: 0,
},
switchBase: {
padding: 1,
"&$checked": {
transform: "translateX(24px)",
color: theme.palette.common.white,
"& + $track": {
backgroundColor: "#4CCB92",
boxShadow: "inset 0px 1px 4px rgba(0,0,0,0.1)",
opacity: 1,
border: "none",
},
},
"&$focusVisible $thumb": {
color: "#4CCB92",
border: "6px solid #fff",
},
},
thumb: {
width: 22,
height: 22,
backgroundColor: "#FAFAFA",
border: "2px solid #FFFFFF",
marginLeft: 1,
},
track: {
borderRadius: 24 / 2,
backgroundColor: "#E2E2E2",
boxShadow: "inset 0px 1px 4px rgba(0,0,0,0.1)",
opacity: 1,
transition: theme.transitions.create(["background-color", "border"]),
},
checked: {},
focusVisible: {},
switchContainer: {
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
},
}))(Switch)
Example #10
Source File: SettingsModal.tsx From rewind with MIT License | 5 votes |
function ReplayCursorSettingsSection() {
const { replayCursorSettingsStore } = useCommonManagers();
const settings = useObservable(() => replayCursorSettingsStore.settings$, DEFAULT_REPLAY_CURSOR_SETTINGS);
return (
<Paper sx={{ boxShadow: "none", p: 2 }}>
<Stack gap={1}>
<Typography variant={"h6"}>Replay Cursor</Typography>
<FormGroup>
<FormControlLabel
control={
<Switch
checked={settings.enabled}
onChange={(event) =>
replayCursorSettingsStore.changeSettings((s) => (s.enabled = event.target.checked))
}
/>
}
label={"Enabled"}
/>
</FormGroup>
<FormGroup>
<FormControlLabel
disabled={!settings.enabled}
control={
<Switch
checked={settings.smoothCursorTrail}
onChange={(event) =>
replayCursorSettingsStore.changeSettings((s) => (s.smoothCursorTrail = event.target.checked))
}
/>
}
label={"Smooth Cursor Trail"}
/>
</FormGroup>
<Typography>Scale</Typography>
<Slider
value={Math.round(settings.scale * 100)}
valueLabelFormat={formatToPercent}
disabled={!settings.enabled}
min={10}
max={200}
onChange={(_, v) => replayCursorSettingsStore.changeSettings((s) => (s.scale = (v as number) / 100))}
valueLabelDisplay={"auto"}
/>
</Stack>
</Paper>
);
}
Example #11
Source File: ModeSwitch.tsx From Cromwell with MIT License | 5 votes |
ModeSwitch = withStyles((theme: Theme | undefined) =>
createStyles({
track: {
backgroundImage: "url('/admin/static/sun.svg')",
transition: theme?.transitions?.create(['background-color', 'border']),
},
switchBase: {
'&$checked': {
'& + $track': {
backgroundImage: 'url("/admin/static/night-mode.svg")',
},
}
},
checked: {},
}),
)(({ classes, ...props }: Props & {
onToggle: () => void;
value: 'light' | 'dark';
}) => {
return (
<div className={props.value === 'dark' ? styles.darkMode : ''}>
<Tooltip title={props.value === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'}>
<Switch
size="medium"
checked={props.value === 'dark'}
onChange={props.onToggle}
focusVisibleClassName={classes.focusVisible}
classes={{
root: styles.root,
switchBase: clsx(styles.switchBase, classes.switchBase),
thumb: styles.thumb,
track: clsx(styles.track, classes.track),
checked: clsx(styles.checked, classes.checked),
}}
{...props}
/>
</Tooltip>
</div>
);
})
Example #12
Source File: ReaderNavBar.tsx From Tachidesk-WebUI with Mozilla Public License 2.0 | 4 votes |
export default function ReaderNavBar(props: IProps) {
const history = useHistory();
const {
settings, setSettings, manga, chapter, curPage,
} = props;
const [drawerOpen, setDrawerOpen] = useState(false || settings.staticNav);
const [hideOpenButton, setHideOpenButton] = useState(false);
const [prevScrollPos, setPrevScrollPos] = useState(0);
const [settingsCollapseOpen, setSettingsCollapseOpen] = useState(true);
const setSettingValue = (key: string, value: any) => setSettings({ ...settings, [key]: value });
const handleScroll = () => {
const currentScrollPos = window.pageYOffset;
if (Math.abs(currentScrollPos - prevScrollPos) > 20) {
setHideOpenButton(currentScrollPos > prevScrollPos);
setPrevScrollPos(currentScrollPos);
}
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
const rootEl:HTMLDivElement = document.querySelector('#root')!;
const mainContainer:HTMLDivElement = document.querySelector('#appMainContainer')!;
// main container and root div need to change styles...
rootEl.style.display = 'flex';
mainContainer.style.display = 'none';
return () => {
rootEl.style.display = 'block';
mainContainer.style.display = 'block';
window.removeEventListener('scroll', handleScroll);
};
}, [handleScroll]);// handleScroll changes on every render
return (
<>
<Slide
direction="right"
in={drawerOpen}
timeout={200}
appear={false}
mountOnEnter
unmountOnExit
>
<Root sx={{
position: settings.staticNav ? 'sticky' : 'fixed',
}}
>
<header>
{!settings.staticNav
&& (
<IconButton
edge="start"
color="inherit"
aria-label="menu"
disableRipple
onClick={() => setDrawerOpen(false)}
size="large"
>
<KeyboardArrowLeftIcon />
</IconButton>
)}
<Typography variant="h1">
{chapter.name}
</Typography>
<IconButton
edge="start"
color="inherit"
aria-label="menu"
disableRipple
onClick={() => history.push('..')}
size="large"
sx={{ mr: -1 }}
>
<CloseIcon />
</IconButton>
</header>
<ListItem
ContainerComponent="div"
sx={{
'& span': {
fontWeight: 'bold',
},
}}
>
<ListItemText primary="Reader Settings" />
<ListItemSecondaryAction>
<IconButton
edge="start"
color="inherit"
aria-label="menu"
disableRipple
disableFocusRipple
onClick={() => setSettingsCollapseOpen(!settingsCollapseOpen)}
size="large"
>
{settingsCollapseOpen && <KeyboardArrowUpIcon />}
{!settingsCollapseOpen && <KeyboardArrowDownIcon />}
</IconButton>
</ListItemSecondaryAction>
</ListItem>
<Collapse in={settingsCollapseOpen} timeout="auto" unmountOnExit>
<List>
<ListItem>
<ListItemText primary="Static Navigation" />
<ListItemSecondaryAction>
<Switch
edge="end"
checked={settings.staticNav}
onChange={(e) => setSettingValue('staticNav', e.target.checked)}
/>
</ListItemSecondaryAction>
</ListItem>
<ListItem>
<ListItemText primary="Show page number" />
<ListItemSecondaryAction>
<Switch
edge="end"
checked={settings.showPageNumber}
onChange={(e) => setSettingValue('showPageNumber', e.target.checked)}
/>
</ListItemSecondaryAction>
</ListItem>
<ListItem>
<ListItemText primary="Load next chapter at ending" />
<ListItemSecondaryAction>
<Switch
edge="end"
checked={settings.loadNextonEnding}
onChange={(e) => setSettingValue('loadNextonEnding', e.target.checked)}
/>
</ListItemSecondaryAction>
</ListItem>
<ListItem>
<ListItemText primary="Reader Type" />
<Select
variant="standard"
value={settings.readerType}
onChange={(e) => setSettingValue('readerType', e.target.value)}
sx={{ p: 0 }}
>
<MenuItem value="SingleLTR">
Single Page (LTR)
</MenuItem>
<MenuItem value="SingleRTL">
Single Page (RTL)
</MenuItem>
{/* <MenuItem value="SingleVertical">
Vertical(WIP)
</MenuItem> */}
<MenuItem value="DoubleLTR">
Double Page (LTR)
</MenuItem>
<MenuItem value="DoubleRTL">
Double Page (RTL)
</MenuItem>
<MenuItem value="Webtoon">
Webtoon
</MenuItem>
<MenuItem value="ContinuesVertical">
Continues Vertical
</MenuItem>
<MenuItem value="ContinuesHorizontalLTR">
Horizontal (LTR)
</MenuItem>
<MenuItem value="ContinuesHorizontalRTL">
Horizontal (RTL)
</MenuItem>
</Select>
</ListItem>
</List>
</Collapse>
<hr />
<Navigation>
<span>
{`Currently on page ${curPage + 1} of ${chapter.pageCount}`}
</span>
<ChapterNavigation>
{chapter.index > 1
&& (
<Link
replace
to={`/manga/${manga.id}/chapter/${chapter.index - 1}`}
>
<Button
variant="outlined"
sx={{ gridArea: 'prev' }}
startIcon={<KeyboardArrowLeftIcon />}
>
Prev. Chapter
</Button>
</Link>
)}
{chapter.index < chapter.chapterCount
&& (
<Link
replace
style={{ gridArea: 'next' }}
to={`/manga/${manga.id}/chapter/${chapter.index + 1}`}
>
<Button
variant="outlined"
endIcon={<KeyboardArrowRightIcon />}
>
Next Chapter
</Button>
</Link>
)}
</ChapterNavigation>
</Navigation>
</Root>
</Slide>
<Zoom in={!drawerOpen}>
<Fade in={!hideOpenButton}>
<OpenDrawerButton
edge="start"
color="inherit"
aria-label="menu"
disableRipple
disableFocusRipple
onClick={() => setDrawerOpen(true)}
size="large"
>
<KeyboardArrowRightIcon />
</OpenDrawerButton>
</Fade>
</Zoom>
</>
);
}
Example #13
Source File: GroupLog.tsx From abrechnung with GNU Affero General Public License v3.0 | 4 votes |
export default function GroupLog({ group }) {
const [message, setMessage] = useState("");
const [showAllLogs, setShowAllLogs] = useState(false);
const logEntries = useRecoilValue(groupLog(group.id));
const members = useRecoilValue(groupMembers(group.id));
useTitle(`${group.name} - Log`);
const sendMessage = () => {
sendGroupMessage({
groupID: group.id,
message: message,
})
.then((result) => {
setMessage("");
})
.catch((err) => {
toast.error(err);
});
};
const getMemberUsername = (member_id) => {
const member = members.find((member) => member.user_id === member_id);
if (member === undefined) {
return "unknown";
}
return member.username;
};
const onKeyUp = (key) => {
key.preventDefault();
if (key.keyCode === 13) {
sendMessage();
}
};
const log = showAllLogs ? logEntries : logEntries.filter((entry) => entry.type === "text-message");
return (
<MobilePaper>
<Typography component="h3" variant="h5">
Group Log
</Typography>
<FormControlLabel
control={
<Switch
name="showAllLogs"
checked={showAllLogs}
color="primary"
onChange={(e) => setShowAllLogs(e.target.checked)}
/>
}
label="Show all Logs"
/>
<TextField
required
fullWidth
name="newMessage"
placeholder="Write a message to the group ..."
value={message}
variant="outlined"
onKeyUp={onKeyUp}
multiline
onChange={(e) => setMessage(e.target.value)}
/>
<Button type="submit" color="primary" onClick={sendMessage}>
Send
</Button>
<Divider variant="middle" />
<List>
{log.map((logEntry) => (
<ListItem key={logEntry.id}>
<ListItemText
primary={`${logEntry.type} - ${logEntry.message}`}
secondary={`by ${getMemberUsername(logEntry.user_id)}
on ${DateTime.fromISO(logEntry.logged_at).toLocaleString(DateTime.DATETIME_FULL)}`}
/>
</ListItem>
))}
</List>
</MobilePaper>
);
}
Example #14
Source File: Config.tsx From NekoMaid with MIT License | 4 votes |
configs.push({
title: lang.config.serverConfig,
component () {
const plugin = usePlugin()
const globalData = useGlobalData()
const [flag, update] = useState(0)
const [info, setInfo] = useState<Record<string, string>>({ })
const [open, setOpen] = useState(false)
const [canGetData, setCanGetData] = useState(true)
const [loading, setLoading] = useState(false)
const setValue = (field: string, value: any, isGlobal = true) => {
plugin.emit('server:set', field, value)
success()
if (isGlobal) {
(globalData as any)[field] = value
update(flag + 1)
location.reload()
}
}
const createEditButtom = (field: string, isGlobal?: boolean, isInt = true) => <IconButton
onClick={() => dialog(
{
content: lang.inputValue,
input: isInt
? {
error: true,
type: 'number',
helperText: lang.invalidValue,
validator: (it: string) => /^\d+$/.test(it) && +it >= 0
}
: { }
}).then(res => res != null && setValue(field, isInt ? parseInt(res as any) : (res || null), isGlobal))}
><Edit /></IconButton>
const infoElm: JSX.Element[] = []
for (const key in info) {
const name = (lang.config as any)[key]
infoElm.push(<ListItem key={key} sx={{ pl: 4 }}>
<ListItemText
primary={key === 'isAikarFlags' ? <Link href='https://mcflags.emc.gs' target='_blank' rel='noopener'>{name}</Link> : name}
secondary={info[key].toString()}
/>
</ListItem>)
}
return <List>
<CircularLoading loading={loading} />
<ListItem secondaryAction={globalData.canSetMaxPlayers
? createEditButtom('maxPlayers')
: undefined}>
<ListItemText primary={lang.config.maxPlayers + ': ' + globalData.maxPlayers} />
</ListItem>
<ListItem secondaryAction={createEditButtom('spawnRadius')}>
<ListItemText primary={lang.config.spawnRadius + ': ' + globalData.spawnRadius} />
</ListItem>
<ListItem secondaryAction={createEditButtom('motd', false, false)}>
<ListItemText primary={lang.config.motd} />
</ListItem>
<ListItem secondaryAction={<Switch checked={globalData.hasWhitelist} onChange={e => setValue('hasWhitelist', e.target.checked)} />}>
<ListItemText primary={lang.config.whitelist} />
</ListItem>
{canGetData && <>
<ListItemButton onClick={() => {
if (infoElm.length) setOpen(!open)
else {
setLoading(true)
plugin.emit('server:fetchInfo', (data: any) => {
setLoading(false)
if (!data) {
failed(lang.unsupported)
setCanGetData(false)
return
}
setInfo(data)
setOpen(true)
})
}
}}>
<ListItemIcon><Equalizer /></ListItemIcon>
<ListItemText primary={lang.info} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
<Collapse in={open} timeout='auto' unmountOnExit>
<List component='div' dense disablePadding>{infoElm}</List>
</Collapse>
</>}
</List>
}
},
{
title: lang.history,
component () {
const [cur, update] = useState(0)
const list: ServerRecord[] = JSON.parse(localStorage.getItem('NekoMaid:servers') || '[]')
return <List>
{list.sort((a, b) => b.time - a.time).map(it => {
const i = it.address.indexOf('?')
return <ListItem
disablePadding
key={it.address}
secondaryAction={<IconButton edge='end' size='small' onClick={() => {
localStorage.setItem('NekoMaid:servers', JSON.stringify(list.filter(s => s.address !== it.address)))
success()
update(cur + 1)
}}><Delete /></IconButton>}
>
<ListItemButton onClick={() => {
location.hash = ''
location.search = it.address
}} dense>
<ListItemAvatar><Avatar src={it.icon} variant='rounded'><HelpOutline /></Avatar></ListItemAvatar>
<ListItemText primary={<Tooltip title={it.address.slice(i + 1)}>
<span>{it.address.slice(0, i)}</span></Tooltip>} secondary={dayjs(it.time).fromNow()} />
</ListItemButton>
</ListItem>
})}
</List>
}
},
{
title: lang.config.theme,
component () {
const color = localStorage.getItem('NekoMaid:color') || 'blue'
return <CardContent sx={{ textAlign: 'center' }}>
<Box>
<ToggleButtonGroup exclusive value={localStorage.getItem('NekoMaid:colorMode') || ''} onChange={(_, it) => {
localStorage.setItem('NekoMaid:colorMode', it)
location.reload()
}}>
<ToggleButton value='light'><Brightness7 /> {lang.config.light}</ToggleButton>
<ToggleButton value=''><SettingsBrightness /> {lang.config.system}</ToggleButton>
<ToggleButton value='dark'><Brightness4 /> {lang.config.dark}</ToggleButton>
</ToggleButtonGroup>
</Box>
<Paper sx={{ marginTop: 2, width: '176px', overflow: 'hidden', display: 'inline-block' }}>
{Object.keys(colors).slice(1, 17).map((key, i) => {
const checked = color === key
const elm = <Box
key={key}
onClick={() => {
localStorage.setItem('NekoMaid:color', key)
location.reload()
}}
sx={{
backgroundColor: (colors as any)[key][600],
width: '44px',
height: '44px',
display: 'inline-block',
cursor: 'pointer'
}}
><Check htmlColor='white' sx={{ top: '10px', position: 'relative', opacity: checked ? 1 : 0 }} /></Box>
return (i + 1) % 4 === 0 ? <React.Fragment key={key}>{elm}<br /></React.Fragment> : elm
})}
</Paper>
</CardContent>
}
})
Example #15
Source File: EntityEditor.tsx From NekoMaid with MIT License | 4 votes |
EntityEditor: React.FC = () => {
const theme = useTheme()
const plugin = usePlugin()
const his = useHistory()
const loc = useLocation()
const globalData = useGlobalData()
const drawerWidth = useDrawerWidth()
const [customName, setCustomName] = useState('')
const [entity, setEntity] = useState<Entity>()
let id: string | null = null
if (loc.pathname.startsWith('/NekoMaid/entity/')) {
const arr = loc.pathname.split('/')
if (arr.length > 3) id = arr[3]
}
useEffect(() => {
const off = plugin.on('entity:select', id => his.push('/NekoMaid/entity/' + id))
return () => void off()
}, [])
const update = () => {
if (id) {
plugin.emit('entity:fetch', (entity: Entity) => {
if (!entity) {
failed()
his.push('/NekoMaid/entity')
return
}
if (globalData.hasNBTAPI && entity.nbt) entity.nbt = stringify(parse(entity.nbt), { pretty: true })
setCustomName(entity.customName || '')
setEntity(entity)
}, id)
}
}
const updateWithAction = (res: boolean) => {
action(res)
update()
}
useEffect(update, [id])
return <Box sx={{ minHeight: '100%', py: 3 }}>
<Toolbar />
<Container maxWidth={false}>
<Grid container spacing={3} sx={{ width: { sm: `calc(100vw - ${drawerWidth}px - ${theme.spacing(3)})` } }}>
<Grid item lg={6} md={12} xl={6} xs={12}>
<Card>
<CardHeader
title={(entity && minecraft['entity.minecraft.' + entity.type.toLowerCase()]) || lang.entityEditor.title}
sx={{ position: 'relative' }}
action={<Box sx={cardActionStyles}>
<IconButton
size='small'
disabled={!entity}
onClick={() => entity && plugin.emit('entity:save', (res: boolean) => {
action(res)
update()
}, id, entity.nbt || null, customName || null)}
><Save /></IconButton>
<IconButton
size='small'
disabled={!entity}
onClick={() => {
update()
success()
}}
><Refresh /></IconButton>
</Box>}
/>
<Divider />
{entity
? <>
<CardContent>
<Grid container>
<Grid item lg={6} md={6} xl={6} xs={12}>
<TextField
size='small'
label={lang.entityEditor.customName}
value={customName}
sx={{ width: '90%' }}
onChange={e => setCustomName(e.target.value)}
/>
</Grid>
{values.map(it => <Grid item lg={6} md={6} xl={6} xs={12} key={it}>
<FormControlLabel
control={<Switch checked={(entity as any)[it]} />}
label={(lang.entityEditor as any)[it]}
onChange={(e: any) => plugin.emit('entity:set', (res: boolean) => {
action(res)
update()
}, id, it, e.target.checked)}
/>
</Grid>)}
</Grid>
</CardContent>
{entity.nbt != null && <Accordion sx={{ '&::before': { opacity: '1!important' } }} disableGutters>
<AccordionSummary expandIcon={<ExpandMore />}><Typography>NBT</Typography></AccordionSummary>
<AccordionDetails sx={{
padding: 0,
'& .CodeMirror': { width: '100%', height: 350 },
'& .CodeMirror-dialog, .CodeMirror-scrollbar-filler': { backgroundColor: theme.palette.background.paper + '!important' }
}}>
<UnControlled
value={entity.nbt}
options={{
mode: 'javascript',
phrases: lang.codeMirrorPhrases,
theme: theme.palette.mode === 'dark' ? 'material' : 'one-light'
}}
onChange={(_: any, __: any, data: string) => (entity.nbt = data)}
/>
</AccordionDetails>
</Accordion>}
</>
: <CardContent><EntitySelector /></CardContent>}
</Card>
</Grid>
{entity?.inventory?.length
? <Grid item lg={6} md={12} xl={6} xs={12}>
<Card>
<CardHeader
title={lang.entityEditor.container}
sx={{ position: 'relative' }}
/>
<Divider />
<CardContent sx={{ whiteSpace: 'nowrap', overflowX: 'auto', textAlign: 'center' }}>
{entity.inventory.map((it, i) => <React.Fragment key={i}><ItemViewer
item={it}
data={{ type: InvType.ENTITY, solt: i, id }}
onDrag={() => plugin.emit('entity:setItem', update, id, i, null, -1)}
onDrop={(item, obj) => plugin.emit('entity:setItem', update, id, i, JSON.stringify(item),
obj?.type === InvType.ENTITY && obj.id === id ? obj.solt : -1)}
onEdit={item => item !== false && plugin.emit('entity:setItem', updateWithAction, id, i, item && JSON.stringify(item), -1)}
/>{!((i + 1) % 9) && <br />}</React.Fragment>)}
</CardContent>
</Card>
</Grid>
: undefined}
</Grid>
</Container>
</Box>
}
Example #16
Source File: Profiler.tsx From NekoMaid with MIT License | 4 votes |
Timings: React.FC = React.memo(() => {
const plugin = usePlugin()
const theme = useTheme()
const { isTimingsV1 } = useGlobalData()
const [status, setStatus] = useState(false)
const [data, setData] = useState<TimingsData | null>(null)
useEffect(() => {
const off = plugin.emit('profiler:timingsStatus', setStatus).on('profiler:timings', setData)
return () => { off() }
}, [])
const [tree, entitiesTick, tilesTick] = useMemo(() => {
if (!data) return []
const entitiesTickMap: Record<string, { value: number, name: string, count: number }> = {}
const tilesTickMap: Record<string, { value: number, name: string, count: number }> = {}
const map: Record<number, [number, number, number, [number, number, number][] | undefined] | undefined> = { }
data.data.forEach(it => (map[it[0]] = it))
const createNode = (id: number, percent: number) => {
const cur = map[id]
if (!cur) return
map[id] = undefined
const [, count, time] = cur
const handler = data.handlers[id] || [0, lang.unknown]
const handlerName = data.groups[handler[0]] || lang.unknown
const name = handler[1]
const children = cur[cur.length - 1]
if (isTimingsV1) {
if (name.startsWith('tickEntity - ')) {
const came = name.slice(13).replace(/^Entity(Mob)?/, '')
const entity = decamelize(came)
const node = entitiesTickMap[entity]
if (node) {
node.count += count
node.value += time
} else entitiesTickMap[entity] = { count, value: time, name: minecraft['entity.minecraft.' + entity] || came }
} else if (name.startsWith('tickTileEntity - ')) {
const came = name.slice(17).replace(/^TileEntity(Mob)?/, '')
const entity = decamelize(came)
const node = tilesTickMap[entity]
if (node) {
node.count += count
node.value += time
} else tilesTickMap[entity] = { count, value: time, name: minecraft['block.minecraft.' + entity] || came }
}
} else {
if (name.startsWith('tickEntity - ') && name.endsWith('ick')) {
const res = ENTITY_TYPE.exec(name)
if (res) {
const node = entitiesTickMap[res[1]]
if (node) {
node.count += count
node.value += time
} else entitiesTickMap[res[1]] = { count, value: time, name: minecraft['entity.minecraft.' + res[1]] || res[1] }
}
} else if (name.startsWith('tickTileEntity - ')) {
const arr = name.split('.')
const came = arr[arr.length - 1].replace(/^TileEntity(Mob)?/, '')
const tile = decamelize(came)
const node = tilesTickMap[tile]
if (node) {
node.count += count
node.value += time
} else tilesTickMap[tile] = { count, value: time, name: minecraft['block.minecraft.' + tile] || came }
}
}
return <TreeItem
key={id}
nodeId={id.toString()}
label={<Box sx={{
'& .info, .count': { color: 'transparent' },
'&:hover .count': { color: 'inherit' },
'&:hover .info': {
color: theme.palette.primary.contrastText,
textShadow: theme.palette.mode === 'light'
? '#000 1px 0 0, #000 0 1px 0, #000 -1px 0 0, #000 0 -1px 0'
: '#fff 1px 0 0, #fff 0 1px 0, #fff -1px 0 0, #fff 0 -1px 0'
}
}}>
<Box sx={{
position: 'relative',
zIndex: 2,
display: 'flex',
alignItems: 'center'
}}>
{handlerName !== 'Minecraft' && <><Typography color='primary' component='span'>
{isTimingsV1 ? 'Bukkit' : lang.plugin + ':' + handlerName}</Typography>::</>}
{name}
<Typography variant='caption' className='count'>({lang.profiler.timingsCount}: {count})</Typography>
</Box>
<Box className='info' sx={{
position: 'absolute',
height: 10,
right: 0,
top: '50%',
marginTop: '-5px',
minWidth: 40,
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
}}>
<Typography variant='caption' sx={{ position: 'absolute' }}>({Math.round(100 * percent)}%)</Typography>
<div style={{ width: 100 * percent + 'px' }} className='bar' />
</Box>
</Box>}
>{Array.isArray(children) && children.sort((a, b) => b[2] - a[2]).map(it => createNode(it[0], percent * (it[2] / time)))}</TreeItem>
}
// eslint-disable-next-line react/jsx-key
return [<TreeView defaultCollapseIcon={<ExpandMore />} defaultExpandIcon={<ChevronRight />} defaultExpanded={['1']}>
{createNode(1, 1)}
</TreeView>, Object.values(entitiesTickMap), Object.values(tilesTickMap)]
}, [data])
return <Container maxWidth={false} sx={{ py: 3 }}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Card>
<CardHeader title='Timings' sx={{ position: 'relative' }} action={<FormControlLabel
control={<Switch checked={status} onChange={e => plugin.emit('profiler:timingsStatus', setStatus, e.target.checked)} />}
label={minecraft['addServer.resourcePack.enabled']}
sx={cardActionStyles}
/>} />
<Divider />
{status
? <Box sx={{
position: 'relative',
minHeight: data ? undefined : 300,
'& .bar': { backgroundColor: theme.palette.primary.main, height: 10, marginLeft: 'auto', borderRadius: 2 }
}}>
<CircularLoading loading={!data} />
{tree}
</Box>
: <CardContent><Empty title={lang.profiler.timingsNotStarted} /></CardContent>}
</Card>
</Grid>
{data && <Pie title={lang.profiler.entitiesTick} data={entitiesTick!} formatter={countFormatter} />}
{data && <Pie title={lang.profiler.tilesTick} data={tilesTick!} formatter={countFormatter} />}
</Grid>
</Container>
})
Example #17
Source File: Scheduler.tsx From NekoMaid with MIT License | 4 votes |
Scheduler: React.FC = () => {
const plugin = usePlugin()
const [id, setId] = useState(-1)
let [tasks, setTasks] = useState<Task[]>([])
const [name, setName] = useState('')
const [cron, setCron] = useState('')
const [values, setValues] = useState('')
const [whenIdle, setWhenIdle] = useState(false)
const [cronError, setCronError] = useState('')
const save = () => plugin.emit('scheduler:update', (res: boolean) => {
action(res)
plugin.emit('scheduler:fetch', setTasks)
}, JSON.stringify(tasks))
useEffect(() => { plugin.emit('scheduler:fetch', setTasks) }, [])
return <Box sx={{ minHeight: '100%', py: 3 }}>
<Toolbar />
<Container maxWidth={false}>
<Grid container spacing={3}>
<Grid item lg={4} md={12} xl={4} xs={12}>
<Card>
<CardHeader
title={lang.scheduler.title}
sx={{ position: 'relative' }}
action={<IconButton
size='small'
onClick={() => {
const task = {
name: lang.scheduler.newTask,
cron: '*/1 * * * *',
enabled: true,
whenIdle: false,
values: ['/say Hello, %server_tps% (PlaceholderAPI)', 'This is a chat message']
}
setTasks([...tasks, task])
setId(tasks.length)
setCronError('')
setCron(task.cron)
setName(task.name)
setValues(task.values.join('\n'))
setWhenIdle(false)
}}
sx={cardActionStyles}
><Add /></IconButton>}
/>
<Divider />
{tasks.length
? <List
sx={{ width: '100%' }}
component='nav'
>
{tasks.map((it, i) => <ListItem
key={i}
disablePadding
secondaryAction={<IconButton
edge='end'
onClick={() => dialog(lang.scheduler.confirmDelete)
.then(it => {
if (it == null) return
setTasks((tasks = tasks.filter((_, id) => i !== id)))
save()
})}
><Delete /></IconButton>}
sx={{ position: 'relative' }}
>
<ListItemIcon sx={{ paddingLeft: 2, position: 'absolute' }}>
<Checkbox
edge='start'
checked={it.enabled}
tabIndex={-1}
/>
</ListItemIcon>
<ListItemButton onClick={() => {
setId(i)
setCronError('')
setCron(tasks[i].cron)
setName(tasks[i].name)
setValues(tasks[i].values.join('\n'))
setWhenIdle(!!tasks[i].whenIdle)
}}><ListItemText inset primary={it.name} /></ListItemButton >
</ListItem>)}
</List>
: <CardContent><Empty /></CardContent>}
</Card>
</Grid>
<Grid item lg={8} md={12} xl={8} xs={12}>
<Card>
<CardHeader
title={lang.scheduler.editor}
sx={{ position: 'relative' }}
action={<IconButton
size='small'
onClick={() => {
tasks[id].values = values.split('\n')
tasks[id].cron = cron
tasks[id].name = name
tasks[id].whenIdle = whenIdle
save()
}}
sx={cardActionStyles}
disabled={!tasks[id] || !!cronError}
><Save /></IconButton>}
/>
<Divider />
<CardContent>
{tasks[id]
? <>
<TextField
required
fullWidth
variant='standard'
label={lang.scheduler.name}
value={name}
onChange={e => setName(e.target.value)}
/>
<TextField
fullWidth
multiline
rows={4}
value={values}
sx={{ marginTop: 3 }}
label={lang.scheduler.content}
onChange={e => setValues(e.target.value)}
/>
<FormControlLabel
control={<Switch checked={whenIdle} />}
label={lang.scheduler.whenIdle}
onChange={(e: any) => setWhenIdle(e.target.checked)}
/>
</>
: <Empty title={lang.scheduler.notSelected} />}
</CardContent>
{tasks[id] && <>
<Divider textAlign='left'>{lang.scheduler.timer}</Divider>
<CardContent>
<Box sx={{
'& .MuiTextField-root': { backgroundColor: 'inherit!important' },
'& .MuiOutlinedInput-input': { color: 'inherit!important' },
'& .MuiTypography-h6': { color: theme => theme.palette.primary.main + '!important' }
}}>
<Cron cron={cron} setCron={setCron} setCronError={setCronError} locale={currentLanguage as any} isAdmin />
</Box>
</CardContent>
</>}
</Card>
</Grid>
</Grid>
</Container>
</Box>
}
Example #18
Source File: Worlds.tsx From NekoMaid with MIT License | 4 votes |
Worlds: React.FC = () => {
const plugin = usePlugin()
const globalData = useGlobalData()
const [worlds, setWorlds] = useState<World[]>([])
const [selected, setSelected] = useState('')
const [open, setOpen] = useState(false)
const update = () => plugin.emit('worlds:fetch', (data: World[]) => {
setWorlds(data)
if (data.length) setSelected(old => data.some(it => it.id === old) ? old : '')
})
useEffect(() => {
const offUpdate = plugin.on('worlds:update', update)
update()
return () => { offUpdate() }
}, [])
const sw = worlds.find(it => it.id === selected)
const getSwitch = (name: string, configId = name) => sw
? <ListItem
secondaryAction={<Switch disabled={!globalData.hasMultiverse} checked={(sw as any)[name]}
onChange={e => {
plugin.emit('worlds:set', sw.id, configId, e.target.checked.toString())
success()
}}
/>}><ListItemText primary={(lang.worlds as any)[name]} /></ListItem>
: null
return <Box sx={{ minHeight: '100%', py: 3 }}>
<Toolbar />
<Container maxWidth={false}>
<Grid container spacing={3}>
<Grid item lg={8} md={12} xl={9} xs={12}>
<Card>
<CardHeader title={lang.worlds.title} />
<Divider />
<Box sx={{ position: 'relative' }}>
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell padding='checkbox' />
<TableCell>{lang.worlds.name}</TableCell>
{globalData.hasMultiverse && <TableCell>{lang.worlds.alias}</TableCell>}
<TableCell>{lang.worlds.players}</TableCell>
<TableCell>{lang.worlds.chunks}</TableCell>
<TableCell>{lang.worlds.entities}</TableCell>
<TableCell>{lang.worlds.tiles}</TableCell>
<TableCell>{lang.worlds.time}</TableCell>
<TableCell>{lang.worlds.weather}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{worlds.map(it => <TableRow key={it.id}>
<TableCell padding='checkbox'><Checkbox checked={selected === it.id} onClick={() => setSelected(it.id)} /></TableCell>
<TableCell><Tooltip title={it.id}><span>{it.name}</span></Tooltip></TableCell>
{globalData.hasMultiverse && <TableCell>{it.alias}
<IconButton size='small' onClick={() => dialog(lang.inputValue, lang.worlds.alias).then(res => {
if (res == null) return
plugin.emit('worlds:set', it.id, 'alias', res)
success()
})}><Edit fontSize='small' /></IconButton>
</TableCell>}
<TableCell>{it.players}</TableCell>
<TableCell>{it.chunks}</TableCell>
<TableCell>{it.entities}</TableCell>
<TableCell>{it.tiles}</TableCell>
<TableCell><Countdown time={it.time} max={24000} interval={50} /></TableCell>
<TableCell><IconButton size='small' onClick={() => {
plugin.emit('worlds:weather', it.id)
success()
}}>
{React.createElement((it.weather === 1 ? WeatherRainy : it.weather === 2 ? WeatherLightningRainy : WbSunny) as any)}
</IconButton></TableCell>
</TableRow>)}
</TableBody>
</Table>
</TableContainer>
</Box>
</Card>
</Grid>
<Grid item lg={4} md={6} xl={3} xs={12}>
<Card>
<CardHeader
title={lang.operations}
sx={{ position: 'relative' }}
action={<Tooltip title={lang.worlds.save} placement='left'>
<IconButton
size='small'
onClick={() => {
if (!sw) return
plugin.emit('worlds:save', sw.id)
success()
}}
sx={cardActionStyles}
><Save /></IconButton>
</Tooltip>}
/>
<Divider />
<Box sx={{ position: 'relative' }}>
{sw
? <List sx={{ width: '100%' }} component='nav'>
<ListItem secondaryAction={<ToggleButtonGroup
exclusive
color='primary'
size='small'
value={sw.difficulty}
onChange={(_, value) => {
plugin.emit('worlds:difficulty', sw.id, value)
success()
}}
>
{difficulties.map(it => <ToggleButton value={it.toUpperCase()} key={it}>{minecraft['options.difficulty.' + it]}</ToggleButton>)}
</ToggleButtonGroup>}><ListItemText primary={minecraft['options.difficulty']} /></ListItem>
<ListItem secondaryAction={<Switch checked={sw.pvp} onChange={e => {
plugin.emit('worlds:pvp', sw.id, e.target.checked)
success()
}} />}><ListItemText primary='PVP' /></ListItem>
{getSwitch('allowAnimals', 'spawning.animals.spawn')}
{getSwitch('allowMonsters', 'spawning.monsters.spawn')}
{globalData.hasMultiverse && <>
{getSwitch('allowFlight')}
{getSwitch('autoHeal')}
{getSwitch('hunger')}
</>}
<ListItem secondaryAction={globalData.canSetViewDistance
? <IconButton
onClick={() => dialog({
content: lang.inputValue,
input: {
error: true,
type: 'number',
helperText: lang.invalidValue,
validator: (it: string) => /^\d+$/.test(it) && +it > 1 && +it < 33
}
}).then(res => {
if (!res) return
plugin.emit('worlds:viewDistance', sw.id, parseInt(res as any))
success()
})}
><Edit /></IconButton>
: undefined}>
<ListItemText primary={lang.worlds.viewDistance + ': ' + sw.viewDistance} />
</ListItem>
<ListItem><ListItemText primary={minecraft['selectWorld.enterSeed']} secondary={sw.seed} /></ListItem>
<ListItemButton onClick={() => setOpen(!open)}>
<ListItemText primary={minecraft['selectWorld.gameRules']} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component='div' dense disablePadding>
{sw.rules.map(([key, value]) => {
const isTrue = value === 'true'
const isBoolean = isTrue || value === 'false'
const isNumber = /^\d+$/.test(value)
return <ListItem
key={key}
sx={{ pl: 4 }}
secondaryAction={isBoolean
? <Switch
checked={isTrue}
onChange={e => {
plugin.emit('worlds:rule', sw.id, key, e.target.checked.toString())
success()
}}
/>
: <IconButton
onClick={() => dialog({
content: lang.inputValue,
input: isNumber
? {
error: true,
type: 'number',
helperText: lang.invalidValue,
validator: (it: string) => /^\d+$/.test(it)
}
: { }
}).then(res => {
if (res == null) return
plugin.emit('worlds:rule', sw.id, key, res)
success()
})}
><Edit /></IconButton>}
>
<ListItemText primary={(minecraft['gamerule.' + key] || key) + (isBoolean ? '' : ': ' + value)} />
</ListItem>
})}
</List>
</Collapse>
</List>
: <CardContent><Empty /></CardContent>
}
</Box>
</Card>
</Grid>
</Grid>
</Container>
</Box>
}
Example #19
Source File: index.tsx From wallet-adapter with Apache License 2.0 | 4 votes |
Index: NextPage = () => {
const { autoConnect, setAutoConnect } = useAutoConnect();
return (
<Table>
<TableHead>
<TableRow>
<TableCell width={240}>Component</TableCell>
<TableCell width={240}>Material UI</TableCell>
<TableCell width={240}>Ant Design</TableCell>
<TableCell width={240}>React UI</TableCell>
<TableCell>Example v{pkg.version}</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>Connect Button</TableCell>
<TableCell>
<MaterialUIWalletConnectButton />
</TableCell>
<TableCell>
<AntDesignWalletConnectButton />
</TableCell>
<TableCell>
<ReactUIWalletConnectButton />
</TableCell>
<TableCell></TableCell>
</TableRow>
<TableRow>
<TableCell>Disconnect Button</TableCell>
<TableCell>
<MaterialUIWalletDisconnectButton />
</TableCell>
<TableCell>
<AntDesignWalletDisconnectButton />
</TableCell>
<TableCell>
<ReactUIWalletDisconnectButton />
</TableCell>
<TableCell></TableCell>
</TableRow>
<TableRow>
<TableCell>Dialog/Modal Button</TableCell>
<TableCell>
<MaterialUIWalletDialogButton />
</TableCell>
<TableCell>
<AntDesignWalletModalButton />
</TableCell>
<TableCell>
<ReactUIWalletModalButton />
</TableCell>
<TableCell></TableCell>
</TableRow>
<TableRow>
<TableCell>Multi Button</TableCell>
<TableCell>
<MaterialUIWalletMultiButton />
</TableCell>
<TableCell>
<AntDesignWalletMultiButton />
</TableCell>
<TableCell>
<ReactUIWalletMultiButton />
</TableCell>
<TableCell></TableCell>
</TableRow>
<TableRow>
<TableCell></TableCell>
<TableCell>
<Tooltip title="Only runs if the wallet is ready to connect" placement="left">
<FormControlLabel
control={
<Switch
name="autoConnect"
color="secondary"
checked={autoConnect}
onChange={(event, checked) => setAutoConnect(checked)}
/>
}
label="AutoConnect"
/>
</Tooltip>
</TableCell>
<TableCell>
<RequestAirdrop />
</TableCell>
<TableCell>
<SendTransaction />
</TableCell>
<TableCell>
<SignMessage />
</TableCell>
</TableRow>
</TableBody>
</Table>
);
}
Example #20
Source File: TextField.tsx From firecms with MIT License | 4 votes |
/**
* Generic text field.
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function TextField<T extends string | number>({
name,
value,
setValue,
error,
showError,
disabled,
autoFocus,
property,
includeDescription,
allowInfinity,
shouldAlwaysRerender
}: TextFieldProps<T>) {
const classes = formStyles();
let mediaType: MediaType | undefined;
let multiline: boolean | undefined;
if (property.dataType === "string") {
const url = (property as StringProperty).config?.url;
mediaType = typeof url === "string" ? url : undefined;
multiline = (property as StringProperty).config?.multiline;
}
useClearRestoreValue({
property,
value,
setValue
});
const isMultiline = !!multiline;
const internalValue = value ?? (property.dataType === "string" ? "" : value === 0 ? 0 : "");
const valueIsInfinity = internalValue === Infinity;
const inputType = !valueIsInfinity && property.dataType === "number" ? "number" : undefined;
const updateValue = (newValue: typeof internalValue | undefined) => {
if (!newValue) {
setValue(
null
);
} else if (inputType === "number") {
const numValue = parseFloat(newValue as string);
setValue(
numValue as T
);
} else {
setValue(
newValue
);
}
};
const filledInput = (
<FilledInput
sx={{
minHeight: "64px"
}}
autoFocus={autoFocus}
type={inputType}
multiline={isMultiline}
inputProps={{
rows: 4
}}
value={valueIsInfinity ? "Infinity" : (value ?? "")}
disabled={disabled}
onChange={(evt) => {
updateValue(evt.target.value as T);
}}
/>
);
return (
<>
<FormControl
variant="filled"
required={property.validation?.required}
error={showError}
disabled={valueIsInfinity}
fullWidth>
<InputLabel
classes={{
root: classes.inputLabel,
shrink: classes.shrinkInputLabel
}}>
<LabelWithIcon property={property}/>
</InputLabel>
{filledInput}
<Box display={"flex"}>
<Box flexGrow={1}>
{showError && <FormHelperText>{error}</FormHelperText>}
{includeDescription &&
<FieldDescription property={property}/>}
</Box>
{allowInfinity &&
<FormControlLabel
checked={valueIsInfinity}
style={{ marginRight: 0 }}
labelPlacement={"start"}
control={
<Switch
size={"small"}
type={"checkbox"}
onChange={(evt) => {
updateValue(
evt.target.checked ? Infinity as T : undefined);
}}/>
}
disabled={disabled}
label={
<Typography variant={"caption"}>
Set value to Infinity
</Typography>
}
/>
}
</Box>
</FormControl>
{mediaType && internalValue &&
<ErrorBoundary>
<Box m={1}>
<PreviewComponent name={name}
value={internalValue}
property={property}
size={"regular"}/>
</Box>
</ErrorBoundary>
}
</>
);
}
Example #21
Source File: index.tsx From Search-Next with GNU General Public License v3.0 | 4 votes |
Release: FC = () => {
const [update, setUpdate] = React.useState(false);
const [remind, setRemind] =
React.useState<AccountUpdateMessageRemind>('popup');
const [interval, setInterval] = React.useState(0);
const [messageData, setMessageData] = React.useState({} as AuthMessage);
const init = () => {
const account = localStorage.getItem('account');
const result = getAuthDataByKey(account ?? '', 'message');
if (isBoolean(result?.update)) {
setUpdate(result.update);
setRemind('popup');
setInterval(0);
} else {
const { update = {} } = result || {};
const {
update: privUpdate = true,
remind = 'popup',
interval = 0,
} = update;
setUpdate(privUpdate);
setRemind(remind);
setInterval(interval);
}
setMessageData(result);
};
const handleUpdate = (key: any, val: any) => {
const account = localStorage.getItem('account');
const updateData: any = {
update,
interval,
remind,
lastTime: dayjs(),
};
updateData[key] = val;
const newMessageData = {
...messageData,
update: updateData,
};
setMessageData(newMessageData);
updateAuthDataByKey(account ?? '', 'message', newMessageData);
init();
};
const onUpdateSwichChange = (
_: React.ChangeEvent<HTMLInputElement>,
checked: boolean,
) => {
setUpdate(checked);
handleUpdate('update', checked);
};
const onRemindChange = (e: SelectChangeEvent<any>) => {
const value = e.target.value as AccountUpdateMessageRemind;
setRemind(value);
handleUpdate('remind', value);
};
const onIntervalChange = (e: SelectChangeEvent<any>) => {
const value = e.target.value as number;
setInterval(value);
handleUpdate('interval', value);
};
useEffect(() => {
init();
}, []);
return (
<div>
<ContentList>
<Alert severity="info">
<AlertTitle>提示</AlertTitle>
修改任意配置都会重置版本更新时间间隔依赖的时间
</Alert>
<ItemCard
title="版本更新提醒"
desc="设置版本更新时是否提醒"
action={<Switch checked={update} onChange={onUpdateSwichChange} />}
/>
<ItemCard
title="提醒方式"
desc="设置版本更新提醒方式"
action={
<Select
size="small"
label="提醒方式"
value={remind}
options={[
{ label: '消息', value: 'message' },
// { label: '通知', value: 'notification' },
{ label: '弹窗', value: 'popup' },
]}
onChange={onRemindChange}
/>
}
/>
<ItemCard
title="提醒间隔"
desc="设置版本更新提醒时间间隔"
action={
<Select
size="small"
label="提醒间隔"
value={interval}
options={[
{ label: '随时', value: 0 },
{ label: '7天', value: 7 },
{ label: '30天', value: 30 },
{ label: '60天', value: 60 },
{ label: '90天', value: 90 },
]}
onChange={onIntervalChange}
/>
}
/>
</ContentList>
</div>
);
}
Example #22
Source File: index.tsx From Search-Next with GNU General Public License v3.0 | 4 votes |
Weather: FC = () => {
let timer: number | undefined; // 定时器(点击授权时检查是否授权)
let lastState: string | undefined; // 上一次的状态(记录单次点击授权最后一次状态,undefined时表示第一次点击)
const userId = localStorage.getItem('account') ?? '';
const [weather, setWeather] = React.useState<QWeatherNow>({} as QWeatherNow);
const [location, setLocation] = React.useState<QWeatherCity>(
{} as QWeatherCity,
);
const [permission, setPermission] = React.useState<boolean>(false);
const [status, setStatus] = React.useState<string>('');
const [geolocationStatus, setGeolocationStatusStatus] =
React.useState<boolean>(false);
const [key, setKey] = useState('');
const [pluginKey, setPluginKey] = useState('');
const [loading, setLoading] = useState(false);
const [latlng, setLatlng] = useState<number[]>([]);
const [weatherInterval, setWeatherInterval] = useState(15);
const [show, setShow] = useState(true);
const refreshOptions = [
{ label: '10分钟', value: 10 },
{ label: '15分钟', value: 15 },
{ label: '30分钟', value: 30 },
];
// 获取当前位置并获取天气
const getCurrentPosition = () => {
geolocation.getCurrentPosition().then((res) => {
const localData = getWeather(userId);
const time = dayjs(localData?.updatedTime ?? localData?.createdTime);
const diff = localData ? dayjs().diff(time, 'minute') > 10 : true;
setKey(localData?.key ?? '');
setPluginKey(localData?.pluginKey ?? '');
if (diff) {
setLatlng([res.longitude, res.latitude]);
getLocationInfo({
key: key ?? localData?.key,
location: res.longitude + ',' + res.latitude,
});
getWeatherInfo({
key: key ?? localData?.key,
location: res.longitude + ',' + res.latitude,
});
} else if (localData) {
localData.weather && setWeather(localData.weather);
localData.city && setLocation(localData.city);
}
});
};
const applyPermission = () => {
if (geolocation.checkGeolocation) {
/* 地理位置服务可用 */
setPermission(true);
geolocation.getPermissionStatus().then((res) => {
if (res === 'granted') {
setGeolocationStatusStatus(true);
getCurrentPosition();
} else {
setGeolocationStatusStatus(false);
}
});
} else {
/* 地理位置服务不可用 */
setPermission(false);
}
};
// 检查授权状态
const checkPermission = () => {
getCurrentPosition();
timer = setInterval(async () => {
geolocation.getPermissionStatus().then((res) => {
setGeolocationStatusStatus(res === 'granted');
setStatus(res);
if (res !== 'prompt') {
clearTimeout(timer);
!lastState && toast.info('已选择位置信息权限,请检查浏览器设置');
return;
}
lastState = res;
});
}, 100);
};
// 获取位置城市信息
const getLocationInfo = (params: QweatherCityParams) => {
setLoading(true);
const { key } = params;
locationInfo(params).then((res) => {
setLocation(key ? res : res.data);
setLoading(false);
});
};
// 获取天气信息
const getWeatherInfo = (params: QweatherNowParams) => {
setLoading(true);
const { key } = params;
qweatherNow(params).then((res) => {
setWeather(key ? res : res.data);
setLoading(false);
});
};
// 获取主页 天气设置
const getWeatherSetting = () => {
const res = getIndexWeatherSetting(userId);
const setting = res?.navBar?.left?.weather;
if (setting) {
setWeatherInterval(setting.interval);
setShow(setting.show);
}
};
useEffect(() => {
applyPermission();
getWeatherSetting();
}, []);
useEffect(() => {
// 保存天气信息前校验是否超过十分钟,填写key时不校验
const localData = getWeather(userId);
const time = dayjs(localData?.updatedTime ?? localData?.createdTime);
const diff = localData ? dayjs().diff(time, 'minute') > 10 : true;
if (
Object.keys(weather).length > 0 &&
Object.keys(location).length > 0 &&
(diff || !!localData?.key)
) {
saveWeather({
userId,
weather: weather,
city: location,
key: key,
latlng,
});
}
}, [weather, location]);
useEffect(() => {
saveIndexWeatherSetting({
userId,
interval: weatherInterval,
show,
});
}, [weatherInterval, show]);
return (
<div>
{geolocationStatus && (
<WeatherCard
apiKey={key}
onRefresh={() => getCurrentPosition()}
weather={weather}
city={location}
loading={loading}
/>
)}
<ContentList>
<ContentTitle title="权限"></ContentTitle>
<ItemAccordion
title="位置访问"
desc="获取用户地理位置信息,用于天气查询"
action={
<Switch
disabled={!permission}
onClick={(e) => e.stopPropagation()}
checked={geolocationStatus}
onChange={(e) => {
checkPermission();
}}
/>
}
>
{!permission && (
<Alert severity="warning">当前浏览器位置访问权限不可用</Alert>
)}
{status === 'granted' && (
<Alert severity="success">已授权位置访问权限</Alert>
)}
{status === 'denied' && (
<Alert severity="error">位置访问权限被拒绝,请检查浏览器设置</Alert>
)}
{status === 'prompt' && (
<Alert severity="info">等待授权位置访问权限</Alert>
)}
</ItemAccordion>
<ContentTitle title="KEY"></ContentTitle>
<Alert severity="info">
<AlertTitle>为什么需要填写KEY?</AlertTitle>
虽然和风天气提供了免费方案,但考虑到使用次数限制,最好的方式是自己申请KEY,然后填写到下方。
当然不填写KEY也可以使用天气功能,但是查询次数会有限制,如果超过限制,则无法使用天气功能。
</Alert>
<ItemAccordion title="和风天气KEY" desc="设置和风天气使用时必须的KEY">
<Alert
severity="warning"
className={css`
margin-bottom: 8px;
`}
>
该KEY仅用作和风天气API使用,不会保存到服务器,请勿将KEY泄露给他人。
</Alert>
<TextField
fullWidth
variant="standard"
label="和风天气API KEY"
placeholder="请输入和风天气API KEY"
value={key}
disabled={!permission}
onChange={(e) => {
setKey(e.target.value);
}}
onBlur={() => {
saveWeather({
userId,
weather: weather,
city: location,
key,
});
}}
error={key.length > 32}
helperText={key.length > 32 ? 'KEY长度不能超过32位' : ''}
></TextField>
<div className="h-3"></div>
<Alert
severity="warning"
className={css`
margin-bottom: 8px;
`}
>
该KEY仅用作和风天气插件使用,不会保存到服务器,请勿将KEY泄露给他人。
</Alert>
<TextField
fullWidth
variant="standard"
label="和风天气插件 KEY"
placeholder="请输入和风天气天气插件 KEY"
value={pluginKey}
disabled={!permission}
onChange={(e) => {
setPluginKey(e.target.value);
}}
onBlur={() => {
saveWeather({
userId,
weather: weather,
city: location,
pluginKey,
});
}}
error={pluginKey.length > 32}
helperText={pluginKey.length > 32 ? 'KEY长度不能超过32位' : ''}
></TextField>
</ItemAccordion>
<ContentTitle title="高级设置" />
<ItemCard
title="刷新时间"
desc="设置天气自动更新时间间隔"
action={
<Select
disabled={!key || !permission}
value={weatherInterval}
onChange={(e) => setWeatherInterval(e.target.value)}
options={refreshOptions}
/>
}
/>
<ItemCard
title="首页展示"
desc="设置首页是否展示天气"
action={
<Switch
disabled={!permission}
checked={show}
onChange={(e) => setShow(e.target.checked)}
/>
}
/>
</ContentList>
<ContentLinkList>
<ContentTitle title="相关链接" />
<Link text="和风天气开发平台" href="https://dev.qweather.com/" />
</ContentLinkList>
</div>
);
}
Example #23
Source File: index.tsx From Search-Next with GNU General Public License v3.0 | 4 votes |
Logo: React.FC = () => {
const [logoData, setLogoData] = React.useState<AuthLogo>({
type: 'clock',
show: true,
zoom: true,
} as AuthLogo);
const [clockLogoData, setClockLogoData] = React.useState<ClockLogo>(
{} as ClockLogo,
);
const initData = () => {
const id = localStorage.getItem('account');
if (!id) return;
const logoData = getAuthDataByKey(id, 'logo');
setClockLogoData(logoData.config.clock);
setLogoData(logoData);
};
const updateLogoData = (data: any) => {
const id = localStorage.getItem('account');
if (!id) return;
const newData = {
...logoData,
...data,
};
const update = updateLogoSetting(id, newData);
if (!update) toast.error('设置logo出现错误');
setClockLogoData(newData.config.clock);
setLogoData(newData);
};
React.useEffect(() => {
initData();
}, []);
return (
<div>
<ContentList>
<ItemCard
title="Logo显示"
desc="设置首页是否显示Logo"
action={
<Switch
checked={logoData?.show}
onChange={(e) => updateLogoData({ show: e.target.checked })}
/>
}
/>
<Alert title="提示" severity="warning">
由于需求调整,Logo缩放功能将在未来删除
</Alert>
<ItemCard
title="Logo缩放"
desc="设置首页Logo在点击搜索框时是否缩放"
action={
<Switch
disabled
checked={logoData?.zoom}
onChange={(e) => updateLogoData({ zoom: e.target.checked })}
/>
}
/>
<ItemCard
title="Logo类型"
desc="设置首页显示Logo的类型"
action={
<Select
label="Logo类型"
size="small"
value={logoData?.type}
onChange={(e) => updateLogoData({ type: e.target.value })}
options={LogoData.filter((i) => i.show).map((i) => ({
value: i.value,
label: i.name,
}))}
></Select>
}
/>
<ItemAccordion title="Logo样式" desc="设置首页显示Logo的样式">
{logoData.type === 'clock' && (
<div className="flex flex-col gap-2">
{ClockData.map((i) => (
<OutlineCard
fullWidth
key={i.id}
id={i.value}
value={clockLogoData.type}
tip={i.tooltip}
label={i.title}
onChange={(val) =>
updateLogoData({
config: {
...logoData.config,
clock: { type: val },
},
})
}
>
<div className="flex justify-center items-center p-2">
{React.createElement(i.component)}
</div>
</OutlineCard>
))}
</div>
)}
{logoData.type === 'image' && (
<AccordionDetailItem
title="在线图片地址"
action={
<TextField
size="small"
label="链接"
value={''}
placeholder="请输入图片链接"
onFocus={() => {}}
onChange={(e) => {}}
onBlur={(e) => {}}
/>
}
/>
)}
{logoData.type !== 'clock' && <Alert severity="info">敬请期待</Alert>}
</ItemAccordion>
</ContentList>
</div>
);
}
Example #24
Source File: SettingsView.tsx From react-flight-tracker with MIT License | 4 votes |
SettingsView: React.FC<Props> = (props) => {
// Fields
const contextName: string = ViewKeys.SettingsView;
// Contexts
const systemContext = useContext(SystemContext);
const appContext = useContext(AppContext);
const getSetting = (key: string, type: string) => {
const value = systemContext.getSetting(key)
if (typeof (value) === type)
return value;
return false;
};
const handleChange = (e: SelectChangeEvent) => {
appContext.changeTheme(e.target.value);
};
const handleSettingsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
systemContext.storeSetting(e.target.name, e.target.checked);
};
const renderAppSettings = () => {
return (
<Card>
<CardContent>
<Typography
variant={'h6'}
gutterBottom={true}>
{'App settings'}
</Typography>
<FormGroup>
<FormControl
color='secondary'
variant="filled"
sx={{ m: 1, minWidth: 120 }}>
<InputLabel
id="demo-simple-select-filled-label">
Theme change
</InputLabel>
<Select
labelId="demo-simple-select-filled-label"
id="demo-simple-select-filled"
value={appContext.activeThemeName}
onChange={handleChange}>
<MenuItem
value={ThemeKeys.DarkTheme}>
{ThemeKeys.DarkTheme}
</MenuItem>
<MenuItem
value={ThemeKeys.LightTheme}>
{ThemeKeys.LightTheme}
</MenuItem>
<MenuItem
value={ThemeKeys.PineappleTheme}>
{ThemeKeys.PineappleTheme}
</MenuItem>
</Select>
</FormControl>
</FormGroup>
</CardContent>
</Card>
);
};
const renderMapSettings = () => {
return (
<Card>
<CardContent>
<Typography
variant={'h6'}
gutterBottom={true}>
{'Map settings'}
</Typography>
<FormGroup>
<FormControlLabel
control={
<Switch
color='secondary'
name={SettingKeys.ShowDataOverlayOnMap}
checked={getSetting(SettingKeys.ShowDataOverlayOnMap, 'boolean')}
onChange={handleSettingsChange} />
}
label="Show data overlay on map"
/>
<FormControlLabel
control={
<Switch
color='secondary'
name={SettingKeys.ShowLogOverlayOnMap}
checked={getSetting(SettingKeys.ShowLogOverlayOnMap, 'boolean')}
onChange={handleSettingsChange} />
}
label="Show log overlay on map"
/>
</FormGroup>
</CardContent>
</Card>
);
};
return (
<ViewContainer
isScrollLocked={true}>
{renderAppSettings()}
<Box sx={{ height: (theme) => theme.spacing(1) }} />
{renderMapSettings()}
</ViewContainer>
);
}
Example #25
Source File: index.tsx From yearn-watch-legacy with GNU Affero General Public License v3.0 | 4 votes |
SearchInput = (props: SearchInputProps) => {
const {
onFilter,
debounceWait,
totalItems,
foundItems,
totalSubItems,
foundSubItems,
} = props;
const [searchText, setSearchText] = useState('');
const [isSearching, setIsSearching] = useState(false);
const [filterVaultsWithWarnings, setFilterVaultsWithWarnings] =
useState(false);
const [healthCheckFilter, setHealthCheckFilter] = useState('');
const debounceFilter = useCallback(
debounce((newSearchText, flags) => {
const newSearchTextLowerCase = newSearchText.toLowerCase();
onFilter(newSearchTextLowerCase, flags, healthCheckFilter);
setIsSearching(false);
}, debounceWait),
[debounceWait, isSearching]
);
// Event listener called on every change
const onChange = useCallback(
(event: ChangeEvent) => {
const value = (event.target as HTMLInputElement).value;
setIsSearching(true);
setSearchText(value);
debounceFilter(value, getCurrentFlags(filterVaultsWithWarnings));
},
[filterVaultsWithWarnings, searchText, isSearching, healthCheckFilter]
);
const onFilterVaultsWithWarnings = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
setFilterVaultsWithWarnings(e.target.checked);
setIsSearching(true);
const newSearchTextLowerCase = searchText.toLowerCase();
onFilter(
newSearchTextLowerCase,
getCurrentFlags(e.target.checked),
healthCheckFilter
);
setIsSearching(false);
},
[searchText, isSearching, healthCheckFilter]
);
const handleClickClearSearch = useCallback(() => {
setSearchText('');
setFilterVaultsWithWarnings(false);
onFilter('', getCurrentFlags(false), '');
}, [onFilter]);
const healthCheckFilterChange = useCallback(
(e: SelectChangeEvent<unknown>) => {
setHealthCheckFilter((e.target as HTMLInputElement).value);
setIsSearching(true);
const newSearchTextLowerCase = searchText.toLowerCase();
onFilter(
newSearchTextLowerCase,
getCurrentFlags(filterVaultsWithWarnings),
(e.target as HTMLInputElement).value
);
setIsSearching(false);
},
[searchText, healthCheckFilter, isSearching]
);
const renderSearchingLabel = useCallback(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let render: any;
if (isSearching) {
render = (
<div>
<ProgressSpinnerBar label="results" />
</div>
);
} else {
render = (
<>
{healthCheckFilter !== '' && (
<WarningLabel
warningText={'HealthCheck Filter is ON!'}
/>
)}
<ResultsLabel
title="Vaults"
totalItems={totalItems}
foundItems={foundItems}
displayFound={true}
isSearching={isSearching}
/>
<ResultsLabel
title="Strategies"
totalItems={totalSubItems}
foundItems={foundSubItems}
displayFound={true}
isSearching={isSearching}
/>
</>
);
}
return render;
}, [isSearching, totalItems, foundItems, totalSubItems, foundSubItems]);
return (
<div>
<StyledForm>
<Grid container direction="row" alignItems="center" spacing={3}>
<Grid item xs={12} sm={6}>
<StyledContainer maxWidth="lg">
<StyledTextField
variant="outlined"
onChange={onChange}
type="search"
value={searchText}
placeholder="Search by vault/strategy address/name, strategist address, token name/symbol, share token symbol/name or API version."
InputProps={
searchText == ''
? {
startAdornment: (
<InputAdornment position="end">
<Search />
</InputAdornment>
),
}
: {
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-label="delete"
onClick={
handleClickClearSearch
}
size="large"
>
<Delete />
</IconButton>
</InputAdornment>
),
}
}
/>
</StyledContainer>
</Grid>
<Grid item xs={12} sm={3}>
<StyledContainer maxWidth="lg">
<StyledFormControlLabel
control={
<Switch
checked={filterVaultsWithWarnings}
onChange={onFilterVaultsWithWarnings}
color="primary"
/>
}
labelPlacement="start"
label="Vaults with warnings"
/>
</StyledContainer>
</Grid>
<Grid item xs={12} sm={3}>
<StyledContainer maxWidth="lg">
<StyledFormControlLabel
control={
<StyledSelect
displayEmpty
variant="standard"
defaultValue=""
value={healthCheckFilter}
onChange={healthCheckFilterChange}
>
<MenuItem value="">All</MenuItem>
<MenuItem value="Enabled">
Enabled
</MenuItem>
<MenuItem value="Disabled">
Disabled
</MenuItem>
<MenuItem value="None">
Not Set
</MenuItem>
</StyledSelect>
}
labelPlacement="start"
label="HealthCheck"
/>
</StyledContainer>
</Grid>
</Grid>
</StyledForm>
<StyledContainerResult maxWidth="lg">
{renderSearchingLabel()}
</StyledContainerResult>
</div>
);
}