feat: add dev tool client component with hono jsx
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
23472bae66
commit
9456957e63
114
src/dev/app.tsx
Normal file
114
src/dev/app.tsx
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
import { useState } from "hono/jsx"
|
||||
import { render } from "hono/jsx/dom"
|
||||
|
||||
const App = () => {
|
||||
const [spriteUrl, setSpriteUrl] = useState("")
|
||||
const [width, setWidth] = useState(32)
|
||||
const [height, setHeight] = useState(32)
|
||||
const [frames, setFrames] = useState(4)
|
||||
const [columns, setColumns] = useState<number | undefined>()
|
||||
const [frameDuration, setFrameDuration] = useState(100)
|
||||
|
||||
const handleFileChange = (e: Event) => {
|
||||
const file = (e.target as HTMLInputElement).files?.[0]
|
||||
if (!file) return
|
||||
setSpriteUrl(URL.createObjectURL(file))
|
||||
}
|
||||
|
||||
const isGrid = columns !== undefined
|
||||
const cols = isGrid ? columns : frames
|
||||
const rows = isGrid ? Math.ceil(frames / columns!) : 1
|
||||
const sheetWidth = cols * width
|
||||
const sheetHeight = rows * height
|
||||
const totalDuration = frames * frameDuration
|
||||
|
||||
const keyframeId = "sprite-preview"
|
||||
let keyframes: string
|
||||
|
||||
if (isGrid) {
|
||||
const steps: string[] = []
|
||||
for (let i = 0; i < frames; i++) {
|
||||
const col = i % columns!
|
||||
const row = Math.floor(i / columns!)
|
||||
const x = -col * width
|
||||
const y = -row * height
|
||||
const percent = (i / frames) * 100
|
||||
steps.push(`${percent}%{background-position:${x}px ${y}px}`)
|
||||
}
|
||||
keyframes = `@keyframes ${keyframeId}{${steps.join("")}}`
|
||||
} else {
|
||||
keyframes = `@keyframes ${keyframeId}{from{background-position:0 0}to{background-position:-${sheetWidth}px 0}}`
|
||||
}
|
||||
|
||||
const previewStyle = {
|
||||
width: `${width}px`,
|
||||
height: `${height}px`,
|
||||
backgroundImage: `url('${spriteUrl}')`,
|
||||
backgroundSize: `${sheetWidth}px ${sheetHeight}px`,
|
||||
animation: `${keyframeId} ${totalDuration}ms steps(${frames}) infinite`,
|
||||
}
|
||||
|
||||
const columnsAttr = columns ? `\n columns={${columns}}` : ""
|
||||
const code = `<Sprite
|
||||
src="YOUR_SPRITE_URL"
|
||||
width={${width}}
|
||||
height={${height}}
|
||||
frames={${frames}}
|
||||
frameDuration={${frameDuration}}${columnsAttr}
|
||||
/>`
|
||||
|
||||
const copyCode = () => navigator.clipboard.writeText(code)
|
||||
|
||||
return (
|
||||
<div class="grid">
|
||||
<div>
|
||||
<label>
|
||||
Spritesheet
|
||||
<input type="file" accept="image/*" onChange={handleFileChange} />
|
||||
</label>
|
||||
<label>
|
||||
Frame Width (px)
|
||||
<input type="number" value={width} min={1} onInput={(e) => setWidth(+(e.target as HTMLInputElement).value)} />
|
||||
</label>
|
||||
<label>
|
||||
Frame Height (px)
|
||||
<input type="number" value={height} min={1} onInput={(e) => setHeight(+(e.target as HTMLInputElement).value)} />
|
||||
</label>
|
||||
<label>
|
||||
Frame Count
|
||||
<input type="number" value={frames} min={1} onInput={(e) => setFrames(+(e.target as HTMLInputElement).value)} />
|
||||
</label>
|
||||
<label>
|
||||
Columns (empty = horizontal strip)
|
||||
<input type="number" value={columns} min={1} onInput={(e) => {
|
||||
const val = (e.target as HTMLInputElement).value
|
||||
setColumns(val ? +val : undefined)
|
||||
}} />
|
||||
</label>
|
||||
<label>
|
||||
Frame Duration (ms)
|
||||
<input type="number" value={frameDuration} min={1} onInput={(e) => setFrameDuration(+(e.target as HTMLInputElement).value)} />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<div class="preview-area">
|
||||
{spriteUrl ? (
|
||||
<>
|
||||
<style>{keyframes}</style>
|
||||
<div style={previewStyle} />
|
||||
</>
|
||||
) : (
|
||||
<span>Upload a spritesheet to preview</span>
|
||||
)}
|
||||
</div>
|
||||
<label>
|
||||
Generated Code
|
||||
<textarea readonly rows={8} value={code} />
|
||||
</label>
|
||||
<button onClick={copyCode}>Copy Code</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render(<App />, document.getElementById("app")!)
|
||||
Loading…
Reference in New Issue
Block a user