diff --git a/src/app/(home)/page.tsx b/src/app/(home)/page.tsx index 65bb548..6e01b76 100644 --- a/src/app/(home)/page.tsx +++ b/src/app/(home)/page.tsx @@ -1,8 +1,7 @@ "use client"; -import MorphText from "@/components/Morph"; -import { Card } from "fumadocs-ui/components/card"; -import { BookOpenIcon, NewspaperIcon, RocketIcon } from "lucide-react"; +import MorphCode from "@/components/Morph"; +import { NewspaperIcon, RocketIcon } from "lucide-react"; import Link from "next/link"; import { useEffect, useRef, useState } from "react"; @@ -152,11 +151,9 @@ export default function HomePage() { return (
- - - - - +
+ +
diff --git a/src/components/Morph.tsx b/src/components/Morph.tsx index 95e7f1f..788ba5d 100644 --- a/src/components/Morph.tsx +++ b/src/components/Morph.tsx @@ -1,60 +1,70 @@ -import { motion, AnimatePresence } from "framer-motion"; +"use client"; -interface MorphTextProps { - text: string; +import { BundledLanguage, codeToTokens } from "shiki"; +import { motion, AnimatePresence } from "framer-motion"; +import { useEffect, useState } from "react"; + +interface Props { + code: string; + lang?: BundledLanguage; } -const tokenize = (str: string) => { - const counts: Record = {}; - 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 MorphCode({ code, lang = "rust" }: Props) { + const [lines, setLines] = useState([]); -export default function MorphText({ text }: MorphTextProps) { - const lines = text.split("\n"); // 👈 split by newline + useEffect(() => { + 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 ( -
- - {lines.map((line, lineIndex) => { - const tokens = tokenize(line); - - // 👇 empty line = real vertical space - if (line === "") { - return ( -
- ); - } - - return ( -
- {tokens.map(({ char, id }) => ( +
+      
+        
+          {lines.map((line, lineIndex) => (
+            
+ {line.map((token, tokenIndex) => ( - {char} + {token.content} ))}
- ); - })} -
-
+ ))} + + + ); }