aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
Diffstat (limited to 'src/features')
-rw-r--r--src/features/messages.js37
1 files changed, 31 insertions, 6 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index a3452ee..cab7a97 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -43,6 +43,7 @@ import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
import { sha256 } from '@noble/hashes/sha256';
import { base64urlnopad } from '@scure/base';
import { t, getLang } from '../i18n.js';
+import { createGifPicker, gifMedia } from '../gif-picker.js';
import { inLanguage, isMachinePost, guessLang } from '../lang-guess.js';
import { translatePieces, translatable as transParts } from '../translate-split.js';
import { animateZap, warmZapSound } from '../zap-animation.js';
@@ -82,6 +83,10 @@ const OPEN_VIEW = (() => {
export function messagesFeature(ctx) {
const { h, ui, render, wallet, toast, hook } = ctx;
+ const gifs = createGifPicker({ h, t, ui, render });
+ // NIP-92: an attachment described, so clients needn't sniff the URL
+ const mediaImeta = (m) => ['imeta', 'url ' + m.url, ...(m.m ? ['m ' + m.m] : []), ...(m.dim ? ['dim ' + m.dim] : []),
+ ...(m.size ? ['size ' + m.size] : []), ...(m.alt ? ['alt ' + m.alt] : [])];
// ---- persisted state ----------------------------------------------------
@@ -9796,8 +9801,7 @@ export function messagesFeature(ctx) {
render();
try {
// NIP-92: what we uploaded, described, so clients needn't sniff the URL
- const imeta = media.filter((m) => m && m.url)
- .map((m) => ['imeta', 'url ' + m.url, ...(m.m ? ['m ' + m.m] : [])]);
+ const imeta = media.filter((m) => m && m.url).map(mediaImeta);
// NIP-18 quote: the reference is already in the text; the tags let a
// client render the quoted post inline and tell its author
const q = ui.quoteOf && text.includes(ui.quoteOf.id.slice(0, 8))
@@ -9833,8 +9837,7 @@ export function messagesFeature(ctx) {
])].filter((pk) => pk !== id.pubkey).slice(0, 8);
// and whoever the reply mentions by name (NIP-27), beyond the thread's eight
for (const pk of mentionedPks(text)) if (pk !== id.pubkey && !pTags.includes(pk)) pTags.push(pk);
- const imeta = (ui.postMedia || []).filter((m) => m && m.url && text.includes(m.url))
- .map((m) => ['imeta', 'url ' + m.url, ...(m.m ? ['m ' + m.m] : [])]);
+ const imeta = (ui.postMedia || []).filter((m) => m && m.url && text.includes(m.url)).map(mediaImeta);
const root = c.root || (target.id === rootId ? target : null);
// the root's scope: from the root itself, or — not loaded yet — copied
// off the comment being answered, which carries it
@@ -10726,10 +10729,22 @@ export function messagesFeature(ctx) {
type: 'file', id: 'post-file', accept: 'image/*,video/*', style: 'display:none',
onChange: async (e) => { const f = e.target.files && e.target.files[0]; e.target.value = ''; await attachMedia(f); },
}),
+ gifs.button('post', 'attach-btn gif-btn'),
h('div', { class: 'row gap6 composer-options' },
previewBtn(!!ui.postPreview, () => { ui.postPreview = !ui.postPreview; render(); }),
h('button', { class: 'btn-ghost btn-sm', onClick: requestCancelPost }, t('cancel')))),
- postCancelWarning());
+ postCancelWarning(),
+ gifs.sheet('post', (g) => {
+ const cur = composeText().replace(/\s+$/, '');
+ const next = (cur ? cur + '\n' : '') + g.url;
+ ui.profCompose = next;
+ setDraft(POST_DRAFT, next);
+ (ui.postMedia ||= []).push(gifMedia(g));
+ ui.postPreview = true;
+ const el = document.querySelector('.post-input');
+ if (el) el.value = next;
+ render();
+ }));
}
// ---- the feed view --------------------------------------------------------
@@ -12431,7 +12446,17 @@ export function messagesFeature(ctx) {
// animation, so re-stick once now and once when it has settled.
onFocus: () => { stickToBottom(); setTimeout(stickToBottom, 350); },
}),
- h('button', { class: 'btn-primary btn-sm', onClick: onSend }, t('msgSend'))));
+ gifs.button('chat:' + draftKey, 'iconbtn chat-gif'),
+ h('button', { class: 'btn-primary btn-sm', onClick: onSend }, t('msgSend'))),
+ // a picked GIF goes out at once, after whatever was typed
+ gifs.sheet('chat:' + draftKey, (g) => {
+ const cur = draftFor(draftKey).replace(/\s+$/, '');
+ const next = (cur ? cur + ' ' : '') + g.url;
+ setDraft(draftKey, next);
+ const el = document.getElementById('msg-draft');
+ if (el) el.value = next;
+ onSend();
+ }));
};
// ---- home ---------------------------------------------------------------