[client] Move timeline to vue-virtual-scroller

This commit is contained in:
Laura Hausmann 2023-11-22 20:43:51 +01:00
parent 3cb46cd6fc
commit 61df9f65f9
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
14 changed files with 335 additions and 129 deletions

79
.pnp.cjs generated
View file

@ -8446,6 +8446,7 @@ const RAW_RUNTIME_STATE =
["vue-isyourpasswordsafe", "npm:2.0.0"],\
["vue-plyr", "npm:7.0.0"],\
["vue-prism-editor", "virtual:658502eb4296e93abedc18b6aa9b26978f434f08d98e21ebb0e725354b8bb54b62db9c4a1893e460c694ff7500ff5cbafa4457b0dfd26b5838868666c861e990#npm:2.0.0-alpha.2"],\
["vue-virtual-scroller", "virtual:658502eb4296e93abedc18b6aa9b26978f434f08d98e21ebb0e725354b8bb54b62db9c4a1893e460c694ff7500ff5cbafa4457b0dfd26b5838868666c861e990#npm:2.0.0-beta.8"],\
["vuedraggable", "virtual:658502eb4296e93abedc18b6aa9b26978f434f08d98e21ebb0e725354b8bb54b62db9c4a1893e460c694ff7500ff5cbafa4457b0dfd26b5838868666c861e990#npm:4.1.0"]\
],\
"linkType": "SOFT"\
@ -17837,6 +17838,15 @@ const RAW_RUNTIME_STATE =
"linkType": "HARD"\
}]\
]],\
["mitt", [\
["npm:2.1.0", {\
"packageLocation": "./.yarn/cache/mitt-npm-2.1.0-77f3c96db4-d4087f8678.zip/node_modules/mitt/",\
"packageDependencies": [\
["mitt", "npm:2.1.0"]\
],\
"linkType": "HARD"\
}]\
]],\
["mixin-deep", [\
["npm:1.3.2", {\
"packageLocation": "./.yarn/cache/mixin-deep-npm-1.3.2-29b528e571-820d5a51fc.zip/node_modules/mixin-deep/",\
@ -24912,6 +24922,28 @@ const RAW_RUNTIME_STATE =
"linkType": "HARD"\
}]\
]],\
["vue-observe-visibility", [\
["npm:2.0.0-alpha.1", {\
"packageLocation": "./.yarn/cache/vue-observe-visibility-npm-2.0.0-alpha.1-2336a276e1-251948d4bd.zip/node_modules/vue-observe-visibility/",\
"packageDependencies": [\
["vue-observe-visibility", "npm:2.0.0-alpha.1"]\
],\
"linkType": "SOFT"\
}],\
["virtual:1ff70a214f776664ffdd69e6c80dedbacd96b8cdab401980bd5ea13591b1cea0033ea9ca782fc6be0c2a7cbd792aa0bd2ba47d82b6b45a27a55d439ae67b26e0#npm:2.0.0-alpha.1", {\
"packageLocation": "./.yarn/__virtual__/vue-observe-visibility-virtual-38a3aa5843/0/cache/vue-observe-visibility-npm-2.0.0-alpha.1-2336a276e1-251948d4bd.zip/node_modules/vue-observe-visibility/",\
"packageDependencies": [\
["vue-observe-visibility", "virtual:1ff70a214f776664ffdd69e6c80dedbacd96b8cdab401980bd5ea13591b1cea0033ea9ca782fc6be0c2a7cbd792aa0bd2ba47d82b6b45a27a55d439ae67b26e0#npm:2.0.0-alpha.1"],\
["@types/vue", null],\
["vue", "npm:3.3.4"]\
],\
"packagePeers": [\
"@types/vue",\
"vue"\
],\
"linkType": "HARD"\
}]\
]],\
["vue-plyr", [\
["npm:7.0.0", {\
"packageLocation": "./.yarn/cache/vue-plyr-npm-7.0.0-aab8325658-09f1cdd290.zip/node_modules/vue-plyr/",\
@ -24945,6 +24977,53 @@ const RAW_RUNTIME_STATE =
"linkType": "HARD"\
}]\
]],\
["vue-resize", [\
["npm:2.0.0-alpha.1", {\
"packageLocation": "./.yarn/cache/vue-resize-npm-2.0.0-alpha.1-b3eb21b45c-d6e66472cd.zip/node_modules/vue-resize/",\
"packageDependencies": [\
["vue-resize", "npm:2.0.0-alpha.1"]\
],\
"linkType": "SOFT"\
}],\
["virtual:1ff70a214f776664ffdd69e6c80dedbacd96b8cdab401980bd5ea13591b1cea0033ea9ca782fc6be0c2a7cbd792aa0bd2ba47d82b6b45a27a55d439ae67b26e0#npm:2.0.0-alpha.1", {\
"packageLocation": "./.yarn/__virtual__/vue-resize-virtual-7d46fa71e5/0/cache/vue-resize-npm-2.0.0-alpha.1-b3eb21b45c-d6e66472cd.zip/node_modules/vue-resize/",\
"packageDependencies": [\
["vue-resize", "virtual:1ff70a214f776664ffdd69e6c80dedbacd96b8cdab401980bd5ea13591b1cea0033ea9ca782fc6be0c2a7cbd792aa0bd2ba47d82b6b45a27a55d439ae67b26e0#npm:2.0.0-alpha.1"],\
["@types/vue", null],\
["vue", "npm:3.3.4"]\
],\
"packagePeers": [\
"@types/vue",\
"vue"\
],\
"linkType": "HARD"\
}]\
]],\
["vue-virtual-scroller", [\
["npm:2.0.0-beta.8", {\
"packageLocation": "./.yarn/cache/vue-virtual-scroller-npm-2.0.0-beta.8-02cf134969-78047d2281.zip/node_modules/vue-virtual-scroller/",\
"packageDependencies": [\
["vue-virtual-scroller", "npm:2.0.0-beta.8"]\
],\
"linkType": "SOFT"\
}],\
["virtual:658502eb4296e93abedc18b6aa9b26978f434f08d98e21ebb0e725354b8bb54b62db9c4a1893e460c694ff7500ff5cbafa4457b0dfd26b5838868666c861e990#npm:2.0.0-beta.8", {\
"packageLocation": "./.yarn/__virtual__/vue-virtual-scroller-virtual-1ff70a214f/0/cache/vue-virtual-scroller-npm-2.0.0-beta.8-02cf134969-78047d2281.zip/node_modules/vue-virtual-scroller/",\
"packageDependencies": [\
["vue-virtual-scroller", "virtual:658502eb4296e93abedc18b6aa9b26978f434f08d98e21ebb0e725354b8bb54b62db9c4a1893e460c694ff7500ff5cbafa4457b0dfd26b5838868666c861e990#npm:2.0.0-beta.8"],\
["@types/vue", null],\
["mitt", "npm:2.1.0"],\
["vue", "npm:3.3.4"],\
["vue-observe-visibility", "virtual:1ff70a214f776664ffdd69e6c80dedbacd96b8cdab401980bd5ea13591b1cea0033ea9ca782fc6be0c2a7cbd792aa0bd2ba47d82b6b45a27a55d439ae67b26e0#npm:2.0.0-alpha.1"],\
["vue-resize", "virtual:1ff70a214f776664ffdd69e6c80dedbacd96b8cdab401980bd5ea13591b1cea0033ea9ca782fc6be0c2a7cbd792aa0bd2ba47d82b6b45a27a55d439ae67b26e0#npm:2.0.0-alpha.1"]\
],\
"packagePeers": [\
"@types/vue",\
"vue"\
],\
"linkType": "HARD"\
}]\
]],\
["vuedraggable", [\
["npm:4.1.0", {\
"packageLocation": "./.yarn/cache/vuedraggable-npm-4.1.0-785593d488-87d4faba83.zip/node_modules/vuedraggable/",\

BIN
.yarn/cache/mitt-npm-2.1.0-77f3c96db4-d4087f8678.zip (Stored with Git LFS) vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
.yarn/cache/vue-resize-npm-2.0.0-alpha.1-b3eb21b45c-d6e66472cd.zip (Stored with Git LFS) vendored Normal file

Binary file not shown.

Binary file not shown.

View file

@ -98,6 +98,7 @@
"vue-isyourpasswordsafe": "^2.0.0",
"vue-plyr": "^7.0.0",
"vue-prism-editor": "2.0.0-alpha.2",
"vue-virtual-scroller": "next",
"vuedraggable": "next"
},
"dependencies": {

View file

@ -15,6 +15,7 @@
:class="{ cover }"
:style="{ 'object-fit': cover ? 'cover' : null }"
loading="lazy"
decoding="async"
@load="onLoad"
/>
</template>

View file

@ -7,7 +7,7 @@
:to="url"
@click.stop
>
<img class="icon" :src="`/avatar/@${username}@${host}`" alt="" />
<img class="icon" :src="`/avatar/@${username}@${host}`" alt="" loading="lazy" decoding="async" />
<span class="main">
<span class="username">@{{ username }}</span>
<span

View file

@ -12,22 +12,31 @@
</template>
<template #default="{ items: notes }">
<div class="giivymft" :class="{ noGap }" ref="tlEl">
<XList
ref="notes"
v-slot="{ item: note }"
<div class="notes-wrapper" :class="{ noGap }" ref="tlEl">
<DynamicScroller
page-mode
v-slot="{ item: note, index, active }"
:items="notes"
:direction="pagination.reversed ? 'up' : 'down'"
:reversed="pagination.reversed"
:no-gap="noGap"
class="notes"
:min-item-size="10"
:buffer="200"
:class="{ noGap }"
listClass="notes"
itemClass="note"
>
<XNote
:key="note._featuredId_ || note._prId_ || note.id"
class="qtqtichx"
:note="note"
/>
</XList>
<DynamicScrollerItem
:key="index"
:item="note"
:active="active"
:data-index="index"
>
<div class="note-wrapper">
<XNote
:key="note._featuredId_ || note._prId_ || note.id"
:note="note"
/>
</div>
</DynamicScrollerItem>
</DynamicScroller>
</div>
</template>
</MkPagination>
@ -37,11 +46,12 @@
import { ref } from "vue";
import type { Paging } from "@/components/MkPagination.vue";
import XNote from "@/components/MkNote.vue";
import XList from "@/components/MkDateSeparatedList.vue";
import MkPagination from "@/components/MkPagination.vue";
import { i18n } from "@/i18n";
import { scroll } from "@/scripts/scroll";
import {instance} from "@/instance";
import { instance } from "@/instance";
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
const tlEl = ref<HTMLElement>();
@ -60,21 +70,89 @@ defineExpose({
pagingComponent,
scrollTop,
});
setInterval(() => {
if (!tlEl.value) return;
const viewport = document.documentElement.clientHeight;
const left = document.documentElement.scrollHeight - document.documentElement.scrollTop;
if (left <= viewport * 3) pagingComponent.value.fetchMore();
}, 100);
</script>
<style lang="scss" scoped>
.giivymft {
.notes-wrapper {
&.noGap {
> .notes {
:deep(.notes) {
background: var(--panel) !important;
border-radius: var(--radius);
}
}
&:not(.noGap) {
> .notes {
.qtqtichx {
background: var(--panel);
border-radius: var(--radius);
:deep(.notes) .note .note-wrapper > div {
background: var(--panel);
border-radius: var(--radius);
}
}
:deep(.notes) {
.note .note-container:empty {
display: none;
}
.note .note-wrapper {
padding-bottom: var(--margin);
}
> .separator {
text-align: center;
> .date {
display: inline-block;
position: relative;
margin: 0;
padding: 0 16px;
line-height: 32px;
text-align: center;
font-size: 12px;
color: var(--dateLabelFg);
> span {
&:first-child {
margin-right: 8px;
> .icon {
margin-right: 8px;
}
}
&:last-child {
margin-left: 8px;
> .icon {
margin-left: 8px;
}
}
}
}
}
&.noGap {
> * {
margin: 0 !important;
border: none;
border-radius: 0;
box-shadow: none;
&:first-child {
border-radius: var(--radius) var(--radius) 0 0;
}
&:last-child {
border-radius: 0 0 var(--radius) var(--radius);
}
&:not(:last-child) {
border-bottom: solid 0.5px var(--divider);
}
}
}
}

View file

@ -41,13 +41,11 @@
key="_more_"
class="cxiknjgy _gap"
>
<div
v-appear="$store.state.enableInfiniteScroll && !disableAutoLoad ? fetchMore : null"
/>
<MkButton
v-if="!moreFetching"
v-appear="
$store.state.enableInfiniteScroll && !disableAutoLoad
? fetchMore
: null
"
v-if="!moreFetching && !$store.state.enableInfiniteScroll && !disableAutoLoad"
class="button"
:disabled="moreFetching"
:style="{ cursor: moreFetching ? 'wait' : 'pointer' }"
@ -109,7 +107,7 @@ export type Paging<
offsetMode?: boolean;
};
const SECOND_FETCH_LIMIT = 30;
const SECOND_FETCH_LIMIT = 15;
const props = withDefaults(
defineProps<{
@ -118,7 +116,7 @@ const props = withDefaults(
displayLimit?: number;
}>(),
{
displayLimit: 30,
displayLimit: 15,
},
);
@ -498,6 +496,7 @@ defineExpose({
append,
removeItem,
updateItem,
fetchMore,
});
</script>

View file

@ -1,101 +1,96 @@
<template>
<transition
:name="defaultStore.state.animation ? 'zoom' : ''"
mode="out-in"
>
<!-- v-if="!fetching" for now, I think there's something
weird w/ some links stuck loading (?) -->
<article v-if="!fetching" class="url-preview" @click.stop>
<component
:is="self ? 'MkA' : 'a'"
:[attr]="self ? url.substring(local.length) : url"
rel="nofollow noopener"
:target="target"
:title="url"
:class="{
hasButton: tweetId || player.url,
}"
>
<div v-if="thumbnail" class="thumbnail">
<img :src="thumbnail" loading="lazy" />
<button
v-if="tweetId"
class="_button"
v-tooltip="
tweetExpanded ? i18n.ts.close : i18n.ts.expandTweet
"
@click.stop.prevent="tweetExpanded = !tweetExpanded"
>
<i
v-if="!tweetExpanded"
class="ph-twitter-logo ph-bold ph-lg"
></i>
<i v-else class="ph-x ph-bold ph-lg"></i>
</button>
<button
v-else-if="player.url"
class="_button"
v-tooltip="
playerEnabled ? i18n.ts.close : i18n.ts.enablePlayer
"
@click.stop.prevent="playerEnabled = !playerEnabled"
>
<i
v-if="!playerEnabled"
class="ph-play ph-bold ph-lg"
></i>
<i v-else class="ph-x ph-bold ph-lg"></i>
</button>
</div>
<div v-if="fetching">
<MkLoading mini />
</div>
<div v-else>
<h3 :title="title || undefined">{{ title || url }}</h3>
<p :title="description">
<span>
<span :title="sitename || undefined">
<img v-if="icon" class="icon" :src="icon" />
{{ sitename }}
</span>
{{ description }}
<!-- v-if="!fetching" for now, I think there's something
weird w/ some links stuck loading (?) -->
<article v-if="!fetching" class="url-preview" @click.stop>
<component
:is="self ? 'MkA' : 'a'"
:[attr]="self ? url.substring(local.length) : url"
rel="nofollow noopener"
:target="target"
:title="url"
:class="{
hasButton: tweetId || player.url,
}"
>
<div v-if="thumbnail" class="thumbnail">
<img :src="thumbnail" loading="lazy" decoding="async" />
<button
v-if="tweetId"
class="_button"
v-tooltip="
tweetExpanded ? i18n.ts.close : i18n.ts.expandTweet
"
@click.stop.prevent="tweetExpanded = !tweetExpanded"
>
<i
v-if="!tweetExpanded"
class="ph-twitter-logo ph-bold ph-lg"
></i>
<i v-else class="ph-x ph-bold ph-lg"></i>
</button>
<button
v-else-if="player.url"
class="_button"
v-tooltip="
playerEnabled ? i18n.ts.close : i18n.ts.enablePlayer
"
@click.stop.prevent="playerEnabled = !playerEnabled"
>
<i
v-if="!playerEnabled"
class="ph-play ph-bold ph-lg"
></i>
<i v-else class="ph-x ph-bold ph-lg"></i>
</button>
</div>
<div v-if="fetching">
<MkLoading mini />
</div>
<div v-else>
<h3 :title="title || undefined">{{ title || url }}</h3>
<p :title="description">
<span>
<span :title="sitename || undefined">
<img v-if="icon" class="icon" :src="icon" />
{{ sitename }}
</span>
</p>
</div>
</component>
<iframe
v-if="playerEnabled"
:src="
player.url +
(player.url.match(/\?/)
? '&autoplay=1&auto_play=1'
: '?autoplay=1&auto_play=1')
"
:style="`aspect-ratio: ${
(player.width || 1) / (player.height || 1)
}`"
frameborder="0"
allow="autoplay; encrypted-media"
allowfullscreen
@click.stop
/>
<iframe
v-else-if="tweetId && tweetExpanded"
ref="tweet"
scrolling="no"
frameborder="no"
:style="{
position: 'relative',
width: '100%',
height: `${tweetHeight}px`,
}"
:src="`https://platform.twitter.com/embed/index.html?embedId=${embedId}&amp;hideCard=false&amp;hideThread=false&amp;lang=en&amp;theme=${
defaultStore.state.darkMode ? 'dark' : 'light'
}&amp;id=${tweetId}`"
@click.stop
></iframe>
</article>
</transition>
{{ description }}
</span>
</p>
</div>
</component>
<iframe
v-if="playerEnabled"
:src="
player.url +
(player.url.match(/\?/)
? '&autoplay=1&auto_play=1'
: '?autoplay=1&auto_play=1')
"
:style="`aspect-ratio: ${
(player.width || 1) / (player.height || 1)
}`"
frameborder="0"
allow="autoplay; encrypted-media"
allowfullscreen
@click.stop
/>
<iframe
v-else-if="tweetId && tweetExpanded"
ref="tweet"
scrolling="no"
frameborder="no"
:style="{
position: 'relative',
width: '100%',
height: `${tweetHeight}px`,
}"
:src="`https://platform.twitter.com/embed/index.html?embedId=${embedId}&amp;hideCard=false&amp;hideThread=false&amp;lang=en&amp;theme=${
defaultStore.state.darkMode ? 'dark' : 'light'
}&amp;id=${tweetId}`"
@click.stop
></iframe>
</article>
</template>
<script lang="ts" setup>

View file

@ -8,7 +8,7 @@
:title="acct(user)"
@click="onClick"
>
<img class="inner" :src="url" decoding="async" />
<img class="inner" :src="url" loading="lazy" decoding="async" />
<MkUserOnlineIndicator
v-if="showIndicator && user.instance == null"
class="indicator"
@ -26,7 +26,7 @@
:target="target"
@click.stop
>
<img class="inner" :src="url" decoding="async" />
<img class="inner" :src="url" loading="lazy" decoding="async" />
<MkUserOnlineIndicator
v-if="showIndicator && user.instance == null"
class="indicator"

View file

@ -7,6 +7,7 @@
:alt="alt"
:title="alt"
decoding="async"
loading="lazy"
/>
<img
v-else-if="char && !useOsNativeEmojis"
@ -15,6 +16,7 @@
:alt="alt"
:title="alt"
decoding="async"
loading="lazy"
/>
<span v-else-if="char && useOsNativeEmojis">{{ char }}</span>
<span v-else>{{ emoji }}</span>

View file

@ -6604,6 +6604,7 @@ __metadata:
vue-isyourpasswordsafe: "npm:^2.0.0"
vue-plyr: "npm:^7.0.0"
vue-prism-editor: "npm:2.0.0-alpha.2"
vue-virtual-scroller: "npm:next"
vuedraggable: "npm:next"
languageName: unknown
linkType: soft
@ -14692,6 +14693,13 @@ __metadata:
languageName: node
linkType: hard
"mitt@npm:^2.1.0":
version: 2.1.0
resolution: "mitt@npm:2.1.0"
checksum: d4087f8678ef9de18af10171ed39c14fc9282532f9104b522265e4a206f81630767bce5e3ae2405e9d863d7f6a7f3095f738c33c55c06872ed25978f1c8ea9f3
languageName: node
linkType: hard
"mixin-deep@npm:^1.2.0":
version: 1.3.2
resolution: "mixin-deep@npm:1.3.2"
@ -20955,6 +20963,15 @@ __metadata:
languageName: node
linkType: hard
"vue-observe-visibility@npm:^2.0.0-alpha.1":
version: 2.0.0-alpha.1
resolution: "vue-observe-visibility@npm:2.0.0-alpha.1"
peerDependencies:
vue: ^3.0.0
checksum: 251948d4bdcc67e134962a754fcf10407add5ca1f6093a931f94081f0a434603a24175a0ae0fa147766e4a487f7e733f68558d245989f081dd29ea1e68f5fa57
languageName: node
linkType: hard
"vue-plyr@npm:^7.0.0":
version: 7.0.0
resolution: "vue-plyr@npm:7.0.0"
@ -20974,6 +20991,28 @@ __metadata:
languageName: node
linkType: hard
"vue-resize@npm:^2.0.0-alpha.1":
version: 2.0.0-alpha.1
resolution: "vue-resize@npm:2.0.0-alpha.1"
peerDependencies:
vue: ^3.0.0
checksum: d6e66472cd312b256fb277d1f7fc1b19f1faa45b1d8ea32bb473130a9075f5b2b0aa9efb3ad3f9492e88f6def65f8c93bc64b7cb818147ca6522e95981cb90ef
languageName: node
linkType: hard
"vue-virtual-scroller@npm:next":
version: 2.0.0-beta.8
resolution: "vue-virtual-scroller@npm:2.0.0-beta.8"
dependencies:
mitt: "npm:^2.1.0"
vue-observe-visibility: "npm:^2.0.0-alpha.1"
vue-resize: "npm:^2.0.0-alpha.1"
peerDependencies:
vue: ^3.2.0
checksum: 78047d2281dd133b63cc317d69e7a098088fb0fdfad386f2455aa791f3666f4dc7c9787e8beede7ec2113d46831d8cc89da63a61c9a9f59b09f2da0e8f4f96bb
languageName: node
linkType: hard
"vue@npm:3.3.4":
version: 3.3.4
resolution: "vue@npm:3.3.4"