Skip to content

Commit

Permalink
feat: toolbar actionbar styling
Browse files Browse the repository at this point in the history
  • Loading branch information
atanasster committed Jun 24, 2020
1 parent 9f35f67 commit b37084a
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 116 deletions.
81 changes: 42 additions & 39 deletions ui/app/src/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/** @jsx jsx */
import { FC, useContext } from 'react';
import { jsx, Box, Text } from 'theme-ui';
import { PageType, PageConfiguration } from '@component-controls/core';
import { FC, useContext, useMemo } from 'react';
import { jsx, Box } from 'theme-ui';
import { PageType } from '@component-controls/core';
import { ActionBar, ActionItems } from '@component-controls/components';

import {
Link,
ColorMode,
SidebarContext,
Header as AppHeader,
Expand All @@ -19,46 +19,49 @@ export const Header: FC = () => {
const { storeProvider } = useContext(BlockContext);
const config = storeProvider.config;
const { pages } = config || {};
const leftActions: ActionItems = useMemo(() => {
const actions: ActionItems = [
{ title: 'Home', href: '/', 'aria-label': 'go to home page', id: 'home' },
];
if (pages) {
return [
...actions,
...Object.keys(pages)
.map(type => {
const pageType = type as PageType;
return { page: pages[pageType], pageType };
})
.filter(({ page, pageType }) => {
return (
page.topMenu &&
Object.keys(storeProvider.getPageList(pageType)).length > 0
);
})
.map(({ page }) => ({
id: page.label?.toLowerCase(),
'aria-label': `go to page ${page.label}`,
href: `/${page.basePath}`,
title: page.label,
})),
];
}
return actions;
}, [pages, storeProvider]);

const rightActions: ActionItems = useMemo(() => {
const actions: ActionItems = [
{ title: <Search />, id: 'search' },
{ title: <ColorMode />, id: 'colormode' },
];
return actions;
}, []);
return (
<AppHeader>
<Box variant="appheader.container">
{collapsed && <SidebarToggle />}
<Box variant="appheader.inner">
<Link href="/">
<Text variant="appheader.linktext">Home</Text>
</Link>
{pages
? Object.keys(pages).map(type => {
const pageType = type as PageType;
const page: PageConfiguration = pages[pageType];
if (
page.topMenu &&
Object.keys(storeProvider.getPageList(pageType)).length > 0
) {
return (
<Link
key={`link_${page.basePath}`}
href={`/${page.basePath}`}
>
<Text variant="appheader.linktext">{page.label}</Text>
</Link>
);
}
return null;
})
: null}
</Box>
<ActionBar themeKey="toolbar" actions={leftActions} />
</Box>
{!responsive && (
<Box variant="appheader.righthandrow">
<Box variant="appheader.righthanditem">
<Search />
</Box>
<Box variant="appheader.righthanditem">
<ColorMode />
</Box>
</Box>
)}
{!responsive && <ActionBar themeKey="toolbar" actions={rightActions} />}
</AppHeader>
);
};
14 changes: 0 additions & 14 deletions ui/components/src/ActionBar/ActionBar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,6 @@ export const overview = () => (
</Container>
);

export const disabled = () => (
<Container>
<ActionBar
actions={[
{
title: 'click action',
onClick: () => console.log('clicked'),
disabled: true,
},
]}
/>
</Container>
);

export const link = () => (
<Container>
<ActionBar
Expand Down
71 changes: 25 additions & 46 deletions ui/components/src/ActionBar/ActionBar.tsx
Original file line number Diff line number Diff line change
@@ -1,88 +1,67 @@
/** @jsx jsx */
import { FC, useMemo } from 'react';
import { transparentize } from 'polished';
import { Theme, Box, Flex, Button, jsx } from 'theme-ui';
import { Box, Button, jsx } from 'theme-ui';
import { getSortedActions, ActionItems } from './utils';
import { useTheme } from '../ThemeContext';
import { Link } from '../Link';

export interface ActionBarProps {
/**
* collection of action items
*/
actions?: ActionItems;
}

const ActionColors = ({
theme,
disabled,
}: {
theme: Theme;
disabled: boolean | undefined;
}) => ({
backgroundColor: theme.colors?.['action'],
color: disabled ? '#ddd' : 'background',
//safari fix:
WebkitTextFillColor: 'initial',
cursor: disabled ? 'not-allowed' : undefined,
px: 2,
py: 1,
lineHeight: 1,
borderRadius: 1,
display: 'inline-block',
boxShadow: `${transparentize(
0.9,
theme.colors?.text as string,
)} 0 1px 3px 1px, ${transparentize(
0.35,
theme.colors?.text as string,
)} 0 0 0 1px`,
border: `1px solid ${theme.colors?.['action'] as string}`,
});
/**
* two possible layouts from the theme
*/
themeKey?: 'actionbar' | 'toolbar';
}

/**
* a strip of actions to be attached to a container
* the action items contain the labels and click event handler
* actions can accept an order prop, and can also be superimposed
*
*/
export const ActionBar: FC<ActionBarProps> = ({ actions = [] }) => {
const theme = useTheme();
export const ActionBar: FC<ActionBarProps> = ({
actions = [],
themeKey = 'actionbar',
}) => {
const items = useMemo(() => {
const sortedItems = getSortedActions(actions);
return sortedItems.map(
({ title, onClick, disabled, 'aria-label': ariaLabel, group }, index) => {
({ title, onClick, 'aria-label': ariaLabel, group, href }, index) => {
const nextGroup =
index < sortedItems.length - 1 ? sortedItems[index + 1].group : group;
return (
<Box
key={`${typeof title === 'string' ? title : 'item'}_${index}`}
variant="actionbar.item"
variant={`${themeKey}.item`}
sx={{
mr: index === 0 ? 1 : 0,
ml: nextGroup !== group || group === undefined ? 2 : 1,
a: ActionColors({ theme, disabled }),
button: ActionColors({ theme, disabled }),
}}
>
{typeof title === 'string' ? (
<Button
onClick={onClick}
disabled={disabled}
aria-label={ariaLabel}
>
{title}
</Button>
href ? (
<Link href={href} aria-label={ariaLabel}>
{title}
</Link>
) : (
<Button onClick={onClick} aria-label={ariaLabel}>
{title}
</Button>
)
) : (
title
)}
</Box>
);
},
);
}, [theme, actions]);
}, [actions, themeKey]);
return (
<Box variant="actionbar.container">
<Flex variant="actionbar.inner">{items}</Flex>
<Box variant={`${themeKey}.container`}>
<Box variant={`${themeKey}.inner`}>{items}</Box>
</Box>
);
};
10 changes: 6 additions & 4 deletions ui/components/src/ActionBar/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ export interface ActionItem {
* title - if a string, will use the Button component, else can prvide custom React component
*/
title: React.ReactNode;

/**
* onClick event when passing a string as the title
* if the title is a string and href is set will use a default <Link /> component
*/
onClick?: (e: MouseEvent<HTMLButtonElement>) => void | boolean;
href?: string;

/**
* displays the Button as disabled
* if the title is a string and href is not set, onClick will be used on a <,>Button /> component
*/
disabled?: boolean;
onClick?: (e: MouseEvent<HTMLButtonElement>) => void | boolean;
/**
* hide an action item
*/
Expand Down
40 changes: 27 additions & 13 deletions ui/components/src/ThemeContext/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,24 @@ const heading = {
fontWeight: 'semibold',
};

const ActionItemStyle: ThemeUIStyleObject = {
color: 'background',
backgroundColor: 'action',
//safari fix:
WebkitTextFillColor: 'initial',
px: 2,
py: 1,
lineHeight: 1,
borderRadius: 1,
display: 'inline-block',
boxShadow: (t: Theme) =>
`${t.colors?.shadow} 0 1px 3px 1px, ${t.colors?.shadow} 0 0 0 1px`,
border: (t: Theme) => `1px solid ${t.colors?.action}`,
};

export type ControlsTheme = {
actionbar: Record<string, ThemeUIStyleObject>;
toolbar: Record<string, ThemeUIStyleObject>;
actioncontainer: ThemeUIStyleObject | Record<string, ThemeUIStyleObject>;
blockcontainer: Record<string, ThemeUIStyleObject>;
blockpagecontainer: Record<string, ThemeUIStyleObject>;
Expand Down Expand Up @@ -264,13 +280,23 @@ export const theme: ControlsTheme = {
},
inner: {
position: 'absolute',
display: 'flex',
width: '100%',
flexDirection: 'row-reverse',
marginLeft: 'auto',
},
item: {
mt: 1,
fontSize: 1,
a: ActionItemStyle,
button: ActionItemStyle,
},
},
toolbar: {
inner: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
},
},
actioncontainer: {
Expand Down Expand Up @@ -707,20 +733,8 @@ export const theme: ControlsTheme = {
':hover': { color: `accent` },
fontWeight: 'bold',
},
},
inner: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
py: 3,
},
linktext: { px: 2 },
righthandrow: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
},
righthanditem: { px: 2 },
},
appfooter: {
container: {
Expand Down Expand Up @@ -805,7 +819,7 @@ export const theme: ControlsTheme = {
display: 'grid',
flex: 1,
minHeight: '100vh',
gridTemplateColumns: '300px 1fr 250px',
gridTemplateColumns: ['1fr', '1fr', '300px 1fr 250px'],
position: 'relative',
},
//@ts-ignore
Expand Down

0 comments on commit b37084a

Please sign in to comment.