mirror of
https://github.com/juherr/kill-the-news.git
synced 2026-06-20 22:03:48 +00:00
Enhance admin interface, security, and feed management with improved UX and authentication
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
// Authentication helper functions
|
||||
// Handles user authentication state
|
||||
|
||||
export const authHelpers = `
|
||||
// Check if user is authenticated
|
||||
function isAuthenticated() {
|
||||
// Check localStorage first (client-side)
|
||||
if (localStorage.getItem('authenticated') === 'true') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for cookie (server-side auth)
|
||||
function getCookie(name) {
|
||||
const value = \`; \${document.cookie}\`;
|
||||
const parts = value.split(\`; \${name}=\`);
|
||||
if (parts.length === 2) return parts.pop().split(';').shift();
|
||||
return null;
|
||||
}
|
||||
|
||||
return getCookie('admin_auth') === 'true';
|
||||
}
|
||||
|
||||
// Set authentication state
|
||||
function setAuthenticated(value) {
|
||||
localStorage.setItem('authenticated', value ? 'true' : 'false');
|
||||
}
|
||||
|
||||
// Logout function
|
||||
function logout() {
|
||||
localStorage.removeItem('authenticated');
|
||||
// Also clear the cookie by setting expiry in the past
|
||||
document.cookie = 'admin_auth=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
||||
window.location.href = '/admin/login';
|
||||
}
|
||||
|
||||
// Check authentication on page load
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const path = window.location.pathname;
|
||||
if (path !== '/admin/login' && !isAuthenticated()) {
|
||||
window.location.href = '/admin/login';
|
||||
}
|
||||
});
|
||||
`;
|
||||
@@ -0,0 +1,62 @@
|
||||
// Clipboard functionality
|
||||
// Handles copying text to clipboard with visual feedback
|
||||
|
||||
export const clipboardScripts = `
|
||||
// Copy text to clipboard with animation feedback
|
||||
function copyToClipboard(text, element) {
|
||||
// Find the parent .copyable element and the content element
|
||||
const copyableContainer = element.closest('.copyable');
|
||||
const contentElement = copyableContainer?.querySelector('.copyable-content');
|
||||
if (!copyableContainer || !contentElement) return;
|
||||
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
// Add the 'copied' class to the content element for success styling
|
||||
contentElement.classList.add('copied');
|
||||
|
||||
// Remove the class after a delay (let CSS handle the transitions)
|
||||
setTimeout(() => {
|
||||
contentElement.classList.remove('copied');
|
||||
}, 1500);
|
||||
}).catch(err => {
|
||||
console.error('Could not copy text: ', err);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize copyable elements
|
||||
function setupCopyableElements() {
|
||||
document.querySelectorAll('.copyable').forEach(container => {
|
||||
const contentElement = container.querySelector('.copyable-content');
|
||||
const valueElement = container.querySelector('.copyable-value');
|
||||
|
||||
if (contentElement && valueElement) {
|
||||
const textToCopy = valueElement.getAttribute('data-copy') || valueElement.textContent.trim();
|
||||
|
||||
// Add click handler to the entire content area
|
||||
contentElement.addEventListener('click', () => {
|
||||
copyToClipboard(textToCopy, contentElement);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Confirmation dialogs for deletion
|
||||
function confirmDelete(feedId) {
|
||||
if (confirm('Are you sure you want to delete this feed? This action cannot be undone.')) {
|
||||
const form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = '/admin/feeds/' + feedId + '/delete';
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
}
|
||||
|
||||
function confirmDeleteEmail(emailKey, feedId) {
|
||||
if (confirm('Are you sure you want to delete this email? This action cannot be undone.')) {
|
||||
const form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = '/admin/emails/' + emailKey + '/delete?feedId=' + feedId;
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,17 @@
|
||||
// Main scripts exports file
|
||||
// Combines and re-exports all JavaScript functionality
|
||||
|
||||
import { modalScripts, emailViewScripts, initScripts } from './interactions';
|
||||
import { clipboardScripts } from './clipboard';
|
||||
import { authHelpers } from './auth';
|
||||
|
||||
// Combine all scripts into a single JavaScript string
|
||||
export const interactiveScripts = `
|
||||
${modalScripts}
|
||||
${emailViewScripts}
|
||||
${clipboardScripts}
|
||||
${initScripts}
|
||||
`;
|
||||
|
||||
// Re-export for modular usage if needed
|
||||
export { modalScripts, emailViewScripts, initScripts, clipboardScripts, authHelpers };
|
||||
@@ -0,0 +1,73 @@
|
||||
// Interactive scripts for UI elements
|
||||
// Handles modals, toggles, and other UI interactions
|
||||
|
||||
export const modalScripts = `
|
||||
// Modal Functionality
|
||||
function setupModals() {
|
||||
const modalTriggers = document.querySelectorAll('[data-modal-target]');
|
||||
|
||||
modalTriggers.forEach(trigger => {
|
||||
trigger.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
const modalId = trigger.getAttribute('data-modal-target');
|
||||
const modal = document.getElementById(modalId);
|
||||
|
||||
if (modal) {
|
||||
modal.classList.add('visible');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Close modals when clicking outside or on close button
|
||||
document.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('modal-bg') || e.target.classList.contains('modal-close')) {
|
||||
const modal = e.target.closest('.modal-bg');
|
||||
if (modal) {
|
||||
modal.classList.remove('visible');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Close modals with ESC key
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
const visibleModals = document.querySelectorAll('.modal-bg.visible');
|
||||
visibleModals.forEach(modal => {
|
||||
modal.classList.remove('visible');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
`;
|
||||
|
||||
export const emailViewScripts = `
|
||||
// Toggle email view functions
|
||||
function showRendered() {
|
||||
document.getElementById('rendered-view').style.display = 'block';
|
||||
document.getElementById('raw-view').style.display = 'none';
|
||||
document.getElementById('rendered-button').classList.add('active');
|
||||
document.getElementById('raw-button').classList.remove('active');
|
||||
}
|
||||
|
||||
function showRaw() {
|
||||
document.getElementById('rendered-view').style.display = 'none';
|
||||
document.getElementById('raw-view').style.display = 'block';
|
||||
document.getElementById('rendered-button').classList.remove('active');
|
||||
document.getElementById('raw-button').classList.add('active');
|
||||
}
|
||||
`;
|
||||
|
||||
export const initScripts = `
|
||||
// Initialize all interactive elements
|
||||
function initInteractive() {
|
||||
setupModals();
|
||||
setupCopyableElements(); // Initialize copyable elements
|
||||
|
||||
// Make these functions globally available
|
||||
window.showRendered = showRendered;
|
||||
window.showRaw = showRaw;
|
||||
}
|
||||
|
||||
// Run setup when DOM is fully loaded
|
||||
document.addEventListener('DOMContentLoaded', initInteractive);
|
||||
`;
|
||||
Reference in New Issue
Block a user