diff --git a/hyperglass/ui/components/debugger.tsx b/hyperglass/ui/components/debugger.tsx
index c4c91a8..89a3ba6 100644
--- a/hyperglass/ui/components/debugger.tsx
+++ b/hyperglass/ui/components/debugger.tsx
@@ -13,7 +13,7 @@ import {
ModalCloseButton,
} from '@chakra-ui/react';
import { useConfig, useColorValue, useBreakpointValue } from '~/context';
-import { CodeBlock, DynamicIcon } from '~/components';
+import { CodeBlock, DynamicIcon } from '~/elements';
import { useHyperglassConfig } from '~/hooks';
import type { UseDisclosureReturn } from '@chakra-ui/react';
diff --git a/hyperglass/ui/components/directive-info-modal.tsx b/hyperglass/ui/components/directive-info-modal.tsx
index 3271696..aa3aa65 100644
--- a/hyperglass/ui/components/directive-info-modal.tsx
+++ b/hyperglass/ui/components/directive-info-modal.tsx
@@ -9,8 +9,8 @@ import {
useDisclosure,
ModalCloseButton,
} from '@chakra-ui/react';
-import { DynamicIcon, Markdown } from '~/components';
import { useColorValue } from '~/context';
+import { DynamicIcon, Markdown } from '~/elements';
import type { ModalContentProps } from '@chakra-ui/react';
diff --git a/hyperglass/ui/components/footer/button.tsx b/hyperglass/ui/components/footer/button.tsx
index fd747c1..b92bcbe 100644
--- a/hyperglass/ui/components/footer/button.tsx
+++ b/hyperglass/ui/components/footer/button.tsx
@@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { Button, Menu, MenuButton, MenuList } from '@chakra-ui/react';
-import { Markdown } from '~/components';
import { useColorValue, useBreakpointValue, useConfig } from '~/context';
+import { Markdown } from '~/elements';
import { useOpposingColor, useStrf } from '~/hooks';
import type { MenuListProps } from '@chakra-ui/react';
diff --git a/hyperglass/ui/components/footer/color-mode.tsx b/hyperglass/ui/components/footer/color-mode.tsx
index 8644caf..dbc0c9c 100644
--- a/hyperglass/ui/components/footer/color-mode.tsx
+++ b/hyperglass/ui/components/footer/color-mode.tsx
@@ -1,8 +1,8 @@
import { forwardRef } from 'react';
import { Button, Tooltip } from '@chakra-ui/react';
import { Switch, Case } from 'react-if';
-import { DynamicIcon } from '~/components';
import { useColorMode, useColorValue, useBreakpointValue } from '~/context';
+import { DynamicIcon } from '~/elements';
import { useOpposingColor } from '~/hooks';
import type { ButtonProps } from '@chakra-ui/react';
diff --git a/hyperglass/ui/components/footer/footer.tsx b/hyperglass/ui/components/footer/footer.tsx
index 2b1e3dc..60f4a82 100644
--- a/hyperglass/ui/components/footer/footer.tsx
+++ b/hyperglass/ui/components/footer/footer.tsx
@@ -1,8 +1,8 @@
import { useMemo } from 'react';
import { Flex, HStack, useToken } from '@chakra-ui/react';
import { If, Then } from 'react-if';
-import { DynamicIcon } from '~/components';
import { useConfig, useMobile, useColorValue, useBreakpointValue } from '~/context';
+import { DynamicIcon } from '~/elements';
import { useStrf } from '~/hooks';
import { FooterButton } from './button';
import { ColorModeToggle } from './color-mode';
diff --git a/hyperglass/ui/components/greeting.tsx b/hyperglass/ui/components/greeting.tsx
index b34bf3e..959d206 100644
--- a/hyperglass/ui/components/greeting.tsx
+++ b/hyperglass/ui/components/greeting.tsx
@@ -10,7 +10,7 @@ import {
ModalCloseButton,
} from '@chakra-ui/react';
import { If, Then } from 'react-if';
-import { Markdown } from '~/components';
+import { Markdown } from '~/elements';
import { useConfig, useColorValue } from '~/context';
import { useGreeting, useOpposingColor } from '~/hooks';
diff --git a/hyperglass/ui/components/header/header.tsx b/hyperglass/ui/components/header/header.tsx
index 338bc95..2e408c6 100644
--- a/hyperglass/ui/components/header/header.tsx
+++ b/hyperglass/ui/components/header/header.tsx
@@ -1,6 +1,6 @@
import { Flex, ScaleFade } from '@chakra-ui/react';
-import { motionChakra } from '~/components';
import { useBreakpointValue } from '~/context';
+import { motionChakra } from '~/elements';
import { useBooleanValue, useFormInteractive } from '~/hooks';
import { Title } from './title';
diff --git a/hyperglass/ui/components/index.ts b/hyperglass/ui/components/index.ts
index 3358af0..6c0f318 100644
--- a/hyperglass/ui/components/index.ts
+++ b/hyperglass/ui/components/index.ts
@@ -1,24 +1,19 @@
-export * from './animated';
-export * from './card';
-export * from './code-block';
-export * from './countdown';
-export * from './custom';
+/**
+ * The components directory contains React components that handle logic.
+ *
+ * Generally, components that call hooks or reference configuration, or API types should be in
+ * components.
+ */
+
export * from './debugger';
export * from './directive-info-modal';
-export * from './dynamic-icon';
-export * from './favicon';
export * from './footer';
export * from './form-field';
-export * from './form-row';
export * from './greeting';
export * from './header';
-export * from './label';
export * from './layout';
-export * from './load-error';
-export * from './loading';
export * from './location-card';
export * from './looking-glass-form';
-export * from './markdown';
export * from './meta';
export * from './output';
export * from './path';
@@ -26,6 +21,7 @@ export * from './prompt';
export * from './query-location';
export * from './query-target';
export * from './query-type';
+export * from './reset-button';
export * from './resolved-target';
export * from './results';
export * from './select';
diff --git a/hyperglass/ui/components/layout/frame.tsx b/hyperglass/ui/components/layout.tsx
similarity index 77%
rename from hyperglass/ui/components/layout/frame.tsx
rename to hyperglass/ui/components/layout.tsx
index 1014cb0..c90d307 100644
--- a/hyperglass/ui/components/layout/frame.tsx
+++ b/hyperglass/ui/components/layout.tsx
@@ -1,18 +1,29 @@
import { useCallback, useRef } from 'react';
import { Flex } from '@chakra-ui/react';
-import { motion } from 'framer-motion';
import { isSafari } from 'react-device-detect';
import { If, Then } from 'react-if';
-import { Debugger, Greeting, Footer, Header } from '~/components';
+import { Debugger, Greeting, Footer, Header, ResetButton } from '~/components';
import { useConfig } from '~/context';
+import { motionChakra } from '~/elements';
import { useFormState } from '~/hooks';
-import { ResetButton } from './reset-button';
import type { FlexProps } from '@chakra-ui/react';
-const AnimatedFlex = motion(Flex);
+const Main = motionChakra('main', {
+ baseStyle: {
+ px: 4,
+ py: 0,
+ w: '100%',
+ display: 'flex',
+ flex: '1 1 auto',
+ flexDir: 'column',
+ textAlign: 'center',
+ alignItems: 'center',
+ justifyContent: 'start',
+ },
+});
-export const Frame = (props: FlexProps): JSX.Element => {
+export const Layout = (props: FlexProps): JSX.Element => {
const { developerMode } = useConfig();
const { setStatus, reset } = useFormState(
useCallback(({ setStatus, reset }) => ({ setStatus, reset }), []),
@@ -42,24 +53,15 @@ export const Frame = (props: FlexProps): JSX.Element => {
minHeight={isSafari ? '-webkit-fill-available' : '100vh'}
>
-
{props.children}
-
+
diff --git a/hyperglass/ui/components/layout/index.ts b/hyperglass/ui/components/layout/index.ts
deleted file mode 100644
index aee1748..0000000
--- a/hyperglass/ui/components/layout/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './frame';
-export * from './layout';
diff --git a/hyperglass/ui/components/layout/layout.tsx b/hyperglass/ui/components/layout/layout.tsx
deleted file mode 100644
index 2607975..0000000
--- a/hyperglass/ui/components/layout/layout.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { AnimatePresence } from 'framer-motion';
-import { LookingGlassForm, Results } from '~/components';
-import { useView } from '~/hooks';
-import { Frame } from './frame';
-
-export const Layout = (): JSX.Element => {
- const view = useView();
- return (
-
- {view === 'results' ? (
-
- ) : (
-
-
-
- )}
-
- );
-};
diff --git a/hyperglass/ui/components/looking-glass-form.tsx b/hyperglass/ui/components/looking-glass-form.tsx
index 9804e70..5a095dd 100644
--- a/hyperglass/ui/components/looking-glass-form.tsx
+++ b/hyperglass/ui/components/looking-glass-form.tsx
@@ -5,7 +5,6 @@ import { FormProvider, useForm } from 'react-hook-form';
import { vestResolver } from '@hookform/resolvers/vest';
import vest, { test, enforce } from 'vest';
import {
- FormRow,
FormField,
DirectiveInfoModal,
QueryType,
@@ -14,6 +13,7 @@ import {
QueryLocation,
} from '~/components';
import { useConfig } from '~/context';
+import { FormRow } from '~/elements';
import { useStrf, useGreeting, useDevice, useFormState } from '~/hooks';
import { isString, isQueryField, Directive } from '~/types';
diff --git a/hyperglass/ui/components/output/fields.tsx b/hyperglass/ui/components/output/fields.tsx
index 3205138..293d9f3 100644
--- a/hyperglass/ui/components/output/fields.tsx
+++ b/hyperglass/ui/components/output/fields.tsx
@@ -4,8 +4,8 @@ import dayjs from 'dayjs';
import relativeTimePlugin from 'dayjs/plugin/relativeTime';
import utcPlugin from 'dayjs/plugin/utc';
import { If, Then, Else } from 'react-if';
-import { DynamicIcon } from '~/components';
import { useConfig, useColorValue } from '~/context';
+import { DynamicIcon } from '~/elements';
import { useOpposingColor } from '~/hooks';
import type { TextProps } from '@chakra-ui/react';
diff --git a/hyperglass/ui/components/output/highlighted.tsx b/hyperglass/ui/components/output/highlighted.tsx
index 359e496..9f0cdfc 100644
--- a/hyperglass/ui/components/output/highlighted.tsx
+++ b/hyperglass/ui/components/output/highlighted.tsx
@@ -45,13 +45,7 @@ const _Highlighted = (props: HighlightedProps): JSX.Element => {
times++;
}
- return (
- <>
- {result.map(r => (
- <>{r}>
- ))}
- >
- );
+ return <>{result}>;
};
export const Highlighted = memo(_Highlighted, isEqual);
diff --git a/hyperglass/ui/components/path/controls.tsx b/hyperglass/ui/components/path/controls.tsx
index d6e1f6c..e4636ea 100644
--- a/hyperglass/ui/components/path/controls.tsx
+++ b/hyperglass/ui/components/path/controls.tsx
@@ -1,6 +1,6 @@
import { ButtonGroup, IconButton } from '@chakra-ui/react';
import { useZoomPanHelper } from 'react-flow-renderer';
-import { DynamicIcon } from '~/components';
+import { DynamicIcon } from '~/elements';
export const Controls = (): JSX.Element => {
const { fitView, zoomIn, zoomOut } = useZoomPanHelper();
diff --git a/hyperglass/ui/components/path/path-button.tsx b/hyperglass/ui/components/path/path-button.tsx
index 38a5d04..4b1d121 100644
--- a/hyperglass/ui/components/path/path-button.tsx
+++ b/hyperglass/ui/components/path/path-button.tsx
@@ -1,5 +1,5 @@
import { Button, Tooltip } from '@chakra-ui/react';
-import { DynamicIcon } from '~/components';
+import { DynamicIcon } from '~/elements';
interface PathButtonProps {
onOpen(): void;
diff --git a/hyperglass/ui/components/layout/reset-button.tsx b/hyperglass/ui/components/reset-button.tsx
similarity index 96%
rename from hyperglass/ui/components/layout/reset-button.tsx
rename to hyperglass/ui/components/reset-button.tsx
index 64a7d23..7348583 100644
--- a/hyperglass/ui/components/layout/reset-button.tsx
+++ b/hyperglass/ui/components/reset-button.tsx
@@ -1,7 +1,7 @@
import { Flex, IconButton } from '@chakra-ui/react';
import { AnimatePresence } from 'framer-motion';
-import { AnimatedDiv, DynamicIcon } from '~/components';
import { useColorValue } from '~/context';
+import { AnimatedDiv, DynamicIcon } from '~/elements';
import { useOpposingColor, useFormState } from '~/hooks';
import type { FlexProps } from '@chakra-ui/react';
diff --git a/hyperglass/ui/components/resolved-target.tsx b/hyperglass/ui/components/resolved-target.tsx
index 1264225..d976967 100644
--- a/hyperglass/ui/components/resolved-target.tsx
+++ b/hyperglass/ui/components/resolved-target.tsx
@@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { Button, Stack, Text, VStack } from '@chakra-ui/react';
-import { DynamicIcon } from '~/components';
import { useConfig, useColorValue } from '~/context';
+import { DynamicIcon } from '~/elements';
import { useStrf, useDNSQuery, useFormState } from '~/hooks';
import type { DnsOverHttps } from '~/types';
diff --git a/hyperglass/ui/components/results/copy-button.tsx b/hyperglass/ui/components/results/copy-button.tsx
index 70cce55..fddd87e 100644
--- a/hyperglass/ui/components/results/copy-button.tsx
+++ b/hyperglass/ui/components/results/copy-button.tsx
@@ -1,5 +1,5 @@
import { Button, Tooltip, useClipboard } from '@chakra-ui/react';
-import { DynamicIcon } from '~/components';
+import { DynamicIcon } from '~/elements';
import type { ButtonProps } from '@chakra-ui/react';
diff --git a/hyperglass/ui/components/results/group.tsx b/hyperglass/ui/components/results/group.tsx
index a11dbb6..585671f 100644
--- a/hyperglass/ui/components/results/group.tsx
+++ b/hyperglass/ui/components/results/group.tsx
@@ -1,7 +1,7 @@
import { useEffect } from 'react';
import { Accordion } from '@chakra-ui/react';
import { AnimatePresence } from 'framer-motion';
-import { AnimatedDiv } from '~/components';
+import { AnimatedDiv } from '~/elements';
import { useFormState } from '~/hooks';
import { Result } from './individual';
import { Tags } from './tags';
diff --git a/hyperglass/ui/components/results/header.tsx b/hyperglass/ui/components/results/header.tsx
index 95d8b7b..ee21359 100644
--- a/hyperglass/ui/components/results/header.tsx
+++ b/hyperglass/ui/components/results/header.tsx
@@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { AccordionIcon, Box, Spinner, HStack, Text, Tooltip } from '@chakra-ui/react';
-import { DynamicIcon } from '~/components';
import { useConfig, useColorValue } from '~/context';
+import { DynamicIcon } from '~/elements';
import { useOpposingColor, useStrf } from '~/hooks';
import type { ErrorLevels } from '~/types';
diff --git a/hyperglass/ui/components/results/individual.tsx b/hyperglass/ui/components/results/individual.tsx
index e2b6578..50f50ae 100644
--- a/hyperglass/ui/components/results/individual.tsx
+++ b/hyperglass/ui/components/results/individual.tsx
@@ -16,8 +16,9 @@ import { motion } from 'framer-motion';
import startCase from 'lodash/startCase';
import isEqual from 'react-fast-compare';
import { If, Then, Else } from 'react-if';
-import { BGPTable, Countdown, DynamicIcon, Path, TextOutput } from '~/components';
+import { BGPTable, Path, TextOutput } from '~/components';
import { useColorValue, useConfig, useMobile } from '~/context';
+import { Countdown, DynamicIcon } from '~/elements';
import { useStrf, useLGQuery, useTableToString, useFormState, useDevice } from '~/hooks';
import { isStructuredOutput, isStringOutput } from '~/types';
import { isStackError, isFetchError, isLGError, isLGOutputOrError } from './guards';
@@ -227,8 +228,8 @@ const _Result: React.ForwardRefRenderFunction = (
>
- {!isError && typeof data !== 'undefined' ? (
- <>
+
+
{isStructuredOutput(data) && data.level === 'success' && tableComponent ? (
{data.output}
) : isStringOutput(data) && data.level === 'success' && !tableComponent ? (
@@ -242,12 +243,13 @@ const _Result: React.ForwardRefRenderFunction = (
)}
- >
- ) : (
-
-
-
- )}
+
+
+
+
+
+
+
@@ -260,24 +262,26 @@ const _Result: React.ForwardRefRenderFunction = (
justifyContent={{ base: 'flex-start', lg: 'flex-end' }}
>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hyperglass/ui/components/results/requery-button.tsx b/hyperglass/ui/components/results/requery-button.tsx
index f4ab286..50adf48 100644
--- a/hyperglass/ui/components/results/requery-button.tsx
+++ b/hyperglass/ui/components/results/requery-button.tsx
@@ -1,6 +1,6 @@
import { forwardRef } from 'react';
import { Button, Tooltip } from '@chakra-ui/react';
-import { DynamicIcon } from '~/components';
+import { DynamicIcon } from '~/elements';
import type { ButtonProps } from '@chakra-ui/react';
import type { UseQueryResult } from 'react-query';
diff --git a/hyperglass/ui/components/results/tags.tsx b/hyperglass/ui/components/results/tags.tsx
index b4c04b7..7d82421 100644
--- a/hyperglass/ui/components/results/tags.tsx
+++ b/hyperglass/ui/components/results/tags.tsx
@@ -1,8 +1,8 @@
import { useMemo } from 'react';
import { Box, Stack, useToken } from '@chakra-ui/react';
import { motion, AnimatePresence } from 'framer-motion';
-import { Label } from '~/components';
import { useConfig, useBreakpointValue } from '~/context';
+import { Label } from '~/elements';
import { useFormState } from '~/hooks';
import type { Transition } from 'framer-motion';
diff --git a/hyperglass/ui/components/submit-button.tsx b/hyperglass/ui/components/submit-button.tsx
index 7b8f400..e62e747 100644
--- a/hyperglass/ui/components/submit-button.tsx
+++ b/hyperglass/ui/components/submit-button.tsx
@@ -15,8 +15,9 @@ import {
} from '@chakra-ui/react';
import { useFormContext } from 'react-hook-form';
import { If, Then, Else } from 'react-if';
-import { DynamicIcon, ResolvedTarget } from '~/components';
+import { ResolvedTarget } from '~/components';
import { useMobile, useColorValue } from '~/context';
+import { DynamicIcon } from '~/elements';
import { useFormState } from '~/hooks';
import type { IconButtonProps } from '@chakra-ui/react';
diff --git a/hyperglass/ui/components/table/main.tsx b/hyperglass/ui/components/table/main.tsx
index bd242c3..9d2a671 100644
--- a/hyperglass/ui/components/table/main.tsx
+++ b/hyperglass/ui/components/table/main.tsx
@@ -4,7 +4,7 @@ import { Flex, Text } from '@chakra-ui/react';
import { usePagination, useSortBy, useTable } from 'react-table';
import { If, Then, Else } from 'react-if';
import { useMobile } from '~/context';
-import { CardBody, CardFooter, CardHeader, DynamicIcon } from '~/components';
+import { CardBody, CardFooter, CardHeader, DynamicIcon } from '~/elements';
import { TableMain } from './table';
import { TableCell } from './cell';
import { TableHead } from './head';
diff --git a/hyperglass/ui/components/user-ip.tsx b/hyperglass/ui/components/user-ip.tsx
index bd9ffc0..6f22a00 100644
--- a/hyperglass/ui/components/user-ip.tsx
+++ b/hyperglass/ui/components/user-ip.tsx
@@ -1,7 +1,8 @@
import { useMemo } from 'react';
import { Button, Stack, Text, VStack, useDisclosure } from '@chakra-ui/react';
-import { DynamicIcon, Prompt } from '~/components';
+import { Prompt } from '~/components';
import { useConfig, useColorValue } from '~/context';
+import { DynamicIcon } from '~/elements';
import { useStrf, useWtf } from '~/hooks';
interface UserIPProps {
diff --git a/hyperglass/ui/components/animated.ts b/hyperglass/ui/elements/animated.ts
similarity index 100%
rename from hyperglass/ui/components/animated.ts
rename to hyperglass/ui/elements/animated.ts
diff --git a/hyperglass/ui/components/card/body.tsx b/hyperglass/ui/elements/card/body.tsx
similarity index 100%
rename from hyperglass/ui/components/card/body.tsx
rename to hyperglass/ui/elements/card/body.tsx
diff --git a/hyperglass/ui/components/card/footer.tsx b/hyperglass/ui/elements/card/footer.tsx
similarity index 100%
rename from hyperglass/ui/components/card/footer.tsx
rename to hyperglass/ui/elements/card/footer.tsx
diff --git a/hyperglass/ui/components/card/header.tsx b/hyperglass/ui/elements/card/header.tsx
similarity index 100%
rename from hyperglass/ui/components/card/header.tsx
rename to hyperglass/ui/elements/card/header.tsx
diff --git a/hyperglass/ui/components/card/index.ts b/hyperglass/ui/elements/card/index.ts
similarity index 100%
rename from hyperglass/ui/components/card/index.ts
rename to hyperglass/ui/elements/card/index.ts
diff --git a/hyperglass/ui/components/code-block.tsx b/hyperglass/ui/elements/code-block.tsx
similarity index 100%
rename from hyperglass/ui/components/code-block.tsx
rename to hyperglass/ui/elements/code-block.tsx
diff --git a/hyperglass/ui/components/countdown.tsx b/hyperglass/ui/elements/countdown.tsx
similarity index 100%
rename from hyperglass/ui/components/countdown.tsx
rename to hyperglass/ui/elements/countdown.tsx
diff --git a/hyperglass/ui/components/custom.tsx b/hyperglass/ui/elements/custom.tsx
similarity index 100%
rename from hyperglass/ui/components/custom.tsx
rename to hyperglass/ui/elements/custom.tsx
diff --git a/hyperglass/ui/components/dynamic-icon.tsx b/hyperglass/ui/elements/dynamic-icon.tsx
similarity index 100%
rename from hyperglass/ui/components/dynamic-icon.tsx
rename to hyperglass/ui/elements/dynamic-icon.tsx
diff --git a/hyperglass/ui/components/favicon.tsx b/hyperglass/ui/elements/favicon.tsx
similarity index 100%
rename from hyperglass/ui/components/favicon.tsx
rename to hyperglass/ui/elements/favicon.tsx
diff --git a/hyperglass/ui/components/form-row.tsx b/hyperglass/ui/elements/form-row.tsx
similarity index 100%
rename from hyperglass/ui/components/form-row.tsx
rename to hyperglass/ui/elements/form-row.tsx
diff --git a/hyperglass/ui/elements/index.ts b/hyperglass/ui/elements/index.ts
new file mode 100644
index 0000000..64df0df
--- /dev/null
+++ b/hyperglass/ui/elements/index.ts
@@ -0,0 +1,21 @@
+/**
+ * The elements directory contains React components that are stateless and contain no logic or
+ * references to configuration.
+ *
+ * Generally, elements should not call non-theme-related hooks, rely on context, or reference
+ * configuration/API types.
+ */
+
+export * from './animated';
+export * from './card';
+export * from './code-block';
+export * from './countdown';
+export * from './custom';
+export * from './dynamic-icon';
+export * from './favicon';
+export * from './form-row';
+export * from './label';
+export * from './load-error';
+export * from './loading';
+export * from './markdown';
+export * from './no-config';
diff --git a/hyperglass/ui/components/label.tsx b/hyperglass/ui/elements/label.tsx
similarity index 100%
rename from hyperglass/ui/components/label.tsx
rename to hyperglass/ui/elements/label.tsx
diff --git a/hyperglass/ui/components/load-error.tsx b/hyperglass/ui/elements/load-error.tsx
similarity index 98%
rename from hyperglass/ui/components/load-error.tsx
rename to hyperglass/ui/elements/load-error.tsx
index b86d2f6..779bd72 100644
--- a/hyperglass/ui/components/load-error.tsx
+++ b/hyperglass/ui/elements/load-error.tsx
@@ -7,7 +7,7 @@ import {
AlertTitle,
AlertDescription,
} from '@chakra-ui/react';
-import { NoConfig } from './no-config';
+import { NoConfig } from '~/elements';
import type { CenterProps } from '@chakra-ui/react';
import type { ConfigLoadError } from '~/util';
diff --git a/hyperglass/ui/components/loading.tsx b/hyperglass/ui/elements/loading.tsx
similarity index 82%
rename from hyperglass/ui/components/loading.tsx
rename to hyperglass/ui/elements/loading.tsx
index 2120765..79575bf 100644
--- a/hyperglass/ui/components/loading.tsx
+++ b/hyperglass/ui/elements/loading.tsx
@@ -1,5 +1,5 @@
import { Spinner } from '@chakra-ui/react';
-import { NoConfig } from './no-config';
+import { NoConfig } from '~/elements';
export const Loading = (): JSX.Element => {
return (
diff --git a/hyperglass/ui/components/markdown/elements.tsx b/hyperglass/ui/elements/markdown/elements.tsx
similarity index 98%
rename from hyperglass/ui/components/markdown/elements.tsx
rename to hyperglass/ui/elements/markdown/elements.tsx
index b996bc0..5f91dd4 100644
--- a/hyperglass/ui/components/markdown/elements.tsx
+++ b/hyperglass/ui/elements/markdown/elements.tsx
@@ -18,7 +18,7 @@ import {
ListItem as ChakraListItem,
} from '@chakra-ui/react';
import { If, Then, Else } from 'react-if';
-import { CodeBlock as CustomCodeBlock } from '~/components';
+import { CodeBlock as CustomCodeBlock } from '~/elements';
import { useColorValue } from '~/context';
import type {
diff --git a/hyperglass/ui/components/markdown/index.ts b/hyperglass/ui/elements/markdown/index.ts
similarity index 100%
rename from hyperglass/ui/components/markdown/index.ts
rename to hyperglass/ui/elements/markdown/index.ts
diff --git a/hyperglass/ui/components/markdown/markdown.tsx b/hyperglass/ui/elements/markdown/markdown.tsx
similarity index 100%
rename from hyperglass/ui/components/markdown/markdown.tsx
rename to hyperglass/ui/elements/markdown/markdown.tsx
diff --git a/hyperglass/ui/components/no-config.tsx b/hyperglass/ui/elements/no-config.tsx
similarity index 100%
rename from hyperglass/ui/components/no-config.tsx
rename to hyperglass/ui/elements/no-config.tsx
diff --git a/hyperglass/ui/hooks/index.ts b/hyperglass/ui/hooks/index.ts
index bebe080..cc0c05a 100644
--- a/hyperglass/ui/hooks/index.ts
+++ b/hyperglass/ui/hooks/index.ts
@@ -1,3 +1,4 @@
+export * from './theme-hooks';
export * from './useASNDetail';
export * from './useBooleanValue';
export * from './useDevice';
diff --git a/hyperglass/ui/hooks/theme-hooks.ts b/hyperglass/ui/hooks/theme-hooks.ts
new file mode 100644
index 0000000..262aefb
--- /dev/null
+++ b/hyperglass/ui/hooks/theme-hooks.ts
@@ -0,0 +1,34 @@
+import {
+ useBreakpointValue,
+ useTheme as useChakraTheme,
+ useColorModeValue,
+ useToken,
+} from '@chakra-ui/react';
+import type { Theme } from '~/types';
+
+export {
+ useBreakpointValue,
+ useColorMode,
+ useColorModeValue as useColorValue,
+ useToken,
+} from '@chakra-ui/react';
+
+/**
+ * Determine if device is mobile or desktop based on Chakra UI theme breakpoints.
+ */
+export const useMobile = (): boolean =>
+ useBreakpointValue({ base: true, md: true, lg: false, xl: false }) ?? true;
+
+/**
+ * Get the current theme object.
+ */
+export const useTheme = (): Theme.Full => useChakraTheme();
+
+/**
+ * Convenience function to combine Chakra UI's useToken & useColorModeValue.
+ */
+export const useColorToken = (
+ token: keyof Theme.Full,
+ light: L,
+ dark: D,
+): L | D => useColorModeValue(useToken(token, light), useToken(token, dark));
diff --git a/hyperglass/ui/pages/_app.tsx b/hyperglass/ui/pages/_app.tsx
index 1afd2eb..2b905ad 100644
--- a/hyperglass/ui/pages/_app.tsx
+++ b/hyperglass/ui/pages/_app.tsx
@@ -1,15 +1,45 @@
import { QueryClient, QueryClientProvider } from 'react-query';
+import { Switch, Case, Default } from 'react-if';
+import { Meta, Layout } from '~/components';
+import { HyperglassProvider } from '~/context';
+import { LoadError, Loading } from '~/elements';
+import { useHyperglassConfig } from '~/hooks';
import type { AppProps } from 'next/app';
const queryClient = new QueryClient();
-const App = (props: AppProps): JSX.Element => {
+const AppComponent = (props: AppProps) => {
const { Component, pageProps } = props;
+ const { data, error, isLoading, ready, refetch, showError, isLoadingInitial } =
+ useHyperglassConfig();
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+const App = (props: AppProps): JSX.Element => {
return (
-
+
);
};
diff --git a/hyperglass/ui/pages/_document.tsx b/hyperglass/ui/pages/_document.tsx
index ab3053d..811e418 100644
--- a/hyperglass/ui/pages/_document.tsx
+++ b/hyperglass/ui/pages/_document.tsx
@@ -1,6 +1,6 @@
import fs from 'fs';
import Document, { Html, Head, Main, NextScript } from 'next/document';
-import { Favicon, CustomJavascript, CustomHtml } from '~/components';
+import { CustomJavascript, CustomHtml, Favicon } from '~/elements';
import favicons from '../favicon-formats';
import type { DocumentContext, DocumentInitialProps } from 'next/document';
diff --git a/hyperglass/ui/pages/index.tsx b/hyperglass/ui/pages/index.tsx
index cf2c192..e7e2dc1 100644
--- a/hyperglass/ui/pages/index.tsx
+++ b/hyperglass/ui/pages/index.tsx
@@ -1,37 +1,36 @@
import dynamic from 'next/dynamic';
-import { Switch, Case, Default } from 'react-if';
-import { Meta, Loading, LoadError } from '~/components';
-import { HyperglassProvider } from '~/context';
-import { useHyperglassConfig } from '~/hooks';
+import { If, Then, Else } from 'react-if';
+import { Loading } from '~/elements';
+import { useView } from '~/hooks';
import type { NextPage } from 'next';
+import type { AnimatePresenceProps } from 'framer-motion';
-const Layout = dynamic(() => import('~/components').then(i => i.Layout), {
+const AnimatePresence = dynamic(() =>
+ import('framer-motion').then(i => i.AnimatePresence),
+);
+
+const LookingGlassForm = dynamic(() => import('~/components').then(i => i.LookingGlassForm), {
+ loading: Loading,
+});
+
+const Results = dynamic(() => import('~/components').then(i => i.Results), {
loading: Loading,
});
const Index: NextPage = () => {
- const { data, error, isLoading, ready, refetch, showError, isLoadingInitial } =
- useHyperglassConfig();
-
+ const view = useView();
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
);
};
diff --git a/hyperglass/ui/tsconfig.json b/hyperglass/ui/tsconfig.json
index 2066216..d9287a4 100644
--- a/hyperglass/ui/tsconfig.json
+++ b/hyperglass/ui/tsconfig.json
@@ -10,6 +10,8 @@
"~/components/*": ["components/*"],
"~/context": ["context/index"],
"~/context/*": ["context/*"],
+ "~/elements": ["elements/index"],
+ "~/elements/*": ["elements/*"],
"~/hooks": ["hooks/index"],
"~/hooks/*": ["hooks/*"],
"~/state": ["state/index"],
diff --git a/hyperglass/ui/types/guards.ts b/hyperglass/ui/types/guards.ts
index 8fb37d3..3e587f6 100644
--- a/hyperglass/ui/types/guards.ts
+++ b/hyperglass/ui/types/guards.ts
@@ -29,7 +29,7 @@ export function isStringOutput(data: unknown): data is StringQueryResponse {
* Determine if a form field name is a valid form key name.
*/
export function isQueryField(field: string): field is keyof FormData {
- return ['queryLocation', 'queryType', 'queryGroup', 'queryTarget'].includes(field);
+ return ['queryLocation', 'queryType', 'queryTarget'].includes(field);
}
/**