-
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.
OpenAPI V2 - implement sidebar (#2594)
* fix IS_VERCEL_DEPLOY check logic Previously if VERCEL_ENV was equal to anything other than `development`, then we'd have `IS_VERCEL_DEPLOY` as `true`. This isn't accurate in cases where `VERCEL_ENV` is undefined, which is sometimes the case when running the site locally. * add note to preview landing on reload issue * add open api sidebar related utils * add schema transforms * add disentangled sidebar link components * use new sidebar components, update types * remove now-unused utility * enable new features in preview tool * fix bad property access in test * avoid conditionals within smaller components * remove placeholder * rm dupe fn * Fix typo in comment on sidebar-link Co-authored-by: Noel Quiles <[email protected]> * Fix missing wording in preview fallback page --------- Co-authored-by: Noel Quiles <[email protected]>
- Loading branch information
Showing
26 changed files
with
931 additions
and
133 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
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
49 changes: 49 additions & 0 deletions
49
src/views/open-api-docs-view-v2/components/sidebar-link-external/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,49 @@ | ||
/** | ||
* Copyright (c) HashiCorp, Inc. | ||
* SPDX-License-Identifier: MPL-2.0 | ||
*/ | ||
|
||
// Components | ||
import { IconExternalLink16 } from '@hashicorp/flight-icons/svg-react/external-link-16' | ||
import { SidebarLink, SidebarLinkText } from '../sidebar-link' | ||
// Types | ||
import type { PropsWithChildren } from 'react' | ||
// Styles | ||
import s from './style.module.css' | ||
|
||
/** | ||
* Render a SidebarLink with an external link icon. | ||
*/ | ||
export function SidebarLinkExternal({ | ||
href, | ||
children, | ||
}: PropsWithChildren<{ | ||
href: string | ||
}>) { | ||
return ( | ||
<SidebarLink | ||
className={s.root} | ||
href={href} | ||
/** | ||
* We've decided to open external links in new tabs, note there's | ||
* underlying logic in @components/link that handles target="_blank" | ||
*/ | ||
target="_blank" | ||
/** | ||
* Modern browsers treat target="_blank" as implicitly | ||
* having noopener, but we include it explicitly anyways. | ||
* Note that in past implementations of similar components, we added | ||
* rel=noreferrer as well. This doesn't seem necessary in a sidebar | ||
* context, where we control which links appear, and will likely benefit | ||
* from knowing when users are referred from our docs to pages elsewhere | ||
* within our web presence. | ||
*/ | ||
rel="noopener" | ||
> | ||
<SidebarLinkText>{children}</SidebarLinkText> | ||
<span className={s.icon}> | ||
<IconExternalLink16 /> | ||
</span> | ||
</SidebarLink> | ||
) | ||
} |
16 changes: 16 additions & 0 deletions
16
src/views/open-api-docs-view-v2/components/sidebar-link-external/style.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,16 @@ | ||
.root { | ||
display: flex; | ||
gap: 8px; | ||
justify-content: space-between; | ||
align-items: center; | ||
} | ||
|
||
.icon { | ||
/* flex-shrink: 0 prevents the icon from shrinking */ | ||
flex-shrink: 0; | ||
|
||
/* display: block removes built-in margin that'd otherwise appear */ | ||
& > svg { | ||
display: block; | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
src/views/open-api-docs-view-v2/components/sidebar-link-with-product-icon/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,55 @@ | ||
/** | ||
* Copyright (c) HashiCorp, Inc. | ||
* SPDX-License-Identifier: MPL-2.0 | ||
*/ | ||
|
||
// Components | ||
import ProductIcon from 'components/product-icon' | ||
import Text from 'components/text' | ||
import { SidebarLink } from '../sidebar-link' | ||
// Utils | ||
import { isProductSlug } from 'lib/products' | ||
// Types | ||
import type { ProductSlug } from 'types/products' | ||
// Styles | ||
import s from './style.module.css' | ||
|
||
/** | ||
* Render a fancy-looking, product themed linked sidebar item. | ||
* | ||
* Intended to be used as a kind of title-ish element, to establish hierarchy | ||
* within sidebar contents. | ||
* | ||
* This component is largely the same as SidebarNavHighlightItem, but | ||
* requires `href`, and eliminates some related conditional rendering. | ||
* See notes in `../sidebar-link` for more thoughts on a potential move | ||
* away from previously implemented sidebar link components. | ||
*/ | ||
export function SidebarLinkWithProductIcon({ | ||
productSlug, | ||
text, | ||
href, | ||
isActive, | ||
}: { | ||
productSlug: ProductSlug | ||
text: string | ||
href: string | ||
isActive: boolean | ||
}) { | ||
const icon = isProductSlug(productSlug) ? ( | ||
<ProductIcon className={s.icon} productSlug={productSlug} /> | ||
) : null | ||
|
||
return ( | ||
<SidebarLink | ||
aria-current={isActive ? 'page' : undefined} | ||
className={s.root} | ||
href={href} | ||
> | ||
{icon} | ||
<Text asElement="span" size={200} weight="medium"> | ||
{text} | ||
</Text> | ||
</SidebarLink> | ||
) | ||
} |
88 changes: 88 additions & 0 deletions
88
src/views/open-api-docs-view-v2/components/sidebar-link-with-product-icon/style.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,88 @@ | ||
.root { | ||
/* Generic default theme, eg. for HCP and Sentinel */ | ||
--gradient-start: var(--token-color-palette-neutral-100); | ||
--gradient-stop: var(--token-color-palette-neutral-50); | ||
--inset-border-color: var(--token-color-palette-neutral-200); | ||
|
||
/* Set up themed property helpers */ | ||
--inset-border-shadow: inset 0 0 0 1px var(--inset-border-color); | ||
--gradient-background: linear-gradient( | ||
315deg, | ||
var(--gradient-start) 0%, | ||
var(--gradient-stop) 100% | ||
); | ||
|
||
/* Layout icon and text */ | ||
display: flex; | ||
align-items: center; | ||
gap: 8px; | ||
|
||
/* Builds on SidebarLink hover style, adds gradient background */ | ||
&:hover { | ||
background: var(--gradient-background); | ||
} | ||
|
||
/* Builds on SidebarLink current page style, adds gradient background, | ||
and box-shadow border when not focused. */ | ||
&[aria-current='page'] { | ||
background: var(--gradient-background); | ||
|
||
&:not(:focus-visible) { | ||
box-shadow: var(--inset-border-shadow); | ||
} | ||
} | ||
} | ||
|
||
.icon { | ||
flex-shrink: 0; | ||
} | ||
|
||
/* Theming by product slug */ | ||
|
||
.theme-terraform { | ||
--gradient-start: var(--token-color-terraform-gradient-faint-stop); | ||
--gradient-stop: var(--token-color-terraform-gradient-faint-start); | ||
--inset-border-color: var(--token-color-terraform-border); | ||
} | ||
|
||
.theme-packer { | ||
--gradient-start: var(--token-color-packer-gradient-faint-stop); | ||
--gradient-stop: var(--token-color-packer-gradient-faint-start); | ||
--inset-border-color: var(--token-color-packer-border); | ||
} | ||
|
||
.theme-consul { | ||
--gradient-start: var(--token-color-consul-gradient-faint-stop); | ||
--gradient-stop: var(--token-color-consul-gradient-faint-start); | ||
--inset-border-color: var(--token-color-consul-border); | ||
} | ||
|
||
.theme-vault { | ||
--gradient-start: var(--token-color-vault-gradient-faint-stop); | ||
--gradient-stop: var(--token-color-vault-gradient-faint-start); | ||
--inset-border-color: var(--token-color-vault-border); | ||
} | ||
|
||
.theme-boundary { | ||
--gradient-start: var(--token-color-boundary-gradient-faint-stop); | ||
--gradient-stop: var(--token-color-boundary-gradient-faint-start); | ||
--inset-border-color: var(--token-color-boundary-border); | ||
} | ||
|
||
.theme-nomad { | ||
--gradient-start: var(--token-color-nomad-gradient-faint-stop); | ||
--gradient-stop: var(--token-color-nomad-gradient-faint-start); | ||
--inset-border-color: var(--token-color-nomad-border); | ||
} | ||
|
||
.theme-waypoint { | ||
--gradient-start: var(--token-color-waypoint-gradient-faint-stop); | ||
--gradient-stop: var(--token-color-waypoint-gradient-faint-start); | ||
--inset-border-color: var(--token-color-waypoint-border); | ||
} | ||
|
||
.theme-vagrant { | ||
--gradient-start: var(--token-color-vagrant-gradient-faint-stop); | ||
--gradient-stop: var(--token-color-vagrant-gradient-faint-start); | ||
--inset-border-color: var(--token-color-vagrant-border); | ||
} |
69 changes: 69 additions & 0 deletions
69
src/views/open-api-docs-view-v2/components/sidebar-link/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,69 @@ | ||
/** | ||
* Copyright (c) HashiCorp, Inc. | ||
* SPDX-License-Identifier: MPL-2.0 | ||
*/ | ||
|
||
// Components | ||
import Link from '@components/link' | ||
import Text from '@components/text' | ||
// Types | ||
import type { PropsWithChildren } from 'react' | ||
import type { LinkProps } from '@components/link' | ||
// Styles | ||
import s from './style.module.css' | ||
import classNames from 'classnames' | ||
|
||
/** | ||
* Render a link element styled for use in our sidebar. | ||
* | ||
* Note: this component is based on the existing SidebarNavLinkItem. This | ||
* component aims to render similar link elements through a more composable | ||
* interface. We could in theory start to replace SidebarNavLinkItem with | ||
* this component. For now, focus is on delivering API docs, so intent here | ||
* is more narrow, hopefully this component will make the new API docs easier | ||
* to maintain and iterate on by decoupling from our existing component. If | ||
* we're happy with the pattern, then we could adopt it elsewhere. | ||
* | ||
* If further functionality from SidebarNavLinkItem is required in this | ||
* context, it may be worth first trying to build the desired use case by | ||
* composing existing pieces (such as SidebarLink and SidebarLinkText). | ||
* For example, an "external link" component could be something like | ||
* `<SidebarLink><SidebarLinkText /><IconExternalLink16 /></SidebarLink>`. | ||
* | ||
* If composed patterns are repeated _exactly_, and in a way where we'd | ||
* definitely want to update all instances at once, then it may be worth | ||
* creating a re-usable component that captures the composition pattern. | ||
* | ||
* A component that captures a common pattern of composition should _not_ need | ||
* any conditional statements. The props interface should be very simple - the | ||
* point being to _reduce_ the complexity of repeating the identical composed | ||
* pattern. If "edge cases" need to be handled, then the consumer can "eject" | ||
* from the composed pattern by copying and pasting the body of the composed | ||
* component and making changes from there. | ||
*/ | ||
export function SidebarLink({ | ||
children, | ||
/** | ||
* We merge the className prop with our own styles. This allows consumers | ||
* to target the `<a />` element rendered by `<Link />`. | ||
*/ | ||
className, | ||
...linkProps | ||
}: PropsWithChildren<LinkProps>) { | ||
return ( | ||
<Link {...linkProps} className={classNames(s.sidebarLink, className)}> | ||
{children} | ||
</Link> | ||
) | ||
} | ||
|
||
/** | ||
* Render a span element with text styles that fit with SidebarLink. | ||
*/ | ||
export function SidebarLinkText({ children }) { | ||
return ( | ||
<Text asElement="span" size={200} weight="regular"> | ||
{children} | ||
</Text> | ||
) | ||
} |
Oops, something went wrong.