@chakra-ui/react#Spacer TypeScript Examples
The following examples show how to use
@chakra-ui/react#Spacer.
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: index.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
StatBox = (
{ title, text, color }:
{ title: string, text: string | number | null, color: string }
): JSX.Element => {
return (
<Box maxW='sm' borderWidth='1px' borderRadius='lg' overflow='hidden' p={5} m={1}>
<Badge borderRadius='full' px='2' colorScheme={color} mb={2}>
{title}
</Badge>
<Spacer />
<Box
color='gray.500'
fontWeight='semibold'
letterSpacing='wide'
>
{(text === null) ? (
<SkeletonText height={20} mt={2} noOfLines={3} />
) : (
(typeof(text) === 'number') ? (
<Text fontSize='2vw'>{formatNumber(text)}</Text>
) : (
<Text fontSize='2vw'>{text}</Text>
)
)}
</Box>
</Box>
);
}
Example #2
Source File: Music.tsx From dope-monorepo with GNU General Public License v3.0 | 6 votes |
SongComponent = (props: { song: Song, musicManager: MusicManager, updateState: React.DispatchWithoutAction }) => <HStack> <Text> {props.song.name} </Text> <Spacer /> <Button // backgroundColor="green" onClick={() => { props.musicManager.shuffle(props.song, undefined, false); props.updateState(); }} variant="primary" disabled={props.song === props.musicManager.currentSong} > Play </Button> </HStack>
Example #3
Source File: Controls.tsx From dope-monorepo with GNU General Public License v3.0 | 6 votes |
Key = (props: {keyName: string, keyCode: number, selectedKey?: number, onSelect: (key?: number) => void}) => {
return (
<HStack>
<Text>
{props.keyName}
</Text>
<Spacer />
<Button
// backgroundColor="green"
onClick={() => props.onSelect(props.selectedKey === props.keyCode ? undefined : props.keyCode)}
variant="primary"
>
{props.selectedKey === props.keyCode ? 'Type a key' : keyCodeToChar[props.keyCode]}
</Button>
</HStack>
)
}
Example #4
Source File: SortHandler.tsx From ke with MIT License | 6 votes |
export function SortHandler({ orderDirection, onChange, headerValue }: SortHandlerProps): JSX.Element {
return (
<Flex>
<Box pr="2">{headerValue}</Box>
<Spacer />
<Center>
<SortDirection value={orderDirection} onChange={onChange} />
</Center>
</Flex>
)
}
Example #5
Source File: DatabaseSettings.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
DatabaseSettings = (): JSX.Element => {
return (
<section>
<Stack direction='column' p={5}>
<Text fontSize='2xl'>Database Settings</Text>
<Divider orientation='horizontal' />
<Spacer />
<PollIntervalField />
</Stack>
</section>
);
}
Example #6
Source File: ResetSettings.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
ResetSettings = (): JSX.Element => {
const alertRef = useRef(null);
const [requiresConfirmation, confirm] = useState((): string | null => {
return null;
});
return (
<Stack direction='column' p={5}>
<Text fontSize='2xl'>Reset Settings</Text>
<Divider orientation='horizontal' />
<Spacer />
<Button
onClick={() => confirm('resetTutorial')}
>
Reset Tutorial
</Button>
<Button
colorScheme={'red'}
onClick={() => confirm('resetApp')}
>
Reset App
</Button>
<ConfirmationDialog
modalRef={alertRef}
onClose={() => confirm(null)}
body={confirmationActions[requiresConfirmation as string]?.message}
onAccept={() => {
confirmationActions[requiresConfirmation as string].func();
}}
isOpen={requiresConfirmation !== null}
/>
</Stack>
);
}
Example #7
Source File: ThemeSettings.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
ThemeSettings = (): JSX.Element => {
return (
<section>
<Stack direction='column' p={5}>
<Text fontSize='2xl'>Theme Settings</Text>
<Divider orientation='horizontal' />
<Spacer />
<UseOledDarkModeField />
</Stack>
</section>
);
}
Example #8
Source File: UpdateSettings.tsx From bluebubbles-server with Apache License 2.0 | 6 votes |
UpdateSettings = (): JSX.Element => {
return (
<section>
<Stack direction='column' p={5}>
<Text fontSize='2xl'>Update Settings</Text>
<Divider orientation='horizontal' />
<Spacer />
<CheckForUpdatesField />
<Spacer />
<AutoInstallUpdatesField />
</Stack>
</section>
);
}
Example #9
Source File: OrderedTable.factory.tsx From ke with MIT License | 6 votes |
function addOrdering(header: HeaderConfig | ReactNode, orderingName: string | number): HeaderConfig {
const normalizedHeader = normalizeHeader(header)
const { value } = normalizedHeader
const orderedValue =
typeof value === 'function' ? (
(columnIndex: number) => (
<Flex>
<Box p="2">{value(columnIndex)}</Box>
<Spacer />
<Center>
<Field name={orderingName} as={Order} />
</Center>
</Flex>
)
) : (
<Flex>
<Box pr="2">{value}</Box>
<Spacer />
<Center>
<Field name={orderingName} as={Order} />
</Center>
</Flex>
)
return {
...normalizedHeader,
value: orderedValue,
}
}
Example #10
Source File: Setup.tsx From bluebubbles-server with Apache License 2.0 | 5 votes |
NavBar = (): JSX.Element => {
const { colorMode, toggleColorMode } = useColorMode();
return (
<Flex
height="20"
alignItems="center"
borderBottomWidth="1px"
borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
justifyContent='space-between'
p={4}
pl={6}
>
<Flex alignItems="center" justifyContent='flex-start'>
<img src={logo} className="logo" alt="logo" height={48} />
<Text fontSize="1xl" ml={2}>BlueBubbles</Text>
</Flex>
<Flex justifyContent='flex-end'>
<HStack spacing={{ base: '0', md: '1' }}>
<Tooltip label="Website Home" aria-label="website-tip">
<Link href="https://bluebubbles.app" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="website" icon={<AiOutlineHome />} />
</Link>
</Tooltip>
<Tooltip label="BlueBubbles Web" aria-label="website-tip">
<Link href="https://bluebubbles.app/web" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="bluebubbles web" icon={<FiMessageCircle />} />
</Link>
</Tooltip>
<Tooltip label="Support Us" aria-label="donate-tip">
<Link href="https://bluebubbles.app/donate" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="donate" icon={<MdOutlineAttachMoney />} />
</Link>
</Tooltip>
<Tooltip label="Join our Discord" aria-label="discord-tip">
<Link href="https://discord.gg/yC4wr38" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="discord" icon={<FaDiscord />} />
</Link>
</Tooltip>
<Tooltip label="Read our Source Code" aria-label="github-tip">
<Link href="https://github.com/BlueBubblesApp" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="github" icon={<FiGithub />} />
</Link>
</Tooltip>
<Spacer />
<Divider orientation="vertical" width={1} height={15} borderColor='gray' />
<Spacer />
<Spacer />
<Spacer />
<FormControl display='flex' alignItems='center'>
<Box mr={2}><MdOutlineDarkMode size={20} /></Box>
<Switch id='theme-mode-toggle' onChange={toggleColorMode} isChecked={colorMode === 'light'} />
<Box ml={2}><MdOutlineLightMode size={20} /></Box>
</FormControl>
</HStack>
</Flex>
</Flex>
);
}
Example #11
Source File: NewsHeader.tsx From dope-monorepo with GNU General Public License v3.0 | 5 votes |
NewsHeader = ({
$paper = 20,
description = PHRASES[getRandomNumber(0, PHRASES.length - 1)],
location = 'DOPECITY',
date,
}: DopePostHeaderProps) => (
<Wrapper>
<Flex padding="12px 0">
<TitleWrapper>
<Text color="#000" fontWeight="normal" marginBottom={0} paddingBottom={0} as="h1">
The Daily Dope
</Text>
<Description>
<Flex height="full">
<Text
fontSize="xs"
textTransform="uppercase"
color="#000"
width="80%"
padding={0}
paddingLeft=".5em"
>
{description}
</Text>
</Flex>
</Description>
</TitleWrapper>
<Spacer />
<Box textAlign="right" paddingRight="20px">
<Flex height="100%" align="center" justify="center" gap="0">
<div>
<Text fontSize="md" paddingBottom="0px" textTransform="uppercase">
{new Date().getHours() > 12 ? 'Evening' : 'Morning'} EDITION
</Text>
<Text
fontSize="sm"
paddingBottom={0}
textTransform="uppercase"
>{`${$paper} $paper`}</Text>
</div>
</Flex>
</Box>
</Flex>
<Box
padding="1 0"
borderBottom="1px solid black"
borderTop="1px solid black"
textAlign="center"
>
<Text
textTransform="uppercase"
padding="4px"
color="#000"
fontSize="xs"
>{`${location} ${format(date ? new Date(date) : new Date(), 'MMMM Y')}`}</Text>
</Box>
</Wrapper>
)
Example #12
Source File: ConnectionSettings.tsx From bluebubbles-server with Apache License 2.0 | 5 votes |
ConnectionSettings = (): JSX.Element => {
const proxyService: string = (useAppSelector(state => state.config.proxy_service) ?? '').toLowerCase().replace(' ', '-');
return (
<Stack direction='column' p={5}>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Text fontSize='2xl'>Connection Settings</Text>
<Popover trigger='hover'>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
<AiOutlineInfoCircle />
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Information</PopoverHeader>
<PopoverBody>
<Text>
These settings will determine how your clients will connect to the server
</Text>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Divider orientation='horizontal' />
<Spacer />
<ProxyServiceField />
<Spacer />
{(proxyService === 'ngrok') ? (<NgrokRegionField />) : null}
<Spacer />
{(proxyService === 'ngrok') ? (<NgrokAuthTokenField />) : null}
<Spacer />
<Divider orientation='horizontal' />
<ServerPasswordField />
<LocalPortField />
<Spacer />
<Accordion allowMultiple>
<AccordionItem>
<AccordionButton>
<Box flex='1' textAlign='left' width="15em">
Advanced Connection Settings
</Box>
<AccordionIcon />
</AccordionButton>
<AccordionPanel pb={4}>
<EncryptCommunicationsField />
<Box m={15} />
{(proxyService === 'dynamic-dns') ? (<UseHttpsField />) : null}
</AccordionPanel>
</AccordionItem>
</Accordion>
</Stack>
);
}
Example #13
Source File: FeatureSettings.tsx From bluebubbles-server with Apache License 2.0 | 5 votes |
FeatureSettings = (): JSX.Element => {
const hideDockIcon = (useAppSelector(state => state.config.hide_dock_icon) ?? false);
const useTerminal = (useAppSelector(state => state.config.start_via_terminal) ?? false);
return (
<section>
<Stack direction='column' p={5}>
<Text fontSize='2xl'>Features</Text>
<Divider orientation='horizontal' />
<Spacer />
<PrivateApiField />
<Spacer />
<AutoCaffeinateField />
<Spacer />
<AutoStartField />
<Spacer />
<FormControl>
<Checkbox id='hide_dock_icon' isChecked={hideDockIcon} onChange={onCheckboxToggle}>Hide Dock Icon</Checkbox>
<FormHelperText>
Hiding the dock icon will not close the app. You can open the app again via the status bar icon.
</FormHelperText>
</FormControl>
<Spacer />
<Accordion allowMultiple>
<AccordionItem>
<AccordionButton>
<Box flex='1' textAlign='left' width="15em">
Advanced Feature Settings
</Box>
<AccordionIcon />
</AccordionButton>
<AccordionPanel pb={4}>
<FormControl>
<Checkbox id='start_via_terminal' isChecked={useTerminal} onChange={onCheckboxToggle}>Always Start via Terminal</Checkbox>
<FormHelperText>
When BlueBubbles starts up, it will auto-reload itself in terminal mode.
When in terminal, type "help" for command information.
</FormHelperText>
</FormControl>
</AccordionPanel>
</AccordionItem>
</Accordion>
</Stack>
</section>
);
}
Example #14
Source File: Music.tsx From dope-monorepo with GNU General Public License v3.0 | 4 votes |
Music = (props: {
musicManager: MusicManager
}) => {
const [, forceUpdate] = React.useReducer((i) => i + 1, 0);
const [ songProgress, setSongProgress ] = React.useState(props.musicManager.currentSong?.song.seek);
React.useEffect(() => {
let intervalId: NodeJS.Timer;
if (props.musicManager.currentSong)
intervalId = setInterval(() => {
setSongProgress(props.musicManager.currentSong!.song.seek);
});
return () => {
clearInterval(intervalId);
}
}, []);
console.log(props.musicManager.soundManager.volume);
return (
<div>
<HStack style={{
alignItems: "stretch",
marginBlock: "1rem",
}}>
{
props.musicManager.currentSong &&
<Container style={{
padding: "0.5rem",
minWidth: "60%",
borderRadius: "7px",
backgroundColor: "rgba(255,255,255,0.5)",
}}>
<HStack>
<div style={{
width: "70%"
}}>
<div>
<Text fontWeight="bold" paddingBottom="0px">
Currently playing
</Text>
<Text paddingBottom="0px">
{props.musicManager.currentSong.name}
</Text>
<Slider
value={songProgress}
onChange={(v) => {
props.musicManager.currentSong?.song.setSeek(v);
}}
max={props.musicManager.currentSong!.song.duration}
width="100%"
>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<SliderThumb style={{
boxShadow: "none"
}} />
</Slider>
</div>
{
props.musicManager.upcomingSong && <div>
<Text fontWeight="bold" paddingBottom="0px">
Upcoming
</Text>
<Text>
{props.musicManager.upcomingSong.name}
</Text>
</div>
}
</div>
<Spacer />
<VStack>
{
<Button variant="primary" onClick={() => {
props.musicManager.currentSong!.song.isPaused ?
props.musicManager.currentSong!.song.resume() :
props.musicManager.currentSong!.song.pause();
forceUpdate();
}}>
{
props.musicManager.currentSong.song.isPaused ? "Resume" : "Pause"
}
</Button>
}
<Button variant="primary" onClick={() => {
props.musicManager.shuffle(undefined, undefined, false);
forceUpdate();
}}>
Skip
</Button>
</VStack>
</HStack>
</Container>
}
<Container style={{
padding: "0.5rem",
borderRadius: "7px",
minHeight: "100%",
backgroundColor: "rgba(255,255,255,0.5)",
}}>
<div>
<div>
<Text fontWeight="bold" paddingBottom="0px">
Volume
</Text>
<Slider
defaultValue={props.musicManager.soundManager.volume * 100}
onChange={(v) => props.musicManager.soundManager.setVolume(v / 100)}
width="70%"
>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<SliderThumb />
</Slider>
</div>
<div>
<Text fontWeight="bold" paddingBottom="0px">
Rate
</Text>
<Slider
defaultValue={props.musicManager.soundManager.rate * 100}
onChange={(v) => props.musicManager.soundManager.setRate(v / 100)}
width="70%"
max={200}
>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<SliderThumb />
</Slider>
</div>
<div>
<Text fontWeight="bold" paddingBottom="0px">
Detune
</Text>
<Slider
defaultValue={props.musicManager.soundManager.detune}
onChange={(v) => props.musicManager.soundManager.setDetune(v)}
width="70%"
max={1200}
min={-1200}
>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
<SliderThumb />
</Slider>
</div>
</div>
</Container>
</HStack>
<SimpleGrid columns={2} spacing={5} paddingBottom="2">
{
props.musicManager.songs.map((song, i) =>
<SongComponent key={i} song={song} musicManager={props.musicManager} updateState={forceUpdate} />)
}
</SimpleGrid>
</div>
)
}
Example #15
Source File: ChatType.tsx From dope-monorepo with GNU General Public License v3.0 | 4 votes |
export default function ChatType(props: Props) {
const [ unreadMessages, setUnreadMessages ] = React.useState(0);
const [ inputText, setInputText ] = React.useState('');
const [ messages, setMessages ] = React.useState(props.messagesStore);
const [ canSendMessage, setCanSendMessage ] = React.useState((props.chatMessageBoxes?.length ?? 0) < 3);
const messagesListRef = React.useRef<HTMLUListElement>(null);
let state = React.useRef({
i: -1,
});
useEffect(() => {
props.manager.events.on('chat_message', (message: DataTypes[NetworkEvents.SERVER_PLAYER_CHAT_MESSAGE]) => {
setMessages(m => [...m, message]);
const lastMessageEl = messagesListRef.current?.lastElementChild as HTMLLIElement;
if (lastMessageEl &&
lastMessageEl?.parentElement?.parentElement && !isVisible(lastMessageEl, lastMessageEl?.parentElement?.parentElement))
setUnreadMessages(u => u + 1);
});
// constantly check chatMessageBoxes size and if it's less than 3, set canSendMessage to true
const interval = setInterval(() => setCanSendMessage((props.chatMessageBoxes?.length ?? 0) < 3));
return () => clearInterval(interval);
}, []);
const handleInputKey = (e: KeyboardEvent) => {
if (e.key === 'Enter' && canSendMessage) handleSubmit(inputText);
else if (e.key === 'Escape')
// send "nothing", chat will get closed & message will not get sent
handleSubmit('');
else if (e.key === 'ArrowUp') {
state.current.i = ++state.current.i % props.precedentMessages.length;
const precedentMessage = props.precedentMessages[state.current.i];
if (precedentMessage) setInputText(precedentMessage);
} else if (e.key === 'ArrowDown') {
// rolling window, wrap around
state.current.i = --state.current.i % props.precedentMessages.length;
if (state.current.i < 0) state.current.i = props.precedentMessages.length - 1;
const precedentMessage = props.precedentMessages[state.current.i];
if (precedentMessage) setInputText(precedentMessage);
}
};
const handleSubmit = (content: string) => {
if (content.length > 150)
return;
props.manager.events.emit('chat_submit', content);
};
return (
<ChakraProvider theme={theme}>
<Container
style={{
position: 'absolute',
backgroundColor: 'rgba(0,0,0,0.7)',
borderRadius: '0.5rem',
boxShadow: '0 0.5rem 1rem rgba(0, 0, 0, 0.7)',
height: '30%',
width: '30%',
left: "1%",
bottom: "1%",
}}>
<Stack style={{
paddingTop: '1rem',
height: '95%',
}}>
<div style={{
display: 'flex',
overflow: 'auto',
flexDirection: 'column-reverse',
marginBottom: '-3%',
}}>
<List ref={messagesListRef} spacing={-2} style={{
}}>
<Text style={{
color: 'blueviolet',
}}>
Welcome to the Dopeverse!
</Text>
{messages.map((message, i) => <ListItem key={i}>
<HStack style={{
opacity: '0.8'
}}>
<Text style={{
color: 'white',
}}>
{message.author}: {message.message}
</Text>
<Spacer />
<Text style={{
color: 'grey',
fontSize: '0.6rem',
}}>
{new Date(message.timestamp).toLocaleString()}
</Text>
</HStack>
</ListItem>)}
</List>
</div>
<Spacer />
<Center>
<Button
style={{
marginRight: '1%',
marginTop: '-10%'
}}
variant="primary"
backgroundColor="red.600"
hidden={inputText.length <= 150}
onClick={() => setInputText(inputText.substring(0, 150))}
>
❌ Message too long
</Button>
<Button
style={{
marginTop: '-10%',
}}
variant="primary"
hidden={unreadMessages === 0}
onClick={(e) => {
setUnreadMessages(0);
e.currentTarget.hidden = true;
if (messagesListRef.current)
(messagesListRef.current as HTMLOListElement).lastElementChild?.scrollIntoView({
behavior: 'smooth',
});
}}
>
⬇️ New message ({unreadMessages})
</Button>
</Center>
<Center>
<InputGroup width="90%" size="md">
<Input
autoFocus={true}
focusBorderColor="white"
onBlur={({ target }) => target.focus()}
pr="4.5rem"
placeholder="Message"
_placeholder={{ color: '#b8b8b8' }}
textColor="#f5f5f5"
value={inputText}
onChange={({ target }) => setInputText(target.value)}
onKeyDown={handleInputKey}
style={{
backgroundColor: 'rgba(0, 0, 0, 0.3)',
}}
/>
<InputRightElement width="4.5rem" style={{ paddingRight: '2%' }}>
<Button h="1.75rem" size="sm" disabled={!canSendMessage} onClick={() => handleSubmit(inputText)}>
Send
</Button>
</InputRightElement>
</InputGroup>
</Center>
</Stack>
</Container>
</ChakraProvider>
);
}
Example #16
Source File: InterestRatesView.tsx From rari-dApp with GNU Affero General Public License v3.0 | 4 votes |
export default function InterestRatesView() {
// name of table in view (current)
const [tableName, setTableName] = useState<InterestRatesTableOptions>(
InterestRatesTableOptions.Lending
);
// search term in TokenSearch component
const [tokenSearchValue, setTokenSearchValue] = useState("");
// information about each token
const [tokenData, setTokenData] = useState<TokenData[]>([]);
// Aave
const aaveReserves = useReserves();
// Compound
const compoundMarkets = useCompoundMarkets();
// Fuse
const { pools: fusePools, markets: fuseMarkets } = useFuseMarkets();
useEffect(() => {
let isUnmounting = false;
async function getTokenData() {
// gather list of all tokens
const allTokens = [
...aaveReserves.map((reserve) => reserve.tokenAddress),
...compoundMarkets.map((market) => market.tokenAddress),
];
// add fuse pools if available
if (fusePools)
allTokens.push(
...fusePools.map((pool) => pool.underlyingTokens).flat()
);
// isolate unique tokens only
const tokenAddresses = [...new Set(allTokens)];
// fetch token data asynchronously
const tokenDataList: TokenData[] = [];
await Promise.all(
tokenAddresses.map(async (address) => {
tokenDataList.push(await fetchTokenDataWithCache(address));
})
);
// sort token data
tokenDataList.sort(
(a, b) =>
tokenAddresses.indexOf(a.address!) -
tokenAddresses.indexOf(b.address!)
);
// set list in state if conditions are met
if (!isUnmounting && tokenDataList.length === tokenAddresses.length)
setTokenData(tokenDataList);
}
getTokenData();
// set isUnmounting to true when unmounting
return () => {
isUnmounting = false;
};
}, [aaveReserves, compoundMarkets, setTokenData, fusePools]);
// token list filtered by search term
const filteredTokenData = useMemo(
() =>
tokenSearchValue === ""
? tokenData
: tokenData // filter token by search term
.filter(
(token) =>
token
.name!.toLowerCase()
.includes(tokenSearchValue.toLowerCase()) ||
token
.symbol!.toLowerCase()
.includes(tokenSearchValue.toLowerCase())
),
[tokenSearchValue, tokenData]
);
const { t } = useTranslation();
return (
<InterestRatesContext.Provider
value={{
selectedTable: tableName,
tokens: filteredTokenData,
fusePools: fusePools,
markets: {
aave: aaveReserves,
compound: compoundMarkets,
fuse: fuseMarkets,
},
marketDataLoaded: aaveReserves.length > 0 && compoundMarkets.length > 0,
}}
>
<Column
width="100%"
mainAxisAlignment="center"
crossAxisAlignment="flex-start"
mt="3"
p={15}
>
{/* TODO (Zane): Add i18n */}
<Heading size="lg" mb="5">
Interest Rates
</Heading>
{tokenData.length === 0 ||
!fusePools ||
!fuseMarkets ||
!aaveReserves ||
!compoundMarkets ? (
<Center w="100%" h="100px">
<Spinner size="xl" />
</Center>
) : (
<>
<Flex w="100%">
<Box flex="3">
<MultiPicker
options={{
lending: t("Lending Rates"),
borrowing: t("Borrowing Rates"),
}}
// set table on change
onChange={(value) =>
setTableName(value as InterestRatesTableOptions)
}
/>
</Box>
<Spacer flex="2" />
<Box flex="3">
<TokenSearch onChange={setTokenSearchValue} />
</Box>
</Flex>
<Box mt="4" w="100%" position="relative">
<InterestRatesTable />
</Box>
</>
)}
</Column>
</InterestRatesContext.Provider>
);
}
Example #17
Source File: top-nav.tsx From notebook with MIT License | 4 votes |
TopNav: React.SFC<TopNavProps> = ({ handleNoteCreate }) => {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<>
<Flex mb={"30px"} align="center">
<HStack>
<Box p="2" as={Link} to="/">
<motion.div whileHover={{ scale: 1.1 }}>
<Heading
as="h1"
size="xl"
bgGradient="linear(to-l, #7928CA,#FF0080)"
bgClip="text"
_focus={{ boxShadow: "none", outline: "none" }}
_hover={{
textDecoration: "none",
bgGradient: "linear(to-r, red.500, yellow.500)"
}}
>
Notebook App
</Heading>
</motion.div>
</Box>
</HStack>
<Spacer />
<Box>
<HStack>
<HStack d={["none", "none", "block"]}>
<Button
leftIcon={<AddIcon />}
bgGradient="linear(to-l, #7928CA,#FF0080)"
_hover={{ bgGradient: "linear(to-r, red.500, yellow.500)" }}
variant="solid"
size="sm"
onClick={onOpen}
>
Add new note
</Button>
<Button
leftIcon={<ArrowRightIcon />}
bgGradient="linear(to-l, #7928CA,#FF0080)"
_hover={{ bgGradient: "linear(to-r, red.500, yellow.500)" }}
variant="solid"
size="sm"
as={Link}
to="/projects"
>
Open source
</Button>
</HStack>
<Box d={["block", "block", "none"]}>
<Menu>
<MenuButton
as={IconButton}
aria-label="Options"
icon={<HamburgerIcon />}
transition="all 0.2s"
size="md"
variant="outline"
_hover={{ bg: "gray.400" }}
_focus={{ boxShadow: "outline" }}
/>
<MenuList fontSize="sm" zIndex={5}>
<MenuItem icon={<AddIcon />} onClick={onOpen}>
{" "}
<Text textShadow="1px 1px #9c1786">Add new note</Text>
</MenuItem>
<MenuDivider />
<MenuItem icon={<ArrowRightIcon />} as={Link} to="/projects">
{" "}
<Text textShadow="1px 1px #9c1786">
Open source repositories
</Text>
</MenuItem>
</MenuList>
</Menu>
</Box>
<ColorModeSwitcher justifySelf="flex-end" />
</HStack>
</Box>
</Flex>
<NoteForm
isOpen={isOpen}
onClose={onClose}
handleNoteCreate={handleNoteCreate}
/>
</>
);
}
Example #18
Source File: LogsLayout.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
LogsLayout = (): JSX.Element => {
const dispatch = useAppDispatch();
const [requiresConfirmation, confirm] = useState((): string | null => {
return null;
});
const alertRef = useRef(null);
let logs = useAppSelector(state => state.logStore.logs);
const showDebug = useAppSelector(state => state.logStore.debug);
// If we don't want to show debug logs, filter them out
if (!showDebug) {
logs = logs.filter(e => e.type !== 'debug');
}
const toggleDebugMode = (e: React.ChangeEvent<HTMLInputElement>) => {
dispatch(setDebug(e.target.checked));
};
return (
<Box p={3} borderRadius={10}>
<Flex flexDirection="column">
<Stack direction='column' p={5}>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Text fontSize='2xl'>Controls</Text>
<Popover trigger='hover'>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
<AiOutlineInfoCircle />
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Information</PopoverHeader>
<PopoverBody>
<Text>
This page will allow you to perform debugging actions on your BlueBubbles server.
As many of you know, software is not perfect, and there will always be edge cases
depending on the environment. These controls allow us to get the information needed, or
take the required actions to solve an issue. It also allows you to "see" into what
the server is doing in the background.
</Text>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Divider orientation='horizontal' />
<Flex flexDirection="row" justifyContent="flex-start">
<Menu>
<MenuButton
as={Button}
rightIcon={<BsChevronDown />}
width="12em"
mr={5}
>
Manage
</MenuButton>
<MenuList>
<MenuItem icon={<VscDebugRestart />} onClick={() => confirm('restartServices')}>
Restart Services
</MenuItem>
<MenuItem icon={<BsBootstrapReboot />} onClick={() => confirm('fullRestart')}>
Full Restart
</MenuItem>
<MenuItem icon={<FiExternalLink />} onClick={() => openLogLocation()}>
Open Log Location
</MenuItem>
<MenuItem icon={<GoFileSubmodule />} onClick={() => openAppLocation()}>
Open App Location
</MenuItem>
<MenuItem icon={<AiOutlineClear />} onClick={() => clearLogs()}>
Clear Logs
</MenuItem>
</MenuList>
</Menu>
<Menu>
<MenuButton
as={Button}
rightIcon={<BsChevronDown />}
width="12em"
mr={5}
>
Debug Actions
</MenuButton>
<MenuList>
<MenuItem icon={<BsTerminal />} onClick={() => confirm('restartViaTerminal')}>
Restart via Terminal
</MenuItem>
<MenuItem icon={<AiOutlineClear />} onClick={() => confirm('clearEventCache')}>
Clear Event Cache
</MenuItem>
</MenuList>
</Menu>
</Flex>
</Stack>
<Stack direction='column' p={5}>
<Text fontSize='2xl'>Debug Logs</Text>
<Divider orientation='horizontal' />
<Spacer />
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Checkbox onChange={(e) => toggleDebugMode(e)} isChecked={showDebug}>Show Debug Logs</Checkbox>
<Popover trigger='hover'>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
<AiOutlineInfoCircle />
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Inforamation</PopoverHeader>
<PopoverBody>
<Text>
Enabling this option will show DEBUG level logs. Leaving
this disabled will only INFO, WARN, and ERROR level logs.
</Text>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Spacer />
<LogsTable logs={logs} />
</Stack>
</Flex>
<ConfirmationDialog
modalRef={alertRef}
onClose={() => confirm(null)}
body={confirmationActions[requiresConfirmation as string]?.message}
onAccept={() => {
if (hasKey(confirmationActions, requiresConfirmation as string)) {
if (confirmationActions[requiresConfirmation as string].shouldDispatch ?? false) {
dispatch(confirmationActions[requiresConfirmation as string].func() as AnyAction);
} else {
confirmationActions[requiresConfirmation as string].func();
}
}
}}
isOpen={requiresConfirmation !== null}
/>
</Box>
);
}
Example #19
Source File: HomeLayout.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
HomeLayout = (): JSX.Element => {
const address = useAppSelector(state => state.config.server_address);
const fcmClient = useAppSelector(state => state.config.fcm_client);
const password = useAppSelector(state => state.config.password);
const port = useAppSelector(state => state.config.socket_port);
const qrCode = fcmClient ? buildQrData(password, address, fcmClient) : null;
return (
<Box p={3} borderRadius={10}>
<Flex flexDirection="column">
<Stack direction='column' p={5}>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Text fontSize='2xl'>Connection Details</Text>
<Popover trigger='hover'>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
<AiOutlineInfoCircle />
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Information</PopoverHeader>
<PopoverBody>
<Text>
This page will detail your current connection details. This includes your
server address and your local port.
</Text>
<br />
<UnorderedList>
<ListItem><strong>Server Address:</strong> This is the address that your clients will connect to</ListItem>
<ListItem><strong>Local Port:</strong> This is the port that the HTTP server is running on,
and the port you will use when port forwarding
for a dynamic DNS
</ListItem>
</UnorderedList>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Divider orientation='horizontal' />
<Spacer />
<Flex flexDirection="row" justifyContent="space-between">
<Stack>
<Flex flexDirection="row" alignItems='center'>
<Text fontSize='md' fontWeight='bold' mr={2}>Server Address: </Text>
{(!address) ? (
<SkeletonText noOfLines={1} />
) : (
<Text fontSize='md'>{address}</Text>
)}
<Tooltip label='Copy Address'>
<IconButton
ml={3}
size='md'
aria-label='Copy Address'
icon={<BiCopy size='22px' />}
onClick={() => copyToClipboard(address)}
/>
</Tooltip>
<Popover placement='bottom' isLazy={true}>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }} >
<Tooltip label='Show QR Code'>
<IconButton
ml={1}
size='md'
aria-label='Show QR Code'
icon={<AiOutlineQrcode size='24px' />}
/>
</Tooltip>
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>QR Code</PopoverHeader>
<PopoverBody>
<Flex justifyContent='center' flexDirection='column' alignItems='center'>
<Text>
Your QR Code contains your server configuration so that clients can connect.
Your QR Code should remain <strong>private</strong> as it contains sensitive information!
</Text>
<Box border="5px solid" borderColor='white' mt={4} height='266px' width='266px' borderRadius='lg' mb={3}>
{/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
{/* @ts-ignore: ts2876 */}
{(qrCode) ? <QRCode value={qrCode as string} /> : null}
</Box>
</Flex>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Flex flexDirection="row">
<Text fontSize='md' fontWeight='bold' mr={2}>Local Port: </Text>
{(!port) ? (
<SkeletonText noOfLines={1} />
) : (
<Text fontSize='md'>{port}</Text>
)}
</Flex>
</Stack>
<Divider orientation="vertical" />
</Flex>
</Stack>
<Stack direction='column' p={5}>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Text fontSize='2xl'>iMessage Highlights</Text>
<Popover trigger='hover'>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
<AiOutlineInfoCircle />
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Information</PopoverHeader>
<PopoverBody>
<Text>
These are just some fun stats that I included to give you a quick "snapshot"
of your iMessage history on the Mac Device. This does not include messages that
are on Apple's servers, only what is local to this device.
</Text>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Divider orientation='horizontal' />
<Spacer />
{ /* Delays are so older systems do not freeze when requesting data from the databases */ }
<SimpleGrid columns={3} spacing={5}>
<TotalMessagesStatBox />
<TopGroupStatBox delay={200} />
<BestFriendStatBox delay={400} />
<DailyMessagesStatBox delay={600} />
<TotalPicturesStatBox delay={800} />
<TotalVideosStatBox delay={1000} />
</SimpleGrid>
</Stack>
</Flex>
</Box>
);
}
Example #20
Source File: GuidesLayout.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
GuidesLayout = (): JSX.Element => {
return (
<Box p={3} borderRadius={10}>
<Stack direction='column' p={5}>
<Text fontSize='2xl'>Help Guides & FAQ</Text>
<Divider orientation='horizontal' />
<Spacer />
<Text fontSize='md' my={5}>
In addition to the links in the navigation bar, use the links below to learn more about BlueBubbles and how to use it!
</Text>
<Spacer />
<Spacer />
<Wrap spacing='30px' mt={5}>
<WrapItem>
<LinkBox as='article' maxW='xs' px='5' pb={5} pt={2} borderWidth='1px' rounded='xl'>
<Text color='gray'>
https://bluebubbles.app/install
</Text>
<Heading size='md' my={2}>
<LinkOverlay href='https://bluebubbles.app/install' target='_blank'>
Installation Guide
</LinkOverlay>
</Heading>
<Text>
Let us help walk you through the full setup of BlueBubbles. This guide will take you step
by step to learn how to setup Google FCM and the BlueBubbles Server.
</Text>
</LinkBox>
</WrapItem>
<WrapItem>
<LinkBox as='article' maxW='xs' px='5' pb={5} pt={2} borderWidth='1px' rounded='xl'>
<Text color='gray'>
https://docs.bluebubbles.app
</Text>
<Heading size='md' my={2}>
<LinkOverlay href='https://docs.bluebubbles.app' target='_blank'>
Documentation & User Guide
</LinkOverlay>
</Heading>
<Text>
Read about what BlueBubbles has to offer, how to set it up, and how to use the plethora
of features. This documentation also provides more links to other useful articles.
</Text>
</LinkBox>
</WrapItem>
<WrapItem>
<LinkBox as='article' maxW='xs' px='5' pb={5} pt={2} borderWidth='1px' rounded='xl'>
<Text color='gray'>
https://bluebubbles.app/faq
</Text>
<Heading size='md' my={2}>
<LinkOverlay href='https://bluebubbles.app/faq' target='_blank'>
FAQ
</LinkOverlay>
</Heading>
<Text>
If you have any questions, someone else has likely already asked them! View our frequently
asked questions to figure out how you may be able to solve an issue.
</Text>
</LinkBox>
</WrapItem>
<WrapItem>
<LinkBox as='article' maxW='xs' px='5' pb={5} pt={2} borderWidth='1px' rounded='xl'>
<Text color='gray'>
https://docs.bluebubbles.app/private-api
</Text>
<Heading size='md' my={2}>
<LinkOverlay href='https://docs.bluebubbles.app/private-api/installation' target='_blank'>
Private API Setup Guide
</LinkOverlay>
</Heading>
<Text>
If you want to have the ability to send reactions, replies, effects, subjects, etc. Read
this guide to figure out how to setup the Private API features.
</Text>
</LinkBox>
</WrapItem>
<WrapItem>
<LinkBox as='article' maxW='xs' px='5' pb={5} pt={2} borderWidth='1px' rounded='xl'>
<Text color='gray'>
https://documenter.getpostman.com
</Text>
<Heading size='md' my={2}>
<LinkOverlay href='https://documenter.getpostman.com/view/765844/UV5RnfwM' target='_blank'>
REST API
</LinkOverlay>
</Heading>
<Text>
If you're a developer looking to utilize the REST API to interact with iMessage in unique
ways, look no further. Perform automation, orchestration, or basic scripting!
</Text>
</LinkBox>
</WrapItem>
<WrapItem>
<LinkBox as='article' maxW='xs' px='5' pb={5} pt={2} borderWidth='1px' rounded='xl'>
<Text color='gray'>
https://bluebubbles.app/web
</Text>
<Heading size='md' my={2}>
<LinkOverlay href='https://bluebubbles.app/web' target='_blank'>
BlueBubbles Web
</LinkOverlay>
</Heading>
<Text>
BlueBubbles is not limited to running on your Android device. It can also be run in your
browser so you can use it on the go! Connect it to this server once setup is complete.
</Text>
</LinkBox>
</WrapItem>
<WrapItem>
<LinkBox as='article' maxW='xs' px='5' pb={5} pt={2} borderWidth='1px' rounded='xl'>
<Text color='gray'>
https://github.com/sponsors/BlueBubblesApp
</Text>
<Heading size='md' my={2}>
<LinkOverlay href='https://github.com/sponsors/BlueBubblesApp' target='_blank'>
Sponsor Us
</LinkOverlay>
</Heading>
<Text>
Sponsor us by contributing a recurring donation to us, through GitHub. A monthly donation
is just another way to help support the developers and help maintain the project!
</Text>
</LinkBox>
</WrapItem>
<WrapItem>
<LinkBox as='article' maxW='xs' px='5' pb={5} pt={2} borderWidth='1px' rounded='xl'>
<Text color='gray'>
https://bluebubbles.app/donate
</Text>
<Heading size='md' my={2}>
<LinkOverlay href='https://bluebubbles.app/donate' target='_blank'>
Support Us
</LinkOverlay>
</Heading>
<Text>
BlueBubbles was created and is currently run by independent engineers in their free time.
Any sort of support is greatly appreciated! This can be monetary, or just a review.
</Text>
</LinkBox>
</WrapItem>
</Wrap>
</Stack>
</Box>
);
}
Example #21
Source File: FcmLayout.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
FcmLayout = (): JSX.Element => {
const dispatch = useAppDispatch();
const alertRef = useRef(null);
const confirmationActions: NodeJS.Dict<any> = {
clearConfiguration: {
message: (
'Are you sure you want to clear your FCM Configuration?<br /><br />' +
'Doing so will prevent notifications from being delivered until ' +
'your configuration is re-loaded'
),
func: async () => {
const success = await clearFcmConfiguration();
if (success) {
dispatch(setConfig({ name: 'fcm_client', 'value': null }));
dispatch(setConfig({ name: 'fcm_server', 'value': null }));
}
}
}
};
const serverLoaded = (useAppSelector(state => state.config.fcm_server !== null) ?? false);
const clientLoaded = (useAppSelector(state => state.config.fcm_client !== null) ?? false);
const [isDragging, setDragging] = useBoolean();
const [errors, setErrors] = useState([] as Array<ErrorItem>);
const [requiresConfirmation, setRequiresConfirmation] = useState(null as string | null);
const alertOpen = errors.length > 0;
const onDrop = async (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
dragCounter = 0;
setDragging.off();
// I'm not sure why, but we need to copy the file data _before_ we read it using the file reader.
// If we do not, the data transfer file list gets set to empty after reading the first file.
const listCopy: Array<Blob> = [];
for (let i = 0; i < e.dataTransfer.files.length; i++) {
listCopy.push(e.dataTransfer.files.item(i) as Blob);
}
// Actually read the files
const errors: Array<ErrorItem> = [];
for (let i = 0; i < listCopy.length; i++) {
try {
const fileStr = await readFile(listCopy[i]);
const validClient = isValidClientConfig(fileStr);
const validServer = isValidServerConfig(fileStr);
const jsonData = JSON.parse(fileStr);
if (validClient) {
const test = isValidFirebaseUrl(jsonData);
if (test) {
await saveFcmClient(jsonData);
dispatch(setConfig({ name: 'fcm_client', 'value': jsonData }));
} else {
throw new Error(
'Your Firebase setup does not have a real-time database enabled. ' +
'Please enable the real-time database in your Firebase Console.'
);
}
} else if (validServer) {
await saveFcmServer(jsonData);
dispatch(setConfig({ name: 'fcm_server', 'value': jsonData }));
} else {
throw new Error('Invalid Google FCM File!');
}
} catch (ex: any) {
errors.push({ id: String(i), message: ex?.message ?? String(ex) });
}
}
if (errors.length > 0) {
setErrors(errors);
}
};
const onDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
if (dragCounter === 0) {
setDragging.on();
}
dragCounter += 1;
};
const onDragOver = (e: React.DragEvent<HTMLDivElement>) => {
e.stopPropagation();
e.preventDefault();
};
const onDragLeave = () => {
dragCounter -= 1;
if (dragCounter === 0) {
setDragging.off();
}
};
const closeAlert = () => {
setErrors([]);
};
const confirm = (confirmationType: string | null) => {
setRequiresConfirmation(confirmationType);
};
return (
<Box
p={3}
borderRadius={10}
onDragEnter={(e) => onDragEnter(e)}
onDragLeave={() => onDragLeave()}
onDragOver={(e) => onDragOver(e)}
onDrop={(e) => onDrop(e)}
>
<Stack direction='column' p={5}>
<Text fontSize='2xl'>Controls</Text>
<Divider orientation='horizontal' />
<Flex flexDirection="row" justifyContent="flex-start">
<Menu>
<MenuButton
as={Button}
rightIcon={<BsChevronDown />}
width="12em"
mr={5}
>
Manage
</MenuButton>
<MenuList>
<MenuItem icon={<FiTrash />} onClick={() => confirm('clearConfiguration')}>
Clear Configuration
</MenuItem>
</MenuList>
</Menu>
</Flex>
</Stack>
<Stack direction='column' p={5}>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Text fontSize='2xl'>Configuration</Text>
<Popover trigger='hover'>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
<AiOutlineInfoCircle />
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Information</PopoverHeader>
<PopoverBody>
<Text>
Drag and drop your JSON configuration files from your Google Firebase Console. If you
do not have these configuration files. Please go to
<span style={{ color: baseTheme.colors.brand.primary }}>
<Link href='https://bluebubbles.app/install' color='brand.primary' target='_blank'> Our Website </Link>
</span>
to learn how.
</Text>
<Text>
These configurations enable the BlueBubbles server to send notifications and other
messages to all of the clients via Google FCM. Google Play Services is required
for Android Devices.
</Text>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Divider orientation='horizontal' />
<Spacer />
<SimpleGrid columns={2} spacing={5}>
<DropZone
text="Drag n' Drop Google Services JSON"
loadedText="Google Services JSON Successfully Loaded!"
isDragging={isDragging}
isLoaded={clientLoaded}
/>
<DropZone
text="Drag n' Drop Admin SDK JSON"
loadedText="Admin SDK JSON Successfully Loaded!"
isDragging={isDragging}
isLoaded={serverLoaded}
/>
</SimpleGrid>
</Stack>
<ErrorDialog
errors={errors}
modalRef={alertRef}
onClose={() => closeAlert()}
isOpen={alertOpen}
/>
<ConfirmationDialog
modalRef={alertRef}
onClose={() => confirm(null)}
body={confirmationActions[requiresConfirmation as string]?.message}
onAccept={() => {
if (hasKey(confirmationActions, requiresConfirmation as string)) {
confirmationActions[requiresConfirmation as string].func();
}
}}
isOpen={requiresConfirmation !== null}
/>
</Box>
);
}
Example #22
Source File: ApiLayout.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
ApiLayout = (): JSX.Element => {
const dialogRef = useRef(null);
const [dialogOpen, setDialogOpen] = useBoolean();
const webhooks = useAppSelector(state => state.webhookStore.webhooks);
return (
<Box p={3} borderRadius={10}>
<Flex flexDirection="column">
<Stack direction='column' p={5}>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Text fontSize='2xl'>API</Text>
<Popover trigger='hover'>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
<AiOutlineInfoCircle />
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Information</PopoverHeader>
<PopoverBody>
<Text>
Learn how you can interact with the API to automate and orchestrate iMessage-related
actions. Our REST API gives you access to the underlying iMessage API in a
more succinct and easy to digest way. We also offer webhooks so you can receive
callbacks from the server.
</Text>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Divider orientation='horizontal' />
<Text>
BlueBubbles offers a high-level REST API to interact with the server, as well as iMessage itself.
With the API, you'll be able to send messages, fetch messages, filter chats, and more! To see what
else you can do in the API, please see the documentation below:
</Text>
<Spacer />
<LinkBox as='article' maxW='sm' px='5' pb={5} pt={2} borderWidth='1px' rounded='xl'>
<Text color='gray'>
https://documenter.getpostman.com
</Text>
<Heading size='sm' mt={2}>
<LinkOverlay href='https://documenter.getpostman.com/view/765844/UV5RnfwM' target='_blank'>
Click to view API documentation
</LinkOverlay>
</Heading>
</LinkBox>
</Stack>
<Stack direction='column' p={5}>
<Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
<Text fontSize='2xl'>Webhooks</Text>
<Popover trigger='hover'>
<PopoverTrigger>
<Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
<AiOutlineInfoCircle />
</Box>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<PopoverHeader>Information</PopoverHeader>
<PopoverBody>
<Text>
Any webhooks registered here will receive a POST request whenever an iMessage event
occurs. The body of the POST request will be a JSON payload containing the type of
event and the event data.
</Text>
</PopoverBody>
</PopoverContent>
</Popover>
</Flex>
<Divider orientation='horizontal' />
<Spacer />
<Box>
<Menu>
<MenuButton
as={Button}
rightIcon={<BsChevronDown />}
width="12em"
>
Manage
</MenuButton>
<MenuList>
<MenuItem icon={<AiOutlinePlus />} onClick={setDialogOpen.on}>
Add Webhook
</MenuItem>
</MenuList>
</Menu>
</Box>
<Spacer />
<WebhooksTable webhooks={webhooks} />
</Stack>
</Flex>
<AddWebhookDialog
modalRef={dialogRef}
isOpen={dialogOpen}
onClose={() => setDialogOpen.off()}
/>
</Box>
);
}
Example #23
Source File: Navigation.tsx From bluebubbles-server with Apache License 2.0 | 4 votes |
MobileNav = ({ onOpen, onNotificationOpen, unreadCount, ...rest }: MobileProps) => {
const { colorMode, toggleColorMode } = useColorMode();
return (
<Flex
ml={{ base: 0, md: 60 }}
px={{ base: 4, md: 4 }}
height="20"
alignItems="center"
borderBottomWidth="1px"
borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
justifyContent={{ base: 'space-between', md: 'flex-end' }}
{...rest}
>
<IconButton
display={{ base: 'flex', md: 'none' }}
onClick={onOpen}
variant="outline"
aria-label="open menu"
icon={<FiMenu />}
/>
<Text display={{ base: 'flex', md: 'none' }} fontSize="2xl" fontFamily="monospace" fontWeight="bold">
<img src={logo} className="logo-small" alt="logo" />
</Text>
<HStack spacing={{ base: '0', md: '1' }}>
<Tooltip label="Website Home" aria-label="website-tip">
<Link href="https://bluebubbles.app" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="website" icon={<AiOutlineHome />} />
</Link>
</Tooltip>
<Tooltip label="BlueBubbles Web" aria-label="website-tip">
<Link href="https://bluebubbles.app/web" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="bluebubbles web" icon={<FiMessageCircle />} />
</Link>
</Tooltip>
<Tooltip label="Sponsor Us" aria-label="sponsor-tip">
<Link href="https://github.com/sponsors/BlueBubblesApp" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="donate" icon={<AiOutlineHeart />} />
</Link>
</Tooltip>
<Tooltip label="Support Us" aria-label="donate-tip">
<Link href="https://bluebubbles.app/donate" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="donate" icon={<MdOutlineAttachMoney />} />
</Link>
</Tooltip>
<Tooltip label="Join our Discord" aria-label="discord-tip">
<Link href="https://discord.gg/yC4wr38" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="discord" icon={<FaDiscord />} />
</Link>
</Tooltip>
<Tooltip label="Read our Source Code" aria-label="github-tip">
<Link href="https://github.com/BlueBubblesApp" style={{ textDecoration: 'none' }} target="_blank">
<IconButton size="lg" variant="ghost" aria-label="github" icon={<FiGithub />} />
</Link>
</Tooltip>
<Box position='relative' float='left'>
<IconButton
size="lg"
verticalAlign='middle'
zIndex={1}
variant="ghost"
aria-label="notifications"
icon={<FiBell />}
onClick={() => onNotificationOpen()}
/>
{(unreadCount > 0) ? (
<Badge
borderRadius='lg'
variant='solid'
colorScheme='red'
position='absolute'
margin={0}
top={1}
right={1}
zIndex={2}
>{unreadCount}</Badge>
) : null}
</Box>
<Spacer />
<Divider orientation="vertical" width={1} height={15} borderColor='gray' />
<Spacer />
<Spacer />
<Spacer />
<FormControl display='flex' alignItems='center'>
<Box mr={2}><MdOutlineDarkMode size={20} /></Box>
<Switch id='theme-mode-toggle' onChange={toggleColorMode} isChecked={colorMode === 'light'} />
<Box ml={2}><MdOutlineLightMode size={20} /></Box>
</FormControl>
</HStack>
</Flex>
);
}