first commit
This commit is contained in:
commit
b216a187bd
34 changed files with 4829 additions and 0 deletions
315
Static/js/technologies.js
Normal file
315
Static/js/technologies.js
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
// 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue