diff --git a/ui/components/CopyButton.js b/ui/components/CopyButton.js
index f8bcc03..28ad79a 100644
--- a/ui/components/CopyButton.js
+++ b/ui/components/CopyButton.js
@@ -1,11 +1,19 @@
import React from "react";
import { Button, Icon, Tooltip, useClipboard } from "@chakra-ui/core";
-export default ({ bg = "secondary", copyValue }) => {
+export default ({ bg = "secondary", copyValue, ...props }) => {
const { onCopy, hasCopied } = useClipboard(copyValue);
return (
-
diff --git a/ui/components/Footer.js b/ui/components/Footer.js
index 2e64b79..3167a57 100644
--- a/ui/components/Footer.js
+++ b/ui/components/Footer.js
@@ -71,7 +71,7 @@ export default ({ general, help, extLink, credit, terms, content }) => {
/>
)}
{
- const theme = useTheme();
const { colorMode } = useColorMode();
- const labelColor =
- colorMode === "dark" ? theme.colors.whiteAlpha[600] : theme.colors.blackAlpha[600];
+ const labelColor = { dark: "whiteAlpha.600", light: "blackAlpha.600" };
return (
-
+
{label}
{helpIcon?.enable && }
diff --git a/ui/components/Header.js b/ui/components/Header.js
index 353bf1f..93a5fec 100644
--- a/ui/components/Header.js
+++ b/ui/components/Header.js
@@ -1,44 +1,123 @@
import React from "react";
-import { Flex, IconButton, useColorMode, useTheme } from "@chakra-ui/core";
-import { motion } from "framer-motion";
+import { Flex, IconButton, useColorMode } from "@chakra-ui/core";
+import { motion, AnimatePresence } from "framer-motion";
+import ResetButton from "~/components/ResetButton";
+import useMedia from "~/components/MediaProvider";
+import Title from "~/components/Title";
const AnimatedFlex = motion.custom(Flex);
+const AnimatedResetButton = motion.custom(ResetButton);
-export default () => {
- const theme = useTheme();
+const titleVariants = {
+ sm: {
+ fullSize: { scale: 1, marginLeft: 0 },
+ small: { marginLeft: "auto" }
+ },
+ md: {
+ fullSize: { scale: 1 },
+ small: { scale: 1 }
+ },
+ lg: {
+ fullSize: { scale: 1 },
+ small: { scale: 1 }
+ },
+ xl: {
+ fullSize: { scale: 1 },
+ small: { scale: 1 }
+ }
+};
+
+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", damping: 15, stiffness: 100 };
+
+export default ({ height, isSubmitting, handleFormReset, ...props }) => {
const { colorMode, toggleColorMode } = useColorMode();
- const bg = { light: theme.colors.white, dark: theme.colors.black };
- const icon = { light: "moon", dark: "sun" };
+ const { mediaSize } = useMedia();
+ const resetButton = (
+
+
+
+
+
+ );
+ const title = (
+
+
+
+ );
+ const colorModeToggle = (
+
+
+
+ );
+ const layout = {
+ false: {
+ sm: [title, resetButton, colorModeToggle],
+ md: [resetButton, title, colorModeToggle],
+ lg: [resetButton, title, colorModeToggle],
+ xl: [resetButton, title, colorModeToggle]
+ },
+ true: {
+ sm: [resetButton, colorModeToggle, title],
+ md: [resetButton, title, colorModeToggle],
+ lg: [resetButton, title, colorModeToggle],
+ xl: [resetButton, title, colorModeToggle]
+ }
+ };
return (
-
-
-
-
+
+ {layout[isSubmitting][mediaSize]}
);
diff --git a/ui/components/HyperglassForm.js b/ui/components/HyperglassForm.js
index 68bd94c..60496d2 100644
--- a/ui/components/HyperglassForm.js
+++ b/ui/components/HyperglassForm.js
@@ -10,11 +10,10 @@ import QueryType from "~/components/QueryType";
import QueryTarget from "~/components/QueryTarget";
import QueryVrf from "~/components/QueryVrf";
import SubmitButton from "~/components/SubmitButton";
+import useConfig from "~/components/HyperglassProvider";
format.extend(String.prototype, {});
-const all = (...items) => [...items].every(i => (i ? true : false));
-
const formSchema = config =>
yup.object().shape({
query_location: yup
@@ -33,13 +32,20 @@ const formSchema = config =>
});
const FormRow = ({ children, ...props }) => (
-
+
{children}
);
-export default React.forwardRef(
- ({ config, isSubmitting, setSubmitting, setFormData, ...props }, ref) => {
+const HyperglassForm = React.forwardRef(
+ ({ isSubmitting, setSubmitting, setFormData, ...props }, ref) => {
+ const config = useConfig();
const { handleSubmit, register, setValue, errors } = useForm({
validationSchema: formSchema(config)
});
@@ -47,8 +53,6 @@ export default React.forwardRef(
const [queryType, setQueryType] = useState("");
const [queryVrf, setQueryVrf] = useState("");
const [availVrfs, setAvailVrfs] = useState([]);
- // const [showHelpIcon, setShowHelpIcon] = useState(false);
-
const onSubmit = values => {
setFormData(values);
setSubmitting(true);
@@ -138,17 +142,25 @@ export default React.forwardRef(
register={register}
/>
-
+
+
-
+
);
}
);
+
+HyperglassForm.displayName = "HyperglassForm";
+export default HyperglassForm;
diff --git a/ui/components/Label.js b/ui/components/Label.js
index 745a1fc..1cab54d 100644
--- a/ui/components/Label.js
+++ b/ui/components/Label.js
@@ -2,20 +2,27 @@ import React from "react";
import { Flex, useColorMode, useTheme } from "@chakra-ui/core";
export default React.forwardRef(
- ({ value, label, labelBg, labelColor, valueBg, valueColor }, ref) => {
+ ({ value, label, labelColor, valueBg, valueColor, ...props }, ref) => {
const theme = useTheme();
const { colorMode } = useColorMode();
- const _labelBg = { light: theme.colors.black, dark: theme.colors.gray[200] };
- const _labelColor = { light: theme.colors.white, dark: theme.colors.white };
+ const _labelColor = { dark: "whiteAlpha.700", light: "blackAlpha.700" };
const _valueBg = { light: theme.colors.primary[600], dark: theme.colors.primary[600] };
- const _valueColor = { light: theme.colors.white, dark: theme.colors.white };
+ const _valueColor = { light: "white", dark: "white" };
return (
-
+
{value}
@@ -39,13 +46,13 @@ export default React.forwardRef(
mb={2}
ml={0}
mr={0}
- bg={labelBg || _labelBg[colorMode]}
+ boxShadow={`inset 0px 0px 0px 1px ${valueBg || _valueBg[colorMode]}`}
color={labelColor || _labelColor[colorMode]}
borderBottomRightRadius={4}
borderTopRightRadius={4}
borderBottomLeftRadius={0}
borderTopLeftRadius={0}
- fontSize="sm"
+ fontSize={["xs", "sm", "sm", "sm"]}
>
{label}
diff --git a/ui/components/Layout.js b/ui/components/Layout.js
index ac346c7..08726c7 100644
--- a/ui/components/Layout.js
+++ b/ui/components/Layout.js
@@ -1,67 +1,67 @@
-import React, { useState } from "react";
-import { Flex, useColorMode, useTheme } from "@chakra-ui/core";
+import React, { useRef, useState } from "react";
+import { Flex, useColorMode } from "@chakra-ui/core";
import { motion, AnimatePresence } from "framer-motion";
-import ResetButton from "~/components/ResetButton";
import HyperglassForm from "~/components/HyperglassForm";
import Results from "~/components/Results";
import Header from "~/components/Header";
import Footer from "~/components/Footer";
-import Title from "~/components/Title";
import Meta from "~/components/Meta";
+import useConfig from "~/components/HyperglassProvider";
+import Debugger from "~/components/Debugger";
const AnimatedForm = motion.custom(HyperglassForm);
-const AnimatedTitle = motion.custom(Title);
-const AnimatedResetButton = motion.custom(ResetButton);
-export default ({ config }) => {
- const theme = useTheme();
+const bg = { light: "white", dark: "black" };
+const color = { light: "black", dark: "white" };
+const headerHeightDefault = { true: [16, 16, 16, 16], false: [24, 64, 64, 64] };
+const headerHeightAll = { true: [32, 32, 32, 32], false: [48, "20rem", "20rem", "20rem"] };
+
+const Layout = () => {
+ const config = useConfig();
const { colorMode } = useColorMode();
- const bg = { light: theme.colors.white, dark: theme.colors.black };
- const color = { light: theme.colors.black, dark: theme.colors.white };
const [isSubmitting, setSubmitting] = useState(false);
const [formData, setFormData] = useState({});
+ const containerRef = useRef(null);
const handleFormReset = () => {
+ containerRef.current.scrollIntoView({ behavior: "smooth", block: "start" });
setSubmitting(false);
};
+ const headerHeight =
+ config.branding.text.title_mode === "all"
+ ? headerHeightAll[isSubmitting]
+ : headerHeightDefault[isSubmitting];
return (
<>
-
+
-
+
+
+
-
-
-
{isSubmitting && formData && (
{
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
exit={{ opacity: 0, x: -300 }}
- config={config}
isSubmitting={isSubmitting}
setSubmitting={setSubmitting}
setFormData={setFormData}
@@ -84,18 +83,7 @@ export default ({ config }) => {
)}
-
- {isSubmitting && (
-
- )}
-
+ {config.general.debug && }
);
};
+
+export default ({ loading, error, refresh }) => {
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/ui/components/RequeryButton.js b/ui/components/RequeryButton.js
index d2d6a93..8ea0722 100644
--- a/ui/components/RequeryButton.js
+++ b/ui/components/RequeryButton.js
@@ -1,11 +1,19 @@
import React from "react";
-import { Button, Icon, Spinner, Tooltip } from "@chakra-ui/core";
+import { Button, Icon, Tooltip } from "@chakra-ui/core";
-export default ({ isLoading, requery, bg = "secondary" }) => {
+export default ({ requery, bg = "secondary", ...props }) => {
return (
-
- {isLoading ? : }
+
+
);
diff --git a/ui/components/ResetButton.js b/ui/components/ResetButton.js
index eef90cf..708f3f8 100644
--- a/ui/components/ResetButton.js
+++ b/ui/components/ResetButton.js
@@ -1,11 +1,17 @@
import React from "react";
-import { Box, Button } from "@chakra-ui/core";
+import { Button } from "@chakra-ui/core";
import { FiChevronLeft } from "react-icons/fi";
export default React.forwardRef(({ isSubmitting, onClick }, ref) => (
-
-
-
-
-
+
+
+
));
diff --git a/ui/components/Result.js b/ui/components/Result.js
index 1439f38..e09e22d 100644
--- a/ui/components/Result.js
+++ b/ui/components/Result.js
@@ -3,10 +3,10 @@ import {
AccordionItem,
AccordionHeader,
AccordionPanel,
- AccordionIcon,
Alert,
Box,
ButtonGroup,
+ css,
Flex,
Text,
useTheme,
@@ -15,26 +15,35 @@ import {
import styled from "@emotion/styled";
import useAxios from "axios-hooks";
import strReplace from "react-string-replace";
+import useConfig from "~/components/HyperglassProvider";
import CopyButton from "~/components/CopyButton";
import RequeryButton from "~/components/RequeryButton";
import ResultHeader from "~/components/ResultHeader";
-const PreBox = styled(Box)`
- &::selection {
- background-color: ${props => props.selectionBg};
- color: ${props => props.selectionColor};
- }
-`;
-
const FormattedError = ({ keywords, message }) => {
const patternStr = `(${keywords.join("|")})`;
const pattern = new RegExp(patternStr, "gi");
- const errorFmt = strReplace(message, pattern, match => {match});
+ const errorFmt = strReplace(message, pattern, match => (
+
+ {match}
+
+ ));
return {errorFmt};
};
-export default React.forwardRef(
- ({ config, device, timeout, queryLocation, queryType, queryVrf, queryTarget }, ref) => {
+const AccordionHeaderWrapper = styled(Flex)`
+ justify-content: space-between;
+ &:hover {
+ background-color: ${props => props.hoverBg};
+ }
+ &:focus {
+ box-shadow: "outline";
+ }
+`;
+
+const Result = React.forwardRef(
+ ({ device, timeout, queryLocation, queryType, queryVrf, queryTarget }, ref) => {
+ const config = useConfig();
const theme = useTheme();
const { colorMode } = useColorMode();
const bg = { dark: theme.colors.gray[800], light: theme.colors.blackAlpha[100] };
@@ -68,60 +77,68 @@ export default React.forwardRef(
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ {data && (
+
+ {cleanOutput}
+
+ )}
+ {error && (
+
+
+
+ )}
+
-
-
-
- {data && (
-
- {cleanOutput}
-
- )}
- {error && (
-
-
-
- )}
-
-
-
-
-
);
}
);
+
+Result.displayName = "HyperglassQueryResult";
+export default Result;
diff --git a/ui/components/ResultHeader.js b/ui/components/ResultHeader.js
index 3b69c8c..1aebd80 100644
--- a/ui/components/ResultHeader.js
+++ b/ui/components/ResultHeader.js
@@ -1,18 +1,29 @@
import React from "react";
-import { Icon, Spinner, Stack, Text, Tooltip, useColorMode, useTheme } from "@chakra-ui/core";
+import {
+ AccordionIcon,
+ Icon,
+ Spinner,
+ Stack,
+ Text,
+ Tooltip,
+ useColorMode,
+ useTheme
+} from "@chakra-ui/core";
+import useConfig from "~/components/HyperglassProvider";
-export default React.forwardRef(({ config, title, loading, error }, ref) => {
+export default React.forwardRef(({ title, loading, error }, ref) => {
+ const config = useConfig();
const theme = useTheme();
const { colorMode } = useColorMode();
- const statusColor = { dark: theme.colors.primary[300], light: theme.colors.primary[500] };
- const defaultWarningColor = { dark: theme.colors.danger[300], light: theme.colors.danger[500] };
+ const statusColor = { dark: "primary.300", light: "primary.500" };
+ const defaultWarningColor = { dark: "danger.300", light: "danger.500" };
const warningColor = { dark: 300, light: 500 };
const defaultStatusColor = {
- dark: theme.colors.success[300],
- light: theme.colors.success[500]
+ dark: "success.300",
+ light: "success.500"
};
return (
-
+
{loading ? (
) : error ? (
@@ -36,6 +47,7 @@ export default React.forwardRef(({ config, title, loading, error }, ref) => {
)}
{title}
+
);
});
diff --git a/ui/components/Results.js b/ui/components/Results.js
index f869ab0..52a0994 100644
--- a/ui/components/Results.js
+++ b/ui/components/Results.js
@@ -1,25 +1,60 @@
import React from "react";
-import { Accordion, Box, Stack, useColorMode, useTheme } from "@chakra-ui/core";
+import { Accordion, Box, Stack, useTheme } from "@chakra-ui/core";
import { motion, AnimatePresence } from "framer-motion";
import Label from "~/components/Label";
import Result from "~/components/Result";
+import useConfig from "~/components/HyperglassProvider";
+import useMedia from "~/components/MediaProvider";
const AnimatedResult = motion.custom(Result);
const AnimatedLabel = motion.custom(Label);
-export default ({
- config,
- queryLocation,
- queryType,
- queryVrf,
- queryTarget,
- setSubmitting,
- ...props
-}) => {
+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 }
+ }
+};
+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 }
+ }
+};
+
+const Results = ({ queryLocation, queryType, queryVrf, queryTarget, setSubmitting, ...props }) => {
+ const config = useConfig();
const theme = useTheme();
- const { colorMode } = useColorMode();
+ const { mediaSize } = useMedia();
const matchedVrf = config.vrfs.filter(v => v.id === queryVrf)[0];
- const labelColor = { light: theme.colors.white, dark: theme.colors.black };
return (
<>
-
+
{queryLocation && (
<>
>
)}
@@ -71,7 +106,7 @@ export default ({
(
);
};
+
+Results.displayName = "HyperglassResults";
+export default Results;
diff --git a/ui/components/Title.js b/ui/components/Title.js
index a4d6c1c..e945a56 100644
--- a/ui/components/Title.js
+++ b/ui/components/Title.js
@@ -1,62 +1,98 @@
import React from "react";
-import { Button, Flex, Heading, Image, Stack, useColorMode } from "@chakra-ui/core";
+import { Button, Heading, Image, Stack, useColorMode } from "@chakra-ui/core";
+import { motion, AnimatePresence } from "framer-motion";
+import useConfig from "~/components/HyperglassProvider";
+import useMedia from "~/components/MediaProvider";
-const TitleOnly = ({ text }) => (
-
+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 titleMargin = { true: 2, false: 0 };
+
+const TitleOnly = ({ text, showSubtitle }) => (
+
{text}
);
-const SubtitleOnly = ({ text }) => (
-
+const SubtitleOnly = React.forwardRef(({ text, size = "md", ...props }, ref) => (
+
{text}
-);
+));
-const TextOnly = ({ text }) => (
-
-
-
+const AnimatedSubtitle = motion.custom(SubtitleOnly);
+
+const textAlignment = { false: ["right", "center"], true: ["left", "center"] };
+
+const TextOnly = ({ text, mediaSize, showSubtitle, ...props }) => (
+
+
+
+ {showSubtitle && }
+
);
-const LogoOnly = ({ text, logo }) => {
+const Logo = ({ text, logo }) => {
const { colorMode } = useColorMode();
const logoColor = { light: logo.dark, dark: logo.light };
const logoPath = logoColor[colorMode];
- return (
-
- );
+ return ;
};
-const LogoTitle = ({ text, logo }) => (
+const LogoTitle = ({ text, logo, showSubtitle }) => (
<>
-
-
+
+
+ {showSubtitle && (
+
+ )}
+
>
);
-const All = ({ text, logo }) => (
+const All = ({ text, logo, mediaSize, showSubtitle }) => (
<>
-
-
+
+
>
);
-const modeMap = { text_only: TextOnly, logo_only: LogoOnly, logo_title: LogoTitle, all: All };
+const modeMap = { text_only: TextOnly, logo_only: Logo, logo_title: LogoTitle, all: All };
-export default React.forwardRef(({ text, logo, resetForm }, ref) => {
- const MatchedMode = modeMap[text.title_mode];
+const btnJustify = {
+ true: ["flex-end", "center"],
+ false: ["flex-start", "center"]
+};
+export default React.forwardRef(({ onClick, isSubmitting, ...props }, ref) => {
+ const { branding } = useConfig();
+ const { mediaSize } = useMedia();
+ const titleMode = branding.text.title_mode;
+ const MatchedMode = modeMap[titleMode];
return (
-
-
-
-
+
+
);
});