Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 71 additions & 109 deletions src/components/Navigation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import { useRef } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import clsx from 'clsx'
import { AnimatePresence, motion, useIsPresent } from 'framer-motion'
import { AnimatePresence, motion } from 'framer-motion'

import { Button } from '@/components/Button'
import { useIsInsideMobileNavigation } from '@/components/MobileNavigation'
import { useSectionStore } from '@/components/SectionProvider'
import { Tag } from '@/components/Tag'
import { remToPx } from '@/lib/remToPx'

function useInitialValue(value, condition = true) {
let initialValue = useRef(value).current
Expand All @@ -28,14 +26,20 @@ function TopLevelNavItem({ href, children }) {
)
}

function NavLink({ href, tag, active, isAnchorLink = false, children }) {
function NavLink({ href, tag, active, level = 0, children }) {
let leftPaddingClass = {
0: 'pl-0',
1: 'pl-4',
2: 'pl-4',
}[level] ?? 'pl-12'

return (
<Link
href={href}
aria-current={active ? 'page' : undefined}
className={clsx(
'flex justify-between gap-2 py-1 pr-3 text-sm transition',
isAnchorLink ? 'pl-7' : 'pl-4',
leftPaddingClass,
active
? 'text-zinc-900 dark:text-white'
: 'text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white'
Expand All @@ -51,57 +55,55 @@ function NavLink({ href, tag, active, isAnchorLink = false, children }) {
)
}

function VisibleSectionHighlight({ group, pathname }) {
let [sections, visibleSections] = useInitialValue(
[
useSectionStore((s) => s.sections),
useSectionStore((s) => s.visibleSections),
],
useIsInsideMobileNavigation()
)

let isPresent = useIsPresent()
let firstVisibleSectionIndex = Math.max(
0,
[{ id: '_top' }, ...sections].findIndex(
(section) => section.id === visibleSections[0]
)
)
let itemHeight = remToPx(2)
let height = isPresent
? Math.max(1, visibleSections.length) * itemHeight
: itemHeight
let top =
group.links.findIndex((link) => link.href === pathname) * itemHeight +
firstVisibleSectionIndex * itemHeight
function isLinkActive(link, pathname) {
if (link.href === pathname) {
return true
}

return (
<motion.div
layout
initial={{ opacity: 0 }}
animate={{ opacity: 1, transition: { delay: 0.2 } }}
exit={{ opacity: 0 }}
className="absolute inset-x-0 top-0 bg-zinc-800/2.5 will-change-transform dark:bg-white/2.5"
style={{ borderRadius: 8, height, top }}
/>
)
return (link.links ?? []).some((childLink) => isLinkActive(childLink, pathname))
}

function ActivePageMarker({ group, pathname }) {
let itemHeight = remToPx(2)
let offset = remToPx(0.25)
let activePageIndex = group.links.findIndex((link) => link.href === pathname)
let top = offset + activePageIndex * itemHeight
function NavigationLinkItem({ link, pathname, level = 0 }) {
let isActive = isLinkActive(link, pathname)

return (
<motion.div
layout
className="absolute left-2 h-6 w-px bg-yellow-500"
initial={{ opacity: 0 }}
animate={{ opacity: 1, transition: { delay: 0.2 } }}
exit={{ opacity: 0 }}
style={{ top }}
/>
<motion.li layout="position" className="relative">
<NavLink href={link.href} active={isActive} level={level}>
{link.title}
</NavLink>
<AnimatePresence mode="popLayout" initial={false}>
{isActive && (link.links?.length ?? 0) > 0 && (
<motion.ul
role="list"
className={clsx(level === 0 && 'relative')}
initial={{ opacity: 0 }}
animate={{
opacity: 1,
transition: { delay: 0.1 },
}}
exit={{
opacity: 0,
transition: { duration: 0.15 },
}}
>
{level === 0 && (
<motion.div
layout
className="absolute inset-y-0 left-0 w-px bg-zinc-900/10 dark:bg-white/5"
/>
)}
{link.links.map((childLink) => (
<NavigationLinkItem
key={childLink.href}
link={childLink}
pathname={pathname}
level={level + 1}
/>
))}
</motion.ul>
)}
</AnimatePresence>
</motion.li>
)
}

Expand All @@ -110,13 +112,7 @@ function NavigationGroup({ group, className }) {
// state, so that the state does not change during the close animation.
// The state will still update when we re-open (re-render) the navigation.
let isInsideMobileNavigation = useIsInsideMobileNavigation()
let [router, sections] = useInitialValue(
[useRouter(), useSectionStore((s) => s.sections)],
isInsideMobileNavigation
)

let isActiveGroup =
group.links.findIndex((link) => link.href === router.pathname) !== -1
let router = useInitialValue(useRouter(), isInsideMobileNavigation)

return (
<li className={clsx('relative mt-6', className)}>
Expand All @@ -130,56 +126,10 @@ function NavigationGroup({ group, className }) {
<span>{group.title}</span>
)}
</motion.h2>
<div className="relative mt-3 pl-2">
<AnimatePresence initial={!isInsideMobileNavigation}>
{isActiveGroup && (
<VisibleSectionHighlight group={group} pathname={router.pathname} />
)}
</AnimatePresence>
<motion.div
layout
className="absolute inset-y-0 left-2 w-px bg-zinc-900/10 dark:bg-white/5"
/>
<AnimatePresence initial={false}>
{isActiveGroup && (
<ActivePageMarker group={group} pathname={router.pathname} />
)}
</AnimatePresence>
<div className="relative mt-3">
<ul role="list" className="border-l border-transparent">
{group.links.map((link) => (
<motion.li key={link.href} layout="position" className="relative">
<NavLink href={link.href} active={link.href === router.pathname}>
{link.title}
</NavLink>
<AnimatePresence mode="popLayout" initial={false}>
{link.href === router.pathname && sections.length > 0 && (
<motion.ul
role="list"
initial={{ opacity: 0 }}
animate={{
opacity: 1,
transition: { delay: 0.1 },
}}
exit={{
opacity: 0,
transition: { duration: 0.15 },
}}
>
{sections.map((section) => (
<li key={section.id}>
<NavLink
href={`${link.href}#${section.id}`}
tag={section.tag}
isAnchorLink
>
{section.title}
</NavLink>
</li>
))}
</motion.ul>
)}
</AnimatePresence>
</motion.li>
<NavigationLinkItem key={link.href} link={link} pathname={router.pathname} />
))}
</ul>
</div>
Expand All @@ -192,12 +142,24 @@ export const navigation = [
title: 'Documentation',
href: '/docs',
links: [
{ title: 'Introduction', href: '/docs/introduction' },
{ title: 'Install', href: '/docs/install' },
{ title: 'Basics', href: '/docs/quickstart' },
{ title: 'Advanced', href: '/docs/advanced' },
{ title: 'Ops ⛨', href: '/docs/ops' },
{ title: 'GitHub ★', href: 'https://github.com/dotenvx/dotenvx' },
{ title: 'Whitepaper ¶', href: '/dotenvx.pdf' },
]
},
{
title: 'Quickstart',
href: '/docs/quickstart',
links: [
{
title: 'Node.js',
href: '/docs/secrets-for-nodejs',
links: [
{ title: 'Introduction', href: '/docs/secrets-for-nodejs' },
{ title: 'Express', href: '/docs/secrets-for-express' },
],
},
]
},
{
Expand Down
7 changes: 7 additions & 0 deletions src/pages/docs/cli/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { HeadRedirect } from '@/components/HeadRedirect'

<HeadRedirect url="/docs/cli/introduction"/>

# Redirecting

<a href="/docs/cli/introduction">Click here if you are not redirected.</a>
7 changes: 7 additions & 0 deletions src/pages/docs/cli/introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const description =
'Introduction'

##### [CLI Reference](/docs)
# Introduction

TODO
6 changes: 6 additions & 0 deletions src/pages/docs/introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const description = 'Introduction'

##### [Documentation](/docs)
# Introduction

coming soon
17 changes: 1 addition & 16 deletions src/pages/docs/quickstart/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,14 @@ export const description =
'Manage secrets with dotenvx'

##### [Documentation](/docs)
# Basics
# Quickstart

Learn the basics of `dotenvx` in just a few minutes. {{ className: 'lead' }}

- run anywhere (cross-platform)
- multiple environments
- encrypted envs

## Quickstart

> Install and use it in code just like `dotenv`.

```sh
npm install @dotenvx/dotenvx --save
```
```js
// index.js
require('@dotenvx/dotenvx').config()
// or import '@dotenvx/dotenvx/config' // for esm

console.log(`Hello ${process.env.HELLO}`)
```

## Run Anywhere

> Run it with `dotenvx run -- yourcommand`.
Expand Down
6 changes: 6 additions & 0 deletions src/pages/docs/secrets-for-express.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const description = 'Secrets for Express'

##### [Documentation](/docs)
# Secrets for Express

coming soon
6 changes: 6 additions & 0 deletions src/pages/docs/secrets-for-nodejs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const description = 'Secrets for Node.js'

##### [Documentation](/docs)
# Secrets for Node.js

coming soon
6 changes: 6 additions & 0 deletions src/pages/docs/secrets-for-nodejs/introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const description = 'Secrets for Node.js Introduction'

##### [Documentation](/docs)
# Secrets for Node.js: Introduction

coming soon
11 changes: 11 additions & 0 deletions src/styles/tailwind.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,14 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
.prose h5 a {
color: var(--tw-prose-captions);
text-decoration: none;
}

.prose h5 a:hover {
color: var(--tw-prose-body);
}
}
10 changes: 10 additions & 0 deletions typography.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,16 @@ module.exports = ({ theme }) => ({
marginTop: theme('spacing.10'),
marginBottom: theme('spacing.2'),
},
h5: {
color: 'var(--tw-prose-captions)',
},
'h5 a': {
color: 'var(--tw-prose-captions)',
textDecoration: 'none',
'&:hover': {
color: 'var(--tw-prose-body)',
},
},

// Media
'img, video, figure': {
Expand Down