From 66da3ebe77107805e2c4bc8913a0c4f78bbd1992 Mon Sep 17 00:00:00 2001 From: Anvesha Srivastava <207409304+Anvesha-Sri@users.noreply.github.com> Date: Sat, 13 Jun 2026 22:23:31 +0530 Subject: [PATCH 01/13] Create TypingSvgGenerator.tsx --- src/components/generator/TypingSvgGenerator.tsx | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/components/generator/TypingSvgGenerator.tsx diff --git a/src/components/generator/TypingSvgGenerator.tsx b/src/components/generator/TypingSvgGenerator.tsx new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/components/generator/TypingSvgGenerator.tsx @@ -0,0 +1 @@ + From 710abe0b2055a3b126e28503f18a534b233e8d2b Mon Sep 17 00:00:00 2001 From: Anvesha Srivastava <207409304+Anvesha-Sri@users.noreply.github.com> Date: Sat, 13 Jun 2026 22:25:49 +0530 Subject: [PATCH 02/13] Enhance TypingSvgGenerator functionality and UI Updated TypingSvgGenerator component to enhance functionality and improve user experience. Changes include the removal of unused imports, integration of sonner for toast notifications, and adjustments to the configuration settings. --- .../generator/TypingSvgGenerator.tsx | 542 ++++++++++++++++++ 1 file changed, 542 insertions(+) diff --git a/src/components/generator/TypingSvgGenerator.tsx b/src/components/generator/TypingSvgGenerator.tsx index 8b137891..52e3a99f 100644 --- a/src/components/generator/TypingSvgGenerator.tsx +++ b/src/components/generator/TypingSvgGenerator.tsx @@ -1 +1,543 @@ +import { useState, useCallback, useEffect } from "react"; // Removed 'React' import +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Slider } from "@/components/ui/slider"; +import { Switch } from "@/components/ui/switch"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { + Plus, + Trash2, + GripVertical, + Copy, + RefreshCw, + Eye, + // FileText removed - not being used +} from "lucide-react"; +import { toast } from "sonner"; // Changed from useToast to sonner toast +interface TypingLine { + id: string; + text: string; +} + +interface TypingSvgConfig { + lines: TypingLine[]; + color: string; + fontSize: number; + typingSpeed: number; + pauseDuration: number; + loop: boolean; + showCursor: boolean; + center: boolean; + width: number; + height: number; + fontFamily: string; +} + +const DEFAULT_CONFIG: TypingSvgConfig = { + lines: [ + { id: "1", text: "Front-End Developer" }, + { id: "2", text: "UI/UX Enthusiast" }, + { id: "3", text: "Open Source Contributor" }, + ], + color: "#4F46E5", + fontSize: 24, + typingSpeed: 100, + pauseDuration: 1500, + loop: true, + showCursor: true, + center: true, + width: 500, + height: 60, + fontFamily: "Fira Code, monospace", +}; + +const PRESET_COLORS = [ + "#4F46E5", "#EF4444", "#10B981", "#F59E0B", "#3B82F6", + "#EC4899", "#8B5CF6", "#06B6D4", "#6B7280", "#000000", +]; + +const FONT_FAMILIES = [ + { label: "Fira Code", value: "Fira Code, monospace" }, + { label: "Courier New", value: "Courier New, monospace" }, + { label: "Consolas", value: "Consolas, monospace" }, + { label: "Menlo", value: "Menlo, monospace" }, + { label: "SF Mono", value: "SF Mono, monospace" }, +]; + +const SPEED_PRESETS = { + "Very Slow": 200, + "Slow": 150, + "Medium": 100, + "Fast": 50, + "Very Fast": 25, +}; + +export function TypingSvgGenerator() { + const [config, setConfig] = useState(DEFAULT_CONFIG); + const [markdownCode, setMarkdownCode] = useState(""); + const [previewError, setPreviewError] = useState(false); + + const generateSvgUrl = useCallback(() => { + // Encode lines properly for URL + const linesParam = config.lines.map(line => encodeURIComponent(line.text)).join('\n'); + + // Build params for readme-typing-svg service + const params = new URLSearchParams({ + lines: linesParam, + color: config.color.replace('#', ''), + size: config.fontSize.toString(), + speed: config.typingSpeed.toString(), + pause: config.pauseDuration.toString(), + loop: config.loop ? "true" : "false", + cursor: config.showCursor ? "█" : "", + center: config.center ? "true" : "false", + width: config.width.toString(), + height: config.height.toString(), + font: config.fontFamily, + }); + + return `https://readme-typing-svg.demolab.com?${params.toString()}`; + }, [config]); + + const generateMarkdown = useCallback(() => { + const svgUrl = generateSvgUrl(); + const markdown = `[![Typing SVG](${svgUrl})](https://git.io/typing-svg)`; + setMarkdownCode(markdown); + return markdown; + }, [generateSvgUrl]); + + const addLine = () => { + const newLine = { + id: Date.now().toString(), + text: "New Line", + }; + setConfig((prev) => ({ + ...prev, + lines: [...prev.lines, newLine], + })); + }; + + const removeLine = (id: string) => { + if (config.lines.length <= 1) { + toast.error("Cannot remove", { + description: "You need at least one line of text", + }); + return; + } + setConfig((prev) => ({ + ...prev, + lines: prev.lines.filter((line) => line.id !== id), + })); + }; + + const updateLineText = (id: string, text: string) => { + setConfig((prev) => ({ + ...prev, + lines: prev.lines.map((line) => + line.id === id ? { ...line, text } : line + ), + })); + }; + + const moveLineUp = (index: number) => { + if (index === 0) return; + const newLines = [...config.lines]; + [newLines[index], newLines[index - 1]] = [newLines[index - 1], newLines[index]]; + setConfig({ ...config, lines: newLines }); + }; + + const moveLineDown = (index: number) => { + if (index === config.lines.length - 1) return; + const newLines = [...config.lines]; + [newLines[index], newLines[index + 1]] = [newLines[index + 1], newLines[index]]; + setConfig({ ...config, lines: newLines }); + }; + + const copyToClipboard = async () => { + try { + await navigator.clipboard.writeText(markdownCode); + toast.success("Copied!", { + description: "Markdown code copied to clipboard", + }); + } catch (err) { + toast.error("Error", { + description: "Failed to copy to clipboard", + }); + } + }; + + const resetToDefault = () => { + setConfig(DEFAULT_CONFIG); + toast.success("Reset", { + description: "Settings reset to default", + }); + }; + + useEffect(() => { + generateMarkdown(); + setPreviewError(false); + }, [config, generateMarkdown]); + + // Handle preview image error + const handlePreviewError = () => { + setPreviewError(true); + }; + + return ( +
+
+

