parent
d3a109a0cc
commit
92cba49b0d
6 changed files with 472 additions and 108 deletions
101
static/app.js
101
static/app.js
|
|
@ -106,6 +106,13 @@ const el = {
|
|||
mobileMembersBtn: document.getElementById("mobile-members-btn"),
|
||||
overlay: document.getElementById("overlay"),
|
||||
utilitySidebar: document.getElementById("utility-sidebar"),
|
||||
|
||||
// GIF Picker
|
||||
gifBtn: document.getElementById("gif-btn"),
|
||||
gifPicker: document.getElementById("gif-picker"),
|
||||
gifPickerClose: document.getElementById("gif-picker-close"),
|
||||
gifSearchInput: document.getElementById("gif-search-input"),
|
||||
gifResults: document.getElementById("gif-results"),
|
||||
};
|
||||
|
||||
// --- API Helpers ---
|
||||
|
|
@ -193,6 +200,18 @@ function escapeHtml(s) {
|
|||
.replaceAll("'", "'");
|
||||
}
|
||||
|
||||
function formatMessageBody(body) {
|
||||
const escaped = escapeHtml(body);
|
||||
// Detect GIF URLs (simple regex for demo)
|
||||
const urlRegex = /(https?:\/\/[^\s]+(?:\.gif|\/giphy\.gif)[^\s]*)/gi;
|
||||
if (urlRegex.test(body)) {
|
||||
return escaped.replace(urlRegex, (url) => {
|
||||
return `<div class="msg-gif"><img src="${url}" loading="lazy" /></div>`;
|
||||
});
|
||||
}
|
||||
return escaped;
|
||||
}
|
||||
|
||||
function formatDate(isoString) {
|
||||
const d = new Date(isoString);
|
||||
const now = new Date();
|
||||
|
|
@ -394,7 +413,7 @@ function renderMessages(messages) {
|
|||
const displayName = m.author_display_name || "Unknown User";
|
||||
|
||||
if (isGrouped) {
|
||||
row.innerHTML = `<div class="msg-content"><div class="msg-body">${escapeHtml(m.body)}</div></div>`;
|
||||
row.innerHTML = `<div class="msg-content"><div class="msg-body">${formatMessageBody(m.body)}</div></div>`;
|
||||
} else {
|
||||
row.innerHTML = `
|
||||
<div class="msg-avatar">${shortName(displayName)}</div>
|
||||
|
|
@ -403,7 +422,7 @@ function renderMessages(messages) {
|
|||
<span class="msg-author">${escapeHtml(displayName)}</span>
|
||||
<span class="msg-time">${formatDate(m.created_at)}</span>
|
||||
</div>
|
||||
<div class="msg-body">${escapeHtml(m.body)}</div>
|
||||
<div class="msg-body">${formatMessageBody(m.body)}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
|
@ -1414,6 +1433,84 @@ async function init() {
|
|||
}
|
||||
};
|
||||
|
||||
// --- GIF Picker Logic ---
|
||||
const GIPHY_API_KEY = "dc6zaTOxFJmzC"; // Public beta key
|
||||
|
||||
el.gifBtn.onclick = () => {
|
||||
el.gifPicker.classList.remove("hidden");
|
||||
searchGifs(""); // Initial trending search
|
||||
};
|
||||
|
||||
el.gifPickerClose.onclick = () => {
|
||||
el.gifPicker.classList.add("hidden");
|
||||
};
|
||||
|
||||
let searchTimeout = null;
|
||||
el.gifSearchInput.oninput = () => {
|
||||
clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(() => {
|
||||
searchGifs(el.gifSearchInput.value);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
async function searchGifs(query) {
|
||||
el.gifResults.innerHTML = '<div class="gif-loading">Searching...</div>';
|
||||
const endpoint = query
|
||||
? `https://api.giphy.com/v1/gifs/search?api_key=${GIPHY_API_KEY}&q=${encodeURIComponent(query)}&limit=20`
|
||||
: `https://api.giphy.com/v1/gifs/trending?api_key=${GIPHY_API_KEY}&limit=20`;
|
||||
|
||||
try {
|
||||
const res = await fetch(endpoint);
|
||||
const data = await res.json();
|
||||
renderGifs(data.data);
|
||||
} catch (err) {
|
||||
el.gifResults.innerHTML = '<div class="gif-loading">Error loading GIFs</div>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderGifs(gifs) {
|
||||
el.gifResults.innerHTML = "";
|
||||
if (!gifs || gifs.length === 0) {
|
||||
el.gifResults.innerHTML = '<div class="gif-loading">No GIFs found</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
gifs.forEach(gif => {
|
||||
const imgUrl = gif.images.fixed_height.url;
|
||||
const item = document.createElement("div");
|
||||
item.className = "gif-item";
|
||||
item.innerHTML = `<img src="${imgUrl}" loading="lazy" />`;
|
||||
item.onclick = () => {
|
||||
sendGif(imgUrl);
|
||||
el.gifPicker.classList.add("hidden");
|
||||
el.gifSearchInput.value = "";
|
||||
};
|
||||
el.gifResults.appendChild(item);
|
||||
});
|
||||
}
|
||||
|
||||
async function sendGif(url) {
|
||||
try {
|
||||
if (state.selectedTextChannelId) {
|
||||
await api(`/channels/${state.selectedTextChannelId}/messages`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ body: url }),
|
||||
});
|
||||
} else if (state.selectedDmUserId) {
|
||||
await api(`/dms/${state.selectedDmUserId}/messages`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ body: url }),
|
||||
});
|
||||
}
|
||||
const messages = state.selectedTextChannelId
|
||||
? await api(`/channels/${state.selectedTextChannelId}/messages?limit=100`)
|
||||
: await api(`/dms/${state.selectedDmUserId}/messages?limit=100`);
|
||||
renderMessages(messages);
|
||||
} catch (err) {
|
||||
console.error("Failed to send GIF", err);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
state.me = await api("/me");
|
||||
if (state.me && state.me.display_name) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue