better display of empty/initially-loading timeline

This commit is contained in:
Henry Jameson 2026-08-27 17:25:35 +03:00
commit d8e530581d
5 changed files with 44 additions and 18 deletions

View file

@ -31,6 +31,7 @@ const Timeline = {
embedded: Boolean, embedded: Boolean,
inProfile: Boolean, inProfile: Boolean,
skipPinned: Boolean, skipPinned: Boolean,
hideEmpty: Boolean,
}, },
data() { data() {
return { return {

View file

@ -4,6 +4,14 @@
backdrop-filter: none; backdrop-filter: none;
} }
.timeline-placeholder {
background: var(--background);
display: flex;
place-items: center;
place-content: center;
padding: 5em;
}
.alert-badge { .alert-badge {
font-size: 0.75em; font-size: 0.75em;
line-height: 1; line-height: 1;

View file

@ -94,6 +94,24 @@
collapsable collapsable
/> />
</div> </div>
<template v-if="!hideEmpty && count === 0">
<div
v-if="timeline.fetcher.loadingNewer || timeline.fetcher.loadingOlder"
class="timeline-placeholder"
>
<FAIcon
icon="circle-notch"
spin
size="4x"
/>
</div>
<div
v-else
class="timeline-placeholder faint"
>
{{ $t('timeline.no_statuses') }}
</div>
</template>
</div> </div>
<div v-if="!embedded || footerSlipgate" :class="classes.footer"> <div v-if="!embedded || footerSlipgate" :class="classes.footer">
<teleport <teleport
@ -101,28 +119,13 @@
:disabled="!embedded || !footerSlipgate" :disabled="!embedded || !footerSlipgate"
> >
<div <div
v-if="count === 0" v-if="timeline.fetcher.bottomedOut"
class="new-status-notification text-center faint"
>
{{ $t('timeline.no_statuses') }}
</div>
<div
v-else-if="timeline.fetcher.bottomedOut"
class="new-status-notification text-center faint" class="new-status-notification text-center faint"
> >
{{ $t('timeline.no_more_statuses') }} {{ $t('timeline.no_more_statuses') }}
</div> </div>
<button
v-else-if="!timeline.fetcher.loadingOlder"
class="button-unstyled -link"
@click.prevent="fetchOlderStatuses()"
>
<div class="new-status-notification text-center">
{{ $t('timeline.load_older') }}
</div>
</button>
<div <div
v-else v-else-if="timeline.fetcher.loadingOlder"
class="new-status-notification text-center" class="new-status-notification text-center"
> >
<FAIcon <FAIcon
@ -131,6 +134,15 @@
size="lg" size="lg"
/> />
</div> </div>
<button
v-else-if="timeline.minId !== ''"
class="button-unstyled -link"
@click.prevent="fetchOlderStatuses()"
>
<div class="new-status-notification text-center">
{{ $t('timeline.load_older') }}
</div>
</button>
</teleport> </teleport>
<!-- spacer to avoid having empty shrug --> <!-- spacer to avoid having empty shrug -->
<span v-if="embedded && footerSlipgate" /> <span v-if="embedded && footerSlipgate" />

View file

@ -30,6 +30,7 @@
:timeline-ref="{ name: 'userPinned', argument: userId }" :timeline-ref="{ name: 'userPinned', argument: userId }"
embedded embedded
in-profile in-profile
hide-empty
/> />
<Timeline <Timeline
:timeline-ref="{ name: 'user', argument: userId }" :timeline-ref="{ name: 'user', argument: userId }"

View file

@ -52,9 +52,13 @@ const timelineFetcher = (timeline, argument, credentials) => {
const numStatusesBeforeFetch = timeline.statusIds.size const numStatusesBeforeFetch = timeline.statusIds.size
if (bottomedOut.value) return if (older && bottomedOut.value) return
return fetchTimeline(args) return fetchTimeline(args)
.then(({ data: statuses, pagination, timestamp }) => { .then(({ data: statuses, pagination, timestamp }) => {
// No statuses for timeline, ever.
if (timeline.order.length === 0 && statuses.length === 0) {
bottomedOut.value = true
}
if (!older && statuses.length >= 20 && numStatusesBeforeFetch > 0) { if (!older && statuses.length >= 20 && numStatusesBeforeFetch > 0) {
useTimelinesStore().requireReload(timeline.name) useTimelinesStore().requireReload(timeline.name)
} }