Implement lazy loading of chats via lazy portal

This commit is contained in:
kwaroran
2025-04-28 15:38:57 +09:00
parent 39048dd142
commit 05c51f333f
3 changed files with 190 additions and 96 deletions

View File

@@ -29,11 +29,11 @@
import PlaygroundMenu from '../Playground/PlaygroundMenu.svelte';
import { ConnectionOpenStore } from 'src/ts/sync/multiuser';
import { coldStorageHeader, preLoadChat } from 'src/ts/process/coldstorage.svelte';
import LazyPortal from '../UI/GUI/LazyPortal.svelte';
let messageInput:string = $state('')
let messageInputTranslate:string = $state('')
let openMenu = $state(false)
let loadPages = $state(30)
let autoMode = $state(false)
let rerolls:Message[][] = []
let rerollid = -1
@@ -42,6 +42,23 @@
let currentCharacter:character|groupChat = $state(DBState.db.characters[$selectedCharID])
let toggleStickers:boolean = $state(false)
let fileInput:string[] = $state([])
let blocks = $state(new Uint8Array(500) )//hacky hacky
let blockEle:HTMLElement[] = []
let root: HTMLElement = $state(null)
for(let i=0;i<500;i++){
blockEle.push(null)
}
$effect(() => {
if(blocks.length-10 < DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length){
blocks = new Uint8Array(blocks.length + 500)
for(let i=0;i<500;i++){
blockEle.push(null)
}
}
})
async function send(){
return sendMain(false)
@@ -365,7 +382,6 @@
async function screenShot(){
try {
loadPages = Infinity
const html2canvas = await import('html-to-image');
const chats = document.querySelectorAll('.default-chat-screen .risu-chat')
alertWait("Taking screenShot...")
@@ -412,7 +428,6 @@
mergedCanvas.remove();
}
alertNormal(language.screenshotSaved)
loadPages = 10
} catch (error) {
console.error(error)
alertError("Error while taking screenshot")
@@ -435,13 +450,7 @@
<PlaygroundMenu />
{/if}
{:else}
<div class="h-full w-full flex flex-col-reverse overflow-y-auto relative default-chat-screen" onscroll={(e) => {
//@ts-ignore
const scrolled = (e.target.scrollHeight - e.target.clientHeight + e.target.scrollTop)
if(scrolled < 100 && DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length > loadPages){
loadPages += 15
}
}}>
<div class="h-full w-full flex flex-col-reverse overflow-y-auto relative default-chat-screen" bind:this={root}>
<div
class="{DBState.db.fixedChatTextarea ? 'sticky pt-2 pb-2 right-0 bottom-0 bg-bgcolor' : 'mt-2 mb-2'} flex items-stretch w-full"
style="{DBState.db.fixedChatTextarea ? 'z-index:29;' : ''}"
@@ -649,6 +658,15 @@
)} {send}/>
{/if}
{#each blocks as block, i}
<div
class="w-full max-w-full" id={'x-chat-' + (blocks.length - i - 1)}
bind:this={blockEle[blocks.length - i - 1]}
>
</div>
{/each}
{#if DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message?.[0]?.data?.startsWith(coldStorageHeader) }
{#await preLoadChat($selectedCharID, DBState.db.characters[$selectedCharID].chatPage)}
<div class="w-full flex justify-center text-textcolor2 italic mb-12">
@@ -658,11 +676,13 @@
<div></div>
{/await}
{:else}
{#each messageForm(DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message, loadPages) as chat, i}
{#each DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message as chat, i}
<LazyPortal root={root} idx={i} target={blockEle[i + 1]}>
{#if chat.role === 'char'}
{#if DBState.db.characters[$selectedCharID].type !== 'group'}
<Chat
idx={chat.index}
idx={i}
name={DBState.db.characters[$selectedCharID].name}
message={chat.data}
img={getCharImage(DBState.db.characters[$selectedCharID].image, 'css')}
@@ -676,7 +696,7 @@
/>
{:else}
<Chat
idx={chat.index}
idx={i}
name={findCharacterbyId(chat.saying).name}
rerollIcon={i === 0}
message={chat.data}
@@ -692,7 +712,7 @@
{:else}
<Chat
character={createSimpleCharacter(DBState.db.characters[$selectedCharID])}
idx={chat.index}
idx={i}
name={chat.name ?? currentUsername}
message={chat.data}
img={$ConnectionOpenStore ? '' : getCharImage(userIcon, 'css')}
@@ -701,9 +721,11 @@
messageGenerationInfo={chat.generationInfo}
/>
{/if}
</LazyPortal>
{/each}
{#if DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length <= loadPages}
<LazyPortal root={root} target={blockEle[0]}>
{#if DBState.db.characters[$selectedCharID].type !== 'group' }
<Chat
character={createSimpleCharacter(DBState.db.characters[$selectedCharID])}
@@ -754,7 +776,8 @@
}} />
{/if}
{/if}
{/if}
</LazyPortal>
{/if}

View File

@@ -0,0 +1,65 @@
<script lang="ts">
import { getAllContexts, mount, onDestroy, onMount, unmount } from "svelte";
//@ts-ignore
import PortalConsumer from "./PortalConsumer.svelte";
import { sleep } from "src/ts/util";
interface Props {
target?: HTMLElement;
children: any;
root?: HTMLElement
idx?: number
}
const { target: target = document.body, children, root, idx }:Props = $props();
const paddingEle = document.createElement('div')
const context = getAllContexts();
let instance;
let seen = $state(false)
onMount(() => {
paddingEle.style.height = '48px';
paddingEle.style.width = '100%'
paddingEle.style.backgroundColor = '#ffffff'
paddingEle.style.color = 'black'
target.appendChild(paddingEle)
sleep(100).then(() => {
const observer = new IntersectionObserver((v) => {
if(v[0].intersectionRatio > 0.5){
seen = true
target.removeChild(paddingEle)
observer.disconnect()
}
}, {
threshold: 0.5,
})
observer.observe(target)
return () => {
if(!seen){
observer.disconnect()
}
}
})
})
$effect(() => {
if(seen){
instance = mount(PortalConsumer, { target, props: { children }, context })
}
return () => {
if(instance){
unmount(instance);
try {
target.removeChild(paddingEle)
} catch (error) {}
}
}
});
</script>

View File

@@ -1708,6 +1708,12 @@ function basicMatcher (p1:string,matcherArg:matcherArg,vars:{[key:string]:string
}
return total.toString()
}
case 'fromhex':{
return Number.parseInt(arra[1], 16).toString()
}
case 'tohex':{
return Number.parseInt(arra[1]).toString(16)
}
}
}
if(p1.startsWith('random')){