Typing SVG Generator

+

+ Create animated typing SVGs for your GitHub README profile with live preview +

+
+ +
+ {/* Left Panel - Configuration */} +
+ {/* Text Lines Section */} + + + + Text Lines + + + + Add, remove, or reorder the lines to be typed + + + +
+ {config.lines.map((line, index) => ( +
+ + updateLineText(line.id, e.target.value)} + placeholder="Enter text..." + className="flex-1" + /> +
+ + + +
+
+ ))} +
+
+
+ + {/* Typography Section */} + + + Typography + Customize text appearance + + +
+ +
+ {PRESET_COLORS.map((color) => ( +
+
+ +
+ + setConfig({ ...config, fontSize: value })} + min={12} + max={48} + step={1} + className="mt-2" + /> +
+ +
+ + +
+
+
+ + {/* Animation Settings Section */} + + + Animation Settings + Control the typing animation behavior + + +
+ + +
+ setConfig({ ...config, typingSpeed: value })} + min={20} + max={200} + step={5} + /> +
+
+ +
+ + setConfig({ ...config, pauseDuration: value })} + min={500} + max={5000} + step={100} + className="mt-2" + /> +
+ +
+ + setConfig({ ...config, loop: checked })} + /> +
+ +
+ + setConfig({ ...config, showCursor: checked })} + /> +
+ +
+ + setConfig({ ...config, center: checked })} + /> +
+
+
+ + {/* Dimensions Section */} + + + Dimensions + Adjust the SVG canvas size + + +
+ + setConfig({ ...config, width: value })} + min={300} + max={800} + step={10} + className="mt-2" + /> +
+
+ + setConfig({ ...config, height: value })} + min={30} + max={150} + step={5} + className="mt-2" + /> +
+
+
+
+ + {/* Right Panel - Preview & Code */} +
+ {/* Live Preview */} + + + + Live Preview +
+ + +
+
+ See your typing SVG in action +
+ +
+ {previewError ? ( +
+ +

Preview temporarily unavailable

+

Try adjusting the settings

+
+ ) : ( + Typing SVG Preview + )} +
+
+
+ + {/* Markdown Code */} + + + + Markdown Code + + + + Copy this code and paste it into your GitHub README + + + +
+                
+                  {markdownCode}
+                
+              
+
+
+ + {/* Tips Section */} + + + Quick Tips + + +
    +
  • + + Add multiple lines to create a typing animation sequence +
  • +
  • + + Use the up/down arrows to reorder the animation sequence +
  • +
  • + + Adjust typing speed to control the animation tempo +
  • +
  • + + Enable loop for continuous animation +
  • +
  • + + Preview updates automatically as you make changes +
  • +
