general emote support, room structure
This commit is contained in:
parent
10425070aa
commit
04c3ba25df
10 changed files with 193 additions and 85 deletions
|
@ -20,6 +20,7 @@
|
|||
"type": "module",
|
||||
"dependencies": {
|
||||
"matrix-js-sdk": "^31.4.0",
|
||||
"svelte-collapsible": "^0.3.0",
|
||||
"svelte-use-form": "latest"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
<script>
|
||||
import { flip } from 'svelte/animate';
|
||||
import { onMount } from 'svelte';
|
||||
let baskets = [];
|
||||
let isLoading = true;
|
||||
export let data;
|
||||
|
||||
const hs = "https://" + data.homeserver;
|
||||
const token = data.token;
|
||||
|
||||
onMount(async () => {
|
||||
const response = await fetch(hs + "/_matrix/client/v3/rooms/!WesIJpYbWDvdAYThkW:matrix.org/state", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Authorization": "Bearer " + token
|
||||
}
|
||||
})
|
||||
const res = await response.json();
|
||||
|
||||
res.forEach(e => {
|
||||
if(e.type === "im.ponies.room_emotes" && e.content.pack != undefined) {
|
||||
let prepareArr = [];
|
||||
for(const [key, value] of Object.entries(e.content.images)) {
|
||||
let image_id = value.url.split("/")[3];
|
||||
let emote_hs = value.url.split("/")[2];
|
||||
prepareArr.push(hs + "/_matrix/media/r0/thumbnail/" + emote_hs + "/" + image_id + "?width=256&height=256&method=crop")
|
||||
}
|
||||
baskets.push({"name": e.content.pack.display_name, "items": prepareArr})
|
||||
}
|
||||
});
|
||||
isLoading = false;
|
||||
});
|
||||
|
||||
let hoveringOverBasket;
|
||||
|
||||
function dragStart(event, basketIndex, itemIndex) {
|
||||
// The data we want to make available when the element is dropped
|
||||
// is the index of the item being dragged and
|
||||
// the index of the basket from which it is leaving.
|
||||
const data = {basketIndex, itemIndex};
|
||||
event.dataTransfer.setData('text/plain', JSON.stringify(data));
|
||||
}
|
||||
|
||||
function drop(event, basketIndex) {
|
||||
event.preventDefault();
|
||||
const json = event.dataTransfer.getData("text/plain");
|
||||
const data = JSON.parse(json);
|
||||
|
||||
// Remove the item from one basket.
|
||||
// Splice returns an array of the deleted elements, just one in this case.
|
||||
const [item] = baskets[data.basketIndex].items.splice(data.itemIndex, 1);
|
||||
|
||||
// Add the item to the drop target basket.
|
||||
baskets[basketIndex].items.push(item);
|
||||
baskets = baskets;
|
||||
|
||||
hoveringOverBasket = null;
|
||||
}
|
||||
</script>
|
||||
{#if isLoading}
|
||||
<p>Loading the Emotes...</p>
|
||||
{:else}
|
||||
{#each baskets as basket, basketIndex (basket)}
|
||||
<div animate:flip>
|
||||
<p>{basket.name}</p>
|
||||
<ul
|
||||
class:hovering={hoveringOverBasket === basket.name}
|
||||
on:dragenter={() => hoveringOverBasket = basket.name}
|
||||
on:dragleave={() => hoveringOverBasket = null}
|
||||
on:drop={event => drop(event, basketIndex)}
|
||||
ondragover="return false" >
|
||||
{#each basket.items as item, itemIndex (item)}
|
||||
<div class="item" animate:flip>
|
||||
<li
|
||||
draggable={true}
|
||||
on:dragstart={event => dragStart(event, basketIndex, itemIndex)} >
|
||||
<img src={item} alt="Emote"/>
|
||||
</li>
|
||||
</div>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
7
src/routes/emotes/[slug]/+page.server.js
Normal file
7
src/routes/emotes/[slug]/+page.server.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
export const load = (async ({ params, cookies }) => {
|
||||
const homeserver = cookies.get("hs");
|
||||
const token = cookies.get("mToken");
|
||||
const slug = params.slug;
|
||||
|
||||
return { homeserver: homeserver, token: token, slug: slug}
|
||||
})
|
111
src/routes/emotes/[slug]/+page.svelte
Normal file
111
src/routes/emotes/[slug]/+page.svelte
Normal file
|
@ -0,0 +1,111 @@
|
|||
<script>
|
||||
import { flip } from 'svelte/animate';
|
||||
import { CollapsibleCard } from 'svelte-collapsible'
|
||||
import { onMount } from 'svelte';
|
||||
let baskets = [];
|
||||
let isLoading = true;
|
||||
let error = "";
|
||||
export let data;
|
||||
|
||||
const hs = "https://" + data.homeserver;
|
||||
const token = data.token;
|
||||
|
||||
async function updateSet() {
|
||||
baskets.forEach(async basket => {
|
||||
const response = await fetch(hs + "/_matrix/client/v3/rooms/" + data.slug + "/state/im.ponies.room_emotes/" + basket.state_key, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Authorization": "Bearer " + token,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify(basket.content)
|
||||
});
|
||||
const res = await response.json();
|
||||
if(response.status != 200) error = "There was an error updating the emote set!";
|
||||
});
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
const response = await fetch(hs + "/_matrix/client/v3/rooms/" + data.slug + "/state", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Authorization": "Bearer " + token
|
||||
}
|
||||
});
|
||||
const res = await response.json();
|
||||
if(response.status != 200) error = "There was an error getting an emote set!";
|
||||
|
||||
res.forEach(e => {
|
||||
if(e.type === "im.ponies.room_emotes" && e.content.pack != undefined) {
|
||||
baskets.push(e);
|
||||
}
|
||||
});
|
||||
if(baskets.length == 0) error = "Either there are no emotes on this room, or you have insufficent rights. (You need atleast Mod)"
|
||||
isLoading = false;
|
||||
});
|
||||
|
||||
|
||||
let hoveringOverBasket;
|
||||
|
||||
function dragStart(event, basketIndex, itemIndex) {
|
||||
// The data we want to make available when the element is dropped
|
||||
// is the index of the item being dragged and
|
||||
// the index of the basket from which it is leaving.
|
||||
const data = {basketIndex, itemIndex};
|
||||
event.dataTransfer.setData('text/plain', JSON.stringify(data));
|
||||
}
|
||||
|
||||
function drop(event, basketIndex) {
|
||||
event.preventDefault();
|
||||
const json = event.dataTransfer.getData("text/plain");
|
||||
const data = JSON.parse(json);
|
||||
let insert = {};
|
||||
const emoteName = Object.entries(baskets[data.basketIndex].content.images)[data.itemIndex][0];
|
||||
const emoteUrl = Object.entries(baskets[data.basketIndex].content.images)[data.itemIndex][1];
|
||||
|
||||
// Remove the item from one basket.
|
||||
// Splice returns an array of the deleted elements, just one in this case.
|
||||
delete baskets[data.basketIndex].content.images[emoteName];
|
||||
|
||||
// Add the item to the drop target basket.
|
||||
insert[emoteName] = emoteUrl;
|
||||
baskets[basketIndex].content.images = {...baskets[basketIndex].content.images, ...insert}
|
||||
baskets = baskets;
|
||||
|
||||
hoveringOverBasket = null;
|
||||
}
|
||||
</script>
|
||||
{#if error}
|
||||
<err>{error}</err>
|
||||
<br>
|
||||
{:else}
|
||||
{#if isLoading}
|
||||
<p>Loading the Emotes...</p>
|
||||
{:else}
|
||||
<button on:click={updateSet}>Update</button>
|
||||
{#each baskets as basket, basketIndex (basket)}
|
||||
<div>
|
||||
<CollapsibleCard>
|
||||
<h2 slot="header" class="header">{basket.content.pack.display_name}</h2>
|
||||
<ul
|
||||
class:hovering={hoveringOverBasket === basket.content.pack.display_name}
|
||||
on:dragenter={() => hoveringOverBasket = basket.content.pack.display_name}
|
||||
on:dragleave={() => hoveringOverBasket = null}
|
||||
on:drop={event => drop(event, basketIndex)}
|
||||
ondragover="return false"
|
||||
slot='body' class='body' >
|
||||
{#each Object.entries(basket.content.images) as [key, value], itemIndex (key)}
|
||||
<div class="item">
|
||||
<li
|
||||
draggable={true}
|
||||
on:dragstart={event => dragStart(event, basketIndex, itemIndex)} >
|
||||
<img src={hs + "/_matrix/media/r0/thumbnail/" + value.url.split("/")[2] + "/" + value.url.split("/")[3] + "?width=256&height=256&method=crop"} alt="{key}"/>
|
||||
</li>
|
||||
</div>
|
||||
{/each}
|
||||
</ul>
|
||||
</CollapsibleCard>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
{/if}
|
|
@ -37,3 +37,18 @@ p {
|
|||
img {
|
||||
height: 32px;
|
||||
}
|
||||
button {
|
||||
background-color: green;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 15px 32px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 10px;
|
||||
}
|
||||
err {
|
||||
color: red;
|
||||
font-size: 32px;
|
||||
}
|
5
src/routes/rooms/+layout.svelte
Normal file
5
src/routes/rooms/+layout.svelte
Normal file
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
import "./app.css";
|
||||
</script>
|
||||
|
||||
<slot />
|
43
src/routes/rooms/+page.svelte
Normal file
43
src/routes/rooms/+page.svelte
Normal file
|
@ -0,0 +1,43 @@
|
|||
<script>
|
||||
import { RoomState } from 'matrix-js-sdk';
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
export let data;
|
||||
const hs = "https://" + data.homeserver;
|
||||
const token = data.token;
|
||||
let isLoading = true;
|
||||
let error = "";
|
||||
let rooms = [];
|
||||
|
||||
onMount(async () => {
|
||||
const response = await fetch(hs + "/_matrix/client/v3/joined_rooms", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Authorization": "Bearer " + token
|
||||
}
|
||||
});
|
||||
const res = await response.json();
|
||||
if(response.status != 200) error = "There was an error getting your room list!";
|
||||
|
||||
res.joined_rooms.forEach(r => {
|
||||
rooms.push(r);
|
||||
});
|
||||
if(rooms.length == 0) error = "You have not joined any rooms!"
|
||||
isLoading = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if error}
|
||||
<err>{error}</err>
|
||||
<br>
|
||||
{:else}
|
||||
{#if isLoading}
|
||||
<p>Loading the Rooms...</p>
|
||||
{:else}
|
||||
<div class="grid">
|
||||
{#each rooms as room}
|
||||
<div><a href="/emotes/{room}">{room}</a></div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
10
src/routes/rooms/app.css
Normal file
10
src/routes/rooms/app.css
Normal file
|
@ -0,0 +1,10 @@
|
|||
.grid {
|
||||
display: grid;
|
||||
gap: 1px;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
div > div {
|
||||
padding: 10px;
|
||||
background-color: #ccc;
|
||||
}
|
Loading…
Reference in a new issue