Implement lazy loading of chats via lazy portal
This commit is contained in:
@@ -29,11 +29,11 @@
|
|||||||
import PlaygroundMenu from '../Playground/PlaygroundMenu.svelte';
|
import PlaygroundMenu from '../Playground/PlaygroundMenu.svelte';
|
||||||
import { ConnectionOpenStore } from 'src/ts/sync/multiuser';
|
import { ConnectionOpenStore } from 'src/ts/sync/multiuser';
|
||||||
import { coldStorageHeader, preLoadChat } from 'src/ts/process/coldstorage.svelte';
|
import { coldStorageHeader, preLoadChat } from 'src/ts/process/coldstorage.svelte';
|
||||||
|
import LazyPortal from '../UI/GUI/LazyPortal.svelte';
|
||||||
|
|
||||||
let messageInput:string = $state('')
|
let messageInput:string = $state('')
|
||||||
let messageInputTranslate:string = $state('')
|
let messageInputTranslate:string = $state('')
|
||||||
let openMenu = $state(false)
|
let openMenu = $state(false)
|
||||||
let loadPages = $state(30)
|
|
||||||
let autoMode = $state(false)
|
let autoMode = $state(false)
|
||||||
let rerolls:Message[][] = []
|
let rerolls:Message[][] = []
|
||||||
let rerollid = -1
|
let rerollid = -1
|
||||||
@@ -42,6 +42,23 @@
|
|||||||
let currentCharacter:character|groupChat = $state(DBState.db.characters[$selectedCharID])
|
let currentCharacter:character|groupChat = $state(DBState.db.characters[$selectedCharID])
|
||||||
let toggleStickers:boolean = $state(false)
|
let toggleStickers:boolean = $state(false)
|
||||||
let fileInput:string[] = $state([])
|
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(){
|
async function send(){
|
||||||
return sendMain(false)
|
return sendMain(false)
|
||||||
@@ -365,7 +382,6 @@
|
|||||||
|
|
||||||
async function screenShot(){
|
async function screenShot(){
|
||||||
try {
|
try {
|
||||||
loadPages = Infinity
|
|
||||||
const html2canvas = await import('html-to-image');
|
const html2canvas = await import('html-to-image');
|
||||||
const chats = document.querySelectorAll('.default-chat-screen .risu-chat')
|
const chats = document.querySelectorAll('.default-chat-screen .risu-chat')
|
||||||
alertWait("Taking screenShot...")
|
alertWait("Taking screenShot...")
|
||||||
@@ -412,7 +428,6 @@
|
|||||||
mergedCanvas.remove();
|
mergedCanvas.remove();
|
||||||
}
|
}
|
||||||
alertNormal(language.screenshotSaved)
|
alertNormal(language.screenshotSaved)
|
||||||
loadPages = 10
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
alertError("Error while taking screenshot")
|
alertError("Error while taking screenshot")
|
||||||
@@ -435,13 +450,7 @@
|
|||||||
<PlaygroundMenu />
|
<PlaygroundMenu />
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="h-full w-full flex flex-col-reverse overflow-y-auto relative default-chat-screen" onscroll={(e) => {
|
<div class="h-full w-full flex flex-col-reverse overflow-y-auto relative default-chat-screen" bind:this={root}>
|
||||||
//@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
|
<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"
|
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;' : ''}"
|
style="{DBState.db.fixedChatTextarea ? 'z-index:29;' : ''}"
|
||||||
@@ -649,6 +658,15 @@
|
|||||||
)} {send}/>
|
)} {send}/>
|
||||||
{/if}
|
{/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) }
|
{#if DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message?.[0]?.data?.startsWith(coldStorageHeader) }
|
||||||
{#await preLoadChat($selectedCharID, DBState.db.characters[$selectedCharID].chatPage)}
|
{#await preLoadChat($selectedCharID, DBState.db.characters[$selectedCharID].chatPage)}
|
||||||
<div class="w-full flex justify-center text-textcolor2 italic mb-12">
|
<div class="w-full flex justify-center text-textcolor2 italic mb-12">
|
||||||
@@ -658,103 +676,108 @@
|
|||||||
<div></div>
|
<div></div>
|
||||||
{/await}
|
{/await}
|
||||||
{:else}
|
{:else}
|
||||||
{#each messageForm(DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message, loadPages) as chat, i}
|
|
||||||
{#if chat.role === 'char'}
|
{#each DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message as chat, i}
|
||||||
{#if DBState.db.characters[$selectedCharID].type !== 'group'}
|
<LazyPortal root={root} idx={i} target={blockEle[i + 1]}>
|
||||||
<Chat
|
{#if chat.role === 'char'}
|
||||||
idx={chat.index}
|
{#if DBState.db.characters[$selectedCharID].type !== 'group'}
|
||||||
name={DBState.db.characters[$selectedCharID].name}
|
<Chat
|
||||||
message={chat.data}
|
idx={i}
|
||||||
img={getCharImage(DBState.db.characters[$selectedCharID].image, 'css')}
|
name={DBState.db.characters[$selectedCharID].name}
|
||||||
rerollIcon={i === 0}
|
message={chat.data}
|
||||||
onReroll={reroll}
|
img={getCharImage(DBState.db.characters[$selectedCharID].image, 'css')}
|
||||||
unReroll={unReroll}
|
rerollIcon={i === 0}
|
||||||
isLastMemory={DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].lastMemory === (chat.chatId ?? 'none') && DBState.db.showMemoryLimit}
|
onReroll={reroll}
|
||||||
character={createSimpleCharacter(DBState.db.characters[$selectedCharID])}
|
unReroll={unReroll}
|
||||||
largePortrait={DBState.db.characters[$selectedCharID].largePortrait}
|
isLastMemory={DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].lastMemory === (chat.chatId ?? 'none') && DBState.db.showMemoryLimit}
|
||||||
messageGenerationInfo={chat.generationInfo}
|
character={createSimpleCharacter(DBState.db.characters[$selectedCharID])}
|
||||||
/>
|
largePortrait={DBState.db.characters[$selectedCharID].largePortrait}
|
||||||
|
messageGenerationInfo={chat.generationInfo}
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<Chat
|
||||||
|
idx={i}
|
||||||
|
name={findCharacterbyId(chat.saying).name}
|
||||||
|
rerollIcon={i === 0}
|
||||||
|
message={chat.data}
|
||||||
|
onReroll={reroll}
|
||||||
|
unReroll={unReroll}
|
||||||
|
img={getCharImage(findCharacterbyId(chat.saying).image, 'css')}
|
||||||
|
isLastMemory={DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].lastMemory === (chat.chatId ?? 'none') && DBState.db.showMemoryLimit}
|
||||||
|
character={chat.saying}
|
||||||
|
largePortrait={findCharacterbyId(chat.saying).largePortrait}
|
||||||
|
messageGenerationInfo={chat.generationInfo}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<Chat
|
<Chat
|
||||||
idx={chat.index}
|
character={createSimpleCharacter(DBState.db.characters[$selectedCharID])}
|
||||||
name={findCharacterbyId(chat.saying).name}
|
idx={i}
|
||||||
rerollIcon={i === 0}
|
name={chat.name ?? currentUsername}
|
||||||
message={chat.data}
|
message={chat.data}
|
||||||
onReroll={reroll}
|
img={$ConnectionOpenStore ? '' : getCharImage(userIcon, 'css')}
|
||||||
unReroll={unReroll}
|
|
||||||
img={getCharImage(findCharacterbyId(chat.saying).image, 'css')}
|
|
||||||
isLastMemory={DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].lastMemory === (chat.chatId ?? 'none') && DBState.db.showMemoryLimit}
|
isLastMemory={DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].lastMemory === (chat.chatId ?? 'none') && DBState.db.showMemoryLimit}
|
||||||
character={chat.saying}
|
largePortrait={userIconProtrait}
|
||||||
largePortrait={findCharacterbyId(chat.saying).largePortrait}
|
|
||||||
messageGenerationInfo={chat.generationInfo}
|
messageGenerationInfo={chat.generationInfo}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
</LazyPortal>
|
||||||
<Chat
|
|
||||||
character={createSimpleCharacter(DBState.db.characters[$selectedCharID])}
|
|
||||||
idx={chat.index}
|
|
||||||
name={chat.name ?? currentUsername}
|
|
||||||
message={chat.data}
|
|
||||||
img={$ConnectionOpenStore ? '' : getCharImage(userIcon, 'css')}
|
|
||||||
isLastMemory={DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].lastMemory === (chat.chatId ?? 'none') && DBState.db.showMemoryLimit}
|
|
||||||
largePortrait={userIconProtrait}
|
|
||||||
messageGenerationInfo={chat.generationInfo}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
{/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])}
|
|
||||||
name={DBState.db.characters[$selectedCharID].name}
|
|
||||||
message={DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].fmIndex === -1 ? DBState.db.characters[$selectedCharID].firstMessage :
|
|
||||||
DBState.db.characters[$selectedCharID].alternateGreetings[DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].fmIndex]}
|
|
||||||
img={getCharImage(DBState.db.characters[$selectedCharID].image, 'css')}
|
|
||||||
idx={-1}
|
|
||||||
altGreeting={DBState.db.characters[$selectedCharID].alternateGreetings.length > 0}
|
|
||||||
largePortrait={DBState.db.characters[$selectedCharID].largePortrait}
|
|
||||||
firstMessage={true}
|
|
||||||
onReroll={() => {
|
|
||||||
const cha = DBState.db.characters[$selectedCharID]
|
|
||||||
const chat = DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage]
|
|
||||||
if(cha.type !== 'group'){
|
|
||||||
if (chat.fmIndex >= (cha.alternateGreetings.length - 1)){
|
|
||||||
chat.fmIndex = -1
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
chat.fmIndex += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] = chat
|
|
||||||
}}
|
|
||||||
unReroll={() => {
|
|
||||||
const cha = DBState.db.characters[$selectedCharID]
|
|
||||||
const chat = DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage]
|
|
||||||
if(cha.type !== 'group'){
|
|
||||||
if (chat.fmIndex === -1){
|
|
||||||
chat.fmIndex = (cha.alternateGreetings.length - 1)
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
chat.fmIndex -= 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] = chat
|
|
||||||
}}
|
|
||||||
isLastMemory={false}
|
|
||||||
|
|
||||||
/>
|
{#if DBState.db.characters[$selectedCharID].type !== 'group' }
|
||||||
{#if !DBState.db.characters[$selectedCharID].removedQuotes && DBState.db.characters[$selectedCharID].creatorNotes.length >= 2}
|
<Chat
|
||||||
<CreatorQuote quote={DBState.db.characters[$selectedCharID].creatorNotes} onRemove={() => {
|
character={createSimpleCharacter(DBState.db.characters[$selectedCharID])}
|
||||||
const cha = DBState.db.characters[$selectedCharID]
|
name={DBState.db.characters[$selectedCharID].name}
|
||||||
if(cha.type !== 'group'){
|
message={DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].fmIndex === -1 ? DBState.db.characters[$selectedCharID].firstMessage :
|
||||||
cha.removedQuotes = true
|
DBState.db.characters[$selectedCharID].alternateGreetings[DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].fmIndex]}
|
||||||
}
|
img={getCharImage(DBState.db.characters[$selectedCharID].image, 'css')}
|
||||||
DBState.db.characters[$selectedCharID] = cha
|
idx={-1}
|
||||||
}} />
|
altGreeting={DBState.db.characters[$selectedCharID].alternateGreetings.length > 0}
|
||||||
|
largePortrait={DBState.db.characters[$selectedCharID].largePortrait}
|
||||||
|
firstMessage={true}
|
||||||
|
onReroll={() => {
|
||||||
|
const cha = DBState.db.characters[$selectedCharID]
|
||||||
|
const chat = DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage]
|
||||||
|
if(cha.type !== 'group'){
|
||||||
|
if (chat.fmIndex >= (cha.alternateGreetings.length - 1)){
|
||||||
|
chat.fmIndex = -1
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
chat.fmIndex += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] = chat
|
||||||
|
}}
|
||||||
|
unReroll={() => {
|
||||||
|
const cha = DBState.db.characters[$selectedCharID]
|
||||||
|
const chat = DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage]
|
||||||
|
if(cha.type !== 'group'){
|
||||||
|
if (chat.fmIndex === -1){
|
||||||
|
chat.fmIndex = (cha.alternateGreetings.length - 1)
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
chat.fmIndex -= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] = chat
|
||||||
|
}}
|
||||||
|
isLastMemory={false}
|
||||||
|
|
||||||
|
/>
|
||||||
|
{#if !DBState.db.characters[$selectedCharID].removedQuotes && DBState.db.characters[$selectedCharID].creatorNotes.length >= 2}
|
||||||
|
<CreatorQuote quote={DBState.db.characters[$selectedCharID].creatorNotes} onRemove={() => {
|
||||||
|
const cha = DBState.db.characters[$selectedCharID]
|
||||||
|
if(cha.type !== 'group'){
|
||||||
|
cha.removedQuotes = true
|
||||||
|
}
|
||||||
|
DBState.db.characters[$selectedCharID] = cha
|
||||||
|
}} />
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
|
||||||
{/if}
|
</LazyPortal>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|||||||
65
src/lib/UI/GUI/LazyPortal.svelte
Normal file
65
src/lib/UI/GUI/LazyPortal.svelte
Normal 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>
|
||||||
@@ -1708,6 +1708,12 @@ function basicMatcher (p1:string,matcherArg:matcherArg,vars:{[key:string]:string
|
|||||||
}
|
}
|
||||||
return total.toString()
|
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')){
|
if(p1.startsWith('random')){
|
||||||
|
|||||||
Reference in New Issue
Block a user