test: lock semantic and no-script portfolio behavior

This commit is contained in:
2026-09-02 03:12:12 +03:00
parent 3638a0beef
commit 091ff70deb
8 changed files with 811 additions and 2 deletions

View File

@@ -2,13 +2,42 @@
import type { SectionId } from '@/content/types';
defineProps<{ items: ReadonlyArray<{ id: SectionId; label: string }> }>();
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 }));
};
</script>
<template>
<nav class="site-navigation" aria-label="Portfolio sections">
<ul>
<li v-for="item in items" :key="item.id">
<a :href="`#${item.id}`">{{ item.label }}</a>
<a :href="`#${item.id}`" @click="focusActivatedSection">{{ item.label }}</a>
</li>
</ul>
</nav>