1
0
mirror of https://github.com/checktheroads/hyperglass synced 2024-05-11 05:55:08 +00:00

Refactor React components & update deps

This commit is contained in:
checktheroads
2020-07-05 17:20:10 -07:00
parent 6ea8dfe975
commit 79c271b0ce
56 changed files with 1231 additions and 1272 deletions

View File

@@ -218,8 +218,6 @@ const Cell = ({ data, rawData, longestASN }) => {
const BGPTable = ({ children: data, ...props }) => {
const config = useConfig();
const columns = makeColumns(config.parsed_data_fields);
// const allASN = data.routes.map(r => r.as_path).flat();
// const asLength = longestASNLength(allASN);
return (
<Flex my={8} maxW={["100%", "100%", "100%", "100%"]} w="100%" {...props}>
@@ -235,6 +233,4 @@ const BGPTable = ({ children: data, ...props }) => {
);
};
BGPTable.displayName = "BGPTable";
export default BGPTable;

View File

@@ -5,37 +5,35 @@ import { Text, useColorMode } from "@chakra-ui/core";
const bg = { dark: "white", light: "black" };
const Renderer = ({ hours, minutes, seconds, completed, props }) => {
if (completed) {
return <Text fontSize="xs" />;
} else {
let time = [zeroPad(seconds)];
minutes !== 0 && time.unshift(zeroPad(minutes));
hours !== 0 && time.unshift(zeroPad(hours));
return (
<Text fontSize="xs" color="gray.500">
{props.text}
<Text as="span" fontSize="xs" color={bg[props.colorMode]}>
{time.join(":")}
</Text>
</Text>
);
}
if (completed) {
return <Text fontSize="xs" />;
} else {
let time = [zeroPad(seconds)];
minutes !== 0 && time.unshift(zeroPad(minutes));
hours !== 0 && time.unshift(zeroPad(hours));
return (
<Text fontSize="xs" color="gray.500">
{props.text}
<Text as="span" fontSize="xs" color={bg[props.colorMode]}>
{time.join(":")}
</Text>
</Text>
);
}
};
const CacheTimeout = ({ timeout, text }) => {
const then = timeout * 1000;
const { colorMode } = useColorMode();
return (
<Countdown
date={Date.now() + then}
renderer={Renderer}
daysInHours
text={text}
colorMode={colorMode}
/>
);
const then = timeout * 1000;
const { colorMode } = useColorMode();
return (
<Countdown
date={Date.now() + then}
renderer={Renderer}
daysInHours
text={text}
colorMode={colorMode}
/>
);
};
CacheTimeout.displayName = "CacheTimeout";
export default CacheTimeout;

View File

@@ -4,7 +4,7 @@ import { Flex, useColorMode } from "@chakra-ui/core";
const bg = { light: "white", dark: "original.dark" };
const color = { light: "original.dark", dark: "white" };
const CardBody = ({ onClick = () => false, children, ...props }) => {
export const CardBody = ({ onClick = () => false, children, ...props }) => {
const { colorMode } = useColorMode();
return (
<Flex
@@ -23,7 +23,3 @@ const CardBody = ({ onClick = () => false, children, ...props }) => {
</Flex>
);
};
CardBody.displayName = "CardBody";
export default CardBody;

View File

@@ -1,25 +1,19 @@
import * as React from "react";
import { Flex } from "@chakra-ui/core";
const CardFooter = ({ children, ...props }) => {
return (
<Flex
p={4}
roundedBottomLeft={4}
roundedBottomRight={4}
direction="column"
borderTopWidth="1px"
overflowX="hidden"
overflowY="hidden"
flexDirection="row"
justifyContent="space-between"
{...props}
>
{children}
</Flex>
);
};
CardFooter.displayName = "CardFooter";
export default CardFooter;
export const CardFooter = ({ children, ...props }) => (
<Flex
p={4}
roundedBottomLeft={4}
roundedBottomRight={4}
direction="column"
borderTopWidth="1px"
overflowX="hidden"
overflowY="hidden"
flexDirection="row"
justifyContent="space-between"
{...props}
>
{children}
</Flex>
);

View File

@@ -3,7 +3,7 @@ import { Flex, Text, useColorMode } from "@chakra-ui/core";
const bg = { light: "blackAlpha.50", dark: "whiteAlpha.100" };
const CardHeader = ({ children, ...props }) => {
export const CardHeader = ({ children, ...props }) => {
const { colorMode } = useColorMode();
return (
<Flex
@@ -19,7 +19,3 @@ const CardHeader = ({ children, ...props }) => {
</Flex>
);
};
CardHeader.displayName = "CardHeader";
export default CardHeader;

View File

@@ -1,5 +1,3 @@
import CardBody from "./CardBody";
import CardFooter from "./CardFooter";
import CardHeader from "./CardHeader";
export { CardBody, CardFooter, CardHeader };
export { CardBody } from "./CardBody";
export { CardFooter } from "./CardFooter";
export { CardHeader } from "./CardHeader";

View File

@@ -203,5 +203,4 @@ const ChakraSelect = React.forwardRef(
}
);
ChakraSelect.displayName = "ChakraSelect";
export default ChakraSelect;

View File

@@ -1,26 +1,25 @@
import React from "react";
import { Box, useColorMode, useTheme } from "@chakra-ui/core";
import * as React from "react";
import { Box, useColorMode } from "@chakra-ui/core";
export default ({ children }) => {
const { colorMode } = useColorMode();
const theme = useTheme();
const bg = { dark: theme.colors.gray[800], light: theme.colors.blackAlpha[100] };
const color = { dark: theme.colors.white, light: theme.colors.black };
return (
<Box
fontFamily="mono"
mt={5}
p={3}
border="1px"
borderColor="inherit"
rounded="md"
bg={bg[colorMode]}
color={color[colorMode]}
fontSize="sm"
whiteSpace="pre-wrap"
as="pre"
>
{children}
</Box>
);
const { colorMode } = useColorMode();
const bg = { dark: "gray.800", light: "blackAlpha.100" };
const color = { dark: "white", light: "black" };
return (
<Box
fontFamily="mono"
mt={5}
p={3}
border="1px"
borderColor="inherit"
rounded="md"
bg={bg[colorMode]}
color={color[colorMode]}
fontSize="sm"
whiteSpace="pre-wrap"
as="pre"
>
{children}
</Box>
);
};

View File

@@ -4,38 +4,46 @@ import { Text } from "@chakra-ui/core";
import { components } from "react-select";
import ChakraSelect from "~/components/ChakraSelect";
const CommunitySelect = ({ name, communities, onChange, register, unregister }) => {
const communitySelections = communities.map((c) => {
return { value: c.community, label: c.display_name, description: c.description };
});
const Option = ({ label, data, ...props }) => {
return (
<components.Option {...props}>
<Text>{label}</Text>
<Text fontSize="xs" as="span">
{data.description}
</Text>
</components.Option>
);
const CommunitySelect = ({
name,
communities,
onChange,
register,
unregister
}) => {
const communitySelections = communities.map(c => {
return {
value: c.community,
label: c.display_name,
description: c.description
};
useEffect(() => {
register({ name });
return () => unregister(name);
}, [name, register, unregister]);
});
const Option = ({ label, data, ...props }) => {
return (
<ChakraSelect
innerRef={register}
size="lg"
name={name}
onChange={(e) => {
onChange({ field: name, value: e.value || "" });
}}
options={communitySelections}
components={{ Option }}
/>
<components.Option {...props}>
<Text>{label}</Text>
<Text fontSize="xs" as="span">
{data.description}
</Text>
</components.Option>
);
};
useEffect(() => {
register({ name });
return () => unregister(name);
}, [name, register, unregister]);
return (
<ChakraSelect
innerRef={register}
size="lg"
name={name}
onChange={e => {
onChange({ field: name, value: e.value || "" });
}}
options={communitySelections}
components={{ Option }}
/>
);
};
CommunitySelect.displayName = "CommunitySelect";
export default CommunitySelect;

View File

@@ -1,21 +1,27 @@
import React from "react";
import * as React from "react";
import { Button, Icon, Tooltip, useClipboard } from "@chakra-ui/core";
export default ({ bg = "secondary", copyValue, ...props }) => {
const { onCopy, hasCopied } = useClipboard(copyValue);
return (
<Tooltip hasArrow label="Copy Output" placement="top">
<Button
as="a"
size="sm"
variantColor={bg}
zIndex="dropdown"
onClick={onCopy}
mx={1}
{...props}
>
{hasCopied ? <Icon name="check" size="16px" /> : <Icon name="copy" size="16px" />}
</Button>
</Tooltip>
);
const CopyButton = ({ bg = "secondary", copyValue, ...props }) => {
const { onCopy, hasCopied } = useClipboard(copyValue);
return (
<Tooltip hasArrow label="Copy Output" placement="top">
<Button
as="a"
size="sm"
variantColor={bg}
zIndex="dropdown"
onClick={onCopy}
mx={1}
{...props}
>
{hasCopied ? (
<Icon name="check" size="16px" />
) : (
<Icon name="copy" size="16px" />
)}
</Button>
</Tooltip>
);
};
export default CopyButton;

View File

@@ -1,94 +1,106 @@
import React from "react";
import * as React from "react";
import {
Button,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalCloseButton,
Stack,
Tag,
useDisclosure,
useColorMode,
useTheme,
Button,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalCloseButton,
Stack,
Tag,
useDisclosure,
useColorMode,
useTheme
} from "@chakra-ui/core";
import useConfig from "~/components/HyperglassProvider";
import useMedia from "~/components/MediaProvider";
import CodeBlock from "~/components/CodeBlock";
const prettyMediaSize = { sm: "SMALL", md: "MEDIUM", lg: "LARGE", xl: "X-LARGE" };
const Debugger = () => {
const { isOpen: configOpen, onOpen: onConfigOpen, onClose: configClose } = useDisclosure();
const { isOpen: themeOpen, onOpen: onThemeOpen, onClose: themeClose } = useDisclosure();
const config = useConfig();
const theme = useTheme();
const bg = { light: "white", dark: "black" };
const color = { light: "black", dark: "white" };
const { colorMode } = useColorMode();
const { mediaSize } = useMedia();
const borderColor = { light: "gray.100", dark: "gray.600" };
return (
<>
<Stack
borderWidth="1px"
borderColor={borderColor[colorMode]}
py={4}
px={4}
isInline
position="relative"
left={0}
right={0}
bottom={0}
justifyContent="center"
zIndex={1000}
maxW="100%"
>
<Tag variantColor="gray">{colorMode.toUpperCase()}</Tag>
<Tag variantColor="teal">{prettyMediaSize[mediaSize]}</Tag>
<Button size="sm" variantColor="cyan" onClick={onConfigOpen}>
View Config
</Button>
<Button size="sm" variantColor="purple" onClick={onThemeOpen}>
View Theme
</Button>
</Stack>
<Modal isOpen={configOpen} onClose={configClose} size="full">
<ModalOverlay />
<ModalContent
bg={bg[colorMode]}
color={color[colorMode]}
py={4}
borderRadius="md"
maxW="90%"
>
<ModalHeader>Loaded Configuration</ModalHeader>
<ModalCloseButton />
<ModalBody>
<CodeBlock>{JSON.stringify(config, null, 4)}</CodeBlock>
</ModalBody>
</ModalContent>
</Modal>
<Modal isOpen={themeOpen} onClose={themeClose} size="full">
<ModalOverlay />
<ModalContent
bg={bg[colorMode]}
color={color[colorMode]}
py={4}
borderRadius="md"
maxW="90%"
>
<ModalHeader>Loaded Theme</ModalHeader>
<ModalCloseButton />
<ModalBody>
<CodeBlock>{JSON.stringify(theme, null, 4)}</CodeBlock>
</ModalBody>
</ModalContent>
</Modal>
</>
);
const prettyMediaSize = {
sm: "SMALL",
md: "MEDIUM",
lg: "LARGE",
xl: "X-LARGE"
};
const Debugger = () => {
const {
isOpen: configOpen,
onOpen: onConfigOpen,
onClose: configClose
} = useDisclosure();
const {
isOpen: themeOpen,
onOpen: onThemeOpen,
onClose: themeClose
} = useDisclosure();
const config = useConfig();
const theme = useTheme();
const bg = { light: "white", dark: "black" };
const color = { light: "black", dark: "white" };
const { colorMode } = useColorMode();
const { mediaSize } = useMedia();
const borderColor = { light: "gray.100", dark: "gray.600" };
return (
<>
<Stack
borderWidth="1px"
borderColor={borderColor[colorMode]}
py={4}
px={4}
isInline
position="relative"
left={0}
right={0}
bottom={0}
justifyContent="center"
zIndex={1000}
maxW="100%"
>
<Tag variantColor="gray">{colorMode.toUpperCase()}</Tag>
<Tag variantColor="teal">{prettyMediaSize[mediaSize]}</Tag>
<Button size="sm" variantColor="cyan" onClick={onConfigOpen}>
View Config
</Button>
<Button size="sm" variantColor="purple" onClick={onThemeOpen}>
View Theme
</Button>
</Stack>
<Modal isOpen={configOpen} onClose={configClose} size="full">
<ModalOverlay />
<ModalContent
bg={bg[colorMode]}
color={color[colorMode]}
py={4}
borderRadius="md"
maxW="90%"
>
<ModalHeader>Loaded Configuration</ModalHeader>
<ModalCloseButton />
<ModalBody>
<CodeBlock>{JSON.stringify(config, null, 4)}</CodeBlock>
</ModalBody>
</ModalContent>
</Modal>
<Modal isOpen={themeOpen} onClose={themeClose} size="full">
<ModalOverlay />
<ModalContent
bg={bg[colorMode]}
color={color[colorMode]}
py={4}
borderRadius="md"
maxW="90%"
>
<ModalHeader>Loaded Theme</ModalHeader>
<ModalCloseButton />
<ModalBody>
<CodeBlock>{JSON.stringify(theme, null, 4)}</CodeBlock>
</ModalBody>
</ModalContent>
</Modal>
</>
);
};
Debugger.displayName = "Debugger";
export default Debugger;

View File

@@ -1,33 +1,25 @@
import React, { useState } from "react";
import { Flex, useColorMode, useTheme } from "@chakra-ui/core";
import * as React from "react";
import { useState } from "react";
import { Flex, useColorMode } from "@chakra-ui/core";
import { FiCode } from "react-icons/fi";
import { GoLinkExternal } from "react-icons/go";
import format from "string-format";
import useConfig from "~/components/HyperglassProvider";
import FooterButton from "~/components/FooterButton";
import FooterContent from "~/components/FooterContent";
import FooterButton from "./FooterButton";
import FooterContent from "./FooterContent";
format.extend(String.prototype, {});
const footerBg = { light: "blackAlpha.50", dark: "whiteAlpha.100" };
const footerColor = { light: "black", dark: "white" };
const contentBorder = { light: "blackAlpha.100", dark: "whiteAlpha.200" };
const Footer = () => {
const theme = useTheme();
const config = useConfig();
const { colorMode } = useColorMode();
const footerBg = {
light: theme.colors.blackAlpha[50],
dark: theme.colors.whiteAlpha[100]
};
const footerColor = { light: theme.colors.black, dark: theme.colors.white };
const contentBorder = {
light: theme.colors.blackAlpha[100],
dark: theme.colors.whiteAlpha[200]
};
const [helpVisible, showHelp] = useState(false);
const [termsVisible, showTerms] = useState(false);
const [creditVisible, showCredit] = useState(false);
const extUrl = config.web.external_link.url.includes("{primary_asn}")
? config.web.external_link.url.format({ primary_asn: config.primary_asn })
: config.web.external_link.url || "/";
const handleCollapse = i => {
if (i === "help") {
showTerms(false);
@@ -43,6 +35,9 @@ const Footer = () => {
showTerms(!termsVisible);
}
};
const extUrl = config.web.external_link.url.includes("{primary_asn}")
? config.web.external_link.url.format({ primary_asn: config.primary_asn })
: config.web.external_link.url || "/";
return (
<>
{config.web.help_menu.enable && (
@@ -141,5 +136,4 @@ const Footer = () => {
);
};
Footer.displayName = "Footer";
export default Footer;

View File

@@ -1,4 +1,4 @@
import React from "react";
import * as React from "react";
import { Button, Flex } from "@chakra-ui/core";
import { motion } from "framer-motion";
@@ -28,5 +28,4 @@ const FooterButton = React.forwardRef(
}
);
FooterButton.displayName = "FooterButton";
export default FooterButton;

View File

@@ -0,0 +1,30 @@
import * as React from "react";
import { forwardRef } from "react";
import { Box, Collapse } from "@chakra-ui/core";
import MarkDown from "~/components/MarkDown";
const FooterContent = forwardRef(
({ isOpen = false, content, side = "left", title, ...props }, ref) => {
return (
<Collapse
px={6}
py={4}
w="auto"
ref={ref}
borderBottom="1px"
display="flex"
maxWidth="100%"
isOpen={isOpen}
flexBasis="auto"
justifyContent={side === "left" ? "flex-start" : "flex-end"}
{...props}
>
<Box textAlign={side}>
<MarkDown content={content} />
</Box>
</Collapse>
);
}
);
export default FooterContent;

View File

@@ -0,0 +1,2 @@
import Footer from "./Footer";
export default Footer;

View File

@@ -1,27 +0,0 @@
import React from "react";
import { Box, Collapse } from "@chakra-ui/core";
import MarkDown from "~/components/MarkDown";
export default React.forwardRef(
({ isOpen = false, content, side = "left", title, ...props }, ref) => {
return (
<Collapse
px={6}
py={4}
w="auto"
ref={ref}
borderBottom="1px"
display="flex"
maxWidth="100%"
isOpen={isOpen}
flexBasis="auto"
justifyContent={side === "left" ? "flex-start" : "flex-end"}
{...props}
>
<Box textAlign={side}>
<MarkDown content={content} />
</Box>
</Collapse>
);
}
);

View File

@@ -1,4 +1,4 @@
import React from "react";
import * as React from "react";
import {
Flex,
FormControl,
@@ -7,7 +7,9 @@ import {
useColorMode
} from "@chakra-ui/core";
export default ({
const labelColor = { dark: "whiteAlpha.700", light: "blackAlpha.700" };
const FormField = ({
label,
name,
error,
@@ -21,7 +23,7 @@ export default ({
...props
}) => {
const { colorMode } = useColorMode();
const labelColor = { dark: "whiteAlpha.700", light: "blackAlpha.700" };
return (
<FormControl
as={Flex}
@@ -59,3 +61,5 @@ export default ({
</FormControl>
);
};
export default FormField;

View File

@@ -1,15 +1,15 @@
import * as React from "react";
import {
Button,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
useColorMode,
useDisclosure,
Button,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
useColorMode,
useDisclosure
} from "@chakra-ui/core";
import MarkDown from "~/components/MarkDown";
import { motion } from "framer-motion";
@@ -21,53 +21,51 @@ const AnimatedModalContent = motion.custom(ModalContent);
const AnimatedModalOverlay = motion.custom(ModalOverlay);
const Greeting = ({ greetingConfig, content, onClickThrough }) => {
const { isOpen, onOpen, onClose } = useDisclosure(true);
const { colorMode } = useColorMode();
const { isOpen, onOpen, onClose } = useDisclosure(true);
const { colorMode } = useColorMode();
const handleClick = () => {
onClickThrough(true);
onClose();
};
const handleClick = () => {
onClickThrough(true);
onClose();
};
return (
<Modal
onClose={handleClick}
isOpen={isOpen}
size="full"
isCentered
closeOnOverlayClick={!greetingConfig.required}
closeOnEsc={!greetingConfig.required}
>
<AnimatedModalOverlay
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.3, delay: 0.7 }}
/>
<AnimatedModalContent
initial={{ scale: 0.5, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ duration: 0.3, delay: 0.7 }}
bg={bg[colorMode]}
color={color[colorMode]}
py={4}
borderRadius="md"
maxW={["95%", "75%", "75%", "75%"]}
>
<ModalHeader>{greetingConfig.title}</ModalHeader>
{!greetingConfig.required && <ModalCloseButton />}
<ModalBody>
<MarkDown content={content} />
</ModalBody>
<ModalFooter>
<Button variantColor="primary" onClick={handleClick}>
{greetingConfig.button}
</Button>
</ModalFooter>
</AnimatedModalContent>
</Modal>
);
return (
<Modal
onClose={handleClick}
isOpen={isOpen}
size="full"
isCentered
closeOnOverlayClick={!greetingConfig.required}
closeOnEsc={!greetingConfig.required}
>
<AnimatedModalOverlay
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.3, delay: 0.7 }}
/>
<AnimatedModalContent
initial={{ scale: 0.5, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ duration: 0.3, delay: 0.7 }}
bg={bg[colorMode]}
color={color[colorMode]}
py={4}
borderRadius="md"
maxW={["95%", "75%", "75%", "75%"]}
>
<ModalHeader>{greetingConfig.title}</ModalHeader>
{!greetingConfig.required && <ModalCloseButton />}
<ModalBody>
<MarkDown content={content} />
</ModalBody>
<ModalFooter>
<Button variantColor="primary" onClick={handleClick}>
{greetingConfig.button}
</Button>
</ModalFooter>
</AnimatedModalContent>
</Modal>
);
};
Greeting.displayName = "Greeting";
export default Greeting;

View File

@@ -1,4 +1,4 @@
import React from "react";
import * as React from "react";
import { Flex, useColorMode } from "@chakra-ui/core";
import { motion, AnimatePresence } from "framer-motion";
import ResetButton from "~/components/ResetButton";
@@ -33,12 +33,7 @@ const titleVariants = {
}
};
const icon = { light: "moon", dark: "sun" };
const bg = { light: "white", dark: "black" };
const colorSwitch = {
dark: "Switch to light mode",
light: "Switch to dark mode"
};
const headerTransition = {
type: "spring",
ease: "anticipate",
@@ -107,7 +102,6 @@ const Header = ({ layoutRef, ...props }) => {
}
variants={titleVariants[mediaSize]}
justifyContent={titleJustify[isSubmitting]}
mb={[null, isSubmitting ? "auto" : null]}
mt={[null, isSubmitting ? null : "auto"]}
maxW={widthMap[web.text.title_mode]}
flex="1 0 0"
@@ -168,6 +162,4 @@ const Header = ({ layoutRef, ...props }) => {
);
};
Header.displayName = "Header";
export default Header;

View File

@@ -1,63 +1,73 @@
import React from "react";
import * as React from "react";
import {
IconButton,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalCloseButton,
useDisclosure,
useColorMode,
useTheme
IconButton,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalCloseButton,
useDisclosure,
useColorMode,
useTheme
} from "@chakra-ui/core";
import { motion, AnimatePresence } from "framer-motion";
import MarkDown from "~/components/MarkDown";
const AnimatedIcon = motion.custom(IconButton);
export default ({ item, name }) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const theme = useTheme();
const { colorMode } = useColorMode();
const bg = { light: theme.colors.white, dark: theme.colors.dark };
const color = { light: theme.colors.black, dark: theme.colors.white };
const iconColor = { light: theme.colors.primary[500], dark: theme.colors.primary[300] };
return (
<>
<AnimatePresence>
<AnimatedIcon
initial={{ opacity: 0, scale: 0.3, color: theme.colors.gray[500] }}
animate={{ opacity: 1, scale: 1, color: iconColor[colorMode] }}
transition={{ duration: 0.2 }}
exit={{ opacity: 0, scale: 0.3 }}
variantColor="primary"
aria-label={`${name}_help`}
icon="info-outline"
variant="link"
size="sm"
h="unset"
w={3}
minW={3}
maxW={3}
h={3}
minH={3}
maxH={3}
ml={1}
mb={1}
onClick={onOpen}
/>
</AnimatePresence>
<Modal isOpen={isOpen} onClose={onClose} size="xl">
<ModalOverlay />
<ModalContent bg={bg[colorMode]} color={color[colorMode]} py={4} borderRadius="md">
<ModalHeader>{item.params.title}</ModalHeader>
<ModalCloseButton />
<ModalBody>
<MarkDown content={item.content} />
</ModalBody>
</ModalContent>
</Modal>
</>
);
const HelpModal = ({ item, name }) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const { colors } = useTheme();
const { colorMode } = useColorMode();
const bg = { light: "whiteFaded.50", dark: "blackFaded.800" };
const color = { light: "black", dark: "white" };
const iconColor = {
light: colors.primary[500],
dark: colors.primary[300]
};
return (
<>
<AnimatePresence>
<AnimatedIcon
initial={{ opacity: 0, scale: 0.3, color: colors.gray[500] }}
animate={{ opacity: 1, scale: 1, color: iconColor[colorMode] }}
transition={{ duration: 0.2 }}
exit={{ opacity: 0, scale: 0.3 }}
variantColor="primary"
aria-label={`${name}_help`}
icon="info-outline"
variant="link"
size="sm"
h="unset"
w={3}
minW={3}
maxW={3}
h={3}
minH={3}
maxH={3}
ml={1}
mb={1}
onClick={onOpen}
/>
</AnimatePresence>
<Modal isOpen={isOpen} onClose={onClose} size="xl">
<ModalOverlay />
<ModalContent
bg={bg[colorMode]}
color={color[colorMode]}
py={4}
borderRadius="md"
>
<ModalHeader>{item.params.title}</ModalHeader>
<ModalCloseButton />
<ModalBody>
<MarkDown content={item.content} />
</ModalBody>
</ModalContent>
</Modal>
</>
);
};
export default HelpModal;

View File

@@ -1,5 +1,5 @@
import * as React from "react";
import { useState, useEffect } from "react";
import { forwardRef, useState, useEffect } from "react";
import { Box, Flex } from "@chakra-ui/core";
import { useForm } from "react-hook-form";
import lodash from "lodash";
@@ -53,7 +53,7 @@ const FormRow = ({ children, ...props }) => (
</Flex>
);
const HyperglassForm = React.forwardRef(
const HyperglassForm = forwardRef(
(
{
isSubmitting,
@@ -164,6 +164,8 @@ const HyperglassForm = React.forwardRef(
Object.keys(errors).length >= 1 && console.error(errors);
return (
<Box
as="form"
onSubmit={handleSubmit(onSubmit)}
maxW={["100%", "100%", "75%", "75%"]}
w="100%"
p={0}
@@ -173,111 +175,108 @@ const HyperglassForm = React.forwardRef(
ref={ref}
{...props}
>
<form onSubmit={handleSubmit(onSubmit)}>
<FormRow>
<FormField
<FormRow>
<FormField
label={config.web.text.query_location}
name="query_location"
error={errors.query_location}
>
<QueryLocation
onChange={handleChange}
locations={config.networks}
label={config.web.text.query_location}
name="query_location"
error={errors.query_location}
>
<QueryLocation
onChange={handleChange}
locations={config.networks}
label={config.web.text.query_location}
/>
</FormField>
<FormField
/>
</FormField>
<FormField
label={config.web.text.query_type}
name="query_type"
error={errors.query_type}
labelAddOn={
vrfContent && <HelpModal item={vrfContent} name="query_type" />
}
>
<QueryType
onChange={handleChange}
queryTypes={config.queries.list}
label={config.web.text.query_type}
name="query_type"
error={errors.query_type}
labelAddOn={
vrfContent && <HelpModal item={vrfContent} name="query_type" />
}
/>
</FormField>
</FormRow>
<FormRow>
{availVrfs.length > 1 && (
<FormField
label={config.web.text.query_vrf}
name="query_vrf"
error={errors.query_vrf}
>
<QueryType
<QueryVrf
label={config.web.text.query_vrf}
vrfs={availVrfs}
onChange={handleChange}
queryTypes={config.queries.list}
label={config.web.text.query_type}
/>
</FormField>
</FormRow>
<FormRow>
{availVrfs.length > 1 && (
<FormField
label={config.web.text.query_vrf}
name="query_vrf"
error={errors.query_vrf}
>
<QueryVrf
label={config.web.text.query_vrf}
vrfs={availVrfs}
onChange={handleChange}
/>
</FormField>
)}
<FormField
label={config.web.text.query_target}
name="query_target"
error={errors.query_target}
fieldAddOn={
queryLocation.length !== 0 &&
validFqdnQueryType && (
<ResolvedTarget
queryTarget={queryTarget}
fqdnTarget={validFqdnQueryType}
setTarget={handleChange}
families={families}
availVrfs={availVrfs}
/>
)
}
>
{queryType === "bgp_community" &&
config.queries.bgp_community.mode === "select" ? (
<CommunitySelect
label={config.queries.bgp_community.display_name}
name="query_target"
register={register}
unregister={unregister}
onChange={handleChange}
communities={config.queries.bgp_community.communities}
/>
) : (
<QueryTarget
name="query_target"
placeholder={config.web.text.query_target}
register={register}
unregister={unregister}
resolveTarget={["ping", "traceroute", "bgp_route"].includes(
queryType
)}
value={queryTarget}
setFqdn={setFqdnTarget}
)}
<FormField
label={config.web.text.query_target}
name="query_target"
error={errors.query_target}
fieldAddOn={
queryLocation.length !== 0 &&
validFqdnQueryType && (
<ResolvedTarget
queryTarget={queryTarget}
fqdnTarget={validFqdnQueryType}
setTarget={handleChange}
displayValue={displayTarget}
setDisplayValue={setDisplayTarget}
families={families}
availVrfs={availVrfs}
/>
)}
</FormField>
</FormRow>
<FormRow mt={0} justifyContent="flex-end">
<Flex
w="100%"
maxW="100%"
ml="auto"
my={2}
mr={[0, 0, 2, 2]}
flexDirection="column"
flex="0 0 0"
>
<SubmitButton isLoading={isSubmitting} />
</Flex>
</FormRow>
</form>
)
}
>
{queryType === "bgp_community" &&
config.queries.bgp_community.mode === "select" ? (
<CommunitySelect
label={config.queries.bgp_community.display_name}
name="query_target"
register={register}
unregister={unregister}
onChange={handleChange}
communities={config.queries.bgp_community.communities}
/>
) : (
<QueryTarget
name="query_target"
placeholder={config.web.text.query_target}
register={register}
unregister={unregister}
resolveTarget={["ping", "traceroute", "bgp_route"].includes(
queryType
)}
value={queryTarget}
setFqdn={setFqdnTarget}
setTarget={handleChange}
displayValue={displayTarget}
setDisplayValue={setDisplayTarget}
/>
)}
</FormField>
</FormRow>
<FormRow mt={0} justifyContent="flex-end">
<Flex
w="100%"
maxW="100%"
ml="auto"
my={2}
mr={[0, 0, 2, 2]}
flexDirection="column"
flex="0 0 0"
>
<SubmitButton isLoading={isSubmitting} />
</Flex>
</FormRow>
</Box>
);
}
);
HyperglassForm.displayName = "HyperglassForm";
export default HyperglassForm;

View File

@@ -22,16 +22,16 @@ export const HyperglassProvider = ({ config, children }) => {
const userTheme = value && makeTheme(value.web.theme);
const theme = value ? userTheme : defaultTheme;
return (
<HyperglassContext.Provider value={value}>
<ThemeProvider theme={theme}>
<ColorModeProvider value={config.web.theme.default_color_mode ?? null}>
<CSSReset />
<MediaProvider theme={theme}>
<ThemeProvider theme={theme}>
<ColorModeProvider value={config.web.theme.default_color_mode ?? null}>
<CSSReset />
<MediaProvider theme={theme}>
<HyperglassContext.Provider value={value}>
<StateProvider>{children}</StateProvider>
</MediaProvider>
</ColorModeProvider>
</ThemeProvider>
</HyperglassContext.Provider>
</HyperglassContext.Provider>
</MediaProvider>
</ColorModeProvider>
</ThemeProvider>
);
};

View File

@@ -1,62 +1,62 @@
import React from "react";
import { Flex, useColorMode, useTheme } from "@chakra-ui/core";
import * as React from "react";
import { forwardRef } from "react";
import { Flex, useColorMode } from "@chakra-ui/core";
export default React.forwardRef(
({ value, label, labelColor, valueBg, valueColor, ...props }, ref) => {
const theme = useTheme();
const { colorMode } = useColorMode();
const _labelColor = { dark: "whiteAlpha.700", light: "blackAlpha.700" };
const _valueBg = { light: theme.colors.primary[600], dark: theme.colors.primary[600] };
const _valueColor = { light: "white", dark: "white" };
return (
<Flex
ref={ref}
flexWrap="nowrap"
alignItems="center"
justifyContent="flex-start"
mx={[1, 2, 2, 2]}
my={2}
{...props}
>
<Flex
display="inline-flex"
justifyContent="center"
lineHeight="1.5"
px={[1, 3, 3, 3]}
whiteSpace="nowrap"
mb={2}
mr={0}
bg={valueBg || _valueBg[colorMode]}
color={valueColor || _valueColor[colorMode]}
borderBottomLeftRadius={4}
borderTopLeftRadius={4}
borderBottomRightRadius={0}
borderTopRightRadius={0}
fontWeight="bold"
fontSize={["xs", "sm", "sm", "sm"]}
>
{value}
</Flex>
<Flex
display="inline-flex"
justifyContent="center"
lineHeight="1.5"
px={3}
whiteSpace="nowrap"
mb={2}
ml={0}
mr={0}
boxShadow={`inset 0px 0px 0px 1px ${valueBg || _valueBg[colorMode]}`}
color={labelColor || _labelColor[colorMode]}
borderBottomRightRadius={4}
borderTopRightRadius={4}
borderBottomLeftRadius={0}
borderTopLeftRadius={0}
fontSize={["xs", "sm", "sm", "sm"]}
>
{label}
</Flex>
</Flex>
);
}
const Label = forwardRef(
({ value, label, labelColor, valueBg, valueColor, ...props }, ref) => {
const { colorMode } = useColorMode();
const _labelColor = { dark: "whiteAlpha.700", light: "blackAlpha.700" };
return (
<Flex
ref={ref}
flexWrap="nowrap"
alignItems="center"
justifyContent="flex-start"
mx={[1, 2, 2, 2]}
my={2}
{...props}
>
<Flex
display="inline-flex"
justifyContent="center"
lineHeight="1.5"
px={[1, 3, 3, 3]}
whiteSpace="nowrap"
mb={2}
mr={0}
bg={valueBg || "primary.600"}
color={valueColor || "white"}
borderBottomLeftRadius={4}
borderTopLeftRadius={4}
borderBottomRightRadius={0}
borderTopRightRadius={0}
fontWeight="bold"
fontSize={["xs", "sm", "sm", "sm"]}
>
{value}
</Flex>
<Flex
display="inline-flex"
justifyContent="center"
lineHeight="1.5"
px={3}
whiteSpace="nowrap"
mb={2}
ml={0}
mr={0}
boxShadow={`inset 0px 0px 0px 1px ${valueBg || "primary.600"}`}
color={labelColor || _labelColor[colorMode]}
borderBottomRightRadius={4}
borderTopRightRadius={4}
borderBottomLeftRadius={0}
borderTopLeftRadius={0}
fontSize={["xs", "sm", "sm", "sm"]}
>
{label}
</Flex>
</Flex>
);
}
);
export default Label;

View File

@@ -1,37 +1,36 @@
import React from "react";
import * as React from "react";
import { Flex, Spinner, useColorMode } from "@chakra-ui/core";
const Loading = () => {
const { colorMode } = useColorMode();
const bg = { light: "white", dark: "black" };
const color = { light: "black", dark: "white" };
return (
<Flex
flexDirection="column"
minHeight="100vh"
w="100%"
bg={bg[colorMode]}
color={color[colorMode]}
>
<Flex
as="main"
w="100%"
flexGrow={1}
flexShrink={1}
flexBasis="auto"
alignItems="center"
justifyContent="start"
textAlign="center"
flexDirection="column"
px={2}
py={0}
mt={["50%", "50%", "50%", "25%"]}
>
<Spinner color="primary.500" w="6rem" h="6rem" />
</Flex>
</Flex>
);
const { colorMode } = useColorMode();
const bg = { light: "white", dark: "black" };
const color = { light: "black", dark: "white" };
return (
<Flex
flexDirection="column"
minHeight="100vh"
w="100%"
bg={bg[colorMode]}
color={color[colorMode]}
>
<Flex
as="main"
w="100%"
flexGrow={1}
flexShrink={1}
flexBasis="auto"
alignItems="center"
justifyContent="start"
textAlign="center"
flexDirection="column"
px={2}
py={0}
mt={["50%", "50%", "50%", "25%"]}
>
<Spinner color="primary.500" w="6rem" h="6rem" />
</Flex>
</Flex>
);
};
Loading.displayName = "Loading";
export default Loading;

View File

@@ -1,75 +0,0 @@
import React from "react";
import dynamic from "next/dynamic";
import {
Checkbox as ChakraCheckbox,
Divider,
Code,
Heading as ChakraHeading,
Link as ChakraLink,
List as ChakraList,
ListItem as ChakraListItem,
Spinner,
Text as ChakraText
} from "@chakra-ui/core";
import CustomCodeBlock from "~/components/CodeBlock";
import { TableCell, TableHeader, Table } from "~/components/Table";
// Dynaimc Imports
const ReactMarkdown = dynamic(() => import("react-markdown"), { loading: Spinner });
const Checkbox = ({ checked, children }) => (
<ChakraCheckbox isChecked={checked}>{children}</ChakraCheckbox>
);
const List = ({ ordered, children }) => (
<ChakraList as={ordered ? "ol" : "ul"}>{children}</ChakraList>
);
const ListItem = ({ checked, children }) =>
checked ? (
<Checkbox checked={checked}>{children}</Checkbox>
) : (
<ChakraListItem>{children}</ChakraListItem>
);
const Heading = ({ level, children }) => {
const levelMap = {
1: { as: "h1", size: "lg", fontWeight: "bold" },
2: { as: "h2", size: "lg", fontWeight: "normal" },
3: { as: "h3", size: "lg", fontWeight: "bold" },
4: { as: "h4", size: "md", fontWeight: "normal" },
5: { as: "h5", size: "md", fontWeight: "bold" },
6: { as: "h6", size: "sm", fontWeight: "bold" }
};
return <ChakraHeading {...levelMap[level]}>{children}</ChakraHeading>;
};
const Link = ({ children, ...props }) => (
<ChakraLink isExternal {...props}>
{children}
</ChakraLink>
);
const CodeBlock = ({ value }) => <CustomCodeBlock>{value}</CustomCodeBlock>;
const TableData = ({ isHeader, children, ...props }) => {
const Component = isHeader ? TableHeader : TableCell;
return <Component {...props}>{children}</Component>;
};
const mdComponents = {
paragraph: ChakraText,
link: Link,
heading: Heading,
inlineCode: Code,
list: List,
listItem: ListItem,
thematicBreak: Divider,
code: CodeBlock,
table: Table,
tableCell: TableData
};
export default React.forwardRef(({ content }, ref) => (
<ReactMarkdown ref={ref} renderers={mdComponents} source={content} />
));

View File

@@ -0,0 +1,66 @@
import * as React from "react";
import {
Checkbox as ChakraCheckbox,
Divider as ChakraDivider,
Code as ChakraCode,
Heading as ChakraHeading,
Link as ChakraLink,
List as ChakraList,
ListItem as ChakraListItem,
Text as ChakraText
} from "@chakra-ui/core";
import {
TableCell,
TableHeader,
Table as ChakraTable
} from "~/components/Table";
import CustomCodeBlock from "~/components/CodeBlock";
export const Checkbox = ({ checked, children }) => (
<ChakraCheckbox isChecked={checked}>{children}</ChakraCheckbox>
);
export const List = ({ ordered, children }) => (
<ChakraList as={ordered ? "ol" : "ul"}>{children}</ChakraList>
);
export const ListItem = ({ checked, children }) =>
checked ? (
<Checkbox checked={checked}>{children}</Checkbox>
) : (
<ChakraListItem>{children}</ChakraListItem>
);
export const Heading = ({ level, children }) => {
const levelMap = {
1: { as: "h1", size: "lg", fontWeight: "bold" },
2: { as: "h2", size: "lg", fontWeight: "normal" },
3: { as: "h3", size: "lg", fontWeight: "bold" },
4: { as: "h4", size: "md", fontWeight: "normal" },
5: { as: "h5", size: "md", fontWeight: "bold" },
6: { as: "h6", size: "sm", fontWeight: "bold" }
};
return <ChakraHeading {...levelMap[level]}>{children}</ChakraHeading>;
};
export const Link = ({ children, ...props }) => (
<ChakraLink isExternal {...props}>
{children}
</ChakraLink>
);
export const CodeBlock = ({ value }) => (
<CustomCodeBlock>{value}</CustomCodeBlock>
);
export const TableData = ({ isHeader, children, ...props }) => {
const Component = isHeader ? TableHeader : TableCell;
return <Component {...props}>{children}</Component>;
};
export const Paragraph = props => <ChakraText {...props} />;
export const InlineCode = props => <ChakraCode {...props} />;
export const Divider = props => <ChakraDivider {...props} />;
export const Table = props => <ChakraTable {...props} />;

View File

@@ -0,0 +1,34 @@
import * as React from "react";
import { forwardRef } from "react";
import ReactMarkdown from "react-markdown";
import {
List,
ListItem,
Heading,
Link,
CodeBlock,
TableData,
Paragraph,
InlineCode,
Divider,
Table
} from "./MDComponents";
const mdComponents = {
paragraph: Paragraph,
link: Link,
heading: Heading,
inlineCode: InlineCode,
list: List,
listItem: ListItem,
thematicBreak: Divider,
code: CodeBlock,
table: Table,
tableCell: TableData
};
const Markdown = forwardRef(({ content }, ref) => (
<ReactMarkdown ref={ref} renderers={mdComponents} source={content} />
));
export default Markdown;

View File

@@ -1,4 +1,5 @@
import React, { createContext, useContext, useMemo } from "react";
import * as React from "react";
import { createContext, useContext, useMemo } from "react";
import { useMediaLayout } from "use-media";
const MediaContext = createContext(null);

View File

@@ -1,4 +1,5 @@
import React, { useEffect, useState } from "react";
import * as React from "react";
import { useEffect, useState } from "react";
import Head from "next/head";
import { useTheme } from "@chakra-ui/core";
import useConfig from "~/components/HyperglassProvider";
@@ -9,7 +10,7 @@ const Meta = () => {
const theme = useTheme();
const [location, setLocation] = useState({});
const title = config?.site_title || "hyperglass";
const description = config?.site_description || "The modern looking glass.";
const description = config?.site_description || "Network Looking Glass";
const siteName = `${title} - ${description}`;
const keywords = config?.site_keywords || [
"hyperglass",

View File

@@ -1,4 +1,4 @@
import React from "react";
import * as React from "react";
import ChakraSelect from "~/components/ChakraSelect";
const buildLocations = networks => {
@@ -29,16 +29,15 @@ const QueryLocation = ({ locations, onChange, label }) => {
};
return (
<ChakraSelect
isMulti
size="lg"
options={options}
aria-label={label}
name="query_location"
onChange={handleChange}
options={options}
isMulti
closeMenuOnSelect={false}
aria-label={label}
/>
);
};
QueryLocation.displayName = "QueryLocation";
export default QueryLocation;

View File

@@ -68,5 +68,4 @@ const QueryTarget = ({
);
};
QueryTarget.displayName = "QueryTarget";
export default QueryTarget;

View File

@@ -1,4 +1,4 @@
import React from "react";
import * as React from "react";
import ChakraSelect from "~/components/ChakraSelect";
const QueryType = ({ queryTypes, onChange, label }) => {
@@ -18,5 +18,4 @@ const QueryType = ({ queryTypes, onChange, label }) => {
);
};
QueryType.displayName = "QueryType";
export default QueryType;

View File

@@ -1,17 +1,14 @@
import React from "react";
import * as React from "react";
import ChakraSelect from "~/components/ChakraSelect";
const QueryVrf = ({ vrfs, onChange, label }) => {
return (
<ChakraSelect
size="lg"
onChange={e => onChange({ field: "query_vrf", value: e.value })}
name="query_vrf"
options={vrfs}
aria-label={label}
/>
);
};
const QueryVrf = ({ vrfs, onChange, label }) => (
<ChakraSelect
size="lg"
options={vrfs}
name="query_vrf"
aria-label={label}
onChange={e => onChange({ field: "query_vrf", value: e.value })}
/>
);
QueryVrf.displayName = "QueryVrf";
export default QueryVrf;

View File

@@ -1,20 +1,20 @@
import React from "react";
import * as React from "react";
import { Button, Icon, Tooltip } from "@chakra-ui/core";
export default ({ requery, bg = "secondary", ...props }) => {
return (
<Tooltip hasArrow label="Reload Query" placement="top">
<Button
as="a"
size="sm"
variantColor={bg}
zIndex="1"
onClick={requery}
mx={1}
{...props}
>
<Icon size="16px" name="repeat" />
</Button>
</Tooltip>
);
};
const RequeryButton = ({ requery, bg = "secondary", ...props }) => (
<Tooltip hasArrow label="Reload Query" placement="top">
<Button
mx={1}
as="a"
size="sm"
zIndex="1"
variantColor={bg}
onClick={requery}
{...props}
>
<Icon size="16px" name="repeat" />
</Button>
</Tooltip>
);
export default RequeryButton;

View File

@@ -1,19 +1,18 @@
import React from "react";
import * as React from "react";
import { Button } from "@chakra-ui/core";
import { FiChevronLeft } from "react-icons/fi";
const ResetButton = React.forwardRef(({ isSubmitting, onClick }, ref) => (
<Button
ref={ref}
color="current"
variant="ghost"
onClick={onClick}
aria-label="Reset Form"
opacity={isSubmitting ? 1 : 0}
variant="ghost"
color="current"
onClick={onClick}
>
<FiChevronLeft size={24} />
</Button>
));
ResetButton.displayName = "ResetButton";
export default ResetButton;

View File

@@ -1,6 +1,15 @@
import React, { useEffect } from "react";
import { Button, Icon, Spinner, Stack, Tag, Text, Tooltip, useColorMode } from "@chakra-ui/core";
import axios from "axios";
import * as React from "react";
import { forwardRef, useEffect } from "react";
import {
Button,
Icon,
Spinner,
Stack,
Tag,
Text,
Tooltip,
useColorMode
} from "@chakra-ui/core";
import useAxios from "axios-hooks";
import format from "string-format";
import useConfig from "~/components/HyperglassProvider";
@@ -10,150 +19,164 @@ format.extend(String.prototype, {});
const labelBg = { dark: "secondary", light: "secondary" };
const labelBgSuccess = { dark: "success", light: "success" };
async function containingPrefix(ipAddress) {
try {
const prefixData = await axios.get("https://stat.ripe.net/data/network-info/data.json", {
params: { resource: ipAddress },
});
return prefixData.data?.data?.prefix;
} catch (err) {
console.dir(err);
return null;
}
}
const ResolvedTarget = forwardRef(
({ fqdnTarget, setTarget, queryTarget, families, availVrfs }, ref) => {
const { colorMode } = useColorMode();
const config = useConfig();
const labelBgStatus = {
true: labelBgSuccess[colorMode],
false: labelBg[colorMode]
};
const dnsUrl = config.web.dns_provider.url;
const query4 = families.includes(4);
const query6 = families.includes(6);
const params = {
4: {
url: dnsUrl,
params: { name: fqdnTarget, type: "A" },
headers: { accept: "application/dns-json" },
crossdomain: true,
timeout: 1000
},
6: {
url: dnsUrl,
params: { name: fqdnTarget, type: "AAAA" },
headers: { accept: "application/dns-json" },
crossdomain: true,
timeout: 1000
}
};
const ResolvedTarget = React.forwardRef(
({ fqdnTarget, setTarget, queryTarget, families, availVrfs }, ref) => {
const { colorMode } = useColorMode();
const config = useConfig();
const labelBgStatus = { true: labelBgSuccess[colorMode], false: labelBg[colorMode] };
const dnsUrl = config.web.dns_provider.url;
const query4 = families.includes(4);
const query6 = families.includes(6);
const params = {
4: {
url: dnsUrl,
params: { name: fqdnTarget, type: "A" },
headers: { accept: "application/dns-json" },
crossdomain: true,
timeout: 1000,
},
6: {
url: dnsUrl,
params: { name: fqdnTarget, type: "AAAA" },
headers: { accept: "application/dns-json" },
crossdomain: true,
timeout: 1000,
},
};
const [{ data: data4, loading: loading4, error: error4 }] = useAxios(
params[4]
);
const [{ data: data4, loading: loading4, error: error4 }] = useAxios(params[4]);
const [{ data: data6, loading: loading6, error: error6 }] = useAxios(
params[6]
);
const [{ data: data6, loading: loading6, error: error6 }] = useAxios(params[6]);
const handleOverride = overridden => {
setTarget({ field: "query_target", value: overridden });
};
const handleOverride = (overridden) => {
setTarget({ field: "query_target", value: overridden });
};
const isSelected = value => {
return labelBgStatus[value === queryTarget];
};
const isSelected = (value) => {
return labelBgStatus[value === queryTarget];
};
const findAnswer = data => {
return data?.Answer?.filter(
answerData => answerData.type === data?.Question[0]?.type
)[0]?.data;
};
const findAnswer = (data) => {
return data?.Answer?.filter(
(answerData) => answerData.type === data?.Question[0]?.type
)[0]?.data;
};
useEffect(() => {
if (query6 && data6?.Answer) {
handleOverride(findAnswer(data6));
} else if (query4 && data4?.Answer && !query6 && !data6?.Answer) {
handleOverride(findAnswer(data4));
} else if (query4 && data4?.Answer) {
handleOverride(findAnswer(data4));
}
}, [data4, data6]);
return (
<Stack
ref={ref}
isInline
w="100%"
justifyContent={
query4 && data4?.Answer && query6 && data6?.Answer && availVrfs.length > 1
? "space-between"
: "flex-end"
}
flexWrap="wrap"
>
{loading4 ||
error4 ||
(query4 && findAnswer(data4) && (
<Tag my={2}>
<Tooltip
hasArrow
label={config.web.text.fqdn_tooltip.format({ protocol: "IPv4" })}
placement="bottom"
>
<Button
height="unset"
minW="unset"
fontSize="xs"
py="0.1rem"
px={2}
mr={2}
variantColor={labelBgStatus[findAnswer(data4) === queryTarget]}
borderRadius="md"
onClick={() => handleOverride(findAnswer(data4))}
>
IPv4
</Button>
</Tooltip>
{loading4 && <Spinner />}
{error4 && <Icon name="warning" />}
{findAnswer(data4) && (
<Text fontSize="xs" fontFamily="mono" as="span" fontWeight={400}>
{findAnswer(data4)}
</Text>
)}
</Tag>
))}
{loading6 ||
error6 ||
(query6 && findAnswer(data6) && (
<Tag my={2}>
<Tooltip
hasArrow
label={config.web.text.fqdn_tooltip.format({ protocol: "IPv6" })}
placement="bottom"
>
<Button
height="unset"
minW="unset"
fontSize="xs"
py="0.1rem"
px={2}
mr={2}
variantColor={isSelected(findAnswer(data6))}
borderRadius="md"
onClick={() => handleOverride(findAnswer(data6))}
>
IPv6
</Button>
</Tooltip>
{loading6 && <Spinner />}
{error6 && <Icon name="warning" />}
{findAnswer(data6) && (
<Text fontSize="xs" fontFamily="mono" as="span" fontWeight={400}>
{findAnswer(data6)}
</Text>
)}
</Tag>
))}
</Stack>
);
}
useEffect(() => {
if (query6 && data6?.Answer) {
handleOverride(findAnswer(data6));
} else if (query4 && data4?.Answer && !query6 && !data6?.Answer) {
handleOverride(findAnswer(data4));
} else if (query4 && data4?.Answer) {
handleOverride(findAnswer(data4));
}
}, [data4, data6]);
return (
<Stack
ref={ref}
isInline
w="100%"
justifyContent={
query4 &&
data4?.Answer &&
query6 &&
data6?.Answer &&
availVrfs.length > 1
? "space-between"
: "flex-end"
}
flexWrap="wrap"
>
{loading4 ||
error4 ||
(query4 && findAnswer(data4) && (
<Tag my={2}>
<Tooltip
hasArrow
label={config.web.text.fqdn_tooltip.format({
protocol: "IPv4"
})}
placement="bottom"
>
<Button
height="unset"
minW="unset"
fontSize="xs"
py="0.1rem"
px={2}
mr={2}
variantColor={
labelBgStatus[findAnswer(data4) === queryTarget]
}
borderRadius="md"
onClick={() => handleOverride(findAnswer(data4))}
>
IPv4
</Button>
</Tooltip>
{loading4 && <Spinner />}
{error4 && <Icon name="warning" />}
{findAnswer(data4) && (
<Text
fontSize="xs"
fontFamily="mono"
as="span"
fontWeight={400}
>
{findAnswer(data4)}
</Text>
)}
</Tag>
))}
{loading6 ||
error6 ||
(query6 && findAnswer(data6) && (
<Tag my={2}>
<Tooltip
hasArrow
label={config.web.text.fqdn_tooltip.format({
protocol: "IPv6"
})}
placement="bottom"
>
<Button
height="unset"
minW="unset"
fontSize="xs"
py="0.1rem"
px={2}
mr={2}
variantColor={isSelected(findAnswer(data6))}
borderRadius="md"
onClick={() => handleOverride(findAnswer(data6))}
>
IPv6
</Button>
</Tooltip>
{loading6 && <Spinner />}
{error6 && <Icon name="warning" />}
{findAnswer(data6) && (
<Text
fontSize="xs"
fontFamily="mono"
as="span"
fontWeight={400}
>
{findAnswer(data6)}
</Text>
)}
</Tag>
))}
</Stack>
);
}
);
ResolvedTarget.displayName = "ResolvedTarget";
export default ResolvedTarget;

View File

@@ -1,6 +1,6 @@
/** @jsx jsx */
import { jsx } from "@emotion/core";
import { useEffect, useState } from "react";
import { forwardRef, useEffect, useState } from "react";
import {
AccordionItem,
AccordionHeader,
@@ -78,7 +78,7 @@ const scrollbar = { dark: "whiteAlpha.300", light: "blackAlpha.300" };
const scrollbarHover = { dark: "whiteAlpha.400", light: "blackAlpha.400" };
const scrollbarBg = { dark: "whiteAlpha.50", light: "blackAlpha.50" };
const Result = React.forwardRef(
const Result = forwardRef(
(
{
device,
@@ -276,5 +276,4 @@ const Result = React.forwardRef(
}
);
Result.displayName = "HyperglassQueryResult";
export default Result;

View File

@@ -1,4 +1,5 @@
import React from "react";
import * as React from "react";
import { forwardRef } from "react";
import {
AccordionIcon,
Icon,
@@ -31,7 +32,7 @@ const defaultStatusColor = {
light: "success.500"
};
export default React.forwardRef(
const ResultHeader = forwardRef(
({ title, loading, error, errorMsg, errorLevel, runtime }, ref) => {
const { colorMode } = useColorMode();
const config = useConfig();
@@ -68,3 +69,5 @@ export default React.forwardRef(
);
}
);
export default ResultHeader;

View File

@@ -1,4 +1,5 @@
import React, { useState } from "react";
import * as React from "react";
import { useState } from "react";
import { Accordion, Box, Stack, useTheme } from "@chakra-ui/core";
import { motion, AnimatePresence } from "framer-motion";
import Label from "~/components/Label";
@@ -10,148 +11,155 @@ const AnimatedResult = motion.custom(Result);
const AnimatedLabel = motion.custom(Label);
const labelInitial = {
left: {
sm: { opacity: 0, x: -100 },
md: { opacity: 0, x: -100 },
lg: { opacity: 0, x: -100 },
xl: { opacity: 0, x: -100 }
},
center: {
sm: { opacity: 0 },
md: { opacity: 0 },
lg: { opacity: 0 },
xl: { opacity: 0 }
},
right: {
sm: { opacity: 0, x: 100 },
md: { opacity: 0, x: 100 },
lg: { opacity: 0, x: 100 },
xl: { opacity: 0, x: 100 }
}
left: {
sm: { opacity: 0, x: -100 },
md: { opacity: 0, x: -100 },
lg: { opacity: 0, x: -100 },
xl: { opacity: 0, x: -100 }
},
center: {
sm: { opacity: 0 },
md: { opacity: 0 },
lg: { opacity: 0 },
xl: { opacity: 0 }
},
right: {
sm: { opacity: 0, x: 100 },
md: { opacity: 0, x: 100 },
lg: { opacity: 0, x: 100 },
xl: { opacity: 0, x: 100 }
}
};
const labelAnimate = {
left: {
sm: { opacity: 1, x: 0 },
md: { opacity: 1, x: 0 },
lg: { opacity: 1, x: 0 },
xl: { opacity: 1, x: 0 }
},
center: {
sm: { opacity: 1 },
md: { opacity: 1 },
lg: { opacity: 1 },
xl: { opacity: 1 }
},
right: {
sm: { opacity: 1, x: 0 },
md: { opacity: 1, x: 0 },
lg: { opacity: 1, x: 0 },
xl: { opacity: 1, x: 0 }
}
left: {
sm: { opacity: 1, x: 0 },
md: { opacity: 1, x: 0 },
lg: { opacity: 1, x: 0 },
xl: { opacity: 1, x: 0 }
},
center: {
sm: { opacity: 1 },
md: { opacity: 1 },
lg: { opacity: 1 },
xl: { opacity: 1 }
},
right: {
sm: { opacity: 1, x: 0 },
md: { opacity: 1, x: 0 },
lg: { opacity: 1, x: 0 },
xl: { opacity: 1, x: 0 }
}
};
const Results = ({ queryLocation, queryType, queryVrf, queryTarget, setSubmitting, ...props }) => {
const config = useConfig();
const theme = useTheme();
const { mediaSize } = useMedia();
const matchedVrf =
config.vrfs.filter(v => v.id === queryVrf)[0] ??
config.vrfs.filter(v => v.id === "default")[0];
const [resultsComplete, setComplete] = useState(null);
return (
<>
<Box
maxW={["100%", "100%", "75%", "50%"]}
w="100%"
p={0}
mx="auto"
my={4}
textAlign="left"
{...props}
>
<Stack isInline align="center" justify="center" mt={4} flexWrap="wrap">
<AnimatePresence>
{queryLocation && (
<>
<AnimatedLabel
initial={labelInitial.left[mediaSize]}
animate={labelAnimate.left[mediaSize]}
transition={{ duration: 0.3, delay: 0.3 }}
exit={{ opacity: 0, x: -100 }}
label={config.web.text.query_type}
value={config.queries[queryType].display_name}
valueBg={theme.colors.cyan[500]}
fontSize={["xs", "sm", "sm", "sm"]}
/>
<AnimatedLabel
initial={labelInitial.center[mediaSize]}
animate={labelAnimate.center[mediaSize]}
transition={{ duration: 0.3, delay: 0.3 }}
exit={{ opacity: 0, scale: 0.5 }}
label={config.web.text.query_target}
value={queryTarget}
valueBg={theme.colors.teal[600]}
fontSize={["xs", "sm", "sm", "sm"]}
/>
<AnimatedLabel
initial={labelInitial.right[mediaSize]}
animate={labelAnimate.right[mediaSize]}
transition={{ duration: 0.3, delay: 0.3 }}
exit={{ opacity: 0, x: 100 }}
label={config.web.text.query_vrf}
value={matchedVrf.display_name}
valueBg={theme.colors.blue[500]}
fontSize={["xs", "sm", "sm", "sm"]}
/>
</>
)}
</AnimatePresence>
</Stack>
</Box>
<Box
maxW={["100%", "100%", "75%", "75%"]}
w="100%"
p={0}
mx="auto"
my={4}
textAlign="left"
borderWidth="1px"
rounded="lg"
overflow="hidden"
>
<Accordion
allowMultiple
initial={{ opacity: 1 }}
transition={{ duration: 0.3 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 300 }}
>
<AnimatePresence>
{queryLocation &&
queryLocation.map((loc, i) => (
<AnimatedResult
initial={{ opacity: 0, y: 300 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, delay: i * 0.3 }}
exit={{ opacity: 0, y: 300 }}
key={loc}
timeout={config.request_timeout * 1000}
device={config.devices[loc]}
queryLocation={loc}
queryType={queryType}
queryVrf={queryVrf}
queryTarget={queryTarget}
setSubmitting={setSubmitting}
index={i}
resultsComplete={resultsComplete}
setComplete={setComplete}
/>
))}
</AnimatePresence>
</Accordion>
</Box>
</>
);
const Results = ({
queryLocation,
queryType,
queryVrf,
queryTarget,
setSubmitting,
...props
}) => {
const config = useConfig();
const theme = useTheme();
const { mediaSize } = useMedia();
const matchedVrf =
config.vrfs.filter(v => v.id === queryVrf)[0] ??
config.vrfs.filter(v => v.id === "default")[0];
const [resultsComplete, setComplete] = useState(null);
return (
<>
<Box
maxW={["100%", "100%", "75%", "50%"]}
w="100%"
p={0}
mx="auto"
my={4}
textAlign="left"
{...props}
>
<Stack isInline align="center" justify="center" mt={4} flexWrap="wrap">
<AnimatePresence>
{queryLocation && (
<>
<AnimatedLabel
initial={labelInitial.left[mediaSize]}
animate={labelAnimate.left[mediaSize]}
transition={{ duration: 0.3, delay: 0.3 }}
exit={{ opacity: 0, x: -100 }}
label={config.web.text.query_type}
value={config.queries[queryType].display_name}
valueBg={theme.colors.cyan[500]}
fontSize={["xs", "sm", "sm", "sm"]}
/>
<AnimatedLabel
initial={labelInitial.center[mediaSize]}
animate={labelAnimate.center[mediaSize]}
transition={{ duration: 0.3, delay: 0.3 }}
exit={{ opacity: 0, scale: 0.5 }}
label={config.web.text.query_target}
value={queryTarget}
valueBg={theme.colors.teal[600]}
fontSize={["xs", "sm", "sm", "sm"]}
/>
<AnimatedLabel
initial={labelInitial.right[mediaSize]}
animate={labelAnimate.right[mediaSize]}
transition={{ duration: 0.3, delay: 0.3 }}
exit={{ opacity: 0, x: 100 }}
label={config.web.text.query_vrf}
value={matchedVrf.display_name}
valueBg={theme.colors.blue[500]}
fontSize={["xs", "sm", "sm", "sm"]}
/>
</>
)}
</AnimatePresence>
</Stack>
</Box>
<Box
maxW={["100%", "100%", "75%", "75%"]}
w="100%"
p={0}
mx="auto"
my={4}
textAlign="left"
borderWidth="1px"
rounded="lg"
overflow="hidden"
>
<Accordion
allowMultiple
initial={{ opacity: 1 }}
transition={{ duration: 0.3 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 300 }}
>
<AnimatePresence>
{queryLocation &&
queryLocation.map((loc, i) => (
<AnimatedResult
initial={{ opacity: 0, y: 300 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, delay: i * 0.3 }}
exit={{ opacity: 0, y: 300 }}
key={loc}
timeout={config.request_timeout * 1000}
device={config.devices[loc]}
queryLocation={loc}
queryType={queryType}
queryVrf={queryVrf}
queryTarget={queryTarget}
setSubmitting={setSubmitting}
index={i}
resultsComplete={resultsComplete}
setComplete={setComplete}
/>
))}
</AnimatePresence>
</Accordion>
</Box>
</>
);
};
Results.displayName = "HyperglassResults";

View File

@@ -1,4 +1,5 @@
import React from "react";
import * as React from "react";
import { forwardRef } from "react";
import {
Box,
PseudoBox,
@@ -54,7 +55,11 @@ const btnSizeMap = {
}
};
const SubmitButton = React.forwardRef(
const btnBg = { dark: "primary.300", light: "primary.500" };
const btnBgActive = { dark: "primary.400", light: "primary.600" };
const btnBgHover = { dark: "primary.200", light: "primary.400" };
const SubmitButton = forwardRef(
(
{
isLoading = false,
@@ -71,18 +76,6 @@ const SubmitButton = React.forwardRef(
const _isDisabled = isDisabled || isLoading;
const { colorMode } = useColorMode();
const theme = useTheme();
const btnBg = {
dark: theme.colors.primary[300],
light: theme.colors.primary[500]
};
const btnBgActive = {
dark: theme.colors.primary[400],
light: theme.colors.primary[600]
};
const btnBgHover = {
dark: theme.colors.primary[200],
light: theme.colors.primary[400]
};
const btnColor = opposingColor(theme, btnBg[colorMode]);
const btnColorActive = opposingColor(theme, btnBgActive[colorMode]);
const btnColorHover = opposingColor(theme, btnBgHover[colorMode]);
@@ -126,5 +119,4 @@ const SubmitButton = React.forwardRef(
}
);
SubmitButton.displayName = "SubmitButton";
export default SubmitButton;

View File

@@ -1,24 +1,37 @@
import React from "react";
import * as React from "react";
import { Box, useColorMode } from "@chakra-ui/core";
const Table = props => <Box as="table" textAlign="left" mt={4} width="full" {...props} />;
const Table = props => (
<Box as="table" textAlign="left" mt={4} width="full" {...props} />
);
const bg = { light: "blackAlpha.50", dark: "whiteAlpha.50" };
const TableHeader = props => {
const { colorMode } = useColorMode();
const bg = { light: "blackAlpha.50", dark: "whiteAlpha.50" };
return <Box as="th" bg={bg[colorMode]} fontWeight="semibold" p={2} fontSize="sm" {...props} />;
const { colorMode } = useColorMode();
return (
<Box
as="th"
bg={bg[colorMode]}
fontWeight="semibold"
p={2}
fontSize="sm"
{...props}
/>
);
};
const TableCell = ({ isHeader = false, ...props }) => (
<Box
as={isHeader ? "th" : "td"}
p={2}
borderTopWidth="1px"
borderColor="inherit"
fontSize="sm"
whiteSpace="normal"
{...props}
/>
<Box
as={isHeader ? "th" : "td"}
p={2}
borderTopWidth="1px"
borderColor="inherit"
fontSize="sm"
whiteSpace="normal"
{...props}
/>
);
export { TableCell, TableHeader, Table };

View File

@@ -2,23 +2,19 @@
import { jsx } from "@emotion/core";
import { Box, css } from "@chakra-ui/core";
const TableBody = ({ children, ...props }) => {
return (
<Box
as="tbody"
overflowY="scroll"
css={css({
"&::-webkit-scrollbar": { display: "none" },
"&": { msOverflowStyle: "none" }
})}
overflowX="hidden"
{...props}
>
{children}
</Box>
);
};
TableBody.displayName = "TableBody";
const TableBody = ({ children, ...props }) => (
<Box
as="tbody"
overflowY="scroll"
css={css({
"&::-webkit-scrollbar": { display: "none" },
"&": { msOverflowStyle: "none" }
})}
overflowX="hidden"
{...props}
>
{children}
</Box>
);
export default TableBody;

View File

@@ -1,19 +1,6 @@
import * as React from "react";
import { Box, useColorMode } from "@chakra-ui/core";
// export const TableCell = styled("div")`
// ${space};
// ${color};
// ${justifyContent};
// flex: 1;
// display: flex;
// min-width: 150px;
// align-items: center;
// border-bottom-width: 1px;
// overflow: hidden;
// text-overflow: ellipsis;
// `;
const cellBorder = {
dark: { borderLeft: "1px", borderLeftColor: "whiteAlpha.100" },
light: { borderLeft: "1px", borderLeftColor: "blackAlpha.100" }
@@ -48,6 +35,4 @@ const TableCell = ({
);
};
TableCell.displayName = "TableCell";
export default TableCell;

View File

@@ -1,12 +1,6 @@
import * as React from "react";
import { Box, useColorMode } from "@chakra-ui/core";
// export const TableHead = styled.div`
// ${space};
// display: flex;
// flex-direction: row;
// `;
const bg = { dark: "whiteAlpha.100", light: "blackAlpha.100" };
const TableHead = ({ children, ...props }) => {
@@ -24,6 +18,4 @@ const TableHead = ({ children, ...props }) => {
);
};
TableHead.displayName = "TableHead";
export default TableHead;

View File

@@ -1,27 +1,6 @@
import * as React from "react";
import { IconButton } from "@chakra-ui/core";
// export const TableIconButton = ({ icon, onClick, isDisabled, children, variantColor, ...rest }) => {
// return (
// <IconButton
// size="sm"
// {...rest}
// icon={icon}
// borderWidth={1}
// onClick={onClick}
// variantColor={variantColor}
// isDisabled={isDisabled}
// aria-label="Table Icon button"
// >
// {children}
// </IconButton>
// );
// };
// TableIconButton.defaultProps = {
// variantColor: "gray",
// };
const TableIconButton = ({
icon,
onClick,
@@ -29,23 +8,19 @@ const TableIconButton = ({
color,
children,
...props
}) => {
return (
<IconButton
size="sm"
icon={icon}
borderWidth={1}
onClick={onClick}
variantColor={color}
isDisabled={isDisabled}
aria-label="Table Icon Button"
{...props}
>
{children}
</IconButton>
);
};
TableIconButton.displayName = "TableIconButton";
}) => (
<IconButton
size="sm"
icon={icon}
borderWidth={1}
onClick={onClick}
variantColor={color}
isDisabled={isDisabled}
aria-label="Table Icon Button"
{...props}
>
{children}
</IconButton>
);
export default TableIconButton;

View File

@@ -37,5 +37,4 @@ const MainTable = ({ children, ...props }) => {
);
};
MainTable.displayName = "MainTable";
export default MainTable;

View File

@@ -2,13 +2,6 @@ import * as React from "react";
import { PseudoBox, useColorMode, useTheme } from "@chakra-ui/core";
import { opposingColor } from "~/util";
// export const TableRow = styled(Flex)`
// &:hover {
// cursor: pointer;
// background-color: rgba(0, 0, 0, 0.01);
// }
// `;
const hoverBg = { dark: "whiteAlpha.50", light: "blackAlpha.50" };
const bgStripe = { dark: "whiteAlpha.50", light: "blackAlpha.50" };
const rowBorder = {
@@ -60,6 +53,4 @@ const TableRow = ({
);
};
TableRow.displayName = "TableRow";
export default TableRow;

View File

@@ -1,32 +1,15 @@
import * as React from "react";
import { Select } from "@chakra-ui/core";
{
/* <select
value={pageSize}
onChange={e => {setPageSize(Number(e.target.value))}}
>
{[5, 10, 20, 30, 40, 50].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
const TableSelectShow = ({ value, onChange, children, ...props }) => (
<Select size="sm" onChange={onChange} {...props}>
{[5, 10, 20, 30, 40, 50].map(value => (
<option key={value} value={value}>
Show {value}
</option>
))}
</select> */
}
const TableSelectShow = ({ value, onChange, children, ...props }) => {
return (
<Select size="sm" onChange={onChange} {...props}>
{[5, 10, 20, 30, 40, 50].map(value => (
<option key={value} value={value}>
Show {value}
</option>
))}
{children}
</Select>
);
};
TableSelectShow.displayName = "TableSelectShow";
{children}
</Select>
);
export default TableSelectShow;

View File

@@ -194,6 +194,4 @@ const Table = ({
);
};
Table.displayName = "Table";
export default Table;

View File

@@ -40,5 +40,4 @@ const TextOutput = ({ children, ...props }) => {
);
};
TextOutput.displayName = "TextOutput";
export default TextOutput;

View File

@@ -1,49 +1,48 @@
import React from "react";
/** @jsx jsx */
import { jsx } from "@emotion/core";
import { forwardRef } from "react";
import { Button, Heading, Image, Stack, useColorMode } from "@chakra-ui/core";
import { Textfit } from "react-textfit";
import { motion, AnimatePresence } from "framer-motion";
import useConfig from "~/components/HyperglassProvider";
import useMedia from "~/components/MediaProvider";
const subtitleAnimation = {
transition: { duration: 0.2, type: "tween" },
initial: { opacity: 1, scale: 1 },
animate: { opacity: 1, scale: 1 },
exit: { opacity: 0, scale: 0.3 }
};
const titleSize = { true: "2xl", false: "lg" };
const titleSize = { true: ["2xl", "2xl", "5xl", "5xl"], false: "2xl" };
const titleMargin = { true: 2, false: 0 };
const textAlignment = { false: ["right", "center"], true: ["left", "center"] };
const logoName = { light: "dark", dark: "light" };
const justifyMap = {
true: ["flex-end", "center", "center", "center"],
false: ["flex-start", "center", "center", "center"]
};
const logoFallback = {
light:
"https://res.cloudinary.com/hyperglass/image/upload/v1593916013/logo-dark.svg",
dark:
"https://res.cloudinary.com/hyperglass/image/upload/v1593916013/logo-light.svg"
};
const TitleOnly = ({ text, showSubtitle }) => (
<Heading
as="h1"
mb={titleMargin[showSubtitle]}
size={titleSize[showSubtitle]}
fontSize={titleSize[showSubtitle]}
>
<Textfit mode="single">{text}</Textfit>
{text}
</Heading>
);
const SubtitleOnly = React.forwardRef(
({ text, mediaSize, size = "md", ...props }, ref) => (
<Heading
ref={ref}
as="h3"
size={size}
whiteSpace="break-spaces"
textAlign={["left", "left", "center", "center"]}
{...props}
>
<Textfit mode="multi" max={mediaSize === "sm" ? 13 : 25}>
{text}
</Textfit>
</Heading>
)
const SubtitleOnly = ({ text, mediaSize, ...props }) => (
<Heading
as="h3"
fontSize={["md", "md", "xl", "xl"]}
whiteSpace="break-spaces"
textAlign={["left", "left", "center", "center"]}
{...props}
>
{text}
</Heading>
);
const AnimatedSubtitle = motion.custom(SubtitleOnly);
const TextOnly = ({ text, mediaSize, showSubtitle, ...props }) => (
<Stack
spacing={2}
@@ -51,42 +50,39 @@ const TextOnly = ({ text, mediaSize, showSubtitle, ...props }) => (
textAlign={textAlignment[showSubtitle]}
{...props}
>
<Textfit mode="single" max={20}>
<TitleOnly text={text.title} showSubtitle={showSubtitle} />
</Textfit>
<AnimatePresence>
{showSubtitle && (
<AnimatedSubtitle
text={text.subtitle}
mediaSize={mediaSize}
{...subtitleAnimation}
/>
)}
</AnimatePresence>
<TitleOnly text={text.title} showSubtitle={showSubtitle} />
{showSubtitle && (
<SubtitleOnly text={text.subtitle} mediaSize={mediaSize} />
)}
</Stack>
);
const Logo = ({ text, logo }) => {
const { colorMode } = useColorMode();
const logoExt = { light: logo.dark_format, dark: logo.light_format };
const logoName = { light: "dark", dark: "light" };
const { width, dark_format, light_format } = logo;
const logoExt = { light: dark_format, dark: light_format };
return (
<Image
css={{
userDrag: "none",
userSelect: "none",
msUserSelect: "none",
MozUserSelect: "none",
WebkitUserDrag: "none",
WebkitUserSelect: "none"
}}
alt={text.title}
width={logo.width ?? "auto"}
width={width ?? "auto"}
fallbackSrc={logoFallback[colorMode]}
src={`/images/${logoName[colorMode]}${logoExt[colorMode]}`}
/>
);
};
const LogoSubtitle = ({ text, logo, showSubtitle, mediaSize }) => (
const LogoSubtitle = ({ text, logo, mediaSize }) => (
<>
<Logo text={text} logo={logo} mediaSize={mediaSize} />
<AnimatePresence>
{showSubtitle && (
<AnimatedSubtitle mt={6} text={text.subtitle} {...subtitleAnimation} />
)}
</AnimatePresence>
<SubtitleOnly mt={6} text={text.subtitle} />
</>
);
@@ -108,12 +104,8 @@ const modeMap = {
logo_subtitle: LogoSubtitle,
all: All
};
const justifyMap = {
true: ["flex-end", "center", "center", "center"],
false: ["flex-start", "center", "center", "center"]
};
const Title = React.forwardRef(({ onClick, isSubmitting, ...props }, ref) => {
const Title = forwardRef(({ onClick, isSubmitting, ...props }, ref) => {
const { web } = useConfig();
const { mediaSize } = useMedia();
const titleMode = web.text.title_mode;
@@ -143,5 +135,4 @@ const Title = React.forwardRef(({ onClick, isSubmitting, ...props }, ref) => {
);
});
Title.displayName = "Title";
export default Title;

View File

@@ -2,24 +2,22 @@ import * as React from "react";
import { useTheme } from "@chakra-ui/core";
const LightningBolt = ({ size = 4, color = "currentColor" }) => {
const theme = useTheme();
return (
<svg
width={theme.space[size]}
height={theme.space[size]}
viewBox="0 0 16 16"
fill={theme.colors[color]}
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
d="M11.251.068a.5.5 0 0 1 .227.58L9.677 6.5H13a.5.5 0 0 1 .364.843l-8 8.5a.5.5 0 0 1-.842-.49L6.323 9.5H3a.5.5 0 0 1-.364-.843l8-8.5a.5.5 0 0 1 .615-.09z"
clipRule="evenodd"
/>
</svg>
);
const theme = useTheme();
return (
<svg
width={theme.space[size]}
height={theme.space[size]}
viewBox="0 0 16 16"
fill={theme.colors[color]}
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
d="M11.251.068a.5.5 0 0 1 .227.58L9.677 6.5H13a.5.5 0 0 1 .364.843l-8 8.5a.5.5 0 0 1-.842-.49L6.323 9.5H3a.5.5 0 0 1-.364-.843l8-8.5a.5.5 0 0 1 .615-.09z"
clipRule="evenodd"
/>
</svg>
);
};
LightningBolt.displayName = "LightningBolt";
export default LightningBolt;

View File

@@ -1,6 +0,0 @@
import { useMemo } from "react";
import config from "~/frontend.json";
export default () => useMemo(() => config);
export const useConfig = cfg => useMemo(() => cfg);

View File

@@ -1,4 +0,0 @@
import { useMemo } from "react";
export default (mode = "light", light = "black", dark = "white") =>
useMemo(() => (mode ? light : dark));

View File

@@ -15,7 +15,7 @@
},
"browserslist": "> 0.25%, not dead",
"dependencies": {
"@chakra-ui/core": "^0.7.0",
"@chakra-ui/core": "^0.8",
"@emotion/core": "^10.0.28",
"@emotion/styled": "^10.0.27",
"@styled-system/should-forward-prop": "^5.1.5",
@@ -28,17 +28,16 @@
"framer-motion": "^1.10.0",
"html-to-react": "^1.4.3",
"lodash": "^4.17.15",
"next": "^9.3.1",
"next": "^9.4",
"react": "^16.13.1",
"react-countdown": "^2.2.1",
"react-dom": "^16.13.1",
"react-hook-form": "^5.1.1",
"react-hook-form": "^5.7",
"react-icons": "^3.9.0",
"react-markdown": "^4.3.1",
"react-select": "^3.0.8",
"react-string-replace": "^0.4.4",
"react-table": "^7.0.4",
"react-textfit": "^1.1.0",
"string-format": "^2.0.0",
"styled-system": "^5.1.5",
"tempy": "^0.5.0",

View File

@@ -1015,22 +1015,22 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@chakra-ui/core@^0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@chakra-ui/core/-/core-0.7.0.tgz#5066201cecacc6c48993c8d655f5d85f5da10c2e"
integrity sha512-Ph6y9ds7ejuAom7imEwEEhYqTz3EM23mYuRu5qtZxF6b2tvAVbTZ2CjecaUbwZbCVxxiAVCkC2O+cWokeqBEDA==
"@chakra-ui/core@^0.8":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@chakra-ui/core/-/core-0.8.0.tgz#a377286becd86008448ec8cf29ceb8fc301ac2dc"
integrity sha512-il1I1nEWOmWJSspnC+WyArLHbHvs82hvKTNDd24wr6spa/7v2jaXFZeWDNenY35ay1NHV7Ya2StcBwQRGHMWYA==
dependencies:
"@reach/auto-id" "0.9.0"
"@reach/auto-id" "0.10.2"
"@styled-system/css" "5.1.5"
"@styled-system/should-forward-prop" "5.1.5"
"@types/styled-system" "5.1.9"
aria-hidden "^1.1.1"
body-scroll-lock "^2.6.4"
body-scroll-lock "^3.0.1"
color "3.1.2"
copy-to-clipboard "3.3.1"
exenv "^1.2.2"
popper.js "^1.15.0"
react-animate-height "2.0.20"
react-animate-height "2.0.21"
react-focus-lock "^2.2.1"
react-spring "^8.0.27"
styled-system "5.1.5"
@@ -1504,25 +1504,26 @@
"@reach/component-component" "^0.1.3"
"@reach/visually-hidden" "^0.1.4"
"@reach/auto-id@0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.9.0.tgz#73b5d34bcf432f3e73b235b9dcaa89ea05a0d4db"
integrity sha512-9/aXl+dT0pOenvpkB2kkmQnpMDlmSk8ZkBYmYFzFz3eA4PZFNuXcHVzQevFRhc0HVlskPjxwPNf92EkI9rdFOw==
"@reach/auto-id@0.10.2":
version "0.10.2"
resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.10.2.tgz#a447af67241123dcb701ecd61931a2c786ed111e"
integrity sha512-PWFZevkHshiJV/z0L/5WQkWhe9QRzdZqC7N/JHRCoYo+odvCz9izXVRsxJf7p4sCuOCvnc8zNzAokFk2E1ZzDg==
dependencies:
"@reach/utils" "^0.9.0"
tslib "^1.10.0"
"@reach/utils" "^0.10.2"
tslib "^1.11.2"
"@reach/component-component@^0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@reach/component-component/-/component-component-0.1.3.tgz#5d156319572dc38995b246f81878bc2577c517e5"
integrity sha512-a1USH7L3bEfDdPN4iNZGvMEFuBfkdG+QNybeyDv8RloVFgZYRoM+KGXyy2KOfEnTUM8QWDRSROwaL3+ts5Angg==
"@reach/utils@^0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.9.0.tgz#ee47c25c79eb2f98e6c0e728a2672075cc9991d5"
integrity sha512-cmiykRaxuCysVTsSY3PgrLjySnEIt1PLiSYKh5rAH8nYyEmaOCtw0vaNItFAiqQIjfrxkixmcUE8dyD8kqVuJA==
"@reach/utils@^0.10.2":
version "0.10.5"
resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.10.5.tgz#fbac944d29565f6dd7abd0e1b13950e99b1e470b"
integrity sha512-5E/xxQnUbmpI/LrufBAOXjunl96DnqX6B4zC2MO2KH/dRzLug5gM5VuOwV26egsp0jvsSPxojwciOhS43px3qw==
dependencies:
tslib "^1.10.0"
"@types/warning" "^3.0.0"
tslib "^2.0.0"
warning "^4.0.3"
"@reach/visually-hidden@^0.1.4":
@@ -1691,6 +1692,11 @@
dependencies:
csstype "^2.6.9"
"@types/warning@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52"
integrity sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI=
"@typescript-eslint/eslint-plugin@^2.24.0":
version "2.34.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9"
@@ -2438,10 +2444,10 @@ body-parser@1.19.0:
raw-body "2.4.0"
type-is "~1.6.17"
body-scroll-lock@^2.6.4:
version "2.7.1"
resolved "https://registry.yarnpkg.com/body-scroll-lock/-/body-scroll-lock-2.7.1.tgz#caf3f9c91773af1ffb684cd66ed9137b5b737014"
integrity sha512-hS53SQ8RhM0e4DsQ3PKz6Gr2O7Kpdh59TWU98GHjaQznL7y4dFycEPk7pFQAikqBaUSCArkc5E3pe7CWIt2fZA==
body-scroll-lock@^3.0.1:
version "3.0.3"
resolved "https://registry.yarnpkg.com/body-scroll-lock/-/body-scroll-lock-3.0.3.tgz#221d87435bcfb50e27ab5d4508735f622aed11a2"
integrity sha512-EUryImgD6Gv87HOjJB/yB2WIGECiZMhmcUK+DrqVRFDDa64xR+FsK0LgvLPnBxZDTxIl+W80/KJ8i6gp2IwOHQ==
boolbase@^1.0.0, boolbase@~1.0.0:
version "1.0.0"
@@ -6232,7 +6238,7 @@ next-tick@~1.0.0:
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
next@^9.3.1:
next@^9.4:
version "9.4.4"
resolved "https://registry.yarnpkg.com/next/-/next-9.4.4.tgz#02ad9fea7f7016b6b42fc83b67835e4a0dd0c99a"
integrity sha512-ZT8bU2SAv5jkFQ+y8py+Rl5RJRJ6DnZDS+VUnB1cIscmtmUhDi7LYED7pYm4MCKkYhPbEEM1Lbpo7fnoZJGWNQ==
@@ -7320,7 +7326,7 @@ process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
process@^0.11.10, process@^0.11.9:
process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
@@ -7349,7 +7355,7 @@ prop-types-exact@1.2.0:
object.assign "^4.1.0"
reflect.ownkeys "^0.2.0"
prop-types@15.7.2, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@15.7.2, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -7518,10 +7524,10 @@ rc@^1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
react-animate-height@2.0.20:
version "2.0.20"
resolved "https://registry.yarnpkg.com/react-animate-height/-/react-animate-height-2.0.20.tgz#e519c33a41cb39c071e8115bb3c4f9daad6c703f"
integrity sha512-gs6j9oSiWNAnquEVpPMdTe/kwsdVORkRYsgPju4VfM1wKwai7pdmwob//1ECmCQTD8S0NfRDDBk0l7MJGFNmbw==
react-animate-height@2.0.21:
version "2.0.21"
resolved "https://registry.yarnpkg.com/react-animate-height/-/react-animate-height-2.0.21.tgz#da9223eb0e74457d52f72da477c8626550df2ce6"
integrity sha512-CZHdjMD8qqp10tYtWmauWYASXxxv9vYeljxFGFtbcrbNXhsUv0w3IjxVK+0yCnyfk7769WfMZKHra4vRcbMnQg==
dependencies:
classnames "^2.2.5"
prop-types "^15.6.1"
@@ -7562,7 +7568,7 @@ react-focus-lock@^2.2.1:
use-callback-ref "^1.2.1"
use-sidecar "^1.0.1"
react-hook-form@^5.1.1:
react-hook-form@^5.7:
version "5.7.2"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-5.7.2.tgz#a84e259e5d37dd30949af4f79c4dac31101b79ac"
integrity sha512-bJvY348vayIvEUmSK7Fvea/NgqbT2racA2IbnJz/aPlQ3GBtaTeDITH6rtCa6y++obZzG6E3Q8VuoXPir7QYUg==
@@ -7641,14 +7647,6 @@ react-table@^7.0.4:
dependencies:
"@scarf/scarf" "^1.0.4"
react-textfit@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/react-textfit/-/react-textfit-1.1.0.tgz#088855580f2e7aad269efc81b734bf636877d0e1"
integrity sha512-iznFbj7fCizuo3Xof9iv57I8GZFiYp8vUFj+4qihHJZpzNwxWad7JZu7ALTAnwaiq/H0p60g8G4ifeEJYmfJuw==
dependencies:
process "^0.11.9"
prop-types "^15.5.10"
react-transition-group@^4.3.0:
version "4.4.1"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
@@ -9109,11 +9107,16 @@ tsconfig-paths@^3.9.0:
minimist "^1.2.0"
strip-bom "^3.0.0"
tslib@^1.0.0, tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
tslib@^1.0.0, tslib@^1.10.0, tslib@^1.11.2, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.13.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
tslib@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.0.tgz#18d13fc2dce04051e20f074cc8387fd8089ce4f3"
integrity sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==
tsutils@^3.17.1:
version "3.17.1"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"