From 20669bacd87c470ebc82f0a1341886bc15cacb39 Mon Sep 17 00:00:00 2001 From: Peter Wolf <84736182+peterwolf-pl@users.noreply.github.com> Date: Mon, 1 Sep 2025 13:53:44 +0200 Subject: [PATCH 1/5] chore: remove leftover sample components --- LetterComposer copy.jsx | 328 ---------------------------------------- LetterComposer.jsx | 76 +++++----- PageComposer.jsx | 2 +- PrintModule.jsx | 2 +- aApp.jsx | 35 ----- assets/.gitkeep | 0 index.css | 11 +- 7 files changed, 50 insertions(+), 404 deletions(-) delete mode 100644 LetterComposer copy.jsx delete mode 100644 aApp.jsx create mode 100644 assets/.gitkeep diff --git a/LetterComposer copy.jsx b/LetterComposer copy.jsx deleted file mode 100644 index 71c44a5..0000000 --- a/LetterComposer copy.jsx +++ /dev/null @@ -1,328 +0,0 @@ -import React, { useRef, useState, useEffect } from "react"; - -const KASZTA_WIDTH = 1618; -const KASZTA_HEIGHT = 1080; -const SLOTS_COUNT = 20; - -function getImageWidth(src) { - return new Promise((resolve) => { - const img = new window.Image(); - img.onload = () => resolve(img.width); - img.src = src; - }); -} - -export default function LetterComposer() { - const [letterFields, setLetterFields] = useState([]); - const [slots, setSlots] = useState(Array(SLOTS_COUNT).fill(null)); - const [activeLetter, setActiveLetter] = useState(null); - const [ghostPos, setGhostPos] = useState({ x: 0, y: 0, visible: false }); - const [isDragging, setIsDragging] = useState(false); - const kasztaRef = useRef(); - const wierszownikRef = useRef(); - const [kasztaW, setKasztaW] = useState(KASZTA_WIDTH); - - // BLOKUJ SCROLL strony - useEffect(() => { - const oldOverflow = document.body.style.overflow; - document.body.style.overflow = "hidden"; - return () => { document.body.style.overflow = oldOverflow; }; - }, []); - - // Responsywna szerokość kaszty - useEffect(() => { - function handleResize() { - if (kasztaRef.current) { - const parentW = kasztaRef.current.parentElement.offsetWidth; - setKasztaW(Math.min(parentW, KASZTA_WIDTH)); - } - } - handleResize(); - window.addEventListener("resize", handleResize); - return () => window.removeEventListener("resize", handleResize); - }, []); - - useEffect(() => { - fetch('/poz.json') - .then(res => res.json()) - .then(setLetterFields) - .catch(() => setLetterFields([])); - }, []); - - // DRAG START (mouse/touch na field) - const handleFieldDragStart = async (field, e) => { - e.preventDefault(); - const width = await getImageWidth(field.img); - setActiveLetter({ ...field, width }); - let x = 0, y = 0; - if (e.touches && e.touches[0]) { - x = e.touches[0].clientX; - y = e.touches[0].clientY; - } else if (e.clientX && e.clientY) { - x = e.clientX; - y = e.clientY; - } - setGhostPos({ x, y, visible: true }); - setIsDragging(true); - }; - - // DRAG MOVE & DROP (document-level, działa na iOS) - useEffect(() => { - if (!isDragging) return; - const moveGhost = (e) => { - setGhostPos({ - x: e.clientX, - y: e.clientY, - visible: true - }); - }; - const moveGhostTouch = (e) => { - if (e.touches && e.touches[0]) { - setGhostPos({ - x: e.touches[0].clientX, - y: e.touches[0].clientY, - visible: true - }); - } - }; - const handleDrop = (e) => { - let x = 0, y = 0; - if (e.changedTouches && e.changedTouches[0]) { - x = e.changedTouches[0].clientX; - y = e.changedTouches[0].clientY; - } else if (e.clientX && e.clientY) { - x = e.clientX; - y = e.clientY; - } - if (wierszownikRef.current) { - const rect = wierszownikRef.current.getBoundingClientRect(); - if ( - x >= rect.left && - x <= rect.right && - y >= rect.top && - y <= rect.bottom - ) { - placeLetter(); - } else { - setActiveLetter(null); - setGhostPos({ x: 0, y: 0, visible: false }); - } - } - setIsDragging(false); - }; - document.addEventListener("mousemove", moveGhost); - document.addEventListener("touchmove", moveGhostTouch, { passive: false }); - document.addEventListener("mouseup", handleDrop); - document.addEventListener("touchend", handleDrop, { passive: false }); - return () => { - document.removeEventListener("mousemove", moveGhost); - document.removeEventListener("touchmove", moveGhostTouch); - document.removeEventListener("mouseup", handleDrop); - document.removeEventListener("touchend", handleDrop); - }; - // eslint-disable-next-line - }, [isDragging]); - - // Umieszcza literę na wierszowniku - function placeLetter() { - let idx = slots.lastIndexOf(null); - if (idx === -1) idx = 0; - const updatedSlots = [...slots]; - updatedSlots[idx] = { ...activeLetter, id: Math.random().toString(36) }; - setSlots(updatedSlots); - setActiveLetter(null); - setGhostPos({ x: 0, y: 0, visible: false }); - setIsDragging(false); - } - - // Kaszta – klik/tap poza polem kaszty anuluje ghosta - function handleKasztaBackgroundClick(e) { - setActiveLetter(null); - setGhostPos({ x: 0, y: 0, visible: false }); - setIsDragging(false); - } - - // Usuwanie liter z wierszownika - const removeLetterFromSlot = (i) => { - const updatedSlots = [...slots]; - updatedSlots[i] = null; - setSlots(updatedSlots); - }; - - const scale = kasztaW / KASZTA_WIDTH; - const kasztaH = kasztaW * (KASZTA_HEIGHT / KASZTA_WIDTH); - const lineW = kasztaW * 0.8; // WIERSZOWNIK 80% kaszty - - function renderLettersOnLine() { - let right = 0; - let visibleSlots = []; - for (let i = slots.length - 1; i >= 0; i--) { - const slot = slots[i]; - if (!slot) continue; - right += slot.width * scale; - visibleSlots.push( -
removeLetterFromSlot(i)} - title="Kliknij, aby usunąć literę z wierszownika" - > - {slot.char} -
- ); - } - return visibleSlots.reverse(); - } - - // Ghost litera - const renderGhostLetter = () => { - if (!activeLetter || !ghostPos.visible) return null; - return ( - {activeLetter.char} - ); - }; - - return ( -
- {/* Kaszta */} -
- {/* Tło łapiące kliknięcie na kaszcie */} -
- Kaszta zecerska - {/* Fieldy na kaszcie – tylko drag start */} - {letterFields.map(field => ( -
- - {/* Wierszownik */} -
- -
- {renderLettersOnLine()} -
-
- Educational Game for the Muzeum Książki Artystycznej w Łodzi by peterwolf.pl -
- {renderGhostLetter()} - -
- - - ); -} diff --git a/LetterComposer.jsx b/LetterComposer.jsx index 9f79c41..f955547 100644 --- a/LetterComposer.jsx +++ b/LetterComposer.jsx @@ -3,6 +3,9 @@ import React, { useRef, useState, useEffect } from "react"; const KASZTA_WIDTH = 1618; const KASZTA_HEIGHT = 1080; const SLOTS_COUNT = 20; +const LINE_OFFSET_RIGHT = 340; +const LINE_OFFSET_BOTTOM = 240; +const LETTER_HEIGHT = 96; function getImageWidth(src) { return new Promise((resolve) => { @@ -22,6 +25,7 @@ export default function LetterComposer({ onMoveLineToPage }) { const kasztaRef = useRef(); const wierszownikRef = useRef(); const [kasztaW, setKasztaW] = useState(KASZTA_WIDTH); + const [wierszownikSize, setWierszownikSize] = useState({ w: 0, h: 0 }); // BLOKUJ SCROLL strony useEffect(() => { @@ -160,23 +164,32 @@ export default function LetterComposer({ onMoveLineToPage }) { const scale = kasztaW / KASZTA_WIDTH; const kasztaH = kasztaW * (KASZTA_HEIGHT / KASZTA_WIDTH); const lineW = kasztaW * 0.8; // WIERSZOWNIK 80% kaszty + const lineScale = wierszownikSize.w ? lineW / wierszownikSize.w : scale; + const letterScale = lineScale * 2; + const lineStartX = wierszownikSize.w + ? (wierszownikSize.w - LINE_OFFSET_RIGHT) * lineScale + : 0; + const lineStartY = wierszownikSize.h + ? (wierszownikSize.h - LINE_OFFSET_BOTTOM) * lineScale + : 0; function renderLettersOnLine() { + if (!wierszownikSize.w) return null; let right = 0; let visibleSlots = []; for (let i = slots.length - 1; i >= 0; i--) { const slot = slots[i]; if (!slot) continue; - right += slot.width * scale; + right += slot.width * letterScale; visibleSlots.push(
@@ -206,10 +219,10 @@ export default function LetterComposer({ onMoveLineToPage }) { alt={activeLetter.char} style={{ position: "fixed", - left: ghostPos.x - (activeLetter.width * scale) / 2, - top: ghostPos.y - (96 * scale), - width: activeLetter.width * scale, - height: 96 * scale, + left: ghostPos.x - (activeLetter.width * letterScale) / 2, + top: ghostPos.y - (LETTER_HEIGHT * letterScale), + width: activeLetter.width * letterScale, + height: LETTER_HEIGHT * letterScale, pointerEvents: "none", zIndex: 1000, opacity: 1, @@ -229,7 +242,7 @@ export default function LetterComposer({ onMoveLineToPage }) { minHeight: "100vh", display: "flex", flexDirection: "column", - background: "#f5f6f8", + background: "#d4d4d4", alignItems: "center", justifyContent: "stretch", overflow: "hidden", @@ -324,37 +337,30 @@ export default function LetterComposer({ onMoveLineToPage }) { style={{ position: "relative", width: lineW, - minHeight: 116 * scale, + height: wierszownikSize.h + ? wierszownikSize.h * lineScale + : 116 * scale, margin: "1px auto 0px auto", borderRadius: 8 * scale, - background: "#a6a3a8", touchAction: "none", flexShrink: 0, boxSizing: "border-box" }} > -
+ setWierszownikSize({ + w: e.target.naturalWidth, + h: e.target.naturalHeight + }) + } + draggable={false} style={{ - position: "absolute", - left: -5 * scale, - top: 96 * scale + 16 * scale, - width: lineW + (10 * scale), - height: 8 * scale, - background: "#111", - borderRadius: 8 * scale, - zIndex: 1 - }} - /> -
{renderLettersOnLine()} diff --git a/PageComposer.jsx b/PageComposer.jsx index 3c267e9..8a4365b 100644 --- a/PageComposer.jsx +++ b/PageComposer.jsx @@ -205,7 +205,7 @@ export default function PageComposer({ style={{ minHeight: "100vh", width: "100vw", - background: "#f5f6f8", + background: "#d4d4d4", display: "flex", flexDirection: "column", alignItems: "center", diff --git a/PrintModule.jsx b/PrintModule.jsx index 10252f1..9114b57 100644 --- a/PrintModule.jsx +++ b/PrintModule.jsx @@ -39,7 +39,7 @@ export default function PrintModule({ lines, onBack }) { style={{ minHeight: "100vh", width: "100vw", - background: "#f5f6f8", + background: "#d4d4d4", display: "flex", flexDirection: "column", alignItems: "center", diff --git a/aApp.jsx b/aApp.jsx deleted file mode 100644 index f67355a..0000000 --- a/aApp.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' -import './App.css' - -function App() { - const [count, setCount] = useState(0) - - return ( - <> - -

Vite + React

-
- -

- Edit src/App.jsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

- - ) -} - -export default App diff --git a/assets/.gitkeep b/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/index.css b/index.css index 33389ba..63ce487 100644 --- a/index.css +++ b/index.css @@ -12,9 +12,13 @@ -webkit-user-select: none; -ms-user-select: none; - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; + color-scheme: light; + color: #213547; + background-color: #d4d4d4; + background-image: url('assets/bg.png'); + background-repeat: repeat; + background-size: var(--bg-tile-size); + --bg-tile-size: 64px; font-synthesis: none; text-rendering: optimizeLegibility; @@ -66,7 +70,6 @@ button:focus-visible { @media (prefers-color-scheme: light) { :root { color: #213547; - background-color: #ffffff; } a:hover { color: #747bff; From edd285b78d292d4afbb2c6e555a33c6bf78f9029 Mon Sep 17 00:00:00 2001 From: Peter Wolf <84736182+peterwolf-pl@users.noreply.github.com> Date: Mon, 1 Sep 2025 14:23:47 +0200 Subject: [PATCH 2/5] Ensure body uses tiled gray background --- index.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.css b/index.css index 63ce487..cbfa4fe 100644 --- a/index.css +++ b/index.css @@ -41,6 +41,10 @@ body { place-items: center; min-width: 320px; min-height: 100vh; + background-color: #d4d4d4; + background-image: url('assets/bg.png'); + background-repeat: repeat; + background-size: var(--bg-tile-size); } h1 { From 157f3175cd253a981d47a11e286a021ff08ee50c Mon Sep 17 00:00:00 2001 From: Peter Wolf <84736182+peterwolf-pl@users.noreply.github.com> Date: Mon, 1 Sep 2025 14:37:52 +0200 Subject: [PATCH 3/5] Remove background color definitions --- LetterComposer.jsx | 1 - PageComposer.jsx | 1 - PrintModule.jsx | 1 - index.css | 2 -- 4 files changed, 5 deletions(-) diff --git a/LetterComposer.jsx b/LetterComposer.jsx index f955547..f5c724e 100644 --- a/LetterComposer.jsx +++ b/LetterComposer.jsx @@ -242,7 +242,6 @@ export default function LetterComposer({ onMoveLineToPage }) { minHeight: "100vh", display: "flex", flexDirection: "column", - background: "#d4d4d4", alignItems: "center", justifyContent: "stretch", overflow: "hidden", diff --git a/PageComposer.jsx b/PageComposer.jsx index 8a4365b..f3d6c24 100644 --- a/PageComposer.jsx +++ b/PageComposer.jsx @@ -205,7 +205,6 @@ export default function PageComposer({ style={{ minHeight: "100vh", width: "100vw", - background: "#d4d4d4", display: "flex", flexDirection: "column", alignItems: "center", diff --git a/PrintModule.jsx b/PrintModule.jsx index 9114b57..e3b60ee 100644 --- a/PrintModule.jsx +++ b/PrintModule.jsx @@ -39,7 +39,6 @@ export default function PrintModule({ lines, onBack }) { style={{ minHeight: "100vh", width: "100vw", - background: "#d4d4d4", display: "flex", flexDirection: "column", alignItems: "center", diff --git a/index.css b/index.css index cbfa4fe..5f41ab7 100644 --- a/index.css +++ b/index.css @@ -14,7 +14,6 @@ color-scheme: light; color: #213547; - background-color: #d4d4d4; background-image: url('assets/bg.png'); background-repeat: repeat; background-size: var(--bg-tile-size); @@ -41,7 +40,6 @@ body { place-items: center; min-width: 320px; min-height: 100vh; - background-color: #d4d4d4; background-image: url('assets/bg.png'); background-repeat: repeat; background-size: var(--bg-tile-size); From cff8d50d1cfb8af4b4838bcb3b316e44bd52969f Mon Sep 17 00:00:00 2001 From: Peter Wolf <84736182+peterwolf-pl@users.noreply.github.com> Date: Mon, 1 Sep 2025 17:44:40 +0200 Subject: [PATCH 4/5] Fix background image path for production --- index.css | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/index.css b/index.css index 5f41ab7..64dc43e 100644 --- a/index.css +++ b/index.css @@ -14,7 +14,8 @@ color-scheme: light; color: #213547; - background-image: url('assets/bg.png'); + background-color: #d4d4d4; + background-image: url('/assets/bg.png'); background-repeat: repeat; background-size: var(--bg-tile-size); --bg-tile-size: 64px; @@ -40,7 +41,8 @@ body { place-items: center; min-width: 320px; min-height: 100vh; - background-image: url('assets/bg.png'); + background-color: #d4d4d4; + background-image: url('/assets/bg.png'); background-repeat: repeat; background-size: var(--bg-tile-size); } From e820938982482149771c42f189b2c47808680489 Mon Sep 17 00:00:00 2001 From: Peter Wolf <84736182+peterwolf-pl@users.noreply.github.com> Date: Mon, 1 Sep 2025 17:49:18 +0200 Subject: [PATCH 5/5] Add files via upload --- package.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 0000000..045f15f --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "my-app", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-router-dom": "^7.6.3" + }, + "devDependencies": { + "@eslint/js": "^9.29.0", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.5.2", + "eslint": "^9.29.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.2.0", + "vite": "^7.0.0" + } +}