mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 00:01:21 +00:00
Fix inline script issues
This commit is contained in:
+255
-2867
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<a href="{{ url('/getnzb/' . $release->guid) }}" class="download-nzb px-4 py-2 bg-green-600 dark:bg-green-700 text-white rounded-lg hover:bg-green-700 dark:hover:bg-green-800 transition inline-flex items-center" onclick="showToast('Downloading NZB...', 'success')">
|
||||
<a href="{{ url('/getnzb/' . $release->guid) }}" class="download-nzb px-4 py-2 bg-green-600 dark:bg-green-700 text-white rounded-lg hover:bg-green-700 dark:hover:bg-green-800 transition inline-flex items-center">
|
||||
<i class="fas fa-download mr-2"></i> Download NZB
|
||||
</a>
|
||||
<a href="#" class="add-to-cart px-4 py-2 bg-blue-600 dark:bg-blue-700 text-white rounded-lg hover:bg-blue-700 dark:hover:bg-blue-800 transition inline-flex items-center" data-guid="{{ $release->guid }}">
|
||||
@@ -83,7 +83,7 @@
|
||||
@if($hasPreviewImage)
|
||||
<!-- Preview image -->
|
||||
<div>
|
||||
<div class="block cursor-pointer" onclick="openImageModal('{{ url('/covers/preview/' . $release->guid . '_thumb.jpg') }}', 'Preview Image')">
|
||||
<div class="block cursor-pointer image-modal-trigger" data-image-url="{{ url('/covers/preview/' . $release->guid . '_thumb.jpg') }}" data-image-title="Preview Image">
|
||||
<img src="{{ url('/covers/preview/' . $release->guid . '_thumb.jpg') }}"
|
||||
alt="Preview"
|
||||
class="w-full h-auto rounded-lg shadow-md hover:shadow-lg transition"
|
||||
@@ -96,7 +96,7 @@
|
||||
@if($hasSampleImage)
|
||||
<!-- Sample image -->
|
||||
<div>
|
||||
<div class="block cursor-pointer" onclick="openImageModal('{{ url('/covers/sample/' . $release->guid . '_thumb.jpg') }}', 'Sample Image')">
|
||||
<div class="block cursor-pointer image-modal-trigger" data-image-url="{{ url('/covers/sample/' . $release->guid . '_thumb.jpg') }}" data-image-title="Sample Image">
|
||||
<img src="{{ url('/covers/sample/' . $release->guid . '_thumb.jpg') }}"
|
||||
alt="Sample"
|
||||
class="w-full h-auto rounded-lg shadow-md hover:shadow-lg transition"
|
||||
@@ -922,9 +922,9 @@
|
||||
@endsection
|
||||
|
||||
<!-- Image Modal -->
|
||||
<div id="imageModal" class="fixed inset-0 bg-transparent hidden items-center justify-center p-4">
|
||||
<div class="relative max-w-7xl w-full h-full flex items-center justify-center">
|
||||
<button type="button" onclick="closeImageModal()" class="absolute top-4 right-4 text-white hover:text-gray-300 text-4xl font-bold z-10 bg-black bg-opacity-70 rounded-full w-12 h-12 flex items-center justify-center shadow-lg">
|
||||
<div id="imageModal" class="image-modal-backdrop hidden">
|
||||
<div class="image-modal-container">
|
||||
<button type="button" class="image-modal-close" data-close-image-modal>
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
<div class="text-center">
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
@stack('styles')
|
||||
|
||||
<!-- Dark Mode Script (must be inline to prevent flash) -->
|
||||
<script>
|
||||
<!-- Dark Mode Script (must use nonce to prevent flash) -->
|
||||
<script nonce="{{ csp_nonce() }}">
|
||||
// Initialize theme before page renders to prevent flash
|
||||
(function() {
|
||||
@auth
|
||||
@@ -153,167 +153,24 @@
|
||||
|
||||
@stack('scripts')
|
||||
|
||||
<script>
|
||||
// Theme management with system preference support
|
||||
(function() {
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
<!-- Theme Management Data (moved to csp-safe.js) -->
|
||||
<div id="current-theme-data"
|
||||
data-theme="{{ auth()->check() ? (auth()->user()->theme_preference ?? 'light') : 'light' }}"
|
||||
data-authenticated="{{ auth()->check() ? 'true' : 'false' }}"
|
||||
data-update-url="{{ route('profile.update-theme') }}"
|
||||
style="display: none;">
|
||||
</div>
|
||||
|
||||
function applyTheme(themePreference) {
|
||||
const html = document.documentElement;
|
||||
|
||||
if (themePreference === 'system') {
|
||||
if (mediaQuery.matches) {
|
||||
html.classList.add('dark');
|
||||
} else {
|
||||
html.classList.remove('dark');
|
||||
}
|
||||
} else if (themePreference === 'dark') {
|
||||
html.classList.add('dark');
|
||||
} else {
|
||||
html.classList.remove('dark');
|
||||
}
|
||||
}
|
||||
|
||||
function updateThemeButton(theme) {
|
||||
const themeIcon = document.getElementById('theme-icon');
|
||||
const themeLabel = document.getElementById('theme-label');
|
||||
const themeToggle = document.getElementById('theme-toggle');
|
||||
|
||||
const icons = {
|
||||
'light': 'fa-sun',
|
||||
'dark': 'fa-moon',
|
||||
'system': 'fa-desktop'
|
||||
};
|
||||
const labels = {
|
||||
'light': 'Light',
|
||||
'dark': 'Dark',
|
||||
'system': 'System'
|
||||
};
|
||||
const titles = {
|
||||
'light': 'Light Mode',
|
||||
'dark': 'Dark Mode',
|
||||
'system': 'System Mode'
|
||||
};
|
||||
|
||||
if (themeIcon) {
|
||||
// Remove all possible icon classes first
|
||||
themeIcon.classList.remove('fa-sun', 'fa-moon', 'fa-desktop');
|
||||
// Add the correct icon class
|
||||
themeIcon.classList.add(icons[theme]);
|
||||
}
|
||||
if (themeLabel) {
|
||||
themeLabel.textContent = labels[theme];
|
||||
}
|
||||
if (themeToggle) {
|
||||
themeToggle.setAttribute('title', titles[theme]);
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for OS theme changes
|
||||
mediaQuery.addEventListener('change', () => {
|
||||
@auth
|
||||
const userThemePreference = '{{ auth()->user()->theme_preference ?? 'light' }}';
|
||||
if (userThemePreference === 'system') {
|
||||
applyTheme('system');
|
||||
}
|
||||
@else
|
||||
const theme = localStorage.getItem('theme') || 'light';
|
||||
if (theme === 'system') {
|
||||
applyTheme('system');
|
||||
}
|
||||
@endauth
|
||||
});
|
||||
|
||||
// Listen for custom theme change events from sidebar
|
||||
document.addEventListener('themeChanged', function(e) {
|
||||
if (e.detail && e.detail.theme) {
|
||||
updateThemeButton(e.detail.theme);
|
||||
applyTheme(e.detail.theme);
|
||||
@auth
|
||||
currentTheme = e.detail.theme;
|
||||
@else
|
||||
currentTheme = e.detail.theme;
|
||||
@endauth
|
||||
}
|
||||
});
|
||||
|
||||
// Dark mode toggle - cycles through light -> dark -> system
|
||||
const themeToggle = document.getElementById('theme-toggle');
|
||||
@auth
|
||||
let currentTheme = '{{ auth()->user()->theme_preference ?? 'light' }}';
|
||||
@else
|
||||
let currentTheme = localStorage.getItem('theme') || 'light';
|
||||
@endauth
|
||||
|
||||
themeToggle?.addEventListener('click', function() {
|
||||
let nextTheme;
|
||||
|
||||
// Cycle through: light -> dark -> system -> light
|
||||
if (currentTheme === 'light') {
|
||||
nextTheme = 'dark';
|
||||
} else if (currentTheme === 'dark') {
|
||||
nextTheme = 'system';
|
||||
} else {
|
||||
nextTheme = 'light';
|
||||
}
|
||||
|
||||
applyTheme(nextTheme);
|
||||
updateThemeButton(nextTheme);
|
||||
|
||||
@auth
|
||||
// Save to backend for authenticated users
|
||||
fetch('{{ route('profile.update-theme') }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
},
|
||||
body: JSON.stringify({ theme_preference: nextTheme })
|
||||
}).then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
currentTheme = nextTheme;
|
||||
// Dispatch event to update sidebar
|
||||
document.dispatchEvent(new CustomEvent('themeChanged', { detail: { theme: nextTheme } }));
|
||||
}
|
||||
});
|
||||
@else
|
||||
localStorage.setItem('theme', nextTheme);
|
||||
currentTheme = nextTheme;
|
||||
// Dispatch event to update sidebar
|
||||
document.dispatchEvent(new CustomEvent('themeChanged', { detail: { theme: nextTheme } }));
|
||||
@endauth
|
||||
});
|
||||
|
||||
// Mobile sidebar toggle
|
||||
document.getElementById('mobile-sidebar-toggle')?.addEventListener('click', function() {
|
||||
document.getElementById('sidebar')?.classList.toggle('hidden');
|
||||
});
|
||||
|
||||
// Display flash messages as toast notifications
|
||||
@if(session('success'))
|
||||
window.showToast('{{ session('success') }}', 'success');
|
||||
@endif
|
||||
|
||||
@if(session('error'))
|
||||
@if(is_array(session('error')))
|
||||
@foreach(session('error') as $error)
|
||||
window.showToast('{{ $error }}', 'error');
|
||||
@endforeach
|
||||
@else
|
||||
window.showToast('{{ session('error') }}', 'error');
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if(session('warning'))
|
||||
window.showToast('{{ session('warning') }}', 'warning');
|
||||
@endif
|
||||
|
||||
@if(session('info'))
|
||||
window.showToast('{{ session('info') }}', 'info');
|
||||
@endif
|
||||
})();
|
||||
</script>
|
||||
<!-- Flash Messages Data (moved to csp-safe.js) -->
|
||||
<div id="flash-messages-data"
|
||||
data-messages="{{ json_encode([
|
||||
'success' => session('success'),
|
||||
'error' => session('error'),
|
||||
'warning' => session('warning'),
|
||||
'info' => session('info')
|
||||
]) }}"
|
||||
style="display: none;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -1,71 +1,4 @@
|
||||
{{-- Cart functionality JavaScript --}}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Handle add to cart button clicks
|
||||
document.addEventListener('click', function(e) {
|
||||
// Check if clicked element or its parent is a cart button
|
||||
const cartBtn = e.target.closest('.add-to-cart');
|
||||
|
||||
if (cartBtn) {
|
||||
e.preventDefault();
|
||||
|
||||
// Get the GUID from the button's data attribute
|
||||
const guid = cartBtn.dataset.guid;
|
||||
const iconElement = cartBtn.querySelector('.icon_cart');
|
||||
|
||||
if (!guid) {
|
||||
console.error('No GUID found for cart item');
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent double-clicking
|
||||
if (iconElement && iconElement.classList.contains('icon_cart_clicked')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send AJAX request to add item to cart
|
||||
fetch('/cart/add', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: JSON.stringify({ id: guid })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Visual feedback
|
||||
if (iconElement) {
|
||||
iconElement.classList.remove('fa-shopping-basket');
|
||||
iconElement.classList.add('fa-check', 'icon_cart_clicked');
|
||||
|
||||
// Reset icon after 2 seconds
|
||||
setTimeout(() => {
|
||||
iconElement.classList.remove('fa-check', 'icon_cart_clicked');
|
||||
iconElement.classList.add('fa-shopping-basket');
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
// Update cart count if element exists
|
||||
const cartCount = document.querySelector('.cart-count');
|
||||
if (cartCount && data.cartCount) {
|
||||
cartCount.textContent = data.cartCount;
|
||||
}
|
||||
|
||||
// Show success notification
|
||||
window.showToast('Added to cart successfully!', 'success');
|
||||
} else {
|
||||
window.showToast('Failed to add item to cart', 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error adding to cart:', error);
|
||||
window.showToast('An error occurred', 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{{-- All cart functionality has been moved to resources/js/csp-safe.js for CSP compliance --}}
|
||||
{{-- See initCartFunctionality() function --}}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user