Skip to content

Commit

Permalink
feat(client-electron): add dynamic navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
marcincichocki committed Oct 11, 2022
1 parent 21213f2 commit a5bbb5d
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 77 deletions.
8 changes: 4 additions & 4 deletions src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
export * from './common';
export * from './daemons-i18n';
export * from './ocr';
export {
BreachProtocol,
export { BreachProtocol } from './solver/breach-protocol';
export type {
BreachProtocolOptions,
BreachProtocolResultJSON,
BreachProtocolStrategy,
} from './solver/breach-protocol';
export { FocusHierarchyProvider } from './solver/hierarchy/focus-hierarchy-provider';
export { HierarchyProvider } from './solver/hierarchy/hierarchy-provider';
export type { HierarchyProvider } from './solver/hierarchy/hierarchy-provider';
export { IndexHierarchyProvider } from './solver/hierarchy/index-hierarchy-provider';
export { SequenceJSON } from './solver/sequence';
export type { SequenceJSON } from './solver/sequence';
1 change: 1 addition & 0 deletions src/electron/renderer/components/BufferSizeViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const BufferSizeWrapper = styled.div`
width: calc(${getBufferSizeWrapperWidth()});
overflow-x: auto;
cursor: default;
flex-shrink: 0;
`;

const BufferSizeItem = styled(Square)`
Expand Down
6 changes: 4 additions & 2 deletions src/electron/renderer/components/DaemonsViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import {
import styled from 'styled-components';
import { Col, Row, Spacer } from './Flex';
import { Highlight } from './HistoryViewer';
import { Only } from './Only';

const DaemonsWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 0.5rem;
overflow-y: auto;
flex: 1;
cursor: default;
`;

Expand Down Expand Up @@ -76,7 +76,9 @@ export const DaemonsViewer = ({
}
onMouseLeave={onHighlight ? () => onHighlight(null) : undefined}
>
{types?.isValid && <DaemonType>{eng[types.rawData[i]]}</DaemonType>}
<Only when={types?.isValid}>
<DaemonType>{eng[types.rawData[i]]}</DaemonType>
</Only>
<DaemonSequence>
{d.map((s, j) => (
<span key={j}>{s}</span>
Expand Down
50 changes: 15 additions & 35 deletions src/electron/renderer/components/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { MdKeyboardBackspace } from '@react-icons/all-files/md/MdKeyboardBackspace';
import { useContext } from 'react';
import { Link, NavLink as RouterNavLink, useMatch } from 'react-router-dom';
import { Link, NavLink as RouterNavLink } from 'react-router-dom';
import styled from 'styled-components';
import { getFirstHistoryEntryPath } from '../common';
import { StateContext } from '../state';
import { RouterExtContext } from '../router-ext';
import { Only } from './Only';

const Nav = styled.nav`
display: flex;
Expand Down Expand Up @@ -36,7 +36,7 @@ export const NavLink = styled(RouterNavLink)`
}
`;

const GoBackLink = styled(Link)`
const NavigateBackLink = styled(Link)`
color: var(--accent);
position: absolute;
top: 50%;
Expand All @@ -47,42 +47,22 @@ const GoBackLink = styled(Link)`
`;

export const Navigation = () => {
const match = useMatch('/calibrate/:entryId/*');
const isAnalyzePage = useMatch('/analyze/*');
const { history } = useContext(StateContext);
const historyPath = getFirstHistoryEntryPath(history);
const { items, from } = useContext(RouterExtContext);

return (
<Nav>
{match && (
<GoBackLink to={`/history/${match.params.entryId}`}>
<Only when={!!from}>
<NavigateBackLink to={from}>
<MdKeyboardBackspace size="2rem" />
</GoBackLink>
)}
{isAnalyzePage ? (
<List>
<ListItem>
<NavLink to="/analyze/select">Select sequence</NavLink>
</NavigateBackLink>
</Only>
<List>
{items.map((item, index) => (
<ListItem key={index}>
<NavLink {...item}>{item.label}</NavLink>
</ListItem>
<ListItem>
<NavLink to="/analyze/details">Details</NavLink>
</ListItem>
</List>
) : (
<List>
<ListItem>
<NavLink to="/" end>
Dashboard
</NavLink>
</ListItem>
<ListItem>
<NavLink to={historyPath}>History</NavLink>
</ListItem>
<ListItem>
<NavLink to="/settings">Settings</NavLink>
</ListItem>
</List>
)}
))}
</List>
</Nav>
);
};
13 changes: 13 additions & 0 deletions src/electron/renderer/pages/Analyze.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,21 @@ import { useEffect } from 'react';
import { Outlet } from 'react-router-dom';
import { dispatchAsyncRequest } from '../common';
import { Col, Row } from '../components';
import { NavigationItem, useNavigation } from '../router-ext';

const items: NavigationItem[] = [
{
label: 'Select sequence',
to: '/analyze/select',
},
{
label: 'Details',
to: '/analyze/details',
},
];

export const Analyze = () => {
useNavigation({ items, from: '../' });
useEffect(() => {
return () => {
dispatchAsyncRequest({ type: 'ANALYZE_DISCARD' });
Expand Down
14 changes: 7 additions & 7 deletions src/electron/renderer/pages/Calibrate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
transformTimestamp,
useHistoryEntryFromParam,
} from '../common';
import { Col, NavLink, Row, Spacer } from '../components';
import { Col, Row } from '../components';
import { useNavigation } from '../router-ext';

const Heading = styled.h1`
font-size: 2rem;
Expand All @@ -34,18 +35,17 @@ export const Calibrate = () => {

if (!entry) return null;

const items = entry.fragments.map(({ id }) => ({
to: `/calibrate/${entry.uuid}/${id}`,
label: fromCamelCase(id),
}));
useNavigation({ items, from: `/history/${entry.uuid}` });
useContainerInit(entry.fileName);
const { time, distance } = transformTimestamp(entry.startedAt);

return (
<Col grow>
<Row style={{ gap: '2rem' }}>
{entry.fragments.map((f) => (
<NavLink key={f.id} to={f.id}>
{fromCamelCase(f.id)}
</NavLink>
))}
<Spacer />
<Heading>
{time} - {distance}
</Heading>
Expand Down
7 changes: 6 additions & 1 deletion src/electron/renderer/pages/History.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BreachProtocolStatus } from '@/electron/common';
import { MdClose } from '@react-icons/all-files/md/MdClose';
import { MdDone } from '@react-icons/all-files/md/MdDone';
import { useContext } from 'react';
import { NavLink, Outlet } from 'react-router-dom';
import { Navigate, NavLink, Outlet, useParams } from 'react-router-dom';
import styled from 'styled-components';
import { transformTimestamp } from '../common';
import { Col } from '../components';
Expand Down Expand Up @@ -89,9 +89,14 @@ const H2 = styled.h2`

export const History = () => {
const { history } = useContext(StateContext);
const { entryId = null } = useParams();

if (!history.length) return <NoHistory />;

if (!entryId) {
return <Navigate to={history[0].uuid} replace />;
}

return (
<HistoryWrapper>
<HistoryList>
Expand Down
14 changes: 4 additions & 10 deletions src/electron/renderer/pages/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ActionTypes, AppSettings, State } from '@/electron/common';
import { ActionTypes, State } from '@/electron/common';
import { useEffect } from 'react';
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
import styled from 'styled-components';
Expand All @@ -11,7 +11,7 @@ import {
ThirdPartyLicensesDialog,
TitleBar,
} from '../components';
import { RouterExtContext } from '../router-ext';
import { RouterExt } from '../router-ext';

const Main = styled.main`
flex-grow: 1;
Expand Down Expand Up @@ -51,17 +51,11 @@ function useHashScroll() {
}

export const Root = () => {
const navigate = useNavigate();

useActionRedirect();
useHashScroll();

function navigateToSetting(id: keyof AppSettings) {
navigate(`/settings#${id}`);
}

return (
<RouterExtContext.Provider value={{ navigateToSetting }}>
<RouterExt>
<TitleBar />
<Navigation />
<Main>
Expand All @@ -71,6 +65,6 @@ export const Root = () => {
<ThirdPartyLicensesDialog />
<AnalyzeDropZone />
<StatusBar />
</RouterExtContext.Provider>
</RouterExt>
);
};
12 changes: 2 additions & 10 deletions src/electron/renderer/pages/SelectSequence.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,6 @@ export const SelectSequence = () => {
return a === b;
}

async function discard() {
navigate('/', { replace: true });
}

async function resolve() {
await dispatchAsyncRequest({
type: 'ANALYZE_RESOLVE',
Expand All @@ -97,13 +93,9 @@ export const SelectSequence = () => {
))}
</SequenceList>
</Col>
<Col>
<Col gap>
<HistoryViewer entry={entry} customResult={activeResult} />
<Row style={{ marginTop: 'auto' }}>
<FlatButton color="primary" onClick={discard} disabled={isWorking}>
Discard
</FlatButton>
<Spacer />
<Row style={{ marginTop: 'auto', justifyContent: 'flex-end' }}>
{fromScreenShot && (
<FlatButton
color="accent"
Expand Down
8 changes: 0 additions & 8 deletions src/electron/renderer/router-ext.ts

This file was deleted.

93 changes: 93 additions & 0 deletions src/electron/renderer/router-ext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { AppSettings } from '@/electron/common';
import {
createContext,
PropsWithChildren,
useCallback,
useContext,
useLayoutEffect,
useState,
} from 'react';
import { NavLinkProps, To, useNavigate } from 'react-router-dom';

export interface NavigationItem extends NavLinkProps {
label: string;
}

export interface Navigation {
/** Current navigation items. */
readonly items?: NavigationItem[];

/** Path for back button. */
readonly from?: To;
}

interface RouterExt extends Navigation {
navigateToSetting: (id: keyof AppSettings) => void;

/** Overrides navigation for current route. */
override(navigation: Navigation): void;

/** Resets navigation to the default. */
reset(): void;
}

export const RouterExtContext = createContext<RouterExt>(null);

export function useNavigation({
items = defaultNavigationItems,
from,
}: Navigation): void {
const { override, reset } = useContext(RouterExtContext);

useLayoutEffect(() => {
override({ items, from });

return () => {
reset();
};
}, []);
}

const defaultNavigationItems: NavigationItem[] = [
{
label: 'Dashboard',
to: '/',
end: true,
},
{
label: 'History',
to: '/history',
},
{
label: 'Settings',
to: '/settings',
},
];

export const RouterExt = ({ children }: PropsWithChildren) => {
const navigate = useNavigate();
const [items, setItems] = useState<NavigationItem[]>(defaultNavigationItems);
const [from, setFrom] = useState<To>(null);

const navigateToSetting = useCallback((id: keyof AppSettings) => {
navigate(`/settings#${id}`);
}, []);

const override = useCallback(({ items, from }: Navigation) => {
setFrom(from);
setItems(items);
}, []);

const reset = useCallback(() => {
setFrom(null);
setItems(defaultNavigationItems);
}, []);

return (
<RouterExtContext.Provider
value={{ navigateToSetting, override, reset, items, from }}
>
{children}
</RouterExtContext.Provider>
);
};

0 comments on commit a5bbb5d

Please sign in to comment.