diff --git a/src/app.d.ts b/src/app.d.ts index e76aec6..7de2379 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -3,6 +3,6 @@ // See https://kit.svelte.dev/docs/types#app declare namespace App { interface Session { - instance: { url: string; token?: string }; + instance: { url: string; token: string }; } } diff --git a/src/hooks.ts b/src/hooks.ts index f3696d3..390661b 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -2,7 +2,7 @@ import type { GetSession } from '@sveltejs/kit'; export const getSession: GetSession = async () => { const session: App.Session = { - instance: { url: 'https://trans.enby.town', token: 'bweep' } + instance: { url: 'https://trans.enby.town', token: '' } }; return session; }; diff --git a/src/lib/components/Status.svelte b/src/lib/components/Status.svelte index 781448e..3662fe8 100644 --- a/src/lib/components/Status.svelte +++ b/src/lib/components/Status.svelte @@ -3,22 +3,27 @@ import { now } from '$lib/global-now'; import { linkAccount } from '$lib/mastoapi/account'; - import { linkStatus, type MastodonStatus } from '$lib/mastoapi/status'; + import { + linkStatus, + type MastodonStatus, + type MastodonStatusContext + } from '$lib/mastoapi/status'; import StatusControls from './StatusControls.svelte'; export let status: MastodonStatus; + export let focused: boolean = false; -
+
-
@@ -44,6 +59,10 @@ padding: 0.25em; } + .status.focused { + background-color: var(--col-bg-2); + } + .status-content { display: flex; flex-direction: row; diff --git a/src/lib/mastoapi/pleroma_fixes.ts b/src/lib/mastoapi/pleroma_fixes.ts new file mode 100644 index 0000000..e1698d8 --- /dev/null +++ b/src/lib/mastoapi/pleroma_fixes.ts @@ -0,0 +1,60 @@ +import type { MastodonStatus, MastodonStatusContext } from './status'; + +// Oh jeez + +export function reorderAndFilterPleromaReplies( + status: MastodonStatus, + context: MastodonStatusContext +): MastodonStatusContext { + const findInOrig = (id: string): MastodonStatus | undefined => + context.ancestors.find((status) => status.id === id) || + context.descendants.find((status) => status.id === id); + + const newContext: MastodonStatusContext = { ancestors: [], descendants: [] }; + + let currParent: MastodonStatus | undefined = status; + while (currParent != null) { + let replyingTo = currParent.in_reply_to_id; + if (replyingTo != null) { + currParent = findInOrig(replyingTo); + if (currParent != null) { + newContext.ancestors.unshift(currParent); + } + } else { + currParent = undefined; + } + } + + const replyTree = new Map(); + for (const descendant of context.descendants) { + if (descendant.in_reply_to_id == null) { + continue; + } + + if (!replyTree.has(descendant.in_reply_to_id)) { + replyTree.set(descendant.in_reply_to_id, []); + } + replyTree.get(descendant.in_reply_to_id)?.push(descendant); + } + + let queue = [status]; + newContext.descendants.push(status); + + let potentialParent: MastodonStatus | undefined; + while ((potentialParent = queue.shift()) != null) { + const replies = replyTree.get(potentialParent.id); + if (replies) { + for (const reply of replies.reverse()) { + const parentIndex = newContext.descendants.indexOf(potentialParent); + newContext.descendants.splice(parentIndex + 1, 0, reply); + } + + for (const reply of replies) { + queue.push(reply); + } + } + } + newContext.descendants.shift(); + + return newContext; +} diff --git a/src/lib/mastoapi/status.ts b/src/lib/mastoapi/status.ts index 260baba..306e022 100644 --- a/src/lib/mastoapi/status.ts +++ b/src/lib/mastoapi/status.ts @@ -1,13 +1,28 @@ import type { MastodonAccount } from './account'; import type { MastodonObject } from './base'; +import { reorderAndFilterPleromaReplies } from './pleroma_fixes'; import { fetchAPI, MastodonAPIError, type InstanceInfo } from './util'; +export interface MastodonMediaAttachment { + type: string; + url: string; + description: string; + preview_url: string; +} + export interface MastodonStatus extends MastodonObject { account: MastodonAccount; content: string; spoiler_text: string; url: string; + in_reply_to_id: string | null; + media_attachments: MastodonMediaAttachment[]; +} + +export interface MastodonStatusContext { + ancestors: MastodonStatus[]; + descendants: MastodonStatus[]; } export function linkStatus(status: MastodonStatus) { @@ -19,3 +34,18 @@ export async function fetchStatus(instance: InstanceInfo, id: string): Promise r.json()) .then((b) => b as MastodonStatus); } + +export async function fetchStatusContext( + instance: InstanceInfo, + status: MastodonStatus +): Promise { + const context = await fetchAPI(instance, `/api/v1/statuses/${status.id}/context`) + .then((r) => r.json()) + .then((r) => r as MastodonStatusContext); + + if ('pleroma' in status) { + return reorderAndFilterPleromaReplies(status, context); + } + + return context; +} diff --git a/src/lib/mastoapi/util.ts b/src/lib/mastoapi/util.ts index 04bc95b..625484b 100644 --- a/src/lib/mastoapi/util.ts +++ b/src/lib/mastoapi/util.ts @@ -1,6 +1,6 @@ export interface InstanceInfo { url: string; - token?: string; + token: string; } export class MastodonAPIError extends Error { @@ -24,7 +24,7 @@ export async function fetchAPI( const opts = { ...options }; if (opts.headers == null) opts.headers = {}; - if (instance.token != null) { + if (isLoggedIn(instance)) { opts.headers['Authorization'] = instance.token; } diff --git a/src/routes/post/[id].svelte b/src/routes/post/[id].svelte index 188287b..45524a2 100644 --- a/src/routes/post/[id].svelte +++ b/src/routes/post/[id].svelte @@ -1,11 +1,17 @@ +{#await contextPromise then context} +
+ {#each context.ancestors as ancestor} + + {/each} +
+{/await} + {#if status != null} - + {:else}

a

{/if} + +{#await contextPromise then context} +
+ {#each context.descendants as descendant} + + {/each} +
+{/await} diff --git a/static/themes/purple.css b/static/themes/purple.css index ac3651a..fdcd99c 100644 --- a/static/themes/purple.css +++ b/static/themes/purple.css @@ -1,7 +1,8 @@ :root { --col-bg-0: #18161d; --col-bg-1: #221e28; - + --col-bg-2: #30293a; + --col-fg-0: #f2ecff; --col-fg-1: #ae96cc; --col-fg-2: #85739a;