feat: coordinate sections signs and native navigation

This commit is contained in:
2026-09-02 04:27:10 +03:00
parent 9bbe4652ac
commit 22d456a6ca
11 changed files with 1510 additions and 31 deletions

View File

@@ -1,43 +1,34 @@
<script setup lang="ts">
import type { SectionId } from '@/content/types';
import { watch } from "vue";
import type { SectionId } from "@/content/types";
import { useJourneySections } from "@/composables/useJourneySections";
import { useKeyboardNavigation } from "@/composables/useKeyboardNavigation";
defineProps<{ items: ReadonlyArray<{ id: SectionId; label: string }> }>();
const props = defineProps<{
items: ReadonlyArray<{ id: SectionId; label: string }>;
}>();
const canonicalIds = props.items.map((item) => item.id);
const navigation = useKeyboardNavigation(canonicalIds);
const journey = useJourneySections(canonicalIds, navigation.state);
const focusActivatedSection = (event: MouseEvent): void => {
if (
event.defaultPrevented ||
event.button !== 0 ||
event.altKey ||
event.ctrlKey ||
event.metaKey ||
event.shiftKey ||
!(event.currentTarget instanceof HTMLAnchorElement)
) {
return;
}
let sectionId: string;
try {
sectionId = decodeURIComponent(event.currentTarget.hash.slice(1));
} catch {
return;
}
const section = document.getElementById(sectionId);
const heading = section?.querySelector<HTMLElement>(
':scope > h2[tabindex="-1"]',
);
if (heading === undefined || heading === null) return;
requestAnimationFrame(() => heading.focus({ preventScroll: true }));
};
watch(
() => journey.value.activeSectionId,
(id) => navigation.notePassiveSection(id),
);
</script>
<template>
<nav class="site-navigation" aria-label="Portfolio sections">
<ul>
<li v-for="item in items" :key="item.id">
<a :href="`#${item.id}`" @click="focusActivatedSection">{{ item.label }}</a>
<a
:href="`#${item.id}`"
:aria-current="
journey.activeSectionId === item.id ? 'page' : undefined
"
@click="navigation.onSectionLinkClick"
>{{ item.label }}</a
>
</li>
</ul>
</nav>