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