Compare commits
2 Commits
4b264c8389
...
37ac35e3f4
Author | SHA1 | Date | |
---|---|---|---|
37ac35e3f4 | |||
8117a4870b |
@ -2,9 +2,9 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>demo</title>
|
<title>ivanczn</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
BIN
public/favicon.png
Executable file
BIN
public/favicon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 672 B |
@ -6,6 +6,7 @@ import ProjectsContent from './components/ProjectsContent';
|
|||||||
import TerminalShell from './components/TerminalShell';
|
import TerminalShell from './components/TerminalShell';
|
||||||
import SkillsContent from './components/SkillsContent';
|
import SkillsContent from './components/SkillsContent';
|
||||||
import ResumeContent from './components/ResumeContent';
|
import ResumeContent from './components/ResumeContent';
|
||||||
|
import PostsContent from './components/PostsContent';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [activeSection, setActiveSection] = React.useState('about');
|
const [activeSection, setActiveSection] = React.useState('about');
|
||||||
@ -50,6 +51,12 @@ function App() {
|
|||||||
>
|
>
|
||||||
SKILLS
|
SKILLS
|
||||||
</TerminalButton>
|
</TerminalButton>
|
||||||
|
<TerminalButton
|
||||||
|
onClick={() => setActiveSection('posts')}
|
||||||
|
isSelected={activeSection === 'posts'}
|
||||||
|
>
|
||||||
|
POSTS
|
||||||
|
</TerminalButton>
|
||||||
<TerminalButton
|
<TerminalButton
|
||||||
onClick={() => setActiveSection('resume')}
|
onClick={() => setActiveSection('resume')}
|
||||||
isSelected={activeSection === 'resume'}
|
isSelected={activeSection === 'resume'}
|
||||||
@ -74,6 +81,7 @@ function App() {
|
|||||||
<ProjectsContent markdownPath="/content/projects.md" />
|
<ProjectsContent markdownPath="/content/projects.md" />
|
||||||
)}
|
)}
|
||||||
{activeSection === 'skills' && <SkillsContent />}
|
{activeSection === 'skills' && <SkillsContent />}
|
||||||
|
{activeSection === 'posts' && <PostsContent />}
|
||||||
{activeSection === 'resume' && <ResumeContent />}
|
{activeSection === 'resume' && <ResumeContent />}
|
||||||
{activeSection === 'shell' && <TerminalShell />}
|
{activeSection === 'shell' && <TerminalShell />}
|
||||||
</div>
|
</div>
|
||||||
|
23
src/components/PostsContent.tsx
Normal file
23
src/components/PostsContent.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import TerminalButton from './TerminalButton';
|
||||||
|
|
||||||
|
const PostsContent: React.FC = () => {
|
||||||
|
const postsUrl = "https://blog.ivanch.me";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col h-full">
|
||||||
|
<div className="flex flex-col justify-center items-center h-full">
|
||||||
|
<p className="text-lg mb-4">You can check my (blog) posts by clicking the button below:</p>
|
||||||
|
|
||||||
|
<TerminalButton
|
||||||
|
onClick={() => window.open(postsUrl, '_blank')}
|
||||||
|
isSelected={false}
|
||||||
|
>
|
||||||
|
blog.ivanch.me
|
||||||
|
</TerminalButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PostsContent;
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Mail, Github, Linkedin, User, Code, BookOpen, Building, MapPin } from 'lucide-react';
|
import { Mail, Github, Linkedin, User, Code, BookOpen, Building, MapPin, GraduationCap } from 'lucide-react';
|
||||||
import GlitchyLink from './GlitchyLink';
|
import GlitchyLink from './GlitchyLink';
|
||||||
|
|
||||||
const ProfileContent: React.FC = () => {
|
const ProfileContent: React.FC = () => {
|
||||||
@ -21,6 +21,11 @@ const ProfileContent: React.FC = () => {
|
|||||||
<p className="text-lg">EposNow</p>
|
<p className="text-lg">EposNow</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<GraduationCap className="w-6 h-6" />
|
||||||
|
<p className="text-lg">UTFPR</p><small>(Federal University of Technology of Paraná)</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<MapPin className="w-6 h-6" />
|
<MapPin className="w-6 h-6" />
|
||||||
<p className="text-lg">Curitiba, PR - Brazil</p>
|
<p className="text-lg">Curitiba, PR - Brazil</p>
|
||||||
|
@ -3,22 +3,14 @@ import TerminalButton from './TerminalButton';
|
|||||||
|
|
||||||
const ResumeContent: React.FC = () => {
|
const ResumeContent: React.FC = () => {
|
||||||
const resumeUrl = "https://drive.google.com/file/d/1oYf68qKXUnBz7d4qjHX-hTw_-f5EKgeF/view?usp=sharing";
|
const resumeUrl = "https://drive.google.com/file/d/1oYf68qKXUnBz7d4qjHX-hTw_-f5EKgeF/view?usp=sharing";
|
||||||
const downloadUrl = "https://drive.google.com/file/d/1oYf68qKXUnBz7d4qjHX-hTw_-f5EKgeF/view?usp=sharing";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
<div className="flex-1 mb-4">
|
<div className="flex flex-col justify-center items-center h-full">
|
||||||
<iframe
|
<p className="text-lg mb-4">You can check my resume by clicking the button below:</p>
|
||||||
src={resumeUrl}
|
|
||||||
className="w-full h-full rounded-lg"
|
|
||||||
frameBorder="0"
|
|
||||||
allowFullScreen
|
|
||||||
allow="autoplay"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<TerminalButton
|
<TerminalButton
|
||||||
onClick={() => window.open(downloadUrl, '_blank')}
|
onClick={() => window.open(resumeUrl, '_blank')}
|
||||||
isSelected={false}
|
isSelected={false}
|
||||||
>
|
>
|
||||||
OPEN IN NEW TAB
|
OPEN IN NEW TAB
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import '../styles/skills.css';
|
||||||
|
|
||||||
const SkillsContent: React.FC = () => {
|
const SkillsContent: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center h-full">
|
<div className="flex flex-col items-center justify-center h-full">
|
||||||
<pre className="font-mono text-[#00FF00] whitespace-pre">
|
<pre className="font-mono whitespace-pre skills-text">
|
||||||
{`
|
{`
|
||||||
_____ __ _ _ _ _____
|
_____ __ _ _ _ _____
|
||||||
/ ____|/ /_ (_) | | |/ ____|
|
/ ____|/ /_ (_) | | |/ ____|
|
||||||
@ -11,7 +12,9 @@ const SkillsContent: React.FC = () => {
|
|||||||
\\___ \\| | | | | | | |\\____ \\
|
\\___ \\| | | | | | | |\\____ \\
|
||||||
____) | | | | | | | | ____) |
|
____) | | | | | | | | ____) |
|
||||||
|_____/|_| |_|_|_| |_||_____/
|
|_____/|_| |_|_|_| |_||_____/
|
||||||
|
`}</pre>
|
||||||
|
<pre className="font-mono text-[#00FF00] whitespace-pre">
|
||||||
|
{`
|
||||||
Programming:
|
Programming:
|
||||||
├── Languages: C# (.NET Core, .NET Framework, ASP.NET Core)
|
├── Languages: C# (.NET Core, .NET Framework, ASP.NET Core)
|
||||||
├── Languages: TypeScript, JavaScript, Python, Golang, Java, C/C++
|
├── Languages: TypeScript, JavaScript, Python, Golang, Java, C/C++
|
||||||
|
16
src/main.tsx
16
src/main.tsx
@ -2,9 +2,15 @@ import { StrictMode } from 'react';
|
|||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import App from './App.tsx';
|
import App from './App.tsx';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
import { isMobileDevice } from './utils/deviceDetection';
|
||||||
|
|
||||||
createRoot(document.getElementById('root')!).render(
|
// Check for mobile device and redirect if necessary
|
||||||
<StrictMode>
|
if (isMobileDevice()) {
|
||||||
<App />
|
window.location.href = 'https://blog.ivanch.me';
|
||||||
</StrictMode>
|
} else {
|
||||||
);
|
createRoot(document.getElementById('root')!).render(
|
||||||
|
<StrictMode>
|
||||||
|
<App />
|
||||||
|
</StrictMode>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
33
src/styles/skills.css
Normal file
33
src/styles/skills.css
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
@keyframes rainbow-text {
|
||||||
|
0% { color: #ff0000; }
|
||||||
|
16% { color: #ffa500; }
|
||||||
|
32% { color: #ffff00; }
|
||||||
|
48% { color: #00ff00; }
|
||||||
|
64% { color: #00ffff; }
|
||||||
|
80% { color: #0000ff; }
|
||||||
|
100% { color: #ff00ff; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.skills-text {
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
#ff0000 0%,
|
||||||
|
#ffa500 16%,
|
||||||
|
#ffff00 32%,
|
||||||
|
#00ff00 48%,
|
||||||
|
#00ffff 64%,
|
||||||
|
#0000ff 80%,
|
||||||
|
#ff00ff 100%
|
||||||
|
);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
background-size: 200% auto;
|
||||||
|
animation: rainbow-slide 5s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rainbow-slide {
|
||||||
|
to {
|
||||||
|
background-position: -200% center;
|
||||||
|
}
|
||||||
|
}
|
21
src/utils/deviceDetection.ts
Normal file
21
src/utils/deviceDetection.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
function isPortraitAndNarrow(): boolean {
|
||||||
|
return window.innerWidth < window.innerHeight && window.innerWidth < 768;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isMobileDevice(): boolean {
|
||||||
|
const toMatch = [
|
||||||
|
/Android/i,
|
||||||
|
/webOS/i,
|
||||||
|
/iPhone/i,
|
||||||
|
/iPad/i,
|
||||||
|
/iPod/i,
|
||||||
|
/BlackBerry/i,
|
||||||
|
/Windows Phone/i
|
||||||
|
];
|
||||||
|
|
||||||
|
const isMobileUserAgent = toMatch.some((toMatchItem) => {
|
||||||
|
return navigator.userAgent.match(toMatchItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
return isMobileUserAgent || isPortraitAndNarrow();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user