Working Eventbar
This commit is contained in:
parent
787a85e425
commit
9895a286a3
10 changed files with 403 additions and 77 deletions
|
@ -1,35 +1,225 @@
|
||||||
import { Items, Target } from "../../interfaces/frontend"
|
import { EventBarModes, Target } from "../../interfaces/frontend"
|
||||||
import Item from "./Item"
|
import Item from "./Item"
|
||||||
import React, { Dispatch, SetStateAction } from "react"
|
import { GameSettings } from "@components/Lobby/SettingsFrame/Setting"
|
||||||
|
import {
|
||||||
|
faArrowRightFromBracket,
|
||||||
|
faBroomWide,
|
||||||
|
faComments,
|
||||||
|
faEye,
|
||||||
|
faEyeSlash,
|
||||||
|
faGlasses,
|
||||||
|
faPalette,
|
||||||
|
faReply,
|
||||||
|
faScribble,
|
||||||
|
faSparkles,
|
||||||
|
faSwords,
|
||||||
|
} from "@fortawesome/pro-solid-svg-icons"
|
||||||
|
import { useDrawProps } from "@hooks/useDrawProps"
|
||||||
|
import { useGameProps } from "@hooks/useGameProps"
|
||||||
|
import { socket } from "@lib/socket"
|
||||||
|
import {
|
||||||
|
Dispatch,
|
||||||
|
SetStateAction,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
} from "react"
|
||||||
|
|
||||||
function EventBar({
|
function EventBar({
|
||||||
props: { setMode, setTarget },
|
props: { setMode, setTarget, clear },
|
||||||
}: {
|
}: {
|
||||||
props: {
|
props: {
|
||||||
setMode: Dispatch<SetStateAction<number>>
|
setMode: Dispatch<SetStateAction<number>>
|
||||||
setTarget: Dispatch<SetStateAction<Target>>
|
setTarget: Dispatch<SetStateAction<Target>>
|
||||||
|
clear: () => void
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
const items: Items[] = [
|
const [menu, setMenu] = useState<keyof EventBarModes>("main")
|
||||||
{ icon: "burger-menu", text: "Menu" },
|
const { shouldHide, color } = useDrawProps()
|
||||||
{ icon: "radar", text: "Radar scan", mode: 0, amount: 1 },
|
const { payload, setSetting, full } = useGameProps()
|
||||||
{ icon: "torpedo", text: "Fire torpedo", mode: 1, amount: 1 },
|
|
||||||
{ icon: "scope", text: "Fire missile", mode: 3 },
|
const gameSetting = useCallback(
|
||||||
{ icon: "gear", text: "Settings" },
|
(payload: GameSettings) => {
|
||||||
]
|
const hash = setSetting(payload)
|
||||||
|
socket.emit("gameSetting", payload, (newHash) => {
|
||||||
|
if (newHash === hash) return
|
||||||
|
console.log("hash", hash, newHash)
|
||||||
|
socket.emit("update", full)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[full, setSetting]
|
||||||
|
)
|
||||||
|
const items = useMemo<EventBarModes>(
|
||||||
|
() => ({
|
||||||
|
main: [
|
||||||
|
{
|
||||||
|
icon: "burger-menu",
|
||||||
|
text: "Menu",
|
||||||
|
callback: () => {
|
||||||
|
setMenu("menu")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: faSwords,
|
||||||
|
text: "Attack",
|
||||||
|
callback: () => {
|
||||||
|
setMenu("attack")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "pen",
|
||||||
|
text: "Draw",
|
||||||
|
callback: () => {
|
||||||
|
setMenu("draw")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "gear",
|
||||||
|
text: "Settings",
|
||||||
|
callback: () => {
|
||||||
|
setMenu("settings")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
menu: [
|
||||||
|
{
|
||||||
|
icon: faReply,
|
||||||
|
text: "Return",
|
||||||
|
iconColor: "#555",
|
||||||
|
callback: () => {
|
||||||
|
setMenu("main")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: faArrowRightFromBracket,
|
||||||
|
text: "Leave",
|
||||||
|
iconColor: "darkred",
|
||||||
|
callback: () => {
|
||||||
|
// router.push()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
attack: [
|
||||||
|
{
|
||||||
|
icon: faReply,
|
||||||
|
text: "Return",
|
||||||
|
iconColor: "#555",
|
||||||
|
callback: () => {
|
||||||
|
setMenu("main")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "radar",
|
||||||
|
text: "Radar scan",
|
||||||
|
amount: 1,
|
||||||
|
callback: () => {
|
||||||
|
setMode(0)
|
||||||
|
setTarget((e) => ({ ...e, show: false }))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "torpedo",
|
||||||
|
text: "Fire torpedo",
|
||||||
|
amount: 1,
|
||||||
|
callback: () => {
|
||||||
|
setMode(1)
|
||||||
|
setTarget((e) => ({ ...e, show: false }))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "scope",
|
||||||
|
text: "Fire missile",
|
||||||
|
callback: () => {
|
||||||
|
setMode(3)
|
||||||
|
setTarget((e) => ({ ...e, show: false }))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
draw: [
|
||||||
|
{
|
||||||
|
icon: faReply,
|
||||||
|
text: "Return",
|
||||||
|
iconColor: "#555",
|
||||||
|
callback: () => {
|
||||||
|
setMenu("main")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ icon: faBroomWide, text: "Clear", callback: clear },
|
||||||
|
{ icon: faPalette, text: "Color", iconColor: color },
|
||||||
|
{
|
||||||
|
icon: shouldHide ? faEye : faEyeSlash,
|
||||||
|
text: shouldHide ? "Show" : "Hide",
|
||||||
|
callback: () => {
|
||||||
|
useDrawProps.setState({ shouldHide: !shouldHide })
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
settings: [
|
||||||
|
{
|
||||||
|
icon: faReply,
|
||||||
|
text: "Return",
|
||||||
|
iconColor: "#555",
|
||||||
|
callback: () => {
|
||||||
|
setMenu("main")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: faGlasses,
|
||||||
|
text: "Spectators",
|
||||||
|
disabled: !payload?.game?.allowSpectators,
|
||||||
|
callback: () => {
|
||||||
|
gameSetting({ allowSpectators: !payload?.game?.allowSpectators })
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: faSparkles,
|
||||||
|
text: "Specials",
|
||||||
|
disabled: !payload?.game?.allowSpecials,
|
||||||
|
callback: () => {
|
||||||
|
gameSetting({ allowSpecials: !payload?.game?.allowSpecials })
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: faComments,
|
||||||
|
text: "Chat",
|
||||||
|
disabled: !payload?.game?.allowChat,
|
||||||
|
callback: () => {
|
||||||
|
gameSetting({ allowChat: !payload?.game?.allowChat })
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: faScribble,
|
||||||
|
text: "Mark/Draw",
|
||||||
|
disabled: !payload?.game?.allowMarkDraw,
|
||||||
|
callback: () => {
|
||||||
|
gameSetting({ allowMarkDraw: !payload?.game?.allowMarkDraw })
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
[
|
||||||
|
clear,
|
||||||
|
color,
|
||||||
|
gameSetting,
|
||||||
|
payload?.game?.allowChat,
|
||||||
|
payload?.game?.allowMarkDraw,
|
||||||
|
payload?.game?.allowSpecials,
|
||||||
|
payload?.game?.allowSpectators,
|
||||||
|
setMode,
|
||||||
|
setTarget,
|
||||||
|
shouldHide,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
useDrawProps.setState({ enable: menu === "draw" })
|
||||||
|
}, [menu])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="event-bar">
|
<div className="event-bar">
|
||||||
{items.map((e, i) => (
|
{items[menu].map((e, i) => (
|
||||||
<Item
|
<Item key={i} props={e} />
|
||||||
key={i}
|
|
||||||
props={{
|
|
||||||
...e,
|
|
||||||
callback: () => {
|
|
||||||
if (e.mode !== undefined) setMode(e.mode)
|
|
||||||
setTarget((e) => ({ ...e, show: false }))
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Draw, Hit, MouseCursor, Target } from "../../interfaces/frontend"
|
import { Hit, MouseCursor, Target } from "../../interfaces/frontend"
|
||||||
// import Bluetooth from "./Bluetooth"
|
// import Bluetooth from "./Bluetooth"
|
||||||
// import FogImages from "./FogImages"
|
// import FogImages from "./FogImages"
|
||||||
import Labeling from "./Labeling"
|
import Labeling from "./Labeling"
|
||||||
|
@ -8,6 +8,7 @@ import EventBar from "@components/Gamefield/EventBar"
|
||||||
import HitElems from "@components/Gamefield/HitElems"
|
import HitElems from "@components/Gamefield/HitElems"
|
||||||
import Targets from "@components/Gamefield/Targets"
|
import Targets from "@components/Gamefield/Targets"
|
||||||
import { useDraw } from "@hooks/useDraw"
|
import { useDraw } from "@hooks/useDraw"
|
||||||
|
import { useDrawProps } from "@hooks/useDrawProps"
|
||||||
import {
|
import {
|
||||||
hitReducer,
|
hitReducer,
|
||||||
initlialTarget,
|
initlialTarget,
|
||||||
|
@ -69,28 +70,8 @@ function Gamefield() {
|
||||||
}
|
}
|
||||||
}, [mode, mouseCursor, target])
|
}, [mode, mouseCursor, target])
|
||||||
|
|
||||||
const [color, setColor] = useState<string>("#f00")
|
const { canvasRef, onMouseDown, clear } = useDraw()
|
||||||
const [disable, setDisable] = useState(false)
|
const { enable, color, shouldHide } = useDrawProps()
|
||||||
const { canvasRef, onMouseDown, clear } = useDraw(drawLine)
|
|
||||||
|
|
||||||
function drawLine({ prevPoint, currentPoint, ctx }: Draw) {
|
|
||||||
const { x: currX, y: currY } = currentPoint
|
|
||||||
const lineColor = color
|
|
||||||
const lineWidth = 5
|
|
||||||
|
|
||||||
let startPoint = prevPoint ?? currentPoint
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.lineWidth = lineWidth
|
|
||||||
ctx.strokeStyle = lineColor
|
|
||||||
ctx.moveTo(startPoint.x, startPoint.y)
|
|
||||||
ctx.lineTo(currX, currY)
|
|
||||||
ctx.stroke()
|
|
||||||
|
|
||||||
ctx.fillStyle = lineColor
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(startPoint.x, startPoint.y, 2, 0, 2 * Math.PI)
|
|
||||||
ctx.fill()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="gamefield">
|
<div id="gamefield">
|
||||||
|
@ -117,10 +98,13 @@ function Gamefield() {
|
||||||
|
|
||||||
<Targets props={{ target, targetPreview, mode, hits }} />
|
<Targets props={{ target, targetPreview, mode, hits }} />
|
||||||
{/* <span id='dev-debug' style={{gridArea: '1 / 12 / 1 / 15', backgroundColor: 'red', zIndex: 3} as CSSProperties}>Debug</span> */}
|
{/* <span id='dev-debug' style={{gridArea: '1 / 12 / 1 / 15', backgroundColor: 'red', zIndex: 3} as CSSProperties}>Debug</span> */}
|
||||||
|
|
||||||
<canvas
|
<canvas
|
||||||
style={
|
style={
|
||||||
{
|
{
|
||||||
pointerEvents: !disable ? "auto" : "none",
|
opacity: shouldHide ? 0 : 1,
|
||||||
|
boxShadow: enable ? "inset 0 0 0 2px " + color : "none",
|
||||||
|
pointerEvents: enable && !shouldHide ? "auto" : "none",
|
||||||
} as CSSProperties
|
} as CSSProperties
|
||||||
}
|
}
|
||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
|
@ -129,9 +113,7 @@ function Gamefield() {
|
||||||
height="648"
|
height="648"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button onClick={() => setDisable((e) => !e)}>toggle disable</button>
|
<EventBar props={{ setMode, setTarget, clear }} />
|
||||||
<button onClick={clear}>Clear</button>
|
|
||||||
<EventBar props={{ setMode, setTarget }} />
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,53 @@
|
||||||
|
import { ItemProps } from "../../interfaces/frontend"
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
|
import { useDrawProps } from "@hooks/useDrawProps"
|
||||||
import classNames from "classnames"
|
import classNames from "classnames"
|
||||||
import React, { CSSProperties } from "react"
|
import React, { CSSProperties, useEffect, useRef, useState } from "react"
|
||||||
|
import { HexColorPicker } from "react-colorful"
|
||||||
|
|
||||||
function Item({
|
function Item({
|
||||||
props: { icon, text, amount, callback },
|
props: { icon, text, amount, iconColor, disabled, callback },
|
||||||
}: {
|
}: {
|
||||||
props: {
|
props: ItemProps
|
||||||
icon: string
|
|
||||||
text: string
|
|
||||||
amount?: number
|
|
||||||
callback: () => void
|
|
||||||
}
|
|
||||||
}) {
|
}) {
|
||||||
|
const isColor = text === "Color"
|
||||||
|
const { color, setColor } = useDrawProps()
|
||||||
|
const [active, setActive] = useState(false)
|
||||||
|
const cpRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const inActive = (e: MouseEvent) => {
|
||||||
|
if (cpRef.current && !cpRef.current.contains(e.target as Node))
|
||||||
|
setActive(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listeners
|
||||||
|
if (!isColor) return
|
||||||
|
setTimeout(() => window.addEventListener("click", inActive), 200)
|
||||||
|
|
||||||
|
// Remove event listeners
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("click", inActive)
|
||||||
|
}
|
||||||
|
}, [active, isColor])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="item" onClick={callback}>
|
<div className="item" onClick={isColor ? () => setActive(true) : callback}>
|
||||||
|
{isColor ? (
|
||||||
|
<div
|
||||||
|
ref={cpRef}
|
||||||
|
className={classNames("react-colorful-wrapper", { active: active })}
|
||||||
|
>
|
||||||
|
<HexColorPicker color={color} onChange={setColor} />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
className={classNames("container", { amount: amount })}
|
className={classNames("container", {
|
||||||
|
amount: amount,
|
||||||
|
disabled: disabled,
|
||||||
|
})}
|
||||||
style={
|
style={
|
||||||
amount
|
amount
|
||||||
? ({
|
? ({
|
||||||
|
@ -23,7 +56,15 @@ function Item({
|
||||||
: {}
|
: {}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<img src={`/assets/${icon}.png`} alt={`${icon}.png`} />
|
{typeof icon === "string" ? (
|
||||||
|
<img
|
||||||
|
src={`/assets/${icon}.png`}
|
||||||
|
alt={`${icon}.png`}
|
||||||
|
className="pixelart"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FontAwesomeIcon icon={icon} color={iconColor ?? "#444"} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<span>{text}</span>
|
<span>{text}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -88,7 +88,6 @@ function Player({
|
||||||
isLatched={!!isReady}
|
isLatched={!!isReady}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!player) return
|
if (!player) return
|
||||||
console.log(i, !isReady)
|
|
||||||
setIsReady({
|
setIsReady({
|
||||||
i,
|
i,
|
||||||
isReady: !isReady,
|
isReady: !isReady,
|
||||||
|
|
|
@ -1,14 +1,34 @@
|
||||||
import { Draw, Point } from "../interfaces/frontend"
|
import { Draw, Point } from "../interfaces/frontend"
|
||||||
|
import { useDrawProps } from "./useDrawProps"
|
||||||
import { useEffect, useRef, useState } from "react"
|
import { useEffect, useRef, useState } from "react"
|
||||||
|
|
||||||
export const useDraw = (
|
function onDraw({ prevPoint, currentPoint, ctx, color }: Draw) {
|
||||||
onDraw: ({ ctx, currentPoint, prevPoint }: Draw) => void
|
const { x: currX, y: currY } = currentPoint
|
||||||
) => {
|
const lineColor = color
|
||||||
|
const lineWidth = 5
|
||||||
|
|
||||||
|
let startPoint = prevPoint ?? currentPoint
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.lineWidth = lineWidth
|
||||||
|
ctx.strokeStyle = lineColor
|
||||||
|
ctx.moveTo(startPoint.x, startPoint.y)
|
||||||
|
ctx.lineTo(currX, currY)
|
||||||
|
ctx.stroke()
|
||||||
|
|
||||||
|
ctx.fillStyle = lineColor
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(startPoint.x, startPoint.y, 2, 0, 2 * Math.PI)
|
||||||
|
ctx.fill()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useDraw = () => {
|
||||||
const [mouseDown, setMouseDown] = useState(false)
|
const [mouseDown, setMouseDown] = useState(false)
|
||||||
|
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null)
|
const canvasRef = useRef<HTMLCanvasElement>(null)
|
||||||
const prevPoint = useRef<null | Point>(null)
|
const prevPoint = useRef<null | Point>(null)
|
||||||
|
|
||||||
|
const { color } = useDrawProps()
|
||||||
|
|
||||||
const onMouseDown = () => setMouseDown(true)
|
const onMouseDown = () => setMouseDown(true)
|
||||||
|
|
||||||
const clear = () => {
|
const clear = () => {
|
||||||
|
@ -22,6 +42,9 @@ export const useDraw = (
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const canvas = canvasRef.current
|
||||||
|
if (!canvas) return
|
||||||
|
|
||||||
const handler = (e: MouseEvent) => {
|
const handler = (e: MouseEvent) => {
|
||||||
if (!mouseDown) return
|
if (!mouseDown) return
|
||||||
const currentPoint = computePointInCanvas(e)
|
const currentPoint = computePointInCanvas(e)
|
||||||
|
@ -29,14 +52,11 @@ export const useDraw = (
|
||||||
const ctx = canvasRef.current?.getContext("2d")
|
const ctx = canvasRef.current?.getContext("2d")
|
||||||
if (!ctx || !currentPoint) return
|
if (!ctx || !currentPoint) return
|
||||||
|
|
||||||
onDraw({ ctx, currentPoint, prevPoint: prevPoint.current })
|
onDraw({ ctx, currentPoint, prevPoint: prevPoint.current, color })
|
||||||
prevPoint.current = currentPoint
|
prevPoint.current = currentPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
const computePointInCanvas = (e: MouseEvent) => {
|
const computePointInCanvas = (e: MouseEvent) => {
|
||||||
const canvas = canvasRef.current
|
|
||||||
if (!canvas) return
|
|
||||||
|
|
||||||
const rect = canvas.getBoundingClientRect()
|
const rect = canvas.getBoundingClientRect()
|
||||||
const x = e.clientX - rect.left
|
const x = e.clientX - rect.left
|
||||||
const y = e.clientY - rect.top
|
const y = e.clientY - rect.top
|
||||||
|
@ -50,15 +70,15 @@ export const useDraw = (
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add event listeners
|
// Add event listeners
|
||||||
canvasRef.current?.addEventListener("mousemove", handler)
|
canvas.addEventListener("mousemove", handler)
|
||||||
window.addEventListener("mouseup", mouseUpHandler)
|
window.addEventListener("mouseup", mouseUpHandler)
|
||||||
|
|
||||||
// Remove event listeners
|
// Remove event listeners
|
||||||
return () => {
|
return () => {
|
||||||
canvasRef.current?.removeEventListener("mousemove", handler)
|
canvas.removeEventListener("mousemove", handler)
|
||||||
window.removeEventListener("mouseup", mouseUpHandler)
|
window.removeEventListener("mouseup", mouseUpHandler)
|
||||||
}
|
}
|
||||||
}, [onDraw])
|
}, [color, mouseDown])
|
||||||
|
|
||||||
return { canvasRef, onMouseDown, clear }
|
return { canvasRef, onMouseDown, clear }
|
||||||
}
|
}
|
||||||
|
|
40
leaky-ships/hooks/useDrawProps.ts
Normal file
40
leaky-ships/hooks/useDrawProps.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { produce } from "immer"
|
||||||
|
import { create } from "zustand"
|
||||||
|
import { devtools } from "zustand/middleware"
|
||||||
|
|
||||||
|
const initialState: {
|
||||||
|
enable: boolean
|
||||||
|
shouldHide: boolean
|
||||||
|
color: string
|
||||||
|
} = {
|
||||||
|
enable: false,
|
||||||
|
shouldHide: false,
|
||||||
|
color: "#b32aa9",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type State = typeof initialState
|
||||||
|
|
||||||
|
export type Action = {
|
||||||
|
setColor: (color: string) => void
|
||||||
|
reset: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useDrawProps = create<State & Action>()(
|
||||||
|
devtools(
|
||||||
|
(set) => ({
|
||||||
|
...initialState,
|
||||||
|
setColor: (color) =>
|
||||||
|
set(
|
||||||
|
produce((state) => {
|
||||||
|
state.color = color
|
||||||
|
})
|
||||||
|
),
|
||||||
|
reset: () => {
|
||||||
|
set(initialState)
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "gameState",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { IconDefinition } from "@fortawesome/pro-solid-svg-icons"
|
||||||
|
|
||||||
export interface Position {
|
export interface Position {
|
||||||
x: number
|
x: number
|
||||||
y: number
|
y: number
|
||||||
|
@ -16,11 +18,20 @@ export interface Mode {
|
||||||
pointerGrid: any[][]
|
pointerGrid: any[][]
|
||||||
type: string
|
type: string
|
||||||
}
|
}
|
||||||
export interface Items {
|
export interface ItemProps {
|
||||||
icon: string
|
icon: string | IconDefinition
|
||||||
text: string
|
text: string
|
||||||
mode?: number
|
|
||||||
amount?: number
|
amount?: number
|
||||||
|
iconColor?: string
|
||||||
|
disabled?: boolean
|
||||||
|
callback?: () => void
|
||||||
|
}
|
||||||
|
export interface EventBarModes {
|
||||||
|
main: ItemProps[]
|
||||||
|
menu: ItemProps[]
|
||||||
|
attack: ItemProps[]
|
||||||
|
draw: ItemProps[]
|
||||||
|
settings: ItemProps[]
|
||||||
}
|
}
|
||||||
export interface Field extends Position {
|
export interface Field extends Position {
|
||||||
field: string
|
field: string
|
||||||
|
@ -57,4 +68,5 @@ export interface Draw {
|
||||||
ctx: CanvasRenderingContext2D
|
ctx: CanvasRenderingContext2D
|
||||||
currentPoint: Point
|
currentPoint: Point
|
||||||
prevPoint: Point | null
|
prevPoint: Point | null
|
||||||
|
color: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
"nodemailer": "^6.9.3",
|
"nodemailer": "^6.9.3",
|
||||||
"prisma": "^4.15.0",
|
"prisma": "^4.15.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
"react-colorful": "^5.6.1",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-otp-input": "^3.0.2",
|
"react-otp-input": "^3.0.2",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
|
|
13
leaky-ships/pnpm-lock.yaml
generated
13
leaky-ships/pnpm-lock.yaml
generated
|
@ -71,6 +71,9 @@ dependencies:
|
||||||
react:
|
react:
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
|
react-colorful:
|
||||||
|
specifier: ^5.6.1
|
||||||
|
version: 5.6.1(react-dom@18.2.0)(react@18.2.0)
|
||||||
react-dom:
|
react-dom:
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0(react@18.2.0)
|
version: 18.2.0(react@18.2.0)
|
||||||
|
@ -2877,6 +2880,16 @@ packages:
|
||||||
/queue-microtask@1.2.3:
|
/queue-microtask@1.2.3:
|
||||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||||
|
|
||||||
|
/react-colorful@5.6.1(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.8.0'
|
||||||
|
react-dom: '>=16.8.0'
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-dom@18.2.0(react@18.2.0):
|
/react-dom@18.2.0(react@18.2.0):
|
||||||
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
|
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
|
@ -337,7 +337,8 @@ body {
|
||||||
canvas {
|
canvas {
|
||||||
grid-area: 1 / 1 / -1 / -1;
|
grid-area: 1 / 1 / -1 / -1;
|
||||||
border: 1px solid #000;
|
border: 1px solid #000;
|
||||||
display: absolute;
|
border-radius: 0.5rem;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,10 +353,35 @@ body {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
width: 128px;
|
width: 128px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.react-colorful-wrapper {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
transition: 0.2s;
|
||||||
|
position: absolute;
|
||||||
|
top: -225px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 1;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
pointer-events: auto;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
width: initial;
|
width: initial;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
padding: 8px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 1rem;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
box-shadow: inset 0 0 1rem 1rem #888;
|
||||||
|
}
|
||||||
|
|
||||||
&.amount::after {
|
&.amount::after {
|
||||||
content: var(--amount);
|
content: var(--amount);
|
||||||
|
@ -372,10 +398,12 @@ body {
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 64px;
|
width: 64px;
|
||||||
padding: 8px;
|
|
||||||
@include pixelart;
|
@include pixelart;
|
||||||
background-color: white;
|
}
|
||||||
border-radius: 1rem;
|
svg {
|
||||||
|
margin: 8px;
|
||||||
|
height: 48px;
|
||||||
|
display: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue