gif picker

This commit is contained in:
MathMan05 2025-04-08 12:26:46 -05:00
parent 174fde846a
commit 3952937581
7 changed files with 206 additions and 9 deletions

View file

@ -0,0 +1 @@
<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg"><path d="m400 159-26 1 1 49h25zM112 340V177a85 85 0 0 0-35 58c-8 43 8 89 35 105zM293 209v94h10v-94zM222 277a24 16 90 0 1 2 18l-2 8h31v-94h-44v45a20 20 0 0 1 14 19 20 20 0 0 1-1 4z" style="baseline-shift:baseline;display:inline;overflow:visible;vector-effect:none;fill:red;stroke-linecap:round;stroke-linejoin:round;enable-background:accumulate;stop-color:#000;stop-opacity:1"/><path d="M112 112v13c15-5 31-6 47 1l21 12a24 16 90 0 1 6 34 24 16 90 0 1-22 9l-14-8c-13-5-26-4-38 4v163l7 4c28 11 58-11 70-50l-48 2a20 20 0 0 1-21-19 20 20 0 0 1 19-21l63-2a20 20 0 0 1 7 0v-45h44v-70a20 20 0 0 1 20-20 20 20 0 0 1 20 20v70h10v94h-10l-1 67a20 20 0 0 1-20 20 20 20 0 0 1-20-20l1-67h-31c-16 66-64 105-110 89v8h288V249h-25l1 122a20 20 0 0 1-20 20 20 20 0 0 1-20-20l-2-230a20 20 0 0 1 20-20 20 20 0 0 1 1 0 20 20 0 0 1 3-1l42-1v-7z" style="baseline-shift:baseline;display:inline;overflow:visible;vector-effect:none;fill:red;stroke-linecap:round;stroke-linejoin:round;enable-background:accumulate;stop-color:#000;stop-opacity:1"/><path d="M112 16a96 96 0 0 0-96 96v288a96 96 0 0 0 96 96h288a96 96 0 0 0 96-96V112a96 96 0 0 0-96-96Zm0 96h288v7l45-1a20 20 0 0 1 21 20 20 20 0 0 1-20 20l-46 1v50h52a20 20 0 0 1 20 20 20 20 0 0 1-20 20h-52v151H112v-8l-2-1c-49-20-78-97-65-169 9-49 36-85 67-97Z" style="baseline-shift:baseline;display:inline;overflow:visible;vector-effect:none;fill:red;stroke-linecap:round;stroke-linejoin:round;enable-background:accumulate;stop-color:#000;stop-opacity:1"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -96,6 +96,7 @@
<div class="outerTypeBox">
<span class="svg-upload svgicon" id="upload"></span>
<div id="typebox" contenteditable="true"></div>
<span class="svgicon svg-gif" id="gifTB"></span>
<span class="svgicon svg-emoji" id="emojiTB"></span>
</div>
</div>

View file

@ -275,4 +275,12 @@ import {I18n} from "./i18n.js";
thisUser.TBEmojiMenu(emojiTB.getBoundingClientRect());
};
emojiTB.onclick = (e) => e.stopImmediatePropagation();
const gifTB = document.getElementById("gifTB") as HTMLElement;
gifTB.onmousedown = (e) => {
e.preventDefault();
e.stopImmediatePropagation();
thisUser.makeGifBox(gifTB.getBoundingClientRect());
};
gifTB.onclick = (e) => e.stopImmediatePropagation();
})();

View file

