-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: stub OpenAPI docs mobile menu (#2090)
* feat: add mobile-menu-levels component * feat: add open-api-docs-mobile-menu-levels * feat: use stubbed OpenAPI docs menu levels * refactor: lift out fixed-productData import * docs: update comment * chore: enable flags for review * docs: add comment on level-components * chore: take a baby step towards decoupling * chore: revert flags for dev & review
- Loading branch information
Showing
11 changed files
with
292 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { useState } from 'react' | ||
// Icons | ||
import { IconChevronLeft16 } from '@hashicorp/flight-icons/svg-react/chevron-left-16' | ||
import { IconChevronRight16 } from '@hashicorp/flight-icons/svg-react/chevron-right-16' | ||
// Components | ||
import Button from 'components/button' | ||
import MobileMenuContainer from 'components/mobile-menu-container' | ||
import { MobileAuthenticationControls } from 'components/mobile-menu-container' | ||
// Types | ||
import type { MobileMenuLevelData } from './types' | ||
// Styles | ||
import s from './mobile-menu-levels.module.css' | ||
|
||
/** | ||
* This component allows the consumer to render a multi-pane mobile | ||
* menu without being required to use `SidebarSidecarLayout` | ||
* or the associated `sidebar-nav-data` React context. | ||
* | ||
* Intent is to solidify this into an alternative pattern | ||
* for composing mobile menu contents. | ||
*/ | ||
function MobileMenuLevels({ levels }: { levels: MobileMenuLevelData[] }) { | ||
const [currentLevel, setCurrentLevel] = useState(levels.length - 1) | ||
|
||
return ( | ||
<MobileMenuContainer className={s.mobileMenuContainer}> | ||
<MobileAuthenticationControls /> | ||
<div className={s.levelButtons}> | ||
{currentLevel > 0 ? ( | ||
<Button | ||
className={s.levelUpButton} | ||
color="tertiary" | ||
icon={<IconChevronLeft16 />} | ||
iconPosition="leading" | ||
onClick={() => setCurrentLevel(currentLevel - 1)} | ||
text={levels[currentLevel - 1].levelButtonText} | ||
/> | ||
) : null} | ||
{currentLevel < levels.length - 1 ? ( | ||
<Button | ||
className={s.levelDownButton} | ||
color="tertiary" | ||
icon={<IconChevronRight16 />} | ||
iconPosition="trailing" | ||
onClick={() => setCurrentLevel(currentLevel + 1)} | ||
text={levels[currentLevel + 1].levelButtonText} | ||
/> | ||
) : null} | ||
</div> | ||
{levels[currentLevel].content} | ||
</MobileMenuContainer> | ||
) | ||
} | ||
|
||
export default MobileMenuLevels |
125 changes: 125 additions & 0 deletions
125
src/components/mobile-menu-levels/level-components/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// Components | ||
import { | ||
SidebarHorizontalRule, | ||
SidebarNavMenuItem, | ||
} from 'components/sidebar/components' | ||
// Utils | ||
import { generateTopLevelSubNavItems } from 'lib/generate-top-level-sub-nav-items' | ||
import { generateProductLandingSidebarMenuItems } from 'components/sidebar/helpers/generate-product-landing-nav-items' | ||
import { generateResourcesNavItems } from 'components/sidebar/helpers' | ||
// Types | ||
import type { MenuItem } from 'components/sidebar' | ||
import type { ProductData, ProductSlug } from 'types/products' | ||
import type { MobileMenuLevelData } from '../types' | ||
// Styles | ||
import s from './level-components.module.css' | ||
|
||
/** | ||
* TODO: these "level components" are a good candidate for refactoring. | ||
* We should refactor `mobile-menu-levels` `level-components` to decouple | ||
* business logic & presentation. | ||
* | ||
* This approach here to build `MobileMenuLevelData` doesn't fit as nicely | ||
* into our "view-model" approach to component composition. | ||
* | ||
* This was created as an initial mechanism to decouple the mobile menu from | ||
* the sidebar nav data context, and the intertwined `generate` functions were | ||
* retained as a way to ensure consistency with existing mobile menus. | ||
* | ||
* We'll likely want to refactor this further to split out the intertwined: | ||
* - logic for generating the menu item data (eg `generateResourcesNavItems`) | ||
* - presentation of that data using `<SidebarNavMenuItem />` | ||
* | ||
* To do this consistently across the app, it feels like this might be a | ||
* reasonably large scope of refactor. With this in mind, this work | ||
* was left out of the scope of the API docs template revision. | ||
* | ||
* Task: | ||
* https://app.asana.com/0/1202097197789424/1205093670087688/f | ||
*/ | ||
|
||
/** | ||
* Render a list of resource nav items for a given product slug. | ||
*/ | ||
export function ProductResourceNavItems({ slug }: { slug: ProductSlug }) { | ||
/** | ||
* TODO: this is some business logic that's intertwined with presentation. | ||
* As mentioned in the comment at the top of this file, this is an initial | ||
* cut at decoupling the mobile menu from the sidebar nav data context, | ||
* and is likely something we want to further refactor. | ||
*/ | ||
const menuItems = generateResourcesNavItems(slug) | ||
|
||
return ( | ||
<ul className={s.listResetStyles}> | ||
{menuItems.map((item: MenuItem, index: number) => ( | ||
// eslint-disable-next-line react/no-array-index-key | ||
<SidebarNavMenuItem item={item} key={index} /> | ||
))} | ||
</ul> | ||
) | ||
} | ||
|
||
/** | ||
* Return mobile menu level data for the shared `main` menu pane. | ||
*/ | ||
export function mobileMenuLevelMain(): MobileMenuLevelData { | ||
/** | ||
* TODO: this is some business logic that's intertwined with presentation. | ||
* As mentioned in the comment at the top of this file, this is an initial | ||
* cut at decoupling the mobile menu from the sidebar nav data context, | ||
* and is likely something we want to further refactor. | ||
*/ | ||
const menuItems = generateTopLevelSubNavItems() | ||
|
||
return { | ||
levelButtonText: 'Main Menu', | ||
content: ( | ||
<> | ||
<h3 className={s.heading}>Main Menu</h3> | ||
<ul className={s.listResetStyles}> | ||
{menuItems.map((item: MenuItem, index: number) => ( | ||
// eslint-disable-next-line react/no-array-index-key | ||
<SidebarNavMenuItem item={item} key={index} /> | ||
))} | ||
</ul> | ||
</> | ||
), | ||
} | ||
} | ||
|
||
/** | ||
* Return mobile menu level data for a common `product` menu pane. | ||
*/ | ||
export function mobileMenuLevelProduct( | ||
productData: ProductData | ||
): MobileMenuLevelData { | ||
/** | ||
* TODO: this is some business logic that's intertwined with presentation. | ||
* As mentioned in the comment at the top of this file, this is an initial | ||
* cut at decoupling the mobile menu from the sidebar nav data context, | ||
* and is likely something we want to further refactor. | ||
*/ | ||
const menuItems = [ | ||
{ | ||
title: productData.name, | ||
fullPath: `/${productData.slug}`, | ||
theme: productData.slug, | ||
}, | ||
...generateProductLandingSidebarMenuItems(productData), | ||
] | ||
|
||
return { | ||
levelButtonText: `${productData.name} Home`, | ||
content: ( | ||
<ul className={s.listResetStyles}> | ||
{menuItems.map((item: MenuItem, index: number) => ( | ||
// eslint-disable-next-line react/no-array-index-key | ||
<SidebarNavMenuItem item={item} key={index} /> | ||
))} | ||
<SidebarHorizontalRule /> | ||
<ProductResourceNavItems slug={productData.slug} /> | ||
</ul> | ||
), | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/components/mobile-menu-levels/level-components/level-components.module.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
.listResetStyles { | ||
list-style: none; | ||
margin: 0; | ||
padding: 0; | ||
width: 100%; | ||
} | ||
|
||
.heading { | ||
color: var(--token-color-foreground-primary); | ||
font-size: var(--token-typography-display-100-font-size); | ||
font-weight: var(--token-typography-font-weight-semibold); | ||
line-height: var(--token-typography-display-100-line-height); | ||
padding: 0 8px; | ||
margin: 0 0 12px 0; | ||
} |
19 changes: 19 additions & 0 deletions
19
src/components/mobile-menu-levels/mobile-menu-levels.module.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
.mobileMenuContainer { | ||
padding: 24px; | ||
z-index: 4; | ||
} | ||
|
||
.levelButtons { | ||
display: flex; | ||
margin-bottom: 12px; | ||
} | ||
|
||
.levelUpButton { | ||
margin-right: auto; | ||
padding: 7px 9px 7px 3px; | ||
} | ||
|
||
.levelDownButton { | ||
margin-left: auto; | ||
padding: 7px 9px 7px 3px; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { ReactNode } from 'react' | ||
|
||
export interface MobileMenuLevelData { | ||
levelButtonText: string | ||
content: ReactNode | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './open-api-docs-mobile-menu-levels' |
43 changes: 43 additions & 0 deletions
43
src/views/open-api-docs-view/components/open-api-docs-mobile-menu-levels/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Components | ||
import MobileMenuLevels from 'components/mobile-menu-levels' | ||
import { SidebarHorizontalRule } from 'components/sidebar/components' | ||
import { | ||
ProductResourceNavItems, | ||
mobileMenuLevelMain, | ||
mobileMenuLevelProduct, | ||
} from 'components/mobile-menu-levels/level-components' | ||
// Types | ||
import type { ProductData } from 'types/products' | ||
|
||
/** | ||
* Placeholder for OpenApiDocsView mobile menu levels. | ||
*/ | ||
export function OpenApiDocsMobileMenuLevels({ | ||
productData, | ||
}: { | ||
// Product data, used to generate mobile menu levels. | ||
productData: ProductData | ||
}) { | ||
return ( | ||
<MobileMenuLevels | ||
levels={[ | ||
mobileMenuLevelMain(), | ||
mobileMenuLevelProduct(productData), | ||
{ | ||
levelButtonText: 'Previous', | ||
content: ( | ||
<div> | ||
{/* API docs mobile menu contents */} | ||
<div style={{ border: '1px solid magenta' }}> | ||
PLACEHOLDER for OpenApiDocsView mobile menu contents | ||
</div> | ||
{/* Common resources for this product */} | ||
<SidebarHorizontalRule /> | ||
<ProductResourceNavItems slug={productData.slug} /> | ||
</div> | ||
), | ||
}, | ||
]} | ||
/> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
426e697
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
dev-portal – ./
dev-portal-git-main-hashicorp.vercel.app
dev-portal-hashicorp.vercel.app
docs.hashicorp.com
developer.hashicorp.com