diff --git a/components/ui/animated-circular-progress-bar.tsx b/components/ui/animated-circular-progress-bar.tsx deleted file mode 100644 index 246b2d901..000000000 --- a/components/ui/animated-circular-progress-bar.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { cn } from "@/lib/utils"; - -interface AnimatedCircularProgressBarProps { - max?: number; - min?: number; - value: number; - gaugePrimaryColor: string; - gaugeSecondaryColor: string; - className?: string; - hideText?: boolean; -} - -export function AnimatedCircularProgressBar({ - max = 100, - min = 0, - value = 0, - gaugePrimaryColor, - gaugeSecondaryColor, - hideText = false, - className, -}: AnimatedCircularProgressBarProps) { - const circumference = 2 * Math.PI * 45; - const percentPx = circumference / 100; - const currentPercent = Math.round(((value - min) / (max - min)) * 100); - - return ( -
- - {currentPercent <= 90 && currentPercent >= 0 && ( - - )} - - - {!hideText && ( - - {currentPercent}% - - )} -
- ); -} diff --git a/components/ui/word-rotate.tsx b/components/ui/word-rotate.tsx deleted file mode 100644 index 1e9b4baa7..000000000 --- a/components/ui/word-rotate.tsx +++ /dev/null @@ -1,52 +0,0 @@ -"use client"; - -import { AnimatePresence, motion, MotionProps } from "motion/react"; -import { memo, useEffect, useState, ReactNode } from "react"; - -import { cn } from "@/lib/utils"; - -interface WordRotateProps { - words: ReactNode[]; - duration?: number; - motionProps?: MotionProps; - className?: string; -} - -function WordRotate({ - words, - duration = 2500, - motionProps = { - initial: { opacity: 0, y: -50 }, - animate: { opacity: 1, y: 0 }, - exit: { opacity: 0, y: 50 }, - transition: { duration: 0.25, ease: "easeOut" }, - }, - className, -}: WordRotateProps) { - const [index, setIndex] = useState(0); - - useEffect(() => { - // Simple, consistent interval - no complex calculations - const interval = setInterval(() => { - setIndex((prevIndex) => (prevIndex + 1) % words.length); - }, duration); - - return () => clearInterval(interval); - }, [words.length, duration]); // Only depend on length and duration - - return ( - - - - {words[index]} - - - - ); -} - -export default memo(WordRotate); diff --git a/components/ui/word-typewriter.tsx b/components/ui/word-typewriter.tsx deleted file mode 100644 index ab134b004..000000000 --- a/components/ui/word-typewriter.tsx +++ /dev/null @@ -1,124 +0,0 @@ -"use client"; - -import { useEffect, useState, ReactNode } from "react"; -import { cn } from "@/lib/utils"; - -interface WordTypewriterProps { - words: ReactNode[]; - duration?: number; - typingSpeed?: number; - className?: string; -} - -function WordTypewriter({ - words, - duration = 3000, - typingSpeed = 50, - className, -}: WordTypewriterProps) { - const [currentWordIndex, setCurrentWordIndex] = useState(0); - const [currentText, setCurrentText] = useState(""); - const [isDeleting, setIsDeleting] = useState(false); - const [showCursor, setShowCursor] = useState(true); - - useEffect(() => { - const currentWord = words[currentWordIndex]; - - // Extract text content from ReactNode for typing effect - const getTextFromNode = (node: ReactNode): string => { - if (typeof node === 'string') return node; - if (typeof node === 'number') return node.toString(); - if (!node) return ''; - - // For components with children (like our wordComponent spans) - if (typeof node === 'object' && 'props' in node && node.props.children) { - const children = node.props.children; - if (Array.isArray(children)) { - return children - .filter(child => typeof child === 'string') - .join(''); - } - if (typeof children === 'string') return children; - } - - return ''; - }; - - const fullText = getTextFromNode(currentWord); - - const timer = setTimeout(() => { - if (!isDeleting) { - // Typing - if (currentText.length < fullText.length) { - setCurrentText(fullText.slice(0, currentText.length + 1)); - } else { - // Pause before deleting - setTimeout(() => setIsDeleting(true), duration); - } - } else { - // Deleting - if (currentText.length > 0) { - setCurrentText(currentText.slice(0, -1)); - } else { - setIsDeleting(false); - setCurrentWordIndex((prev) => (prev + 1) % words.length); - } - } - }, isDeleting ? typingSpeed / 2 : typingSpeed); - - return () => clearTimeout(timer); - }, [currentText, currentWordIndex, isDeleting, words, typingSpeed, duration]); - - // Cursor blink effect - useEffect(() => { - const cursorTimer = setInterval(() => { - setShowCursor(prev => !prev); - }, 500); - - return () => clearInterval(cursorTimer); - }, []); - - // Get the original ReactNode with icons - const currentWord = words[currentWordIndex]; - - // Check if the current word has an icon - const hasIcon = typeof currentWord === 'object' && - currentWord !== null && - 'props' in currentWord && - currentWord.props.children && - Array.isArray(currentWord.props.children) && - currentWord.props.children.length > 1; - - return ( - - {hasIcon && typeof currentWord === 'object' && 'props' in currentWord ? ( - <> - {/* Show icon immediately - already wrapped in consistent container */} - {currentWord.props.children[0]} - {/* Type out the text */} - - {currentText} - - - - ) : ( - - {currentText} - - - )} - - ); -} - -export default WordTypewriter; diff --git a/lib/utils/base64Polyfill.ts b/lib/utils/base64Polyfill.ts deleted file mode 100644 index 09f9b2ee3..000000000 --- a/lib/utils/base64Polyfill.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Ensures base64 polyfills are available for environments that don't have them natively - * (like Node.js server-side rendering contexts) - */ -export function ensureBase64Polyfills(): void { - if (typeof globalThis.atob === "undefined") { - globalThis.atob = (data: string) => Buffer.from(data, "base64").toString("binary"); - } - - if (typeof globalThis.btoa === "undefined") { - globalThis.btoa = (data: string) => Buffer.from(data, "binary").toString("base64"); - } -} diff --git a/lib/utils/download-mermaid-chart.ts b/lib/utils/download-mermaid-chart.ts deleted file mode 100644 index d4ddc191f..000000000 --- a/lib/utils/download-mermaid-chart.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { RefObject } from "react"; - -const handleDownload = ({ containerRef }: { containerRef: RefObject }) => { - if (!containerRef.current) return; - - const svgElement = containerRef.current.querySelector('svg'); - if (!svgElement) { - console.error('Could not find SVG element to download.'); - return; - } - - // Serialize the SVG - const serializer = new XMLSerializer(); - let svgString = serializer.serializeToString(svgElement); - - // Add XML declaration and potentially namespace if missing - if (!svgString.startsWith('\n' + svgString; - } - if (!svgString.includes('xmlns="http://www.w3.org/2000/svg"')) { - svgString = svgString.replace(' { - try { - if (short) { - return formatDistanceToNow(new Date(timestamp), { addSuffix: true }); - } - return `${formatDistanceToNow(new Date(timestamp), { addSuffix: true })} (${format(new Date(timestamp), "PPP")})`; - } catch { - return "Recently"; - } -}; - -export default formatTimestamp; \ No newline at end of file diff --git a/lib/utils/normalizeContent.ts b/lib/utils/normalizeContent.ts deleted file mode 100644 index 9deb88e77..000000000 --- a/lib/utils/normalizeContent.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Normalizes content for comparison by handling whitespace, line endings, Unicode, and case. - * - * This ensures that minor formatting differences don't cause false verification failures - * when comparing file content. - * - * @param content - The content string to normalize - * @returns Normalized content string - */ -export function normalizeContent(content: string): string { - return content - .trim() // Remove leading/trailing whitespace - .replace(/\r\n/g, "\n") // Normalize line endings (Windows → Unix) - .replace(/\r/g, "\n") // Normalize old Mac line endings - .replace(/\n+$/g, "\n") // Normalize trailing newlines to single newline - .replace(/[ \t]+$/gm, "") // Remove trailing spaces/tabs from each line - .normalize("NFC"); // Normalize Unicode characters (e.g., é) -} diff --git a/lib/utils/normalizeProfileUrl.ts b/lib/utils/normalizeProfileUrl.ts deleted file mode 100644 index 25f4d946d..000000000 --- a/lib/utils/normalizeProfileUrl.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Normalizes a profile URL to match DB and trigger logic -// Removes protocol, leading www., trailing slashes, and lowercases -export default function normalizeProfileUrl(url: string): string { - if (!url) return ""; - let result = url.trim(); - result = result.replace(/^https?:\/\//i, ""); - result = result.replace(/^www\./i, ""); - result = result.replace(/\/+$/, ""); - return result.toLowerCase(); -}