feat: external links now open in new tab + MDXAccordion component
This commit is contained in:
parent
5f8a34cbd3
commit
06e76d38df
4 changed files with 157 additions and 0 deletions
|
@ -2,6 +2,7 @@ import HR from './components/HR.astro'
|
||||||
import MDXImage from './components/mdx/MDXImage.astro'
|
import MDXImage from './components/mdx/MDXImage.astro'
|
||||||
import MDXCallout from './components/mdx/MDXCallout.astro'
|
import MDXCallout from './components/mdx/MDXCallout.astro'
|
||||||
import MDXCodeBlock from './components/mdx/MDXCodeBlock.astro'
|
import MDXCodeBlock from './components/mdx/MDXCodeBlock.astro'
|
||||||
|
import MDXLink from './components/mdx/MDXLink.astro'
|
||||||
|
|
||||||
export const components = {
|
export const components = {
|
||||||
hr: HR,
|
hr: HR,
|
||||||
|
@ -9,4 +10,5 @@ export const components = {
|
||||||
MDXImage: MDXImage,
|
MDXImage: MDXImage,
|
||||||
MDXCallout: MDXCallout,
|
MDXCallout: MDXCallout,
|
||||||
pre: MDXCodeBlock,
|
pre: MDXCodeBlock,
|
||||||
|
a: MDXLink,
|
||||||
}
|
}
|
126
src/components/mdx/MDXAccordion.astro
Normal file
126
src/components/mdx/MDXAccordion.astro
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
// I stole ALLLLLL of this from https://webreaper.dev/posts/astro-accessible-accordion/
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title } = Astro.props as Props;
|
||||||
|
|
||||||
|
import HR from "../HR.astro";
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<noscript>
|
||||||
|
<h2 class="text-xl text-title font-serif">
|
||||||
|
{ title }
|
||||||
|
<svg
|
||||||
|
class="inline-flex h-7 w-7"
|
||||||
|
aria-hidden="true"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
><path
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="m6 9l6 6l6-6"></path></svg
|
||||||
|
>
|
||||||
|
</h2>
|
||||||
|
<slot/>
|
||||||
|
</noscript>
|
||||||
|
|
||||||
|
<div class="accordion group relative mb-2 rounded-md border border-crusta-900 dark:border-indigo-400 hidden">
|
||||||
|
<button
|
||||||
|
class="accordion__button flex w-full flex-1 items-center justify-between gap-2 p-3 text-left font-medium transition hover:text-subtitle sm:px-4"
|
||||||
|
type="button"
|
||||||
|
id={`${title} accordion menu button`}
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-controls={`${title} accordion menu content`}
|
||||||
|
>
|
||||||
|
<span class="text-xl font-serif">{title}</span>
|
||||||
|
|
||||||
|
<!-- if using astro and the astro-icon package
|
||||||
|
<Icon
|
||||||
|
name="tabler:chevron-down"
|
||||||
|
aria-hidden="true"
|
||||||
|
class="accordion__chevron h-7 w-7 shrink-0 transition-transform"
|
||||||
|
/>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- use this is not using astro-icon (or another SVG you like) -->
|
||||||
|
<svg
|
||||||
|
class="accordion__chevron h-7 w-7 shrink-0 transition-transform"
|
||||||
|
aria-hidden="true"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
><path
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="m6 9l6 6l6-6"></path></svg
|
||||||
|
>
|
||||||
|
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id={`${title} accordion menu content`}
|
||||||
|
aria-labelledby={`${title} accordion menu button`}
|
||||||
|
class="accordion__content hidden max-h-0 overflow-hidden px-3 transition-all duration-300 ease-in-out sm:px-4"
|
||||||
|
>
|
||||||
|
<HR class="mt-0"/>
|
||||||
|
<div class="prose mb-4 items-center mt-1 max-w-full transition-[height]">
|
||||||
|
<slot/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function accordionSetup() {
|
||||||
|
const menus = document.querySelectorAll(".accordion") as NodeListOf<HTMLElement>; // set this up on each menu
|
||||||
|
menus.forEach((menu) => {
|
||||||
|
menu.classList.remove("hidden");
|
||||||
|
|
||||||
|
const button = menu.querySelector(".accordion__button") as HTMLElement; // the clickable banner
|
||||||
|
const chevron = menu.querySelector(".accordion__chevron") as HTMLElement; // the chevron icon that animates
|
||||||
|
const content = menu.querySelector(".accordion__content") as HTMLElement; // the stuff that's revealed when open
|
||||||
|
|
||||||
|
if (button && content && chevron) {
|
||||||
|
button.addEventListener("click", (event) => {
|
||||||
|
if (!menu.classList.contains("active")) { // if closed, stop having it be closed!
|
||||||
|
menu.classList.add("active");
|
||||||
|
button.setAttribute("aria-expanded", true);
|
||||||
|
|
||||||
|
// we need to set the max height to the height of the accordion object so the animations work correctly
|
||||||
|
content.classList.remove("hidden");
|
||||||
|
content.style.maxHeight = content.scrollHeight + "px";
|
||||||
|
chevron.classList.add("rotate-180");
|
||||||
|
} else { // if open, stop having it be open!!!!
|
||||||
|
menu.classList.remove("active");
|
||||||
|
button.setAttribute("aria-expanded", false);
|
||||||
|
|
||||||
|
content.style.maxHeight = '0px';
|
||||||
|
chevron.classList.remove("rotate-180");
|
||||||
|
|
||||||
|
// make text invisible after animation
|
||||||
|
setTimeout(() => { content.classList.add("hidden") }, 300);
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
accordionSetup();
|
||||||
|
|
||||||
|
document.addEventListener("astro:after-swap", accordionSetup);
|
||||||
|
</script>
|
28
src/components/mdx/MDXLink.astro
Normal file
28
src/components/mdx/MDXLink.astro
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
import Icon from '../Icon.astro'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
href: string
|
||||||
|
class: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const p = Astro.props as Props;
|
||||||
|
|
||||||
|
let external = false;
|
||||||
|
|
||||||
|
if (p.href.includes('https://') || p.href.includes('http://')) {
|
||||||
|
external = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a href={p.href} class={p.class} target={external ? '_blank' : '_self'}>
|
||||||
|
<slot/>
|
||||||
|
{external ? (
|
||||||
|
<>
|
||||||
|
<Icon icon="FaExternalLink" class='w-2.5 inline-block align-super fill-crusta-800 fill:stroke-night-400' aria-hidden="true"/>
|
||||||
|
<span class="hidden">opens in a new tab</span>
|
||||||
|
</>
|
||||||
|
) : ''}
|
||||||
|
</a>
|
1
src/svg/FaExternalLink.svg
Normal file
1
src/svg/FaExternalLink.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l82.7 0L201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3l0 82.7c0 17.7 14.3 32 32 32s32-14.3 32-32l0-160c0-17.7-14.3-32-32-32L320 0zM80 32C35.8 32 0 67.8 0 112L0 432c0 44.2 35.8 80 80 80l320 0c44.2 0 80-35.8 80-80l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 112c0 8.8-7.2 16-16 16L80 448c-8.8 0-16-7.2-16-16l0-320c0-8.8 7.2-16 16-16l112 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L80 32z"/></svg>
|
After Width: | Height: | Size: 672 B |
Loading…
Add table
Reference in a new issue