a much better layout, and general concept for the dev tool
This commit is contained in:
@@ -1,18 +1,156 @@
|
||||
'use client'
|
||||
import React from "react";
|
||||
import React, { SyntheticEvent } from "react";
|
||||
import styles from "@/styles/dev-tools.module.css"
|
||||
import { Container, Select, Stack } from "@mui/material"
|
||||
import { Container, Select, Stack, Chip, MenuItem, InputLabel, Snackbar, IconButton, SnackbarCloseReason, Typography } from "@mui/material"
|
||||
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import Draggable from 'react-draggable';
|
||||
|
||||
type EditorMode = "insert" | "update";
|
||||
|
||||
interface DBObject {
|
||||
record_num: number
|
||||
data_id: string;
|
||||
change_timestamp: string;
|
||||
}
|
||||
|
||||
interface Unit extends DBObject {
|
||||
|
||||
}
|
||||
|
||||
interface Card extends DBObject {
|
||||
|
||||
}
|
||||
|
||||
interface EditorContextType {
|
||||
editorMode: "insert" | "update";
|
||||
currentRecordNum: number | null;
|
||||
currentDataId: string | null;
|
||||
cards: Card[] | null;
|
||||
units: Unit[] | null;
|
||||
error: string | null,
|
||||
|
||||
changeEditorMode?: (m: string) => void;
|
||||
changeCurrentRecordNum?: (n: number) => void;
|
||||
changeCurrentDataId?: (n: string) => void;
|
||||
changeError?: (e: string) => void;
|
||||
}
|
||||
const EditorContext = React.createContext<EditorContextType>({
|
||||
currentRecordNum: null,
|
||||
currentDataId: null,
|
||||
editorMode: "insert",
|
||||
cards: null,
|
||||
units: null,
|
||||
error: null,
|
||||
})
|
||||
|
||||
function useEditor() {
|
||||
const ctx = React.useContext(EditorContext);
|
||||
if(!ctx){
|
||||
throw new Error("Error: use Editor must be used within an EditorContext")
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
const unitTypes: string[] = ["minion", "enemy", "hero", "ally"];
|
||||
const buildingTypes: string[] = ["enemy", "minion", "terrain", "support"];
|
||||
|
||||
export default function Page(){
|
||||
const [currentRecordNum, setCurrentRecordNum] = React.useState<number>(0);
|
||||
const [currentDataId, setCurrentDataId] = React.useState<string>("");
|
||||
const [editorMode, setEditorMode] = React.useState<EditorMode>("insert");
|
||||
const [cards, setCards] = React.useState<Card[] | null>(null);
|
||||
const [units, setUnits] = React.useState<Unit[] | null>(null);
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
const [open, setOpen] = React.useState<boolean>(false);
|
||||
|
||||
const changeCurrentRecordNum = (n: number) => setCurrentRecordNum(n)
|
||||
const changeCurrentDataId = (id: string) => setCurrentDataId(id)
|
||||
const changeEditorMode = (m: string) =>{
|
||||
if(m !== "insert" && m !== "update") return
|
||||
setEditorMode(m)
|
||||
}
|
||||
const changeError = (e: string) => setError(e);
|
||||
// get all of the cards, or units
|
||||
React.useEffect(() => {
|
||||
const getCards = async () => {
|
||||
try{
|
||||
// fetch our db
|
||||
}catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const getUnits = async () => {
|
||||
try{
|
||||
|
||||
}catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
getCards();
|
||||
getUnits();
|
||||
}, [])
|
||||
|
||||
const handleClose = (
|
||||
event: React.SyntheticEvent | Event,
|
||||
reason?: SnackbarCloseReason,
|
||||
) => {
|
||||
if (reason === 'clickaway') {
|
||||
return;
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const action = (
|
||||
<React.Fragment>
|
||||
<Typography>
|
||||
{error}
|
||||
</Typography>
|
||||
<IconButton
|
||||
size="small"
|
||||
aria-label="close"
|
||||
color="inherit"
|
||||
onClick={handleClose}
|
||||
>
|
||||
<CloseIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles.maincontainer}>
|
||||
<div className={styles.leftmenucontainer}>
|
||||
<LeftMenu />
|
||||
<EditorContext.Provider value={{
|
||||
currentRecordNum,
|
||||
currentDataId,
|
||||
editorMode,
|
||||
error,
|
||||
cards,
|
||||
units,
|
||||
|
||||
changeCurrentRecordNum,
|
||||
changeCurrentDataId,
|
||||
changeEditorMode,
|
||||
changeError
|
||||
}}>
|
||||
<div className={styles.maincontainer}>
|
||||
<div className={styles.leftmenucontainer}>
|
||||
<LeftMenu />
|
||||
</div>
|
||||
<div className={styles.editorcontainer}>
|
||||
<Editor />
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.editorcontainer}>
|
||||
<Editor />
|
||||
</div>
|
||||
</div>
|
||||
{error && <Snackbar
|
||||
open={open}
|
||||
autoHideDuration={6000}
|
||||
onClose={handleClose}
|
||||
action={action}
|
||||
/>}
|
||||
</EditorContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,42 +163,199 @@ function DynamicCard() {
|
||||
}
|
||||
|
||||
|
||||
interface Theme{
|
||||
interface ThemeSelection {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
|
||||
const debugCard = [
|
||||
{
|
||||
id: "terrain_forest",
|
||||
label: "Forest",
|
||||
children: [
|
||||
{
|
||||
id: "terrain_haunted_forest",
|
||||
label: "Haunted Forest",
|
||||
children: [
|
||||
{
|
||||
id: 'terrain_undead_candy_forest',
|
||||
label: "Undead Candy Forest"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "support_blacksmith",
|
||||
label: "Forest",
|
||||
children: [
|
||||
{
|
||||
id: "support_terrain_haunted_forest",
|
||||
label: "Haunted Forest",
|
||||
children: [
|
||||
{
|
||||
id: 'SUppror_terrain_undead_candy_forest',
|
||||
label: "Undead Candy Forest"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "enemy_graveyard",
|
||||
label: "Forest",
|
||||
children: [
|
||||
{
|
||||
id: "enemy_terrain_haunted_forest",
|
||||
label: "Haunted Forest",
|
||||
children: [
|
||||
{
|
||||
id: 'enemy_terrain_undead_candy_forest',
|
||||
label: "Undead Candy Forest"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
function LeftMenu(){
|
||||
const unitTypes: string[] = ["minion", "enemy", "hero", "ally"];
|
||||
const buildingTypes: string[] = ["enemy", "minion", "terrain", "support"];
|
||||
const [themes, setThemes] = React.useState<Theme[]>([]); // get from the database
|
||||
|
||||
const [themes, setThemes] = React.useState<ThemeSelection[]>([]); // get from the database
|
||||
const [menuMode, setMenuMode] = React.useState<"unit" | "card">("card");
|
||||
|
||||
const { currentRecordNum, } = useEditor();
|
||||
|
||||
const handleSelectAsset = (e: React.MouseEvent<Element, MouseEvent>) => {
|
||||
console.log("Got e:", e)
|
||||
}
|
||||
return (
|
||||
<Container className={styles.leftmenu}>
|
||||
<Stack>
|
||||
Type
|
||||
<Select>
|
||||
<option value="">
|
||||
All types
|
||||
</option>
|
||||
<Stack >
|
||||
<Typography id="assetTypeFilter">Asset Type</Typography>
|
||||
<Select className="assetTypeFilter">
|
||||
<MenuItem value="">All</MenuItem>
|
||||
{menuMode === "card" ?
|
||||
buildingTypes.map((opt) => (<option value={opt}>{opt[0].toUpperCase() + opt.slice(1)}</option>)) :
|
||||
unitTypes.map((opt) => (<option value={opt}>{opt[0].toUpperCase() + opt.slice(1)}</option>))
|
||||
buildingTypes.map((opt, i) => (<MenuItem value={opt} key={i}>{opt[0].toUpperCase() + opt.slice(1)}</MenuItem>)) :
|
||||
unitTypes.map((opt, i) => (<MenuItem value={opt} key={i}>{opt[0].toUpperCase() + opt.slice(1)}</MenuItem>))
|
||||
}
|
||||
</Select>
|
||||
|
||||
Theme
|
||||
<Select>
|
||||
<InputLabel id="themeFilter">Theme</InputLabel>
|
||||
<Select className="themeFilter" label="Theme" >
|
||||
<MenuItem value="">All</MenuItem>
|
||||
</Select>
|
||||
|
||||
</Stack>
|
||||
<Typography >
|
||||
Current {menuMode}s created
|
||||
</Typography>
|
||||
<RichTreeView items={debugCard} onItemClick={handleSelectAsset}>
|
||||
</RichTreeView>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function Editor(){
|
||||
const { editorMode } = useEditor();
|
||||
|
||||
const canvasWrapperRef = React.useRef<HTMLDivElement | null>(null);
|
||||
const canvasRef = React.useRef<HTMLCanvasElement | null>(null);
|
||||
|
||||
const onMouseUp = (e: React.MouseEvent) => {
|
||||
|
||||
console.log("event for mouse up", e)
|
||||
}
|
||||
|
||||
const onMouseDown = (e: React.MouseEvent) => {
|
||||
|
||||
console.log("event for mouse down", e)
|
||||
}
|
||||
|
||||
const onDragOver = (e: React.DragEvent) => {
|
||||
e.preventDefault()
|
||||
//console.log("event for drag over:", e)
|
||||
}
|
||||
|
||||
const onDrop = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
const raw = e.dataTransfer.getData("text/plain");
|
||||
console.log("DROP canvas raw:", raw);
|
||||
// create a box?
|
||||
}
|
||||
|
||||
return (
|
||||
<Container className={styles.editor} maxWidth={false} disableGutters>
|
||||
yes
|
||||
|
||||
{editorMode === "insert" ? <CreateNewAsset type="building"/> : null}
|
||||
<div
|
||||
ref={canvasWrapperRef}
|
||||
onDragOver={(e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = "copy";
|
||||
}}
|
||||
onDrop={(e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
const raw = e.dataTransfer.getData("text/plain");
|
||||
console.log("DROP wrapper raw:", raw);
|
||||
}}
|
||||
style={{ height: "100%", width: "100%", position: "relative" }}
|
||||
>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
onDragOver={onDragOver}
|
||||
onDrop={onDrop}
|
||||
style={{ height: "100%", width: "100%" }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
function CreateNewAsset({ type }: { type: string }) {
|
||||
return (
|
||||
<div style={{ backgroundColor: "#F1E9DB", borderRadius: 20, height: 40, display: "flex", alignItems: "center", justifyContent: "center", columnGap: 20 }}>
|
||||
{type === "building"
|
||||
? buildingTypes.map((buildingType, i) => {
|
||||
const label = buildingType[0].toUpperCase() + buildingType.slice(1);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
draggable
|
||||
onDragStart={(e) => {
|
||||
console.log("DRAG START", buildingType);
|
||||
const payload = { kind: "building", type: buildingType, label, w: 160, h: 90 };
|
||||
e.dataTransfer.setData("text/plain", JSON.stringify(payload));
|
||||
e.dataTransfer.effectAllowed = "copy";
|
||||
}}
|
||||
style={{ display: "inline-flex" }}
|
||||
>
|
||||
<Chip sx={{ backgroundColor: "#5DB7DE" }} label={label} />
|
||||
</div>
|
||||
);
|
||||
})
|
||||
: unitTypes.map((unitType, i) => {
|
||||
const label = unitType[0].toUpperCase() + unitType.slice(1);
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
draggable
|
||||
onDragStart={(e) => {
|
||||
const payload = { kind: "unit", type: unitType, label, w: 140, h: 80 };
|
||||
e.dataTransfer.setData("text/plain", JSON.stringify(payload));
|
||||
e.dataTransfer.effectAllowed = "copy";
|
||||
}}
|
||||
style={{ display: "inline-flex" }}
|
||||
>
|
||||
<Chip sx={{ backgroundColor: "#5DB7DE" }} label={label} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user