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:
1 parent
6aae6f86b6
commit
73527f3781
61 files changed
+4014
-636
No files matched your search
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user