@ -31,6 +31,7 @@ import {Message} from "./message.js";
import {badgeArr} from "./Dbadges.js";
import {Rights} from "./rights.js";
import {Contextmenu} from "./contextmenu.js";
import {Search} from "./search.js";
const wsCodesRetry = new Set([4000, 4001, 4002, 4003, 4005, 4007, 4008, 4009]);
interface CustomHTMLDivElement extends HTMLDivElement {
@ -2238,12 +2239,122 @@ class Localuser {
this.search(document.getElementById("searchOptions") as HTMLDivElement, typeMd, str, pre);
};
}
async makeGifBox(rect: DOMRect) {
interface fullgif {
id: string;
title: string;
url: string;
src: string;
gif_src: string;
width: number;
height: number;
preview: string;
}
const menu = document.createElement("div");
menu.classList.add("flexttb", "gifmenu");
menu.style.bottom = window.innerHeight - rect.top + 15 + "px";
menu.style.right = window.innerWidth - rect.right + "px";
document.body.append(menu);
Contextmenu.keepOnScreen(menu);
if (Contextmenu.currentmenu !== "") {
Contextmenu.currentmenu.remove();
}
Contextmenu.currentmenu = menu;
const trending = (await (
await fetch(
this.info.api + "/gifs/trending?" + new URLSearchParams([["locale", I18n.lang]]),
{headers: this.headers},
)
).json()) as {
categories: {
name: string;
src: string;
}[];
gifs: [fullgif];
};
const gifbox = document.createElement("div");
gifbox.classList.add("gifbox");
const search = document.createElement("input");
let gifs = gifbox;
const searchBox = async () => {
gifs.remove();
if (search.value === "") {
menu.append(gifbox);
gifs = gifbox;
return;
}
gifs = document.createElement("div");
gifs.classList.add("gifbox");
menu.append(gifs);
const sValue = search.value;
const gifReturns = (await (
await fetch(
this.info.api +
"/gifs/search?" +
new URLSearchParams([
["locale", I18n.lang],
["q", sValue],
["limit", "500"],
]),
{headers: this.headers},
)
).json()) as fullgif[];
if (sValue !== search.value) {
return;
}
for (const gif of gifReturns) {
const div = document.createElement("div");
div.classList.add("gifBox");
const img = document.createElement("img");
img.src = gif.gif_src;
img.alt = gif.title;
const scale = gif.width / 196;
img.width = gif.width / scale;
img.height = gif.height / scale;
div.append(img);
gifs.append(div);
div.onclick = () => {
if (this.channelfocus) {
this.channelfocus.sendMessage(gif.url, {embeds: [], attachments: [], replyingto: null});
menu.remove();
}
};
}
};
let last = "";
search.onkeyup = () => {
if (last === search.value) {
return;
}
last = search.value;
searchBox();
};
search.classList.add("searchGifBar");
search.placeholder = I18n.searchGifs();
for (const category of trending.categories) {
const div = document.createElement("div");
div.classList.add("gifPreviewBox");
const img = document.createElement("img");
img.src = category.src;
const title = document.createElement("span");
title.textContent = category.name;
div.append(img, title);
gifbox.append(div);
div.onclick = (e) => {
e.stopImmediatePropagation();
search.value = category.name;
searchBox();
};
}
menu.append(search, gifbox);
search.focus();
}
async TBEmojiMenu(rect: DOMRect) {
const typebox = document.getElementById("typebox") as CustomHTMLDivElement;
const p = saveCaretPosition(typebox);
if (!p) return;
const original = MarkDown.getText();
console.log(original);
const emoji = await Emoji.emojiPicker(
-0 + rect.right - window.innerWidth,

View file

@ -663,8 +663,10 @@ class Message extends SnowFlake {
} else {
this.content.onUpdate = () => {};
const messaged = this.content.makeHTML();
messagedwrap.classList.add("flexttb");
messagedwrap.appendChild(messaged);
if (!this.embeds.find((_) => _.json.url === messaged.textContent)) {
messagedwrap.classList.add("flexttb");
messagedwrap.appendChild(messaged);
}
}
text.appendChild(messagedwrap);
build.appendChild(text);

View file

@ -355,6 +355,9 @@ textarea {
.svg-emoji {
mask: url(/icons/emoji.svg);
}
.svg-gif {
mask: url(/icons/gif.svg);
}
.svg-edit {
mask: url(/icons/edit.svg);
}
@ -433,11 +436,19 @@ textarea {
aspect-ratio: 1/1;
flex-shrink: 0;
}
#emojiTB{
width:.2in;
height:.2in;
#emojiTB {
width: 0.2in;
height: 0.2in;
cursor: pointer;
flex-shrink: 0;
margin-left: 6px;
}
#gifTB {
width: 0.2in;
height: 0.2in;
cursor: pointer;
flex-shrink: 0;
mask-size: 0.2in 0.2in;
}
.selectarrow {
position: absolute;
@ -1158,7 +1169,7 @@ span.instanceStatus {
flex-shrink: 1;
text-wrap: auto;
overflow-y: auto;
margin-right: .03in;
margin-right: 0.03in;
}
.outerTypeBox {
max-height: 50svh;
@ -2395,7 +2406,8 @@ fieldset input[type="radio"] {
background: var(--primary-bg);
transition: left 0.3s;
}
#sideContainDiv, #sideContainDiv.searchDiv {
#sideContainDiv,
#sideContainDiv.searchDiv {
display: block;
right: -100svw;
width: 100svw;
@ -2424,7 +2436,8 @@ fieldset input[type="radio"] {
#page:has(#maintoggle:checked) #mainarea {
left: 0;
}
#page:has(#memberlisttoggle:checked) #sideContainDiv, #sideContainDiv.searchDiv {
#page:has(#memberlisttoggle:checked) #sideContainDiv,
#sideContainDiv.searchDiv {
right: 0;
}
#page:has(#maintoggle:checked) #maintoggleicon {
@ -2631,3 +2644,63 @@ fieldset input[type="radio"] {
right: 0.2in;
cursor: pointer;
}
.gifmenu {
position: absolute;
width: 4.5in;
height: 5in;
background: var(--secondary-bg);
border-radius: 8px;
}
.gifPreviewBox {
position: relative;
width: 2in;
margin-bottom: 10px;
border-radius: 7px;
overflow: hidden;
cursor: pointer;
img {
width: 2in;
height: 1in;
object-fit: cover;
}
span {
top: 0px;
left: 0px;
position: absolute;
width: 100%;
height: 100%;
display: inline-flex;
align-items: center;
justify-content: center;
background: #00000099;
font-weight: bold;
}
}
.gifbox {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-around;
overflow-y: auto;
margin: 0.1in;
align-items: center;
}
.searchGifBar {
height: 0.3in;
margin: 0.15in 0.15in 0 0.15in;
flex-shrink: 0;
background: var(--black);
border: none;
border-radius: 4px;
font-size: 0.2in;
padding: 0 0.1in;
}
.gifBox {
img {
max-width: 196px;
}
cursor: pointer;
cursor: p;
}

View file

@ -149,6 +149,7 @@
"name": "Accessibility",
"roleColors": "Disable role colors"
},
"searchGifs": "Search Tenor",
"channel": {
"creating": "Creating channel",
"name": "Channel",