gay sex.
if you link in Markdown it scrolls to the link in the page. you can see this in mdtest.md
This commit is contained in:
@@ -31,6 +31,71 @@ export default function PostPage({ params }: { params: { slug: string[] } }) {
|
||||
return () => clearInterval(interval);
|
||||
}, [slugPath]);
|
||||
|
||||
// On post load or update, scroll to anchor in hash if present
|
||||
useEffect(() => {
|
||||
// Scroll to anchor if hash is present
|
||||
const scrollToHash = () => {
|
||||
if (window.location.hash) {
|
||||
const id = window.location.hash.substring(1);
|
||||
const el = document.getElementById(id);
|
||||
if (el) {
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}
|
||||
};
|
||||
// On initial load
|
||||
scrollToHash();
|
||||
// Listen for hash changes
|
||||
window.addEventListener('hashchange', scrollToHash);
|
||||
return () => {
|
||||
window.removeEventListener('hashchange', scrollToHash);
|
||||
};
|
||||
}, [post]);
|
||||
|
||||
// Intercept anchor clicks in rendered markdown to ensure smooth scrolling to headings
|
||||
useEffect(() => {
|
||||
// Find the rendered markdown container
|
||||
const prose = document.querySelector('.prose');
|
||||
if (!prose) return;
|
||||
/**
|
||||
* Handles clicks on anchor links (e.g. Table of Contents links) inside the markdown.
|
||||
* - If the link is an in-page anchor (starts with #), prevent default navigation.
|
||||
* - Try to find an element with the corresponding id and scroll to it.
|
||||
* - If not found, search all headings for one whose text matches the anchor (case-insensitive, ignoring spaces/punctuation).
|
||||
* - If a match is found, scroll to that heading.
|
||||
* - Update the URL hash without reloading the page.
|
||||
*/
|
||||
const handleClick = (e: Event) => {
|
||||
if (!(e instanceof MouseEvent)) return;
|
||||
let target = e.target as HTMLElement | null;
|
||||
// Traverse up to find the closest anchor tag
|
||||
while (target && target.tagName !== 'A') {
|
||||
target = target.parentElement;
|
||||
}
|
||||
if (target && target.tagName === 'A' && target.getAttribute('href')?.startsWith('#')) {
|
||||
e.preventDefault();
|
||||
const id = target.getAttribute('href')!.slice(1);
|
||||
let el = document.getElementById(id);
|
||||
if (!el) {
|
||||
// Try to find a heading whose text matches the id (case-insensitive, ignoring spaces/punctuation)
|
||||
const headings = prose.querySelectorAll('h1, h2, h3, h4, h5, h6');
|
||||
const normalize = (str: string) => str.toLowerCase().replace(/[^a-z0-9]+/g, '');
|
||||
const normId = normalize(id);
|
||||
const found = Array.from(headings).find(h => normalize(h.textContent || '') === normId);
|
||||
el = (found as HTMLElement) || null;
|
||||
}
|
||||
if (el) {
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
history.replaceState(null, '', `#${id}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
prose.addEventListener('click', handleClick);
|
||||
return () => {
|
||||
prose.removeEventListener('click', handleClick);
|
||||
};
|
||||
}, [post]);
|
||||
|
||||
const loadPost = async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/posts/${encodeURIComponent(slugPath)}`);
|
||||
|
||||
Reference in New Issue
Block a user