Improved code block

This commit is contained in:
2026-05-11 07:32:16 +02:00
parent ee0b8100ad
commit b8c7b6e3ea
2 changed files with 59 additions and 52 deletions
+5 -8
View File
@@ -1,8 +1,7 @@
"use client"; "use client";
import MorphText from "@/components/Morph"; import MorphCode from "@/components/Morph";
import { Card } from "fumadocs-ui/components/card"; import { NewspaperIcon, RocketIcon } from "lucide-react";
import { BookOpenIcon, NewspaperIcon, RocketIcon } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
@@ -152,11 +151,9 @@ export default function HomePage() {
return ( return (
<div className="flex w-full flex-col md:flex-row"> <div className="flex w-full flex-col md:flex-row">
<div className="order-1 md:order-2 w-full md:w-[40vw] md:h-svh sticky top-20 md:top-0 flex items-center justify-center z-10 bg-background pb-4 md:pb-0"> <div className="order-1 md:order-2 w-full md:w-[40vw] md:h-svh sticky top-20 md:top-0 flex items-center justify-center z-10 bg-background pb-4 md:pb-0">
<Card className="w-full max-w-md h-auto md:h-100" title> <div className="w-max h-auto border border-fd-border p-5 rounded-xl min-h-24">
<code className="whitespace-pre-wrap"> <MorphCode code={currentText} />
<MorphText text={currentText} /> </div>
</code>
</Card>
</div> </div>
<div className="flex-1 order-2 md:order-1"> <div className="flex-1 order-2 md:order-1">
+47 -37
View File
@@ -1,60 +1,70 @@
"use client";
import { BundledLanguage, codeToTokens } from "shiki";
import { motion, AnimatePresence } from "framer-motion"; import { motion, AnimatePresence } from "framer-motion";
import { useEffect, useState } from "react";
interface MorphTextProps { interface Props {
text: string; code: string;
lang?: BundledLanguage;
} }
const tokenize = (str: string) => { export default function MorphCode({ code, lang = "rust" }: Props) {
const counts: Record<string, number> = {}; const [lines, setLines] = useState<any[][]>([]);
return str.split("").map((char) => {
const displayChar = char === " " ? "\u00A0" : char; useEffect(() => {
counts[char] = (counts[char] || 0) + 1; async function run() {
return { char: displayChar, id: `${char}-${counts[char]}` }; const result = await codeToTokens(code, {
lang,
theme: "github-dark",
}); });
};
export default function MorphText({ text }: MorphTextProps) { const rawLines = code.split("\n");
const lines = text.split("\n"); // 👈 split by newline
const fixed = rawLines.map((_, i) => {
return ( return (
<div className="flex flex-col"> result.tokens[i] ?? [
<AnimatePresence mode="popLayout"> {
{lines.map((line, lineIndex) => { content: "\n",
const tokens = tokenize(line); color: undefined,
},
// 👇 empty line = real vertical space ]
if (line === "") {
return (
<div
key={lineIndex}
className="h-4" // adjust spacing as needed
/>
); );
});
setLines(fixed);
} }
run();
}, [code, lang]);
return ( return (
<div key={lineIndex} className="flex flex-wrap"> <pre className="text-sm">
{tokens.map(({ char, id }) => ( <code>
<AnimatePresence mode="popLayout">
{lines.map((line, lineIndex) => (
<div key={lineIndex} className="flex min-h-[1em]">
{line.map((token, tokenIndex) => (
<motion.span <motion.span
key={`${lineIndex}-${id}`} key={`${lineIndex}-${tokenIndex}`}
layoutId={`${lineIndex}-${id}`} layoutId={`${lineIndex}-${tokenIndex}`}
layout layout
initial={{ opacity: 0, y: 10 }} initial={{ opacity: 0, y: 6 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }} exit={{ opacity: 0, y: -6 }}
transition={{ transition={{ duration: 0.35 }}
type: "keyframes", style={{
duration: 0.6, color: token.color,
whiteSpace: "pre",
}} }}
className="inline-block"
> >
{char} {token.content}
</motion.span> </motion.span>
))} ))}
</div> </div>
); ))}
})}
</AnimatePresence> </AnimatePresence>
</div> </code>
</pre>
); );
} }