Compare commits
No commits in common. "20cdd8e68888665bcdecbbc612b3787facc65c46" and "a273c8de4bb56a177d33b2185ef0518916c5a8eb" have entirely different histories.
20cdd8e688
...
a273c8de4b
@ -1,6 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import LoadingSpinnerComponent from '$lib/components/LoadingSpinnerComponent.svelte';
|
|
||||||
|
|
||||||
export let moreAvailable: boolean = false;
|
export let moreAvailable: boolean = false;
|
||||||
export let isLoading: boolean = false;
|
export let isLoading: boolean = false;
|
||||||
@ -25,12 +24,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button on:click={loadOlderPosts} {disabled} {title}>
|
<button on:click={loadOlderPosts} {disabled} {title}>{displayText}</button>
|
||||||
<div class="loading" class:collapsed={!isLoading}>
|
|
||||||
<LoadingSpinnerComponent size='0.5em' thickness='6px' />
|
|
||||||
</div>
|
|
||||||
<span>{displayText}</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
button {
|
button {
|
||||||
@ -40,11 +34,7 @@
|
|||||||
background-color: var(--color-button);
|
background-color: var(--color-button);
|
||||||
color: var(--color-button-text);
|
color: var(--color-button-text);
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
transition: all 0.3s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
font-size: large;
|
|
||||||
font-weight: bold;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button:hover:not(:disabled) {
|
button:hover:not(:disabled) {
|
||||||
@ -52,7 +42,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
button:hover:not(:disabled):not(:active) {
|
button:hover:not(:disabled):not(:active) {
|
||||||
box-shadow: 6px 6px 5px 0 var(--color-button-shadow);
|
box-shadow: 4px 4px 3px 0 var(--color-button-shadow);
|
||||||
translate: -2px -2px;
|
translate: -2px -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,20 +52,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
button:not(:disabled) {
|
button:not(:disabled) {
|
||||||
box-shadow: 4px 4px 2px 0 var(--color-button-shadow);
|
box-shadow: 2px 2px 1px 0 var(--color-button-shadow);
|
||||||
}
|
|
||||||
|
|
||||||
.loading {
|
|
||||||
margin-right: 3px;
|
|
||||||
display: flex;
|
|
||||||
overflow: hidden;
|
|
||||||
max-width: 100%;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cannot be removed, so that it animates its width change */
|
|
||||||
.collapsed {
|
|
||||||
max-width: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,38 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
export let size: string = '64px';
|
|
||||||
export let thickness: string = '6px';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="lds-dual-ring" style="--size: {size}; --thickness: {thickness}"></div>
|
|
||||||
<style>
|
|
||||||
.lds-dual-ring {
|
|
||||||
display: inline-block;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.lds-dual-ring:after {
|
|
||||||
content: " ";
|
|
||||||
display: block;
|
|
||||||
width: var(--size);
|
|
||||||
height: var(--size);
|
|
||||||
border-radius: 50%;
|
|
||||||
border: var(--thickness) solid #fff;
|
|
||||||
border-color: #fff transparent #fff transparent;
|
|
||||||
animation: lds-dual-ring 1.2s linear infinite;
|
|
||||||
}
|
|
||||||
@keyframes lds-dual-ring {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
25% {
|
|
||||||
transform: rotate(36deg);
|
|
||||||
}
|
|
||||||
75% {
|
|
||||||
transform: rotate(234deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
@ -5,52 +5,20 @@ import type { Post } from '$lib/mastodon/response';
|
|||||||
import { PUBLIC_REFRESH_INTERVAL, PUBLIC_MASTODON_INSTANCE_DISPLAY_NAME } from '$env/static/public';
|
import { PUBLIC_REFRESH_INTERVAL, PUBLIC_MASTODON_INSTANCE_DISPLAY_NAME } from '$env/static/public';
|
||||||
import PostComponent from '$lib/components/PostComponent.svelte';
|
import PostComponent from '$lib/components/PostComponent.svelte';
|
||||||
import LoadMoreComponent from '$lib/components/LoadMoreComponent.svelte';
|
import LoadMoreComponent from '$lib/components/LoadMoreComponent.svelte';
|
||||||
import { fly, type FlyParams } from 'svelte/transition';
|
|
||||||
import { cubicInOut } from 'svelte/easing';
|
|
||||||
|
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
|
const refreshInterval = parseInt(PUBLIC_REFRESH_INTERVAL);
|
||||||
|
let interval: NodeJS.Timer | null = null;
|
||||||
|
let moreOlderPostsAvailable = true;
|
||||||
|
let loadingOlderPosts = false;
|
||||||
|
|
||||||
interface FetchOptions {
|
interface FetchOptions {
|
||||||
since?: string,
|
since?: string,
|
||||||
before?: string,
|
before?: string,
|
||||||
count?: number
|
count?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EdgeFlyParams extends FlyParams {
|
|
||||||
created_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const refreshInterval = parseInt(PUBLIC_REFRESH_INTERVAL) * 10;
|
|
||||||
let interval: NodeJS.Timer | null = null;
|
|
||||||
let moreOlderPostsAvailable = true;
|
|
||||||
let loadingOlderPosts = false;
|
|
||||||
|
|
||||||
// Needed, so that edgeFly() can do its thing:
|
|
||||||
// To determine whether a newly loaded post is older than the existing ones, is required to know what the oldest
|
|
||||||
// post was, before the fetch happened.
|
|
||||||
let oldestBeforeLastFetch: number | null = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Animate either from the top, or the bottom of the window, depending if the post is
|
|
||||||
* newer than the existing ones or older.
|
|
||||||
*/
|
|
||||||
function edgeFly(node: Element, opts: EdgeFlyParams) {
|
|
||||||
const createdAt = new Date(opts.created_at).getTime();
|
|
||||||
const diffNewest = Math.abs(new Date(data.posts[0].created_at).getTime() - createdAt);
|
|
||||||
const oldest = oldestBeforeLastFetch !== null
|
|
||||||
? oldestBeforeLastFetch
|
|
||||||
: new Date(data.posts[data.posts.length - 1].created_at).getTime();
|
|
||||||
const diffOldest = Math.abs(oldest - createdAt);
|
|
||||||
const fromTop = diffNewest <= diffOldest;
|
|
||||||
|
|
||||||
const rect = node.getBoundingClientRect();
|
|
||||||
const paramY = +`${opts.y}`;
|
|
||||||
let offset = isNaN(paramY) ? 0 : paramY + rect.height;
|
|
||||||
opts.y = fromTop ? -offset : window.innerHeight + offset;
|
|
||||||
return fly(node, opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchPosts(options: FetchOptions): Promise<Post[]> {
|
async function fetchPosts(options: FetchOptions): Promise<Post[]> {
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
if (options?.since !== undefined) {
|
if (options?.since !== undefined) {
|
||||||
@ -92,9 +60,6 @@ function refresh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if (data.posts.length > 0) {
|
|
||||||
oldestBeforeLastFetch = new Date(data.posts[data.posts.length - 1].created_at).getTime();
|
|
||||||
}
|
|
||||||
interval = setInterval(refresh, refreshInterval);
|
interval = setInterval(refresh, refreshInterval);
|
||||||
|
|
||||||
// - If the page is hidden, slow down refresh rate
|
// - If the page is hidden, slow down refresh rate
|
||||||
@ -119,7 +84,6 @@ function loadOlderPosts() {
|
|||||||
const filter: FetchOptions = { count: 20 };
|
const filter: FetchOptions = { count: 20 };
|
||||||
if (data.posts.length > 0) {
|
if (data.posts.length > 0) {
|
||||||
filter.before = data.posts[data.posts.length - 1].created_at;
|
filter.before = data.posts[data.posts.length - 1].created_at;
|
||||||
oldestBeforeLastFetch = new Date(filter.before).getTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -155,12 +119,7 @@ function loadOlderPosts() {
|
|||||||
Sorry, no posts recommending music aave been found yet
|
Sorry, no posts recommending music aave been found yet
|
||||||
{/if}
|
{/if}
|
||||||
{#each data.posts as post (post.url)}
|
{#each data.posts as post (post.url)}
|
||||||
<div
|
<div class="post"><PostComponent {post} /></div>
|
||||||
class="post"
|
|
||||||
transition:edgeFly="{{ y: 10, created_at: post.created_at, duration: 300, easing: cubicInOut }}"
|
|
||||||
>
|
|
||||||
<PostComponent {post} />
|
|
||||||
</div>
|
|
||||||
{/each}
|
{/each}
|
||||||
<LoadMoreComponent
|
<LoadMoreComponent
|
||||||
on:loadOlderPosts={loadOlderPosts}
|
on:loadOlderPosts={loadOlderPosts}
|
||||||
@ -189,6 +148,5 @@ function loadOlderPosts() {
|
|||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
z-index: 100;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
Loading…
Reference in New Issue
Block a user