Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 89 additions & 5 deletions src/components/skills.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,106 @@
import React from "react"
import React, { useState, useEffect, useRef } from "react"
import Fade from "./animations/Fade"
import { useLanguage } from "../contexts/LanguageContext"
import data, { getText } from "../data"

const Skills = () => {
const { language } = useLanguage();
const [skills, setSkills] = useState([...data.skills]);
const [isDesktop, setIsDesktop] = useState(false);
const [draggedIndex, setDraggedIndex] = useState(null);
const dragItem = useRef(null);
const dragOverItem = useRef(null);

// Check if device is desktop (> 768px) - only load drag functionality on desktop
useEffect(() => {
const checkIsDesktop = () => {
const desktop = window.innerWidth > 768;
setIsDesktop(desktop);
};

checkIsDesktop();
window.addEventListener('resize', checkIsDesktop);

return () => window.removeEventListener('resize', checkIsDesktop);
}, []);

// Load saved order from localStorage
useEffect(() => {
if (isDesktop && typeof window !== 'undefined') {
const savedOrder = localStorage.getItem('skillsOrder');
if (savedOrder) {
try {
const parsedOrder = JSON.parse(savedOrder);
setSkills(parsedOrder);
} catch (e) {
console.error('Failed to parse saved skills order:', e);
}
}
}
}, [isDesktop]);

// Drag and drop handlers (only active on desktop)
const handleDragStart = (index) => {
if (!isDesktop) return;
dragItem.current = index;
setDraggedIndex(index);
};

const handleDragEnter = (index) => {
if (!isDesktop) return;
dragOverItem.current = index;
};

const handleDragEnd = () => {
if (!isDesktop) return;

if (dragItem.current !== null && dragOverItem.current !== null) {
const newSkills = [...skills];
const draggedItemContent = newSkills[dragItem.current];

// Remove dragged item
newSkills.splice(dragItem.current, 1);

// Insert at new position
newSkills.splice(dragOverItem.current, 0, draggedItemContent);

setSkills(newSkills);

// Save to localStorage
if (typeof window !== 'undefined') {
localStorage.setItem('skillsOrder', JSON.stringify(newSkills));
}
}

dragItem.current = null;
dragOverItem.current = null;
setDraggedIndex(null);
};

const handleDragOver = (e) => {
if (!isDesktop) return;
e.preventDefault();
};

return (
<div className="section" id="skills">
<div className="container">
<Fade bottom cascade distance="20px">
<h1>{getText(data.sections.skills, language)}</h1>

</Fade>
<div className="skills-wrapper">
<div className="grid">
<div className={`grid ${isDesktop ? 'draggable' : ''}`}>
<Fade bottom distance="20px">
{data.skills.map((skill, index) => (
<div key={index} className="skill-item">
{skills.map((skill, index) => (
<div
key={`${skill.title}-${index}`}
className={`skill-item ${draggedIndex === index ? 'dragging' : ''} ${isDesktop ? 'desktop-draggable' : ''}`}
draggable={isDesktop}
onDragStart={() => handleDragStart(index)}
onDragEnter={() => handleDragEnter(index)}
onDragEnd={handleDragEnd}
onDragOver={handleDragOver}
>
<img src={skill.img} alt={skill.title} loading="lazy" />
<h3>{skill.title}</h3>
<p>{skill.para}</p>
Expand Down
22 changes: 22 additions & 0 deletions src/styles/skills.scss
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,30 @@
box-shadow: 0 6px 13px rgba(0, 0, 0, 0.2); /* Reverted to original subtle hover shadow */
}

/* Desktop drag-and-drop styles (only on desktop > 768px) */
&.desktop-draggable {
cursor: grab;
user-select: none;

&:active {
cursor: grabbing;
}

&.dragging {
opacity: 0.5;
transform: scale(0.95);
cursor: grabbing;
z-index: 100;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
border: 2px dashed rgba(0, 0, 0, 0.4);
}
}

/* Disable hover effects on mobile for better UX */
@media (max-width: 768px) {
cursor: default;
user-select: auto;

&:hover {
transform: none;
z-index: 1;
Expand Down