Add Custom GUI settings, not for real use now
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Sidebar from './lib/SideBars/Sidebar.svelte';
|
||||
import { DynamicGUI, settingsOpen, sideBarStore, ShowRealmFrameStore, openPresetList, openPersonaList, MobileGUI } from './ts/stores';
|
||||
import { DynamicGUI, settingsOpen, sideBarStore, ShowRealmFrameStore, openPresetList, openPersonaList, MobileGUI, CustomGUISettingMenuStore } from './ts/stores';
|
||||
import { DataBase, loadedStore } from './ts/storage/database';
|
||||
import ChatScreen from './lib/ChatScreens/ChatScreen.svelte';
|
||||
import AlertComp from './lib/Others/AlertComp.svelte';
|
||||
@@ -18,6 +18,7 @@
|
||||
import MobileHeader from './lib/Mobile/MobileHeader.svelte';
|
||||
import MobileBody from './lib/Mobile/MobileBody.svelte';
|
||||
import MobileFooter from './lib/Mobile/MobileFooter.svelte';
|
||||
import CustomGUISettingMenu from './lib/Setting/Pages/CustomGUISettingMenu.svelte';
|
||||
|
||||
|
||||
let didFirstSetup: boolean = false
|
||||
@@ -40,6 +41,8 @@
|
||||
</svg>
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
{:else if $CustomGUISettingMenuStore}
|
||||
<CustomGUISettingMenu />
|
||||
{:else if !didFirstSetup}
|
||||
<WelcomeRisu />
|
||||
{:else if $settingsOpen}
|
||||
|
||||
@@ -748,4 +748,5 @@ export const languageEnglish = {
|
||||
formatGroupInSingle: "Format Group in Single",
|
||||
groupInnerFormat: "Non-Speaker Inner Format",
|
||||
groupOtherBotRole: "Non-Speaker Role in Group",
|
||||
defineCustomGUI: "Define Custom GUI",
|
||||
}
|
||||
260
src/lib/Setting/Pages/CustomGUISettingMenu.svelte
Normal file
260
src/lib/Setting/Pages/CustomGUISettingMenu.svelte
Normal file
@@ -0,0 +1,260 @@
|
||||
<script lang="ts">
|
||||
|
||||
interface CustomTree {
|
||||
name: string; // dom name, like div, span, etc. for component, we use 'component'
|
||||
type: string; // type, used for identifying in editor
|
||||
class: string[]; // classes, used for styling in tailwind
|
||||
children: CustomTree[]; // children, used for nesting
|
||||
}
|
||||
|
||||
let tree:CustomTree[] = [] //children of the main tree
|
||||
let mainTree:HTMLDivElement
|
||||
let menuOpen:boolean = false
|
||||
let subMenu = 0
|
||||
let selectedContatiner = 'root'
|
||||
|
||||
const builtContainerTrees:CustomTree[] = [
|
||||
{
|
||||
type: "leftToRightContainer",
|
||||
name: "div",
|
||||
class: ["flex", "flex-row", "flex-1"],
|
||||
children: []
|
||||
},
|
||||
{
|
||||
type: "topToBottomContainer",
|
||||
name: "div",
|
||||
class: ["flex", "flex-col", "flex-1"],
|
||||
children: []
|
||||
},
|
||||
{
|
||||
type: "centeredleftToRightContainer",
|
||||
name: "div",
|
||||
class: ["flex", "flex-row", "flex-1", "items-center", "justify-center"],
|
||||
children: []
|
||||
},
|
||||
{
|
||||
type: "centeredTopToBottomContainer",
|
||||
name: "div",
|
||||
class: ["flex", "flex-col", "flex-1", "items-center", "justify-center"],
|
||||
children: []
|
||||
}
|
||||
]
|
||||
|
||||
const builtComponentTrees:CustomTree[] = [
|
||||
{
|
||||
type: "fullWidthChat",
|
||||
name: "component",
|
||||
class: ["flex", "flex-col", "flex-1"],
|
||||
children: []
|
||||
},
|
||||
{
|
||||
type: "fixedWidthChat",
|
||||
name: "component",
|
||||
class: ["flex", "flex-col", "w-96"],
|
||||
children: []
|
||||
},
|
||||
{
|
||||
type: "sideBarWithCharacter",
|
||||
name: "component",
|
||||
class: ["flex", "flex-col", "w-96"],
|
||||
children: []
|
||||
},
|
||||
{
|
||||
type: "sideBarWithoutCharacter",
|
||||
name: "component",
|
||||
class: ["flex", "flex-col", "w-96"],
|
||||
children: []
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
function renderTree(dom:HTMLElement, currentTree:CustomTree, treeChain:string = "") {
|
||||
let element = document.createElement(currentTree.name)
|
||||
element.classList.add(...currentTree.class)
|
||||
currentTree.children.forEach((child, i) => {
|
||||
renderTree(element, child, treeChain + "." + i)
|
||||
})
|
||||
|
||||
if(currentTree.type === 'custom'){
|
||||
dom.appendChild(element)
|
||||
}
|
||||
else{
|
||||
const textElement = document.createElement('p')
|
||||
textElement.innerText = currentTree.type
|
||||
if(treeChain === selectedContatiner){
|
||||
element.classList.add("bg-blue-200", "border-2", "border-blue-400", "relative", "bg-opacity-50", "p-4", "z-20")
|
||||
textElement.classList.add("absolute", "top-0", "left-0", "bg-blue-200", "p-1", "text-black")
|
||||
}
|
||||
else{
|
||||
element.classList.add("bg-gray-200", "border-2", "border-gray-400", "relative", "bg-opacity-50", "p-4", "z-20")
|
||||
textElement.classList.add("absolute", "top-0", "left-0", "bg-white", "p-1", "text-black")
|
||||
}
|
||||
element.appendChild(textElement)
|
||||
element.setAttribute("x-tree", treeChain)
|
||||
dom.appendChild(element)
|
||||
|
||||
element.addEventListener('mouseup', (e) => {
|
||||
console.log(treeChain, e.button)
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
switch(e.button){
|
||||
case 0:
|
||||
selectedContatiner = treeChain
|
||||
renderMainTree(tree)
|
||||
break
|
||||
case 2:
|
||||
tree = removeTreeChain(tree, treeChain)
|
||||
renderMainTree(tree)
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
element.addEventListener('contextmenu', (e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function removeTreeChain(tree:CustomTree[], treeChain:string){
|
||||
let treeChainArray = treeChain.split(".")
|
||||
let currentTree = tree
|
||||
for(let i = 0; i < treeChainArray.length; i++){
|
||||
let index = parseInt(treeChainArray[i])
|
||||
if(i === treeChainArray.length - 1){
|
||||
currentTree.splice(index, 1)
|
||||
}
|
||||
else{
|
||||
currentTree = currentTree[index].children
|
||||
}
|
||||
}
|
||||
return tree
|
||||
}
|
||||
|
||||
function renderMainTree(tree:CustomTree[]) {
|
||||
mainTree.innerHTML = ""
|
||||
tree.forEach((child, i) => {
|
||||
renderTree(mainTree, child, i.toString())
|
||||
})
|
||||
}
|
||||
|
||||
function HTMLtoTree(html:string){
|
||||
let parser = new DOMParser()
|
||||
let doc = parser.parseFromString(html, 'text/html')
|
||||
let body = doc.body
|
||||
let tree:CustomTree[] = []
|
||||
let children = body.children
|
||||
for(let i = 0; i < children.length; i++){
|
||||
let child = children[i]
|
||||
let treeChild:CustomTree = {
|
||||
name: child.tagName.toLowerCase(),
|
||||
type: child.tagName.toLowerCase(),
|
||||
class: child.className.split(" "),
|
||||
children: []
|
||||
}
|
||||
if(child.children.length > 0){
|
||||
treeChild.children = HTMLtoTree(child.innerHTML)
|
||||
}
|
||||
tree.push(treeChild)
|
||||
}
|
||||
return tree
|
||||
}
|
||||
|
||||
function addContainerToTree(container:CustomTree, treeChain:string){
|
||||
|
||||
if(treeChain === 'root'){
|
||||
tree.push(container)
|
||||
return
|
||||
}
|
||||
|
||||
let treeChainArray = treeChain.split(".")
|
||||
let currentTree = tree
|
||||
for(let i = 0; i < treeChainArray.length; i++){
|
||||
let index = parseInt(treeChainArray[i])
|
||||
if(i === treeChainArray.length - 1){
|
||||
currentTree[index].children.push(container)
|
||||
}
|
||||
else{
|
||||
currentTree = currentTree[index].children
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function treeToHTML(tree:CustomTree[], indent:number = 0){
|
||||
let html = ""
|
||||
const noClosingTag = ["img", "input", "br", "hr"]
|
||||
const ind = " ".repeat(indent)
|
||||
tree.forEach(child => {
|
||||
if(child.class.length > 0){
|
||||
html += `${ind}<${child.name} class="${child.class.join(" ")}">\n`
|
||||
}
|
||||
else{
|
||||
html += `${ind}<${child.name}>\n`
|
||||
}
|
||||
|
||||
if(noClosingTag.includes(child.name)){
|
||||
return
|
||||
}
|
||||
|
||||
if(child.children.length > 0){
|
||||
html += treeToHTML(child.children, indent + 1)
|
||||
}
|
||||
html += `${ind}</${child.name}>\n`
|
||||
})
|
||||
return html
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="w-full h-full relative flex p-4 border"
|
||||
class:border-blue-500={selectedContatiner === 'root'}
|
||||
on:click={() => {
|
||||
selectedContatiner = 'root'
|
||||
renderMainTree(tree)
|
||||
}}
|
||||
on:contextmenu|preventDefault
|
||||
bind:this={mainTree}
|
||||
>
|
||||
|
||||
</div>
|
||||
{#if menuOpen}
|
||||
<div class="w-138 max-w-full h-full bg-white text-black border-l border-l-black p-4 flex flex-col gap-2 z-20">
|
||||
<div class="flex">
|
||||
<button class="mr-2 p-2 border border-black rounded" class:text-gray-500={subMenu !== 0} on:click={() => {
|
||||
subMenu = 0
|
||||
}}>Component</button>
|
||||
<button class="mr-2 p-2 border border-black rounded" class:text-gray-500={subMenu !== 1} on:click={() => {
|
||||
subMenu = 1
|
||||
}}>Container</button>
|
||||
<button class="mr-2 p-2 border border-black rounded" class:text-gray-500={subMenu !== 2} on:click={() => {
|
||||
subMenu = 2
|
||||
}}>Help</button>
|
||||
</div>
|
||||
<div class="border-b border-b-gray-200">
|
||||
|
||||
</div>
|
||||
{#if subMenu === 0}
|
||||
{#each builtComponentTrees as component, i}
|
||||
<button class="p-2 border border-black rounded" on:click={() => {
|
||||
addContainerToTree(structuredClone(component), selectedContatiner)
|
||||
renderMainTree(tree)
|
||||
}}>{component.type}</button>
|
||||
{/each}
|
||||
{:else if subMenu === 1}
|
||||
{#each builtContainerTrees as container, i}
|
||||
<button class="p-2 border border-black rounded" on:click={() => {
|
||||
addContainerToTree(structuredClone(container), selectedContatiner)
|
||||
renderMainTree(tree)
|
||||
}}>{container.type}</button>
|
||||
{/each}
|
||||
{:else if subMenu === 2}
|
||||
<p>Left click to select, Right click to delete</p>
|
||||
<p>Press a component/container in the menu to add it to the selected container</p>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<button class="absolute top-0 right-0 z-20 p-2 border bg-white rounded" on:click={() => {
|
||||
menuOpen = !menuOpen
|
||||
}}>Menu</button>
|
||||
{/if}
|
||||
@@ -14,6 +14,9 @@
|
||||
import TextInput from "src/lib/UI/GUI/TextInput.svelte";
|
||||
import ColorInput from "src/lib/UI/GUI/ColorInput.svelte";
|
||||
import TextAreaInput from "src/lib/UI/GUI/TextAreaInput.svelte";
|
||||
import Arcodion from "src/lib/UI/Arcodion.svelte";
|
||||
import Button from "src/lib/UI/GUI/Button.svelte";
|
||||
import { CustomGUISettingMenuStore } from "src/ts/stores";
|
||||
|
||||
const onSchemeInputChange = (e:Event) => {
|
||||
changeColorScheme((e.target as HTMLInputElement).value)
|
||||
@@ -50,8 +53,15 @@
|
||||
<OptionInput value="" >Standard Risu</OptionInput>
|
||||
<OptionInput value="waifu" >Waifulike</OptionInput>
|
||||
<OptionInput value="waifuMobile" >WaifuCut</OptionInput>
|
||||
<!-- <OptionInput value="custom" >Custom GUI</OptionInput> -->
|
||||
</SelectInput>
|
||||
|
||||
{#if $DataBase.theme === "custom"}
|
||||
<Button className="mt-2" on:click={() => {
|
||||
CustomGUISettingMenuStore.set(true)
|
||||
}}>{language.defineCustomGUI}</Button>
|
||||
{/if}
|
||||
|
||||
|
||||
{#if $DataBase.theme === "waifu"}
|
||||
<span class="text-textcolor mt-4">{language.waifuWidth}</span>
|
||||
|
||||
@@ -444,6 +444,7 @@ export function setDatabase(data:Database){
|
||||
data.customQuotes ??= false
|
||||
data.customQuotesData ??= ['“','”','‘','’']
|
||||
data.groupOtherBotRole ??= 'user'
|
||||
data.customGUI ??= ''
|
||||
changeLanguage(data.language)
|
||||
DataBase.set(data)
|
||||
}
|
||||
@@ -752,6 +753,7 @@ export interface Database{
|
||||
customQuotesData?:[string, string, string, string]
|
||||
groupTemplate?:string
|
||||
groupOtherBotRole?:string
|
||||
customGUI:string
|
||||
}
|
||||
|
||||
export interface customscript{
|
||||
|
||||
@@ -50,6 +50,7 @@ export const CustomCSSStore = writable('')
|
||||
export const SafeModeStore = writable(false)
|
||||
export const MobileSearch = writable('')
|
||||
export const CharConfigSubMenu = writable(0)
|
||||
export const CustomGUISettingMenuStore = writable(false)
|
||||
|
||||
let lastGlobalEnabledModules: string[] = []
|
||||
let lastChatEnabledModules: string[] = []
|
||||
|
||||
Reference in New Issue
Block a user