diff --git a/ajax/load-more-videos.php b/ajax/load-more-videos.php
new file mode 100644
index 0000000..b10dd84
--- /dev/null
+++ b/ajax/load-more-videos.php
@@ -0,0 +1,92 @@
+ 'Accès non autorisé']);
+ exit;
+}
+
+// Récupérer les paramètres
+$type = isset($_GET['type']) ? $_GET['type'] : '';
+$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
+
+// Vérifier que le type est valide
+if (!in_array($type, ['recent', 'trending', 'independence'])) {
+ http_response_code(400); // Requête incorrecte
+ echo json_encode(['error' => 'Type de vidéos non valide']);
+ exit;
+}
+
+// Récupérer les vidéos en fonction du type
+$videos = [];
+$offset = $page * LOAD_MORE_COUNT;
+
+switch ($type) {
+ case 'recent':
+ // Récupérer les vidéos récentes
+ $data = callPeerTubeApi('videos', [
+ 'sort' => '-publishedAt',
+ 'count' => LOAD_MORE_COUNT,
+ 'start' => $offset,
+ 'isLocal' => true
+ ]);
+ $videos = formatVideosData($data['data'] ?? []);
+ break;
+
+ case 'trending':
+ // Récupérer les vidéos tendances
+ $data = callPeerTubeApi('videos', [
+ 'sort' => '-views',
+ 'count' => LOAD_MORE_COUNT,
+ 'start' => $offset,
+ 'isLocal' => true
+ ]);
+ $videos = formatVideosData($data['data'] ?? []);
+ break;
+
+ case 'independence':
+ // Récupérer les vidéos sur l'indépendance
+ $data = callPeerTubeApi('videos', [
+ 'tagsOneOf' => TAG_INDEPENDENCE,
+ 'count' => LOAD_MORE_COUNT,
+ 'start' => $offset,
+ 'isLocal' => true
+ ]);
+ $videos = formatVideosData($data['data'] ?? []);
+ break;
+}
+
+// Préparer la réponse HTML
+$html = '';
+
+foreach ($videos as $video) {
+ $html .= '
';
+ $html .= '
';
+ $html .= '
![' . htmlspecialchars($video['title']) . '](' . $video['thumbnail'] . ')
';
+ $html .= '
';
+ $html .= ' ';
+ $html .= '
';
+ $html .= '
' . formatDuration($video['duration']) . '
';
+ $html .= '
';
+ $html .= '
';
+ $html .= '
' . htmlspecialchars($video['title']) . '
';
+ $html .= '
' . htmlspecialchars($video['channel']) . '
';
+ $html .= '
';
+ $html .= ' ' . formatViewCount($video['views']) . ' vues';
+ $html .= ' ' . formatDate($video['date']) . '';
+ $html .= '
';
+ $html .= '
';
+ $html .= '
';
+}
+
+// Retourner la réponse
+echo json_encode([
+ 'success' => true,
+ 'html' => $html,
+ 'page' => $page,
+ 'hasMore' => count($videos) >= LOAD_MORE_COUNT
+]);
+?>
\ No newline at end of file
diff --git a/css/styles.css b/css/styles.css
index f4fbdb7..128d58c 100644
--- a/css/styles.css
+++ b/css/styles.css
@@ -325,11 +325,12 @@ img {
/* Video Sections */
.video-section {
margin-bottom: 40px;
+ position: relative;
}
.video-grid {
display: grid;
- grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
+ grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
@@ -340,6 +341,9 @@ img {
box-shadow: var(--card-shadow);
transition: transform 0.3s;
cursor: pointer;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
}
.video-card:hover {
@@ -349,6 +353,7 @@ img {
.video-thumbnail {
position: relative;
padding-top: 56.25%; /* 16:9 aspect ratio */
+ overflow: hidden;
}
.video-thumbnail img {
@@ -377,6 +382,9 @@ img {
.video-info {
padding: 15px;
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
}
.video-title {
@@ -388,6 +396,16 @@ img {
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
+ flex-grow: 1;
+}
+
+.video-channel {
+ font-size: 14px;
+ color: #555;
+ margin-bottom: 8px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
.video-metadata {
@@ -396,6 +414,31 @@ img {
justify-content: space-between;
font-size: 12px;
color: #666;
+ margin-top: auto;
+}
+
+.video-metadata i {
+ margin-right: 4px;
+ font-size: 13px;
+ color: var(--primary-red);
+}
+
+.video-views, .video-date {
+ display: flex;
+ align-items: center;
+ font-size: 12px;
+}
+
+.video-duration {
+ position: absolute;
+ bottom: 10px;
+ right: 10px;
+ background-color: rgba(0, 0, 0, 0.7);
+ color: white;
+ padding: 3px 6px;
+ border-radius: 4px;
+ font-size: 12px;
+ font-weight: 500;
}
.video-tag {
@@ -407,24 +450,23 @@ img {
margin-right: 5px;
}
-.video-date, .video-views {
- font-size: 12px;
-}
-
/* Carousel */
.carousel {
position: relative;
overflow: hidden;
+ margin: 15px 0 30px;
+ padding: 10px 0;
}
.carousel-container {
display: flex;
transition: transform 0.5s ease;
+ padding-bottom: 10px;
}
.carousel-item {
flex: 0 0 auto;
- width: 280px;
+ width: 220px;
margin-right: 20px;
}
@@ -441,28 +483,43 @@ img {
background-color: #ccc;
margin: 0 5px;
cursor: pointer;
+ transition: all 0.2s ease;
}
.carousel-dot.active {
background-color: var(--primary-red);
+ transform: scale(1.2);
}
/* View More Button */
.view-more {
display: block;
width: max-content;
- margin: 20px auto;
- padding: 10px 25px;
- background-color: var(--search-bg);
+ margin: 25px auto 5px;
+ padding: 12px 30px;
+ background-color: var(--primary-red);
+ color: white;
border: none;
border-radius: 4px;
font-size: 16px;
+ font-weight: 500;
cursor: pointer;
- transition: background-color 0.2s;
+ transition: all 0.2s;
+ text-transform: uppercase;
+ letter-spacing: 1px;
}
.view-more:hover {
- background-color: #d0d0d0;
+ background-color: #cc0000;
+ transform: translateY(-2px);
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
+}
+
+.view-more:disabled {
+ background-color: #999;
+ cursor: not-allowed;
+ transform: none;
+ box-shadow: none;
}
/* Info Section */
@@ -689,13 +746,19 @@ img {
@media (max-width: 992px) {
.video-grid {
- grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
+ grid-template-columns: repeat(2, 1fr);
+ gap: 15px;
+ }
+
+ .video-title {
+ font-size: 15px;
}
}
@media (max-width: 576px) {
.video-grid {
grid-template-columns: 1fr;
+ gap: 15px;
}
.section-title {
@@ -714,4 +777,8 @@ img {
.play-button i {
font-size: 24px;
}
+
+ .video-title {
+ font-size: 16px;
+ }
}
\ No newline at end of file
diff --git a/css/video-page.css b/css/video-page.css
index 8387765..025edaa 100644
--- a/css/video-page.css
+++ b/css/video-page.css
@@ -10,6 +10,9 @@
.video-player-container {
grid-column: 1 / -1;
grid-row: 1;
+ max-width: 900px;
+ margin: 0 auto;
+ width: 100%;
}
.video-player {
@@ -54,6 +57,7 @@
.video-info {
display: flex;
+ flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
@@ -66,6 +70,8 @@
flex-direction: row;
align-items: center;
gap: 1rem;
+ margin-bottom: 0;
+ flex-wrap: nowrap;
}
.video-views, .video-date {
@@ -74,29 +80,41 @@
display: flex;
align-items: center;
gap: 5px;
+ height: 36px;
+ white-space: nowrap;
}
.video-views i, .video-date i {
font-size: 0.9375rem;
- color: #555;
+ color: var(--primary-red);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 20px;
}
.video-actions {
display: flex;
+ flex-direction: row;
gap: 1.5rem;
+ align-items: center;
+ flex-wrap: nowrap;
}
.action-button {
display: flex;
align-items: center;
+ justify-content: center;
background: none;
border: none;
cursor: pointer;
gap: 0.5rem;
font-size: 0.875rem;
- padding: 0.5rem;
+ padding: 0.5rem 0.75rem;
border-radius: 4px;
transition: background-color 0.2s;
+ height: 36px;
+ min-width: 80px;
}
.action-button:hover {
@@ -108,6 +126,12 @@
color: #444;
}
+.action-button span {
+ display: inline-flex;
+ align-items: center;
+ height: 100%;
+}
+
.video-secondary-info {
margin-bottom: 30px;
}
@@ -468,13 +492,15 @@
grid-template-columns: repeat(2, 1fr);
gap: 15px;
}
+
+ .video-player-container {
+ max-width: 100%;
+ }
}
@media (max-width: 768px) {
.video-player-container {
- margin-left: -20px;
- margin-right: -20px;
- width: calc(100% + 40px);
+ margin-bottom: 15px;
}
.video-player {
@@ -487,13 +513,23 @@
.video-info {
flex-direction: column;
- gap: 1rem;
align-items: flex-start;
}
-
+
+ .video-metadata {
+ width: 100%;
+ margin-bottom: 10px;
+ }
+
.video-actions {
width: 100%;
justify-content: space-between;
+ flex-wrap: wrap;
+ }
+
+ .action-button {
+ padding: 0.5rem;
+ min-width: 70px;
}
.suggestion-list {
@@ -506,30 +542,36 @@
display: flex;
flex-direction: column;
gap: 20px;
+ margin-top: 10px;
}
.video-player-container {
- width: 100vw;
- margin-left: -20px;
- margin-right: -20px;
+ order: 1;
+ margin-bottom: 0;
}
.video-content,
.video-suggestions {
+ order: 2;
width: 100%;
}
.video-title {
- font-size: 1.2rem;
+ font-size: 1.25rem;
}
.video-actions {
- flex-wrap: wrap;
- gap: 0.5rem;
+ justify-content: space-around;
}
.action-button {
- padding: 0.3rem;
+ font-size: 0.75rem;
+ min-width: 60px;
+ padding: 0.5rem 0.25rem;
+ }
+
+ .video-views, .video-date {
+ font-size: 0.8125rem;
}
.comment {
@@ -537,29 +579,20 @@
}
.comment-avatar {
- display: none;
+ margin-bottom: 10px;
}
.suggested-video {
- display: flex;
- flex-direction: row;
+ grid-template-columns: 120px 1fr;
}
.suggested-video-thumbnail {
width: 120px;
- min-width: 120px;
- height: 68px;
- padding-top: 0;
- margin-right: 10px;
- }
-
- .suggested-video-info {
- padding: 5px;
- width: calc(100% - 120px);
+ height: 67px;
}
.suggested-video-title {
- -webkit-line-clamp: 2;
+ font-size: 0.875rem;
}
}
diff --git a/includes/config.php b/includes/config.php
index a26c971..f371059 100644
--- a/includes/config.php
+++ b/includes/config.php
@@ -14,11 +14,12 @@ define('API_KEY', ''); // Laissez vide si pas nécessaire
// Pagination et affichage
define('VIDEOS_PER_PAGE', 12);
-define('FEATURED_VIDEOS_COUNT', 5);
-define('RECENT_VIDEOS_COUNT', 5);
-define('SHORTS_COUNT', 5);
-define('TRENDING_VIDEOS_COUNT', 5);
-define('INDEPENDENCE_VIDEOS_COUNT', 5);
+define('FEATURED_VIDEOS_COUNT',6);
+define('RECENT_VIDEOS_COUNT', 6);
+define('SHORTS_COUNT', 6);
+define('TRENDING_VIDEOS_COUNT', 6);
+define('INDEPENDENCE_VIDEOS_COUNT', 6);
+define('LOAD_MORE_COUNT', 6);
// Informations du site
define('SITE_NAME', 'Kaubuntu.re');
diff --git a/index.php b/index.php
index cfd5eca..7e90cfe 100644
--- a/index.php
+++ b/index.php
@@ -205,8 +205,8 @@
- vues
-
+ vues
+
@@ -251,8 +251,8 @@
- vues
-
+ vues
+
@@ -297,8 +297,8 @@
- vues
-
+ vues
+
diff --git a/js/main.js b/js/main.js
index cdbb4da..fe52795 100644
--- a/js/main.js
+++ b/js/main.js
@@ -65,58 +65,134 @@ document.addEventListener('DOMContentLoaded', function() {
});
// Gestion des clics sur les vidéos
- const videoCards = document.querySelectorAll('.video-card');
-
- videoCards.forEach(card => {
- card.addEventListener('click', function() {
- const videoId = this.dataset.videoId;
- if (videoId) {
- window.location.href = 'video.php?id=' + videoId;
- }
- });
- });
-
- // Lazy loading des images
- if ('IntersectionObserver' in window) {
- const imageObserver = new IntersectionObserver((entries, observer) => {
- entries.forEach(entry => {
- if (entry.isIntersecting) {
- const img = entry.target;
- const src = img.getAttribute('data-src');
- if (src) {
- img.src = src;
- img.removeAttribute('data-src');
- }
- observer.unobserve(img);
- }
- });
- });
+ function initVideoCardClicks() {
+ const videoCards = document.querySelectorAll('.video-card');
- document.querySelectorAll('img[data-src]').forEach(img => {
- imageObserver.observe(img);
- });
- } else {
- // Fallback pour les navigateurs qui ne supportent pas IntersectionObserver
- document.querySelectorAll('img[data-src]').forEach(img => {
- const src = img.getAttribute('data-src');
- if (src) {
- img.src = src;
- img.removeAttribute('data-src');
+ videoCards.forEach(card => {
+ if (!card.hasAttribute('data-click-initialized')) {
+ card.setAttribute('data-click-initialized', 'true');
+ card.addEventListener('click', function() {
+ const videoId = this.dataset.videoId;
+ if (videoId) {
+ window.location.href = 'video.php?id=' + videoId;
+ }
+ });
}
});
}
+ // Initialiser les clics sur les vidéos existantes
+ initVideoCardClicks();
+
+ // Lazy loading des images
+ function initLazyLoading() {
+ if ('IntersectionObserver' in window) {
+ const imageObserver = new IntersectionObserver((entries, observer) => {
+ entries.forEach(entry => {
+ if (entry.isIntersecting) {
+ const img = entry.target;
+ const src = img.getAttribute('data-src');
+ if (src) {
+ img.src = src;
+ img.removeAttribute('data-src');
+ }
+ observer.unobserve(img);
+ }
+ });
+ });
+
+ document.querySelectorAll('img[data-src]').forEach(img => {
+ imageObserver.observe(img);
+ });
+ } else {
+ // Fallback pour les navigateurs qui ne supportent pas IntersectionObserver
+ document.querySelectorAll('img[data-src]').forEach(img => {
+ const src = img.getAttribute('data-src');
+ if (src) {
+ img.src = src;
+ img.removeAttribute('data-src');
+ }
+ });
+ }
+ }
+
+ // Initialiser le lazy loading
+ initLazyLoading();
+
// Gestion des boutons "Voir plus"
const viewMoreButtons = document.querySelectorAll('.view-more');
viewMoreButtons.forEach(button => {
+ // Déterminer le type de vidéos à charger
+ const section = button.closest('.video-section');
+ const sectionTitle = section.querySelector('.section-title').textContent.trim().toLowerCase();
+ const videoGrid = section.querySelector('.video-grid');
+ let videoType = '';
+
+ if (sectionTitle.includes('dernières')) {
+ videoType = 'recent';
+ } else if (sectionTitle.includes('tendances')) {
+ videoType = 'trending';
+ } else if (sectionTitle.includes('indépendance')) {
+ videoType = 'independence';
+ }
+
+ // Stocker le numéro de page actuel
+ button.dataset.page = '1';
+
button.addEventListener('click', function() {
- // Dans un vrai projet, cela chargerait plus de contenu via AJAX
- // Pour cet exemple, on simule juste un clic
- button.innerText = 'Chargement...';
- setTimeout(() => {
- button.innerText = 'Voir plus';
- }, 1000);
+ const page = parseInt(this.dataset.page);
+
+ // Changer le texte du bouton pendant le chargement
+ button.textContent = 'Chargement...';
+ button.disabled = true;
+
+ // Faire la requête AJAX
+ fetch(`ajax/load-more-videos.php?type=${videoType}&page=${page}`, {
+ headers: {
+ 'X-Requested-With': 'XMLHttpRequest'
+ }
+ })
+ .then(response => response.json())
+ .then(data => {
+ if (data.success) {
+ // Ajouter les nouvelles vidéos à la grille
+ const tempDiv = document.createElement('div');
+ tempDiv.innerHTML = data.html;
+
+ // Ajouter chaque vidéo à la grille
+ while (tempDiv.firstChild) {
+ videoGrid.appendChild(tempDiv.firstChild);
+ }
+
+ // Mettre à jour le numéro de page
+ this.dataset.page = data.page + 1;
+
+ // Réinitialiser le texte du bouton
+ button.textContent = 'Voir plus';
+ button.disabled = false;
+
+ // Si plus de vidéos à charger, masquer le bouton
+ if (!data.hasMore) {
+ button.style.display = 'none';
+ }
+
+ // Initialiser les clics sur les nouvelles vidéos
+ initVideoCardClicks();
+ // Initialiser le lazy loading pour les nouvelles images
+ initLazyLoading();
+ } else {
+ // En cas d'erreur, afficher un message et réactiver le bouton
+ console.error('Erreur lors du chargement des vidéos:', data.error);
+ button.textContent = 'Voir plus';
+ button.disabled = false;
+ }
+ })
+ .catch(error => {
+ console.error('Erreur lors de la requête AJAX:', error);
+ button.textContent = 'Voir plus';
+ button.disabled = false;
+ });
});
});
});
\ No newline at end of file