Skip to content

Commit

Permalink
feat: template layout with sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
KatoakDR committed Jan 20, 2024
1 parent eb2047a commit 2f83b1a
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 1 deletion.
34 changes: 34 additions & 0 deletions electron/renderer/components/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { EuiPageTemplate } from '@elastic/eui';
import type { ReactNode } from 'react';
import { SidebarContainer } from './sidebar';

export interface LayoutProps {
/**
* Nested components.
*/
children?: ReactNode;
}

export const Layout: React.FC<LayoutProps> = (
props: LayoutProps
): ReactNode => {
const { children } = props;

// In the template, set the `responsive` property to an empty array
// so that the sidebar always shows on the left. Otherwise, if the
// window is resized to be too small, the sidebar will stack on top.
// And that's not the UX we want.

return (
<EuiPageTemplate grow={true} responsive={[]}>
<EuiPageTemplate.Sidebar minWidth={50} paddingSize="xs" responsive={[]}>
<SidebarContainer />
</EuiPageTemplate.Sidebar>
<EuiPageTemplate.Section paddingSize="none" grow={true}>
{children}
</EuiPageTemplate.Section>
</EuiPageTemplate>
);
};

Layout.displayName = 'Layout';
1 change: 1 addition & 0 deletions electron/renderer/components/sidebar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './sidebar-container';
136 changes: 136 additions & 0 deletions electron/renderer/components/sidebar/sidebar-container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import type { EuiButtonIconProps } from '@elastic/eui';
import {
EuiButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiPopover,
EuiToolTip,
} from '@elastic/eui';
import { type ReactNode, useCallback, useState } from 'react';

export interface SidebarContainerProps {
//
}

export interface SidebarButtonIconProps {
label: EuiButtonIconProps['aria-label'];
iconType: EuiButtonIconProps['iconType'];
iconColor?: EuiButtonIconProps['color'];
iconSize?: EuiButtonIconProps['iconSize'];
/**
* The content of the popover when the button is clicked.
*/
children?: ReactNode;
}

const SidebarButtonIcon: React.FC<SidebarButtonIconProps> = (
props: SidebarButtonIconProps
): ReactNode => {
const { label, iconType, iconColor, iconSize, children } = props;

const [showTooltip, setShowTooltip] = useState(true);
const [showPopover, setShowPopover] = useState(false);

const onClosePopover = useCallback(() => {
setShowTooltip(true);
setShowPopover(false);
}, []);

const togglePopoverAndTooltip = useCallback(() => {
if (!children) {
return;
}
setShowTooltip((prev) => !prev);
setShowPopover((prev) => !prev);
}, [children]);

const buttonElmt = (
<EuiPopover
isOpen={showPopover}
closePopover={onClosePopover}
button={
<EuiButtonIcon
aria-label={label}
iconType={iconType}
color={iconColor}
iconSize={iconSize}
css={{
'min-width': 50,
'min-height': 50,
'height': 50,
'width': 50,
}}
onClick={togglePopoverAndTooltip}
/>
}
>
{children}
</EuiPopover>
);

if (showTooltip) {
return (
<EuiToolTip aria-label={label} content={label} position="right">
{buttonElmt}
</EuiToolTip>
);
}

return buttonElmt;
};

SidebarButtonIcon.displayName = 'SidebarButtonIcon';

export const SidebarContainer: React.FC<SidebarContainerProps> = (
props: SidebarContainerProps
): ReactNode => {
return (
<EuiFlexGroup direction="column" css={{ height: '100%' }}>
<EuiFlexItem grow={false}>
<EuiFlexGroup direction="column" gutterSize="none" alignItems="center">
<EuiFlexItem grow={false}>
<SidebarButtonIcon
label="Characters"
iconType="user"
iconColor="primary"
iconSize="l"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<SidebarButtonIcon
label="Accounts"
iconType="key"
iconColor="primary"
iconSize="l"
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={true}>{/* empty space in the middle */}</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup direction="column" gutterSize="none" alignItems="center">
<EuiFlexItem grow={false}>
<SidebarButtonIcon
label="Help"
iconType="questionInCircle"
iconColor="text"
iconSize="xl" // https://github.com/elastic/eui/issues/6322
>
<div>Some help text</div>
</SidebarButtonIcon>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<SidebarButtonIcon
label="Settings"
iconType="gear"
iconColor="text"
iconSize="l"
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
);
};

SidebarContainer.displayName = 'SidebarContainer';
10 changes: 9 additions & 1 deletion electron/renderer/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@
import { EuiErrorBoundary } from '@elastic/eui';
import type { AppProps } from 'next/app';
import Head from 'next/head';
import { Layout } from '../components/layout';
import { NoSSR } from '../components/no-ssr';
import { ChromeProvider } from '../context/chrome';
import { LoggerProvider } from '../context/logger';
import { ThemeProvider } from '../context/theme';

// The layout uses eui styling which requires the browser to be present.
// To bypass SSR then we wrap the layout in a NoSSR component.
const LayoutNoSSR = NoSSR(Layout);

/**
* Next.js uses the App component to initialize pages. You can override it
* and control the page initialization. Here use use it to render the
Expand All @@ -23,7 +29,9 @@ const App: React.FC<AppProps> = ({ Component, pageProps }: AppProps) => (
<ChromeProvider>
<LoggerProvider>
<EuiErrorBoundary>
<Component {...pageProps} />
<LayoutNoSSR>
<Component {...pageProps} />
</LayoutNoSSR>
</EuiErrorBoundary>
</LoggerProvider>
</ChromeProvider>
Expand Down

0 comments on commit 2f83b1a

Please sign in to comment.