42 lines
1.1 KiB
Text
42 lines
1.1 KiB
Text
---
|
|
import type { HTMLAttributes } from 'astro/types';
|
|
import { LOCALES } from '~/consts';
|
|
|
|
type Props = HTMLAttributes<'a'>;
|
|
|
|
const { href, class: className, ...props } = Astro.props;
|
|
|
|
function stripTrailing(p: string) {
|
|
return p.length > 1 && p.endsWith('/') ? p.slice(0, -1) : p;
|
|
}
|
|
|
|
function stripBase(p: string) {
|
|
const base = import.meta.env.BASE_URL;
|
|
if (base && base !== '/' && p.startsWith(base)) return p.slice(base.length - 1) || '/';
|
|
return p;
|
|
}
|
|
|
|
const pathname = stripTrailing(stripBase(Astro.url.pathname));
|
|
const target = stripTrailing(String(href ?? ''));
|
|
|
|
// Locale home URLs (`/`, `/en`) should only activate on exact match; deeper
|
|
// routes activate when the pathname equals or is nested under the href.
|
|
const localeHomes = new Set(['/', ...LOCALES.map((l) => `/${l}`)]);
|
|
const isActive = localeHomes.has(target)
|
|
? pathname === target
|
|
: pathname === target || pathname.startsWith(target + '/');
|
|
---
|
|
|
|
<a href={href} class:list={[className, { active: isActive }]} {...props}>
|
|
<slot />
|
|
</a>
|
|
<style>
|
|
a {
|
|
display: inline-block;
|
|
text-decoration: none;
|
|
}
|
|
a.active {
|
|
font-weight: bolder;
|
|
text-decoration: underline;
|
|
}
|
|
</style>
|