From 02075fbd47f4c67f44b2a11821fab3ae3402146a Mon Sep 17 00:00:00 2001 From: sravan Date: Wed, 15 Jul 2026 15:30:44 +0530 Subject: [PATCH] feat(chat): GIF picker via server-proxied GIPHY (#5) (batch87) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Server: GET /api/gifs proxies GIPHY search/trending. The API key is read from the server env only (config.GIPHY_API_KEY, from the gitignored .env) and NEVER reaches the browser; the picker is hidden when it isn't configured. - Emoji picker gains a GIF tab (separated from the emoji categories) with a search box + a 2-col grid, "Powered by GIPHY" attribution. Clicking a GIF sends it immediately. - GIFs are HOTLINKED to GIPHY's CDN (their terms require this — no re-hosting): the message body is the GIF url, and a body that is a lone GIF url renders inline as the animated GIF (reusing the image/lightbox path). Sidebar previews + notifications show "🎞️ GIF", not the raw url. Key is NOT in git — set as GIPHY_API_KEY in the server .env. Co-Authored-By: Claude Opus 4.8 --- server/config.js | 5 +++ server/public/home.html | 73 ++++++++++++++++++++++++++++++++++++----- server/routes.js | 40 +++++++++++++++++++++- 3 files changed, 109 insertions(+), 9 deletions(-) diff --git a/server/config.js b/server/config.js index 993fce5..e1d608f 100644 --- a/server/config.js +++ b/server/config.js @@ -38,6 +38,10 @@ const SMTP_FROM = process.env.SMTP_FROM || (SMTP_USER ? ('Biz Connect <' + SMTP_ const SMTP_ENABLED = !!(SMTP_HOST && SMTP_USER && SMTP_PASS); const PUBLIC_BASE_URL = (process.env.PUBLIC_BASE_URL || 'https://remote.bizgaze.com').replace(/\/+$/, ''); +// GIPHY GIF search (#5). Key is read from the server env only and never sent to the browser — the client +// calls our /api/gifs proxy. GIF picker is hidden when this isn't configured. +const GIPHY_API_KEY = process.env.GIPHY_API_KEY || ''; + module.exports = { PORT: process.env.PORT || 8090, HTTPS_PORT: process.env.HTTPS_PORT || 8443, @@ -53,6 +57,7 @@ module.exports = { SMTP_FROM, SMTP_ENABLED, PUBLIC_BASE_URL, + GIPHY_API_KEY, PUBLIC_DIR, REC_DIR, TRANS_DIR, diff --git a/server/public/home.html b/server/public/home.html index 071aa74..0e1a1a7 100644 --- a/server/public/home.html +++ b/server/public/home.html @@ -605,6 +605,24 @@ .emoji-tabs{display:flex;border-bottom:1px solid var(--line);flex:0 0 auto;} .emoji-tabs button{flex:1;border:none;background:transparent;font-size:1.05rem;padding:.35rem 0;cursor:pointer;opacity:.55;} .emoji-tabs button.active{opacity:1;background:var(--blue-soft);} + /* #5 GIF tab: separated from the emoji category tabs */ + .emoji-tabs .et-sep{width:1px;align-self:stretch;margin:.3rem .15rem;background:var(--line);flex:0 0 auto;} + .emoji-tabs button[data-gif]{flex:0 0 auto;font-size:.7rem;font-weight:800;letter-spacing:.02em;padding:.35rem .5rem;color:var(--blue);opacity:.7;} + .emoji-tabs button[data-gif].active{opacity:1;} + .gif-wrap{display:flex;flex-direction:column;min-height:0;flex:1 1 auto;} + .gif-search{position:relative;padding:.5rem;flex:0 0 auto;} + .gif-search input{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:9px;padding:.5rem 2rem .5rem .6rem;font:inherit;font-size:.85rem;background:#fbfcfe;color:var(--ink);} + .gif-search input:focus{outline:none;border-color:var(--blue);} + .gif-search svg{position:absolute;right:1.1rem;top:50%;transform:translateY(-50%);color:var(--muted);pointer-events:none;} + .gif-grid{flex:1 1 auto;overflow-y:auto;display:grid;grid-template-columns:1fr 1fr;gap:.35rem;padding:0 .5rem .3rem;align-content:start;} + .gif-cell{border:none;background:#f1f5f9;border-radius:9px;overflow:hidden;cursor:pointer;padding:0;aspect-ratio:1;} + .gif-cell img{width:100%;height:100%;object-fit:cover;display:block;} + .gif-cell:hover{outline:2px solid var(--blue);} + .gif-load{grid-column:1/-1;display:grid;place-items:center;padding:1.4rem;} + .gif-load img{animation:ptrspin .8s linear infinite;} + .gif-empty{grid-column:1/-1;text-align:center;color:var(--muted);font-size:.82rem;padding:1.4rem .5rem;} + .gif-attr{flex:0 0 auto;text-align:center;font-size:.6rem;color:var(--muted);letter-spacing:.03em;padding:.15rem 0 .35rem;} + .bubble .msg-gif{max-width:230px;max-height:230px;border-radius:12px;cursor:pointer;} .emoji-grid{flex:1;overflow-y:auto;display:grid;grid-template-columns:repeat(8,1fr);gap:.1rem;padding:.4rem;align-content:start;} .emoji-grid button{border:none;background:transparent;font-size:1.25rem;cursor:pointer;padding:.2rem;border-radius:6px;line-height:1.15;} .emoji-grid button:hover{background:var(--blue-soft);} @@ -1058,7 +1076,7 @@ -