Merge pull request #980 from atchox/main
add functionality for fixed navbar
This commit is contained in:
		@@ -98,13 +98,11 @@ export default function RootLayout({ children }: { children: React.ReactNode })
 | 
			
		||||
        <ThemeProviders>
 | 
			
		||||
          <Analytics analyticsConfig={siteMetadata.analytics as AnalyticsConfig} />
 | 
			
		||||
          <SectionContainer>
 | 
			
		||||
            <div className="flex h-screen flex-col justify-between font-sans">
 | 
			
		||||
              <SearchProvider searchConfig={siteMetadata.search as SearchConfig}>
 | 
			
		||||
                <Header />
 | 
			
		||||
                <main className="mb-auto">{children}</main>
 | 
			
		||||
              </SearchProvider>
 | 
			
		||||
              <Footer />
 | 
			
		||||
            </div>
 | 
			
		||||
            <SearchProvider searchConfig={siteMetadata.search as SearchConfig}>
 | 
			
		||||
              <Header />
 | 
			
		||||
              <main className="mb-auto">{children}</main>
 | 
			
		||||
            </SearchProvider>
 | 
			
		||||
            <Footer />
 | 
			
		||||
          </SectionContainer>
 | 
			
		||||
        </ThemeProviders>
 | 
			
		||||
      </body>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,37 +7,41 @@ import ThemeSwitch from './ThemeSwitch'
 | 
			
		||||
import SearchButton from './SearchButton'
 | 
			
		||||
 | 
			
		||||
