Fixid color picker and drawing functionality

This commit is contained in:
aronmal 2023-09-10 01:42:09 +02:00
parent efcb61b1ed
commit d245009c37
Signed by: aronmal
GPG key ID: 816B7707426FC612
10 changed files with 132 additions and 92 deletions

View file

@ -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"
},

View file

@ -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'}

View file

@ -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()

View file

@ -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>
)
}

View file

@ -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>
)

View file

@ -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
@ -42,18 +34,31 @@ export const useDraw = () => {
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")
}

View file

@ -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")
},
}

View file

@ -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

View file

@ -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)

View file

@ -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;
}
}
}