Skip to content

Commit

Permalink
fix: Replace "Back to main menu" navigation on mobile Navbar to provi…
Browse files Browse the repository at this point in the history
…de clearer context (denoland#137)

Co-authored-by: Kevin Whinnery <[email protected]>
  • Loading branch information
hashrock and kwhinnery authored Sep 22, 2023
1 parent e5a8cbf commit 7972e46
Show file tree
Hide file tree
Showing 11 changed files with 325 additions and 38 deletions.
2 changes: 1 addition & 1 deletion docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ const config = {
alt: "Deno",
src: "img/logo.svg",
srcDark: "img/logo-dark.svg",
href: "/runtime/manual",
href: "/",
},
items: [
{
Expand Down
17 changes: 17 additions & 0 deletions sidebars/products.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const products = [
{
name: "Deno Runtime",
shortName: "Runtime",
slug: "runtime",
},
{
name: "Deno Deploy",
shortName: "Deploy",
slug: "deploy",
},
{
name: "Deno KV",
shortName: "KV",
slug: "kv",
},
];
1 change: 0 additions & 1 deletion src-deno/redirects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export default function configureRedirects(app: Hono) {
}

// Landing page redirects
r("/", "/runtime/manual");
r("/manual", "/runtime/manual");
r("/runtime/manual/introduction", "/runtime/manual");
r("/runtime", "/runtime/manual");
Expand Down
64 changes: 57 additions & 7 deletions src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,12 @@ h3 {
width: 100%;
}

#__docusaurus, .main-wrapper {
.navbar__product_link {
color: var(--ifm-navbar-link-color);
}

#__docusaurus,
.main-wrapper {
overscroll-behavior-y: none;
}

Expand Down Expand Up @@ -111,7 +116,8 @@ h3 {
position: relative;
}

.section-header, .product-header {
.section-header,
.product-header {
color: var(--ifm-navbar-link-color);
font-size: 0.75rem;
text-transform: uppercase;
Expand Down Expand Up @@ -168,8 +174,52 @@ h3 {
font-size: 1.2rem;
}

/* Mobile Nav Customize */
.navbar__brand {
margin-right: 1.5rem;
margin-right: 0.5rem;
}
.product-header {
display: none;
}
.navbar__product {
display: flex;
gap: 0.5rem;
align-items: center;
}
.navbar__product__split {
color: var(--ifm-color-emphasis-500);
}

@media (min-width: 997px) {
.product-header {
display: block;
}
.navbar__brand {
margin-right: 1.5rem;
}
.navbar__product {
display: none;
}
}

.secondary-menu__product {
display: flex;
padding: 0.5rem 1rem 0.5rem 0rem;
justify-content: space-between;
align-items: center;
}
.secondary-menu__product__name {
padding: 0.25rem 0.75rem;
font-size: 1.25rem;
line-height: 1.75rem;
}
.secondary-menu__product__button {
border: none;
padding: 0.5rem 0.75rem;
border-radius: 0.25rem;
font-weight: 600;
background-color: var(--ifm-color-emphasis-200);
color: var(--ifm-color-emphasis-800);
}

.footer {
Expand All @@ -187,9 +237,9 @@ h3 {
margin-left: 0;
}

.icon-menu-user-guide>a,
.icon-menu-tutorials>a,
.icon-menu-api>a {
.icon-menu-user-guide > a,
.icon-menu-tutorials > a,
.icon-menu-api > a {
font-size: 0.9rem;
}

Expand Down Expand Up @@ -246,4 +296,4 @@ h3 {
max-width: 100%;
word-break: break-all;
word-wrap: break-word;
}
}
69 changes: 40 additions & 29 deletions src/pages/index.jsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,55 @@
import React from "react";
import Layout from "@theme/Layout";

function Card({ title, href, children }) {
return (
<div className="border-1 border-solid rounded-xl p-4 w-full md:w-auto flex flex-col">
<h3 className="border-b border-t-0 border-l-0 border-r-0 border-solid pb-2">
{title}
</h3>
<p className="grow">{children}</p>
<a
className="font-bold inline-block hover:opacity-80"
href={href}
>
{title} Docs &gt;
</a>
</div>
);
}

export default function Home() {
const ctaLinks =
`border-2 border-solid rounded-xl px-4 py-2 hover:no-underline font-bold inline-block hover:opacity-80`;
return (
<Layout
title={`Deno: the easiest, most secure JavaScript runtime`}
title={"Deno: the easiest, most secure JavaScript runtime"}
description="Reference documentation for the Deno runtime and Deno Deploy"
>
<div className="flex flex-col-reverse px-8 pt-6 md:mt-12 md:items-center md:justify-center md:flex-row gap-0 md:gap-16">
<div className="flex flex-col px-8 pt-6 md:mt-12 md:items-center md:justify-center md:flex-row gap-0 md:gap-16 max-w-[1200px] mx-auto">
<div className="pb-16 align-middle md:pb-0">
<div className="mb-8 md:mb-12">
<h1 className="text-4xl md:text-5xl">Deno Documentation</h1>
<p className="my-2">
Reference docs for the Deno JavaScript runtime and Deno Deploy.
</p>
<div className="mb-8 text-center">
<img
className="w-64 h-64 mb-[-40px] md:mt-[-40px]"
alt="Deno logo"
src="/deno-looking-up.svg"
/>
<h1 className="text-4xl md:text-5xl">Deno Docs</h1>
</div>
<div className="flex flex-col items-start gap-4 md:flex-row">
<a
className={ctaLinks}
href="/runtime/manual"
>
Build with Deno
</a>
<a
className={ctaLinks}
href="/deploy/manual"
>
Deploy to the edge
</a>
<div className="flex flex-col items-start gap-8 md:grid md:grid-cols-3 md:grid-flow-col md:items-stretch">
<Card title="Deno Runtime" href="/runtime/manual">
Language runtime for TypeScript and JavaScript with a browser-like
programming environment. Features built-in dev tools, powerful
platform APIs, and native support for TypeScript and JSX.
</Card>
<Card title="Deno Deploy" href="/deploy/manual">
Serverless JavaScript platform. Supports Deno platform APIs and
Node.js / npm modules. Runs on a fast global edge network.
</Card>
<Card title="Deno KV" href="/kv/manual">
Key/value database built in to the Deno runtime. Simple API, works
with zero configuration on Deno Deploy.
</Card>
</div>
</div>
<div className="text-center align-middle">
<img
className="w-64 h-64 md:h-96 md:w-96 lg:h-[520px] lg:w-[520px]"
alt="Deno logo"
src="/deno-looking-up.svg"
/>
</div>
</div>
</Layout>
);
Expand Down
101 changes: 101 additions & 0 deletions src/theme/Navbar/Content/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from 'react';
import {useThemeConfig, ErrorCauseBoundary} from '@docusaurus/theme-common';
import {
splitNavbarItems,
useNavbarMobileSidebar,
} from '@docusaurus/theme-common/internal';
import NavbarItem from '@theme/NavbarItem';
import NavbarColorModeToggle from '@theme/Navbar/ColorModeToggle';
import SearchBar from '@theme/SearchBar';
import NavbarMobileSidebarToggle from '@theme/Navbar/MobileSidebar/Toggle';
import NavbarLogo from '@theme/Navbar/Logo';
import NavbarSearch from '@theme/Navbar/Search';
import styles from './styles.module.css';
import { useLocation } from "@docusaurus/router";
import { products } from "../../../../sidebars/products";

function useNavbarItems() {
// TODO temporary casting until ThemeConfig type is improved
return useThemeConfig().navbar.items;
}
function NavbarItems({items}) {
return (
<>
{items.map((item, i) => (
<ErrorCauseBoundary
key={i}
onError={(error) =>
new Error(
`A theme navbar item failed to render.
Please double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:
${JSON.stringify(item, null, 2)}`,
{cause: error},
)
}>
<NavbarItem {...item} />
</ErrorCauseBoundary>
))}
</>
);
}
function NavbarContentLayout({left, right}) {
return (
<div className="navbar__inner">
<div className="navbar__items">{left}</div>
<div className="navbar__items navbar__items--right">{right}</div>
</div>
);
}

function NavbarProduct(){
const location = useLocation();
const currentProduct = products.find((product) =>
location.pathname.includes(product.slug)
);
return (
<div className="navbar__product">
{currentProduct && (
<>
<div className="navbar__product__split">/</div>
<a className="navbar__product_link" href={`/${currentProduct.slug}/manual`}>
{currentProduct.shortName}
</a>
</>
)}
</div>
)
}

export default function NavbarContent() {
const mobileSidebar = useNavbarMobileSidebar();
const items = useNavbarItems();
const [leftItems, rightItems] = splitNavbarItems(items);
const searchBarItem = items.find((item) => item.type === 'search');

return (
<NavbarContentLayout
left={
// TODO stop hardcoding items?
<>
{!mobileSidebar.disabled && <NavbarMobileSidebarToggle />}
<NavbarLogo />
<NavbarProduct />
<NavbarItems items={leftItems} />
</>
}
right={
// TODO stop hardcoding items?
// Ask the user to add the respective navbar items => more flexible
<>
<NavbarItems items={rightItems} />
<NavbarColorModeToggle className={styles.colorModeToggle} />
{!searchBarItem && (
<NavbarSearch>
<SearchBar />
</NavbarSearch>
)}
</>
}
/>
);
}
8 changes: 8 additions & 0 deletions src/theme/Navbar/Content/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
Hide color mode toggle in small viewports
*/
@media (max-width: 996px) {
.colorModeToggle {
display: none;
}
}
59 changes: 59 additions & 0 deletions src/theme/Navbar/MobileSidebar/SecondaryMenu/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import {useThemeConfig} from '@docusaurus/theme-common';
import {useNavbarSecondaryMenu} from '@docusaurus/theme-common/internal';
import { useLocation } from "@docusaurus/router";
import { products } from "../../../../../sidebars/products";

function SecondaryMenuBackButton(props) {
return (
<button
type="button"
{...props}
className="secondary-menu__product__button"
>
All docs
</button>
);
}

function ProductNameWithSwitcher() {
const secondaryMenu = useNavbarSecondaryMenu();
const location = useLocation();

const currentProduct = products.find((product) =>
location.pathname.includes(product.slug)
);

return (
<div>
{currentProduct && (
<div className="secondary-menu__product">
<div className="secondary-menu__product__name">
{currentProduct.name}
</div>
<SecondaryMenuBackButton onClick={() => secondaryMenu.hide()} />
</div>
)}
</div>
);
}

// The secondary menu slides from the right and shows contextual information
// such as the docs sidebar
export default function NavbarMobileSidebarSecondaryMenu() {
const isPrimaryMenuEmpty = useThemeConfig().navbar.items.length === 0;
const secondaryMenu = useNavbarSecondaryMenu();

return (
<>
<ProductNameWithSwitcher />
{/* edge-case: prevent returning to the primaryMenu when it's empty */}
{
/* {!isPrimaryMenuEmpty && (
<SecondaryMenuBackButton onClick={() => secondaryMenu.hide()} />
)} */
}
{secondaryMenu.content}
</>
);
}
Loading

0 comments on commit 7972e46

Please sign in to comment.