315 lines
12 KiB
JavaScript
315 lines
12 KiB
JavaScript
// Gestionnaire des technologies pour les projets
|
|
class TechnologiesManager {
|
|
constructor() {
|
|
this.technologies = {
|
|
'frontend': {
|
|
label: 'Frontend Web',
|
|
items: [
|
|
'HTML', 'CSS', 'JavaScript', 'TypeScript', 'React', 'Vue.js',
|
|
'Angular', 'Svelte', 'Next.js', 'Nuxt.js', 'Sass', 'Tailwind CSS', 'Bootstrap'
|
|
]
|
|
},
|
|
'backend': {
|
|
label: 'Backend Web',
|
|
items: [
|
|
'PHP', 'Laravel', 'Symfony', 'Node.js', 'Express.js', 'Python',
|
|
'Django', 'Flask', 'FastAPI', 'Ruby', 'Ruby on Rails', 'Go', 'Rust'
|
|
]
|
|
},
|
|
'languages': {
|
|
label: 'Langages de Programmation',
|
|
items: [
|
|
'Java', 'Spring', 'C#', '.NET', 'C++', 'C', 'Kotlin', 'Swift',
|
|
'Dart', 'Scala', 'R', 'MATLAB'
|
|
]
|
|
},
|
|
'databases': {
|
|
label: 'Bases de Données',
|
|
items: [
|
|
'MySQL', 'PostgreSQL', 'MongoDB', 'Redis', 'SQLite', 'Elasticsearch',
|
|
'MariaDB', 'Oracle', 'Firebase', 'Supabase'
|
|
]
|
|
},
|
|
'mobile': {
|
|
label: 'Développement Mobile',
|
|
items: [
|
|
'React Native', 'Flutter', 'Ionic', 'Xamarin', 'Apache Cordova', 'Android', 'iOS'
|
|
]
|
|
},
|
|
'games': {
|
|
label: 'Développement de Jeux',
|
|
items: [
|
|
'Unity', 'Unreal Engine', 'Godot', 'Phaser', 'Three.js', 'Babylon.js',
|
|
'PixiJS', 'Construct 3', 'GameMaker Studio', 'RPG Maker'
|
|
]
|
|
},
|
|
'devops': {
|
|
label: 'DevOps & Cloud',
|
|
items: [
|
|
'Docker', 'Kubernetes', 'AWS', 'Azure', 'Google Cloud', 'Heroku',
|
|
'Vercel', 'Netlify', 'Jenkins', 'GitLab CI', 'GitHub Actions', 'Terraform'
|
|
]
|
|
},
|
|
'tools': {
|
|
label: 'Outils & Frameworks',
|
|
items: [
|
|
'Git', 'GitHub', 'Webpack', 'Vite', 'Babel', 'ESLint', 'Prettier',
|
|
'Jest', 'Cypress', 'Storybook'
|
|
]
|
|
},
|
|
'design': {
|
|
label: 'Design & Création',
|
|
items: [
|
|
'Figma', 'Sketch', 'Adobe XD', 'Photoshop', 'Illustrator', 'Canva',
|
|
'Blender', 'Maya', '3ds Max'
|
|
]
|
|
}
|
|
};
|
|
|
|
this.selectedTechs = new Set();
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
this.render();
|
|
this.attachEvents();
|
|
this.addSearchFunctionality();
|
|
this.addQuickActions();
|
|
}
|
|
|
|
generateId(tech) {
|
|
return 'tag-' + tech.toLowerCase().replace(/[^a-z0-9]/g, '-');
|
|
}
|
|
|
|
render() {
|
|
const container = document.querySelector('.technologies-grid');
|
|
if (!container) return;
|
|
|
|
let html = `
|
|
<div class="tech-controls">
|
|
<div class="tech-search">
|
|
<input type="text" id="tech-search" placeholder="Rechercher une technologie...">
|
|
<span class="search-icon">🔍</span>
|
|
</div>
|
|
<div class="tech-quick-actions">
|
|
<button type="button" class="btn-quick" id="select-all">Tout sélectionner</button>
|
|
<button type="button" class="btn-quick" id="deselect-all">Tout désélectionner</button>
|
|
<button type="button" class="btn-quick" id="toggle-categories">Replier/Déplier</button>
|
|
</div>
|
|
<div class="selected-count">
|
|
<span id="count-display">0 technologie(s) sélectionnée(s)</span>
|
|
</div>
|
|
</div>
|
|
<div class="tech-categories">
|
|
`;
|
|
|
|
for (const [categoryKey, category] of Object.entries(this.technologies)) {
|
|
html += `
|
|
<div class="tech-category" data-category="${categoryKey}">
|
|
<div class="category-header" data-toggle="${categoryKey}">
|
|
<h4>${category.label}</h4>
|
|
<span class="category-toggle">▼</span>
|
|
<span class="category-count">(${category.items.length})</span>
|
|
</div>
|
|
<div class="category-items" id="category-${categoryKey}">
|
|
`;
|
|
|
|
category.items.forEach(tech => {
|
|
const id = this.generateId(tech);
|
|
html += `
|
|
<div class="tech-item">
|
|
<input type="checkbox" id="${id}" name="tags[]" value="${tech}" class="tech-checkbox">
|
|
<label for="${id}" class="tech-label">${tech}</label>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
html += `
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
html += '</div>';
|
|
container.innerHTML = html;
|
|
}
|
|
|
|
attachEvents() {
|
|
// Événements pour les checkboxes
|
|
document.querySelectorAll('.tech-checkbox').forEach(checkbox => {
|
|
checkbox.addEventListener('change', (e) => {
|
|
if (e.target.checked) {
|
|
this.selectedTechs.add(e.target.value);
|
|
} else {
|
|
this.selectedTechs.delete(e.target.value);
|
|
}
|
|
this.updateSelectedCount();
|
|
this.updateHiddenField();
|
|
});
|
|
});
|
|
|
|
// Événements pour replier/déplier les catégories
|
|
document.querySelectorAll('.category-header').forEach(header => {
|
|
header.addEventListener('click', (e) => {
|
|
const categoryKey = e.currentTarget.dataset.toggle;
|
|
const categoryItems = document.getElementById(`category-${categoryKey}`);
|
|
const toggle = e.currentTarget.querySelector('.category-toggle');
|
|
|
|
if (categoryItems.style.display === 'none') {
|
|
categoryItems.style.display = 'grid';
|
|
toggle.textContent = '▼';
|
|
} else {
|
|
categoryItems.style.display = 'none';
|
|
toggle.textContent = '▶';
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
addSearchFunctionality() {
|
|
const searchInput = document.getElementById('tech-search');
|
|
if (!searchInput) return;
|
|
|
|
searchInput.addEventListener('input', (e) => {
|
|
const query = e.target.value.toLowerCase();
|
|
const techItems = document.querySelectorAll('.tech-item');
|
|
|
|
techItems.forEach(item => {
|
|
const label = item.querySelector('.tech-label').textContent.toLowerCase();
|
|
if (label.includes(query)) {
|
|
item.style.display = 'flex';
|
|
} else {
|
|
item.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
// Masquer les catégories vides
|
|
document.querySelectorAll('.tech-category').forEach(category => {
|
|
const visibleItems = category.querySelectorAll('.tech-item[style*="flex"]');
|
|
if (query && visibleItems.length === 0) {
|
|
category.style.display = 'none';
|
|
} else {
|
|
category.style.display = 'block';
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
addQuickActions() {
|
|
const selectAllBtn = document.getElementById('select-all');
|
|
const deselectAllBtn = document.getElementById('deselect-all');
|
|
const toggleCategoriesBtn = document.getElementById('toggle-categories');
|
|
|
|
if (selectAllBtn) {
|
|
selectAllBtn.addEventListener('click', () => {
|
|
document.querySelectorAll('.tech-checkbox').forEach(checkbox => {
|
|
checkbox.checked = true;
|
|
this.selectedTechs.add(checkbox.value);
|
|
});
|
|
this.updateSelectedCount();
|
|
this.updateHiddenField();
|
|
});
|
|
}
|
|
|
|
if (deselectAllBtn) {
|
|
deselectAllBtn.addEventListener('click', () => {
|
|
document.querySelectorAll('.tech-checkbox').forEach(checkbox => {
|
|
checkbox.checked = false;
|
|
});
|
|
this.selectedTechs.clear();
|
|
this.updateSelectedCount();
|
|
this.updateHiddenField();
|
|
});
|
|
}
|
|
|
|
if (toggleCategoriesBtn) {
|
|
toggleCategoriesBtn.addEventListener('click', () => {
|
|
const allCategories = document.querySelectorAll('.category-items');
|
|
const allToggles = document.querySelectorAll('.category-toggle');
|
|
const firstCategory = allCategories[0];
|
|
const isCollapsed = firstCategory.style.display === 'none';
|
|
|
|
allCategories.forEach(category => {
|
|
category.style.display = isCollapsed ? 'grid' : 'none';
|
|
});
|
|
|
|
allToggles.forEach(toggle => {
|
|
toggle.textContent = isCollapsed ? '▼' : '▶';
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
updateSelectedCount() {
|
|
const countDisplay = document.getElementById('count-display');
|
|
if (countDisplay) {
|
|
const count = this.selectedTechs.size;
|
|
countDisplay.textContent = `${count} technologie(s) sélectionnée(s)`;
|
|
|
|
// Changer la couleur selon le nombre
|
|
if (count === 0) {
|
|
countDisplay.className = 'count-empty';
|
|
} else if (count <= 3) {
|
|
countDisplay.className = 'count-low';
|
|
} else if (count <= 6) {
|
|
countDisplay.className = 'count-medium';
|
|
} else {
|
|
countDisplay.className = 'count-high';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Méthode pour pré-sélectionner des technologies (utile pour l'édition)
|
|
selectTechnologies(techArray) {
|
|
this.selectedTechs.clear();
|
|
|
|
techArray.forEach(tech => {
|
|
this.selectedTechs.add(tech);
|
|
const checkbox = document.querySelector(`input[value="${tech}"]`);
|
|
if (checkbox) {
|
|
checkbox.checked = true;
|
|
}
|
|
});
|
|
|
|
this.updateSelectedCount();
|
|
this.updateHiddenField();
|
|
}
|
|
|
|
// Alias pour la compatibilité
|
|
preselectTechnologies(techArray) {
|
|
this.selectTechnologies(techArray);
|
|
}
|
|
|
|
// Méthode pour effacer toutes les sélections
|
|
clearAllSelections() {
|
|
document.querySelectorAll('.tech-checkbox').forEach(checkbox => {
|
|
checkbox.checked = false;
|
|
});
|
|
this.selectedTechs.clear();
|
|
this.updateSelectedCount();
|
|
this.updateHiddenField();
|
|
}
|
|
|
|
// Méthode pour mettre à jour le champ caché
|
|
updateHiddenField() {
|
|
const hiddenField = document.getElementById('selected-technologies');
|
|
if (hiddenField) {
|
|
hiddenField.value = Array.from(this.selectedTechs).join(',');
|
|
}
|
|
}
|
|
|
|
// Méthode pour obtenir les technologies sélectionnées
|
|
getSelectedTechnologies() {
|
|
return Array.from(this.selectedTechs);
|
|
}
|
|
}
|
|
|
|
// Initialiser le gestionnaire au chargement de la page
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
window.techManager = new TechnologiesManager();
|
|
});
|
|
|
|
// Export pour utilisation dans d'autres fichiers
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = TechnologiesManager;
|
|
}
|