Add sports-match type, device tracking, profile visits, and share refactor

- New SportsMatch model/controller and sports UI components/modal
- Move share-modal to a reusable x-share-modal/x-share-button component
- Add VideoSharedWithUser notification and share-to-members flow
- Device/user-agent tracking on views, downloads, share accesses
- ProfileVisit model + migration; subscription source tracking
- Email thumbnail support; remove stale TODO files
This commit is contained in:
ghassan committed 2026-05-29 01:50:28 +03:00
1 parent 6aae6f86b6
commit 73527f3781
61 files changed
+4014 -636

No files matched your search

+20 -13
View File
@@ -648,7 +648,10 @@
.vdb-desc-text { font-size: 14px; line-height: 1.6; color: var(--text-primary); white-space: pre-wrap; }
.vdb-desc-text p { margin-bottom: 8px; }
.vdb-desc-text a { color: #3ea6ff; }
.vdb-show-more { background: none; border: none; color: var(--text-primary); font-weight: 700; font-size: 13px; cursor: pointer; padding: 6px 0 0; }
.vdb-show-more { display: flex; align-items: center; justify-content: center; gap: 6px; margin: 12px auto 0; background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-primary); font-weight: 700; font-size: 13px; cursor: pointer; padding: 7px 16px; border-radius: 18px; transition: background .15s ease, border-color .15s ease; }
.vdb-show-more:hover { background: var(--bg-hover, rgba(127,127,127,.12)); }
.vdb-show-more i { font-size: 14px; transition: transform .2s ease; }
.vdb-show-more.expanded i { transform: rotate(180deg); }
</style>
@@ -680,7 +683,7 @@
<div id="vdbDescShort" class="vdb-desc-text">{{ $needsExpand ? $shortDescription : $fullDescription }}</div>
@if($needsExpand)
<div id="vdbDescFull" class="vdb-desc-text" style="display:none;">{{ $fullDescription }}</div>
<button class="vdb-show-more" onclick="toggleVdbDesc(this)">Show more</button>
<button class="vdb-show-more" onclick="toggleVdbDesc(this)"><span>Show more</span> <i class="bi bi-chevron-down"></i></button>
@endif
@else
<p style="font-size:13px;color:var(--text-secondary);margin:0;">No description added.</p>
@@ -707,20 +710,24 @@
function toggleVdbDesc(btn) {
const short = document.getElementById('vdbDescShort');
const full = document.getElementById('vdbDescFull');
const label = btn.querySelector('span');
if (full.style.display === 'none') {
short.style.display = 'none';
full.style.display = 'block';
btn.textContent = 'Show less';
label.textContent = 'Show less';
btn.classList.add('expanded');
} else {
short.style.display = 'block';
full.style.display = 'none';
btn.textContent = 'Show more';
label.textContent = 'Show more';
btn.classList.remove('expanded');
}
}
// ── Share + track ──────────────────────────────────────
function videoShare(url, title, trackUrl) {
openShareModal(url, title);
// Pass the full argument set so email + share-to-members are available (see share component rule).
openShareModal(url, title, '', '{{ auth()->check() ? route('videos.shareEmail', $video) : '' }}', '{{ auth()->check() ? route('videos.shareMembers', $video) : '' }}');
fetch(trackUrl, {
method: 'POST',
headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content || '', 'Accept': 'application/json' }
@@ -773,7 +780,8 @@
@foreach ($playlistVideos as $index => $playlistVideo)
@php $isCurrent = $playlistVideo->id === $video->id; @endphp
<div class="sidebar-video-card{{ $isCurrent ? ' current-video' : '' }}"
{{ $isCurrent ? '' : "onclick=\"window.location.href='".route('videos.show', $playlistVideo)."?playlist={$playlist->share_token}'\"" }}
data-pl-id="{{ $playlistVideo->id }}"
{{ $isCurrent ? '' : 'onclick="plGoTo(\''.route('videos.show', $playlistVideo).'?playlist='.$playlist->share_token.'\')"' }}
style="{{ $isCurrent ? 'cursor:default;' : 'cursor:pointer;' }}">
<div class="sidebar-thumb" style="position: relative;">
@if ($playlistVideo->thumbnail)
@@ -892,10 +900,9 @@
@endauth
@if ($video->isShareable())
<button class="yt-action-btn"
onclick="openShareModal('{{ $video->share_url }}', '{{ addslashes($video->title) }}')" style="flex:1;">
<x-share-button :video="$video" class="yt-action-btn" style="flex:1;">
<i class="bi bi-share"></i><span>Share</span>
</button>
</x-share-button>
@endif
<button class="yt-action-btn" onclick="openAddToPlaylistModal({{ $video->id }})" style="flex:1;">
@@ -921,7 +928,7 @@
@endauth
</div>
@include('layouts.partials.share-modal')
{{-- Share modal is the app-layout singleton (<x-share-modal/>); do not re-render it here. --}}
@include('layouts.partials.edit-video-modal')
@include('layouts.partials.add-to-playlist-modal')
@@ -1000,12 +1007,12 @@
var pos = order.indexOf(curIdx);
var nextPos = (pos + 1) % order.length;
if (pos === order.length - 1 && plLoop !== 'all') return; // end of shuffle, no loop
window.location.href = PL_VIDEOS[order[nextPos]].url;
plGoTo(PL_VIDEOS[order[nextPos]].url);
} else {
if (PL_NEXT_URL) {
window.location.href = PL_NEXT_URL;
plGoTo(PL_NEXT_URL);
} else if (plLoop === 'all' && PL_FIRST_URL) {
window.location.href = PL_FIRST_URL;
plGoTo(PL_FIRST_URL);
}
}
}