Fixid color picker and drawing functionality
This commit is contained in:
parent
efcb61b1ed
commit
d245009c37
10 changed files with 132 additions and 92 deletions
|
@ -31,13 +31,16 @@
|
|||
"drizzle-zod": "^0.5.1",
|
||||
"http-status": "^1.7.0",
|
||||
"json-stable-stringify": "^1.0.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nodemailer": "^6.9.5",
|
||||
"object-hash": "^3.0.0",
|
||||
"postgres": "^3.3.5",
|
||||
"socket.io": "^4.7.2",
|
||||
"socket.io-client": "^4.7.2",
|
||||
"solid-color": "^0.0.4",
|
||||
"solid-js": "^1.7.11",
|
||||
"solid-start": "^0.3.5",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"unique-names-generator": "^4.7.1",
|
||||
"zod": "3.21.1"
|
||||
},
|
||||
|
|
25
leaky-ships/pnpm-lock.yaml
generated
25
leaky-ships/pnpm-lock.yaml
generated
|
@ -69,6 +69,9 @@ dependencies:
|
|||
json-stable-stringify:
|
||||
specifier: ^1.0.2
|
||||
version: 1.0.2
|
||||
lodash-es:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
nodemailer:
|
||||
specifier: ^6.9.5
|
||||
version: 6.9.5
|
||||
|
@ -84,12 +87,18 @@ dependencies:
|
|||
socket.io-client:
|
||||
specifier: ^4.7.2
|
||||
version: 4.7.2
|
||||
solid-color:
|
||||
specifier: ^0.0.4
|
||||
version: 0.0.4(solid-js@1.7.11)
|
||||
solid-js:
|
||||
specifier: ^1.7.11
|
||||
version: 1.7.11
|
||||
solid-start:
|
||||
specifier: ^0.3.5
|
||||
version: 0.3.5(@solidjs/meta@0.28.6)(@solidjs/router@0.8.3)(solid-js@1.7.11)(solid-start-node@0.3.5)(vite@4.4.9)
|
||||
tinycolor2:
|
||||
specifier: ^1.6.0
|
||||
version: 1.6.0
|
||||
unique-names-generator:
|
||||
specifier: ^4.7.1
|
||||
version: 4.7.1
|
||||
|
@ -4088,6 +4097,10 @@ packages:
|
|||
p-locate: 5.0.0
|
||||
dev: true
|
||||
|
||||
/lodash-es@4.17.21:
|
||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||
dev: false
|
||||
|
||||
/lodash.debounce@4.0.8:
|
||||
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
||||
|
||||
|
@ -5021,6 +5034,14 @@ packages:
|
|||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/solid-color@0.0.4(solid-js@1.7.11):
|
||||
resolution: {integrity: sha512-hFZ0E0v6OYiuxc73txwlN8NB1KoeEU3mw5rwBfk3eJ8Kr/yY7h4G7X/QZ1xhnmOeVmam8lHk8iTujee8BeWSOw==}
|
||||
peerDependencies:
|
||||
solid-js: '>=1.0.0'
|
||||
dependencies:
|
||||
solid-js: 1.7.11
|
||||
dev: false
|
||||
|
||||
/solid-js@1.7.11:
|
||||
resolution: {integrity: sha512-JkuvsHt8jqy7USsy9xJtT18aF9r2pFO+GB8JQ2XGTvtF49rGTObB46iebD25sE3qVNvIbwglXOXdALnJq9IHtQ==}
|
||||
dependencies:
|
||||
|
@ -5316,6 +5337,10 @@ packages:
|
|||
next-tick: 1.1.0
|
||||
dev: true
|
||||
|
||||
/tinycolor2@1.6.0:
|
||||
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
|
||||
dev: false
|
||||
|
||||
/titleize@3.0.0:
|
||||
resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
|
@ -26,7 +26,12 @@ import { modes } from "~/lib/utils/helpers"
|
|||
// import { Icons, toast } from "react-toastify"
|
||||
import { For, Show, createEffect } from "solid-js"
|
||||
import { useNavigate } from "solid-start"
|
||||
import { useDrawProps } from "~/hooks/useDrawProps"
|
||||
import {
|
||||
color,
|
||||
setEnable,
|
||||
setShouldHide,
|
||||
shouldHide,
|
||||
} from "~/hooks/useDrawProps"
|
||||
import {
|
||||
gameProps,
|
||||
reset,
|
||||
|
@ -43,7 +48,6 @@ import { EventBarModes } from "../../interfaces/frontend"
|
|||
import Item from "./Item"
|
||||
|
||||
function EventBar(props: { clear: () => void }) {
|
||||
const { shouldHide, setShouldHide, setEnable, color } = useDrawProps
|
||||
const { selfIndex, selfIsActiveIndex, selfUser, ships } = useSession()
|
||||
const navigator = useNavigate()
|
||||
|
||||
|
|
|
@ -7,8 +7,7 @@ import BorderTiles from "~/components/Gamefield/BorderTiles"
|
|||
import EventBar from "~/components/Gamefield/EventBar"
|
||||
import HitElems from "~/components/Gamefield/HitElems"
|
||||
import Targets from "~/components/Gamefield/Targets"
|
||||
import { useDraw } from "~/hooks/useDraw"
|
||||
import { useDrawProps } from "~/hooks/useDrawProps"
|
||||
import { DrawingCanvas, clearDrawing } from "~/hooks/useDraw"
|
||||
import {
|
||||
full,
|
||||
gameProps,
|
||||
|
@ -33,8 +32,6 @@ function Gamefield() {
|
|||
const { ships } = useSession()
|
||||
const navigator = useNavigate()
|
||||
const { isConnected } = useSocket()
|
||||
const usingDraw = useDraw()
|
||||
const { enable, color, shouldHide } = useDrawProps
|
||||
|
||||
createEffect(() => {
|
||||
if (
|
||||
|
@ -119,19 +116,9 @@ function Gamefield() {
|
|||
|
||||
<Targets />
|
||||
|
||||
<canvas
|
||||
style={{
|
||||
opacity: shouldHide() ? 0 : 1,
|
||||
"box-shadow": enable() ? "inset 0 0 0 2px " + color : "none",
|
||||
"pointer-events": enable() && !shouldHide() ? "auto" : "none",
|
||||
}}
|
||||
ref={usingDraw.canvasRef}
|
||||
onMouseDown={usingDraw.onMouseDown}
|
||||
width="648"
|
||||
height="648"
|
||||
/>
|
||||
<DrawingCanvas />
|
||||
</div>
|
||||
<EventBar clear={usingDraw.clear} />
|
||||
<EventBar clear={clearDrawing} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,47 +1,31 @@
|
|||
import { Show, createEffect, createSignal, onCleanup } from "solid-js"
|
||||
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
|
||||
// import { useDrawProps } from "~/hooks/useDrawProps"
|
||||
// import { HexColorPicker } from "react-colorful"
|
||||
import classNames from "classnames"
|
||||
import { BlockPicker } from "solid-color"
|
||||
import { Show, createSignal } from "solid-js"
|
||||
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
|
||||
import { color, colors, setColor } from "~/hooks/useDrawProps"
|
||||
import { ItemProps } from "../../interfaces/frontend"
|
||||
|
||||
function Item(props: ItemProps) {
|
||||
const isColor = () => props.text === "Color"
|
||||
// const { color, setColor } = useDrawProps()
|
||||
const [active, setActive] = createSignal(false)
|
||||
let cpRef: HTMLDivElement
|
||||
|
||||
createEffect(() => {
|
||||
const inActive = (e: MouseEvent) => {
|
||||
if (cpRef && !cpRef.contains(e.target as Node)) setActive(false)
|
||||
}
|
||||
|
||||
// Add event listeners
|
||||
if (!isColor()) return
|
||||
setTimeout(() => window.addEventListener("click", inActive), 200)
|
||||
|
||||
// Remove event listeners
|
||||
onCleanup(() => {
|
||||
window.removeEventListener("click", inActive)
|
||||
})
|
||||
})
|
||||
|
||||
return (
|
||||
<div
|
||||
class="item"
|
||||
onClick={() =>
|
||||
isColor() ? setActive(true) : props.callback && props.callback()
|
||||
}
|
||||
>
|
||||
<div class="item">
|
||||
<Show when={isColor()}>
|
||||
<div
|
||||
ref={cpRef!}
|
||||
class={classNames("react-colorful-wrapper", { active: active })}
|
||||
class={classNames("color-picker-wrapper", { active: active() })}
|
||||
>
|
||||
{/* <HexColorPicker color={color} onChange={setColor} /> */}
|
||||
<BlockPicker
|
||||
color={color()}
|
||||
onChange={(e) => setColor(e.hex)}
|
||||
colors={colors}
|
||||
triangle="hide"
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
<div
|
||||
<button
|
||||
class={classNames("container", {
|
||||
amount: typeof props.amount !== "undefined",
|
||||
disabled: props.disabled || props.amount === 0,
|
||||
|
@ -54,6 +38,9 @@ function Item(props: ItemProps) {
|
|||
}
|
||||
: {}
|
||||
}
|
||||
onClick={() => {
|
||||
isColor() ? setActive((e) => !e) : props.callback && props.callback()
|
||||
}}
|
||||
>
|
||||
{typeof props.icon === "string" ? (
|
||||
<img
|
||||
|
@ -67,7 +54,7 @@ function Item(props: ItemProps) {
|
|||
color={props.iconColor ?? "#444"}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
<span>{props.text}</span>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { createEffect, createSignal, onCleanup } from "solid-js"
|
||||
import { socket } from "~/lib/socket"
|
||||
import { Draw, DrawLineProps, PlayerEvent, Point } from "../interfaces/frontend"
|
||||
import { useDrawProps } from "./useDrawProps"
|
||||
import { color, enable, shouldHide } from "./useDrawProps"
|
||||
|
||||
let canvasRef: HTMLCanvasElement
|
||||
|
||||
function drawLine({ prevPoint, currentPoint, ctx, color }: Draw) {
|
||||
const { x: currX, y: currY } = currentPoint
|
||||
|
@ -22,17 +24,7 @@ function drawLine({ prevPoint, currentPoint, ctx, color }: Draw) {
|
|||
ctx.fill()
|
||||
}
|
||||
|
||||
export const useDraw = () => {
|
||||
const [mouseDown, setMouseDown] = createSignal(false)
|
||||
|
||||
let canvasRef: HTMLCanvasElement
|
||||
let prevPoint: null | Point
|
||||
|
||||
const { color } = useDrawProps
|
||||
|
||||
const onMouseDown = () => setMouseDown(true)
|
||||
|
||||
const clear = () => {
|
||||
function clear() {
|
||||
const canvas = canvasRef
|
||||
if (!canvas) return
|
||||
|
||||
|
@ -40,20 +32,33 @@ export const useDraw = () => {
|
|||
if (!ctx) return
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
}
|
||||
}
|
||||
|
||||
export function DrawingCanvas() {
|
||||
const [mouseDown, setMouseDown] = createSignal(false)
|
||||
|
||||
let prevPoint: null | Point
|
||||
|
||||
const onMouseDown = () => setMouseDown(true)
|
||||
|
||||
createEffect(() => {
|
||||
const canvas = canvasRef
|
||||
if (!canvas) return
|
||||
|
||||
const handler = (e: MouseEvent) => {
|
||||
if (!mouseDown) return
|
||||
if (!mouseDown()) return
|
||||
const currentPoint = computePointInCanvas(e)
|
||||
|
||||
const ctx = canvasRef?.getContext("2d")
|
||||
if (!ctx || !currentPoint) return
|
||||
|
||||
drawLine({ ctx, currentPoint, prevPoint: prevPoint, color: color() })
|
||||
const props = {
|
||||
currentPoint,
|
||||
prevPoint: prevPoint,
|
||||
color: color(),
|
||||
}
|
||||
socket.emit("draw-line", props)
|
||||
drawLine({ ctx, ...props })
|
||||
prevPoint = currentPoint
|
||||
}
|
||||
|
||||
|
@ -121,5 +126,22 @@ export const useDraw = () => {
|
|||
})
|
||||
})
|
||||
|
||||
return { canvasRef: canvasRef!, onMouseDown, clear }
|
||||
return (
|
||||
<canvas
|
||||
style={{
|
||||
opacity: shouldHide() ? 0 : 1,
|
||||
"box-shadow": enable() ? "inset 0 0 0 2px " + color() : "none",
|
||||
"pointer-events": enable() && !shouldHide() ? "auto" : "none",
|
||||
}}
|
||||
ref={canvasRef}
|
||||
onMouseDown={onMouseDown}
|
||||
width="648"
|
||||
height="648"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function clearDrawing() {
|
||||
clear()
|
||||
socket.emit("canvas-clear")
|
||||
}
|
|
@ -1,19 +1,30 @@
|
|||
import { createSignal } from "solid-js"
|
||||
|
||||
const [enable, setEnable] = createSignal(false)
|
||||
const [shouldHide, setShouldHide] = createSignal(false)
|
||||
const [color, setColor] = createSignal("#b32aa9")
|
||||
export const colors = [
|
||||
"#ff4400",
|
||||
"#fea800",
|
||||
"#ffd635",
|
||||
"#00a367",
|
||||
"#7eed55",
|
||||
"#2351a6",
|
||||
"#3590ea",
|
||||
"#52e9f3",
|
||||
"#811e9f",
|
||||
"#b34abf",
|
||||
"#fe99a9",
|
||||
"#9c6926",
|
||||
// "#ffffff",
|
||||
"#d3d7d8",
|
||||
"#898d90",
|
||||
"#000000",
|
||||
]
|
||||
|
||||
export const useDrawProps = {
|
||||
enable,
|
||||
setEnable,
|
||||
shouldHide,
|
||||
setShouldHide,
|
||||
color,
|
||||
setColor,
|
||||
reset: () => {
|
||||
export const [enable, setEnable] = createSignal(false)
|
||||
export const [shouldHide, setShouldHide] = createSignal(false)
|
||||
export const [color, setColor] = createSignal("#b32aa9")
|
||||
|
||||
export function reset() {
|
||||
setEnable(false)
|
||||
setShouldHide(false)
|
||||
setColor("#b32aa9")
|
||||
},
|
||||
}
|
||||
|
|
|
@ -129,14 +129,6 @@ export function setPlayer(newUsers: Players): string | null {
|
|||
setUsers(0, newUsers)
|
||||
setUsers(1, newUsers)
|
||||
const body = getPayloadwithChecksum(getPayloadFromProps())
|
||||
if (!body.hash) {
|
||||
console.log("Something is wrong... ")
|
||||
// toast.warn("Something is wrong... ", {
|
||||
// toastId: "st_wrong",
|
||||
// theme: "colored",
|
||||
// })
|
||||
return null
|
||||
}
|
||||
hash = body.hash
|
||||
setGameProps("hash", hash)
|
||||
return hash
|
||||
|
|
|
@ -2,6 +2,8 @@ import status from "http-status"
|
|||
// import { toast } from "react-toastify"
|
||||
import { createEffect, createSignal, onCleanup } from "solid-js"
|
||||
import { useNavigate } from "solid-start"
|
||||
import { getPayloadFromProps } from "~/lib/getPayloadFromProps"
|
||||
import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum"
|
||||
import { socket } from "~/lib/socket"
|
||||
import { GamePropsSchema, GameState } from "~/lib/zodSchemas"
|
||||
import { isAuthenticated } from "~/routes/start"
|
||||
|
@ -70,8 +72,11 @@ function useSocket() {
|
|||
let message: string
|
||||
if (type !== "disconnect") {
|
||||
const { hash } = event
|
||||
const hashAlreadyMatches =
|
||||
hash === getPayloadwithChecksum(getPayloadFromProps()).hash
|
||||
if (hashAlreadyMatches) return
|
||||
const newHash = setPlayer(event.users)
|
||||
if (newHash && newHash !== hash) {
|
||||
if (newHash !== hash) {
|
||||
console.log("hash", hash, newHash)
|
||||
socket.emit("update", (body) => {
|
||||
console.log("Update is needed after", type)
|
||||
|
|
|
@ -395,12 +395,12 @@ body {
|
|||
width: 128px;
|
||||
position: relative;
|
||||
|
||||
.react-colorful-wrapper {
|
||||
.color-picker-wrapper {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: 0.2s;
|
||||
position: absolute;
|
||||
top: -225px;
|
||||
bottom: 105%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 1;
|
||||
|
@ -454,6 +454,10 @@ body {
|
|||
color: black;
|
||||
font-size: 0.75em;
|
||||
font-weight: bold;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue