From be13d4d45a385926956dc8cfcdad3b2035eedbad Mon Sep 17 00:00:00 2001 From: pavel Date: Wed, 25 Feb 2026 00:29:37 +0100 Subject: [PATCH 01/51] sadf --- desktop/app.js | 21 ++++++----- desktop/styles.css | 88 ++++++++++++++++++++++++++++++++++++++++++++++ static/app.js | 21 ++++++----- static/styles.css | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 202 insertions(+), 16 deletions(-) diff --git a/desktop/app.js b/desktop/app.js index bc67687..9d8b9d8 100644 --- a/desktop/app.js +++ b/desktop/app.js @@ -1455,11 +1455,12 @@ async function init() { }; // --- GIF Picker Logic --- - const GIPHY_API_KEY = "dc6zaTOxFJmzC"; // Public beta key + const TENOR_API_KEY = "exTiFGKJ0CzESIHzVQWy3pRO8I1MAdpRomg95DBSu2sg6e7YcHgThMI4giGAx8D0"; // Placeholder / Public key if available, otherwise "YOUR_API_KEY" + const TENOR_CLIENT_KEY = "pavel-discord"; el.gifBtn.onclick = () => { el.gifPicker.classList.remove("hidden"); - searchGifs(""); // Initial trending search + searchGifs(""); // Initial featured search }; el.gifPickerClose.onclick = () => { @@ -1476,14 +1477,15 @@ async function init() { async function searchGifs(query) { el.gifResults.innerHTML = '
Searching...
'; + const baseUrl = "https://api.klipy.com/v2"; 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`; + ? `${baseUrl}/search?q=${encodeURIComponent(query)}&key=${TENOR_API_KEY}&client_key=${TENOR_CLIENT_KEY}&limit=20` + : `${baseUrl}/featured?key=${TENOR_API_KEY}&client_key=${TENOR_CLIENT_KEY}&limit=20`; try { const res = await fetch(endpoint); const data = await res.json(); - renderGifs(data.data); + renderGifs(data.results); } catch (err) { el.gifResults.innerHTML = '
Error loading GIFs
'; } @@ -1497,12 +1499,15 @@ async function init() { } gifs.forEach(gif => { - const imgUrl = gif.images.fixed_height.url; + // Use tinygif for preview, standard gif for sending + const previewUrl = gif.media_formats.tinygif.url; + const fullUrl = gif.media_formats.gif.url; + const item = document.createElement("div"); item.className = "gif-item"; - item.innerHTML = ``; + item.innerHTML = ``; item.onclick = () => { - sendGif(imgUrl); + sendGif(fullUrl); el.gifPicker.classList.add("hidden"); el.gifSearchInput.value = ""; }; diff --git a/desktop/styles.css b/desktop/styles.css index 218927d..7bfb922 100644 --- a/desktop/styles.css +++ b/desktop/styles.css @@ -864,6 +864,94 @@ select { object-fit: contain; } +/* ═══════════════════════════════════════════════════════════ */ +/* Sound Board */ +/* ═══════════════════════════════════════════════════════════ */ +.soundboard-container { + padding: 12px; + background: var(--bg-secondary); + border-top: 1px solid rgba(255, 255, 255, 0.03); + display: flex; + flex-direction: column; + gap: 8px; +} + +.soundboard-header { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.4px; + color: var(--text-muted); +} + +.soundboard-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); + gap: 8px; + max-height: 200px; + overflow-y: auto; +} + +.sound-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + padding: 10px 8px; + background: var(--bg-darker); + border-radius: var(--radius-md); + cursor: pointer; + transition: all var(--transition); + border: 1px solid transparent; + position: relative; +} + +.sound-item:hover { + background: var(--bg-modifier-hover); + transform: translateY(-2px); + border-color: rgba(255, 255, 255, 0.06); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +.sound-item:active { + transform: scale(0.95); +} + +.sound-delete { + position: absolute; + top: 4px; + right: 4px; + width: 18px; + height: 18px; + border-radius: 50%; + background: rgba(0, 0, 0, 0.6); + color: var(--text-muted); + display: grid; + place-items: center; + opacity: 0; + transition: all var(--transition); + z-index: 2; +} + +.sound-delete:hover { + background: var(--danger); + color: #fff; + transform: scale(1.1); +} + +.sound-item:hover .sound-delete { + opacity: 1; +} + +.sound-icon { + font-size: 24px; + display: block; + object-fit: contain; +} + .sound-name { font-size: 11px; text-align: center; diff --git a/static/app.js b/static/app.js index adc84c9..85b910d 100644 --- a/static/app.js +++ b/static/app.js @@ -1434,11 +1434,12 @@ async function init() { }; // --- GIF Picker Logic --- - const GIPHY_API_KEY = "dc6zaTOxFJmzC"; // Public beta key + const TENOR_API_KEY = "exTiFGKJ0CzESIHzVQWy3pRO8I1MAdpRomg95DBSu2sg6e7YcHgThMI4giGAx8D0"; // Placeholder / Public key if available, otherwise "YOUR_API_KEY" + const TENOR_CLIENT_KEY = "pavel-discord"; el.gifBtn.onclick = () => { el.gifPicker.classList.remove("hidden"); - searchGifs(""); // Initial trending search + searchGifs(""); // Initial featured search }; el.gifPickerClose.onclick = () => { @@ -1455,14 +1456,15 @@ async function init() { async function searchGifs(query) { el.gifResults.innerHTML = '
Searching...
'; + const baseUrl = "https://api.klipy.com/v2"; 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`; + ? `${baseUrl}/search?q=${encodeURIComponent(query)}&key=${TENOR_API_KEY}&client_key=${TENOR_CLIENT_KEY}&limit=20` + : `${baseUrl}/featured?key=${TENOR_API_KEY}&client_key=${TENOR_CLIENT_KEY}&limit=20`; try { const res = await fetch(endpoint); const data = await res.json(); - renderGifs(data.data); + renderGifs(data.results); } catch (err) { el.gifResults.innerHTML = '
Error loading GIFs
'; } @@ -1476,12 +1478,15 @@ async function init() { } gifs.forEach(gif => { - const imgUrl = gif.images.fixed_height.url; + // Use tinygif for preview, standard gif for sending + const previewUrl = gif.media_formats.tinygif.url; + const fullUrl = gif.media_formats.gif.url; + const item = document.createElement("div"); item.className = "gif-item"; - item.innerHTML = ``; + item.innerHTML = ``; item.onclick = () => { - sendGif(imgUrl); + sendGif(fullUrl); el.gifPicker.classList.add("hidden"); el.gifSearchInput.value = ""; }; diff --git a/static/styles.css b/static/styles.css index 218927d..7bfb922 100644 --- a/static/styles.css +++ b/static/styles.css @@ -864,6 +864,94 @@ select { object-fit: contain; } +/* ═══════════════════════════════════════════════════════════ */ +/* Sound Board */ +/* ═══════════════════════════════════════════════════════════ */ +.soundboard-container { + padding: 12px; + background: var(--bg-secondary); + border-top: 1px solid rgba(255, 255, 255, 0.03); + display: flex; + flex-direction: column; + gap: 8px; +} + +.soundboard-header { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.4px; + color: var(--text-muted); +} + +.soundboard-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); + gap: 8px; + max-height: 200px; + overflow-y: auto; +} + +.sound-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + padding: 10px 8px; + background: var(--bg-darker); + border-radius: var(--radius-md); + cursor: pointer; + transition: all var(--transition); + border: 1px solid transparent; + position: relative; +} + +.sound-item:hover { + background: var(--bg-modifier-hover); + transform: translateY(-2px); + border-color: rgba(255, 255, 255, 0.06); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +.sound-item:active { + transform: scale(0.95); +} + +.sound-delete { + position: absolute; + top: 4px; + right: 4px; + width: 18px; + height: 18px; + border-radius: 50%; + background: rgba(0, 0, 0, 0.6); + color: var(--text-muted); + display: grid; + place-items: center; + opacity: 0; + transition: all var(--transition); + z-index: 2; +} + +.sound-delete:hover { + background: var(--danger); + color: #fff; + transform: scale(1.1); +} + +.sound-item:hover .sound-delete { + opacity: 1; +} + +.sound-icon { + font-size: 24px; + display: block; + object-fit: contain; +} + .sound-name { font-size: 11px; text-align: center; From bcac7fc375d38287b1e3c695ebf7e4358c8cecb2 Mon Sep 17 00:00:00 2001 From: pavel Date: Wed, 25 Feb 2026 00:38:34 +0100 Subject: [PATCH 02/51] h --- desktop/styles.css | 4 +++- static/styles.css | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/desktop/styles.css b/desktop/styles.css index 7bfb922..cb005b6 100644 --- a/desktop/styles.css +++ b/desktop/styles.css @@ -816,8 +816,9 @@ select { padding: 0 20px 20px; display: grid; grid-template-columns: repeat(2, 1fr); + grid-auto-rows: min-content; gap: 8px; - min-height: 200px; + min-height: 300px; } .gif-item { @@ -825,6 +826,7 @@ select { overflow: hidden; cursor: pointer; background: var(--bg-sidebar); + width: 100%; aspect-ratio: 16 / 9; transition: transform var(--transition); } diff --git a/static/styles.css b/static/styles.css index 7bfb922..cb005b6 100644 --- a/static/styles.css +++ b/static/styles.css @@ -816,8 +816,9 @@ select { padding: 0 20px 20px; display: grid; grid-template-columns: repeat(2, 1fr); + grid-auto-rows: min-content; gap: 8px; - min-height: 200px; + min-height: 300px; } .gif-item { @@ -825,6 +826,7 @@ select { overflow: hidden; cursor: pointer; background: var(--bg-sidebar); + width: 100%; aspect-ratio: 16 / 9; transition: transform var(--transition); } From 0273eab75395d9f240f6468e1a400453cdefdde6 Mon Sep 17 00:00:00 2001 From: pavel Date: Wed, 25 Feb 2026 01:00:07 +0100 Subject: [PATCH 03/51] a --- desktop/app.js | 30 +++++++++++++++++++++++++++--- desktop/index.html | 1 + desktop/preload.js | 5 +++++ desktop/styles.css | 37 +++++++++++++++++++++++++++++++++++++ main.js | 14 ++++++++++---- static/app.js | 10 +++++++++- static/index.html | 1 + static/styles.css | 37 +++++++++++++++++++++++++++++++++++++ 8 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 desktop/preload.js diff --git a/desktop/app.js b/desktop/app.js index 9d8b9d8..f40ef0b 100644 --- a/desktop/app.js +++ b/desktop/app.js @@ -71,6 +71,7 @@ const el = { addGuildBtn: document.getElementById("add-guild-btn"), guildTitle: document.getElementById("guild-title"), createInviteBtn: document.getElementById("create-invite-btn"), + inviteCopiedBadge: document.getElementById("invite-copied-badge"), // Channels channelList: document.getElementById("channel-list"), @@ -536,11 +537,27 @@ async function createInviteLink() { method: "POST", body: JSON.stringify({ max_uses: 50, expires_in_hours: 24 }), }); - const link = `${location.origin}/?invite=${encodeURIComponent(invite.code)}`; + // Use the backend URL if available, otherwise fallback to current origin + const base = API_BASE_URL ? new URL(API_BASE_URL).origin : location.origin; + const link = `${base}/?invite=${encodeURIComponent(invite.code)}`; + + // Use Electron's native clipboard API if available (defined in preload.js) + if (window.electronAPI && window.electronAPI.copyToClipboard) { + try { + await window.electronAPI.copyToClipboard(link); + showCopiedBadge(); + return; + } catch (e) { + console.error("Electron clipboard write failed:", e); + } + } + + // Fallback to navigator.clipboard try { await navigator.clipboard.writeText(link); - alert(`Invite link copied:\n${link}`); - } catch { + showCopiedBadge(); + } catch (err) { + console.error("Navigator clipboard write failed:", err); prompt("Copy invite link:", link); } } catch (err) { @@ -548,6 +565,13 @@ async function createInviteLink() { } } +function showCopiedBadge() { + el.inviteCopiedBadge.classList.remove("hidden"); + setTimeout(() => { + el.inviteCopiedBadge.classList.add("hidden"); + }, 2000); +} + // --- Logic --- async function loadGuilds() { diff --git a/desktop/index.html b/desktop/index.html index c0b54c6..c58c23d 100644 --- a/desktop/index.html +++ b/desktop/index.html @@ -40,6 +40,7 @@