origin
This commit is contained in:
		
							
								
								
									
										43
									
								
								src/components/GlitchyLink.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/components/GlitchyLink.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| import React, { useState } from 'react'; | ||||
|  | ||||
| interface GlitchyLinkProps { | ||||
|     text: string; | ||||
|     url: string; | ||||
|     type?: 'email' | 'link'; | ||||
| } | ||||
|  | ||||
| const GlitchyLink: React.FC<GlitchyLinkProps> = ({ text, url, type = 'link' }) => { | ||||
|     const [copied, setCopied] = useState(false); | ||||
|  | ||||
|     const handleClick = async (e: React.MouseEvent) => { | ||||
|         if (type === 'email') { | ||||
|             e.preventDefault(); | ||||
|             if (copied) return; | ||||
|             await navigator.clipboard.writeText(text); | ||||
|             setCopied(true); | ||||
|             setTimeout(() => setCopied(false), 2000); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     return ( | ||||
|         <a | ||||
|             href={url} | ||||
|             target="_blank" | ||||
|             rel="noopener noreferrer" | ||||
|             onClick={handleClick} | ||||
|             className="group relative inline-block hover:text-green-400 transition-colors" | ||||
|         > | ||||
|             <span className="relative inline-block animate-glitch-1"> | ||||
|                 {copied ? 'Copied!' : text} | ||||
|             </span> | ||||
|             <span className="absolute top-0 left-0 w-full h-full opacity-0 group-hover:opacity-70 group-hover:animate-glitch-1"> | ||||
|                 {copied ? 'Copied!' : text} | ||||
|             </span> | ||||
|             <span className="absolute top-0 left-0 w-full h-full opacity-0 group-hover:opacity-70 group-hover:animate-glitch-2"> | ||||
|                 {copied ? 'Copied!' : text} | ||||
|             </span> | ||||
|         </a> | ||||
|     ); | ||||
| }; | ||||
|  | ||||
| export default GlitchyLink; | ||||
							
								
								
									
										60
									
								
								src/components/ProfileContent.tsx
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										60
									
								
								src/components/ProfileContent.tsx
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| import React from 'react'; | ||||
| import { Mail, Github, Linkedin, User, Code, BookOpen, Building, MapPin } from 'lucide-react'; | ||||
| import GlitchyLink from './GlitchyLink'; | ||||
|  | ||||
| const ProfileContent: React.FC = () => { | ||||
|   return ( | ||||
|     <div className="flex-1 overflow-auto"> | ||||
|       <div className="space-y-8"> | ||||
|         <div className="flex items-center gap-2"> | ||||
|           <User className="w-6 h-6" /> | ||||
|           <h2 className="text-2xl font-bold">José Henrique Ivanchechen</h2> | ||||
|         </div> | ||||
|  | ||||
|         <div className="flex items-center gap-2"> | ||||
|           <Code className="w-6 h-6" /> | ||||
|           <p className="text-lg">Software Engineer</p> | ||||
|         </div> | ||||
|  | ||||
|         <div className="flex items-center gap-2"> | ||||
|           <Building className="w-6 h-6" /> | ||||
|           <p className="text-lg">EposNow</p> | ||||
|         </div> | ||||
|  | ||||
|         <div className="flex items-center gap-2"> | ||||
|           <MapPin className="w-6 h-6" /> | ||||
|           <p className="text-lg">Curitiba, PR - Brazil</p> | ||||
|         </div> | ||||
|  | ||||
|         <div className="flex items-center gap-2"> | ||||
|           <BookOpen className="w-6 h-6" /> | ||||
|           <p className="text-lg">5+ Years Experience</p> | ||||
|         </div> | ||||
|  | ||||
|         <div className="mt-12 space-y-6"> | ||||
|           <h3 className="text-xl font-semibold">> Contact Info:</h3> | ||||
|           <div className="space-y-4 pl-6"> | ||||
|             <div className="flex items-center gap-3"> | ||||
|               <Mail className="w-5 h-5" /> | ||||
|               <GlitchyLink | ||||
|                 text="jose.henrique.ivan@gmail.com" | ||||
|                 url="mailto:jose.henrique.ivan@gmail.com" | ||||
|                 type="email" | ||||
|               /> | ||||
|             </div> | ||||
|             <div className="flex items-center gap-3"> | ||||
|               <Github className="w-5 h-5" /> | ||||
|               <GlitchyLink text="@ivanch" url="https://github.com/ivanch" /> | ||||
|             </div> | ||||
|             <div className="flex items-center gap-3"> | ||||
|               <Linkedin className="w-5 h-5" /> | ||||
|               <GlitchyLink text="/in/joseivanch" url="https://linkedin.com/in/joseivanch" /> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| export default ProfileContent; | ||||
							
								
								
									
										46
									
								
								src/components/ProjectsContent.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/components/ProjectsContent.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| import React from 'react'; | ||||
| import ReactMarkdown from 'react-markdown'; | ||||
| import remarkGfm from 'remark-gfm'; | ||||
| import { FileWarning } from 'lucide-react'; | ||||
|  | ||||
| interface ProjectsContentProps { | ||||
|   markdownPath: string; | ||||
| } | ||||
|  | ||||
| const ProjectsContent: React.FC<ProjectsContentProps> = ({ markdownPath }) => { | ||||
|   const [content, setContent] = React.useState<string>(''); | ||||
|   const [error, setError] = React.useState<string>(''); | ||||
|  | ||||
|   React.useEffect(() => { | ||||
|     fetch(markdownPath) | ||||
|       .then(response => { | ||||
|         if (!response.ok) throw new Error('Failed to load content'); | ||||
|         return response.text(); | ||||
|       }) | ||||
|       .then(text => setContent(text)) | ||||
|       .catch(err => setError(err.message)); | ||||
|   }, [markdownPath]); | ||||
|  | ||||
|   if (error) { | ||||
|     return ( | ||||
|       <div className="flex-1 flex items-center justify-center"> | ||||
|         <div className="text-center space-y-4"> | ||||
|           <FileWarning className="w-12 h-12 mx-auto" /> | ||||
|           <p className="text-lg">Error loading content: {error}</p> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   return ( | ||||
|     <div className="flex-1"> | ||||
|       <div className="prose prose-invert prose-green max-w-none"> | ||||
|         <ReactMarkdown remarkPlugins={[remarkGfm]}> | ||||
|           {content} | ||||
|         </ReactMarkdown> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| export default ProjectsContent; | ||||
							
								
								
									
										34
									
								
								src/components/TerminalButton.tsx
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										34
									
								
								src/components/TerminalButton.tsx
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| import React from 'react'; | ||||
| import { ChevronRight } from 'lucide-react'; | ||||
|  | ||||
| interface TerminalButtonProps { | ||||
|   children: React.ReactNode; | ||||
|   onClick?: () => void; | ||||
|   isSelected?: boolean; | ||||
| } | ||||
|  | ||||
| const TerminalButton: React.FC<TerminalButtonProps> = ({ children, onClick, isSelected }) => { | ||||
|   const playKeyPress = () => { | ||||
|     const audio = new Audio('data:audio/wav;base64,UklGRnQGAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YU8GAACBhYqFbF1fdH2Dg4R/gIKFi4SAgX98eoCFhQAAhIWKhWxdX3R9g4OEf4CChYuEgIF/fHqAhYUAAP//'); | ||||
|     audio.volume = 0.2; | ||||
|     audio.play().catch(() => {}); | ||||
|   }; | ||||
|  | ||||
|   const handleClick = (e: React.MouseEvent) => { | ||||
|     playKeyPress(); | ||||
|     onClick?.(e); | ||||
|   }; | ||||
|  | ||||
|   return ( | ||||
|     <button  | ||||
|       className={`terminal-button group ${isSelected ? 'terminal-button-selected' : ''}`} | ||||
|       onClick={handleClick} | ||||
|     > | ||||
|       <div className="glare-effect"></div> | ||||
|       <ChevronRight className="inline-block mr-2 w-4 h-4 transition-transform group-hover:translate-x-1" /> | ||||
|       {children} | ||||
|     </button> | ||||
|   ); | ||||
| } | ||||
|  | ||||
| export default TerminalButton; | ||||
		Reference in New Issue
	
	Block a user