Spaces:
Running
Running
| document.addEventListener('DOMContentLoaded', () => { | |
| // --- Intersection Observer for Scroll Animations --- | |
| const observerOptions = { | |
| root: null, | |
| rootMargin: '0px', | |
| threshold: 0.1 | |
| }; | |
| const observer = new IntersectionObserver((entries, observer) => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| entry.target.classList.add('is-visible'); | |
| // Stop observing once visible | |
| observer.unobserve(entry.target); | |
| } | |
| }); | |
| }, observerOptions); | |
| document.querySelectorAll('.fade-in-section').forEach(section => { | |
| observer.observe(section); | |
| }); | |
| // --- Populate Skills Dynamically --- | |
| const skills = [ | |
| { name: "JavaScript", level: "Expert" }, | |
| { name: "React.js", level: "Advanced" }, | |
| { name: "Tailwind CSS", level: "Expert" }, | |
| { name: "Node.js", level: "Intermediate" }, | |
| { name: "TypeScript", level: "Advanced" }, | |
| { name: "UI/UX Design", level: "Advanced" }, | |
| { name: "HTML5 & CSS3", level: "Expert" }, | |
| { name: "Git & GitHub", level: "Advanced" }, | |
| { name: "Python", level: "Intermediate" }, | |
| { name: "SQL", level: "Intermediate" }, | |
| ]; | |
| const skillsContainer = document.getElementById('skills-container'); | |
| if(skillsContainer) { | |
| skills.forEach(skill => { | |
| const badge = document.createElement('div'); | |
| // Styling the badge manually to ensure it matches the design without creating a new component | |
| badge.className = ` | |
| group relative px-6 py-4 bg-surface/40 border border-white/5 | |
| rounded-xl hover:border-primary/50 hover:bg-surface/80 | |
| transition-all duration-300 cursor-default | |
| `; | |
| badge.innerHTML = ` | |
| <div class="flex items-center gap-3"> | |
| <div class="w-2 h-2 rounded-full bg-secondary group-hover:bg-primary transition-colors"></div> | |
| <span class="font-medium text-slate-200 group-hover:text-white">${skill.name}</span> | |
| </div> | |
| <div class="text-xs text-slate-500 mt-1 pl-5 font-mono">${skill.level}</div> | |
| `; | |
| skillsContainer.appendChild(badge); | |
| }); | |
| } | |
| // --- Fetch Real Data from GitHub (Optional Enhancement) --- | |
| // This section tries to fetch real repos but falls back if it fails (e.g., rate limits) | |
| async function fetchGitHubRepos() { | |
| const projectGrid = document.getElementById('projects-grid'); | |
| if(!projectGrid) return; | |
| try { | |
| const response = await fetch('https://api.github.com/users/kimyg119/repos?sort=updated&per_page=6'); | |
| if (!response.ok) throw new Error('API limit or error'); | |
| const repos = await response.json(); | |
| // Keep the static ones, maybe add to them or replace. | |
| // Let's create new web component elements dynamically | |
| repos.forEach((repo, index) => { | |
| if(index > 2) return; // Just adding a couple for demo to not clutter | |
| const card = document.createElement('custom-project-card'); | |
| card.setAttribute('title', repo.name); | |
| card.setAttribute('desc', repo.description || 'No description provided.'); | |
| // Use a random tech image | |
| card.setAttribute('image', `http://static.photos/technology/640x360/${repo.id % 100}`); | |
| card.setAttribute('tags', repo.language || 'Code'); | |
| card.setAttribute('link', repo.html_url); | |
| projectGrid.appendChild(card); | |
| }); | |
| } catch (error) { | |
| console.log('Using static projects due to API limits or error.'); | |
| } | |
| } | |
| fetchGitHubRepos(); | |
| }); |