feat: module lorebook sort, import, export
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
import { language } from "src/lang";
|
import { language } from "src/lang";
|
||||||
import TextInput from "src/lib/UI/GUI/TextInput.svelte";
|
import TextInput from "src/lib/UI/GUI/TextInput.svelte";
|
||||||
import LoreBookData from "src/lib/SideBars/LoreBook/LoreBookData.svelte";
|
import LoreBookData from "src/lib/SideBars/LoreBook/LoreBookData.svelte";
|
||||||
|
import type { loreBook } from "src/ts/storage/database.svelte";
|
||||||
|
import LoreBookList from "src/lib/SideBars/LoreBook/LoreBookList.svelte";
|
||||||
|
import { type CCLorebook, convertExternalLorebook } from "src/ts/process/lorebook.svelte";
|
||||||
import type { RisuModule } from "src/ts/process/modules";
|
import type { RisuModule } from "src/ts/process/modules";
|
||||||
import { DownloadIcon, FolderUpIcon, PlusIcon, TrashIcon } from "lucide-svelte";
|
import { DownloadIcon, FolderUpIcon, PlusIcon, TrashIcon } from "lucide-svelte";
|
||||||
import RegexList from "src/lib/SideBars/Scripts/RegexList.svelte";
|
import RegexList from "src/lib/SideBars/Scripts/RegexList.svelte";
|
||||||
@@ -9,7 +12,8 @@
|
|||||||
import Check from "src/lib/UI/GUI/CheckInput.svelte";
|
import Check from "src/lib/UI/GUI/CheckInput.svelte";
|
||||||
import Help from "src/lib/Others/Help.svelte";
|
import Help from "src/lib/Others/Help.svelte";
|
||||||
import TextAreaInput from "src/lib/UI/GUI/TextAreaInput.svelte";
|
import TextAreaInput from "src/lib/UI/GUI/TextAreaInput.svelte";
|
||||||
import { getFileSrc, openURL, saveAsset } from "src/ts/globalApi.svelte";
|
import { getFileSrc, openURL, saveAsset, downloadFile } from "src/ts/globalApi.svelte";
|
||||||
|
import { alertNormal, alertError } from "src/ts/alert";
|
||||||
import { exportRegex, importRegex } from "src/ts/process/scripts";
|
import { exportRegex, importRegex } from "src/ts/process/scripts";
|
||||||
import { selectMultipleFile } from "src/ts/util";
|
import { selectMultipleFile } from "src/ts/util";
|
||||||
|
|
||||||
@@ -57,6 +61,48 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function exportLoreBook(){
|
||||||
|
try {
|
||||||
|
const lore = currentModule.lorebook
|
||||||
|
const stringl = Buffer.from(JSON.stringify({
|
||||||
|
type: 'risu',
|
||||||
|
ver: 1,
|
||||||
|
data: lore
|
||||||
|
}), 'utf-8')
|
||||||
|
|
||||||
|
await downloadFile(`lorebook_export.json`, stringl)
|
||||||
|
|
||||||
|
alertNormal(language.successExport)
|
||||||
|
} catch (error) {
|
||||||
|
alertError(`${error}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function importLoreBook(){
|
||||||
|
let lore = currentModule.lorebook
|
||||||
|
const lorebook = (await selectMultipleFile(['json', 'lorebook']))
|
||||||
|
if(!lorebook){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for(const f of lorebook){
|
||||||
|
const importedlore = JSON.parse(Buffer.from(f.data).toString('utf-8'))
|
||||||
|
if(importedlore.type === 'risu' && importedlore.data){
|
||||||
|
const datas:loreBook[] = importedlore.data
|
||||||
|
for(const data of datas){
|
||||||
|
lore.push(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(importedlore.entries){
|
||||||
|
const entries:{[key:string]:CCLorebook} = importedlore.entries
|
||||||
|
lore.push(...convertExternalLorebook(entries))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alertError(`${error}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addRegex(){
|
function addRegex(){
|
||||||
if(Array.isArray(currentModule.regex)){
|
if(Array.isArray(currentModule.regex)){
|
||||||
currentModule.regex.push({
|
currentModule.regex.push({
|
||||||
@@ -150,17 +196,18 @@
|
|||||||
<TextAreaInput bind:value={currentModule.customModuleToggle}/>
|
<TextAreaInput bind:value={currentModule.customModuleToggle}/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if submenu === 1 && (Array.isArray(currentModule.lorebook))}
|
{#if submenu === 1 && (Array.isArray(currentModule.lorebook))}
|
||||||
<div class="border border-selected p-2 flex flex-col rounded-md mt-2">
|
<LoreBookList externalLoreBooks={currentModule.lorebook} />
|
||||||
{#each currentModule.lorebook as lore, i}
|
<div class="text-textcolor2 mt-2 flex">
|
||||||
<LoreBookData bind:value={currentModule.lorebook[i]} idx={i} onRemove={() => {
|
<button onclick={() => {addLorebook()}} class="hover:text-textcolor cursor-pointer ml-1">
|
||||||
currentModule.lorebook.splice(i, 1)
|
<PlusIcon />
|
||||||
currentModule.lorebook = currentModule.lorebook
|
</button>
|
||||||
}}/>
|
<button onclick={() => {exportLoreBook()}} class="hover:text-textcolor cursor-pointer ml-2">
|
||||||
{/each}
|
<DownloadIcon />
|
||||||
|
</button>
|
||||||
|
<button onclick={() => {importLoreBook()}} class="hover:text-textcolor cursor-pointer ml-2">
|
||||||
|
<FolderUpIcon />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button onclick={() => {addLorebook()}} class="hover:text-textcolor cursor-pointer">
|
|
||||||
<PlusIcon />
|
|
||||||
</button>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if submenu === 2 && (Array.isArray(currentModule.regex))}
|
{#if submenu === 2 && (Array.isArray(currentModule.regex))}
|
||||||
|
|||||||
@@ -11,9 +11,10 @@
|
|||||||
globalMode?: boolean;
|
globalMode?: boolean;
|
||||||
submenu?: number;
|
submenu?: number;
|
||||||
lorePlus?: boolean;
|
lorePlus?: boolean;
|
||||||
|
externalLoreBooks?: loreBook[];
|
||||||
}
|
}
|
||||||
|
|
||||||
let { globalMode = false, submenu = 0, lorePlus = false }: Props = $props();
|
let { globalMode = false, submenu = 0, lorePlus = false, externalLoreBooks = null }: Props = $props();
|
||||||
let stb: Sortable = null
|
let stb: Sortable = null
|
||||||
let ele: HTMLDivElement = $state()
|
let ele: HTMLDivElement = $state()
|
||||||
let sorted = $state(0)
|
let sorted = $state(0)
|
||||||
@@ -31,6 +32,13 @@
|
|||||||
})
|
})
|
||||||
DBState.db.loreBook[DBState.db.loreBookPage].data = newLore
|
DBState.db.loreBook[DBState.db.loreBookPage].data = newLore
|
||||||
}
|
}
|
||||||
|
else if(externalLoreBooks){
|
||||||
|
let newLore:loreBook[] = []
|
||||||
|
idx.forEach((i) => {
|
||||||
|
newLore.push(externalLoreBooks[i])
|
||||||
|
})
|
||||||
|
externalLoreBooks = newLore
|
||||||
|
}
|
||||||
else if(submenu === 1){
|
else if(submenu === 1){
|
||||||
let newLore:loreBook[] = []
|
let newLore:loreBook[] = []
|
||||||
idx.forEach((i) => {
|
idx.forEach((i) => {
|
||||||
@@ -97,6 +105,18 @@
|
|||||||
}} onOpen={onOpen} onClose={onClose}/>
|
}} onOpen={onOpen} onClose={onClose}/>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
{:else if externalLoreBooks}
|
||||||
|
{#if externalLoreBooks.length === 0}
|
||||||
|
<span class="text-textcolor2">No Lorebook</span>
|
||||||
|
{:else}
|
||||||
|
{#each externalLoreBooks as book, i}
|
||||||
|
<LoreBookData bind:value={externalLoreBooks[i]} idx={i} onRemove={() => {
|
||||||
|
let lore = externalLoreBooks
|
||||||
|
lore.splice(i, 1)
|
||||||
|
externalLoreBooks = lore
|
||||||
|
}} onOpen={onOpen} onClose={onClose}/>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
{:else if submenu === 0}
|
{:else if submenu === 0}
|
||||||
{#if DBState.db.characters[$selectedCharID].globalLore.length === 0}
|
{#if DBState.db.characters[$selectedCharID].globalLore.length === 0}
|
||||||
<span class="text-textcolor2">No Lorebook</span>
|
<span class="text-textcolor2">No Lorebook</span>
|
||||||
|
|||||||
@@ -510,7 +510,7 @@ export async function importLoreBook(mode:'global'|'local'|'sglobal'){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CCLorebook{
|
export interface CCLorebook{
|
||||||
key:string[]
|
key:string[]
|
||||||
comment:string
|
comment:string
|
||||||
content:string
|
content:string
|
||||||
|
|||||||
Reference in New Issue
Block a user