Annoucement Web -Depreciated
This commit is contained in:
Executable
+311
@@ -0,0 +1,311 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Control Panel - Church Announcements</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- SortableJS & Flatpickr CSS -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.15.0/Sortable.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
|
||||
<style>
|
||||
/* Basic styling */
|
||||
body { background: #222; color: #fff; font-family: sans-serif; margin: 0; padding: 0; }
|
||||
#pageTitle { text-align: center; margin: 1rem 0; font-family: 'Roboto', sans-serif; text-transform: uppercase; font-weight: bold; letter-spacing: 1px; font-size: 2rem; }
|
||||
.preview-container { max-width: 1000px; margin: 0 auto 1rem; text-align: center; }
|
||||
.preview-iframe { width: 50%; aspect-ratio: 16/9; border: 3px solid #fff; border-radius: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.5); }
|
||||
.tab-nav { display: flex; justify-content: center; margin-bottom: 1rem; }
|
||||
.tab-nav button { background: #444; border: none; color: #fff; padding: .5rem 1rem; margin: 0 .5rem; cursor: pointer; font-size: 1rem; border-radius: 4px; transition: background .3s; }
|
||||
.tab-nav button:hover { background: #666; }
|
||||
.active-tab { background: #4caf50 !important; }
|
||||
#announcementsSection { display: block; }
|
||||
#bibleSection { display: none; max-width: 1000px; margin: 0 auto; padding: 1rem 0; }
|
||||
#bibleSection h2 { text-align: center; margin-bottom: 1rem; }
|
||||
|
||||
/* Slider-style toggle */
|
||||
#activeFilterContainer { text-align: right; padding: 0 1rem; }
|
||||
.toggle-label { position: relative; display: inline-block; width: 60px; height: 34px; }
|
||||
.toggle-label input { opacity: 0; width: 0; height: 0; position: absolute; }
|
||||
.toggle-slider { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: #888; border-radius: 34px; transition: .4s; cursor: pointer; }
|
||||
.toggle-slider:before { content: ""; position: absolute; height: 26px; width: 26px; left: 4px; bottom: 4px; background: #fff; border-radius: 50%; transition: .4s; }
|
||||
.toggle-label input:checked + .toggle-slider { background: #4caf50; }
|
||||
.toggle-label input:checked + .toggle-slider:before { transform: translateX(26px); }
|
||||
.toggle-slider .icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 14px; pointer-events: none; opacity: 0; transition: opacity .2s; color: #4caf50; }
|
||||
.toggle-label input:checked + .toggle-slider .icon.check { opacity: 1; }
|
||||
.toggle-label input:not(:checked) + .toggle-slider .icon.cross { opacity: 1; }
|
||||
|
||||
/* Slides grid */
|
||||
.slides-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(325px,1fr)); gap: 2rem; padding: 1rem; justify-items: center; }
|
||||
.slide-item { width: 150px; cursor: pointer; position: relative; transition: outline-color .3s ease; }
|
||||
.slide-item img { width: 100%; border-radius: 10px; outline: 3px solid transparent; outline-offset: -3px; box-shadow: 0 0 10px rgba(0,0,0,0.5); transition: outline-color .3s ease; }
|
||||
.slide-item.active img { outline-color: lime; }
|
||||
@media(min-width:768px){ .slide-item{ width:325px; } }
|
||||
|
||||
/* Bible search table */
|
||||
#bibleSearchContainer { text-align: center; margin-bottom: 1rem; }
|
||||
#bibleSearchInput { width: 60%; padding: .5rem; font-size:1rem; background:#333; border:1px solid #555; border-radius:4px; color:#fff; }
|
||||
#bibleSearchButton { padding:.5rem 1rem; margin-left:.5rem; background:#4caf50; border:none; border-radius:4px; color:#fff; cursor:pointer; }
|
||||
#bibleTable { width:100%; border-collapse:collapse; }
|
||||
#bibleTable th, #bibleTable td { border:1px solid #555; padding:.5rem; text-align:left; }
|
||||
#bibleTable th { background:#333; }
|
||||
|
||||
.custom-context-menu { position:absolute; display:none; z-index:9999; background:#333; border:1px solid #444; border-radius:8px; padding:8px; box-shadow:0 2px 5px rgba(0,0,0,0.5); min-width:160px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="pageTitle">Announcements</h1>
|
||||
|
||||
<div class="preview-container">
|
||||
<iframe id="previewIframe" class="preview-iframe" src="http://127.0.0.1:5000/"></iframe>
|
||||
</div>
|
||||
|
||||
<!-- Slider toggle -->
|
||||
<div id="activeFilterContainer">
|
||||
<label class="toggle-label">
|
||||
<input type="checkbox" id="activeFilterToggle">
|
||||
<span class="toggle-slider">
|
||||
<span class="icon check">✔</span>
|
||||
<span class="icon cross">✖</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Tabs -->
|
||||
<div class="tab-nav">
|
||||
<button id="announcementsTab" class="active-tab">Announcements</button>
|
||||
<button id="bibleTab">Bible Verses</button>
|
||||
</div>
|
||||
|
||||
<!-- Announcements Section -->
|
||||
<div id="announcementsSection">
|
||||
<div class="slides-container" id="slidesContainer">
|
||||
{% for slide, data in statuses %}
|
||||
<div class="slide-item {% if data.active %}active{% endif %}"
|
||||
data-slide="{{ slide }}"
|
||||
data-duration="{{ data.duration|default(7) }}"
|
||||
data-title="{{ data.title|default(slide.split('.')[0]) }}"
|
||||
data-end_date="{{ data.end_date|default('') }}">
|
||||
<img src="{{ slide_urls[slide] }}" alt="{{ slide }}">
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bible Verses Section -->
|
||||
<div id="bibleSection">
|
||||
<h2>Bible Verses</h2>
|
||||
<div id="bibleSearchContainer">
|
||||
<input type="text" id="bibleSearchInput" placeholder="Search verses..." />
|
||||
<button id="bibleSearchButton">Search</button>
|
||||
</div>
|
||||
<table id="bibleTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Book</th><th>Chapter</th><th>Verse</th><th>Text</th><th>Translation</th><th>Add/Remove</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Context Menu -->
|
||||
<div class="custom-context-menu" id="customContextMenu">
|
||||
<!-- existing context-menu items + submenus -->
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.4/socket.io.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
||||
<script>
|
||||
// 1) Load persisted registry
|
||||
let bibleRegistry = [];
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
fetch('/bible_registry')
|
||||
.then(r => r.json())
|
||||
.then(data => { bibleRegistry = data; })
|
||||
.catch(console.error);
|
||||
});
|
||||
|
||||
// 2) Tab switching
|
||||
const announcementsTab = document.getElementById('announcementsTab'),
|
||||
bibleTab = document.getElementById('bibleTab'),
|
||||
announcementsSec = document.getElementById('announcementsSection'),
|
||||
bibleSec = document.getElementById('bibleSection'),
|
||||
pageTitle = document.getElementById('pageTitle'),
|
||||
activeToggle = document.getElementById('activeFilterToggle'),
|
||||
slidesContainer = document.getElementById('slidesContainer');
|
||||
|
||||
announcementsTab.addEventListener('click', () => {
|
||||
announcementsSec.style.display = 'block';
|
||||
bibleSec.style.display = 'none';
|
||||
announcementsTab.classList.add('active-tab');
|
||||
bibleTab.classList.remove('active-tab');
|
||||
pageTitle.innerText = 'Announcements';
|
||||
activeToggle.parentElement.style.display = 'block';
|
||||
});
|
||||
bibleTab.addEventListener('click', () => {
|
||||
announcementsSec.style.display = 'none';
|
||||
bibleSec.style.display = 'block';
|
||||
bibleTab.classList.add('active-tab');
|
||||
announcementsTab.classList.remove('active-tab');
|
||||
pageTitle.innerText = 'Bible Verses';
|
||||
activeToggle.parentElement.style.display = 'none';
|
||||
});
|
||||
|
||||
// 3) Drag-and-drop ordering
|
||||
let isDragging = false;
|
||||
Sortable.create(slidesContainer, {
|
||||
animation: 150, delay: 50,
|
||||
onStart: () => { isDragging = true; },
|
||||
onEnd: () => {
|
||||
isDragging = false;
|
||||
const order = Array.from(slidesContainer.children).map(c => c.dataset.slide);
|
||||
fetch('/update_order', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ order })
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 4) Toggle hiding inactive slides
|
||||
activeToggle.addEventListener('change', () => {
|
||||
slidesContainer.querySelectorAll('.slide-item').forEach(item => {
|
||||
item.style.display = activeToggle.checked && !item.classList.contains('active')
|
||||
? 'none' : 'block';
|
||||
});
|
||||
});
|
||||
|
||||
// 5) Click slide to activate/deactivate
|
||||
slidesContainer.addEventListener('click', e => {
|
||||
if (isDragging) return;
|
||||
const item = e.target.closest('.slide-item');
|
||||
if (item && e.button === 0) {
|
||||
item.classList.toggle('active');
|
||||
fetch('/update_active', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
slide: item.dataset.slide,
|
||||
active: item.classList.contains('active')
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 6) Bible search & add/remove logic
|
||||
const bibleSearchInput = document.getElementById('bibleSearchInput'),
|
||||
bibleSearchButton = document.getElementById('bibleSearchButton'),
|
||||
bibleTableBody = document.querySelector('#bibleTable tbody');
|
||||
|
||||
bibleSearchButton.addEventListener('click', () => {
|
||||
const q = bibleSearchInput.value.trim();
|
||||
bibleTableBody.innerHTML = '';
|
||||
|
||||
// Empty query → show what's in registry
|
||||
if (!q) {
|
||||
bibleRegistry.forEach(entry => {
|
||||
const idx = entry.reference.lastIndexOf(' '),
|
||||
book = entry.reference.slice(0, idx),
|
||||
[chapter, verse] = entry.reference.slice(idx + 1).split(':'),
|
||||
tr = document.createElement('tr');
|
||||
tr.innerHTML = `
|
||||
<td>${book}</td>
|
||||
<td>${chapter}</td>
|
||||
<td>${verse}</td>
|
||||
<td>${entry.verse}</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
`;
|
||||
const btn = document.createElement('button');
|
||||
btn.textContent = '–';
|
||||
btn.style.width = '2rem';
|
||||
btn.dataset.id = entry.id;
|
||||
btn.addEventListener('click', () => {
|
||||
fetch('/remove_bible_verse', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id: Number(btn.dataset.id) })
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(resp => {
|
||||
if (resp.status === 'success') {
|
||||
bibleRegistry = bibleRegistry.filter(e => e.id !== entry.id);
|
||||
tr.remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
tr.cells[5].appendChild(btn);
|
||||
bibleTableBody.appendChild(tr);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Non-empty → query DB
|
||||
fetch('/search_verses?q=' + encodeURIComponent(q))
|
||||
.then(r => r.json())
|
||||
.then(results => {
|
||||
results.forEach(verse => {
|
||||
const ref = `${verse.book} ${verse.chapter}:${verse.verse}`,
|
||||
exist = bibleRegistry.find(e => e.reference === ref),
|
||||
tr = document.createElement('tr');
|
||||
tr.innerHTML = `
|
||||
<td>${verse.book}</td>
|
||||
<td>${verse.chapter}</td>
|
||||
<td>${verse.verse}</td>
|
||||
<td>${verse.text}</td>
|
||||
<td>${verse.translation}</td>
|
||||
<td></td>
|
||||
`;
|
||||
const btn = document.createElement('button');
|
||||
btn.style.width = '2rem';
|
||||
if (exist) {
|
||||
btn.textContent = '–';
|
||||
btn.dataset.id = exist.id;
|
||||
} else {
|
||||
btn.textContent = '+';
|
||||
}
|
||||
btn.addEventListener('click', () => {
|
||||
if (btn.textContent === '+') {
|
||||
// Add
|
||||
fetch('/add_bible_verse', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ verse: verse.text, reference: ref })
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(resp => {
|
||||
if (resp.status === 'success') {
|
||||
btn.textContent = '–';
|
||||
btn.dataset.id = resp.entry.id;
|
||||
bibleRegistry.push(resp.entry);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Remove
|
||||
const id = Number(btn.dataset.id);
|
||||
fetch('/remove_bible_verse', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id })
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(resp => {
|
||||
if (resp.status === 'success') {
|
||||
bibleRegistry = bibleRegistry.filter(e => e.id !== id);
|
||||
btn.textContent = '+';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
tr.cells[5].appendChild(btn);
|
||||
bibleTableBody.appendChild(tr);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
bibleSearchInput.addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter') bibleSearchButton.click();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user