diff --git a/posts/mdtest.md b/posts/mdtest.md new file mode 100644 index 0000000..db1d72c --- /dev/null +++ b/posts/mdtest.md @@ -0,0 +1,145 @@ +--- +title: "Markdown Testing" +date: "2025-06-17" +tags: ["testing"] +summary: "Testing Markdown Features" +--- +# Markdown Feature Test + +## Table of Contents +- [Headings](#headings) +- [Text Formatting](#text-formatting) +- [Lists](#lists) +- [Links](#links) +- [Images](#images) +- [Code](#code) +- [Blockquotes](#blockquotes) +- [Horizontal Rule](#horizontal-rule) +- [Tables](#tables) +- [Task Lists](#task-lists) +- [HTML in Markdown](#html-in-markdown) + +--- + +## Headings + +# H1 +## H2 +### H3 +#### H4 +##### H5 +###### H6 + +--- + +## Text Formatting + +- **Bold** +- *Italic* +- ***Bold and Italic*** +- ~~Strikethrough~~ +- Underline (HTML) +- ==Highlight (non-standard)== + +--- + +## Lists + +### Unordered +- Item 1 + - Subitem 1.1 + - Subitem 1.1.1 +- Item 2 + +### Ordered +1. First item +2. Second item + 1. Subitem + 2. Subitem +3. Third item + +--- + +## Links + +- [Inline Link](https://www.example.com) +- [Reference Link][example] +- + +[example]: https://www.example.com + +--- + +## Images + +![Alt text](https://via.placeholder.com/150 "Optional title") + +--- + +## Code + +### Inline Code + +Here is `inline code`. + +### Code Block (fenced) + +```Python + +def hello\_world(): +print("Hello, world!") + +``` + +### Code Block (indented) +```Python + def indented_example(): + return True +``` +--- + +## Blockquotes + +> This is a blockquote. +> +> > Nested blockquote. + +--- + +## Horizontal Rule + +--- + +___ + +*** + +--- + +## Tables + +| Syntax | Description | +|--------|-------------| +| Header | Title | +| Cell | Content | + +--- + +## Task Lists + +- [x] Task 1 +- [ ] Task 2 + - [x] Subtask + - [ ] Subtask + +--- + +## HTML in Markdown + +
+This is raw HTML in Markdown. +
+ +--- + +_End of Markdown Feature Test_ diff --git a/posts/welcome.md b/posts/welcome.md index 36e4c19..53e175b 100644 --- a/posts/welcome.md +++ b/posts/welcome.md @@ -1,6 +1,6 @@ --- title: "Read Me . Markdown!" -date: "2025-05-17" +date: "2025-06-17" tags: ["welcome", "introduction"] summary: "Read Me Please" --- @@ -29,7 +29,7 @@ Standard Markdown is supported. HTML with some basic CSS too! External CSS files | engine | Engine to be used for processing templates. Handlebars is the default. | | ext | Extension to be used for destination files. | -

If you noticed data was blue! This works due to the HTML / CSS / Markdown Transpiler. This basically means you can embed HTML into your Markdown blog-styled posts, and it will interpret correctly!

+

If you noticed data was blue! This works due to the HTML / CSS / Markdown Transpiler. This basically means you can embed HTML into your Markdown blog-styled posts, and it will interpret correctly!

**HTML Example:** diff --git a/src/app/posts/[...slug]/page.tsx b/src/app/posts/[...slug]/page.tsx index 1e1d714..fdb970e 100644 --- a/src/app/posts/[...slug]/page.tsx +++ b/src/app/posts/[...slug]/page.tsx @@ -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)}`);