rewrite URLs to represent instance (#2)
This commit is contained in:
parent
41143cdddf
commit
a3fdd0007c
|
@ -18,7 +18,10 @@ app.subscribe(app => {
|
||||||
*/
|
*/
|
||||||
function saveApp(app) {
|
function saveApp(app) {
|
||||||
if (!browser) return;
|
if (!browser) return;
|
||||||
if (!app) localStorage.removeItem(app_name + "_app");
|
if (!app) {
|
||||||
|
localStorage.removeItem(app_name + "_app");
|
||||||
|
return;
|
||||||
|
}
|
||||||
localStorage.setItem(app_name + "_app", JSON.stringify(app));
|
localStorage.setItem(app_name + "_app", JSON.stringify(app));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,10 @@ export async function createServer(host) {
|
||||||
*/
|
*/
|
||||||
function saveServer(server) {
|
function saveServer(server) {
|
||||||
if (!browser) return;
|
if (!browser) return;
|
||||||
if (!server) localStorage.removeItem(app_name + "_server");
|
if (!server) {
|
||||||
|
localStorage.removeItem(app_name + "_server");
|
||||||
|
return;
|
||||||
|
}
|
||||||
localStorage.setItem(app_name + "_server", JSON.stringify(server));
|
localStorage.setItem(app_name + "_server", JSON.stringify(server));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{#if $logged_in}
|
{#if $account}
|
||||||
<div id="nav-items">
|
<div id="nav-items">
|
||||||
<Button label="Timeline"
|
<Button label="Timeline"
|
||||||
on:click={() => handle_btn("timeline")}
|
on:click={() => handle_btn("timeline")}
|
||||||
|
@ -180,6 +180,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<span class="version">
|
<span class="version">
|
||||||
campfire v{VERSION}
|
campfire v{VERSION}
|
||||||
<br>
|
<br>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import * as api from '$lib/api';
|
import * as api from '$lib/api';
|
||||||
import { get } from 'svelte/store';
|
|
||||||
import { server } from '$lib/client/server';
|
import { server } from '$lib/client/server';
|
||||||
import { app } from '$lib/client/app';
|
import { app } from '$lib/client/app';
|
||||||
import { account } from '@cf/store/account';
|
import { account } from '@cf/store/account';
|
||||||
|
@ -20,11 +19,13 @@
|
||||||
export let post;
|
export let post;
|
||||||
|
|
||||||
async function toggleBoost() {
|
async function toggleBoost() {
|
||||||
|
if (!$app || !$app.token) return;
|
||||||
|
|
||||||
let data;
|
let data;
|
||||||
if (post.boosted)
|
if (post.boosted)
|
||||||
data = await api.unboostPost(get(server).host, get(app).token, post.id);
|
data = await api.unboostPost($server.host, $app.token, post.id);
|
||||||
else
|
else
|
||||||
data = await api.boostPost(get(server).host, get(app).token, post.id);
|
data = await api.boostPost($server.host, $app.token, post.id);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
console.error(`Failed to boost post ${post.id}`);
|
console.error(`Failed to boost post ${post.id}`);
|
||||||
return;
|
return;
|
||||||
|
@ -34,11 +35,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleFavourite() {
|
async function toggleFavourite() {
|
||||||
|
if (!$app || !$app.token) return;
|
||||||
|
|
||||||
let data;
|
let data;
|
||||||
if (post.favourited)
|
if (post.favourited)
|
||||||
data = await api.unfavouritePost(get(server).host, get(app).token, post.id);
|
data = await api.unfavouritePost($server.host, $app.token, post.id);
|
||||||
else
|
else
|
||||||
data = await api.favouritePost(get(server).host, get(app).token, post.id);
|
data = await api.favouritePost($server.host, $app.token, post.id);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
console.error(`Failed to favourite post ${post.id}`);
|
console.error(`Failed to favourite post ${post.id}`);
|
||||||
return;
|
return;
|
||||||
|
@ -69,13 +72,13 @@
|
||||||
<ActionButton type="reply" label="Reply" bind:count={post.reply_count} sound="post" disabled>
|
<ActionButton type="reply" label="Reply" bind:count={post.reply_count} sound="post" disabled>
|
||||||
<ReplyIcon/>
|
<ReplyIcon/>
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
<ActionButton type="boost" label="Boost" on:click={toggleBoost} bind:active={post.boosted} bind:count={post.boost_count} sound="boost">
|
<ActionButton type="boost" label="Boost" on:click={toggleBoost} bind:active={post.boosted} bind:count={post.boost_count} sound="boost" disabled={!$account}>
|
||||||
<RepostIcon/>
|
<RepostIcon/>
|
||||||
<svelte:fragment slot="activeIcon">
|
<svelte:fragment slot="activeIcon">
|
||||||
<RepostIcon/>
|
<RepostIcon/>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
<ActionButton type="favourite" label="Favourite" on:click={toggleFavourite} bind:active={post.favourited} bind:count={post.favourite_count}>
|
<ActionButton type="favourite" label="Favourite" on:click={toggleFavourite} bind:active={post.favourited} bind:count={post.favourite_count} disabled={!$account}>
|
||||||
<FavouriteIcon/>
|
<FavouriteIcon/>
|
||||||
<svelte:fragment slot="activeIcon">
|
<svelte:fragment slot="activeIcon">
|
||||||
<FavouriteIconFill/>
|
<FavouriteIconFill/>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import { server } from '$lib/client/server';
|
||||||
|
|
||||||
import BoostContext from './BoostContext.svelte';
|
import BoostContext from './BoostContext.svelte';
|
||||||
import ReplyContext from './ReplyContext.svelte';
|
import ReplyContext from './ReplyContext.svelte';
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
event.ctrlKey)) return;
|
event.ctrlKey)) return;
|
||||||
if (event.key && event.key !== "Enter") return;
|
if (event.key && event.key !== "Enter") return;
|
||||||
}
|
}
|
||||||
goto(`/post/${post.id}`);
|
goto(`/${$server.host}/${post.account.mention}/${post.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let el;
|
let el;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import * as api from '$lib/api.js';
|
import * as api from '$lib/api.js';
|
||||||
import { server, capabilities } from '$lib/client/server.js';
|
import { server, capabilities } from '$lib/client/server.js';
|
||||||
import { app } from '$lib/client/app.js';
|
import { app } from '$lib/client/app.js';
|
||||||
import { get } from 'svelte/store';
|
import { account } from '@cf/store/account';
|
||||||
import { parseReactions } from '$lib/post.js';
|
import { parseReactions } from '$lib/post.js';
|
||||||
|
|
||||||
import ReactionButton from './ReactionButton.svelte';
|
import ReactionButton from './ReactionButton.svelte';
|
||||||
|
@ -11,6 +11,8 @@
|
||||||
export let post;
|
export let post;
|
||||||
|
|
||||||
async function toggleReaction(reaction) {
|
async function toggleReaction(reaction) {
|
||||||
|
if (!$app || !$app.token) return;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
reaction.name.includes('@') &&
|
reaction.name.includes('@') &&
|
||||||
!$server.capabilities.includes(capabilities.FOREIGN_REACTIONS)
|
!$server.capabilities.includes(capabilities.FOREIGN_REACTIONS)
|
||||||
|
@ -18,9 +20,9 @@
|
||||||
|
|
||||||
let data;
|
let data;
|
||||||
if (reaction.me)
|
if (reaction.me)
|
||||||
data = await api.unreactPost(get(server).host, get(app).token, post.id, reaction.name);
|
data = await api.unreactPost($server.host, $app.token, post.id, reaction.name);
|
||||||
else
|
else
|
||||||
data = await api.reactPost(get(server).host, get(app).token, post.id, reaction.name);
|
data = await api.reactPost($server.host, $app.token, post.id, reaction.name);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
console.error(`Failed to favourite post ${post.id}`);
|
console.error(`Failed to favourite post ${post.id}`);
|
||||||
return;
|
return;
|
||||||
|
@ -39,7 +41,7 @@
|
||||||
on:click={() => toggleReaction(reaction)}
|
on:click={() => toggleReaction(reaction)}
|
||||||
bind:active={reaction.me}
|
bind:active={reaction.me}
|
||||||
bind:count={reaction.count}
|
bind:count={reaction.count}
|
||||||
disabled={reaction.name.includes('@') && !$server.capabilities.includes(capabilities.FOREIGN_REACTIONS)}
|
disabled={!$account || (reaction.name.includes('@') && !$server.capabilities.includes(capabilities.FOREIGN_REACTIONS))}
|
||||||
title={reaction.name}
|
title={reaction.name}
|
||||||
label="">
|
label="">
|
||||||
{#if reaction.url}
|
{#if reaction.url}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
import { account, logged_in } from '$lib/stores/account.js';
|
import { account, logged_in } from '$lib/stores/account.js';
|
||||||
import { parseAccount } from '$lib/account.js';
|
import { parseAccount } from '$lib/account.js';
|
||||||
import { unread_notif_count, last_read_notif_id } from '$lib/notifications.js';
|
import { unread_notif_count, last_read_notif_id } from '$lib/notifications.js';
|
||||||
import { get } from 'svelte/store';
|
|
||||||
|
|
||||||
import Navigation from '$lib/ui/Navigation.svelte';
|
import Navigation from '$lib/ui/Navigation.svelte';
|
||||||
import Modal from '@cf/ui/Modal.svelte';
|
import Modal from '@cf/ui/Modal.svelte';
|
||||||
|
@ -16,25 +15,25 @@
|
||||||
let show_composer = false;
|
let show_composer = false;
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
if (!get(app) || !get(app).token) {
|
if (!$app || !$app.token) {
|
||||||
account.set(false);
|
account.set(false);
|
||||||
logged_in.set(false);
|
logged_in.set(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// logged in- attempt to retrieve using token
|
// logged in- attempt to retrieve using token
|
||||||
const data = await api.verifyCredentials(get(server).host, get(app).token);
|
const data = await api.verifyCredentials($server.host, $app.token);
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
account.set(parseAccount(data));
|
account.set(parseAccount(data));
|
||||||
logged_in.set(true);
|
logged_in.set(true);
|
||||||
console.log(`Logged in as @${get(account).username}@${get(account).host}`);
|
console.log(`Logged in as @${$account.username}@${$account.host}`);
|
||||||
|
|
||||||
// spin up async task to fetch notifications
|
// spin up async task to fetch notifications
|
||||||
const notif_data = await api.getNotifications(
|
const notif_data = await api.getNotifications(
|
||||||
get(server).host,
|
$server.host,
|
||||||
get(app).token,
|
$app.token,
|
||||||
get(last_read_notif_id)
|
$last_read_notif_id
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!notif_data) return;
|
if (!notif_data) return;
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
<script>
|
<script>
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { get } from 'svelte/store';
|
import { get } from 'svelte/store';
|
||||||
import { logged_in } from '$lib/stores/account.js';
|
import { account } from '$lib/stores/account.js';
|
||||||
import { timeline, getTimeline } from '$lib/timeline.js';
|
import { timeline, getTimeline } from '$lib/timeline.js';
|
||||||
|
|
||||||
import LoginForm from '$lib/ui/LoginForm.svelte';
|
import LoginForm from '$lib/ui/LoginForm.svelte';
|
||||||
import Button from '$lib/ui/Button.svelte';
|
import Button from '$lib/ui/Button.svelte';
|
||||||
import Post from '$lib/ui/post/Post.svelte';
|
import Post from '$lib/ui/post/Post.svelte';
|
||||||
|
|
||||||
logged_in.subscribe(logged_in => {
|
account.subscribe(account => {
|
||||||
if (logged_in) getTimeline();
|
if (account) getTimeline();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("scroll", () => {
|
document.addEventListener("scroll", () => {
|
||||||
|
@ -20,13 +20,13 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $logged_in}
|
{#if $account}
|
||||||
<header>
|
<header>
|
||||||
<h1>Home</h1>
|
<h1>Home</h1>
|
||||||
<nav>
|
<nav>
|
||||||
<Button centered active>Home</Button>
|
<Button centered active>Home</Button>
|
||||||
<Button centered disabled>Local</Button>
|
<Button centered disabled>Local</Button>
|
||||||
<Button centered disabled>Federated</Button>
|
<Button centered disabled>Federated</Button>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export async function load({ params }) {
|
export async function load({ params }) {
|
||||||
return {
|
return {
|
||||||
post_id: params.id
|
server_domain: params.server
|
||||||
};
|
};
|
||||||
}
|
}
|
8
src/routes/[server]/[account]/+page.js
Normal file
8
src/routes/[server]/[account]/+page.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
export async function load({ params }) {
|
||||||
|
return error(404, 'Not Found');
|
||||||
|
// return {
|
||||||
|
// account_name: params.account
|
||||||
|
// };
|
||||||
|
}
|
7
src/routes/[server]/[account]/[post]/+page.js
Normal file
7
src/routes/[server]/[account]/[post]/+page.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export async function load({ params }) {
|
||||||
|
return {
|
||||||
|
server_host: params.server,
|
||||||
|
account_handle: params.account,
|
||||||
|
post_id: params.post
|
||||||
|
};
|
||||||
|
}
|
143
src/routes/[server]/[account]/[post]/+page.svelte
Normal file
143
src/routes/[server]/[account]/[post]/+page.svelte
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
<script>
|
||||||
|
import * as api from '$lib/api.js';
|
||||||
|
import { server, createServer } from '$lib/client/server.js';
|
||||||
|
import { app } from '$lib/client/app.js';
|
||||||
|
import { parsePost } from '$lib/post.js';
|
||||||
|
import { goto, afterNavigate } from '$app/navigation';
|
||||||
|
import { base as previous_page } from '$app/paths'
|
||||||
|
|
||||||
|
import Post from '$lib/ui/post/Post.svelte';
|
||||||
|
import Button from '$lib/ui/Button.svelte';
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
|
||||||
|
let post;
|
||||||
|
let error = false;
|
||||||
|
|
||||||
|
if (($server && $server.host === data.server_host) && $app) {
|
||||||
|
post = fetchPost(data.post_id, $app.token);
|
||||||
|
} else {
|
||||||
|
post = createServer(data.server_host).then(new_server => {
|
||||||
|
server.set(new_server);
|
||||||
|
if (!$server) {
|
||||||
|
error = `Failed to connect to <code>${data.server_host}</code>.`;
|
||||||
|
console.error(`Failed to connect to ${data.server_host}.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return post = fetchPost(data.post_id, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
afterNavigate(({from}) => {
|
||||||
|
previous_page = from?.url.pathname || previous_page
|
||||||
|
})
|
||||||
|
|
||||||
|
async function fetchPost(post_id, token) {
|
||||||
|
const post_data = await api.getPost($server.host, token, post_id);
|
||||||
|
if (!post_data || post_data.error) {
|
||||||
|
error = `Failed to retrieve post <code>${post_id}</code>.`;
|
||||||
|
console.error(`Failed to retrieve post ${post_id}.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let post = await parsePost(post_data, 0);
|
||||||
|
|
||||||
|
const post_context = await api.getPostContext($server.host, token, post_id);
|
||||||
|
|
||||||
|
if (!post_context || !post_context.ancestors || !post_context.descendants)
|
||||||
|
return post;
|
||||||
|
|
||||||
|
// handle ancestors (above post)
|
||||||
|
let thread_top = post;
|
||||||
|
while (post_context.ancestors.length > 0) {
|
||||||
|
thread_top.reply = await parsePost(post_context.ancestors.pop(), 0);
|
||||||
|
thread_top = thread_top.reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle descendants (below post)
|
||||||
|
post.replies = [];
|
||||||
|
for (let i in post_context.descendants) {
|
||||||
|
post.replies.push(parsePost(post_context.descendants[i], 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return post;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#await post}
|
||||||
|
<div class="loading throb">
|
||||||
|
<span>loading post...</span>
|
||||||
|
</div>
|
||||||
|
{:then post}
|
||||||
|
{#if error}
|
||||||
|
<p>{@html error}</p>
|
||||||
|
{:else}
|
||||||
|
<header>
|
||||||
|
{#if previous_page}
|
||||||
|
<nav>
|
||||||
|
<Button centered on:click={() => {goto(previous_page)}}>Back</Button>
|
||||||
|
</nav>
|
||||||
|
{/if}
|
||||||
|
<img src={post.account.avatar_url} type={post.account.avatar_type || "image/png"} alt="" width="40" height="40" class="header-avatar" loading="lazy" decoding="async">
|
||||||
|
<h1>
|
||||||
|
Post by {@html post.account.rich_name}
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div id="feed" role="feed">
|
||||||
|
<Post post_data={post} focused />
|
||||||
|
<br>
|
||||||
|
{#each post.replies as reply}
|
||||||
|
{#await reply then reply}
|
||||||
|
<Post post_data={reply} />
|
||||||
|
{/await}
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/await}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
header {
|
||||||
|
width: 100%;
|
||||||
|
height: 64px;
|
||||||
|
margin: 16px 0 8px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
header .header-avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
margin: auto 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
margin: auto auto auto 8px;
|
||||||
|
font-size: 1.5em;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
header nav {
|
||||||
|
margin-right: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#feed {
|
||||||
|
margin-bottom: 20vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
width: 100%;
|
||||||
|
height: 80vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 2em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -19,7 +19,6 @@
|
||||||
api.getToken(get(server).host, get(app).id, get(app).secret, auth_code).then(token => {
|
api.getToken(get(server).host, get(app).id, get(app).secret, auth_code).then(token => {
|
||||||
if (!token) {
|
if (!token) {
|
||||||
error(400, { message: "Invalid auth code provided" });
|
error(400, { message: "Invalid auth code provided" });
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.update(app => {
|
app.update(app => {
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
import { error } from '@sveltejs/kit';
|
|
||||||
|
|
||||||
export function load(event) {
|
|
||||||
error(404, 'Not Found');
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
<script>
|
|
||||||
import * as api from '$lib/api.js';
|
|
||||||
import { logged_in } from '$lib/stores/account.js';
|
|
||||||
import { server } from '$lib/client/server.js';
|
|
||||||
import { app } from '$lib/client/app.js';
|
|
||||||
import { parsePost } from '$lib/post.js';
|
|
||||||
import { get } from 'svelte/store';
|
|
||||||
import { goto, afterNavigate } from '$app/navigation';
|
|
||||||
import { base } from '$app/paths'
|
|
||||||
|
|
||||||
import Post from '$lib/ui/post/Post.svelte';
|
|
||||||
import Button from '$lib/ui/Button.svelte';
|
|
||||||
|
|
||||||
export let data;
|
|
||||||
let error = false;
|
|
||||||
|
|
||||||
if (!get(logged_in)) goto("/");
|
|
||||||
|
|
||||||
let previous_page = base;
|
|
||||||
|
|
||||||
afterNavigate(({from}) => {
|
|
||||||
previous_page = from?.url.pathname || previous_page
|
|
||||||
})
|
|
||||||
|
|
||||||
$: post = (async resolve => {
|
|
||||||
const post_data = await api.getPost(get(server).host, get(app).token, data.post_id);
|
|
||||||
if (!post_data) {
|
|
||||||
error = `Failed to retrieve post <code>${data.post_id}</code>.`;
|
|
||||||
console.error(`Failed to retrieve post ${data.post_id}.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let post = await parsePost(post_data, 0);
|
|
||||||
|
|
||||||
const post_context = await api.getPostContext(get(server).host, get(app).token, data.post_id);
|
|
||||||
|
|
||||||
if (!post_context || !post_context.ancestors || !post_context.descendants)
|
|
||||||
return post;
|
|
||||||
|
|
||||||
// handle ancestors (above post)
|
|
||||||
let thread_top = post;
|
|
||||||
while (post_context.ancestors.length > 0) {
|
|
||||||
thread_top.reply = await parsePost(post_context.ancestors.pop(), 0);
|
|
||||||
thread_top = thread_top.reply;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle descendants (below post)
|
|
||||||
post.replies = [];
|
|
||||||
for (let i in post_context.descendants) {
|
|
||||||
post.replies.push(parsePost(post_context.descendants[i], 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
return post;
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if !error}
|
|
||||||
<header>
|
|
||||||
{#await post then post}
|
|
||||||
<nav>
|
|
||||||
<Button centered on:click={() => {goto(previous_page)}}>Back</Button>
|
|
||||||
</nav>
|
|
||||||
<img src={post.account.avatar_url} type={post.account.avatar_type} alt="" width="40" height="40" class="header-avatar" loading="lazy" decoding="async">
|
|
||||||
<h1>
|
|
||||||
Post by {@html post.account.rich_name}
|
|
||||||
</h1>
|
|
||||||
{/await}
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div id="feed" role="feed">
|
|
||||||
{#await post}
|
|
||||||
<div class="loading throb">
|
|
||||||
<span>loading post...</span>
|
|
||||||
</div>
|
|
||||||
{:then post}
|
|
||||||
<Post post_data={post} focused />
|
|
||||||
<br>
|
|
||||||
{#each post.replies as reply}
|
|
||||||
{#await reply then reply}
|
|
||||||
<Post post_data={reply} />
|
|
||||||
{/await}
|
|
||||||
{/each}
|
|
||||||
{/await}
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<p>{@html error}</p>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
header {
|
|
||||||
width: 100%;
|
|
||||||
height: 64px;
|
|
||||||
margin: 16px 0 8px 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
header .header-avatar {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
margin: auto 0;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
header h1 {
|
|
||||||
margin: auto auto auto 8px;
|
|
||||||
font-size: 1.5em;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
header nav {
|
|
||||||
margin-right: 8px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#feed {
|
|
||||||
margin-bottom: 20vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading {
|
|
||||||
width: 100%;
|
|
||||||
height: 80vh;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 2em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
</style>
|
|
Loading…
Reference in a new issue