Add toggleable dark mode to errata

This commit is contained in:
Ted Adams 2023-01-26 01:34:14 -08:00
parent c0b97f5c85
commit b6d94ecdc4
5 changed files with 120 additions and 33 deletions

View File

@ -51,6 +51,7 @@ import {
Input, Input,
InputGroup, InputGroup,
InputLeftElement, InputLeftElement,
Link,
Select, Select,
Spinner, Spinner,
Stack, Stack,
@ -80,13 +81,18 @@ import {
} from 'bazel-bin/apollo/proto/v1/client_typescript/models'; } from 'bazel-bin/apollo/proto/v1/client_typescript/models';
import { reqap } from 'common/ui/reqap'; import { reqap } from 'common/ui/reqap';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom'; import { Link as RouterLink } from 'react-router-dom';
import { api } from '../api'; import { api } from '../api';
import { COLOR_RESF_GREEN } from '../styles'; import { COLOR_RESF_GREEN } from '../styles';
export const Overview = () => { export const Overview = () => {
const inputBackground = useColorModeValue('white', 'gray.800'); const inputBackground = useColorModeValue('white', undefined);
const tableBg = useColorModeValue('white', 'gray.800');
const pagerButtonScheme = useColorModeValue('blackAlpha', 'gray');
const linkBlue = useColorModeValue('blue.600', 'blue.300');
const linkPurple = useColorModeValue('purple.600', 'purple.300');
const [advisories, setAdvisories] = useState<V1Advisory[]>(); const [advisories, setAdvisories] = useState<V1Advisory[]>();
const [lastUpdated, setLastUpdated] = useState<Date>(); const [lastUpdated, setLastUpdated] = useState<Date>();
@ -340,7 +346,7 @@ export const Overview = () => {
size="xs" size="xs"
isAttached isAttached
alignItems="stretch" alignItems="stretch"
colorScheme="blackAlpha" colorScheme={pagerButtonScheme}
> >
<IconButton <IconButton
aria-label="First Page" aria-label="First Page"
@ -359,7 +365,7 @@ export const Overview = () => {
// borderTop="1px solid" // borderTop="1px solid"
// borderBottom="1px solid" // borderBottom="1px solid"
borderColor="gray.200" borderColor="gray.200"
backgroundColor="white" backgroundColor={tableBg}
lineHeight="24px" lineHeight="24px"
px={2} px={2}
> >
@ -401,9 +407,9 @@ export const Overview = () => {
<AlertDescription>Failed to load errata</AlertDescription> <AlertDescription>Failed to load errata</AlertDescription>
</Alert> </Alert>
) : ( ) : (
<Box backgroundColor="white" boxShadow="base"> <Box backgroundColor={tableBg} boxShadow="base">
<TableContainer> <TableContainer>
<Table size="sm"> <Table size="sm" variant="striped">
<Thead> <Thead>
<Tr> <Tr>
<Th {...stickyProps} width="36px" /> <Th {...stickyProps} width="36px" />
@ -424,37 +430,33 @@ export const Overview = () => {
)} )}
{advisories?.map((a, idx) => ( {advisories?.map((a, idx) => (
<Tr key={a.name}> <Tr key={a.name}>
<Td <Td textAlign="center" pr={0}>
backgroundColor={idx % 2 ? 'gray.50' : undefined}
textAlign="center"
pr={0}
>
{severityToBadge(a.severity, a.type)} {severityToBadge(a.severity, a.type)}
</Td> </Td>
<Td backgroundColor={idx % 2 ? 'gray.50' : undefined}> <Td>
<Link <Link
className="text-peridot-primary visited:text-purple-500" as={RouterLink}
to={`/${a.name}`} to={`/${a.name}`}
color={linkBlue}
_visited={{ color: linkPurple }}
> >
{a.name} {a.name}
</Link> </Link>
</Td> </Td>
<Td backgroundColor={idx % 2 ? 'gray.50' : undefined}> <Td>
{a.synopsis?.replace( {a.synopsis?.replace(
/^(Critical|Important|Moderate|Low): /, /^(Critical|Important|Moderate|Low): /,
'' ''
)} )}
</Td> </Td>
<Td backgroundColor={idx % 2 ? 'gray.50' : undefined}> <Td>
{typeToText(a.type)} {typeToText(a.type)}
{a.type === V1AdvisoryType.Security {a.type === V1AdvisoryType.Security
? ` / ${severityToText(a.severity)}` ? ` / ${severityToText(a.severity)}`
: ''} : ''}
</Td> </Td>
<Td backgroundColor={idx % 2 ? 'gray.50' : undefined}> <Td>{a.affectedProducts?.join(', ')}</Td>
{a.affectedProducts?.join(', ')} <Td>
</Td>
<Td backgroundColor={idx % 2 ? 'gray.50' : undefined}>
{Intl.DateTimeFormat(undefined, { {Intl.DateTimeFormat(undefined, {
day: '2-digit', day: '2-digit',
month: 'short', month: 'short',

View File

@ -30,7 +30,17 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
import { Box, HStack, Text, Link as ChakraLink } from '@chakra-ui/react'; import { MoonIcon, SunIcon } from '@chakra-ui/icons';
import {
Box,
HStack,
Text,
Link as ChakraLink,
useColorMode,
IconButton,
useColorModeValue,
DarkMode,
} from '@chakra-ui/react';
import { RESFLogo } from 'common/ui/RESFLogo'; import { RESFLogo } from 'common/ui/RESFLogo';
import React from 'react'; import React from 'react';
import { Route, Switch } from 'react-router'; import { Route, Switch } from 'react-router';
@ -41,6 +51,11 @@ import { Overview } from './Overview';
import { ShowErrata } from './ShowErrata'; import { ShowErrata } from './ShowErrata';
export const Root = () => { export const Root = () => {
const { colorMode, toggleColorMode } = useColorMode();
const SwitchIcon = useColorModeValue(MoonIcon, SunIcon);
const bodyBg = useColorModeValue('gray.100', 'gray.900');
return ( return (
<Box <Box
display="flex" display="flex"
@ -55,6 +70,7 @@ export const Root = () => {
display="flex" display="flex"
flexDirection="row" flexDirection="row"
alignItems="center" alignItems="center"
justifyContent="space-between"
py="1" py="1"
px={4} px={4}
> >
@ -75,8 +91,20 @@ export const Root = () => {
</Text> </Text>
</HStack> </HStack>
</Link> </Link>
<DarkMode>
<IconButton
size="md"
fontSize="lg"
aria-label={`Switch to ${
colorMode === 'light' ? 'dark' : 'light'
} mode`}
variant="ghost"
onClick={toggleColorMode}
icon={<SwitchIcon />}
/>
</DarkMode>
</Box> </Box>
<Box as="main" flexGrow={1} overflow="auto"> <Box as="main" flexGrow={1} overflow="auto" background={bodyBg}>
<Switch> <Switch>
<Route path="/" exact component={Overview} /> <Route path="/" exact component={Overview} />
<Route path="/:id" component={ShowErrata} /> <Route path="/:id" component={ShowErrata} />

View File

@ -51,6 +51,7 @@ import {
Tabs, Tabs,
Text, Text,
UnorderedList, UnorderedList,
useColorModeValue,
VStack, VStack,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
@ -68,7 +69,7 @@ import { RouteComponentProps } from 'react-router';
import { Link as RouterLink } from 'react-router-dom'; import { Link as RouterLink } from 'react-router-dom';
import { api } from '../api'; import { api } from '../api';
import { COLOR_RESF_BLUE, COLOR_RESF_GREEN } from '../styles'; import { COLOR_RESF_GREEN } from '../styles';
interface ShowErrataParams { interface ShowErrataParams {
id: string; id: string;
@ -80,6 +81,11 @@ export interface ShowErrataProps
export const ShowErrata = (props: ShowErrataProps) => { export const ShowErrata = (props: ShowErrataProps) => {
const id = props.match.params.id; const id = props.match.params.id;
const cardBg = useColorModeValue('white', 'gray.800');
const sideBg = useColorModeValue('gray.100', 'gray.700');
const linkBlue = useColorModeValue('blue.600', 'blue.300');
const linkPurple = useColorModeValue('purple.600', 'purple.300');
const [errata, setErrata] = useState<V1Advisory>(); const [errata, setErrata] = useState<V1Advisory>();
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [isError, setIsError] = useState(false); const [isError, setIsError] = useState(false);
@ -152,7 +158,7 @@ export const ShowErrata = (props: ShowErrataProps) => {
<> <>
<HStack <HStack
alignItems="center" alignItems="center"
backgroundColor="white" backgroundColor={cardBg}
py="2" py="2"
px="4" px="4"
spacing="6" spacing="6"
@ -168,7 +174,7 @@ export const ShowErrata = (props: ShowErrataProps) => {
<Text fontSize="sm">{errata.synopsis}</Text> <Text fontSize="sm">{errata.synopsis}</Text>
</VStack> </VStack>
</HStack> </HStack>
<Tabs backgroundColor="white" p="2"> <Tabs backgroundColor={cardBg} p="2">
<TabList> <TabList>
<Tab>Erratum</Tab> <Tab>Erratum</Tab>
<Tab>Affected Packages</Tab> <Tab>Affected Packages</Tab>
@ -238,7 +244,7 @@ export const ShowErrata = (props: ShowErrataProps) => {
minWidth="300px" minWidth="300px"
spacing="5" spacing="5"
flexShrink={0} flexShrink={0}
backgroundColor="gray.100" backgroundColor={sideBg}
> >
<Text> <Text>
<b>Issued:</b> {errata.publishedAt?.toLocaleDateString()} <b>Issued:</b> {errata.publishedAt?.toLocaleDateString()}
@ -270,7 +276,10 @@ export const ShowErrata = (props: ShowErrataProps) => {
<Link <Link
href={x.sourceLink} href={x.sourceLink}
isExternal isExternal
color={COLOR_RESF_BLUE} color={linkBlue}
_visited={{
color: linkPurple,
}}
> >
{x.sourceBy} - {x.ticket} {x.sourceBy} - {x.ticket}
</Link> </Link>
@ -295,7 +304,10 @@ export const ShowErrata = (props: ShowErrataProps) => {
<Link <Link
href={x.sourceLink} href={x.sourceLink}
isExternal isExternal
color={COLOR_RESF_BLUE} color={linkBlue}
_visited={{
color: linkPurple,
}}
> >
{text} {text}
</Link> </Link>

View File

@ -32,20 +32,24 @@
import 'tailwind/tailwind.css'; import 'tailwind/tailwind.css';
import { ChakraProvider } from '@chakra-ui/react'; import { ChakraProvider, ColorModeScript } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import { Root } from './components/Root'; import { Root } from './components/Root';
import theme from './theme';
export const app = () => { export const app = () => {
ReactDOM.render( ReactDOM.render(
<BrowserRouter> <>
<ChakraProvider> <ColorModeScript initialColorMode={theme.config.initialColorMode} />
<Root /> <BrowserRouter>
</ChakraProvider> <ChakraProvider theme={theme}>
</BrowserRouter>, <Root />
</ChakraProvider>
</BrowserRouter>
</>,
document.getElementById('root') document.getElementById('root')
); );
}; };

41
apollo/ui/src/theme.ts Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (c) All respective contributors to the Peridot Project. All rights reserved.
* Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved.
* Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
import { extendTheme, type ThemeConfig } from '@chakra-ui/react';
const config: ThemeConfig = {
initialColorMode: 'system',
};
const theme = extendTheme({ config });
export default theme;