Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support fixed, application-wide alerts #1472

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/app/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import PageContainer from 'components/shared/PageContainer';
import DocsSidePanel from 'components/sidePanelDocs/SidePanel';
import { useShowSidePanelDocs } from 'context/SidePanelDocs';
import { NavWidths } from 'context/Theme';
import { useEffect, useState } from 'react';
import { ReflexContainer, ReflexElement, ReflexSplitter } from 'react-reflex';
import { Outlet } from 'react-router';
import { useLocalStorage } from 'react-use';
import { useSidePanelDocsStore } from 'stores/SidePanelDocs/Store';
import { LocalStorageKeys } from 'utils/localStorage-utils';
import { useEffect, useState } from 'react';
import { hasLength } from 'utils/misc-utils';
import { useSidePanelDocsStore } from 'stores/SidePanelDocs/Store';

function AppLayout() {
const theme = useTheme();
Expand Down
97 changes: 97 additions & 0 deletions src/components/navigation/Banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {
Collapse,
IconButton,
Stack,
Typography,
useTheme,
} from '@mui/material';
import { NavArrowDown } from 'iconoir-react';
import { useEffect, useRef, useState } from 'react';
import { useTopBarStore } from 'stores/TopBar/Store';
import {
BANNER_HEIGHT,
getSemanticBackgroundColor,
getSemanticBorder,
isOverflown,
} from './shared';

export default function Banner() {
const theme = useTheme();

const contentEl = useRef<HTMLElement | null>(null);

const bannerOpen = useTopBarStore((state) => state.bannerOpen);
const setBannerOpen = useTopBarStore((state) => state.setBannerOpen);

const [severity, setSeverity] = useState<string>('');
const [expanded, setExpanded] = useState(false);
const [overflown, setOverflown] = useState(false);

useEffect(() => {
setSeverity('error');
setBannerOpen(true);
setOverflown(isOverflown(contentEl.current));
}, [setBannerOpen, setOverflown, setSeverity]);

return (
<Collapse in={bannerOpen}>
<Stack
direction="row"
style={{
alignItems: 'flex-start',
backgroundColor: getSemanticBackgroundColor(
theme.palette.mode,
severity
),
border: getSemanticBorder(theme.palette.mode, severity),
height: expanded ? 'fit-content' : BANNER_HEIGHT,
justifyContent: 'space-between',
paddingBottom: 4,
paddingLeft: 72,
paddingRight: 24,
paddingTop: 4,
}}
>
<Typography
noWrap={!expanded}
ref={contentEl}
style={{ textOverflow: 'ellipsis' }}
variant="caption"
>
Here is a short message that could potentially be close to
the length of a real message. Here is a short message that
could potentially be close to the length of a real message.
Here is a short message that could potentially be close to
the length of a real message. Here is a short message that
could potentially be close to the length of a real message.
Here is a short message that could potentially be close to
the length of a real message. Here is a short message that
could potentially be close to the length of a real message.
Here is a short message that could potentially be close to
the length of a real message. Here is a short message that
could potentially be close to the length of a real message.
</Typography>

{overflown ? (
<IconButton
size="small"
onClick={() => {
setExpanded(!expanded);
}}
style={{ padding: 0 }}
>
<NavArrowDown
style={{
color: theme.palette.text.primary,
transform: expanded
? 'scaleY(-1)'
: 'scaleY(1)',
transition: 'all 50ms ease-in-out',
}}
/>
</IconButton>
) : null}
</Stack>
</Collapse>
);
}
14 changes: 8 additions & 6 deletions src/components/navigation/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,17 @@ import {
Settings,
} from 'iconoir-react';
import { useIntl } from 'react-intl';
import { useTopBarStore } from 'stores/TopBar/Store';
import ListItemLink from './ListItemLink';

interface NavigationProps {
open: boolean;
width: number;
onNavigationToggle: Function;
}
import { BANNER_HEIGHT } from './shared';
import { NavigationProps } from './types';

const Navigation = ({ open, width, onNavigationToggle }: NavigationProps) => {
const intl = useIntl();
const theme = useTheme();

const bannerOpen = useTopBarStore((state) => state.bannerOpen);

const openNavigation = () => {
onNavigationToggle(true);
};
Expand Down Expand Up @@ -70,6 +69,9 @@ const Navigation = ({ open, width, onNavigationToggle }: NavigationProps) => {
sx={{
height: '100%',
justifyContent: 'space-between',
marginTop: bannerOpen
? `${BANNER_HEIGHT - 8}px`
: undefined,
overflowX: 'hidden',
}}
>
Expand Down
7 changes: 5 additions & 2 deletions src/components/navigation/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import PageTitle from 'components/navigation/PageTitle';
import SidePanelDocsOpenButton from 'components/sidePanelDocs/OpenButton';
import { UpdateAlert } from 'components/UpdateAlert';
import { zIndexIncrement } from 'context/Theme';
import Banner from './Banner';

const Topbar = () => {
const TopBar = () => {
const theme = useTheme();

return (
Expand Down Expand Up @@ -48,8 +49,10 @@ const Topbar = () => {
<SidePanelDocsOpenButton />
</Stack>
</Toolbar>

<Banner />
</MuiAppBar>
);
};

export default Topbar;
export default TopBar;
53 changes: 53 additions & 0 deletions src/components/navigation/shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { PaletteMode } from '@mui/material';
import {
errorColoredOutline_hovered,
infoColoredOutline_hovered,
semiTransparentBackground_error,
semiTransparentBackground_info,
semiTransparentBackground_success,
semiTransparentBackground_warning,
successColoredOutline_hovered,
warningColoredOutline_hovered,
} from 'context/Theme';

export const BANNER_HEIGHT = 28;

export const getSemanticBackgroundColor = (
colorMode: PaletteMode,
severity: string
): string => {
switch (severity) {
case 'success':
return semiTransparentBackground_success[colorMode];
case 'error':
return semiTransparentBackground_error[colorMode];
case 'info':
return semiTransparentBackground_info[colorMode];
default:
return semiTransparentBackground_warning[colorMode];
}
};

export const getSemanticBorder = (
colorMode: PaletteMode,
severity: string
): string => {
switch (severity) {
case 'success':
return successColoredOutline_hovered[colorMode];
case 'error':
return errorColoredOutline_hovered[colorMode];
case 'info':
return infoColoredOutline_hovered[colorMode];
default:
return warningColoredOutline_hovered[colorMode];
}
};

export const isOverflown = (el: HTMLElement | null) => {
if (!el) {
return false;
}

return el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth;
};
5 changes: 5 additions & 0 deletions src/components/navigation/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface NavigationProps {
open: boolean;
width: number;
onNavigationToggle: Function;
}
4 changes: 2 additions & 2 deletions src/components/shared/PageContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Container, Paper, Snackbar, useTheme } from '@mui/material';
import Topbar from 'components/navigation/TopBar';
import TopBar from 'components/navigation/TopBar';
import { paperBackground } from 'context/Theme';
import { ReactNode, useEffect, useMemo, useState } from 'react';
import useNotificationStore, {
Expand Down Expand Up @@ -108,7 +108,7 @@ function PageContainer({ children, hideBackground }: Props) {
</Snackbar>
) : null}

<Topbar />
<TopBar />

<Paper
sx={{
Expand Down
40 changes: 40 additions & 0 deletions src/context/Theme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,16 @@ export const errorColoredOutline_hovered = {
dark: `1px solid #CA3B55`,
};

export const warningColoredOutline_hovered = {
light: `1px solid #F5D75E`,
dark: `1px solid #F57C00`,
};

export const infoColoredOutline_hovered = {
light: `1px solid #4FD6FF`,
dark: `1px solid #0288D1`,
};

export const jsonViewTheme: {
light: ThemeKeys;
dark: ThemeKeys;
Expand Down Expand Up @@ -378,6 +388,36 @@ export const semiTransparentBackground_purple = {
dark: 'rgba(214, 194, 255, 0.12)',
};

// Light is an RGB translation of #3A56CA; Dark is an RGB translation of #BACDFD.
export const semiTransparentBackground_primary = {
light: 'rgba(58, 86, 202, 0.3)',
dark: 'rgba(186, 205, 253, 0.3)',
};

// Light is an RGB translation of #2A7942; Dark is an RGB translation of #66BB6A.
export const semiTransparentBackground_success = {
light: 'rgba(42, 121, 66, 0.5)',
dark: 'rgba(102, 187, 106, 0.5)',
};

// RGB translation of #CA3B55.
export const semiTransparentBackground_error = {
light: 'rgba(202, 59, 85, 0.5)',
dark: 'rgba(202, 59, 85, 0.5)',
};

// Light is an RGB translation of #F5D75E; Dark is an RGB translation of #F57C00.
export const semiTransparentBackground_warning = {
light: 'rgba(245, 215, 94, 0.5)',
dark: 'rgba(245, 124, 0, 0.5)',
};

// Light is an RGB translation of #4FD6FF; Dark is an RGB translation of #0288D1.
export const semiTransparentBackground_info = {
light: 'rgba(79, 214, 255, 0.5)',
dark: 'rgba(2, 136, 209, 0.5)',
};

export const primaryColoredBackground_hovered = {
light: '#3149AB',
dark: '#9EAED7',
Expand Down
16 changes: 15 additions & 1 deletion src/stores/TopBar/Store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { devtools, NamedSet } from 'zustand/middleware';
import { GlobalStoreNames } from '../names';
import { TopBarState } from './types';

const getInitialStateData = (): Pick<TopBarState, 'header' | 'headerLink'> => ({
const getInitialStateData = (): Pick<
TopBarState,
'bannerOpen' | 'header' | 'headerLink'
> => ({
bannerOpen: false,
header: '',
headerLink: undefined,
});
Expand All @@ -16,6 +20,16 @@ const getInitialState = (
): TopBarState => ({
...getInitialStateData(),

setBannerOpen: (value) => {
set(
produce((state: TopBarState) => {
state.bannerOpen = value;
}),
false,
'Application Banner Open Set'
);
},

setHeader: (val) => {
set(
produce((state: TopBarState) => {
Expand Down
3 changes: 3 additions & 0 deletions src/stores/TopBar/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ export interface TopBarState {
headerLink: string | undefined;
setHeaderLink: (val: TopBarState['headerLink']) => void;

bannerOpen: boolean;
setBannerOpen: (value: TopBarState['bannerOpen']) => void;

resetState: () => void;
}