Todos os componentes

Responsive Header Default

Responsive Header Default é um componente de layout para React e Tailwind CSS, da biblioteca UI Layouts, com licença MIT. Copia e cola no teu projeto.

UI Layouts MIT layout

O que é

Responsive Header Default é um componente de layout para React e Tailwind CSS, da biblioteca UI Layouts, com licença MIT. Copia e cola no teu projeto.

Como usar

Abre o componente no catálogo, carrega em copiar, e cola no teu projeto. O prompt copiado leva o código e as regras para o teu agente o reproduzir sem alterar nada.

Abrir no catálogo

Cinco cópias grátis por mês. Sem cartão.

Precisa de

npm i motion

Licença

Este componente vem de UI Layouts e é redistribuído sob a licença MIT, que permite uso comercial. O aviso de copyright viaja com o código.

Responsive Header Default

./components/ui/responsive-header.tsx
'use client';

import { MenuIcon } from 'lucide-react';
import React, { createContext, type ReactNode, useContext, useEffect, useState } from 'react';
import { Drawer as VaulHeader } from 'vaul';

interface DrawerContextProps {
  open: boolean;
  setOpen: (open: boolean) => void;
}

const DrawerContext = createContext<DrawerContextProps | undefined>(undefined);

const useSidebarDrawer = () => {
  const context = useContext(DrawerContext);
  if (!context) {
    throw new Error('useDrawer must be used within a DrawerProvider');
  }
  return context;
};

interface DrawerSidebarProps {
  children: ReactNode;
  open?: boolean;
  setOpen?: (open: boolean) => void;
  drawerBtn?: any | null;
}

export function HeaderDrawer({
  children,
  open: controlledOpen,
  setOpen: controlledSetOpen,
  drawerBtn,
}: DrawerSidebarProps) {
  const [internalOpen, setInternalOpen] = useState(false);
  const open = controlledOpen !== undefined ? controlledOpen : internalOpen;
  const setOpen = controlledSetOpen !== undefined ? controlledSetOpen : setInternalOpen;

  const [isDesktop, setIsDesktop] = useState(false);

  useEffect(() => {
    const mediaQuery = window.matchMedia('(min-width: 768px)');
    const handleMediaChange = (event: MediaQueryListEvent) => {
      setIsDesktop(event.matches);
    };

    setIsDesktop(mediaQuery.matches);
    mediaQuery.addEventListener('change', handleMediaChange);

    return () => {
      mediaQuery.removeEventListener('change', handleMediaChange);
    };
  }, []);
  console.log(drawerBtn);

  return (
    <DrawerContext.Provider value={{ open, setOpen }}>
      <>
        <VaulHeader.Root
          open={open}
          direction='top'
          onOpenChange={setOpen}
          dismissible={isDesktop ? false : true}
        >
          {drawerBtn && <VaulHeader.Trigger asChild>{drawerBtn()}</VaulHeader.Trigger>}
          <VaulHeader.Portal>
            <VaulHeader.Overlay
              className='fixed inset-0 dark:bg-black/40 bg-white/50 backdrop-blur-xs z-50  '
              onClick={() => setOpen(false)}
            />
            <VaulHeader.Content className='dark:bg-neutral-900 bg-white  border-b z-50 w-full h-fit py-3 fixed top-0 left-0'>
              {children}
            </VaulHeader.Content>
          </VaulHeader.Portal>
        </VaulHeader.Root>
      </>
    </DrawerContext.Provider>
  );
}

export function DrawerContent({ children }: { children: ReactNode }) {
  return <>{children}</>;
}
./registry/components/drawer/responsive-header.tsx
'use client';
import { DrawerContent, HeaderDrawer } from '@/components/ui/responsive-header';
import { useMediaQuery } from '@/hooks/use-media-query';
import { MenuIcon, X } from 'lucide-react';
import Link from 'next/link';
import { useState } from 'react';

