Projekt-Tagebuch Blog, Tag 37


coden
Rustikaler, tropischer Arbeitsplatz mit einem Laptop auf einem Holztisch, daneben eine Hängematte.
Daniel Kaser|26. Juni 2024
3 min.
Mittwoch, 26. Juni 2024

Wochen-Ziele:

  • Blog-Projekt-Tagebuch (Mai) in den Blog uploaden

Tages-Ziele:


MDX-Accordion

Als Erstes hab ich mich heute an die Accordion-Komponente fürs MDX gemacht. Accordion ist quasi eine Art Dropdown-Menü im Text, wo man weiteren Text hinter einer Überschrift verstecken kann. Beim Klick auf diese Überschrift wird der versteckte Text sichtbar.

Das bietet sich an für die Code-Challenge-Lösungen auf dem Blog. So sieht der gemeine lösende Leser die Lösungen erst, wenn er auf sie klickt und werden nicht schon vorher gespoilert.

Mit HTML kann man so eine simple Form eines Accordions relativ leicht mit <details> und <summary> zaubern:

<details>
  <summary>Wo bist denn du?</summary>
  Hier!
</details>

Da ich möglichst wenig HTML in meine MDX-Dateien schreiben möchte, habe ich dafür eine Accordion-Komponente gebaut. So wird das erste Child automatisch als summary verwendet und der Rest als (versteckter) Content und ich brauche nicht mehr 2 Tags, sondern nur noch einen.

<Accordion>
Na wo denn?!!

Na hier!!

</Accordion>

Hier muss man darauf achten, dass man die leeren Zeilen nicht vergisst. Denn diese machen in Markdown aus einer befüllten Zeile darüber ein <p>-Element und damit ein neues Child.

Hier meine Accordion-Komponente:

// src/components/Accordion.tsx
type Props = {
  className?: string;
  summary: React.ReactNode;
  content: React.ReactNode;
};

export function Accordion({ className = "", summary, content }: Props) {
  return (
    <details className={`mb-1 ${className}`}>
      <summary className="bg-danger/5 hover:cursor-pointer hover:bg-danger/10 dark:bg-danger/15 dark:hover:bg-danger/20">
        {summary}
      </summary>
      {content}
    </details>
  );
}

Und so mappe isch dat Janze in der CustomStyledMDX:

// src/components/CustomStyledMDX.tsx
// ...
  Accordion: (props) => {
    const { children, ...restProps } = props;
    // extract the first line/children to be the summary
    const [firstParagraph, ...content] = children;
    const summary = firstParagraph.props.children;

    return (
      <Accordion {...restProps} summary={summary} content={content}></Accordion>
    );
  },
// ...

Eine gerenderte Accordion-Komponente in Action findest du auch unten unter Feedback

Syntax Highlighting

Als nächstes war endlich das Syntax-Highlighting dran. D.h., Code-Schnipsel sind jetzt schön bunt, wie im Code-Editor.

rehype-highlight und hightlight-js installieren

Dafür hab ich die Packages rehype-highlight und highlight-js installiert. Die wollten aber nicht so richtig harmonieren. Vor allem nicht mit den bereits installierten Packages remark-gfm und next-mdx-remote.

Das Problem war hier, dass all diese Packages unterschiedliche Versionen von vfile verwendeten. Die Lösung war hier remark-gfm auf Version 4.0.0 upzudaten und next-mdx-remote auf Version 5.0.0.

Allerdings kann ich mich erinnern, dass ich diese beiden Packages bewusst bisher nicht auf die aktuellste Version upgedated hatte, weil es an anderer Stelle ein Problem mit den neuen Versionen gab. Ich weiß nur nicht mehr wo - dammit...

Bisher läuft alles rund, aber ich rechne mit einer bösen Überraschung...

NACHTRAG AUS DER ZUKUNFT
Läuft immernoch alles rund! (Stand: August 2024)

Styles einfügen

Dann hab ich mir ein Style-Paket ausgesucht. Hier kann man sich durch einen Haufen vorgestylter Presets durchwühlen. Wenn man sich dann für eins entschieden hat, kann man es auf GitHub downloaden. Ich habe mich erst mal für github-dark entschieden.

Dann musste ich die Datei nur noch in meinem /styles-Verzeichnis unterbringen und in die dynamische (Single) BlogPage importieren.

// src/app/blog/[slug]/page.tsx
import "@/styles/highlight-js/github-dark.css";
// ...

Zack. Nu hab ich bunte Code-Schnipsel!

Feedback

Schreib mir!