Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions app/components/modules/CodeBlock.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
"use client";
import { useState } from "react";
import { FaCopy, FaCheck, FaCode } from "react-icons/fa";
import { motion, AnimatePresence } from "framer-motion";
import hljs from "highlight.js";
import "highlight.js/styles/github.css";
import "highlight.js/styles/github-dark.css";

const LANGUAGE_NAMES = {
javascript: "JavaScript",
python: "Python",
java: "Java",
c: "C",
cpp: "C++",
};

export const highlightCode = (code, language) => {
const validLanguage = hljs.getLanguage(language) ? language : "plaintext";
return hljs.highlight(code, { language: validLanguage }).value;
};

const CodeBlock = ({ title, codeExamples }) => {
const languageIds = Object.keys(codeExamples);
const [selectedLanguage, setSelectedLanguage] = useState(languageIds[0]);
const [copied, setCopied] = useState(false);
const [isHovered, setIsHovered] = useState(false);

const copyToClipboard = async (text) => {
try {
await navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (err) {
console.error("Failed to copy text: ", err);
}
};

return (
<div
className="max-w-4xl mx-auto"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
className="bg-white dark:bg-gray-800 rounded-xl shadow-lg overflow-hidden border border-gray-200 dark:border-gray-700 transition-colors duration-300"
>
{/* Header */}
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center p-4 bg-gray-50 dark:bg-gray-700/50 border-b border-gray-200 dark:border-gray-700">
<div className="flex items-center mb-2 sm:mb-0">
<FaCode className="text-blue-500 mr-2 text-lg" />
<h3 className="text-lg font-semibold text-gray-800 dark:text-white">
{title}
</h3>
</div>

<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={() => copyToClipboard(codeExamples[selectedLanguage])}
className="flex items-center gap-2 px-3 py-1.5 bg-gray-100 dark:bg-gray-600 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-500 transition-colors text-gray-800 dark:text-gray-100 text-sm font-medium"
aria-label="Copy code"
>
<AnimatePresence mode="wait">
{copied ? (
<motion.span
key="check"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="flex items-center text-green-600 dark:text-green-400"
>
<FaCheck className="mr-1" /> Copied
</motion.span>
) : (
<motion.span
key="copy"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="flex items-center"
>
<FaCopy className="mr-1" /> Copy Code
</motion.span>
)}
</AnimatePresence>
</motion.button>
</div>

{/* Language Selector */}
<div className="px-4 pt-3 pb-2 flex flex-wrap gap-2 border-b border-gray-200 dark:border-gray-700">
{languageIds.map((id) => (
<motion.button
key={id}
whileHover={{ scale: 1.03 }}
whileTap={{ scale: 0.97 }}
onClick={() => setSelectedLanguage(id)}
className={`px-3 py-1.5 rounded-lg text-sm font-medium transition-colors ${
selectedLanguage === id
? "bg-blue-500 text-white shadow-md"
: "bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-600"
}`}
>
{LANGUAGE_NAMES[id] || id}
</motion.button>
))}
</div>

{/* Code Block */}
<div className="relative">
<AnimatePresence mode="wait">
<motion.div
key={selectedLanguage}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
className="overflow-x-auto p-4 bg-gray-900 text-white"
>
<pre className="text-sm leading-relaxed">
<code
className={`language-${selectedLanguage}`}
dangerouslySetInnerHTML={{
__html: highlightCode(
codeExamples[selectedLanguage],
selectedLanguage
),
}}
/>
</pre>
</motion.div>
</AnimatePresence>

{/* Language indicator (shown on hover) */}
<AnimatePresence>
{isHovered && (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 10 }}
className="absolute bottom-3 right-3 px-2 py-1 bg-gray-800 text-gray-300 text-xs rounded-md"
>
{selectedLanguage.toUpperCase()}
</motion.div>
)}
</AnimatePresence>
</div>
</motion.div>
</div>
);
};

export default CodeBlock;
41 changes: 1 addition & 40 deletions app/visualizer/linkedList/operations/comparison/animation.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
"use client";
import React, { useState, useRef, useEffect } from 'react';
import { gsap } from 'gsap';
import Footer from '@/app/components/footer';
import ExploreOther from '@/app/components/ui/exploreOther';
import Content from "@/app/visualizer/linkedList/operations/comparison/content";
import Quiz from '@/app/visualizer/linkedList/operations/comparison/quiz';
import CodeBlock from "@/app/visualizer/linkedList/operations/comparison/codeBlock";
import BackToTop from '@/app/components/ui/backtotop';
import GoBackButton from "@/app/components/ui/goback";

const LinkedListComparison = () => {
const [list1, setList1] = useState([]);
Expand Down Expand Up @@ -111,17 +104,7 @@ const LinkedListComparison = () => {
}, [list1, list2]);

return (
<div className="min-h-screen bg-gray-100 dark:bg-zinc-950 text-gray-800 dark:text-gray-200 flex flex-col">
<main className="container mx-auto px-2 sm:px-6 pt-16 pb-4 flex-1">
<div className="mt-8 sm:mt-10">
<GoBackButton />
</div>

<h1 className="text-3xl sm:text-4xl mt-6 ml-2 sm:ml-10 font-bold text-left text-gray-900 dark:text-white mb-0">
Linked List Comparison
</h1>
<div className="bg-black dark:bg-gray-600 w-full h-[2px] rounded-xl mt-2 mb-5"></div>
<Content />
<div className="container mx-auto px-2 sm:px-6 pb-4">
<p className="text-base sm:text-lg text-center text-gray-600 dark:text-gray-400 mb-8">
Visualize comparison of two linked lists node by node
</p>
Expand Down Expand Up @@ -273,28 +256,6 @@ const LinkedListComparison = () => {
</div>
</div>
</div>

<p className="text-lg text-center text-gray-600 dark:text-gray-400 mt-8 mb-8">
Test Your Knowledge Before Moving Forward!
</p>
<Quiz />

<CodeBlock />

<ExploreOther
title="Explore Other Operations"
links={[
{ text: "Insertion", url: "./insertion" },
{ text: "Deletion", url: "./deletion" },
{ text: "Traversal", url: "./traversal" },
{ text: "Merging", url: "./merge" },
{ text: "Searching", url: "./search" },
{ text: "Reverse", url: "./reverse" },
]}
/>
</main>
<BackToTop />
<Footer />
</div>
);
};
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

159 changes: 0 additions & 159 deletions app/visualizer/linkedList/operations/comparison/codeBlock.jsx

This file was deleted.

Loading
Loading