diff --git a/documentation/docs/api/Components/Scaffold.mdx b/documentation/docs/api/Components/Scaffold.mdx new file mode 100644 index 00000000..9efeb2b0 --- /dev/null +++ b/documentation/docs/api/Components/Scaffold.mdx @@ -0,0 +1,31 @@ +--- +id: 'Scaffold' +title: 'Scaffold' +sidebar_label: 'Scaffold' +sidebar_position: 2.1 +--- + +import Type from '../_type-definitions/ScaffoldProps.md'; + +```ts +import { Scaffold } from '@orfium/toolbox'; +``` + +:::info +Must be a descendant of [`ThemeProvider`](https://designlab.orfium.com/?path=/docs/design-system-themeprovider--setting-up-a-button-example). +::: + +## Description + +A component that provides the basic HTML structure for all Orfium applications. + +## Props + +Ƭ [`ScaffoldProps`](../types/ScaffoldProps) + + + +:::warning +While you can pass any valid `ReactElement` to the `navigationSlot` and `headerSlot` props, it is really only intended to be +used with [`Navigation`](./Navigation) and [`TopBar`](./TopBar) respectively. +::: \ No newline at end of file diff --git a/documentation/docs/api/Types/ScaffoldProps.mdx b/documentation/docs/api/Types/ScaffoldProps.mdx new file mode 100644 index 00000000..a9770284 --- /dev/null +++ b/documentation/docs/api/Types/ScaffoldProps.mdx @@ -0,0 +1,17 @@ +--- +id: 'ScaffoldProps' +title: 'ScaffoldProps' +sidebar_label: 'ScaffoldProps' +sidebar_position: 1 +--- +import Type from '../_type-definitions/ScaffoldProps.md'; + + +```ts +import { type ScaffoldProps } from '@orfium/toolbox'; +``` + +### Definition + + + diff --git a/documentation/docs/api/_type-definitions/ScaffoldProps.md b/documentation/docs/api/_type-definitions/ScaffoldProps.md new file mode 100644 index 00000000..561bee5e --- /dev/null +++ b/documentation/docs/api/_type-definitions/ScaffoldProps.md @@ -0,0 +1,5 @@ +| Name | Type | Info | +|:-----------------| :------------- | ----------------------------------------------------------------------------------------- | +| `navigationSlot` | `ReactElement` | This **must** be an instance of [`Navigation`](/docs/api/Components/Navigation) component | +| `headerSlot` | `ReactElement` | This **must** be an instance of [`TopBar`](/docs/api/Components/TopBar) component | +| `children` | `ReactNode` | | diff --git a/documentation/docs/tutorials/01-Installation and Usage/UI/navigation-component.md b/documentation/docs/tutorials/01-Installation and Usage/UI/navigation-component.md index a43fbdb1..9d4c290d 100644 --- a/documentation/docs/tutorials/01-Installation and Usage/UI/navigation-component.md +++ b/documentation/docs/tutorials/01-Installation and Usage/UI/navigation-component.md @@ -25,13 +25,13 @@ In order to make usage easier for the user, the `Navigation` component: In order to use the `Navigation` component, you only have to import it from `@orfium/toolbox` and add it to the file where you build your product's overall layout. Keep in mind that `@orfium/ictinus` must be installed in your app. Follow these [steps](https://ictinus.herokuapp.com/?path=/story/guide-getting-started--page) before you proceed. -```jsx -... +```tsx +//... // highlight-next-line import { Navigation } from '@orfium/toolbox'; -... +//... -const Page: React.FC = () => { +function Page() { return ( <...> diff --git a/documentation/docs/tutorials/01-Installation and Usage/UI/scaffold-component.md b/documentation/docs/tutorials/01-Installation and Usage/UI/scaffold-component.md new file mode 100644 index 00000000..adadc2b0 --- /dev/null +++ b/documentation/docs/tutorials/01-Installation and Usage/UI/scaffold-component.md @@ -0,0 +1,58 @@ +--- +id: 'Scaffold Component' +sidebar_label: 'Scaffold Component' +sidebar_position: 3 +--- + +# Scaffold Component + +## Overview + +In general, the basic HTML structure of almost all Orfium client apps is the following: + +- The [`Navigation`](../../../api/Components/Navigation.mdx) element on the left +- The [`TopBar`](../../../api/Components/TopBar.mdx) element at the top, on the right of the [`Navigation`](../../../api/Components/Navigation.mdx) element +- The main content below the [`TopBar`](../../../api/Components/TopBar.mdx), on the right of the [`Navigation`](../../../api/Components/Navigation.mdx) element + +![Orfium app structure example](/img/example_structure.png) + +The [`Scaffold`](../../../api/Components/Scaffold.mdx) component provides an out-of-the-box solution for setting up your +app with the aforementioned HTML structure. + +:::info +Using [`Scaffold`](../../../api/Components/Scaffold.mdx) is not required in order to use [`Navigation`](../../../api/Components/Navigation.mdx) and [`TopBar`](../../../api/Components/TopBar.mdx). +::: + +## Usage + +In order to use the [`Scaffold`](../../../api/Components/Scaffold.mdx) component, you only have to import it from `@orfium/toolbox` and add it to the file where you build your product's overall layout. +Keep in mind that `@orfium/ictinus` must be installed in your app. Follow these [steps](https://ictinus.herokuapp.com/?path=/story/guide-getting-started--page) before you proceed. + +```tsx +//... +// highlight-next-line +import { Navigation, Scaffold, TopBar } from '@orfium/toolbox'; +//... + +function Layout() { + // .... + + return ( + + } + headerSlot={} + > + {children} + + ); +} +``` diff --git a/documentation/docs/tutorials/01-Installation and Usage/UI/top-bar-component.md b/documentation/docs/tutorials/01-Installation and Usage/UI/top-bar-component.md index 73023ca5..07422b55 100644 --- a/documentation/docs/tutorials/01-Installation and Usage/UI/top-bar-component.md +++ b/documentation/docs/tutorials/01-Installation and Usage/UI/top-bar-component.md @@ -19,13 +19,13 @@ breadcrumbs, or whatever is necessary based on product requirements. In order to use the `TopBar` component you only have to import it from `@orfium/toolbox` and add it to the file where you build your product's overall layout. Keep in mind that `@orfium/ictinus` must be installed in your app. Follow these [steps](https://ictinus.herokuapp.com/?path=/story/guide-getting-started--page) before you proceed. -```jsx -... +```tsx +// ... // highlight-next-line import { TopBar } from '@orfium/toolbox'; -... +// ... -const Page: React.FC = () => { +function Page() { return ( <...> diff --git a/documentation/static/img/example_structure.png b/documentation/static/img/example_structure.png new file mode 100644 index 00000000..6797c689 Binary files /dev/null and b/documentation/static/img/example_structure.png differ diff --git a/src/ui/Navigation/Navigation.styles.tsx b/src/ui/Navigation/Navigation.styles.tsx index a070d940..50760130 100644 --- a/src/ui/Navigation/Navigation.styles.tsx +++ b/src/ui/Navigation/Navigation.styles.tsx @@ -1,13 +1,6 @@ import styled from '@emotion/styled'; export const Wrapper = styled.div` - height: 100%; + height: 100vh; display: flex; `; - -export const LocalNav = styled.div` - position: relative; - height: 100%; - display: flex; - flex-direction: column; -`; diff --git a/src/ui/Navigation/common.styles.ts b/src/ui/Navigation/common.styles.ts index 4e3ab4dc..3d6a34ab 100644 --- a/src/ui/Navigation/common.styles.ts +++ b/src/ui/Navigation/common.styles.ts @@ -5,6 +5,10 @@ import { flexCenter, transition } from '@orfium/ictinus/dist/theme/functions'; import { getFocus } from '@orfium/ictinus/dist/theme/states'; import { rem } from 'polished'; +export function getGlobalNavWidth(theme: Theme) { + return `calc(7 * ${theme.spacing.sm})`; // 56px +} + export const menuItemStyle = (theme: Theme) => css` height: ${rem(44)}; color: ${theme.utils.getColor('darkGrey', 850)}; diff --git a/src/ui/Navigation/components/Drawer/Drawer.styles.ts b/src/ui/Navigation/components/Drawer/Drawer.styles.ts index 5903dddb..b42d1ea5 100644 --- a/src/ui/Navigation/components/Drawer/Drawer.styles.ts +++ b/src/ui/Navigation/components/Drawer/Drawer.styles.ts @@ -1,15 +1,17 @@ import styled from '@emotion/styled'; import { transition } from '@orfium/ictinus/dist/theme/functions'; import { rem } from 'polished'; -import { menuItemStyle } from '../../common.styles'; +import { getGlobalNavWidth, menuItemStyle } from '../../common.styles'; export const DrawerContainer = styled.div<{ expanded: boolean; isDesktop: boolean; }>` - ${transition(0.2)}; + ${transition(0.2, 'width')}; width: ${({ expanded }) => (expanded ? rem('308px') : 0)}; - background-color: white; + background-color: ${({ theme }) => theme.palette.white}; + position: ${({ isDesktop }) => (isDesktop ? 'relative' : 'absolute')}; + left: ${({ theme, isDesktop }) => (isDesktop ? 0 : getGlobalNavWidth(theme))}; flex-shrink: 0; height: 100%; min-height: 100%; diff --git a/src/ui/Navigation/components/GlobalNav/GlobalNav.styles.ts b/src/ui/Navigation/components/GlobalNav/GlobalNav.styles.ts index e963d991..6ff91d07 100644 --- a/src/ui/Navigation/components/GlobalNav/GlobalNav.styles.ts +++ b/src/ui/Navigation/components/GlobalNav/GlobalNav.styles.ts @@ -4,9 +4,10 @@ import { Theme } from '@orfium/ictinus'; import { rem } from 'polished'; import { LinkProps, NavLink } from 'react-router-dom'; import { DEFAULT_NAVBAR_HEIGHT } from '../../../consts'; +import { getGlobalNavWidth } from '../../common.styles'; export const Wrapper = styled.div` - width: calc(7 * ${({ theme }) => `${theme.spacing.sm}`}); // 56px + width: ${({ theme }) => getGlobalNavWidth(theme)}; display: flex; flex-basis: calc(7 * ${({ theme }) => `${theme.spacing.sm}`}); // 56px flex-direction: column; diff --git a/src/ui/Scaffold/Scaffold.styles.ts b/src/ui/Scaffold/Scaffold.styles.ts new file mode 100644 index 00000000..fd786a43 --- /dev/null +++ b/src/ui/Scaffold/Scaffold.styles.ts @@ -0,0 +1,33 @@ +import styled from '@emotion/styled'; + +export const GridContainer = styled.div` + display: grid; + grid-template-columns: auto 1fr; + grid-template-rows: 0fr; + grid-template-areas: + 'sidebar header' + 'sidebar main' + 'sidebar main'; + height: 100vh; +`; + +export const Header = styled.header` + grid-area: header; + position: sticky; + top: 0; + padding: 0 ${({ theme }) => theme.spacing.md}; +`; + +export const Contents = styled.main` + grid-area: main; + position: relative; + padding: ${({ theme }) => theme.spacing.md} ${({ theme }) => theme.spacing.md} + ${({ theme }) => theme.spacing.lg}; +`; + +export const SideNav = styled.aside` + grid-area: sidebar; + transition: all 0.2s ease-in-out; + position: relative; + z-index: 101; +`; diff --git a/src/ui/Scaffold/Scaffold.tsx b/src/ui/Scaffold/Scaffold.tsx new file mode 100644 index 00000000..54178ce4 --- /dev/null +++ b/src/ui/Scaffold/Scaffold.tsx @@ -0,0 +1,20 @@ +import { type ReactElement, type ReactNode } from 'react'; +import { Contents, GridContainer, Header, SideNav } from './Scaffold.styles'; + +export type ScaffoldProps = { + navigationSlot: ReactElement; + headerSlot: ReactElement; + children: ReactNode; +}; + +export function Scaffold(props: ScaffoldProps) { + const { navigationSlot, headerSlot, children } = props; + + return ( + + {navigationSlot} +
{headerSlot}
+ {children} +
+ ); +} diff --git a/src/ui/Scaffold/index.ts b/src/ui/Scaffold/index.ts new file mode 100644 index 00000000..c3b1792b --- /dev/null +++ b/src/ui/Scaffold/index.ts @@ -0,0 +1 @@ +export * from './Scaffold'; diff --git a/src/ui/index.ts b/src/ui/index.ts index 938f269e..5ff8f412 100644 --- a/src/ui/index.ts +++ b/src/ui/index.ts @@ -1,3 +1,4 @@ export { DEFAULT_NAVBAR_HEIGHT } from './consts'; export { Navigation, type MenuItem, type NavigationProps } from './Navigation'; +export { Scaffold, type ScaffoldProps } from './Scaffold'; export { TopBar, type TopBarProps } from './TopBar';