🐘
edit_opening.php
← Back
πŸ“ Php ⚑ Executable Ctrl+S: Save β€’ Ctrl+R: Run β€’ Ctrl+F: Find
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Section Layout Manager</title> </head> <body> <script type="module"> const SectionLayout = () => { // Initial data - will be loaded from server let sections = []; let currentStyle = 0; const loadFromServer = async () => { try { const response = await fetch('sections.json?t=' + new Date().getTime()); if (response.ok) { const data = await response.json(); sections = data.sections || []; currentStyle = data.style || 0; } else { // Default data if file doesn't exist sections = [ {"title": "First Section", "description": "This is a short description for the first section.", "color": "#6b7d8b", "image": "", "audio": ""}, {"title": "Second Section", "description": "This is a longer description for the second section that will demonstrate how the truncation works when you have more text to display.", "color": "#8b7d7a", "image": "", "audio": ""} ]; currentStyle = 0; } } catch (error) { console.error('Error loading data:', error); // Default data on error sections = [ {"title": "First Section", "description": "This is a short description for the first section.", "color": "#8b7d6b", "image": "https://via.placeholder.com/150", "audio": ""}, {"title": "Second Section", "description": "This is a longer description for the second section that will demonstrate how the truncation works when you have more text to display.", "color": "#7a8c8e", "image": "https://via.placeholder.com/150", "audio": ""} ]; currentStyle = 0; } render(); }; const styles = [ { name: 'Classic Dark', background: '#2b2d31', card: '#3d4147', text: '#d4d4d4', accent: '#6b8cae', wireframe: false, neon: false, lineBottom: false, invisible: false }, { name: 'Vibrant Neon', background: '#050505', card: '#0b0014', text: '#fff', accent: '#ff00ff', wireframe: false, neon: true, lineBottom: false, invisible: false }, { name: 'Neon Wireframe', background: '#050505', card: 'transparent', text: '#fff', accent: '#ff00ff', wireframe: true, neon: true, lineBottom: false, invisible: false }, { name: 'Neon Line', background: '#050505', card: 'transparent', text: '#fff', accent: '#ff00ff', wireframe: false, neon: true, lineBottom: true, invisible: false }, { name: 'Line Bottom', background: '#35373b', card: 'transparent', text: '#c9c9c9', accent: '#8a9ba8', wireframe: false, neon: false, lineBottom: true, invisible: false }, { name: 'Rounded Wireframe', background: '#2e3035', card: '#2e3035', text: '#b8b8b8', accent: '#7a8c9e', wireframe: true, neon: false, lineBottom: false, invisible: false, rounded: true }, { name: 'Wireframe', background: '#2e3035', card: '#2e3035', text: '#b8b8b8', accent: '#7a8c9e', wireframe: true, neon: false, lineBottom: false, invisible: false }, { name: 'Invisible Block', background: '#35373b', card: 'transparent', text: '#c9c9c9', accent: '#8a9ba8', wireframe: false, neon: false, lineBottom: false, invisible: true } ]; const header = document.createElement('div'); header.className = 'header'; const title = document.createElement('h1'); title.textContent = 'Section Layout Manager'; header.appendChild(title); const container = document.createElement('div'); container.id = 'container'; const controls = document.createElement('div'); controls.className = 'controls'; // File upload section const uploadSection = document.createElement('div'); uploadSection.className = 'upload-section'; const imageUploadLabel = document.createElement('label'); imageUploadLabel.className = 'upload-label'; imageUploadLabel.innerHTML = 'πŸ“· Upload Image'; const imageUpload = document.createElement('input'); imageUpload.type = 'file'; imageUpload.accept = 'image/*'; imageUpload.style.display = 'none'; imageUpload.onchange = (e) => handleImageUpload(e); imageUploadLabel.appendChild(imageUpload); const audioUploadLabel = document.createElement('label'); audioUploadLabel.className = 'upload-label'; audioUploadLabel.innerHTML = '🎡 Upload Audio'; const audioUpload = document.createElement('input'); audioUpload.type = 'file'; audioUpload.accept = 'audio/mp3,audio/mpeg'; audioUpload.style.display = 'none'; audioUpload.onchange = (e) => handleAudioUpload(e); audioUploadLabel.appendChild(audioUpload); uploadSection.append(imageUploadLabel, audioUploadLabel); const addButton = document.createElement('button'); addButton.className = 'add-btn'; addButton.textContent = '+ Add Section'; const styleButton = document.createElement('button'); styleButton.className = 'style-btn'; styleButton.textContent = '🎨 Style: ' + styles[currentStyle].name; const saveButton = document.createElement('button'); saveButton.className = 'save-btn'; saveButton.textContent = 'πŸ’Ύ Save'; controls.append(uploadSection, addButton, styleButton, saveButton); const truncateText = (text, maxLength = 80) => { if (text.length <= maxLength) return text; return text.substring(0, maxLength) + '...'; }; const handleImageUpload = async (e) => { const file = e.target.files[0]; if (!file) return; const formData = new FormData(); formData.append('image', file); try { const response = await fetch('upload_image.php', { method: 'POST', body: formData }); const result = await response.json(); if (result.success) { alert('Image uploaded! URL: ' + result.url); // You can now use result.url in your sections } else { alert('Upload failed: ' + result.error); } } catch (error) { alert('Upload error: ' + error.message); } e.target.value = ''; // Reset input }; const handleAudioUpload = async (e) => { const file = e.target.files[0]; if (!file) return; const formData = new FormData(); formData.append('audio', file); try { const response = await fetch('upload_audio.php', { method: 'POST', body: formData }); const result = await response.json(); if (result.success) { alert('Audio uploaded! URL: ' + result.url); // You can now use result.url in your sections } else { alert('Upload failed: ' + result.error); } } catch (error) { alert('Upload error: ' + error.message); } e.target.value = ''; // Reset input }; const showFileBrowser = async (type, form) => { try { const response = await fetch(`browse_files.php?type=${type}`); const result = await response.json(); if (!result.success) { alert('Error: ' + result.error); return; } if (result.files.length === 0) { alert(`No ${type} files found. Upload some files first!`); return; } // Create file browser overlay const overlay = document.createElement('div'); overlay.className = 'overlay'; const modal = document.createElement('div'); modal.className = 'modal file-browser'; const closeBtn = document.createElement('button'); closeBtn.className = 'close-btn'; closeBtn.textContent = 'βœ•'; closeBtn.onclick = () => overlay.remove(); const title = document.createElement('h2'); title.textContent = `Select ${type === 'image' ? 'an Image' : 'Audio'}`; title.style.marginTop = '0'; const fileList = document.createElement('div'); fileList.className = 'file-list'; result.files.forEach(file => { const fileItem = document.createElement('div'); fileItem.className = 'file-item'; if (type === 'image') { const img = document.createElement('img'); img.src = file; img.className = 'file-preview'; fileItem.appendChild(img); } const fileName = document.createElement('div'); fileName.className = 'file-name'; fileName.textContent = file.split('/').pop(); fileItem.appendChild(fileName); fileItem.onclick = () => { const input = form.querySelector(type === 'image' ? '.image' : '.audio'); input.value = file; overlay.remove(); }; fileList.appendChild(fileItem); }); modal.append(closeBtn, title, fileList); overlay.appendChild(modal); overlay.onclick = (e) => { if (e.target === overlay) overlay.remove(); }; document.body.appendChild(overlay); } catch (error) { alert('Error loading files: ' + error.message); } }; // Track current audio playback let currentAudio = null; let isSpeaking = false; const playAudio = (section, button) => { // Stop any currently playing audio or speech if (currentAudio) { currentAudio.pause(); currentAudio.currentTime = 0; currentAudio = null; } if (isSpeaking) { window.speechSynthesis.cancel(); isSpeaking = false; button.textContent = section.audio && section.audio.trim() !== '' ? 'πŸ”Š Play Audio' : 'πŸ”Š Read Aloud'; return; } if (section.audio && section.audio.trim() !== '') { // Play MP3 if URL exists currentAudio = new Audio(section.audio); button.textContent = '⏸️ Stop Audio'; currentAudio.onended = () => { currentAudio = null; button.textContent = 'πŸ”Š Play Audio'; }; currentAudio.play().catch(err => { console.error('Error playing audio:', err); alert('Could not play audio file. URL may be invalid.'); currentAudio = null; button.textContent = 'πŸ”Š Play Audio'; }); } else { // Use text-to-speech if no audio URL const utterance = new SpeechSynthesisUtterance(section.description); utterance.lang = 'en-US'; isSpeaking = true; button.textContent = '⏸️ Stop Reading'; utterance.onend = () => { isSpeaking = false; button.textContent = 'πŸ”Š Read Aloud'; }; window.speechSynthesis.speak(utterance); } }; const showOverlay = (section) => { const overlay = document.createElement('div'); overlay.className = 'overlay'; const modal = document.createElement('div'); modal.className = 'modal'; const closeBtn = document.createElement('button'); closeBtn.className = 'close-btn'; closeBtn.textContent = 'βœ•'; closeBtn.onclick = () => overlay.remove(); const img = document.createElement('img'); img.src = section.image; img.alt = section.title; img.className = 'modal-image'; const titleEl = document.createElement('h2'); titleEl.className = 'modal-title'; titleEl.textContent = section.title; const audioBtn = document.createElement('button'); audioBtn.className = 'audio-btn'; audioBtn.textContent = section.audio && section.audio.trim() !== '' ? 'πŸ”Š Play Audio' : 'πŸ”Š Read Aloud'; audioBtn.onclick = () => playAudio(section, audioBtn); const text = document.createElement('div'); text.className = 'modal-text'; text.textContent = section.description; if (section.image && section.image.trim() !== '') { modal.append(closeBtn, img, titleEl, audioBtn, text); } else { modal.append(closeBtn, titleEl, audioBtn, text); } overlay.appendChild(modal); overlay.onclick = (e) => { if (e.target === overlay) overlay.remove(); }; document.body.appendChild(overlay); }; const render = () => { const theme = styles[currentStyle]; document.body.style.backgroundColor = theme.background; document.body.style.color = theme.text; container.innerHTML = ''; sections.forEach((section, i) => { const div = document.createElement('div'); div.className = `section ${theme.neon ? 'neon' : ''} ${theme.lineBottom ? 'line-bottom' : ''} ${theme.invisible ? 'invisible' : ''} ${theme.rounded ? 'rounded' : ''}`; div.style.color = theme.text; if (theme.wireframe) { div.style.background = 'transparent'; div.style.border = `2px solid ${section.color || theme.accent}`; } else if (theme.lineBottom) { div.style.background = theme.card; div.style.border = 'none'; div.style.borderBottom = `3px solid ${section.color || theme.accent}`; } else if (theme.invisible) { div.style.background = 'transparent'; div.style.border = 'none'; } else { div.style.background = section.color || theme.card; div.style.border = 'none'; } const contentWrapper = document.createElement('div'); contentWrapper.className = 'content-wrapper'; contentWrapper.style.cursor = 'pointer'; contentWrapper.addEventListener("click", (e) => { e.stopPropagation(); showOverlay(section); }); contentWrapper.title = 'Click to view full description'; const img = document.createElement('img'); img.src = section.image; img.alt = section.title; const titleEl = document.createElement('h3'); titleEl.className = 'section-title'; titleEl.textContent = section.title; const text = document.createElement('div'); text.className = 'description-text'; text.textContent = truncateText(section.description); if (section.image && section.image.trim() !== '') { contentWrapper.append(img, titleEl, text); } else { contentWrapper.append(titleEl, text); } const btnRow = document.createElement('div'); btnRow.className = 'button-row'; const editBtn = document.createElement('button'); editBtn.textContent = '✎ Edit'; editBtn.className = 'edit-btn'; editBtn.addEventListener('click', (e) => { e.stopPropagation(); editSection(i); }); const deleteBtn = document.createElement('button'); deleteBtn.textContent = 'πŸ—‘οΈ Delete'; deleteBtn.className = 'delete-btn'; deleteBtn.addEventListener('click', (e) => { e.stopPropagation(); deleteSection(i); }); btnRow.append(editBtn, deleteBtn); div.append(contentWrapper, btnRow); container.append(div); }); styleButton.textContent = '🎨 Style: ' + styles[currentStyle].name; }; const editSection = (i) => { const s = sections[i]; const form = document.createElement('div'); form.className = 'edit-form'; form.innerHTML = ` <h3>Edit Section</h3> <label>Title</label> <input type="text" value="${s.title}" class="title" /> <label>Description</label> <textarea class="desc" rows="6">${s.description}</textarea> <label>Audio MP3 URL (optional)</label> <div class="input-with-button"> <input type="text" value="${s.audio || ''}" class="audio" placeholder="https://example.com/audio.mp3" /> <button type="button" class="browse-btn" data-type="audio">πŸ“‚ Browse</button> </div> <label>Color</label> <input type="color" value="${s.color}" class="color" /> <label>Image URL</label> <div class="input-with-button"> <input type="text" value="${s.image}" class="image" /> <button type="button" class="browse-btn" data-type="image">πŸ“‚ Browse</button> </div> <div class="form-buttons"> <button class="save-btn">Save</button> <button class="cancel-btn">Cancel</button> </div> `; const sectionDiv = container.children[i]; sectionDiv.replaceWith(form); // Browse button handlers form.querySelectorAll('.browse-btn').forEach(btn => { btn.onclick = () => showFileBrowser(btn.dataset.type, form); }); form.querySelector('.save-btn').onclick = () => { s.title = form.querySelector('.title').value; s.description = form.querySelector('.desc').value; s.audio = form.querySelector('.audio').value; s.color = form.querySelector('.color').value; s.image = form.querySelector('.image').value; render(); }; form.querySelector('.cancel-btn').onclick = render; }; const deleteSection = (i) => { if (confirm('Delete this section?')) { sections.splice(i, 1); render(); } }; const addSection = () => { const theme = styles[currentStyle]; sections.push({ title: `New Section ${sections.length + 1}`, description: `Description for section ${sections.length + 1}`, color: '#7a8c7a', image: '', audio: '' }); render(); }; const changeStyle = () => { currentStyle = (currentStyle + 1) % styles.length; render(); }; const saveToServer = async () => { const payload = { sections, style: currentStyle }; try { const response = await fetch('save.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await response.text(); alert(result); } catch (error) { alert('Error saving: ' + error.message); } }; addButton.onclick = addSection; styleButton.onclick = changeStyle; saveButton.onclick = saveToServer; document.body.append(header, controls, container); // Load data from server on startup loadFromServer(); const style = document.createElement('style'); style.textContent = ` body { margin: 0; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; display: flex; flex-direction: column; align-items: center; min-height: 100vh; padding: 20px; } .header { width: 100%; max-width: 900px; text-align: center; margin-bottom: 30px; } .header h1 { margin: 0; font-size: 2.5em; font-weight: 700; background: linear-gradient(90deg, #6b8cae, #7a8c9e); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } #container { max-width: 900px; width: 100%; display: flex; flex-direction: column; gap: 20px; padding: 20px 0; } .controls { display: flex; flex-wrap: wrap; justify-content: center; gap: 15px; margin-bottom: 20px; } .upload-section { display: flex; gap: 10px; width: 100%; justify-content: center; margin-bottom: 10px; } .upload-label { background: linear-gradient(90deg, #6b8cae, #7a8c9e); border: none; border-radius: 3px; padding: 10px 20px; color: white; cursor: pointer; transition: transform 0.2s; font-size: 0.95em; font-weight: 500; display: inline-block; } .upload-label:hover { transform: scale(1.05); } .section { border-radius: 4px; text-align: center; padding: 40px 30px; transition: all 0.3s; box-shadow: 0 2px 8px rgba(0,0,0,0.3); } .section:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.5); } .section.rounded { border-radius: 16px !important; } .section.rounded img { border-radius: 12px !important; } .section.line-bottom { box-shadow: none; } .section.line-bottom.neon { box-shadow: 0 3px 15px #ff00ff; } .section.invisible { box-shadow: none; } .section.invisible:hover { box-shadow: none; } .neon { border: 2px solid #ff00ff; box-shadow: 0 0 10px #ff00ff, 0 0 20px #ff00ff; } .neon .description-text { text-shadow: 0 0 10px #ff00ff; } .section img { width: 120px; height: 120px; border-radius: 2px; object-fit: cover; margin-bottom: 20px; } .content-wrapper { transition: opacity 0.2s; } .content-wrapper:hover { opacity: 0.8; } .section-title { font-size: 1.5em; font-weight: 600; margin: 15px 0 10px; } .description-text { font-size: 1em; line-height: 1.6; margin: 10px auto 20px; max-width: 700px; padding: 0 20px; word-wrap: break-word; } .button-row { display: flex; gap: 10px; justify-content: center; margin-top: 20px; } button { border: none; border-radius: 3px; padding: 10px 20px; color: white; cursor: pointer; transition: transform 0.2s; font-size: 0.95em; font-weight: 500; } button:hover { transform: scale(1.05); } .add-btn, .style-btn, .save-btn { background: linear-gradient(90deg, #6b8cae, #7a8c9e); } .delete-btn { background: #ff4d4d; } .edit-btn { background: #6b8cae; } .cancel-btn { background: #666; } .edit-form { background: #1a1d22; border-radius: 4px; padding: 30px; box-shadow: 0 2px 8px rgba(0,0,0,0.3); } .edit-form h3 { margin-top: 0; color: #eaeaea; } .edit-form label { display: block; margin-top: 15px; margin-bottom: 5px; font-weight: 500; color: #eaeaea; } .edit-form input[type="text"], .edit-form input[type="color"], .edit-form textarea { width: 100%; padding: 10px; border-radius: 3px; border: 1px solid #444; background: #2a2d32; color: #eaeaea; font-family: inherit; font-size: 1em; box-sizing: border-box; } .input-with-button { display: flex; gap: 5px; align-items: center; } .input-with-button input { flex: 1; } .browse-btn { background: #6b8cae; padding: 10px 15px; white-space: nowrap; flex-shrink: 0; } .edit-form textarea { resize: vertical; min-height: 120px; line-height: 1.5; } .edit-form input[type="color"] { width: 80px; height: 40px; cursor: pointer; } .form-buttons { display: flex; gap: 10px; margin-top: 20px; justify-content: center; } .overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.85); display: flex; justify-content: center; align-items: center; z-index: 1000; animation: fadeIn 0.2s; padding: 20px; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .modal { background: #1a1d22; border-radius: 4px; padding: 40px; max-width: 700px; width: 100%; max-height: 80vh; overflow-y: auto; position: relative; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); animation: slideUp 0.3s; } @keyframes slideUp { from { transform: translateY(30px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } .close-btn { position: absolute; top: 15px; right: 15px; background: #ff4d4d; width: 40px; height: 40px; border-radius: 3px; display: flex; align-items: center; justify-content: center; font-size: 1.3em; padding: 0; } .modal-image { width: 200px; height: 200px; border-radius: 2px; object-fit: cover; margin: 0 auto 20px; display: block; } .modal-title { font-size: 2em; font-weight: 700; color: #eaeaea; text-align: center; margin: 0 0 15px; } .audio-btn { background: linear-gradient(90deg, #6b8cae, #7a8c9e); margin: 0 auto 20px; display: block; } .modal-text { font-size: 1.15em; line-height: 1.8; color: #eaeaea; text-align: left; white-space: pre-wrap; word-wrap: break-word; font-family: Georgia, serif; } .modal-text::first-letter { font-size: 3.5em; font-weight: bold; float: left; line-height: 0.9; margin-right: 8px; margin-top: 4px; } .file-browser { max-width: 800px; } .file-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 15px; max-height: 60vh; overflow-y: auto; padding: 10px; } .file-item { border: 2px solid #444; border-radius: 4px; padding: 10px; cursor: pointer; transition: all 0.2s; background: #2a2d32; text-align: center; } .file-item:hover { border-color: #6b8cae; transform: scale(1.05); } .file-preview { width: 100%; height: 100px; object-fit: cover; border-radius: 3px; margin-bottom: 8px; } .file-name { font-size: 0.85em; color: #d4d4d4; word-break: break-all; } `; document.head.appendChild(style); }; document.addEventListener('DOMContentLoaded', SectionLayout); </script> </body> </html>