Browse Source

#3 TS エラー修正

main
みてるぞ 4 days ago
parent
commit
eba37b8b4d
7 changed files with 419 additions and 399 deletions
  1. +352
    -367
      frontend/package-lock.json
  2. +15
    -9
      frontend/src/App.tsx
  3. +27
    -21
      frontend/src/components/threads/ThreadCanvas.tsx
  4. +0
    -1
      frontend/src/main.tsx
  5. +2
    -0
      frontend/src/pages/threads/ThreadDetailPage.tsx
  6. +0
    -1
      frontend/src/pages/threads/ThreadListPage.tsx
  7. +23
    -0
      frontend/src/types.ts

+ 352
- 367
frontend/package-lock.json
File diff suppressed because it is too large
View File


+ 15
- 9
frontend/src/App.tsx View File

@@ -22,6 +22,17 @@ const colours = ['bg-fuchsia-500 dark:bg-fuchsia-900',
'bg-yellow-500 dark:bg-yellow-900'] as const 'bg-yellow-500 dark:bg-yellow-900'] as const




const ScrollToTop = () => {
const { pathname } = useLocation ()

useEffect (() => {
scrollTo (0, 0)
}, [pathname])

return null
}


export default () => { export default () => {
const bgmRef = useRef<HTMLAudioElement | null> (null) const bgmRef = useRef<HTMLAudioElement | null> (null)


@@ -35,7 +46,7 @@ export default () => {
bgmRef.current.volume = 1 bgmRef.current.volume = 1


const playBGM = async () => { const playBGM = async () => {
if (playing)
if (playing || !(bgmRef.current))
return return


try try
@@ -54,7 +65,7 @@ export default () => {
document.addEventListener ('touchstart', playBGM) document.addEventListener ('touchstart', playBGM)


const changeColour = () => { const changeColour = () => {
setColourIndex (idx => Math.floor (Math.random () * colours.length))
setColourIndex (Math.floor (Math.random () * colours.length))
} }
changeColour () changeColour ()
const colouringInterval = setInterval (changeColour, 3000) const colouringInterval = setInterval (changeColour, 3000)
@@ -86,7 +97,7 @@ export default () => {
{playing && ( {playing && (
<a href="#" onClick={ev => { <a href="#" onClick={ev => {
ev.preventDefault () ev.preventDefault ()
setMute (bgmRef.current.muted = !(mute))
bgmRef.current && setMute (bgmRef.current.muted = !(mute))
}}> }}>
{mute ? 'やっぱり BGM が恋しい人用' : 'BGM がうるさい人用'} {mute ? 'やっぱり BGM が恋しい人用' : 'BGM がうるさい人用'}
</a>)} </a>)}
@@ -94,12 +105,7 @@ export default () => {
</header> </header>
<main className="mb-8"> <main className="mb-8">
<Routes> <Routes>
{() => {
const { pathname } = useLocation ()
useEffect (() => {
scrollTo (0, 0)
}, [pathname])
}}
<ScrollToTop />
<Route path="/" element={<Navigate to="/threads" replace />} /> <Route path="/" element={<Navigate to="/threads" replace />} />
<Route path="/threads" element={<ThreadListPage />} /> <Route path="/threads" element={<ThreadListPage />} />
<Route path="/threads/:id" element={<ThreadDetailPage />} /> <Route path="/threads/:id" element={<ThreadDetailPage />} />


+ 27
- 21
frontend/src/components/threads/ThreadCanvas.tsx View File

@@ -3,7 +3,7 @@ import { useEffect, useRef, useState } from 'react'
import { FaRedo, FaUndo } from 'react-icons/fa' import { FaRedo, FaUndo } from 'react-icons/fa'
import { Layer, Line, Rect, Stage, Image } from 'react-konva' import { Layer, Line, Rect, Stage, Image } from 'react-konva'


import type { KonvaEventObject } from 'konva'
import type Konva from 'konva'
import type { ChangeEventHandler } from 'react' import type { ChangeEventHandler } from 'react'


type ImageItem = { src: string } type ImageItem = { src: string }
@@ -23,34 +23,35 @@ type Line = {
strokeWidth: number } strokeWidth: number }


const Mode = { const Mode = {
Pen: Symbol (),
Rubber: Symbol (),
Image: Symbol () } as const
type Mode = keyof Mode
Pen: 'Pen',
Rubber: 'Rubber',
Image: 'Image' } as const
type Mode = (typeof Mode)[keyof typeof Mode]




export default () => { export default () => {
const drawingRef = useRef (false) const drawingRef = useRef (false)
const fileInputRef = useRef<HTMLInputElement> (null) const fileInputRef = useRef<HTMLInputElement> (null)
const stageRef = useRef<Stage | null> (null)
const stageRef = useRef<Konva.Stage | null> (null)


const [activeLayerId, setActiveLayerId] = useState<string | null> (null) const [activeLayerId, setActiveLayerId] = useState<string | null> (null)
const [colour, setColour] = useState ('#000000') const [colour, setColour] = useState ('#000000')
const [images, setImages] = useState<Record<string, window.Image[]>> ({ })
const [layers, setLayers] = useState<Layer[]> ([])
const [images, setImages] = useState<Record<string, HTMLImageElement>> ({ })
const [layerCnt, setLayerCnt] = useState (0) const [layerCnt, setLayerCnt] = useState (0)
const [layers, setLayers] = useState<Layer[]> ([])
const [mode, setMode] = useState<Mode> (Mode.Pen) const [mode, setMode] = useState<Mode> (Mode.Pen)
const [pointSize, setPointSize] = useState (3) const [pointSize, setPointSize] = useState (3)
const [stageWidth, setStageWidth] = useState (480)
const [stageHeight, setStageHeight] = useState (480) const [stageHeight, setStageHeight] = useState (480)
const [stageWidth, setStageWidth] = useState (480)


const activeLayer = layers.find (l => l.id === activeLayerId) const activeLayer = layers.find (l => l.id === activeLayerId)


const handleMouseDown = (ev: KonvaEventObject<MouseEvent>) => {
drawingRef.current = true
const handleMouseDown = (ev: Konva.KonvaEventObject<MouseEvent | TouchEvent>) => {
const pos = ev.target.getStage ()?.getPointerPosition () const pos = ev.target.getStage ()?.getPointerPosition ()
if (!(pos))
if (!(pos) || !(activeLayer))
return return

drawingRef.current = true
const lines: Line[] = [ const lines: Line[] = [
...activeLayer.lines, ...activeLayer.lines,
{ mode, { mode,
@@ -60,9 +61,10 @@ export default () => {
updateActiveLayerLines (lines) updateActiveLayerLines (lines)
} }


const handleMouseMove = (ev: KonvaEventObject<MouseEvent>) => {
if (!(drawingRef.current))
const handleMouseMove = (ev: Konva.KonvaEventObject<MouseEvent | TouchEvent>) => {
if (!(drawingRef.current) || !(activeLayer))
return return

const stage = ev.target.getStage () const stage = ev.target.getStage ()
const point = stage?.getPointerPosition () const point = stage?.getPointerPosition ()
if (!(point)) if (!(point))
@@ -80,17 +82,17 @@ export default () => {
} }


const handleUndo = () => { const handleUndo = () => {
if (activeLayer.lines.length === 0)
if (!(activeLayer) || activeLayer.lines.length === 0)
return return
const newLines = [...activeLayer.lines] const newLines = [...activeLayer.lines]
const last = newLines.pop()!
newLines.pop()
updateActiveLayerHistory ([...activeLayer.history, activeLayer.lines]) updateActiveLayerHistory ([...activeLayer.history, activeLayer.lines])
updateActiveLayerFuture ([]) updateActiveLayerFuture ([])
updateActiveLayerLines (newLines) updateActiveLayerLines (newLines)
} }


const handleRedo = () => { const handleRedo = () => {
if (activeLayer.history.length === 0)
if (!(activeLayer) || activeLayer.history.length === 0)
return return
const prev = activeLayer.history[activeLayer.history.length - 1] const prev = activeLayer.history[activeLayer.history.length - 1]
updateActiveLayerLines (prev) updateActiveLayerLines (prev)
@@ -181,9 +183,14 @@ export default () => {
useEffect (() => { useEffect (() => {
try try
{ {
const paint = JSON.parse (localStorage.getItem ('paint'))
const paintJSON = localStorage.getItem ('paint')
if (paintJSON == null)
throw new Error

const paint = JSON.parse (paintJSON)
if (!(paint instanceof Array)) if (!(paint instanceof Array))
throw new Error throw new Error

setLayers (paint) setLayers (paint)
setActiveLayerId (paint[0].id) setActiveLayerId (paint[0].id)
} }
@@ -254,7 +261,7 @@ export default () => {
min={32} min={32}
max={640} max={640}
value={stageWidth} value={stageWidth}
onChange={ev => setStageWidth (ev.target.value)} />
onChange={ev => setStageWidth (+ev.target.value)} />
</label> </label>
<label> <label>
高さ: 高さ:
@@ -262,7 +269,7 @@ export default () => {
min={24} min={24}
max={480} max={480}
value={stageHeight} value={stageHeight}
onChange={ev => setStageHeight (ev.target.value)} />
onChange={ev => setStageHeight (+ev.target.value)} />
</label> </label>
</div> </div>
</div> </div>
@@ -363,7 +370,6 @@ export default () => {
<div className="border border-black dark:border-white"> <div className="border border-black dark:border-white">
<Stage ref={node => { <Stage ref={node => {
stageRef.current = node stageRef.current = node
return node
}} }}
width={stageWidth} width={stageWidth}
height={stageHeight} height={stageHeight}


+ 0
- 1
frontend/src/main.tsx View File

@@ -1,4 +1,3 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client' import { createRoot } from 'react-dom/client'
import './index.css' import './index.css'
import App from './App.tsx' import App from './App.tsx'


+ 2
- 0
frontend/src/pages/threads/ThreadDetailPage.tsx View File

@@ -7,6 +7,8 @@ import { useParams } from 'react-router-dom'
import ThreadCanvas from '@/components/threads/ThreadCanvas' import ThreadCanvas from '@/components/threads/ThreadCanvas'
import { API_BASE_URL } from '@/config' import { API_BASE_URL } from '@/config'


import type { Post, Thread } from '@/types'



export default () => { export default () => {
const { id } = useParams () const { id } = useParams ()


+ 0
- 1
frontend/src/pages/threads/ThreadListPage.tsx View File

@@ -1,6 +1,5 @@
import axios from 'axios' import axios from 'axios'
import toCamel from 'camelcase-keys' import toCamel from 'camelcase-keys'
import cn from 'classnames'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Accordion, import { Accordion,
AccordionItem, AccordionItem,


+ 23
- 0
frontend/src/types.ts View File

@@ -0,0 +1,23 @@
export type Post = {
id: number
threadId: number
postNo: number
name: string | null
message: string | null
imageUrl: string | null
held: boolean
sensitive: boolean
good: number
bad: number
createdAt: string
updatedAt: string
deletedAt: string | null }

export type Thread = {
id: number
name: string
description: string | null
postCount: number
createdAt: string
updatedAt: string
deletedAt: string | null }

Loading…
Cancel
Save