fix load more and improve vide page

This commit is contained in:
2025-04-08 10:49:46 +04:00
parent a227247f57
commit 133b2e9d5e
6 changed files with 361 additions and 92 deletions
+92
View File
@@ -0,0 +1,92 @@
<?php
// Inclure la configuration
require_once '../includes/config.php';
// Vérifier que la requête est faite par AJAX
if (!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) !== 'xmlhttprequest') {
http_response_code(403); // Accès non autorisé
echo json_encode(['error' => '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 .= '<div class="video-card" data-video-id="' . $video['id'] . '">';
$html .= ' <div class="video-thumbnail">';
$html .= ' <img src="' . $video['thumbnail'] . '" alt="' . htmlspecialchars($video['title']) . '">';
$html .= ' <div class="video-play-icon">';
$html .= ' <i class="fas fa-play-circle"></i>';
$html .= ' </div>';
$html .= ' <div class="video-duration">' . formatDuration($video['duration']) . '</div>';
$html .= ' </div>';
$html .= ' <div class="video-info">';
$html .= ' <h3 class="video-title">' . htmlspecialchars($video['title']) . '</h3>';
$html .= ' <div class="video-channel">' . htmlspecialchars($video['channel']) . '</div>';
$html .= ' <div class="video-metadata">';
$html .= ' <span class="video-views"><i class="fas fa-eye"></i> ' . formatViewCount($video['views']) . ' vues</span>';
$html .= ' <span class="video-date"><i class="far fa-calendar-alt"></i> ' . formatDate($video['date']) . '</span>';
$html .= ' </div>';
$html .= ' </div>';
$html .= '</div>';
}
// Retourner la réponse
echo json_encode([
'success' => true,
'html' => $html,
'page' => $page,
'hasMore' => count($videos) >= LOAD_MORE_COUNT
]);
?>
+79 -12
View File
@@ -325,11 +325,12 @@ img {
/* Video Sections */ /* Video Sections */
.video-section { .video-section {
margin-bottom: 40px; margin-bottom: 40px;
position: relative;
} }
.video-grid { .video-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); grid-template-columns: repeat(3, 1fr);
gap: 20px; gap: 20px;
} }
@@ -340,6 +341,9 @@ img {
box-shadow: var(--card-shadow); box-shadow: var(--card-shadow);
transition: transform 0.3s; transition: transform 0.3s;
cursor: pointer; cursor: pointer;
height: 100%;
display: flex;
flex-direction: column;
} }
.video-card:hover { .video-card:hover {
@@ -349,6 +353,7 @@ img {
.video-thumbnail { .video-thumbnail {
position: relative; position: relative;
padding-top: 56.25%; /* 16:9 aspect ratio */ padding-top: 56.25%; /* 16:9 aspect ratio */
overflow: hidden;
} }
.video-thumbnail img { .video-thumbnail img {
@@ -377,6 +382,9 @@ img {
.video-info { .video-info {
padding: 15px; padding: 15px;
flex-grow: 1;
display: flex;
flex-direction: column;
} }
.video-title { .video-title {
@@ -388,6 +396,16 @@ img {
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; 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 { .video-metadata {
@@ -396,6 +414,31 @@ img {
justify-content: space-between; justify-content: space-between;
font-size: 12px; font-size: 12px;
color: #666; 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 { .video-tag {
@@ -407,24 +450,23 @@ img {
margin-right: 5px; margin-right: 5px;
} }
.video-date, .video-views {
font-size: 12px;
}
/* Carousel */ /* Carousel */
.carousel { .carousel {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
margin: 15px 0 30px;
padding: 10px 0;
} }
.carousel-container { .carousel-container {
display: flex; display: flex;
transition: transform 0.5s ease; transition: transform 0.5s ease;
padding-bottom: 10px;
} }
.carousel-item { .carousel-item {
flex: 0 0 auto; flex: 0 0 auto;
width: 280px; width: 220px;
margin-right: 20px; margin-right: 20px;
} }
@@ -441,28 +483,43 @@ img {
background-color: #ccc; background-color: #ccc;
margin: 0 5px; margin: 0 5px;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease;
} }
.carousel-dot.active { .carousel-dot.active {
background-color: var(--primary-red); background-color: var(--primary-red);
transform: scale(1.2);
} }
/* View More Button */ /* View More Button */
.view-more { .view-more {
display: block; display: block;
width: max-content; width: max-content;
margin: 20px auto; margin: 25px auto 5px;
padding: 10px 25px; padding: 12px 30px;
background-color: var(--search-bg); background-color: var(--primary-red);
color: white;
border: none; border: none;
border-radius: 4px; border-radius: 4px;
font-size: 16px; font-size: 16px;
font-weight: 500;
cursor: pointer; cursor: pointer;
transition: background-color 0.2s; transition: all 0.2s;
text-transform: uppercase;
letter-spacing: 1px;
} }
.view-more:hover { .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 */ /* Info Section */
@@ -689,13 +746,19 @@ img {
@media (max-width: 992px) { @media (max-width: 992px) {
.video-grid { .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) { @media (max-width: 576px) {
.video-grid { .video-grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: 15px;
} }
.section-title { .section-title {
@@ -714,4 +777,8 @@ img {
.play-button i { .play-button i {
font-size: 24px; font-size: 24px;
} }
.video-title {
font-size: 16px;
}
} }
+60 -27
View File
@@ -10,6 +10,9 @@
.video-player-container { .video-player-container {
grid-column: 1 / -1; grid-column: 1 / -1;
grid-row: 1; grid-row: 1;
max-width: 900px;
margin: 0 auto;
width: 100%;
} }
.video-player { .video-player {
@@ -54,6 +57,7 @@
.video-info { .video-info {
display: flex; display: flex;
flex-direction: row;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
@@ -66,6 +70,8 @@
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
gap: 1rem; gap: 1rem;
margin-bottom: 0;
flex-wrap: nowrap;
} }
.video-views, .video-date { .video-views, .video-date {
@@ -74,29 +80,41 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
height: 36px;
white-space: nowrap;
} }
.video-views i, .video-date i { .video-views i, .video-date i {
font-size: 0.9375rem; font-size: 0.9375rem;
color: #555; color: var(--primary-red);
display: flex;
align-items: center;
justify-content: center;
width: 20px;
} }
.video-actions { .video-actions {
display: flex; display: flex;
flex-direction: row;
gap: 1.5rem; gap: 1.5rem;
align-items: center;
flex-wrap: nowrap;
} }
.action-button { .action-button {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center;
background: none; background: none;
border: none; border: none;
cursor: pointer; cursor: pointer;
gap: 0.5rem; gap: 0.5rem;
font-size: 0.875rem; font-size: 0.875rem;
padding: 0.5rem; padding: 0.5rem 0.75rem;
border-radius: 4px; border-radius: 4px;
transition: background-color 0.2s; transition: background-color 0.2s;
height: 36px;
min-width: 80px;
} }
.action-button:hover { .action-button:hover {
@@ -108,6 +126,12 @@
color: #444; color: #444;
} }
.action-button span {
display: inline-flex;
align-items: center;
height: 100%;
}
.video-secondary-info { .video-secondary-info {
margin-bottom: 30px; margin-bottom: 30px;
} }
@@ -468,13 +492,15 @@
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 15px; gap: 15px;
} }
.video-player-container {
max-width: 100%;
}
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.video-player-container { .video-player-container {
margin-left: -20px; margin-bottom: 15px;
margin-right: -20px;
width: calc(100% + 40px);
} }
.video-player { .video-player {
@@ -487,13 +513,23 @@
.video-info { .video-info {
flex-direction: column; flex-direction: column;
gap: 1rem;
align-items: flex-start; align-items: flex-start;
} }
.video-metadata {
width: 100%;
margin-bottom: 10px;
}
.video-actions { .video-actions {
width: 100%; width: 100%;
justify-content: space-between; justify-content: space-between;
flex-wrap: wrap;
}
.action-button {
padding: 0.5rem;
min-width: 70px;
} }
.suggestion-list { .suggestion-list {
@@ -506,30 +542,36 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 20px; gap: 20px;
margin-top: 10px;
} }
.video-player-container { .video-player-container {
width: 100vw; order: 1;
margin-left: -20px; margin-bottom: 0;
margin-right: -20px;
} }
.video-content, .video-content,
.video-suggestions { .video-suggestions {
order: 2;
width: 100%; width: 100%;
} }
.video-title { .video-title {
font-size: 1.2rem; font-size: 1.25rem;
} }
.video-actions { .video-actions {
flex-wrap: wrap; justify-content: space-around;
gap: 0.5rem;
} }
.action-button { .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 { .comment {
@@ -537,29 +579,20 @@
} }
.comment-avatar { .comment-avatar {
display: none; margin-bottom: 10px;
} }
.suggested-video { .suggested-video {
display: flex; grid-template-columns: 120px 1fr;
flex-direction: row;
} }
.suggested-video-thumbnail { .suggested-video-thumbnail {
width: 120px; width: 120px;
min-width: 120px; height: 67px;
height: 68px;
padding-top: 0;
margin-right: 10px;
}
.suggested-video-info {
padding: 5px;
width: calc(100% - 120px);
} }
.suggested-video-title { .suggested-video-title {
-webkit-line-clamp: 2; font-size: 0.875rem;
} }
} }
+6 -5
View File
@@ -14,11 +14,12 @@ define('API_KEY', ''); // Laissez vide si pas nécessaire
// Pagination et affichage // Pagination et affichage
define('VIDEOS_PER_PAGE', 12); define('VIDEOS_PER_PAGE', 12);
define('FEATURED_VIDEOS_COUNT', 5); define('FEATURED_VIDEOS_COUNT',6);
define('RECENT_VIDEOS_COUNT', 5); define('RECENT_VIDEOS_COUNT', 6);
define('SHORTS_COUNT', 5); define('SHORTS_COUNT', 6);
define('TRENDING_VIDEOS_COUNT', 5); define('TRENDING_VIDEOS_COUNT', 6);
define('INDEPENDENCE_VIDEOS_COUNT', 5); define('INDEPENDENCE_VIDEOS_COUNT', 6);
define('LOAD_MORE_COUNT', 6);
// Informations du site // Informations du site
define('SITE_NAME', 'Kaubuntu.re'); define('SITE_NAME', 'Kaubuntu.re');
+6 -6
View File
@@ -205,8 +205,8 @@
<h3 class="video-title"><?php echo $video['title']; ?></h3> <h3 class="video-title"><?php echo $video['title']; ?></h3>
<div class="video-channel"><?php echo $video['channel']; ?></div> <div class="video-channel"><?php echo $video['channel']; ?></div>
<div class="video-metadata"> <div class="video-metadata">
<span class="video-views"><?php echo formatViewCount($video['views']); ?> vues</span> <span class="video-views"><i class="fas fa-eye"></i> <?php echo formatViewCount($video['views']); ?> vues</span>
<span class="video-date"><?php echo formatDate($video['date']); ?></span> <span class="video-date"><i class="far fa-calendar-alt"></i> <?php echo formatDate($video['date']); ?></span>
</div> </div>
</div> </div>
</div> </div>
@@ -251,8 +251,8 @@
<h3 class="video-title"><?php echo $video['title']; ?></h3> <h3 class="video-title"><?php echo $video['title']; ?></h3>
<div class="video-channel"><?php echo $video['channel']; ?></div> <div class="video-channel"><?php echo $video['channel']; ?></div>
<div class="video-metadata"> <div class="video-metadata">
<span class="video-views"><?php echo formatViewCount($video['views']); ?> vues</span> <span class="video-views"><i class="fas fa-eye"></i> <?php echo formatViewCount($video['views']); ?> vues</span>
<span class="video-date"><?php echo formatDate($video['date']); ?></span> <span class="video-date"><i class="far fa-calendar-alt"></i> <?php echo formatDate($video['date']); ?></span>
</div> </div>
</div> </div>
</div> </div>
@@ -297,8 +297,8 @@
<h3 class="video-title"><?php echo $video['title']; ?></h3> <h3 class="video-title"><?php echo $video['title']; ?></h3>
<div class="video-channel"><?php echo $video['channel']; ?></div> <div class="video-channel"><?php echo $video['channel']; ?></div>
<div class="video-metadata"> <div class="video-metadata">
<span class="video-views"><?php echo formatViewCount($video['views']); ?> vues</span> <span class="video-views"><i class="fas fa-eye"></i> <?php echo formatViewCount($video['views']); ?> vues</span>
<span class="video-date"><?php echo formatDate($video['date']); ?></span> <span class="video-date"><i class="far fa-calendar-alt"></i> <?php echo formatDate($video['date']); ?></span>
</div> </div>
</div> </div>
</div> </div>
+118 -42
View File
@@ -65,58 +65,134 @@ document.addEventListener('DOMContentLoaded', function() {
}); });
// Gestion des clics sur les vidéos // Gestion des clics sur les vidéos
const videoCards = document.querySelectorAll('.video-card'); function initVideoCardClicks() {
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);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => { videoCards.forEach(card => {
imageObserver.observe(img); if (!card.hasAttribute('data-click-initialized')) {
}); card.setAttribute('data-click-initialized', 'true');
} else { card.addEventListener('click', function() {
// Fallback pour les navigateurs qui ne supportent pas IntersectionObserver const videoId = this.dataset.videoId;
document.querySelectorAll('img[data-src]').forEach(img => { if (videoId) {
const src = img.getAttribute('data-src'); window.location.href = 'video.php?id=' + videoId;
if (src) { }
img.src = src; });
img.removeAttribute('data-src');
} }
}); });
} }
// 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" // Gestion des boutons "Voir plus"
const viewMoreButtons = document.querySelectorAll('.view-more'); const viewMoreButtons = document.querySelectorAll('.view-more');
viewMoreButtons.forEach(button => { 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() { button.addEventListener('click', function() {
// Dans un vrai projet, cela chargerait plus de contenu via AJAX const page = parseInt(this.dataset.page);
// Pour cet exemple, on simule juste un clic
button.innerText = 'Chargement...'; // Changer le texte du bouton pendant le chargement
setTimeout(() => { button.textContent = 'Chargement...';
button.innerText = 'Voir plus'; button.disabled = true;
}, 1000);
// 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;
});
}); });
}); });
}); });