Improved code block
This commit is contained in:
@@ -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">
|
||||||
|
|||||||
+54
-44
@@ -1,60 +1,70 @@
|
|||||||
import { motion, AnimatePresence } from "framer-motion";
|
"use client";
|
||||||
|
|
||||||
interface MorphTextProps {
|
import { BundledLanguage, codeToTokens } from "shiki";
|
||||||
text: string;
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
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;
|
|
||||||
counts[char] = (counts[char] || 0) + 1;
|
|
||||||
return { char: displayChar, id: `${char}-${counts[char]}` };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function MorphText({ text }: MorphTextProps) {
|
useEffect(() => {
|
||||||
const lines = text.split("\n"); // 👈 split by newline
|
async function run() {
|
||||||
|
const result = await codeToTokens(code, {
|
||||||
|
lang,
|
||||||
|
theme: "github-dark",
|
||||||
|
});
|
||||||
|
|
||||||
|
const rawLines = code.split("\n");
|
||||||
|
|
||||||
|
const fixed = rawLines.map((_, i) => {
|
||||||
|
return (
|
||||||
|
result.tokens[i] ?? [
|
||||||
|
{
|
||||||
|
content: "\n",
|
||||||
|
color: undefined,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
setLines(fixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
|
}, [code, lang]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col">
|
<pre className="text-sm">
|
||||||
<AnimatePresence mode="popLayout">
|
<code>
|
||||||
{lines.map((line, lineIndex) => {
|
<AnimatePresence mode="popLayout">
|
||||||
const tokens = tokenize(line);
|
{lines.map((line, lineIndex) => (
|
||||||
|
<div key={lineIndex} className="flex min-h-[1em]">
|
||||||
// 👇 empty line = real vertical space
|
{line.map((token, tokenIndex) => (
|
||||||
if (line === "") {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={lineIndex}
|
|
||||||
className="h-4" // adjust spacing as needed
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={lineIndex} className="flex flex-wrap">
|
|
||||||
{tokens.map(({ char, id }) => (
|
|
||||||
<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>
|
</code>
|
||||||
</div>
|
</pre>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user