Skip to content

Commit fe598ef

Browse files
committed
more emojis + gif upload fix
1 parent 7ee5b7f commit fe598ef

2 files changed

Lines changed: 101 additions & 42 deletions

File tree

src/lib/components/Composer.svelte

Lines changed: 96 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,71 @@
1313
1414
const introductionPrefix = '#nostr #introductions\n\n';
1515
const mentionSearchDelayMs = 220;
16+
const croppableImageTypes = new Set(['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/avif']);
1617
const emojiOptions = [
1718
'😀', '😃', '😄', '😁', '😆', '😂', '🤣', '😊', '🙂', '🙃', '😉', '😍',
18-
'😘', '😎', '🤩', '🥳', '😇', '🤔', '🫡', '🤝', '🙏', '👏', '🙌', '💪',
19-
'👍', '👎', '👊', '✌️', '🤘', '👌', '👀', '🧡', '❤️', '💙', '💜', '💚',
20-
'💛', '🖤', '🤍', '💔', '🔥', '', '', '', '🌟', '💥', '💯', '🎉',
21-
'🚀', '🌈', '☀️', '🌙', '🍕', '', '🍺', '🍻', '🎵', '🎸', '🎧', '📸',
22-
'💡', '📌', '📣', '🧠', '🛠️', '🔒', '🔑', '🛡️', '', '💸', '', '🏆'
19+
'😘', '😗', '😙', '😚', '😋', '😛', '😜', '🤪', '😝', '🤑', '🤗', '🤭',
20+
'🫢', '🫣', '🤫', '🤔', '🫡', '🤐', '🤨', '😐', '😑', '😶', '🫥', '😏',
21+
'😒', '🙄', '😬', '😮‍💨', '🤥', '😌', '😔', '😪', '🤤', '😴', '😷', '🤒',
22+
'🤕', '🤢', '🤮', '🤧', '🥵', '🥶', '🥴', '😵', '🤯', '🤠', '🥳', '🥸',
23+
'😎', '🤓', '🧐', '😕', '🫤', '😟', '🙁', '☹️', '😮', '😯', '😲', '😳',
24+
'🥺', '🥹', '😦', '😧', '😨', '😰', '😥', '😢', '😭', '😱', '😖', '😣',
25+
'😞', '😓', '😩', '😫', '😤', '😡', '😠', '🤬', '😈', '👿', '💀', '☠️',
26+
'💩', '🤡', '👻', '👽', '🤖', '😺', '😸', '😹', '😻', '😼', '😽', '🙀',
27+
'😿', '😾', '🙈', '🙉', '🙊', '💋', '💌', '💘', '💝', '💖', '💗', '💓',
28+
'💞', '💕', '💟', '❣️', '💔', '❤️', '🧡', '💛', '💚', '💙', '💜', '🖤',
29+
'🤍', '🤎', '💯', '💢', '💥', '💫', '💦', '💨', '🕳️', '💣', '💬', '👁️‍🗨️',
30+
'🗨️', '🗯️', '💭', '💤', '👋', '🤚', '🖐️', '', '🖖', '👌', '🤌', '🤏',
31+
'✌️', '🤞', '🫰', '🤟', '🤘', '🤙', '👈', '👉', '👆', '🖕', '👇', '☝️',
32+
'🫵', '👍', '👎', '', '👊', '🤛', '🤜', '👏', '🙌', '🫶', '👐', '🤲',
33+
'🤝', '🙏', '✍️', '💅', '🤳', '💪', '🦾', '🧠', '🫀', '🫁', '🦷', '🦴',
34+
'👀', '👁️', '👅', '👄', '🧑', '👨', '👩', '🧔', '👴', '👵', '🙍', '🙎',
35+
'🙅', '🙆', '💁', '🙋', '🧏', '🙇', '🤦', '🤷', '👨‍💻', '👩‍💻', '🧙', '🧚',
36+
'🧛', '🧜', '🧝', '🧞', '🧟', '🏃', '🚶', '🧘', '🛌', '🌍', '🌎', '🌏',
37+
'🌐', '🗺️', '🧭', '🏔️', '⛰️', '🌋', '🏕️', '🏖️', '🏜️', '🏝️', '🏞️', '🏟️',
38+
'🏛️', '🏗️', '🏘️', '🏠', '🏡', '🏢', '🏬', '🏥', '🏦', '🏨', '🏫', '🏭',
39+
'🌁', '🌃', '🌆', '🌇', '🌉', '🌌', '🎠', '🎡', '🎢', '🚂', '🚀', '🛸',
40+
'☀️', '🌤️', '', '🌥️', '☁️', '🌦️', '🌧️', '⛈️', '🌩️', '🌨️', '❄️', '☃️',
41+
'', '🌬️', '💨', '🌪️', '🌈', '🌂', '☂️', '', '🔥', '💧', '🌊', '🎄',
42+
'', '🎋', '🎍', '🌱', '🌿', '☘️', '🍀', '🎍', '🌵', '🌲', '🌳', '🌴',
43+
'🪵', '🌾', '🌺', '🌻', '🌹', '🥀', '🌷', '🌼', '🌸', '🍄', '🌰', '🪨',
44+
'🍇', '🍈', '🍉', '🍊', '🍋', '🍌', '🍍', '🥭', '🍎', '🍏', '🍐', '🍑',
45+
'🍒', '🍓', '🫐', '🥝', '🍅', '🫒', '🥥', '🥑', '🍆', '🥔', '🥕', '🌽',
46+
'🌶️', '🫑', '🥒', '🥬', '🥦', '🧄', '🧅', '🥜', '🫘', '🌰', '🍞', '🥐',
47+
'🥖', '🥨', '🥯', '🥞', '🧇', '🧀', '🍖', '🍗', '🥩', '🥓', '🍔', '🍟',
48+
'🍕', '🌭', '🥪', '🌮', '🌯', '🫔', '🥙', '🧆', '🥚', '🍳', '🥘', '🍲',
49+
'🫕', '🥣', '🥗', '🍿', '🧈', '🧂', '🥫', '🍱', '🍘', '🍙', '🍚', '🍛',
50+
'🍜', '🍝', '🍠', '🍢', '🍣', '🍤', '🍥', '🥮', '🍡', '🥟', '🥠', '🥡',
51+
'🦪', '🍦', '🍧', '🍨', '🍩', '🍪', '🎂', '🍰', '🧁', '🥧', '🍫', '🍬',
52+
'🍭', '🍮', '🍯', '🍼', '🥛', '', '🫖', '🍵', '🍶', '🍾', '🍷', '🍸',
53+
'🍹', '🍺', '🍻', '🥂', '🥃', '🧃', '🧉', '🧊', '🥢', '🍽️', '', '🏀',
54+
'🏈', '', '🥎', '🎾', '🏐', '🏉', '🥏', '🎱', '🪀', '🏓', '🏸', '🏒',
55+
'🏑', '🥍', '🏏', '🪃', '🥅', '', '🪁', '🏹', '🎣', '🤿', '🥊', '🥋',
56+
'🎽', '🛹', '🛼', '🛷', '⛸️', '🥌', '🎿', '⛷️', '🏂', '🪂', '🏋️', '🤼',
57+
'🤸', '⛹️', '🤺', '🤾', '🏌️', '🏇', '🧗', '🏊', '🚣', '🏄', '🎪', '🎭',
58+
'🎨', '🎬', '🎤', '🎧', '🎼', '🎹', '🥁', '🪘', '🎷', '🎺', '🪗', '🎸',
59+
'🪕', '🎻', '🎲', '♟️', '🎯', '🎳', '🎮', '🎰', '🧩', '', '📱', '💻',
60+
'⌨️', '🖥️', '🖨️', '🖱️', '💽', '💾', '💿', '📀', '📷', '📸', '🎥', '📺',
61+
'📻', '🎙️', '', '', '', '📡', '🔋', '🪫', '🔌', '💡', '🔦', '🕯️',
62+
'🧯', '🛢️', '💸', '💵', '💴', '💶', '💷', '🪙', '💰', '💳', '🧾', '💎',
63+
'⚖️', '🧰', '🔧', '🔨', '⚒️', '🛠️', '⛏️', '🪚', '🔩', '⚙️', '🪤', '🧱',
64+
'⛓️', '🧲', '🔫', '💣', '🧨', '🪓', '🔪', '🗡️', '🛡️', '🚬', '⚰️', '🪦',
65+
'⚱️', '🏺', '🔮', '📿', '🧿', '💈', '⚗️', '🔭', '🔬', '🕳️', '🩹', '🩺',
66+
'💊', '💉', '🩸', '🧬', '🦠', '🧫', '🧪', '🌡️', '🧹', '🪠', '🧽', '🧼',
67+
'🪥', '🪒', '🧴', '🛎️', '🔑', '🗝️', '🚪', '🪑', '🛋️', '🛏️', '🧸', '🪆',
68+
'🖼️', '🛍️', '🛒', '🎁', '🎈', '🎏', '🎀', '🎊', '🎉', '🪩', '🪅', '📩',
69+
'📨', '📧', '💌', '📥', '📤', '📦', '🏷️', '🪧', '📪', '📫', '📬', '📭',
70+
'📮', '📯', '📜', '📃', '📄', '📑', '🧾', '📊', '📈', '📉', '🗒️', '🗓️',
71+
'📆', '📅', '🗑️', '📌', '📍', '✂️', '🖊️', '🖋️', '✒️', '🖌️', '🖍️', '📝',
72+
'🔍', '🔎', '🔏', '🔐', '🔒', '🔓', '❤️‍🔥', '❤️‍🩹', '🏆', '🥇', '🥈', '🥉',
73+
'', '🧡', '', '🤙'
2374
];
2475
let content = '';
2576
let busy = false;
2677
let uploading = false;
2778
let error = '';
2879
let emojiPickerOpen = false;
80+
let emojiButtonElement: HTMLElement;
2981
let emojiPickerElement: HTMLElement;
3082
let mediaInput: HTMLInputElement;
3183
let textarea: HTMLTextAreaElement;
@@ -77,10 +129,10 @@
77129
78130
onDestroy(() => {
79131
clearTimeout(mentionSearchTimer);
80-
if (browser) document.removeEventListener('pointerdown', closeEmojiPickerFromOutside);
132+
if (browser) document.removeEventListener('pointerdown', closeComposerPopupsFromOutside);
81133
});
82134
83-
$: if (browser && $composerOpen) syncEmojiPickerListener(emojiPickerOpen);
135+
$: if (browser && $composerOpen) syncComposerPopupListener(emojiPickerOpen);
84136
85137
async function submit() {
86138
if (busy || uploading || !$session || !content.trim()) return;
@@ -124,7 +176,12 @@
124176
return;
125177
}
126178
127-
openCropper(file);
179+
if (shouldCropImage(file)) {
180+
openCropper(file);
181+
return;
182+
}
183+
184+
await uploadCroppedMedia(file);
128185
}
129186
130187
async function uploadCroppedMedia(file: File) {
@@ -148,6 +205,11 @@
148205
error = '';
149206
}
150207
208+
function shouldCropImage(file: File) {
209+
if (croppableImageTypes.has(file.type.toLowerCase())) return true;
210+
return /\.(jpe?g|png|webp|avif)$/i.test(file.name);
211+
}
212+
151213
function closeCropper() {
152214
cropFile = undefined;
153215
if (mediaInput) mediaInput.value = '';
@@ -217,15 +279,23 @@
217279
textarea?.setSelectionRange(caret, caret);
218280
}
219281
220-
function syncEmojiPickerListener(open: boolean) {
282+
function syncComposerPopupListener(open: boolean) {
221283
if (!browser) return;
222-
if (open) document.addEventListener('pointerdown', closeEmojiPickerFromOutside);
223-
else document.removeEventListener('pointerdown', closeEmojiPickerFromOutside);
224-
}
225-
226-
function closeEmojiPickerFromOutside(event: PointerEvent) {
227-
if (!emojiPickerOpen || !emojiPickerElement || !(event.target instanceof Node) || emojiPickerElement.contains(event.target)) return;
228-
emojiPickerOpen = false;
284+
if (open) document.addEventListener('pointerdown', closeComposerPopupsFromOutside);
285+
else document.removeEventListener('pointerdown', closeComposerPopupsFromOutside);
286+
}
287+
288+
function closeComposerPopupsFromOutside(event: PointerEvent) {
289+
if (!(event.target instanceof Node)) return;
290+
if (
291+
emojiPickerOpen &&
292+
emojiPickerElement &&
293+
emojiButtonElement &&
294+
!emojiPickerElement.contains(event.target) &&
295+
!emojiButtonElement.contains(event.target)
296+
) {
297+
emojiPickerOpen = false;
298+
}
229299
}
230300
231301
async function focusComposerStart() {
@@ -394,23 +464,21 @@
394464
<MentionSuggestions profiles={mentionSuggestions} searching={searchingMentions} on:select={(event) => selectMention(event.detail)} />
395465
{/if}
396466
</div>
467+
{#if emojiPickerOpen}
468+
<div class="composer-emoji-picker" bind:this={emojiPickerElement} aria-label="Emoji picker">
469+
{#each emojiOptions as emoji}
470+
<button type="button" aria-label={`Insert ${emoji}`} on:click={() => insertEmoji(emoji)}>{emoji}</button>
471+
{/each}
472+
</div>
473+
{/if}
397474
<div class="composer-actions">
398475
<input class="visually-hidden" type="file" accept="image/*" bind:this={mediaInput} on:change={(event) => uploadMedia(event.currentTarget.files?.[0])} />
399476
<button class="icon-button" disabled={uploading || !$session} aria-label="Add media" on:click={() => mediaInput.click()}>
400477
{#if uploading}<Loader2 size={20} class="spin" />{:else}<ImagePlus size={20} />{/if}
401478
</button>
402-
<span class="composer-emoji-wrap" bind:this={emojiPickerElement}>
403-
<button class="icon-button" type="button" disabled={!$session} aria-label="Add emoji" aria-expanded={emojiPickerOpen} on:click={() => (emojiPickerOpen = !emojiPickerOpen)}>
404-
<Smile size={20} />
405-
</button>
406-
{#if emojiPickerOpen}
407-
<span class="composer-emoji-picker" aria-label="Emoji picker">
408-
{#each emojiOptions as emoji}
409-
<button type="button" aria-label={`Insert ${emoji}`} on:click={() => insertEmoji(emoji)}>{emoji}</button>
410-
{/each}
411-
</span>
412-
{/if}
413-
</span>
479+
<button bind:this={emojiButtonElement} class="icon-button" type="button" disabled={!$session} aria-label="Add emoji" aria-expanded={emojiPickerOpen} on:click={() => (emojiPickerOpen = !emojiPickerOpen)}>
480+
<Smile size={20} />
481+
</button>
414482
<span class="composer-count">{content.length}/2000</span>
415483
<button class="primary" disabled={busy || uploading || !$session || !content.trim()} on:click={submit}><Send size={18} /> {$editTarget ? 'Save edit' : 'Post'}</button>
416484
</div>

src/styles.css

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,27 +1527,18 @@ label span, label strong { color: var(--text); }
15271527
.composer-count {
15281528
margin-left: auto;
15291529
}
1530-
.composer-emoji-wrap {
1531-
position: relative;
1532-
display: inline-flex;
1533-
margin-left: 0 !important;
1534-
}
15351530
.composer-emoji-picker {
1536-
position: absolute;
1537-
left: 0;
1538-
bottom: calc(100% + 8px);
1539-
z-index: 8;
1540-
width: min(320px, calc(100vw - 64px));
1541-
max-height: min(260px, 42svh);
1531+
width: 100%;
1532+
max-height: min(220px, 34svh);
15421533
display: grid;
1543-
grid-template-columns: repeat(8, 1fr);
1534+
grid-template-columns: repeat(auto-fill, minmax(34px, 1fr));
15441535
gap: 4px;
15451536
overflow: auto;
1537+
margin-top: 10px;
15461538
border: 1px solid color-mix(in srgb, var(--line) 66%, transparent);
15471539
border-radius: 8px;
15481540
padding: 8px;
1549-
background: var(--panel);
1550-
box-shadow: var(--shadow);
1541+
background: var(--surface);
15511542
}
15521543
.composer-emoji-picker button {
15531544
min-width: 0;

0 commit comments

Comments
 (0)