wumbo changes (proper mastodon API support and oauth login!)

This commit is contained in:
ari melody 2024-06-19 22:13:16 +01:00
parent b7c03381f7
commit e17b26b075
Signed by: ari
GPG key ID: CF99829C92678188
20 changed files with 1935 additions and 1618 deletions

View file

@ -1,5 +1,8 @@
<script>
export let post;
let rich_text;
post.rich_text().then(res => {rich_text = res});
</script>
<div class="post-body">
@ -7,7 +10,7 @@
<p class="post-warning"><strong>{post.warning}</strong></p>
{/if}
{#if post.text}
<span class="post-text">{@html post.rich_text}</span>
<span class="post-text">{@html rich_text}</span>
{/if}
<div class="post-media-container" data-count={post.files.length}>
{#each post.files as file}
@ -40,6 +43,12 @@
word-wrap: break-word;
}
.post-text :global(.emoji) {
position: relative;
top: 6px;
height: 24px!important;
}
.post-text :global(code) {
font-size: 1.2em;
}

View file

@ -1,5 +1,5 @@
<script>
import { parse_text as parse_emojis } from '../emoji.js';
import { parseText as parseEmojis } from '../emoji.js';
import { shorthand as short_time } from '../time.js';
export let post;
@ -10,7 +10,7 @@
<div class="post-context">
<span class="post-context-icon">🔁</span>
<span class="post-context-action">
<a href="/{post.user.mention}">{@html parse_emojis(post.user.name, post.user.emojis, true)}</a> boosted this post.
<a href="/{post.user.mention}">{@html parseEmojis(post.user.name)}</a> boosted this post.
</span>
<span class="post-context-time">
<time title="{time_string}">{short_time(post.created_at)}</time>

View file

@ -15,7 +15,7 @@
aria-label="{label}"
title="{title}"
on:click={() => (play_sound(sound))}>
<span>{@html icon}</span>
<span class="icon">{@html icon}</span>
{#if count}
<span class="count">{count}</span>
{/if}
@ -23,7 +23,11 @@
<style>
button {
height: 32px;
padding: 6px 8px;
display: flex;
flex-direction: row;
gap: 4px;
font-size: 1em;
background: none;
color: inherit;
@ -44,6 +48,14 @@
background: #0001;
}
.icon {
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.count {
opacity: .5;
}

View file

@ -1,5 +1,5 @@
<script>
import { parse_text as parse_emojis } from '../emoji.js';
import { parseText as parseEmojis } from '../emoji.js';
import { shorthand as short_time } from '../time.js';
export let post;
@ -13,7 +13,7 @@
</a>
<header class="post-header">
<div class="post-user-info">
<a href="/{post.user.mention}" class="name">{@html parse_emojis(post.user.name, post.user.emojis, true)}</a>
<a href="/{post.user.mention}" class="name">{@html post.user.rich_name}</a>
<span class="username">{post.user.mention}</span>
</div>
<div class="post-info">

View file

@ -4,42 +4,42 @@
import Header from './Header.svelte';
import Body from './Body.svelte';
import FooterButton from './FooterButton.svelte';
import { parse_one as parse_reaction } from '../emoji.js';
import { parseOne as parseEmoji } from '../emoji.js';
import { play_sound } from '../sound.js';
export let post;
export let post_data;
let post_context = undefined;
let _post = post;
let post = post_data;
let is_boost = false;
if (_post.boost) {
if (post_data.boost) {
is_boost = true;
post_context = _post;
_post = _post.boost;
post_context = post_data;
post = post_data.boost;
}
let aria_label = post.user.username + '; ' + post.text + '; ' + post.created_at;
</script>
<div class="post-container" aria-label={aria_label}>
{#if _post.reply}
<ReplyContext post={_post.reply} />
{#if post.reply}
<ReplyContext post={post.reply} />
{/if}
{#if is_boost && !post_context.text}
<BoostContext post={post_context} />
{/if}
<article class="post">
<Header post={_post} />
<Body post={_post} />
<Header post={post} />
<Body post={post} />
<footer class="post-footer">
<div class="post-reactions">
{#each Object.keys(_post.reactions) as reaction}
<FooterButton icon={parse_reaction(reaction, _post.emojis)} type="reaction" bind:count={_post.reactions[reaction]} title={reaction} label="" />
{#each post.reactions as reaction}
<FooterButton icon={reaction.emoji.html} type="reaction" bind:count={reaction.count} title={reaction.emoji.id} label="" />
{/each}
</div>
<div class="post-actions">
<FooterButton icon="🗨️" type="reply" label="Reply" bind:count={_post.reply_count} sound="post" />
<FooterButton icon="🔁" type="boost" label="Boost" bind:count={_post.boost_count} sound="boost" />
<FooterButton icon="🗨️" type="reply" label="Reply" bind:count={post.reply_count} sound="post" />
<FooterButton icon="🔁" type="boost" label="Boost" bind:count={post.boost_count} sound="boost" />
<FooterButton icon="⭐" type="favourite" label="Favourite" />
<FooterButton icon="😃" type="react" label="React" />
<FooterButton icon="🗣️" type="quote" label="Quote" />
@ -63,17 +63,19 @@
background-color: var(--bg2);
}
.post-reactions {
margin-top: 8px;
:global(.post-reactions) {
margin-top: 16px;
display: flex;
flex-direction: row;
}
.post-actions {
:global(.post-actions) {
margin-top: 8px;
display: flex;
flex-direction: row;
}
.post-container :global(.emoji) {
position: relative;
top: 6px;
height: 26px;
height: 20px;
}
</style>

View file

@ -3,7 +3,7 @@
import Body from './Body.svelte';
import FooterButton from './FooterButton.svelte';
import Post from './Post.svelte';
import { parse_text as parse_emojis, parse_one as parse_reaction } from '../emoji.js';
import { parseText as parseEmojis, parseOne as parseEmoji } from '../emoji.js';
import { shorthand as short_time } from '../time.js';
export let post;
@ -24,7 +24,7 @@
<div class="post-header-container">
<header class="post-header">
<div class="post-user-info">
<a href="/{post.user.mention}" class="name">{@html parse_emojis(post.user.name, post.user.emojis, true)}</a>
<a href="/{post.user.mention}" class="name">{@html post.user.rich_name}</a>
<span class="username">{post.user.mention}</span>
</div>
<div class="post-info">
@ -39,8 +39,8 @@
<footer class="post-footer">
<div class="post-reactions">
{#each Object.keys(post.reactions) as reaction}
<FooterButton icon={parse_reaction(reaction, post.emojis)} type="reaction" bind:count={post.reactions[reaction]} title={reaction} label="" />
{#each post.reactions as reaction}
<FooterButton icon={reaction.emoji.html} type="reaction" bind:count={reaction.count} title={reaction.emoji.id} label="" />
{/each}
</div>
<div class="post-actions">

View file

@ -1,9 +1,5 @@
import Instance from '../instance.js';
import User from '../user/user.js';
import { parse_one as parse_emoji } from '../emoji.js';
let post_cache = Object;
import { Client, server_types } from '../client/client.js';
import { parseOne as parseEmoji, EMOJI_REGEX } from '../emoji.js';
export default class Post {
id;
@ -21,70 +17,7 @@ export default class Post {
reply;
boost;
static resolve_id(id) {
return post_cache[id] || null;
}
static parse(data) {
const instance = Instance.get_instance();
let post = null;
switch (instance.type) {
case Instance.types.ICESHRIMP:
post = Post.#parse_iceshrimp(data);
break;
case Instance.types.MASTODON:
post = Post.#parse_mastodon(data);
break;
default:
break;
}
if (!post) {
console.error("Error while parsing post data");
return null;
}
post_cache[post.id] = post;
return post;
}
static #parse_iceshrimp(data) {
let post = new Post()
post.id = data.id;
post.created_at = new Date(data.createdAt);
post.user = User.parse(data.user);
post.text = data.text;
post.warning = data.cw;
post.boost_count = data.renoteCount;
post.reply_count = data.repliesCount;
post.mentions = data.mentions;
post.reactions = data.reactions;
post.emojis = data.emojis;
post.files = data.files;
post.url = data.url;
post.boost = data.renote ? Post.parse(data.renote) : null;
post.reply = data.reply ? Post.parse(data.reply) : null;
return post;
}
static #parse_mastodon(data) {
let post = new Post()
post.id = data.id;
post.created_at = new Date(data.created_at);
post.user = User.parse(data.account);
post.text = data.content;
post.warning = data.spoiler_text;
post.boost_count = data.reblogs_count;
post.reply_count = data.replies_count;
post.mentions = data.mentions;
post.reactions = data.reactions;
post.emojis = data.emojis;
post.files = data.media_attachments;
post.url = data.url;
post.boost = data.reblog ? Post.parse(data.reblog) : null;
post.reply = data.in_reply_to_id ? Post.resolve_id(data.in_reply_to_id) : null;
return post;
}
get rich_text() {
async rich_text() {
let text = this.text;
if (!text) return text;
@ -112,7 +45,8 @@ export default class Post {
}
// handle mentions
if (allow_new && sample.match(/@[a-z0-9-_.]+@[a-z0-9-_.]+/g)) {
// TODO: setup a better system for handling different server capabilities
if (Client.get().instance.type !== server_types.MASTODON && allow_new && sample.match(/^@[\w\-.]+@[\w\-.]+/g)) {
// find end of the mention
let length = 1;
while (index + length < text.length && /[a-z0-9-_.]/.test(text[index + length])) length++;
@ -122,11 +56,11 @@ export default class Post {
let mention = text.substring(index, index + length);
// attempt to resolve mention to a user
let user = User.resolve_mention(mention);
let user = await Client.get().getUserByMention(mention);
if (user) {
const out = `<a href="/${user.mention}" class="mention">` +
`<img src="${user.avatar_url}" class="mention-avatar" width="20" height="20">` +
"@" + user.name + "</a>";
'@' + user.username + '@' + user.host + "</a>";
if (current) current.text += out;
else response += out;
} else {
@ -136,33 +70,39 @@ export default class Post {
continue;
}
if (Instance.get_instance().type !== Instance.types.MASTODON) {
// handle links
if (allow_new && sample.match(/^[a-z]{3,6}:\/\/[^\s]+/g)) {
// get length of link
let length = text.substring(index).search(/\s|$/g);
let url = text.substring(index, index + length);
let out = `<a href="${url}">${url}</a>`;
if (current) current.text += out;
else response += out;
index += length;
continue;
}
// handle links
if (Client.get().instance.type !== server_types.MASTODON && allow_new && sample.match(/^[a-z]{3,6}:\/\/[^\s]+/g)) {
// get length of link
let length = text.substring(index).search(/\s|$/g);
let url = text.substring(index, index + length);
let out = `<a href="${url}">${url}</a>`;
if (current) current.text += out;
else response += out;
index += length;
continue;
}
// handle emojis
if (allow_new && sample.startsWith(':')) {
// lookahead to next invalid emoji character
let look = sample.substring(1).search(/[^a-zA-Z0-9-_.]/g) + 1;
// if it's ':', we can parse it
if (look !== 0 && sample[look] === ':') {
let emoji_code = sample.substring(0, look + 1);
let out = parse_emoji(emoji_code, this.emojis);
if (allow_new && sample.match(/^:[\w\-.]{0,32}:/g)) {
// find the emoji name
let length = text.substring(index + 1).search(':');
if (length <= 0) return text;
let emoji_name = text.substring(index + 1, index + length + 1);
let emoji = Client.get().getEmoji(emoji_name + '@' + this.user.host);
index += length + 2;
if (!emoji) {
let out = ':' + emoji_name + ':';
if (current) current.text += out;
else response += out;
index += emoji_code.length;
continue;
}
let out = emoji.html;
if (current) current.text += out;
else response += out;
continue;
}
// handle markdown