const items = [
  {
    id: 1,
    classname: 'bg-linear-to-l from-red-400 to-orange-500',
  },
  {
    classname: 'bg-linear-to-r from-blue-300 to-blue-800',
    id: 2,
  },
  {
    classname: 'bg-linear-to-tl from-amber-500 to-yellow-400',
    id: 3,
  },
];
export default function ResponsiveHeader() {
  const [headerOpen, setHeaderOpen] = useState(false);
  const isDesktop = useMediaQuery('(min-width: 768px)');

  return (
    <>
      <header className='flex justify-between border items-center p-3 bg-white rounded-md dark:bg-black/45 backdrop-blur-md'>
        <h1>Logo</h1>
        <HeaderDrawer
          open={headerOpen}
          setOpen={setHeaderOpen}
          drawerBtn={() => {
            return (
              <button>
                <MenuIcon />
              </button>
            );
          }}
        >
          <DrawerContent>
            {!isDesktop && (
              <div className='flex justify-center w-full absolute bottom-1 left-0 '>
                <div className=' w-16 h-[0.30rem] shrink-0 rounded-full bg-neutral-600 my-4' />
              </div>
            )}
            <div className='container mx-auto  gap-4'>
              <div className='flex justify-between items-center border-b'>
                {isDesktop && (
                  <button
                    className='flex justify-start p-2 mb-2 rounded-md dark:bg-white dark:text-black bg-black text-white'
                    onClick={() => setHeaderOpen(false)}
                  >
                    <X />
                  </button>
                )}
                <h1 className='mx-auto text-2xl'>UI-LAYOUT</h1>
              </div>
              <div className='flex justify-between xl:px-0 px-2 py-2'>
                <nav className='flex gap-8'>
                  <ul className='xl:text-2xl text-lg space-y-2 xl:space-y-4 font-semibold uppercase  pr-8'>
                    <li>
                      <Link
                        href='/'
                        className='relative flex items-center gap-2 after:absolute after:bottom-0 after:left-0 after:h-[2px] after:w-full after:origin-bottom-right after:scale-x-0 dark:after:bg-white 
      after:bg-neutral-800 after:transition-transform after:duration-300 after:ease-[cubic-bezier(0.65_0.05_0.36_1)] hover:after:origin-bottom-left hover:after:scale-x-100'
                      >
                        Home
                      </Link>
                    </li>
                    <li>
                      <Link
                        href='/components'
                        className='relative flex gap-2 items-center after:absolute after:bottom-0 after:left-0 after:h-[2px] after:w-full after:origin-bottom-right after:scale-x-0 dark:after:bg-white 
      after:bg-neutral-800 after:transition-transform after:duration-300 after:ease-[cubic-bezier(0.65_0.05_0.36_1)] hover:after:origin-bottom-left hover:after:scale-x-100'
                      >
                        Components
                      </Link>
                    </li>
                    <li>
                      <Link
                        href='/layouts'
                        className='relative flex gap-2 items-center after:absolute after:bottom-0 after:left-0 after:h-[2px] after:w-full after:origin-bottom-right after:scale-x-0 dark:after:bg-white 
      after:bg-neutral-800 after:transition-transform after:duration-300 after:ease-[cubic-bezier(0.65_0.05_0.36_1)] hover:after:origin-bottom-left hover:after:scale-x-100'
                      >
                        Layouts
                      </Link>
                    </li>
                    <li>
                      <Link
                        href='/templates'
                        className='relative flex items-center gap-2 after:absolute after:bottom-0 after:left-0 after:h-[2px] after:w-full after:origin-bottom-right after:scale-x-0 dark:after:bg-white 
      after:bg-neutral-800 after:transition-transform after:duration-300 after:ease-[cubic-bezier(0.65_0.05_0.36_1)] hover:after:origin-bottom-left hover:after:scale-x-100'
                      >
                        Templates
                      </Link>
                    </li>
                    <li>
                      <Link
                        href='/open-source'
                        className='relative flex items-center gap-2 after:absolute after:bottom-0 after:left-0 after:h-[2px] after:w-full after:origin-bottom-right after:scale-x-0 dark:after:bg-white 
      after:bg-neutral-800 after:transition-transform after:duration-300 after:ease-[cubic-bezier(0.65_0.05_0.36_1)] hover:after:origin-bottom-left hover:after:scale-x-100'
                      >
                        Open Source
                      </Link>
                    </li>
                  </ul>
                </nav>
                {isDesktop && (
                  <div className='grid grid-cols-3 gap-4 py-4 pr-20 w-full'>
                    <>
                      {items.map((item) => (
                        <figure
                          key={item.id}
                          className={`${item.classname} inline-block group w-full xl:h-52 h-full relative rounded-md `}
                        ></figure>
                      ))}
                    </>
                  </div>
                )}
              </div>
            </div>
          </DrawerContent>
        </HeaderDrawer>
      </header>
    </>
  );
}

Componentes parecidos