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 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({
|
||||
props: { setMode, setTarget },
|
||||
props: { setMode, setTarget, clear },
|
||||
}: {
|
||||
props: {
|
||||
setMode: Dispatch<SetStateAction<number>>
|
||||
setTarget: Dispatch<SetStateAction<Target>>
|
||||
clear: () => void
|
||||
}
|
||||
}) {
|
||||
const items: Items[] = [
|
||||
{ icon: "burger-menu", text: "Menu" },
|
||||
{ icon: "radar", text: "Radar scan", mode: 0, amount: 1 },
|
||||
{ icon: "torpedo", text: "Fire torpedo", mode: 1, amount: 1 },
|
||||
{ icon: "scope", text: "Fire missile", mode: 3 },
|
||||
{ icon: "gear", text: "Settings" },
|
||||
]
|
||||
return (
|
||||
<div className="event-bar">
|
||||
{items.map((e, i) => (
|
||||
<Item
|
||||
key={i}
|
||||
props={{
|
||||
...e,
|
||||
const [menu, setMenu] = useState<keyof EventBarModes>("main")
|
||||
const { shouldHide, color } = useDrawProps()
|
||||
const { payload, setSetting, full } = useGameProps()
|
||||
|
||||
const gameSetting = useCallback(
|
||||
(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: () => {
|
||||
if (e.mode !== undefined) setMode(e.mode)
|
||||
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 (
|
||||
<div className="event-bar">
|
||||
{items[menu].map((e, i) => (
|
||||
<Item key={i} props={e} />
|
||||
))}
|
||||
</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 FogImages from "./FogImages"
|
||||
import Labeling from "./Labeling"
|
||||
|
@ -8,6 +8,7 @@ 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 {
|
||||
hitReducer,
|
||||
initlialTarget,
|
||||
|
@ -69,28 +70,8 @@ function Gamefield() {
|
|||
}
|
||||
}, [mode, mouseCursor, target])
|
||||
|
||||
const [color, setColor] = useState<string>("#f00")
|
||||
const [disable, setDisable] = useState(false)
|
||||
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()
|
||||
}
|
||||
const { canvasRef, onMouseDown, clear } = useDraw()
|
||||
const { enable, color, shouldHide } = useDrawProps()
|
||||
|
||||
return (
|
||||
<div id="gamefield">
|
||||
|
@ -117,10 +98,13 @@ function Gamefield() {
|
|||
|
||||
<Targets props={{ target, targetPreview, mode, hits }} />
|
||||
{/* <span id='dev-debug' style={{gridArea: '1 / 12 / 1 / 15', backgroundColor: 'red', zIndex: 3} as CSSProperties}>Debug</span> */}
|
||||
|
||||
<canvas
|
||||
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
|
||||
}
|
||||
ref={canvasRef}
|
||||
|
@ -129,9 +113,7 @@ function Gamefield() {
|
|||
height="648"
|
||||
/>
|
||||
</div>
|
||||
<button onClick={() => setDisable((e) => !e)}>toggle disable</button>
|
||||
<button onClick={clear}>Clear</button>
|
||||
<EventBar props={{ setMode, setTarget }} />
|
||||
<EventBar props={{ setMode, setTarget, clear }} />
|
||||
</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 React, { CSSProperties } from "react"
|
||||
import React, { CSSProperties, useEffect, useRef, useState } from "react"
|
||||
import { HexColorPicker } from "react-colorful"
|
||||
|
||||
function Item({
|
||||
props: { icon, text, amount, callback },
|
||||
props: { icon, text, amount, iconColor, disabled, callback },
|
||||
}: {
|
||||
props: {
|
||||
icon: string
|
||||
text: string
|
||||
amount?: number
|
||||
callback: () => void
|
||||
}
|
||||
props: ItemProps
|
||||
}) {
|
||||
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 (
|
||||
<div className="item" onClick={callback}>
|
||||
<div className="item" onClick={isColor ? () => setActive(true) : callback}>
|
||||
{isColor ? (
|
||||
<div
|
||||
className={classNames("container", { amount: amount })}
|
||||
ref={cpRef}
|
||||
className={classNames("react-colorful-wrapper", { active: active })}
|
||||
>
|
||||
<HexColorPicker color={color} onChange={setColor} />
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<div
|
||||
className={classNames("container", {
|
||||
amount: amount,
|
||||
disabled: disabled,
|
||||
})}
|
||||
style={
|
||||
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>
|
||||
<span>{text}</span>
|
||||
</div>
|
||||
|
|
|
@ -88,7 +88,6 @@ function Player({
|
|||
isLatched={!!isReady}
|
||||
onClick={() => {
|
||||
if (!player) return
|
||||
console.log(i, !isReady)
|
||||
setIsReady({
|
||||
i,
|
||||
isReady: !isReady,
|
||||
|
|
|
@ -1,14 +1,34 @@
|
|||
import { Draw, Point } from "../interfaces/frontend"
|
||||
import { useDrawProps } from "./useDrawProps"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
|
||||
export const useDraw = (
|
||||
onDraw: ({ ctx, currentPoint, prevPoint }: Draw) => void
|
||||
) => {
|
||||
function onDraw({ prevPoint, currentPoint, ctx, color }: 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()
|
||||
}
|
||||
|
||||
export const useDraw = () => {
|
||||
const [mouseDown, setMouseDown] = useState(false)
|
||||
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null)
|
||||
const prevPoint = useRef<null | Point>(null)
|
||||
|
||||
const { color } = useDrawProps()
|
||||
|
||||
const onMouseDown = () => setMouseDown(true)
|
||||
|
||||
const clear = () => {
|
||||
|
@ -22,6 +42,9 @@ export const useDraw = (
|
|||
}
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current
|
||||
if (!canvas) return
|
||||
|
||||
const handler = (e: MouseEvent) => {
|
||||
if (!mouseDown) return
|
||||
const currentPoint = computePointInCanvas(e)
|
||||
|
@ -29,14 +52,11 @@ export const useDraw = (
|
|||
const ctx = canvasRef.current?.getContext("2d")
|
||||
if (!ctx || !currentPoint) return
|
||||
|
||||
onDraw({ ctx, currentPoint, prevPoint: prevPoint.current })
|
||||
onDraw({ ctx, currentPoint, prevPoint: prevPoint.current, color })
|
||||
prevPoint.current = currentPoint
|
||||
}
|
||||
|
||||
const computePointInCanvas = (e: MouseEvent) => {
|
||||
const canvas = canvasRef.current
|
||||
if (!canvas) return
|
||||
|
||||
const rect = canvas.getBoundingClientRect()
|
||||
const x = e.clientX - rect.left
|
||||
const y = e.clientY - rect.top
|
||||
|
@ -50,15 +70,15 @@ export const useDraw = (
|
|||
}
|
||||
|
||||
// Add event listeners
|
||||
canvasRef.current?.addEventListener("mousemove", handler)
|
||||
canvas.addEventListener("mousemove", handler)
|
||||
window.addEventListener("mouseup", mouseUpHandler)
|
||||
|
||||
// Remove event listeners
|
||||
return () => {
|
||||
canvasRef.current?.removeEventListener("mousemove", handler)
|
||||
canvas.removeEventListener("mousemove", handler)
|
||||
window.removeEventListener("mouseup", mouseUpHandler)
|
||||
}
|
||||
}, [onDraw])
|
||||
}, [color, mouseDown])
|
||||
|
||||
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 {
|
||||
x: number
|
||||
y: number
|
||||
|
@ -16,11 +18,20 @@ export interface Mode {
|
|||
pointerGrid: any[][]
|
||||
type: string
|
||||
}
|
||||
export interface Items {
|
||||
icon: string
|
||||
export interface ItemProps {
|
||||
icon: string | IconDefinition
|
||||
text: string
|
||||
mode?: 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 {
|
||||
field: string
|
||||
|
@ -57,4 +68,5 @@ export interface Draw {
|
|||
ctx: CanvasRenderingContext2D
|
||||
currentPoint: Point
|
||||
prevPoint: Point | null
|
||||
color: string
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
"nodemailer": "^6.9.3",
|
||||
"prisma": "^4.15.0",
|
||||
"react": "18.2.0",
|
||||
"react-colorful": "^5.6.1",
|
||||
"react-dom": "18.2.0",
|
||||
"react-otp-input": "^3.0.2",
|
||||
"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:
|
||||
specifier: 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:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0(react@18.2.0)
|
||||
|
@ -2877,6 +2880,16 @@ packages:
|
|||
/queue-microtask@1.2.3:
|
||||
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):
|
||||
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
|
||||
peerDependencies:
|
||||
|
|
|
@ -337,7 +337,8 @@ body {
|
|||
canvas {
|
||||
grid-area: 1 / 1 / -1 / -1;
|
||||
border: 1px solid #000;
|
||||
display: absolute;
|
||||
border-radius: 0.5rem;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,10 +353,35 @@ body {
|
|||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
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 {
|
||||
width: initial;
|
||||
position: relative;
|
||||
padding: 8px;
|
||||
background-color: white;
|
||||
border-radius: 1rem;
|
||||
|
||||
&.disabled {
|
||||
box-shadow: inset 0 0 1rem 1rem #888;
|
||||
}
|
||||
|
||||
&.amount::after {
|
||||
content: var(--amount);
|
||||
|
@ -372,10 +398,12 @@ body {
|
|||
|
||||
img {
|
||||
width: 64px;
|
||||
padding: 8px;
|
||||
@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