diff --git a/docs/acces/courses.md b/docs/acces/courses.md index b2809d783..9da54f19c 100644 --- a/docs/acces/courses.md +++ b/docs/acces/courses.md @@ -1,3 +1,8 @@ +--- +title: "Pour les formations" +sidebar_position: 2 +--- + # Pour les formations (page en cours de création) diff --git a/docs/acces/ou-faire-quoi.mdx b/docs/acces/ou-faire-quoi.mdx new file mode 100644 index 000000000..79a89e035 --- /dev/null +++ b/docs/acces/ou-faire-quoi.mdx @@ -0,0 +1,50 @@ +--- +title: "Où faire quoi" +sidebar_position: 3 +--- + +import SearchableSortableTable from '@site/src/components/SearchableSortableTable'; + +# Où faire quoi + +Ce tableau vous permet de trouver la machine MesoNET la plus adaptée à vos besoins. + + diff --git a/docs/acces/projets.md b/docs/acces/projets.md index 7e3f9d82c..77ab983b1 100644 --- a/docs/acces/projets.md +++ b/docs/acces/projets.md @@ -1,6 +1,6 @@ --- title: "Créer et gérer des projets" -sidebar_position: 3 +sidebar_position: 5 --- :::info diff --git a/docs/acces/ssh.md b/docs/acces/ssh.md index 5d212f626..c8c73f84b 100644 --- a/docs/acces/ssh.md +++ b/docs/acces/ssh.md @@ -1,6 +1,6 @@ --- title: "Gérer ses clés SSH" -sidebar_position: 2 +sidebar_position: 4 --- # Gérer ses clés SSH diff --git a/src/components/SearchableSortableTable.jsx b/src/components/SearchableSortableTable.jsx new file mode 100644 index 000000000..61b7548b9 --- /dev/null +++ b/src/components/SearchableSortableTable.jsx @@ -0,0 +1,157 @@ +import React, { useState, useMemo } from 'react'; + +/** + * Composant de tableau avec recherche et tri + * @param {Object} props + * @param {Array} props.data - Tableau d'objets représentant les lignes + * @param {Array} props.columns - Tableau d'objets { key, label } pour les colonnes + * @param {string} props.title - Titre du tableau (optionnel) + */ +const SearchableSortableTable = ({ data, columns, title }) => { + const [searchTerm, setSearchTerm] = useState(''); + const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); + + // Filtrer les données en fonction du terme de recherche + const filteredData = useMemo(() => { + if (!searchTerm) return data; + + const lowerSearchTerm = searchTerm.toLowerCase(); + return data.filter(row => + columns.some(col => { + const value = row[col.key]; + return value && value.toString().toLowerCase().includes(lowerSearchTerm); + }) + ); + }, [data, searchTerm, columns]); + + // Trier les données + const sortedData = useMemo(() => { + if (!sortConfig.key) return filteredData; + + return [...filteredData].sort((a, b) => { + const aValue = a[sortConfig.key] || ''; + const bValue = b[sortConfig.key] || ''; + + if (aValue < bValue) { + return sortConfig.direction === 'asc' ? -1 : 1; + } + if (aValue > bValue) { + return sortConfig.direction === 'asc' ? 1 : -1; + } + return 0; + }); + }, [filteredData, sortConfig]); + + // Gérer le clic sur l'en-tête de colonne pour le tri + const requestSort = (key) => { + let direction = 'asc'; + if (sortConfig.key === key && sortConfig.direction === 'asc') { + direction = 'desc'; + } + setSortConfig({ key, direction }); + }; + + // Obtenir l'icône de tri pour une colonne + const getSortIcon = (key) => { + if (sortConfig.key !== key) return '↕'; + return sortConfig.direction === 'asc' ? '↑' : '↓'; + }; + + return ( +
+ {title && ( +

{title}

+ )} + + {/* Barre de recherche */} +
+ setSearchTerm(e.target.value)} + style={{ + padding: '8px 12px', + border: '1px solid #e0e0e0', + borderRadius: '4px', + width: '100%', + maxWidth: '400px', + fontSize: '14px', + }} + /> +
+ + {/* Tableau */} +
+ + + + {columns.map((col) => ( + + ))} + + + + {sortedData.length > 0 ? ( + sortedData.map((row, index) => ( + + {columns.map((col) => ( + + ))} + + )) + ) : ( + + + + )} + +
requestSort(col.key)} + style={{ + padding: '12px', + textAlign: 'left', + borderBottom: '2px solid #e0e0e0', + cursor: 'pointer', + userSelect: 'none', + }} + > +
+ {col.label} + {getSortIcon(col.key)} +
+
requestSort(col.key)} + > + {row[col.key]} +
+ Aucun résultat trouvé +
+
+ + {/* Afficher le nombre de résultats */} +
+ {sortedData.length} résultat(s) sur {data.length} au total +
+
+ ); +}; + +export default SearchableSortableTable;