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.
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
'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}</>;
}
'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>
</>
);
}