+
+
+
+
+
+ ); +} From c558acb4e137e4b108484ec8902ada9165582d0f Mon Sep 17 00:00:00 2001 From: Anvesha Srivastava <207409304+Anvesha-Sri@users.noreply.github.com> Date: Sat, 13 Jun 2026 22:30:15 +0530 Subject: [PATCH 03/13] Add TypingSvgGeneratorPage component --- src/pages/TypingSvgGeneratorPage.tsx | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/pages/TypingSvgGeneratorPage.tsx diff --git a/src/pages/TypingSvgGeneratorPage.tsx b/src/pages/TypingSvgGeneratorPage.tsx new file mode 100644 index 00000000..98c19f1a --- /dev/null +++ b/src/pages/TypingSvgGeneratorPage.tsx @@ -0,0 +1,7 @@ +import { TypingSvgGenerator } from "@/components/generator/TypingSvgGenerator"; + +export default function TypingSvgGeneratorPage() { + return ( + + ); +} From c7b954e64ec73b868f9b72bcc75329cc1dcd1937 Mon Sep 17 00:00:00 2001 From: Anvesha Srivastava <207409304+Anvesha-Sri@users.noreply.github.com> Date: Sat, 13 Jun 2026 22:35:40 +0530 Subject: [PATCH 04/13] Add TypingSvgGeneratorPage route to App component --- src/App.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 2cacbef9..9e2cc50c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -22,6 +22,8 @@ import MarkdownEditor from "./pages/MarkdownEditor"; import Cursortrail from "./Cursortrail"; import { HistoryProvider } from "./contexts/HistoryContext"; +import TypingSvgGeneratorPage from "./pages/TypingSvgGeneratorPage"; + const queryClient = new QueryClient(); // Placeholder components for missing routes to prevent app crash @@ -59,7 +61,8 @@ export default function App() { } /> } /> } /> - + + } /> } /> } /> @@ -77,4 +80,4 @@ export default function App() { ); -}; \ No newline at end of file +}; From c10b8b418adb4985bfcc2810e010df15ba5f725c Mon Sep 17 00:00:00 2001 From: Anvesha Srivastava <207409304+Anvesha-Sri@users.noreply.github.com> Date: Sat, 13 Jun 2026 22:57:04 +0530 Subject: [PATCH 05/13] Update Sidebar.tsx --- src/components/Sidebar.tsx | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 065bd333..0d08c240 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -1,13 +1,33 @@ import { cn } from '@/lib/utils'; import { sidebarCategories } from "../data/sidebarCategories"; +import { useNavigate } from 'react-router-dom'; interface SidebarProps { selectedCategory: string; onCategorySelect: (category: string) => void; } +const categoryPaths: Record = { + home: '/', + elements: '/elements', + templates: '/templates', + projects: '/projects', + about: '/about', + 'readme-editor': '/readme-editor', + 'markdown-editor': '/markdown-editor', + 'ai-editor': '/ai-editor-intro', + 'typing-svg': '/typing-svg', +}; + +const Sidebar = ({ selectedCategory, onCategorySelect }: SidebarProps) => { +const navigate = useNavigate(); -const Sidebar = ({ selectedCategory, onCategorySelect }: SidebarProps) => { + const handleCategoryClick = (categoryId: string) => { + onCategorySelect(categoryId); + const path = categoryPaths[categoryId] || '/'; + navigate(path); + }; + return (