latest update
This commit is contained in:
1 parent
9ad842dcd5
commit
062c0e896f
42 files changed
+7052
-2921
No files matched your search
@@ -10,7 +10,7 @@
|
||||
padding: 32px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
|
||||
.channel-avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
@@ -18,44 +18,44 @@
|
||||
object-fit: cover;
|
||||
border: 3px solid var(--border-color);
|
||||
}
|
||||
|
||||
|
||||
.channel-name {
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
margin: 16px 0 4px;
|
||||
}
|
||||
|
||||
|
||||
.channel-meta {
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
.channel-stats {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
|
||||
.channel-stat-value {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
||||
/* Video Grid */
|
||||
.yt-video-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
|
||||
.yt-video-card {
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
|
||||
.yt-video-card:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
|
||||
.yt-video-thumb {
|
||||
position: relative;
|
||||
aspect-ratio: 16/9;
|
||||
@@ -63,7 +63,7 @@
|
||||
overflow: hidden;
|
||||
background: #1a1a1a;
|
||||
}
|
||||
|
||||
|
||||
.yt-video-thumb img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -72,7 +72,7 @@
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
|
||||
.yt-video-thumb video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -84,11 +84,11 @@
|
||||
transition: opacity 0.3s ease;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
|
||||
.yt-video-thumb video.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
.yt-video-duration {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
@@ -100,13 +100,13 @@
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
||||
.yt-video-info {
|
||||
display: flex;
|
||||
margin-top: 12px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
|
||||
.yt-channel-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
@@ -114,12 +114,12 @@
|
||||
background: #555;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
||||
.yt-video-details {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
|
||||
.yt-video-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
@@ -131,12 +131,12 @@
|
||||
overflow: hidden;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
|
||||
.yt-video-title a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
.yt-channel-name, .yt-video-meta {
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
@@ -144,7 +144,7 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
/* More button */
|
||||
.yt-more-btn {
|
||||
background: transparent;
|
||||
@@ -160,15 +160,15 @@
|
||||
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 {
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border-color);
|
||||
@@ -176,7 +176,7 @@
|
||||
padding: 8px 0;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
|
||||
.yt-more-dropdown-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -191,30 +191,30 @@
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
.yt-more-dropdown-item:hover { background: var(--border-color); }
|
||||
|
||||
|
||||
/* Empty State */
|
||||
.yt-empty {
|
||||
text-align: center;
|
||||
padding: 80px 20px;
|
||||
}
|
||||
|
||||
|
||||
.yt-empty-icon {
|
||||
font-size: 80px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
|
||||
.yt-empty-title {
|
||||
font-size: 24px;
|
||||
margin: 20px 0 8px;
|
||||
}
|
||||
|
||||
|
||||
.yt-empty-text {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
|
||||
.yt-upload-btn {
|
||||
background: var(--brand-red);
|
||||
color: white;
|
||||
@@ -229,15 +229,15 @@
|
||||
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;
|
||||
@@ -245,250 +245,250 @@
|
||||
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: 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%);
|
||||
@@ -496,18 +496,18 @@
|
||||
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;
|
||||
}
|
||||
@@ -523,11 +523,11 @@
|
||||
@else
|
||||
<img src="https://i.pravatar.cc/150?u={{ $user->id }}" alt="{{ $user->name }}" class="channel-avatar">
|
||||
@endif
|
||||
|
||||
|
||||
<div class="channel-info">
|
||||
<h1 class="channel-name">{{ $user->name }}</h1>
|
||||
<p class="channel-meta">Joined {{ $user->created_at->format('F d, Y') }}</p>
|
||||
|
||||
|
||||
<div class="channel-stats">
|
||||
<div>
|
||||
<span class="channel-stat-value">{{ $videos->total() }}</span>
|
||||
@@ -538,7 +538,7 @@
|
||||
<span class="channel-meta"> views</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@auth
|
||||
@if(Auth::user()->id === $user->id)
|
||||
<div class="channel-actions">
|
||||
@@ -554,7 +554,42 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Playlists Section - Only show for own channel -->
|
||||
@auth
|
||||
@if(Auth::user()->id === $user->id && $playlists && $playlists->count() > 0)
|
||||
<div class="playlists-section" style="margin-bottom: 24px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
|
||||
<h2 style="font-size: 20px; font-weight: 500;">My Playlists</h2>
|
||||
<a href="{{ route('playlists.index') }}" style="color: var(--text-secondary); text-decoration: none; font-size: 14px;">
|
||||
View all <i class="bi bi-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px;">
|
||||
@foreach($playlists->take(6) as $playlist)
|
||||
<a href="{{ route('playlists.show', $playlist->id) }}" class="playlist-card-mini" style="text-decoration: none; color: inherit;">
|
||||
<div class="playlist-thumb-mini" style="position: relative; aspect-ratio: 16/9; background: var(--bg-secondary); border-radius: 8px; overflow: hidden; margin-bottom: 8px;">
|
||||
@if($playlist->thumbnail_url)
|
||||
<img src="{{ $playlist->thumbnail_url }}" alt="{{ $playlist->name }}" style="width: 100%; height: 100%; object-fit: cover;">
|
||||
@else
|
||||
<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-secondary);">
|
||||
<i class="bi bi-collection-play" style="font-size: 32px;"></i>
|
||||
</div>
|
||||
@endif
|
||||
<span class="playlist-count" style="position: absolute; bottom: 4px; right: 4px; background: rgba(0,0,0,0.8); color: white; padding: 2px 6px; border-radius: 4px; font-size: 12px; font-weight: 500;">
|
||||
{{ $playlist->video_count }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="playlist-name-mini" style="font-size: 14px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
||||
{{ $playlist->name }}
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endauth
|
||||
|
||||
@if($videos->isEmpty())
|
||||
<div class="yt-empty">
|
||||
<i class="bi bi-camera-video yt-empty-icon"></i>
|
||||
@@ -574,10 +609,10 @@
|
||||
<x-video-card :video="$video" size="small" />
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-4">{{ $videos->links() }}</div>
|
||||
@endif
|
||||
|
||||
|
||||
@include('layouts.partials.share-modal')
|
||||
@endsection
|
||||
|
||||
@@ -588,7 +623,7 @@ 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;
|
||||
@@ -628,7 +663,7 @@ document.addEventListener('touchstart', function(e) {
|
||||
if (currentPlayingVideo && currentPlayingVideo !== card) {
|
||||
stopVideo(currentPlayingVideo);
|
||||
}
|
||||
|
||||
|
||||
const video = card.querySelector('video');
|
||||
if (video) {
|
||||
if (card.classList.contains('playing')) {
|
||||
|
||||
@@ -4,193 +4,187 @@
|
||||
|
||||
@section('extra_styles')
|
||||
<style>
|
||||
.profile-header {
|
||||
background: var(--bg-secondary);
|
||||
border-radius: 12px;
|
||||
padding: 32px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.profile-avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.profile-name {
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.profile-email {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.profile-stats {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.profile-stat {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.profile-stat-value {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.profile-stat-label {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.form-card {
|
||||
background: var(--bg-secondary);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
background: #121212;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
padding: 12px 16px;
|
||||
color: var(--text-primary);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--brand-red);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--brand-red);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 24px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #cc1a1a;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background: rgba(34, 197, 94, 0.2);
|
||||
border: 1px solid #22c55e;
|
||||
color: #22c55e;
|
||||
}
|
||||
.profile-header { background: var(--bg-secondary); border-radius: 12px; padding: 32px; margin-bottom: 24px; position: relative; overflow: hidden; }
|
||||
.profile-banner { position: absolute; top: 0; left: 0; right: 0; height: 120px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); z-index: 0; }
|
||||
.profile-content { position: relative; z-index: 1; margin-top: 60px; }
|
||||
.profile-avatar { width: 120px; height: 120px; border-radius: 50%; object-fit: cover; border: 4px solid var(--bg-secondary); margin-bottom: 16px; }
|
||||
.profile-name { font-size: 28px; font-weight: 600; margin-bottom: 4px; }
|
||||
.profile-username { color: var(--text-secondary); margin-bottom: 12px; font-size: 14px; }
|
||||
.profile-bio { color: var(--text-primary); margin-bottom: 16px; max-width: 600px; line-height: 1.6; }
|
||||
.profile-meta { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 20px; color: var(--text-secondary); font-size: 14px; }
|
||||
.profile-meta-item { display: flex; align-items: center; gap: 6px; }
|
||||
.profile-stats { display: flex; gap: 32px; margin-top: 16px; padding-top: 20px; border-top: 1px solid var(--border-color); }
|
||||
.profile-stat { text-align: center; }
|
||||
.profile-stat-value { font-size: 22px; font-weight: 700; }
|
||||
.profile-stat-label { font-size: 13px; color: var(--text-secondary); }
|
||||
.social-links { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 16px; }
|
||||
.social-link { display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; background: var(--bg-primary); color: var(--text-primary); text-decoration: none; transition: all 0.2s; font-size: 18px; }
|
||||
.social-link:hover { transform: translateY(-2px); background: var(--brand-red); color: white; }
|
||||
.social-link.twitter:hover { background: #1da1f2; }
|
||||
.social-link.instagram:hover { background: #e4405f; }
|
||||
.social-link.facebook:hover { background: #1877f2; }
|
||||
.social-link.youtube:hover { background: #ff0000; }
|
||||
.social-link.linkedin:hover { background: #0077b5; }
|
||||
.social-link.tiktok:hover { background: #000000; }
|
||||
.form-card { background: var(--bg-secondary); border-radius: 12px; padding: 24px; margin-bottom: 24px; }
|
||||
.form-title { font-size: 18px; font-weight: 600; margin-bottom: 20px; padding-bottom: 12px; border-bottom: 1px solid var(--border-color); display: flex; align-items: center; gap: 8px; }
|
||||
.form-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; }
|
||||
.form-group { margin-bottom: 16px; }
|
||||
.form-label { display: block; margin-bottom: 8px; font-weight: 500; font-size: 14px; }
|
||||
.form-input, .form-textarea { width: 100%; background: #121212; border: 1px solid var(--border-color); border-radius: 8px; padding: 12px 16px; color: var(--text-primary); font-size: 14px; transition: border-color 0.2s; }
|
||||
.form-input:focus, .form-textarea:focus { outline: none; border-color: var(--brand-red); }
|
||||
.form-textarea { min-height: 100px; resize: vertical; }
|
||||
.form-hint { font-size: 12px; color: var(--text-secondary); margin-top: 4px; }
|
||||
.btn-primary { background: var(--brand-red); color: white; border: none; padding: 12px 32px; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; transition: background 0.2s; display: inline-flex; align-items: center; gap: 8px; }
|
||||
.btn-primary:hover { background: #cc1a1a; }
|
||||
.btn-secondary { background: transparent; color: var(--text-primary); border: 1px solid var(--border-color); padding: 12px 24px; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; transition: all 0.2s; display: inline-flex; align-items: center; gap: 8px; text-decoration: none; }
|
||||
.btn-secondary:hover { background: var(--bg-secondary); border-color: var(--text-secondary); }
|
||||
.alert { padding: 12px 16px; border-radius: 8px; margin-bottom: 20px; }
|
||||
.alert-success { background: rgba(34, 197, 94, 0.15); border: 1px solid #22c55e; color: #22c55e; }
|
||||
.section-title { font-size: 20px; font-weight: 600; margin-bottom: 20px; display: flex; align-items: center; gap: 8px; }
|
||||
.video-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 20px; }
|
||||
.empty-state { text-align: center; padding: 40px 20px; color: var(--text-secondary); }
|
||||
.empty-state i { font-size: 48px; margin-bottom: 16px; opacity: 0.5; }
|
||||
.w-100 { width: 100%; }
|
||||
.mt-4 { margin-top: 24px; }
|
||||
.text-center { text-align: center; }
|
||||
.gap-3 { gap: 12px; }
|
||||
.d-flex { display: flex; }
|
||||
.flex-column { flex-direction: column; }
|
||||
.video-card { background: var(--bg-primary); border-radius: 8px; overflow: hidden; transition: transform 0.2s; }
|
||||
.video-card:hover { transform: translateY(-4px); }
|
||||
.video-thumbnail { position: relative; aspect-ratio: 16/9; background: #000; }
|
||||
.video-thumbnail img { width: 100%; height: 100%; object-fit: cover; }
|
||||
.video-duration { position: absolute; bottom: 8px; right: 8px; background: rgba(0,0,0,0.8); color: white; padding: 2px 6px; border-radius: 4px; font-size: 12px; }
|
||||
.video-info { padding: 12px; }
|
||||
.video-title { font-size: 14px; font-weight: 500; margin-bottom: 6px; line-height: 1.4; }
|
||||
.video-title a { color: var(--text-primary); text-decoration: none; }
|
||||
.video-title a:hover { color: var(--brand-red); }
|
||||
.video-meta { font-size: 12px; color: var(--text-secondary); }
|
||||
@media (max-width: 768px) { .profile-stats { justify-content: center; } .profile-meta { justify-content: center; } .social-links { justify-content: center; } }
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="profile-header text-center">
|
||||
@if($user->avatar)
|
||||
<img src="{{ asset('storage/avatars/' . $user->avatar) }}" alt="{{ $user->name }}" class="profile-avatar">
|
||||
@else
|
||||
<img src="https://i.pravatar.cc/150?u={{ $user->id }}" alt="{{ $user->name }}" class="profile-avatar">
|
||||
@endif
|
||||
|
||||
<h1 class="profile-name">{{ $user->name }}</h1>
|
||||
<p class="profile-email">{{ $user->email }}</p>
|
||||
|
||||
<div class="profile-stats justify-content-center">
|
||||
<div class="profile-stat">
|
||||
<div class="profile-stat-value">{{ $user->videos->count() }}</div>
|
||||
<div class="profile-stat-label">Videos</div>
|
||||
<div class="profile-header">
|
||||
<div class="profile-banner"></div>
|
||||
<div class="profile-content text-center">
|
||||
@if($user->avatar)
|
||||
<img src="{{ asset('storage/avatars/' . $user->avatar) }}" alt="{{ $user->name }}" class="profile-avatar">
|
||||
@else
|
||||
<img src="https://i.pravatar.cc/150?u={{ $user->id }}" alt="{{ $user->name }}" class="profile-avatar">
|
||||
@endif
|
||||
<h1 class="profile-name">{{ $user->name }}</h1>
|
||||
@if($user->username)
|
||||
<p class="profile-username">@ {{ $user->username }}</p>
|
||||
@endif
|
||||
@if($user->bio)
|
||||
<p class="profile-bio">{{ $user->bio }}</p>
|
||||
@endif
|
||||
<div class="profile-meta justify-content-center">
|
||||
@if($user->location)
|
||||
<div class="profile-meta-item"><i class="bi bi-geo-alt"></i><span>{{ $user->location }}</span></div>
|
||||
@endif
|
||||
@if($user->website)
|
||||
<div class="profile-meta-item"><i class="bi bi-link-45deg"></i><a href="{{ $user->website_url }}" target="_blank" style="color: inherit;">{{ Str::limit($user->website, 30) }}</a></div>
|
||||
@endif
|
||||
<div class="profile-meta-item"><i class="bi bi-calendar3"></i><span>Joined {{ $user->created_at->format('M Y') }}</span></div>
|
||||
</div>
|
||||
<div class="profile-stat">
|
||||
<div class="profile-stat-value">{{ $user->likes->count() }}</div>
|
||||
<div class="profile-stat-label">Likes</div>
|
||||
</div>
|
||||
<div class="profile-stat">
|
||||
<div class="profile-stat-value">{{ \DB::table('video_views')->whereIn('video_id', $user->videos->pluck('id'))->count() }}</div>
|
||||
<div class="profile-stat-label">Total Views</div>
|
||||
@if($user->hasSocialLinks())
|
||||
<div class="social-links justify-content-center">
|
||||
@if($user->twitter)<a href="https://twitter.com/{{ $user->twitter }}" target="_blank" class="social-link twitter" title="Twitter"><i class="bi bi-twitter-x"></i></a>@endif
|
||||
@if($user->instagram)<a href="https://instagram.com/{{ $user->instagram }}" target="_blank" class="social-link instagram" title="Instagram"><i class="bi bi-instagram"></i></a>@endif
|
||||
@if($user->facebook)<a href="https://facebook.com/{{ $user->facebook }}" target="_blank" class="social-link facebook" title="Facebook"><i class="bi bi-facebook"></i></a>@endif
|
||||
@if($user->youtube)<a href="https://youtube.com/@{{ $user->youtube }}" target="_blank" class="social-link youtube" title="YouTube"><i class="bi bi-youtube"></i></a>@endif
|
||||
@if($user->linkedin)<a href="https://linkedin.com/in/{{ $user->linkedin }}" target="_blank" class="social-link linkedin" title="LinkedIn"><i class="bi bi-linkedin"></i></a>@endif
|
||||
@if($user->tiktok)<a href="https://tiktok.com/@{{ $user->tiktok }}" target="_blank" class="social-link tiktok" title="TikTok"><i class="bi bi-tiktok"></i></a>@endif
|
||||
@if($user->website)<a href="{{ $user->website_url }}" target="_blank" class="social-link" title="Website"><i class="bi bi-globe"></i></a>@endif
|
||||
</div>
|
||||
@endif
|
||||
<div class="profile-stats justify-content-center">
|
||||
<a href="{{ route('channel', $user->id) }}" class="profile-stat"><div class="profile-stat-value">{{ $user->videos->count() }}</div><div class="profile-stat-label">Videos</div></a>
|
||||
<div class="profile-stat"><div class="profile-stat-value">{{ number_format($user->subscriber_count) }}</div><div class="profile-stat-label">Subscribers</div></div>
|
||||
<div class="profile-stat"><div class="profile-stat-value">{{ \DB::table('video_views')->whereIn('video_id', $user->videos->pluck('id'))->count() }}</div><div class="profile-stat-label">Views</div></div>
|
||||
<div class="profile-stat"><div class="profile-stat-value">{{ $user->likes->count() }}</div><div class="profile-stat-label">Likes</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="col-lg-8">
|
||||
<div class="form-card">
|
||||
<h2 class="form-title">Edit Profile</h2>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('success') }}
|
||||
<h2 class="section-title"><i class="bi bi-play-circle"></i> Recent Videos</h2>
|
||||
@if($user->videos->count() > 0)
|
||||
<div class="video-grid">
|
||||
@foreach($user->videos->take(4) as $video)
|
||||
<div class="video-card">
|
||||
<a href="{{ route('videos.show', $video) }}">
|
||||
<div class="video-thumbnail">
|
||||
<img src="{{ $video->thumbnail ? asset('storage/thumbnails/' . $video->thumbnail) : 'https://i.ytimg.com/vi/default.jpg' }}" alt="{{ $video->title }}">
|
||||
<span class="video-duration">{{ $video->duration ?? '0:00' }}</span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="video-info">
|
||||
<h3 class="video-title"><a href="{{ route('videos.show', $video) }}">{{ Str::limit($video->title, 50) }}</a></h3>
|
||||
<div class="video-meta"><span>{{ number_format($video->view_count ?? 0) }} views</span><span> • </span><span>{{ $video->created_at->diffForHumans() }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@if($user->videos->count() > 4)
|
||||
<div class="text-center mt-4"><a href="{{ route('channel', $user->id) }}" class="btn-secondary">View All Videos <i class="bi bi-arrow-right"></i></a></div>
|
||||
@endif
|
||||
@else
|
||||
<div class="empty-state"><i class="bi bi-camera-video"></i><p>No videos yet</p></div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('profile.update') }}" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Name</label>
|
||||
<input type="text" name="name" class="form-input" value="{{ old('name', $user->name) }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Avatar</label>
|
||||
<input type="file" name="avatar" class="form-input" accept="image/*">
|
||||
<small class="text-muted">Max size: 5MB. Supported: JPG, PNG, WebP</small>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-primary">Save Changes</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="col-lg-4">
|
||||
<div class="form-card">
|
||||
<h2 class="form-title">Quick Links</h2>
|
||||
|
||||
<a href="{{ route('channel', $user->id) }}" class="btn-primary d-inline-block text-decoration-none">
|
||||
<i class="bi bi-play-btn"></i> View My Channel
|
||||
</a>
|
||||
|
||||
<a href="{{ route('settings') }}" class="btn-primary d-inline-block text-decoration-none ms-2">
|
||||
<i class="bi bi-gear"></i> Settings
|
||||
</a>
|
||||
<h2 class="form-title"><i class="bi bi-pencil-square"></i> Edit Profile</h2>
|
||||
@if(session('success'))<div class="alert alert-success">{{ session('success') }}</div>@endif
|
||||
<form method="POST" action="{{ route('profile.update') }}" enctype="multipart/form-data">
|
||||
@csrf @method('PUT')
|
||||
<div class="form-group"><label class="form-label">Name</label><input type="text" name="name" class="form-input" value="{{ old('name', $user->name) }}" required></div>
|
||||
<div class="form-group"><label class="form-label">Avatar</label><input type="file" name="avatar" class="form-input" accept="image/*"><small class="form-hint">Max: 5MB</small></div>
|
||||
<div class="form-group"><label class="form-label">Bio</label><textarea name="bio" class="form-textarea" placeholder="Tell us about yourself...">{{ old('bio', $user->bio) }}</textarea></div>
|
||||
<div class="form-group"><label class="form-label">Location</label><input type="text" name="location" class="form-input" value="{{ old('location', $user->location) }}" placeholder="City, Country"></div>
|
||||
<div class="form-group"><label class="form-label">Birthday</label><input type="date" name="birthday" class="form-input" value="{{ old('birthday', $user->birthday) }}"></div>
|
||||
<button type="submit" class="btn-primary w-100"><i class="bi bi-check-lg"></i> Save Changes</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="form-card">
|
||||
<h2 class="form-title"><i class="bi bi-share"></i> Social Links</h2>
|
||||
<form method="POST" action="{{ route('profile.update') }}" enctype="multipart/form-data">
|
||||
@csrf @method('PUT')
|
||||
<div class="form-row">
|
||||
<div class="form-group"><label class="form-label"><i class="bi bi-twitter-x"></i> Twitter</label><input type="text" name="twitter" class="form-input" value="{{ old('twitter', $user->twitter) }}" placeholder="username"></div>
|
||||
<div class="form-group"><label class="form-label"><i class="bi bi-instagram"></i> Instagram</label><input type="text" name="instagram" class="form-input" value="{{ old('instagram', $user->instagram) }}" placeholder="username"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group"><label class="form-label"><i class="bi bi-facebook"></i> Facebook</label><input type="text" name="facebook" class="form-input" value="{{ old('facebook', $user->facebook) }}" placeholder="username"></div>
|
||||
<div class="form-group"><label class="form-label"><i class="bi bi-youtube"></i> YouTube</label><input type="text" name="youtube" class="form-input" value="{{ old('youtube', $user->youtube) }}" placeholder="channel"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group"><label class="form-label"><i class="bi bi-linkedin"></i> LinkedIn</label><input type="text" name="linkedin" class="form-input" value="{{ old('linkedin', $user->linkedin) }}" placeholder="username"></div>
|
||||
<div class="form-group"><label class="form-label"><i class="bi bi-tiktok"></i> TikTok</label><input type="text" name="tiktok" class="form-input" value="{{ old('tiktok', $user->tiktok) }}" placeholder="username"></div>
|
||||
</div>
|
||||
<div class="form-group"><label class="form-label"><i class="bi bi-globe"></i> Website</label><input type="url" name="website" class="form-input" value="{{ old('website', $user->website) }}" placeholder="https://example.com"></div>
|
||||
<button type="submit" class="btn-primary w-100"><i class="bi bi-check-lg"></i> Save Social Links</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="form-card">
|
||||
<h2 class="form-title"><i class="bi bi-link-45deg"></i> Quick Links</h2>
|
||||
<div class="d-flex flex-column gap-3">
|
||||
<a href="{{ route('channel', $user->id) }}" class="btn-secondary text-center"><i class="bi bi-play-btn"></i> View My Channel</a>
|
||||
<a href="{{ route('settings') }}" class="btn-secondary text-center"><i class="bi bi-gear"></i> Account Settings</a>
|
||||
<a href="{{ route('history') }}" class="btn-secondary text-center"><i class="bi bi-clock-history"></i> Watch History</a>
|
||||
<a href="{{ route('liked') }}" class="btn-secondary text-center"><i class="bi bi-heart"></i> Liked Videos</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
Reference in new issue
Block a user