Compare commits

..

3 commits

Author SHA1 Message Date
4bad86822f
fix: handles on masto 2025-07-23 22:10:08 +01:00
19be3779e3
fix: pagination bug on misskey favourites 2025-07-23 22:10:01 +01:00
cd5dc461f6
refactor: timeline into its own component
fix: bug with last_post not clearing when changing
2025-07-23 21:13:36 +01:00
5 changed files with 116 additions and 62 deletions

View file

@ -41,7 +41,7 @@ export function parseAccount(data) {
else
account.host = get(server).host;
account.fqn = data.fqn || account.username + account.host;
account.fqn = data.fqn || account.username + "@" + account.host;
account.mention = "@" + account.username;
if (account.host != get(server).host)

View file

@ -285,13 +285,17 @@ export async function getTimeline(host, token, timeline, max_id, local_only, rem
headers: { "Authorization": token ? `Bearer ${token}` : null }
})
let links = _parseLinkHeader(data.headers.get("Link"));
let res = {
data: await data.json()
}
return {
data: await data.json(),
prev: links.find(f=>f.rel=="prev"),
next: links.find(f=>f.rel=="next")
};
if(data.headers.has("Link")) {
let links = _parseLinkHeader(data.headers.get("Link"));
res["prev"] = links.find(f=>f.rel=="prev");
res["next"] = links.find(f=>f.rel=="next");
}
return res;
}
/**
@ -312,14 +316,18 @@ export async function getFavourites(host, token, max_id) {
method: 'GET',
headers: { "Authorization": token ? `Bearer ${token}` : null }
})
let res = {
data: await data.json()
}
let links = _parseLinkHeader(data.headers.get("Link"));
if(data.headers.has("Link")) {
let links = _parseLinkHeader(data.headers.get("Link"));
res["prev"] = links.find(f=>f.rel=="prev");
res["next"] = links.find(f=>f.rel=="next");
}
return {
data: await data.json(),
prev: links.find(f=>f.rel=="prev"),
next: links.find(f=>f.rel=="next")
};
return res;
}
/**

View file

@ -10,12 +10,15 @@ export const timeline = writable([]);
const lang = Lang();
let loading = false;
let last_post = false;
let last_post = false; // last post marker, used for fetching next sequence of posts
let at_end = false; // at end of timeline, no next param to paginate
export async function getTimeline(timelineType = "home", clean, localOnly = false, remoteOnly = false) {
if (loading) return; // no spamming!!
loading = true;
if(at_end) return;
if(clean) {
timeline.set([]);
last_post = false;
@ -49,9 +52,12 @@ export async function getTimeline(timelineType = "home", clean, localOnly = fals
return;
}
if (!clean) {
if (!clean && timeline_data.next) {
last_post = timeline_data.next.url.searchParams.get("max_id")
}
} else if(!timeline_data.next) {
console.log(timeline_data)
at_end = true;
}
for (let i in timeline_data.data) {
const post_data = timeline_data.data[i];
@ -71,3 +77,9 @@ export async function getTimeline(timelineType = "home", clean, localOnly = fals
}
loading = false;
}
export function clearTimeline() {
timeline.set([]);
last_post = false;
at_end = false;
}

View file

@ -0,0 +1,78 @@
<script>
import { page } from '$app/stores';
import { account } from '$lib/stores/account.js';
import { timeline, getTimeline, clearTimeline } from '$lib/timeline.js';
import { app_name } from '$lib/config.js';
import Post from '$lib/ui/post/Post.svelte';
import Lang from '$lib/lang';
const lang = Lang();
// TODO: refactor to enum when moving to TS
export let timelineType;
$: {
// awful hack to update timeline fresh
// when timelineType is updated
//
// TODO: migrate to $effect when migrating to svelte 5
timelineType = timelineType
clearTimeline()
getCurrentTimeline()
}
function getCurrentTimeline(clean = false) {
switch(timelineType) {
case "home":
getTimeline("home", clean);
break;
case "local":
getTimeline("public", clean, true)
break;
case "federated":
getTimeline("public", clean, false, true)
break;
}
}
account.subscribe(account => {
if (account) getCurrentTimeline();
});
document.addEventListener('scroll', () => {
if ($account && $page.url.pathname !== "/") return;
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 2048) {
getCurrentTimeline();
}
});
</script>
<div id="feed" role="feed">
{#if $timeline.length <= 0}
<div class="loading throb">
<span>{lang.string('timeline.fetching')}</span>
</div>
{/if}
{#each $timeline as post}
<Post post_data={post} />
{/each}
</div>
<style>
#feed {
margin-bottom: 20vh;
}
.loading {
width: 100%;
height: 80vh;
display: flex;
justify-content: center;
align-items: center;
font-size: 2em;
font-weight: bold;
}
</style>

View file

@ -9,6 +9,7 @@
import Button from '$lib/ui/Button.svelte';
import Post from '$lib/ui/post/Post.svelte';
import PageHeader from '../lib/ui/core/PageHeader.svelte';
import Timeline from '../lib/ui/timeline/Timeline.svelte';
const lang = Lang();
@ -24,40 +25,7 @@
// set in localStorage
localStorage.setItem(app_name + '_selected_timeline', timelineType);
// erase the timeline here so the ui reacts instantly
// mae: i could write an awesome undertale reference here
timeline.set([]);
getCurrentTimeline()
}
function getCurrentTimeline(clean = false) {
switch(timelineType) {
case "home":
getTimeline("home", clean);
break;
case "local":
getTimeline("public", clean, true)
break;
case "federated":
getTimeline("public", clean, false, true)
break;
}
}
account.subscribe(account => {
if (account) getCurrentTimeline();
});
document.addEventListener('scroll', () => {
if ($account && $page.url.pathname !== "/") return;
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 2048) {
getCurrentTimeline();
}
});
</script>
{#if $account}
@ -79,24 +47,12 @@
</Button>
</PageHeader>
<div id="feed" role="feed">
{#if $timeline.length <= 0}
<div class="loading throb">
<span>{lang.string('timeline.fetching')}</span>
</div>
{/if}
{#each $timeline as post}
<Post post_data={post} />
{/each}
</div>
<Timeline timelineType={timelineType}/>
{:else}
<LoginForm />
{/if}
<style>
#feed {
margin-bottom: 20vh;
}
.loading {
width: 100%;