96 lines
4.2 KiB
HTML
96 lines
4.2 KiB
HTML
@include(snippets/header)
|
|
|
|
<div class="container" style="padding-top: 20px;">
|
|
<h2>Custom Emojis</h2>
|
|
|
|
<div class="upload-form"
|
|
style="margin-bottom: 20px; text-align: left; background: var(--dropdown-bg); padding: 15px; border: 1px solid var(--nav-border-color);">
|
|
<h4>Add New Emoji</h4>
|
|
<input type="text" id="emoji-name" placeholder="Name (e.g. pingu)"
|
|
style="background: var(--bg); border: 1px solid var(--black); padding: 5px; color: var(--white);">
|
|
<input type="text" id="emoji-url" placeholder="URL (e.g. /s/img/pingu.gif)"
|
|
style="background: var(--bg); border: 1px solid var(--black); padding: 5px; color: var(--white); width: 300px;">
|
|
<button id="add-emoji" class="btn-upload"
|
|
style="width: auto; padding: 5px 15px; border: 1px solid var(--nav-border-color); background: var(--bg); color: var(--white); cursor: pointer;">Add</button>
|
|
</div>
|
|
|
|
<div class="upload-form" style="overflow-x: auto;">
|
|
<table style="width: 100%; border-collapse: collapse; color: var(--white);">
|
|
<thead>
|
|
<tr style="border-bottom: 1px solid var(--nav-border-color); text-align: left;">
|
|
<th style="padding: 10px;">Preview</th>
|
|
<th style="padding: 10px;">Name</th>
|
|
<th style="padding: 10px;">URL</th>
|
|
<th style="padding: 10px;">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="emoji-list">
|
|
<!-- Populated by JS -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const loadEmojis = async () => {
|
|
try {
|
|
const res = await fetch('/api/v2/emojis');
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
const tbody = document.getElementById('emoji-list');
|
|
tbody.innerHTML = data.emojis.map(e =>
|
|
'<tr style="border-bottom: 1px solid rgba(255,255,255,0.05);">' +
|
|
'<td style="padding: 10px;"><img src="' + e.url + '" style="height: 30px; object-fit: contain;"></td>' +
|
|
'<td style="padding: 10px; font-family: monospace; font-size: 1.1em; color: var(--accent);">:' + e.name + ':</td>' +
|
|
'<td style="padding: 10px; opacity: 0.7;">' + e.url + '</td>' +
|
|
'<td style="padding: 10px;">' +
|
|
'<button onclick="deleteEmoji(' + e.id + ')" class="btn-remove" style="padding: 5px 10px; font-size: 0.8em; background: #c00; color: white; border: none; cursor: pointer;">Delete</button>' +
|
|
'</td>' +
|
|
'</tr>'
|
|
).join('');
|
|
}
|
|
} catch (err) { console.error(err); }
|
|
};
|
|
|
|
const addEmoji = async () => {
|
|
const name = document.getElementById('emoji-name').value;
|
|
const url = document.getElementById('emoji-url').value;
|
|
if (!name || !url) return alert('Fill both fields');
|
|
|
|
try {
|
|
const res = await fetch('/api/v2/admin/emojis', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, // Body parsing middleware uses this or JSON? Typically form-encoded in this stack
|
|
body: new URLSearchParams({ name, url })
|
|
});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
document.getElementById('emoji-name').value = '';
|
|
document.getElementById('emoji-url').value = '';
|
|
loadEmojis();
|
|
} else {
|
|
alert('Failed: ' + data.message);
|
|
}
|
|
} catch (e) {
|
|
alert('Error: ' + e.message);
|
|
}
|
|
};
|
|
|
|
const deleteEmoji = async (id) => {
|
|
if (!confirm('Delete this emoji?')) return;
|
|
try {
|
|
const res = await fetch('/api/v2/admin/emojis/' + id + '/delete', { method: 'POST' });
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
loadEmojis();
|
|
} else {
|
|
alert('Failed');
|
|
}
|
|
} catch (e) { alert(e); }
|
|
};
|
|
|
|
document.getElementById('add-emoji').addEventListener('click', addEmoji);
|
|
loadEmojis();
|
|
</script>
|
|
|
|
@include(snippets/footer) |