latest update my Video Platform is working Great
This commit is contained in:
1 parent
dcdcafe0ba
commit
3aa49d638d
12 files changed
+440
-83
No files matched your search
@@ -16,6 +16,7 @@
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 3px solid var(--border-color);
|
||||
}
|
||||
|
||||
.channel-name {
|
||||
@@ -26,6 +27,7 @@
|
||||
|
||||
.channel-meta {
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.channel-stats {
|
||||
@@ -47,6 +49,11 @@
|
||||
|
||||
.yt-video-card {
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.yt-video-card:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.yt-video-thumb {
|
||||
@@ -110,6 +117,7 @@
|
||||
|
||||
.yt-video-details {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.yt-video-title {
|
||||
@@ -132,6 +140,9 @@
|
||||
.yt-channel-name, .yt-video-meta {
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* More button */
|
||||
@@ -142,6 +153,20 @@
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.yt-more-btn:hover {
|
||||
background: var(--border-color);
|
||||
}
|
||||
|
||||
.yt-more-btn:active {
|
||||
background: var(--border-color);
|
||||
}
|
||||
|
||||
.yt-more-dropdown {
|
||||
@@ -202,22 +227,290 @@
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
transition: transform 0.2s, background 0.2s;
|
||||
}
|
||||
|
||||
.yt-upload-btn:hover {
|
||||
background: #cc1a1a;
|
||||
}
|
||||
|
||||
.yt-upload-btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
/* Channel action buttons container */
|
||||
.channel-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
MOBILE RESPONSIVE STYLES
|
||||
============================================ */
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.channel-header {
|
||||
padding: 20px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.channel-avatar {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
|
||||
.channel-name {
|
||||
font-size: 20px;
|
||||
margin: 12px 0 4px;
|
||||
}
|
||||
|
||||
.channel-meta {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.channel-stats {
|
||||
gap: 16px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.yt-video-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.yt-video-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.yt-channel-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.yt-channel-name, .yt-video-meta {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.yt-more-btn {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.channel-actions {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.channel-actions .yt-upload-btn {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.channel-header {
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.channel-header .d-flex {
|
||||
flex-direction: column;
|
||||
align-items: flex-start !important;
|
||||
gap: 16px !important;
|
||||
}
|
||||
|
||||
.channel-avatar {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.channel-name {
|
||||
font-size: 18px;
|
||||
margin: 8px 0 4px;
|
||||
}
|
||||
|
||||
.channel-meta {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.channel-stats {
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.channel-stat-value {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.yt-video-grid {
|
||||
gap: 12px;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.yt-video-thumb {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.yt-video-info {
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.yt-channel-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.yt-video-details {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.yt-video-title {
|
||||
font-size: 13px;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.yt-empty {
|
||||
padding: 40px 16px;
|
||||
}
|
||||
|
||||
.yt-empty-icon {
|
||||
font-size: 60px;
|
||||
}
|
||||
|
||||
.yt-empty-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Very small screens */
|
||||
@media (max-width: 360px) {
|
||||
.channel-avatar {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.channel-name {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.channel-stats {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.yt-video-info {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.yt-video-details {
|
||||
max-width: calc(100% - 36px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Landscape mobile */
|
||||
@media (max-height: 500px) and (orientation: landscape) {
|
||||
.channel-header {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.channel-avatar {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.channel-name {
|
||||
font-size: 16px;
|
||||
margin: 8px 0 2px;
|
||||
}
|
||||
|
||||
.channel-meta {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.channel-stats {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.yt-video-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pagination improvements */
|
||||
.pagination {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.pagination .page-link {
|
||||
background: var(--bg-secondary);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-primary);
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.pagination .page-link:hover {
|
||||
background: var(--border-color);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.pagination .page-item.active .page-link {
|
||||
background: var(--brand-red);
|
||||
border-color: var(--brand-red);
|
||||
}
|
||||
|
||||
.pagination .page-item.disabled .page-link {
|
||||
background: var(--bg-secondary);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.pagination {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.pagination .page-link {
|
||||
padding: 6px 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.pagination .page-item:not(.active):not(.disabled) .page-link {
|
||||
min-width: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Smooth scroll behavior */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* Video card skeleton loading */
|
||||
.skeleton {
|
||||
background: linear-gradient(90deg, var(--bg-secondary) 25%, var(--border-color) 50%, var(--bg-secondary) 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s infinite;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
/* Mobile touch optimizations */
|
||||
@media (hover: none) {
|
||||
.yt-video-card:hover .yt-video-thumb video {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.yt-video-card.playing .yt-video-thumb video {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
@@ -231,7 +524,7 @@
|
||||
<img src="https://i.pravatar.cc/150?u={{ $user->id }}" alt="{{ $user->name }}" class="channel-avatar">
|
||||
@endif
|
||||
|
||||
<div>
|
||||
<div class="channel-info">
|
||||
<h1 class="channel-name">{{ $user->name }}</h1>
|
||||
<p class="channel-meta">Joined {{ $user->created_at->format('F d, Y') }}</p>
|
||||
|
||||
@@ -248,12 +541,12 @@
|
||||
|
||||
@auth
|
||||
@if(Auth::user()->id === $user->id)
|
||||
<div style="margin-top: 16px;">
|
||||
<div class="channel-actions">
|
||||
<a href="{{ route('videos.create') }}" class="yt-upload-btn">
|
||||
<i class="bi bi-plus-lg"></i> Upload Video
|
||||
<i class="bi bi-plus-lg"></i> <span>Upload Video</span>
|
||||
</a>
|
||||
<a href="{{ route('profile') }}" class="yt-upload-btn" style="background: var(--bg-dark); margin-left: 8px;">
|
||||
<i class="bi bi-pencil"></i> Edit Channel
|
||||
<a href="{{ route('profile') }}" class="yt-upload-btn" style="background: var(--bg-dark);">
|
||||
<i class="bi bi-pencil"></i> <span>Edit Channel</span>
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
@@ -390,14 +683,21 @@
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
let currentPlayingVideo = null;
|
||||
|
||||
function playVideo(card) {
|
||||
// Skip on touch devices - handled by touch events
|
||||
if ('ontouchstart' in window) return;
|
||||
|
||||
const video = card.querySelector('video');
|
||||
if (video) {
|
||||
video.currentTime = 0;
|
||||
video.volume = 0.10;
|
||||
video.play().catch(function(e) {
|
||||
// Auto-play may be blocked, ignore error
|
||||
});
|
||||
video.classList.add('active');
|
||||
currentPlayingVideo = card;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,6 +710,55 @@ function stopVideo(card) {
|
||||
}
|
||||
}
|
||||
|
||||
// Desktop hover behavior
|
||||
document.querySelectorAll('.yt-video-card').forEach(function(card) {
|
||||
card.addEventListener('mouseenter', function() {
|
||||
playVideo(this);
|
||||
});
|
||||
card.addEventListener('mouseleave', function() {
|
||||
stopVideo(this);
|
||||
});
|
||||
});
|
||||
|
||||
// Mobile touch support with tap-to-play/pause
|
||||
document.addEventListener('touchstart', function(e) {
|
||||
const card = e.target.closest('.yt-video-card');
|
||||
if (card) {
|
||||
// Stop currently playing video if different
|
||||
if (currentPlayingVideo && currentPlayingVideo !== card) {
|
||||
stopVideo(currentPlayingVideo);
|
||||
}
|
||||
|
||||
const video = card.querySelector('video');
|
||||
if (video) {
|
||||
if (card.classList.contains('playing')) {
|
||||
// Pause this video
|
||||
video.pause();
|
||||
card.classList.remove('playing');
|
||||
} else {
|
||||
// Play this video
|
||||
video.currentTime = 0;
|
||||
video.volume = 0.10;
|
||||
video.play().catch(function(e) {});
|
||||
video.classList.add('active');
|
||||
card.classList.add('playing');
|
||||
currentPlayingVideo = card;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, { passive: true });
|
||||
|
||||
// Stop video when tapping outside
|
||||
document.addEventListener('touchstart', function(e) {
|
||||
if (!e.target.closest('.yt-video-card')) {
|
||||
if (currentPlayingVideo) {
|
||||
stopVideo(currentPlayingVideo);
|
||||
currentPlayingVideo.classList.remove('playing');
|
||||
currentPlayingVideo = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function deleteVideo(videoId, videoTitle) {
|
||||
if (confirm('Are you sure you want to delete "' + videoTitle + '"? This action cannot be undone.')) {
|
||||
fetch(`/videos/${videoId}`, {
|
||||
@@ -423,7 +772,6 @@ function deleteVideo(videoId, videoTitle) {
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success || data.redirect) {
|
||||
// Reload the page to show updated video list
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert('Failed to delete video. Please try again.');
|
||||
@@ -435,6 +783,14 @@ function deleteVideo(videoId, videoTitle) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Smooth scroll for pagination on mobile
|
||||
document.querySelectorAll('.pagination a').forEach(function(link) {
|
||||
link.addEventListener('click', function(e) {
|
||||
// Add loading indicator
|
||||
document.querySelector('.yt-video-grid').style.opacity = '0.5';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
Reference in new issue
Block a user