diff --git a/src/layouts/sidebar-layout/index.tsx b/src/layouts/sidebar-layout/index.tsx
new file mode 100644
index 0000000000..9244573dbf
--- /dev/null
+++ b/src/layouts/sidebar-layout/index.tsx
@@ -0,0 +1,44 @@
+import { PropsWithChildren, ReactNode } from 'react'
+// Layout
+import BaseLayout from 'layouts/base-layout'
+// Styles
+import s from './sidebar-layout.module.css'
+
+/**
+ * Renders a sidebar area alongside a main content area.
+ *
+ * The sidebar area is layed out as a sticky column on large viewports.
+ * When very tall content is provided, the sidebar area will scroll vertically.
+ *
+ * The sidebar area is completely hidden on mobile viewports.
+ * Consumers should ensure that equivalent navigational elements
+ * are provided through the `mobileMenuSlot` prop.
+ *
+ * Note: this layout could _potentially_ be of use in `SidebarSidecarLayout`.
+ * For context, this layout was created after `SidebarSidecarLayout`, with the
+ * initial intent of making it easier to build a new OpenAPI docs view.
+ * It will likely make sense to consolidate somewhat duplicate layout logic between
+ * this component and `SidebarSidecarLayout`, but this did not feel like it
+ * was within the scope of the OpenAPI docs view work.
+ * Task:
+ * https://app.asana.com/0/1202097197789424/1205088749290838/f
+ */
+function SidebarLayout({
+ children,
+ sidebarSlot,
+ mobileMenuSlot,
+}: PropsWithChildren<{
+ mobileMenuSlot: ReactNode
+ sidebarSlot: ReactNode
+}>) {
+ return (
+
+
+
{sidebarSlot}
+
{children}
+
+
+ )
+}
+
+export default SidebarLayout
diff --git a/src/layouts/sidebar-layout/sidebar-layout.module.css b/src/layouts/sidebar-layout/sidebar-layout.module.css
new file mode 100644
index 0000000000..f146b2d53e
--- /dev/null
+++ b/src/layouts/sidebar-layout/sidebar-layout.module.css
@@ -0,0 +1,35 @@
+.root {
+ display: flex;
+
+ /* Grow to fill the vertical space that BaseLayout creates */
+ flex-grow: 1;
+ gap: 48px;
+
+ @media (min-width: 1440px) {
+ gap: 64px;
+ }
+}
+
+.sidebarArea {
+ /* Note that --navigation-header-height is set by BaseLayout styles */
+ background-color: var(--token-color-surface-primary);
+ box-shadow: var(--token-surface-base-box-shadow);
+ display: none;
+
+ /* Even if content is long, area shoul dbe fully within the viewport.
+ For shorter content, we don't need the height to be tall. */
+ max-height: calc(100vh - var(--navigation-header-height));
+ overflow: auto;
+ padding: 24px 24px 100px 24px;
+ position: sticky;
+ top: var(--navigation-header-height);
+ width: 312px;
+
+ @media (--dev-dot-hide-mobile-menu) {
+ display: block;
+ }
+}
+
+.mainArea {
+ flex: 1 1 0;
+}
diff --git a/src/views/open-api-docs-view/index.tsx b/src/views/open-api-docs-view/index.tsx
index 0eb9417c4a..7e49aa281f 100644
--- a/src/views/open-api-docs-view/index.tsx
+++ b/src/views/open-api-docs-view/index.tsx
@@ -1,3 +1,8 @@
+// Layout
+import SidebarLayout from 'layouts/sidebar-layout'
+// Local
+import MobileMenuLevelsGeneric from 'components/mobile-menu-levels-generic'
+// Types
import type { OpenApiDocsViewProps } from './types'
/**
@@ -5,12 +10,21 @@ import type { OpenApiDocsViewProps } from './types'
*/
function OpenApiDocsView(props: OpenApiDocsViewProps) {
return (
-
-
OpenApiDocsView Placeholder
-
- {JSON.stringify(props, null, 2)}
-
-
+
+ PLACEHOLDER for sidebar contents
+
+ }
+ mobileMenuSlot={}
+ >
+
+
OpenApiDocsView Placeholder
+
+ {JSON.stringify(props, null, 2)}
+
+
+
)
}