diff options
| author | Dawid Rycerz <dawid@rycerz.xyz> | 2025-07-21 21:56:55 +0300 |
|---|---|---|
| committer | Dawid Rycerz <dawid@rycerz.xyz> | 2025-07-21 21:56:55 +0300 |
| commit | c735556726e75428550a3d28a2cf58e2c8490b7d (patch) | |
| tree | fd0ae29d1636b825abeedff6b99d3376bb383135 /src/components/widgets/Header.astro | |
Initial template
Diffstat (limited to 'src/components/widgets/Header.astro')
| -rw-r--r-- | src/components/widgets/Header.astro | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/src/components/widgets/Header.astro b/src/components/widgets/Header.astro new file mode 100644 index 0000000..ff4a3aa --- /dev/null +++ b/src/components/widgets/Header.astro @@ -0,0 +1,167 @@ +--- +import { Icon } from 'astro-icon/components'; +import Logo from '~/components/Logo.astro'; +import ToggleTheme from '~/components/common/ToggleTheme.astro'; +import ToggleMenu from '~/components/common/ToggleMenu.astro'; +import Button from '~/components/ui/Button.astro'; + +import { getHomePermalink } from '~/utils/permalinks'; +import { trimSlash, getAsset } from '~/utils/permalinks'; +import type { CallToAction } from '~/types'; + +interface Link { + text?: string; + href?: string; + ariaLabel?: string; + icon?: string; +} + +interface MenuLink extends Link { + links?: Array<MenuLink>; +} + +export interface Props { + id?: string; + links?: Array<MenuLink>; + actions?: Array<CallToAction>; + isSticky?: boolean; + isDark?: boolean; + isFullWidth?: boolean; + showToggleTheme?: boolean; + showRssFeed?: boolean; + position?: string; +} + +const { + id = 'header', + links = [], + actions = [], + isSticky = false, + isDark = false, + isFullWidth = false, + showToggleTheme = false, + showRssFeed = false, + position = 'center', +} = Astro.props; + +const currentPath = `/${trimSlash(new URL(Astro.url).pathname)}`; +--- + +<header + class:list={[ + { sticky: isSticky, relative: !isSticky, dark: isDark }, + 'top-0 z-40 flex-none mx-auto w-full border-b border-gray-50/0 transition-[opacity] ease-in-out', + ]} + {...isSticky ? { 'data-aw-sticky-header': true } : {}} + {...id ? { id } : {}} +> + <div class="absolute inset-0"></div> + <div + class:list={[ + 'relative text-default py-3 px-3 md:px-6 mx-auto w-full', + { + 'md:flex md:justify-between': position !== 'center', + }, + { + 'md:grid md:grid-cols-3 md:items-center': position === 'center', + }, + { + 'max-w-7xl': !isFullWidth, + }, + ]} + > + <div class:list={[{ 'mr-auto rtl:mr-0 rtl:ml-auto': position === 'right' }, 'flex justify-between']}> + <a class="flex items-center" href={getHomePermalink()}> + <Logo /> + </a> + <div class="flex items-center md:hidden"> + <ToggleMenu /> + </div> + </div> + <nav + class="items-center w-full md:w-auto hidden md:flex md:mx-5 text-default overflow-y-auto overflow-x-hidden md:overflow-y-visible md:overflow-x-auto md:justify-self-center" + aria-label="Main navigation" + > + <ul + class="flex flex-col md:flex-row md:self-center w-full md:w-auto text-xl md:text-[0.9375rem] tracking-[0.01rem] font-medium md:justify-center" + > + { + links.map(({ text, href, links }) => ( + <li class={links?.length ? 'dropdown' : ''}> + {links?.length ? ( + <> + <button + type="button" + class="hover:text-link dark:hover:text-white px-4 py-3 flex items-center whitespace-nowrap" + > + {text}{' '} + <Icon name="tabler:chevron-down" class="w-3.5 h-3.5 ml-0.5 rtl:ml-0 rtl:mr-0.5 hidden md:inline" /> + </button> + <ul class="dropdown-menu md:backdrop-blur-md dark:md:bg-dark rounded md:absolute pl-4 md:pl-0 md:hidden font-medium md:bg-white/90 md:min-w-[200px] drop-shadow-xl"> + {links.map(({ text: text2, href: href2 }) => ( + <li> + <a + class:list={[ + 'first:rounded-t last:rounded-b md:hover:bg-gray-100 hover:text-link dark:hover:text-white dark:hover:bg-gray-700 py-2 px-5 block whitespace-no-wrap', + { 'aw-link-active': href2 === currentPath }, + ]} + href={href2} + > + {text2} + </a> + </li> + ))} + </ul> + </> + ) : ( + <a + class:list={[ + 'hover:text-link dark:hover:text-white px-4 py-3 flex items-center whitespace-nowrap', + { 'aw-link-active': href === currentPath }, + ]} + href={href} + > + {text} + </a> + )} + </li> + )) + } + </ul> + </nav> + <div + class:list={[ + { 'ml-auto rtl:ml-0 rtl:mr-auto': position === 'left' }, + 'hidden md:self-center md:flex items-center md:mb-0 fixed w-full md:w-auto md:static justify-end left-0 rtl:left-auto rtl:right-0 bottom-0 p-3 md:p-0 md:justify-self-end', + ]} + > + <div class="items-center flex justify-between w-full md:w-auto"> + <div class="flex"> + {showToggleTheme && <ToggleTheme iconClass="w-6 h-6 md:w-5 md:h-5 md:inline-block" />} + { + showRssFeed && ( + <a + class="text-muted dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5 inline-flex items-center" + aria-label="RSS Feed" + href={getAsset('/rss.xml')} + > + <Icon name="tabler:rss" class="w-5 h-5" /> + </a> + ) + } + </div> + { + actions?.length ? ( + <span class="ml-4 rtl:ml-0 rtl:mr-4"> + {actions.map((btnProps) => ( + <Button {...btnProps} class="ml-2 py-2.5 px-5.5 md:px-6 font-semibold shadow-none text-sm w-auto" /> + ))} + </span> + ) : ( + '' + ) + } + </div> + </div> + </div> +</header> |
