diff --git a/src/components/Header.jsx b/src/components/Header.jsx index b400e89..3a7b031 100644 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -86,7 +86,7 @@ export const Header = forwardRef(function Header({ className }, ref) { Get Started diff --git a/src/components/Navigation.jsx b/src/components/Navigation.jsx index 2466f0f..f23eaed 100644 --- a/src/components/Navigation.jsx +++ b/src/components/Navigation.jsx @@ -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 @@ -20,7 +18,7 @@ function TopLevelNavItem({ href, children }) {
  • {children} @@ -28,17 +26,25 @@ function TopLevelNavItem({ href, children }) { ) } -function NavLink({ href, tag, active, isAnchorLink = false, children }) { +function NavLink({ href, tag, active, current, level = 0, children }) { + let leftPaddingClass = { + 0: 'pl-2', + 1: 'pl-3', + 2: 'pl-3', + }[level] ?? 'pl-10' + return ( {children} @@ -51,57 +57,64 @@ 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() - ) +function isLinkActive(link, pathname) { + if (link.href === pathname) { + return true + } - 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 + return (link.links ?? []).some((childLink) => isLinkActive(childLink, pathname)) +} - return ( - +function hasDescendantWithHref(link, href) { + return (link.links ?? []).some( + (childLink) => childLink.href === href || hasDescendantWithHref(childLink, href) ) } -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) + // Only one item should be "current" (gets the persistent bg). If a parent and + // child share the same href, prefer the deepest child. + let isCurrent = link.href === pathname && !hasDescendantWithHref(link, pathname) return ( - + + + {link.title} + + + {isActive && (link.links?.length ?? 0) > 0 && ( + + {level === 0 && ( + + )} + {link.links.map((childLink) => ( + + ))} + + )} + + ) } @@ -110,19 +123,13 @@ 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 (
  • {group.href ? ( {group.title} @@ -130,56 +137,10 @@ function NavigationGroup({ group, className }) { {group.title} )} -
    - - {isActiveGroup && ( - - )} - - - - {isActiveGroup && ( - - )} - -
      +
      +
        {group.links.map((link) => ( - - - {link.title} - - - {link.href === router.pathname && sections.length > 0 && ( - - {sections.map((section) => ( -
      • - - {section.title} - -
      • - ))} -
        - )} -
        -
        + ))}
      @@ -192,27 +153,30 @@ export const navigation = [ title: 'Documentation', href: '/docs', links: [ - { 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: 'Introduction', href: '/docs/introduction' }, ] }, { - title: 'Ops ⛨', - href: '/docs/ops', + title: 'Quickstart', + href: '/docs/quickstart', links: [ - { title: 'Install', href: '/docs/ops/install' }, - { title: 'Basics', href: '/docs/ops/quickstart' }, - { title: 'Advanced', href: '/docs/ops/advanced' }, + { + title: 'Node.js', + href: '/docs/secrets-in-nodejs', + links: [ + { title: 'Introduction', href: '/docs/secrets-in-nodejs' }, + { title: 'Express', href: '/docs/secrets-in-express' }, + ], + }, ] }, { title: 'Guides', href: '/docs/guides', links: [ + { title: 'Install', href: '/docs/install' }, + { title: 'Basics', href: '/docs/quickstart' }, + { title: 'Advanced', href: '/docs/advanced' }, { title: 'Quickstart: Run', href: '/docs/quickstart/run' }, { title: 'Quickstart: Environments', href: '/docs/quickstart/environments' }, { title: 'Quickstart: Encrypt', href: '/docs/quickstart/encryption' }, @@ -249,6 +213,16 @@ export const navigation = [ { title: 'llms.txt', href: '/llms.txt' }, ] }, + { + title: 'Ops ⛨', + href: '/docs/ops', + links: [ + { title: 'Install', href: '/docs/ops/install' }, + { title: 'Basics', href: '/docs/ops/quickstart' }, + { title: 'Advanced', href: '/docs/ops/advanced' }, + ] + }, + ] export function Navigation(props) { diff --git a/src/pages/docs/cli/index.mdx b/src/pages/docs/cli/index.mdx new file mode 100644 index 0000000..acb3cc9 --- /dev/null +++ b/src/pages/docs/cli/index.mdx @@ -0,0 +1,7 @@ +import { HeadRedirect } from '@/components/HeadRedirect' + + + +# Redirecting + +Click here if you are not redirected. diff --git a/src/pages/docs/cli/introduction.mdx b/src/pages/docs/cli/introduction.mdx new file mode 100644 index 0000000..b04bcd1 --- /dev/null +++ b/src/pages/docs/cli/introduction.mdx @@ -0,0 +1,7 @@ +export const description = + 'Introduction' + +##### [CLI Reference](/docs) +# Introduction + +TODO diff --git a/src/pages/docs/introduction.mdx b/src/pages/docs/introduction.mdx new file mode 100644 index 0000000..58018b6 --- /dev/null +++ b/src/pages/docs/introduction.mdx @@ -0,0 +1,13 @@ +export const description = 'Introduction' + +##### [Documentation](/docs) +# Introduction + +Dotenvx is the secrets CLI for developers. + +## Quickstart + +Learn how to get Dotenvx set up in your project. + +* [Node.js Quickstart](/docs/secrets-for-nodejs) +* [Express Quickstart](/docs/secrets-for-express) diff --git a/src/pages/docs/quickstart/index.mdx b/src/pages/docs/quickstart/index.mdx index ebadc3c..113e4fe 100644 --- a/src/pages/docs/quickstart/index.mdx +++ b/src/pages/docs/quickstart/index.mdx @@ -15,7 +15,7 @@ export const description = 'Manage secrets with dotenvx' ##### [Documentation](/docs) -# Basics +# Quickstart Learn the basics of `dotenvx` in just a few minutes. {{ className: 'lead' }} @@ -23,21 +23,6 @@ Learn the basics of `dotenvx` in just a few minutes. {{ className: 'lead' }} - 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`. diff --git a/src/pages/docs/secrets-in-express.mdx b/src/pages/docs/secrets-in-express.mdx new file mode 100644 index 0000000..5a07b9a --- /dev/null +++ b/src/pages/docs/secrets-in-express.mdx @@ -0,0 +1,51 @@ +import InstallNodeSdkCodeGroup from '@/pages/partials/installNodeSdkCodeGroup.mdx' + +##### [Documentation](/docs) +# Encrypt secrets in Express + +Learn how to encrypt your first .env file using Express and the Dotenvx Node.js SDK. + +## Prerequisites + +To get the most out of this guide, you'll need to: + +* [Install dotenvx](/docs/install) +* [Create your account](https://dotenvx.com/signup) (optional) + +## 1. Install + +Get the Dotenvx Node.js SDK. + + + +## 2. Encrypt env file + +Encrypt your .env file. + +```sh {{ title: '$ terminal' }} +npx dotenvx encrypt +``` + +## 3. Inject secrets + +Then inject your encrypted secrets at runtime. + + +```js {{ title: 'index.js' }} +require('@dotenvx/dotenvx').config() +const express = require('express') + +const app = express() +app.use(express.json()) + +app.get('/', (req, res) => { + res.json({ + ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY + }) +}) + +const port = process.env.PORT || 3000 +app.listen(port, () => { + console.log(`Server running on http://localhost:${port}`) +}) +``` diff --git a/src/pages/docs/secrets-in-nodejs.mdx b/src/pages/docs/secrets-in-nodejs.mdx new file mode 100644 index 0000000..57efb3f --- /dev/null +++ b/src/pages/docs/secrets-in-nodejs.mdx @@ -0,0 +1,38 @@ +import InstallNodeSdkCodeGroup from '@/pages/partials/installNodeSdkCodeGroup.mdx' + +##### [Documentation](/docs) +# Encrypt secrets in Node.js + +Learn how to encrypt your first .env file using the Dotenvx Node.js SDK. + +## Prerequisites + +To get the most out of this guide, you'll need to: + +* [Install dotenvx](/docs/install) +* [Create your account](https://dotenvx.com/signup) (optional) + +## 1. Install + +Get the Dotenvx Node.js SDK. + + + +## 2. Encrypt + +Encrypt your .env file. + +```sh {{ title: '$ terminal' }} +npx dotenvx encrypt +``` + +## 3. Inject + +Then inject your encrypted secrets at runtime. + + +```js {{ title: 'index.js' }} +require('@dotenvx/dotenvx').config() + +console.log(`ANTHROPIC_API_KEY: ${process.env.ANTHROPIC_API_KEY}`) +``` diff --git a/src/pages/partials/installNodeSdkCodeGroup.mdx b/src/pages/partials/installNodeSdkCodeGroup.mdx new file mode 100644 index 0000000..e1c78e0 --- /dev/null +++ b/src/pages/partials/installNodeSdkCodeGroup.mdx @@ -0,0 +1,19 @@ + + +```bash {{ title: "npm" }} +npm install @dotenvx/dotenvx +``` + +```bash {{ title: "yarn" }} +yarn add @dotenvx/dotenvx +``` + +```bash {{ title: "pnpm" }} +pnpm add @dotenvx/dotenvx +``` + +```bash {{ title: "bun" }} +bun add @dotenvx/dotenvx +``` + + diff --git a/src/styles/tailwind.css b/src/styles/tailwind.css index 4425af7..5752946 100644 --- a/src/styles/tailwind.css +++ b/src/styles/tailwind.css @@ -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); + } +} diff --git a/typography.js b/typography.js index c58a687..515ef0d 100644 --- a/typography.js +++ b/typography.js @@ -3,9 +3,9 @@ module.exports = ({ theme }) => ({ css: { '--tw-prose-body': theme('colors.zinc.700'), '--tw-prose-headings': theme('colors.zinc.900'), - '--tw-prose-links': theme('colors.yellow.500'), - '--tw-prose-links-hover': theme('colors.yellow.600'), - '--tw-prose-links-underline': theme('colors.yellow.500 / 0.3'), + '--tw-prose-links': '#000000', + '--tw-prose-links-hover': '#000000', + '--tw-prose-links-underline': 'rgb(9 9 11 / 0.55)', '--tw-prose-bold': theme('colors.zinc.900'), '--tw-prose-counters': theme('colors.zinc.500'), '--tw-prose-bullets': theme('colors.zinc.300'), @@ -21,9 +21,9 @@ module.exports = ({ theme }) => ({ '--tw-prose-invert-body': theme('colors.zinc.400'), '--tw-prose-invert-headings': theme('colors.white'), - '--tw-prose-invert-links': theme('colors.yellow.400'), - '--tw-prose-invert-links-hover': theme('colors.yellow.500'), - '--tw-prose-invert-links-underline': theme('colors.yellow.500 / 0.3'), + '--tw-prose-invert-links': theme('colors.zinc.400'), + '--tw-prose-invert-links-hover': theme('colors.zinc.400'), + '--tw-prose-invert-links-underline': theme('colors.zinc.400 / 0.5'), '--tw-prose-invert-bold': theme('colors.white'), '--tw-prose-invert-counters': theme('colors.zinc.400'), '--tw-prose-invert-bullets': theme('colors.zinc.600'), @@ -39,7 +39,7 @@ module.exports = ({ theme }) => ({ // Base color: 'var(--tw-prose-body)', - fontSize: theme('fontSize.sm')[0], + fontSize: '0.9375rem', lineHeight: theme('lineHeight.7'), // Layout @@ -56,8 +56,8 @@ module.exports = ({ theme }) => ({ // Text p: { - marginTop: theme('spacing.6'), - marginBottom: theme('spacing.6'), + marginTop: theme('spacing.4'), + marginBottom: theme('spacing.4'), }, '[class~="lead"]': { fontSize: theme('fontSize.base')[0], @@ -67,8 +67,8 @@ module.exports = ({ theme }) => ({ // Lists ol: { listStyleType: 'decimal', - marginTop: theme('spacing.5'), - marginBottom: theme('spacing.5'), + marginTop: theme('spacing.3'), + marginBottom: theme('spacing.3'), paddingLeft: '1.625rem', }, 'ol[type="A"]': { @@ -100,39 +100,41 @@ module.exports = ({ theme }) => ({ }, ul: { listStyleType: 'disc', - marginTop: theme('spacing.5'), - marginBottom: theme('spacing.5'), - paddingLeft: '1.625rem', + marginTop: theme('spacing.3'), + marginBottom: theme('spacing.3'), + paddingLeft: '2rem', }, li: { - marginTop: theme('spacing.2'), - marginBottom: theme('spacing.2'), + marginTop: theme('spacing.1'), + marginBottom: theme('spacing.1'), }, ':is(ol, ul) > li': { - paddingLeft: theme('spacing[1.5]'), + paddingLeft: theme('spacing.2'), }, 'ol > li::marker': { fontWeight: '400', color: 'var(--tw-prose-counters)', }, 'ul > li::marker': { - color: 'var(--tw-prose-bullets)', + color: theme('colors.zinc.600'), + fontWeight: '700', + fontSize: '1.1em', }, '> ul > li p': { - marginTop: theme('spacing.3'), - marginBottom: theme('spacing.3'), + marginTop: theme('spacing.1'), + marginBottom: theme('spacing.1'), }, '> ul > li > *:first-child': { - marginTop: theme('spacing.5'), + marginTop: theme('spacing.2'), }, '> ul > li > *:last-child': { - marginBottom: theme('spacing.5'), + marginBottom: theme('spacing.2'), }, '> ol > li > *:first-child': { - marginTop: theme('spacing.5'), + marginTop: theme('spacing.2'), }, '> ol > li > *:last-child': { - marginBottom: theme('spacing.5'), + marginBottom: theme('spacing.2'), }, 'ul ul, ul ol, ol ul, ol ol': { marginTop: theme('spacing.3'), @@ -190,7 +192,7 @@ module.exports = ({ theme }) => ({ fontWeight: '600', fontSize: theme('fontSize.lg')[0], ...theme('fontSize.lg')[1], - marginTop: theme('spacing.16'), + marginTop: theme('spacing.8'), marginBottom: theme('spacing.2'), }, h3: { @@ -201,6 +203,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': { @@ -278,16 +290,26 @@ module.exports = ({ theme }) => ({ // Inline elements a: { color: 'var(--tw-prose-links)', - textDecoration: 'underline transparent', - fontWeight: '500', - transitionProperty: 'color, text-decoration-color', - transitionDuration: theme('transitionDuration.DEFAULT'), - transitionTimingFunction: theme('transitionTimingFunction.DEFAULT'), + textDecoration: 'none', + borderBottom: '1px solid currentColor', + fontWeight: '400', '&:hover': { color: 'var(--tw-prose-links-hover)', - textDecorationColor: 'var(--tw-prose-links-underline)', + borderBottomWidth: '2px', }, }, + 'a.no-underline': { + borderBottom: 'none', + }, + 'a.no-underline:hover': { + borderBottom: 'none', + }, + 'h5 a, h5 a:hover': { + color: 'var(--tw-prose-captions)', + textDecoration: 'none', + borderBottom: 'none', + fontWeight: '400', + }, ':is(h1, h2, h3) a': { fontWeight: 'inherit', },