const Header = () => {
 | 
			
		||||
  let headerClass = 'flex items-center w-full bg-white dark:bg-gray-950 justify-between py-10'
 | 
			
		||||
  if (siteMetadata.stickyNav) {
 | 
			
		||||
    headerClass += ' sticky top-0 z-50'
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <header className="flex items-center justify-between py-10">
 | 
			
		||||
      <div>
 | 
			
		||||
        <Link href="/" aria-label={siteMetadata.headerTitle}>
 | 
			
		||||
          <div className="flex items-center justify-between">
 | 
			
		||||
            <div className="mr-3">
 | 
			
		||||
              <Logo />
 | 
			
		||||
            </div>
 | 
			
		||||
            {typeof siteMetadata.headerTitle === 'string' ? (
 | 
			
		||||
              <div className="hidden h-6 text-2xl font-semibold sm:block">
 | 
			
		||||
                {siteMetadata.headerTitle}
 | 
			
		||||
              </div>
 | 
			
		||||
            ) : (
 | 
			
		||||
              siteMetadata.headerTitle
 | 
			
		||||
            )}
 | 
			
		||||
    <header className={headerClass}>
 | 
			
		||||
      <Link href="/" aria-label={siteMetadata.headerTitle}>
 | 
			
		||||
        <div className="flex items-center justify-between">
 | 
			
		||||
          <div className="mr-3">
 | 
			
		||||
            <Logo />
 | 
			
		||||
          </div>
 | 
			
		||||
        </Link>
 | 
			
		||||
      </div>
 | 
			
		||||
          {typeof siteMetadata.headerTitle === 'string' ? (
 | 
			
		||||
            <div className="hidden h-6 text-2xl font-semibold sm:block">
 | 
			
		||||
              {siteMetadata.headerTitle}
 | 
			
		||||
            </div>
 | 
			
		||||
          ) : (
 | 
			
		||||
            siteMetadata.headerTitle
 | 
			
		||||
          )}
 | 
			
		||||
        </div>
 | 
			
		||||
      </Link>
 | 
			
		||||
      <div className="flex items-center space-x-4 leading-5 sm:space-x-6">
 | 
			
		||||
        {headerNavLinks
 | 
			
		||||
          .filter((link) => link.href !== '/')
 | 
			
		||||
          .map((link) => (
 | 
			
		||||
            <Link
 | 
			
		||||
              key={link.title}
 | 
			
		||||
              href={link.href}
 | 
			
		||||
              className="hidden font-medium text-gray-900 hover:text-primary-500 dark:text-gray-100 dark:hover:text-primary-400
 | 
			
		||||
              sm:block"
 | 
			
		||||
            >
 | 
			
		||||
              {link.title}
 | 
			
		||||
            </Link>
 | 
			
		||||
          ))}
 | 
			
		||||
        <div className="no-scrollbar hidden max-w-40 items-center space-x-4 overflow-x-auto sm:flex sm:space-x-6 md:max-w-72 lg:max-w-96">
 | 
			
		||||
          {headerNavLinks
 | 
			
		||||
            .filter((link) => link.href !== '/')
 | 
			
		||||
            .map((link) => (
 | 
			
		||||
              <Link
 | 
			
		||||
                key={link.title}
 | 
			
		||||
                href={link.href}
 | 
			
		||||
                className="block font-medium text-gray-900 hover:text-primary-500 dark:text-gray-100 dark:hover:text-primary-400"
 | 
			
		||||
              >
 | 
			
		||||
                {link.title}
 | 
			
		||||
              </Link>
 | 
			
		||||
            ))}
 | 
			
		||||
        </div>
 | 
			
		||||
        <SearchButton />
 | 
			
		||||
        <ThemeSwitch />
 | 
			
		||||
        <MobileNav />
 | 
			
		||||
 
 | 
			
		||||
@@ -1,25 +1,31 @@
 | 
			
		||||
'use client'
 | 
			
		||||
 | 
			
		||||
import { Dialog, Transition } from '@headlessui/react'
 | 
			
		||||
import { Fragment, useState } from 'react'
 | 
			
		||||
import { disableBodyScroll, enableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock'
 | 
			
		||||
import { Fragment, useState, useEffect, useRef } from 'react'
 | 
			
		||||
import Link from './Link'
 | 
			
		||||
import headerNavLinks from '@/data/headerNavLinks'
 | 
			
		||||
 | 
			
		||||
const MobileNav = () => {
 | 
			
		||||
  const [navShow, setNavShow] = useState(false)
 | 
			
		||||
  const navRef = useRef(null)
 | 
			
		||||
 | 
			
		||||
  const onToggleNav = () => {
 | 
			
		||||
    setNavShow((status) => {
 | 
			
		||||
      if (status) {
 | 
			
		||||
        document.body.style.overflow = 'auto'
 | 
			
		||||
        enableBodyScroll(navRef.current)
 | 
			
		||||
      } else {
 | 
			
		||||
        // Prevent scrolling
 | 
			
		||||
        document.body.style.overflow = 'hidden'
 | 
			
		||||
        disableBodyScroll(navRef.current)
 | 
			
		||||
      }
 | 
			
		||||
      return !status
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    return clearAllBodyScrollLocks
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <button aria-label="Toggle Menu" onClick={onToggleNav} className="sm:hidden">
 | 
			
		||||
@@ -36,8 +42,8 @@ const MobileNav = () => {
 | 
			
		||||
          />
 | 
			
		||||
        </svg>
 | 
			
		||||
      </button>
 | 
			
		||||
      <Transition appear show={navShow} as={Fragment}>
 | 
			
		||||
        <Dialog as="div" className="relative z-10" onClose={onToggleNav}>
 | 
			
		||||
      <Transition appear show={navShow} as={Fragment} unmount={false}>
 | 
			
		||||
        <Dialog as="div" onClose={onToggleNav} unmount={false}>
 | 
			
		||||
          <Transition.Child
 | 
			
		||||
            as={Fragment}
 | 
			
		||||
            enter="ease-out duration-300"
 | 
			
		||||
@@ -46,60 +52,53 @@ const MobileNav = () => {
 | 
			
		||||
            leave="ease-in duration-200"
 | 
			
		||||
            leaveFrom="opacity-100"
 | 
			
		||||
            leaveTo="opacity-0"
 | 
			
		||||
            unmount={false}
 | 
			
		||||
          >
 | 
			
		||||
            <div className="fixed inset-0 bg-black/25" />
 | 
			
		||||
            <div className="fixed inset-0 z-60 bg-black/25" />
 | 
			
		||||
          </Transition.Child>
 | 
			
		||||
 | 
			
		||||
          <div className="fixed inset-0 overflow-y-auto">
 | 
			
		||||
            <div className="flex min-h-full items-center justify-center p-4 text-center">
 | 
			
		||||
              <Transition.Child
 | 
			
		||||
                as={Fragment}
 | 
			
		||||
                enter="transition ease-in-out duration-300 transform"
 | 
			
		||||
                enterFrom="translate-x-full opacity-0"
 | 
			
		||||
                enterTo="translate-x-0 opacity-95"
 | 
			
		||||
                leave="transition ease-in duration-200 transform"
 | 
			
		||||
                leaveFrom="translate-x-0 opacity-95"
 | 
			
		||||
                leaveTo="translate-x-full opacity-0"
 | 
			
		||||
          <Transition.Child
 | 
			
		||||
            as={Fragment}
 | 
			
		||||
            enter="transition ease-in-out duration-300 transform"
 | 
			
		||||
            enterFrom="translate-x-full opacity-0"
 | 
			
		||||
            enterTo="translate-x-0 opacity-95"
 | 
			
		||||
            leave="transition ease-in duration-200 transform"
 | 
			
		||||
            leaveFrom="translate-x-0 opacity-95"
 | 
			
		||||
            leaveTo="translate-x-full opacity-0"
 | 
			
		||||
            unmount={false}
 | 
			
		||||
          >
 | 
			
		||||
            <Dialog.Panel className="fixed left-0 top-0 z-70 h-full w-full bg-white opacity-95 duration-300 dark:bg-gray-950 dark:opacity-[0.98]">
 | 
			
		||||
              <nav
 | 
			
		||||
                ref={navRef}
 | 
			
		||||
                className="mt-8 flex h-full basis-0 flex-col items-start overflow-y-auto pl-12 pt-2 text-left"
 | 
			
		||||
              >
 | 
			
		||||
                <Dialog.Panel className="fixed left-0 top-0 z-10 h-full w-full bg-white opacity-95 duration-300 dark:bg-gray-950 dark:opacity-[0.98]">
 | 
			
		||||
                  <nav className="fixed mt-8 h-full text-left">
 | 
			
		||||
                    {headerNavLinks.map((link) => (
 | 
			
		||||
                      <div key={link.title} className="px-12 py-4">
 | 
			
		||||
                        <Link
 | 
			
		||||
                          href={link.href}
 | 
			
		||||
                          className="text-2xl font-bold tracking-widest text-gray-900 hover:text-primary-500 dark:text-gray-100 dark:hover:text-primary-400"
 | 
			
		||||
                          onClick={onToggleNav}
 | 
			
		||||
                        >
 | 
			
		||||
                          {link.title}
 | 
			
		||||
                        </Link>
 | 
			
		||||
                      </div>
 | 
			
		||||
                    ))}
 | 
			
		||||
                  </nav>
 | 
			
		||||
                {headerNavLinks.map((link) => (
 | 
			
		||||
                  <Link
 | 
			
		||||
                    key={link.title}
 | 
			
		||||
                    href={link.href}
 | 
			
		||||
                    className="mb-4 py-2 pr-4 text-2xl font-bold tracking-widest text-gray-900 outline outline-0 hover:text-primary-500 dark:text-gray-100 dark:hover:text-primary-400"
 | 
			
		||||
                    onClick={onToggleNav}
 | 
			
		||||
                  >
 | 
			
		||||
                    {link.title}
 | 
			
		||||
                  </Link>
 | 
			
		||||
                ))}
 | 
			
		||||
              </nav>
 | 
			
		||||
 | 
			
		||||
                  <div className="flex justify-end">
 | 
			
		||||
                    <button
 | 
			
		||||
                      className="mr-8 mt-11 h-8 w-8"
 | 
			
		||||
                      aria-label="Toggle Menu"
 | 
			
		||||
                      onClick={onToggleNav}
 | 
			
		||||
                    >
 | 
			
		||||
                      <svg
 | 
			
		||||
                        xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
                        viewBox="0 0 20 20"
 | 
			
		||||
                        fill="currentColor"
 | 
			
		||||
                        className="text-gray-900 hover:text-primary-500 dark:text-gray-100 dark:hover:text-primary-400"
 | 
			
		||||
                      >
 | 
			
		||||
                        <path
 | 
			
		||||
                          fillRule="evenodd"
 | 
			
		||||
                          d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
 | 
			
		||||
                          clipRule="evenodd"
 | 
			
		||||
                        />
 | 
			
		||||
                      </svg>
 | 
			
		||||
                    </button>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </Dialog.Panel>
 | 
			
		||||
              </Transition.Child>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
              <button
 | 
			
		||||
                className="fixed right-4 top-7 z-80 h-16 w-16 p-4 text-gray-900 hover:text-primary-500 dark:text-gray-100 dark:hover:text-primary-400"
 | 
			
		||||
                aria-label="Toggle Menu"
 | 
			
		||||
                onClick={onToggleNav}
 | 
			
		||||
              >
 | 
			
		||||
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
 | 
			
		||||
                  <path
 | 
			
		||||
                    fillRule="evenodd"
 | 
			
		||||
                    d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
 | 
			
		||||
                    clipRule="evenodd"
 | 
			
		||||
                  />
 | 
			
		||||
                </svg>
 | 
			
		||||
              </button>
 | 
			
		||||
            </Dialog.Panel>
 | 
			
		||||
          </Transition.Child>
 | 
			
		||||
        </Dialog>
 | 
			
		||||
      </Transition>
 | 
			
		||||
    </>
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,15 @@
 | 
			
		||||
  @apply my-5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.no-scrollbar::-webkit-scrollbar {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.no-scrollbar {
 | 
			
		||||
  -ms-overflow-style: none; /* IE and Edge */
 | 
			
		||||
  scrollbar-width: none; /* Firefox */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* https://stackoverflow.com/questions/61083813/how-to-avoid-internal-autofill-selected-style-to-be-applied */
 | 
			
		||||
input:-webkit-autofill,
 | 
			
		||||
input:-webkit-autofill:focus {
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,8 @@ const siteMetadata = {
 | 
			
		||||
  threads: 'https://www.threads.net',
 | 
			
		||||
  instagram: 'https://www.instagram.com',
 | 
			
		||||
  locale: 'en-US',
 | 
			
		||||
  // set to true if you want a navbar fixed to the top
 | 
			
		||||
  stickyNav: false,
 | 
			
		||||
  analytics: {
 | 
			
		||||
    // If you want to use an analytics provider you have to add it to the
 | 
			
		||||
    // content security policy in the `next.config.js` file.
 | 
			
		||||
@@ -34,7 +36,7 @@ const siteMetadata = {
 | 
			
		||||
    },
 | 
			
		||||
    // plausibleAnalytics: {
 | 
			
		||||
    //   plausibleDataDomain: '', // e.g. tailwind-nextjs-starter-blog.vercel.app
 | 
			
		||||
         // If you are hosting your own Plausible.
 | 
			
		||||
    // If you are hosting your own Plausible.
 | 
			
		||||
    //   src: '', // e.g. https://plausible.my-domain.com/js/script.js
 | 
			
		||||
    // },
 | 
			
		||||
    // simpleAnalytics: {},
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
    "@tailwindcss/forms": "^0.5.7",
 | 
			
		||||
    "@tailwindcss/typography": "^0.5.12",
 | 
			
		||||
    "autoprefixer": "^10.4.13",
 | 
			
		||||
    "body-scroll-lock": "^4.0.0-beta.0",
 | 
			
		||||
    "contentlayer2": "0.4.6",
 | 
			
		||||
    "esbuild": "0.20.2",
 | 
			
		||||
    "github-slugger": "^2.0.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,11 @@ module.exports = {
 | 
			
		||||
        primary: colors.pink,
 | 
			
		||||
        gray: colors.gray,
 | 
			
		||||
      },
 | 
			
		||||
      zIndex: {
 | 
			
		||||
        60: '60',
 | 
			
		||||
        70: '70',
 | 
			
		||||
        80: '80',
 | 
			
		||||
      },
 | 
			
		||||
      typography: ({ theme }) => ({
 | 
			
		||||
        DEFAULT: {
 | 
			
		||||
          css: {
 | 
			
		||||
 
 | 
			
		||||
@@ -4002,6 +4002,13 @@ __metadata:
 | 
			
		||||
  languageName: node
 | 
			
		||||
  linkType: hard
 | 
			
		||||
 | 
			
		||||
"body-scroll-lock@npm:^4.0.0-beta.0":
 | 
			
		||||
  version: 4.0.0-beta.0
 | 
			
		||||
  resolution: "body-scroll-lock@npm:4.0.0-beta.0"
 | 
			
		||||
  checksum: 61d40007fddf64ecc69e9e02ed9d96bb895f88d7da65cea7651081110225de48efa44ffc4acd376ed004788e242a9af12059fec728c096774b49365524ea6f46
 | 
			
		||||
  languageName: node
 | 
			
		||||
  linkType: hard
 | 
			
		||||
 | 
			
		||||
"boolbase@npm:^1.0.0":
 | 
			
		||||
  version: 1.0.0
 | 
			
		||||
  resolution: "boolbase@npm:1.0.0"
 | 
			
		||||
@@ -10908,6 +10915,7 @@ __metadata:
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": ^6.1.0
 | 
			
		||||
    "@typescript-eslint/parser": ^6.1.0
 | 
			
		||||
    autoprefixer: ^10.4.13
 | 
			
		||||
    body-scroll-lock: ^4.0.0-beta.0
 | 
			
		||||
    contentlayer2: 0.4.6
 | 
			
		||||
    cross-env: ^7.0.3
 | 
			
		||||
    esbuild: 0.20.2
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user