Merge branch 'master' of https://github.com/sigonasr2/ngsplanner
This commit is contained in:
commit
85c06c089b
85
src/App.js
85
src/App.js
@ -4,7 +4,7 @@ import React, {useState,useEffect,useReducer} from 'react';
|
||||
import Toggle from 'react-toggle' //Tooltip props: http://aaronshaf.github.io/react-toggle/
|
||||
import Helmet from 'react-helmet'
|
||||
|
||||
import {XSquareFill, PlusCircle, LifePreserver, Server, CloudUploadFill} from 'react-bootstrap-icons'
|
||||
import {TrashFill, PlusCircle, LifePreserver, Server, CloudUploadFill} from 'react-bootstrap-icons'
|
||||
|
||||
import { SkillTreeEditor } from './skilltree/skillTreeEditor'
|
||||
|
||||
@ -57,11 +57,11 @@ function Box(p) {
|
||||
}
|
||||
|
||||
function Table(p) {
|
||||
return <p className={p.classes}>
|
||||
return <span className={p.classes}>
|
||||
|
||||
{p.children}
|
||||
|
||||
</p>
|
||||
</span>
|
||||
}
|
||||
|
||||
function InputBox(p) {
|
||||
@ -93,7 +93,7 @@ function InputBox(p) {
|
||||
|
||||
return p.data?<select disabled={p.lockSubmission} className={failed?"failedInput":sending?"submitting":""} value={value} onKeyDown={(f)=>{keydownFunc(f)}} onChange={(f)=>{changeFunc(f)}} onBlur={(f)=>{blurFunc(f)}}>
|
||||
{p.includeBlankValue&&<option/>}
|
||||
{p.data.map((item)=><option value={item.id}>{item.id} - {item.name||item.username}</option>)}
|
||||
{p.data.map((item)=><option key={item.id} value={item.id}>{item.id} - {item.name||item.username}</option>)}
|
||||
</select>:<input disabled={p.lockSubmission} className={failed?"failedInput":sending?"submitting":""} value={value} onKeyDown={(f)=>{keydownFunc(f)}} onChange={(f)=>{changeFunc(f)}} onBlur={(f)=>{blurFunc(f)}}/>
|
||||
}
|
||||
|
||||
@ -101,6 +101,8 @@ function TableEditor(p) {
|
||||
|
||||
const initialVals={}
|
||||
|
||||
const { TESTMODE } = p
|
||||
|
||||
function updateVals(state,update) {
|
||||
if (update==='Clear') {
|
||||
return initialVals
|
||||
@ -116,7 +118,6 @@ function TableEditor(p) {
|
||||
const [loading,setLoading] = useState(false)
|
||||
const [dependencies,setDependencies] = useState([])
|
||||
const [importAllowed,setImportAllowed] = useState(false)
|
||||
const [fileData,setFileData] = useState(undefined)
|
||||
const [lockSubmission,setLockSubmission] = useState(false)
|
||||
|
||||
function patchValue(value,p,col,dat) {
|
||||
@ -144,25 +145,29 @@ function TableEditor(p) {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
function SubmitDeletion() {
|
||||
if (!lockSubmission) {
|
||||
setLockSubmission(true)
|
||||
var promises = []
|
||||
for (var dat of data) {
|
||||
if (document.getElementById("delete_"+dat.id).checked) {
|
||||
promises.push(axios.delete(p.BACKENDURL+p.path,{data:{pass:p.password,id:dat.id}}))
|
||||
}
|
||||
}
|
||||
Promise.allSettled(promises)
|
||||
.catch((err)=>{
|
||||
alert(err.message)
|
||||
})
|
||||
.then((data)=>{
|
||||
setLockSubmission(false)
|
||||
setUpdate(true)
|
||||
},[p.path])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
var promises=[]
|
||||
parse(fileData,{columns:true,skip_empty_lines:true}).forEach((entry)=>{
|
||||
for (var col of fields) {
|
||||
if ((col.dataTypeID===23||col.dataTypeID===701||col.dataTypeID===16)&&entry[col.name]==="") {
|
||||
entry[col.name]=0
|
||||
}
|
||||
}
|
||||
promises.push(axios.post(p.BACKENDURL+p.path,{...entry,pass:p.password}))
|
||||
})
|
||||
Promise.allSettled(promises)
|
||||
.then(()=>{
|
||||
setUpdate(true)
|
||||
})
|
||||
},[fileData,p.path,p.BACKENDURL,p.password])
|
||||
},[p.path,TESTMODE])
|
||||
|
||||
useEffect(()=>{
|
||||
for (var col of fields) {
|
||||
@ -207,24 +212,36 @@ function TableEditor(p) {
|
||||
{!loading?
|
||||
<div>
|
||||
<table>
|
||||
{importAllowed&&<caption><label className="buttonLabel" for="uploads">Import CSV</label><input onChange={(f)=>{
|
||||
{importAllowed&&<caption><label className="buttonLabel" htmlFor="uploads">Import CSV</label><input onChange={(f)=>{
|
||||
const reader = new FileReader()
|
||||
reader.onload=(ev)=>{
|
||||
setFileData(ev.target.result)
|
||||
var promises=[]
|
||||
parse(ev.target.result,{columns:true,skip_empty_lines:true}).forEach((entry)=>{
|
||||
for (var col of fields) {
|
||||
if ((col.dataTypeID===23||col.dataTypeID===701||col.dataTypeID===16)&&entry[col.name]==="") {
|
||||
entry[col.name]=0
|
||||
}
|
||||
}
|
||||
promises.push(axios.post(p.BACKENDURL+p.path,{...entry,pass:p.password}))
|
||||
})
|
||||
Promise.allSettled(promises)
|
||||
.then(()=>{
|
||||
setUpdate(true)
|
||||
})
|
||||
}
|
||||
reader.readAsText(f.target.files[0])
|
||||
}} style={{opacity:0}} id="uploads" type="file" accept=".txt,.csv"/></caption>}
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="table-padding"></th>
|
||||
<th className="table-padding"><TrashFill onClick={()=>{SubmitDeletion()}} className="trashButton"/></th>
|
||||
{fields.map((field,i)=><React.Fragment key={i}><th scope="col" className="table-padding">{field.name}</th></React.Fragment>)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{<tr><td></td>{fields.map((col,i)=><td key={i}>{<InputBox includeBlankValue={true} data={dependencies[col.name]} callback4={
|
||||
(f)=>{setSubmitVal({field:col.name,value:f});}}/>}</td>)}<input style={{display:"none"}}/><PlusCircle onClick={()=>{SubmitBoxes()}} className="submitbutton"/></tr>}
|
||||
(f)=>{setSubmitVal({field:col.name,value:f});}}/>}</td>)}<td><input style={{display:"none"}}/><PlusCircle onClick={()=>{SubmitBoxes()}} className="submitbutton"/></td></tr>}
|
||||
{data.map((dat)=><tr key={dat.id}>
|
||||
<td><XSquareFill className="webicon" onClick={()=>{axios.delete(p.BACKENDURL+p.path,{data:{id:dat.id,pass:p.password}}).then(()=>{setUpdate(true)}).catch((err)=>{alert(err.response.data)})}}/></td>{fields.map((col,i)=><td key={dat.id+"_"+i} className="table-padding table">
|
||||
<td><input id={"delete_"+dat.id} type="checkbox"/></td>{fields.map((col,i)=><td key={dat.id+"_"+i} className="table-padding table">
|
||||
<InputBox lockSubmission={lockSubmission} data={dependencies[col.name]} callback={(value)=>patchValue(value,p,col,dat)} callback2={(f,value)=>{if (f.key==='Enter') {f.currentTarget.blur()} else {return 'Chill'}}} value={String(dat[col.name])}/></td>)}</tr>)}
|
||||
</tbody>
|
||||
</table>
|
||||
@ -306,13 +323,13 @@ function DatabaseEditor(p) {
|
||||
<br/><br/>
|
||||
<span style={{fontSize:"24px",top:"-16px",position:"relative",height:"64px",lineHeight:"64px",textAlign:"center"}}><LifePreserver className="databaseIcon" style={{color:"green"}}/>Live Database</span>
|
||||
<span style={{fontSize:"24px",top:"-16px",position:"relative",height:"64px",lineHeight:"64px",textAlign:"center"}}><LifePreserver className="databaseIcon" style={{color:"red"}}/>Test Database</span><br/>
|
||||
{databases.map((db)=>{
|
||||
{databases.map((db,i)=>{
|
||||
var label = ""
|
||||
if (db.datname!=="ngsplanner"&&db.datname!=="ngsplanner2") {
|
||||
var dateStr = db.datname.replace("ngsplanner","")
|
||||
var date = new Date(dateStr.slice(0,4),dateStr.slice(4,6),dateStr.slice(6,8),dateStr.slice(8,10),dateStr.slice(10,12),dateStr.slice(12,14))
|
||||
label=<><Server className="databaseIcon" style={{color:"blue"}}/>{"Backup from "+date}</>
|
||||
return <><span style={{fontSize:"24px",top:"-16px",position:"relative",height:"64px",lineHeight:"64px",textAlign:"center"}}>{label}<button style={{background:"blue"}}
|
||||
return <React.Fragment key={i}><span style={{fontSize:"24px",top:"-16px",position:"relative",height:"64px",lineHeight:"64px",textAlign:"center"}}>{label}<button style={{background:"blue"}}
|
||||
onClick={()=>{
|
||||
setLoading(true)
|
||||
axios.post(p.BACKENDURL+"/databases/restorefrombackup",{
|
||||
@ -328,9 +345,9 @@ function DatabaseEditor(p) {
|
||||
.then(()=>{
|
||||
setLoading(false)
|
||||
})
|
||||
}}><CloudUploadFill/> Restore</button></span><br/></>
|
||||
}}><CloudUploadFill/> Restore</button></span><br/></React.Fragment>
|
||||
} else {
|
||||
return <></>
|
||||
return <React.Fragment key={i}/>
|
||||
}
|
||||
})}
|
||||
</>
|
||||
@ -413,10 +430,10 @@ function AdminPanel(p) {
|
||||
<div className="boxTitleBar">
|
||||
<h1>Navigation</h1>
|
||||
</div>
|
||||
<p>Testing Mode <Toggle checked={p.TESTMODE} onChange={(f)=>{p.setTESTMODE(f.target.checked)}}/> {p.TESTMODE?<b>ON</b>:<b>OFF</b>}</p>
|
||||
<span>Testing Mode <Toggle checked={p.TESTMODE} onChange={(f)=>{p.setTESTMODE(f.target.checked)}}/> {p.TESTMODE?<b>ON</b>:<b>OFF</b>}</span>
|
||||
<div className="adminNavContainer customScrollbar">
|
||||
<Table classes="adminNav">
|
||||
{navigationData.map((nav)=>(nav.hr)?<hr/>:<><Link to={process.env.PUBLIC_URL+nav.url}>{nav.page}</Link><br/></>)}
|
||||
{navigationData.map((nav,i)=>(nav.hr)?<hr key={i}/>:<React.Fragment key={i}><Link to={process.env.PUBLIC_URL+nav.url}>{nav.page}</Link><br/></React.Fragment>)}
|
||||
<Link to={process.env.PUBLIC_URL+"/admin/database_manager"}>Database Manager</Link><br/>
|
||||
</Table>
|
||||
</div>
|
||||
@ -425,7 +442,7 @@ function AdminPanel(p) {
|
||||
|
||||
|
||||
|
||||
{navigationData.map((nav)=>(nav.duplicate===undefined&&nav.hr===undefined)&&<Route path={process.env.PUBLIC_URL+nav.url}>
|
||||
{navigationData.map((nav,i)=>(nav.duplicate===undefined&&nav.hr===undefined)&&<Route key={i} path={process.env.PUBLIC_URL+nav.url}>
|
||||
<div className="box boxAdminContent">
|
||||
<div className="boxTitleBar">
|
||||
<h1>{nav.page}</h1></div>
|
||||
@ -433,7 +450,7 @@ function AdminPanel(p) {
|
||||
<Helmet>
|
||||
<title>{APP_TITLE+" - Admin Panel: "+nav.page}</title>
|
||||
</Helmet>
|
||||
{nav.render??<TableEditor password={password} BACKENDURL={GetBackendURL(p)} path={nav.table}/>}
|
||||
{nav.render??<TableEditor TESTMODE={p.TESTMODE} password={password} BACKENDURL={GetBackendURL(p)} path={nav.table}/>}
|
||||
</div></div></Route>)}
|
||||
|
||||
<Route path={process.env.PUBLIC_URL+"/admin/database_manager"}>
|
||||
@ -790,8 +807,6 @@ function App() {
|
||||
const [DATAID,setDATAID] = useState({GetData:()=>{}})
|
||||
const [update,setUpdate] = useState(false)
|
||||
|
||||
const [dataLoaded,setDataLoaded] = useState(false)
|
||||
|
||||
const [LOGGEDINUSER,setLOGGEDINUSER] = useState("")
|
||||
const [LOGGEDINHASH,setLOGGEDINHASH] = useState("")
|
||||
|
||||
|
@ -74,7 +74,7 @@ function EditableClass(p){
|
||||
|
||||
function PopupWindow(p) {
|
||||
|
||||
return <Modal isOpen={p.modalOpen} onRequestClose={()=>{p.setModalOpen(false)}} shouldFocusAfterRender={true} shouldCloseOnOverlayClick={true} shouldCloseOnEsc={true} className="modal" overlayClassName="modalOverlay">
|
||||
return <Modal ariaHideApp={false} isOpen={p.modalOpen} onRequestClose={()=>{p.setModalOpen(false)}} shouldFocusAfterRender={true} shouldCloseOnOverlayClick={true} shouldCloseOnEsc={true} className="modal" overlayClassName="modalOverlay">
|
||||
<div className="box boxModal">
|
||||
<div className="boxTitleBar">
|
||||
<h1>{p.title}</h1>
|
||||
@ -117,7 +117,7 @@ function SelectorWindow(p) {
|
||||
{(p.sortItems||p.filter)&&<div className="itemBar">
|
||||
<div className="itemBarSort">
|
||||
{p.sortItems&&<select className="itemBarForm" value={sortSelector} onChange={(f)=>{setSortSelector(f.currentTarget.value)}}>
|
||||
{p.sortItems.map((item)=><option value={item}>{item}</option>)}
|
||||
{p.sortItems.map((item)=><option key={item} value={item}>{item}</option>)}
|
||||
</select>}
|
||||
</div>
|
||||
<div className="itemBarFilter">
|
||||
@ -127,7 +127,7 @@ function SelectorWindow(p) {
|
||||
}
|
||||
<div className="modalItemListContainer customScrollbar">
|
||||
<ul className="itemlist">
|
||||
{p.filter?itemList.filter((item)=>p.filterFunction(tabPage,item)).filter((item)=>p.searchFieldFunction(filter,item)).sort((a,b)=>p.sortOrderFunction(sortSelector,a,b)).map((item)=>p.displayFunction(item)):itemList.map((item)=>p.displayFunction(item))}
|
||||
{p.filter?itemList.filter((item)=>p.filterFunction(tabPage,item)).filter((item)=>p.searchFieldFunction(filter,item)).sort((a,b)=>p.sortOrderFunction(sortSelector,a,b)).map((item,i)=><React.Fragment key={i}>{p.displayFunction(item)}</React.Fragment>):itemList.map((item,i)=><React.Fragment key={i}>{p.displayFunction(item)}</React.Fragment>)}
|
||||
{p.children}
|
||||
</ul>
|
||||
</div>
|
||||
@ -230,7 +230,7 @@ function SkillTreeBoxes(p) {
|
||||
return <>
|
||||
{p.skillTreeSkillData&&p.skillTreeSkillData.map((skill,i)=>{
|
||||
var splitter = skill.split(",")
|
||||
return splitter[0]!==""&&splitter[1]!==""&&splitter[2]!==""&&<SkillBox className={isLocked(splitter[2])?"skillLocked":p.skillPointData[p.page-1][i]===GetHighestLevel(splitter[2])?"skillMaxed":p.skillPointData[p.page-1][i]>0?"skillActive":""} boxId={i} skillPointData={p.skillPointData} setSkillPointData={p.setSkillPointData} page={p.page} cl={p.cl} maxPoints={GetHighestLevel(splitter[2])} points={p.points} setPoints={p.setPoints} GetData={p.GetData} skill={splitter.map((numb)=>Number(numb))}/>
|
||||
return splitter[0]!==""&&splitter[1]!==""&&splitter[2]!==""&&<SkillBox key={i} className={isLocked(splitter[2])?"skillLocked":p.skillPointData[p.page-1][i]===GetHighestLevel(splitter[2])?"skillMaxed":p.skillPointData[p.page-1][i]>0?"skillActive":""} boxId={i} skillPointData={p.skillPointData} setSkillPointData={p.setSkillPointData} page={p.page} cl={p.cl} maxPoints={GetHighestLevel(splitter[2])} points={p.points} setPoints={p.setPoints} GetData={p.GetData} skill={splitter.map((numb)=>Number(numb))}/>
|
||||
})}
|
||||
</>
|
||||
}
|
||||
@ -593,7 +593,7 @@ AUGMENT
|
||||
</div>
|
||||
|
||||
<ClassSelectorWindow class={className} subClass={subclassName} setClassName={setClassName} setEditClass={setClassNameSetter} editClass={classNameSetter} setSubClassName={setSubClassName} modalOpen={classSelectWindowOpen} setModalOpen={setClassSelectWindowOpen} GetData={p.GetData}/>
|
||||
<Modal isOpen={classSkillTreeWindowOpen} onRequestClose={() => { setClassSkillTreeWindowOpen(false) }} shouldFocusAfterRender={true} shouldCloseOnOverlayClick={true} shouldCloseOnEsc={true} className="modal" overlayClassName="modalOverlay">
|
||||
<Modal ariaHideApp={false} isOpen={classSkillTreeWindowOpen} onRequestClose={() => { setClassSkillTreeWindowOpen(false) }} shouldFocusAfterRender={true} shouldCloseOnOverlayClick={true} shouldCloseOnEsc={true} className="modal" overlayClassName="modalOverlay">
|
||||
<div className="box skillTreeBox">
|
||||
<div className="boxTitleBar">
|
||||
<h1>Class Skill Tree</h1>
|
||||
@ -647,7 +647,7 @@ AUGMENT
|
||||
}
|
||||
}}
|
||||
displayFunction={(item)=>{
|
||||
return <li className={"itemwep r"+item[WEAPON_WEAPON].rarity} onClick={()=>{setSelectedWeapon(item);setWeaponSelectWindowOpen(false)}}><div className="itemWeaponWrapper"><img className="itemimg" alt="" src={DisplayIcon(item[WEAPON_EXISTENCE_DATA]?.icon)} /><em className="rifle">{GetSpecialWeaponName(item)}</em></div><br /><span className="atk">{item[WEAPON_WEAPON].atk}</span> <ExpandTooltip id={"mouseover-tooltip"+item[WEAPON_WEAPONTYPE].id+"_"+item[WEAPON_WEAPON].id+"_"+item[WEAPON_POTENTIAL].id+"_"+item[WEAPON_POTENTIAL_TOOLTIP].id} tooltip={<>{item[WEAPON_POTENTIAL_TOOLTIP].map((pot,i)=><>{(i!==0)&&<br/>}{pot.name}: {pot.description?pot.description.split("\\n").map((it)=><>{it}<br/> </>):<></>}</>)}</>}>
|
||||
return <li className={"itemwep r"+item[WEAPON_WEAPON].rarity} onClick={()=>{setSelectedWeapon(item);setWeaponSelectWindowOpen(false)}}><div className="itemWeaponWrapper"><img className="itemimg" alt="" src={DisplayIcon(item[WEAPON_EXISTENCE_DATA]?.icon)} /><em className="rifle">{GetSpecialWeaponName(item)}</em></div><br /><span className="atk">{item[WEAPON_WEAPON].atk}</span> <ExpandTooltip id={"mouseover-tooltip"+item[WEAPON_WEAPONTYPE].id+"_"+item[WEAPON_WEAPON].id+"_"+item[WEAPON_POTENTIAL].id+"_"+item[WEAPON_POTENTIAL_TOOLTIP].id} tooltip={<>{item[WEAPON_POTENTIAL_TOOLTIP].map((pot,i)=><React.Fragment key={i}>{(i!==0)&&<br/>}{pot.name}: {pot.description?pot.description.split("\\n").map((it,ii)=><React.Fragment key={ii}>{it}<br/> </React.Fragment>):<React.Fragment key={i}/>}</React.Fragment>)}</>}>
|
||||
<span className="pot">{item[WEAPON_POTENTIAL].name}</span>
|
||||
</ExpandTooltip></li>}}
|
||||
/>
|
||||
|
@ -36,7 +36,7 @@ function SkillTree(p) {
|
||||
case "┬":context.beginPath();context.moveTo(x*p.gridSizeX+(padX)-p.gridPaddingX,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+(y%2===1?p.halflineheight:p.gridSizeY)/2);context.lineTo(x*p.gridSizeX+(padX)+p.gridSizeX/2,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+(y%2===1?p.halflineheight:p.gridSizeY)/2);context.lineTo(x*p.gridSizeX+(padX)+p.gridSizeX/2,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+p.gridSizeY+p.gridPaddingY);context.stroke();context.beginPath();context.moveTo(x*p.gridSizeX+(padX)+p.gridSizeX+p.gridPaddingX,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+(y%2===1?p.halflineheight:p.gridSizeY)/2);context.lineTo(x*p.gridSizeX+(padX)+p.gridSizeX/2,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+(y%2===1?p.halflineheight:p.gridSizeY)/2);context.lineTo(x*p.gridSizeX+(padX)+p.gridSizeX/2,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+p.gridSizeY+p.gridPaddingY);context.stroke();break;
|
||||
case "┴":context.beginPath();context.moveTo(x*p.gridSizeX+(padX)+p.gridSizeX/2,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)-p.gridPaddingY);context.lineTo(x*p.gridSizeX+(padX)+p.gridSizeX/2,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+(y%2===1?p.halflineheight:p.gridSizeY)/2);context.lineTo(x*p.gridSizeX+(padX)+p.gridSizeX+p.gridPaddingX,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+(y%2===1?p.halflineheight:p.gridSizeY)/2);context.stroke();context.beginPath();context.moveTo(x*p.gridSizeX+(padX)+p.gridSizeX/2,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)-p.gridPaddingY);context.lineTo(x*p.gridSizeX+(padX)+p.gridSizeX/2,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+(y%2===1?p.halflineheight:p.gridSizeY)/2);context.lineTo(x*p.gridSizeX+(padX)-p.gridPaddingX,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+(y%2===1?p.halflineheight:p.gridSizeY)/2);context.stroke();break;
|
||||
case "┼":context.beginPath();context.moveTo(x*p.gridSizeX+(padX)+p.gridSizeX/2,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)-p.gridPaddingY);context.lineTo(x*p.gridSizeX+(padX)+p.gridSizeX/2,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+p.gridSizeY+p.gridPaddingY);context.moveTo(x*p.gridSizeX+(padX)-p.gridPaddingX,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+(y%2===1?p.halflineheight:p.gridSizeY)/2);context.lineTo(x*p.gridSizeX+(padX)+p.gridSizeX+p.gridPaddingX,Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY)+(y%2===1?p.halflineheight:p.gridSizeY)/2);context.stroke();break;
|
||||
case "□":context.fillRect(x*p.gridSizeX+(padX), Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY), p.gridSizeX, y%2===1?p.halflineheight:p.gridSizeY);break;
|
||||
case "□":context.clearRect(x*p.gridSizeX+(padX), Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY), p.gridSizeX, y%2===1?p.halflineheight:p.gridSizeY);context.fillRect(x*p.gridSizeX+(padX), Math.ceil(y/2)*p.gridSizeY+Math.ceil((y-1)/2)*p.halflineheight+(padY), p.gridSizeX, y%2===1?p.halflineheight:p.gridSizeY);break;
|
||||
default:
|
||||
}
|
||||
x++
|
||||
@ -47,7 +47,7 @@ function SkillTree(p) {
|
||||
|
||||
return <canvas
|
||||
width={width}
|
||||
height={height} ref={canvasRef} {...p}>{p.children}</canvas>
|
||||
height={height} ref={canvasRef} style={p.style} className={p.className}>{p.children}</canvas>
|
||||
}
|
||||
|
||||
export {SkillTree}
|
@ -1,5 +1,5 @@
|
||||
import { SkillTree } from "./skillTree";
|
||||
import { useEffect,useState,useMemo,useCallback } from "react";
|
||||
import React, { useEffect,useState,useMemo,useCallback } from "react";
|
||||
import { SkillTreeSelector } from "./skillTreeSelector";
|
||||
import axios from "axios";
|
||||
|
||||
@ -174,9 +174,9 @@ function SkillTreeEditor(p) {
|
||||
return <>
|
||||
{loading?<img src={process.env.PUBLIC_URL+"/spinner.gif"} alt=""/>:<>
|
||||
<h2>{message}</h2>
|
||||
<label for="classSelect">Class Select:</label><select id="classSelect" value={cl} onChange={(f)=>{setCl(Number(f.currentTarget.value))}}>
|
||||
<label htmlFor="classSelect">Class Select:</label><select id="classSelect" value={Number.isNaN(Number(cl))?"?":cl} onChange={(f)=>{setCl(Number(f.currentTarget.value))}}>
|
||||
<option value=""></option>
|
||||
{Object.keys(classList).map((c)=><option value={c}>{c+" - "+classList[c].name}</option>)}
|
||||
{Object.keys(classList).map((c)=><option key={classList[c].name} value={c}>{c+" - "+classList[c].name}</option>)}
|
||||
</select>
|
||||
<br/>
|
||||
<br/>
|
||||
@ -189,19 +189,19 @@ function SkillTreeEditor(p) {
|
||||
gridDimensionsX={dimensionX} gridDimensionsY={dimensionY} gridSizeX={gridSizeX} gridSizeY={gridSizeY} gridPaddingX={gridPaddingX} gridPaddingY={gridPaddingY}
|
||||
skillLines={skillLines} halflineheight={halflineheight}
|
||||
/>
|
||||
{renderedInputs.map((control)=>control)}
|
||||
{renderedInputs.map((control,i)=><React.Fragment key={i}>{control}</React.Fragment>)}
|
||||
<br/>
|
||||
<hr/>
|
||||
<br/>
|
||||
<label for="lineColor">Line Color:</label><input type="color" id="lineColor" value={lineColor} onChange={(f)=>{setLineColor(f.currentTarget.value)}}/><br/>
|
||||
<label for="lineWidth">Line Width:</label><input type="number" id="lineWidth" value={lineWidth} onChange={(f)=>{setLineWidth(f.currentTarget.value)}}/><br/>
|
||||
<label for="gridSizeX">Grid Size X:</label><input type="number" id="gridSizeX" value={dimensionX} onChange={(f)=>{setDimensionX(f.currentTarget.value)}}/><br/>
|
||||
<label for="gridSizeY">Grid Size Y:</label><input type="number" id="gridSizeY" value={dimensionY} onChange={(f)=>{setDimensionY(f.currentTarget.value)}}/><br/>
|
||||
<label for="subrowHeight">Sub-row Height:</label><input type="number" id="subrowHeight" value={halflineheight} onChange={(f)=>{setHalfLineHeight(f.currentTarget.value)}}/><br/>
|
||||
<label for="boxSizeX">Box Size X:</label><input type="number" id="boxSizeX" value={gridSizeX} onChange={(f)=>{setGridSizeX(f.currentTarget.value)}}/><br/>
|
||||
<label for="boxSizeY">Box Size Y:</label><input type="number" id="boxSizeY" value={gridSizeY} onChange={(f)=>{setGridSizeY(f.currentTarget.value)}}/><br/>
|
||||
<label for="gridPaddingX">Grid Padding X:</label><input type="number" id="gridPaddingX" value={gridPaddingX} onChange={(f)=>{setGridPaddingX(f.currentTarget.value)}}/><br/>
|
||||
<label for="gridPaddingY">Grid Padding Y:</label><input type="number" id="gridPaddingY" value={gridPaddingY} onChange={(f)=>{setGridPaddingY(f.currentTarget.value)}}/><br/>
|
||||
<label htmlFor="lineColor">Line Color:</label><input type="color" id="lineColor" value={lineColor} onChange={(f)=>{setLineColor(f.currentTarget.value)}}/><br/>
|
||||
<label htmlFor="lineWidth">Line Width:</label><input type="number" id="lineWidth" value={lineWidth} onChange={(f)=>{setLineWidth(f.currentTarget.value)}}/><br/>
|
||||
<label htmlFor="gridSizeX">Grid Size X:</label><input type="number" id="gridSizeX" value={dimensionX} onChange={(f)=>{setDimensionX(f.currentTarget.value)}}/><br/>
|
||||
<label htmlFor="gridSizeY">Grid Size Y:</label><input type="number" id="gridSizeY" value={dimensionY} onChange={(f)=>{setDimensionY(f.currentTarget.value)}}/><br/>
|
||||
<label htmlFor="subrowHeight">Sub-row Height:</label><input type="number" id="subrowHeight" value={halflineheight} onChange={(f)=>{setHalfLineHeight(f.currentTarget.value)}}/><br/>
|
||||
<label htmlFor="boxSizeX">Box Size X:</label><input type="number" id="boxSizeX" value={gridSizeX} onChange={(f)=>{setGridSizeX(f.currentTarget.value)}}/><br/>
|
||||
<label htmlFor="boxSizeY">Box Size Y:</label><input type="number" id="boxSizeY" value={gridSizeY} onChange={(f)=>{setGridSizeY(f.currentTarget.value)}}/><br/>
|
||||
<label htmlFor="gridPaddingX">Grid Padding X:</label><input type="number" id="gridPaddingX" value={gridPaddingX} onChange={(f)=>{setGridPaddingX(f.currentTarget.value)}}/><br/>
|
||||
<label htmlFor="gridPaddingY">Grid Padding Y:</label><input type="number" id="gridPaddingY" value={gridPaddingY} onChange={(f)=>{setGridPaddingY(f.currentTarget.value)}}/><br/>
|
||||
|
||||
</div></>}
|
||||
</>
|
||||
|
@ -13,11 +13,11 @@ function SkillTreeSelector(p) {
|
||||
return <>
|
||||
<select onChange={(f)=>{p.callback(f.currentTarget.value,Number(p.x),Number(p.y))}} style={{position:"absolute",left:p.ADJUSTMENT[0]+(p.x*p.gridSizeX+p.padX+p.gridSizeX/2),top:p.ADJUSTMENT[1]+((p.y/2)*p.gridSizeY+(p.y/2-1)*p.halflineheight+p.padY+(p.y===0?p.halflineheight:p.gridSizeY)/2)}} value={p.defaultValue}>
|
||||
{[' ','─','│','□','┌','└','┐','┘','┬','┴','├','┤','┼'].map((ch)=>
|
||||
<option value={ch}>{ch}</option>)
|
||||
<option value={ch} key={ch}>{ch}</option>)
|
||||
}
|
||||
</select>
|
||||
{p.defaultValue==='□'&&<select style={{width:"64px",position:"absolute",left:p.ADJUSTMENT[0]+(p.x*p.gridSizeX+p.padX+p.gridSizeX/2),top:p.ADJUSTMENT[1]+((p.y/2)*p.gridSizeY+(p.y/2-1)*p.halflineheight+p.padY+(p.y===0?p.halflineheight:p.gridSizeY)/2)+28}} onChange={(f)=>{p.skillCallback(p.x,p.y,f.currentTarget.value)}} value={p.skill.split(",")[2]}>
|
||||
{["",...Object.keys((skillList)).filter((skill)=>skillList[skill].class_id===p.cl)].map((skill)=><option value={(skillList[skill])?skillList[skill].id:""}>{(skillList[skill])?skillList[skill].name:""}</option>)}
|
||||
{["",...Object.keys((skillList)).filter((skill)=>skillList[skill].class_id===p.cl)].map((skill)=><option key={skill} value={(skillList[skill])?skillList[skill].id:""}>{(skillList[skill])?skillList[skill].name:""}</option>)}
|
||||
</select>}
|
||||
</>
|
||||
|
||||
|
@ -1408,3 +1408,12 @@ dd:before {
|
||||
font-family: "Segoe UI Symbol";
|
||||
content: "\2B1B" !important;
|
||||
}
|
||||
.trashButton{
|
||||
color:rgba(100,50,50,1);
|
||||
width:24px;
|
||||
height:24px;
|
||||
}
|
||||
.trashButton:hover {
|
||||
color:rgba(200,50,50,1);
|
||||
border: 2px solid red;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user