From 749a3356c382b3a63ac0de4f962e897e5c0f6ffd Mon Sep 17 00:00:00 2001 From: cha0s Date: Wed, 18 Sep 2024 17:46:42 -0500 Subject: [PATCH] refactor: gen --- .eslintrc.cjs | 3 + app/react/components/dev/slider-text.jsx | 43 +++++++ app/routes/dev.gen._index/layer.jsx | 10 ++ app/routes/dev.gen._index/layer.module.css | 0 app/routes/dev.gen._index/noise-field.jsx | 51 +++++++++ .../dev.gen._index/noise-field.module.css | 16 +++ app/routes/dev.gen._index/route.jsx | 107 ++++++++++++++++++ app/routes/{gen => dev.gen.forest}/route.jsx | 23 ++-- 8 files changed, 241 insertions(+), 12 deletions(-) create mode 100644 app/react/components/dev/slider-text.jsx create mode 100644 app/routes/dev.gen._index/layer.jsx create mode 100644 app/routes/dev.gen._index/layer.module.css create mode 100644 app/routes/dev.gen._index/noise-field.jsx create mode 100644 app/routes/dev.gen._index/noise-field.module.css create mode 100644 app/routes/dev.gen._index/route.jsx rename app/routes/{gen => dev.gen.forest}/route.jsx (92%) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index a56fa0e..dc58658 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -61,6 +61,9 @@ module.exports = { }, rules: { 'react/prop-types': 'off', + 'jsx-a11y/label-has-associated-control': [2, { + controlComponents: ['SliderText'], + }], }, }, diff --git a/app/react/components/dev/slider-text.jsx b/app/react/components/dev/slider-text.jsx new file mode 100644 index 0000000..1872b07 --- /dev/null +++ b/app/react/components/dev/slider-text.jsx @@ -0,0 +1,43 @@ +import {useState} from 'react'; + +function SliderText({ + defaultValue, + max, + min, + name, + onChange, + step, +}) { + const [value, setValue] = useState(defaultValue); + return ( + <> + { + setValue(value); + if (onChange) { + onChange(value); + } + }} + step={step} + type="range" + /> + { + setValue(value); + if (onChange) { + onChange(value); + } + }} + type="text" + /> + + ) +} + +export default SliderText; \ No newline at end of file diff --git a/app/routes/dev.gen._index/layer.jsx b/app/routes/dev.gen._index/layer.jsx new file mode 100644 index 0000000..c8c2968 --- /dev/null +++ b/app/routes/dev.gen._index/layer.jsx @@ -0,0 +1,10 @@ +import styles from './layer.module.css'; + +function Layer() { + return ( + <> + + ); +} + +export default Layer; diff --git a/app/routes/dev.gen._index/layer.module.css b/app/routes/dev.gen._index/layer.module.css new file mode 100644 index 0000000..e69de29 diff --git a/app/routes/dev.gen._index/noise-field.jsx b/app/routes/dev.gen._index/noise-field.jsx new file mode 100644 index 0000000..b4bfe57 --- /dev/null +++ b/app/routes/dev.gen._index/noise-field.jsx @@ -0,0 +1,51 @@ +import SliderText from '@/react/components/dev/slider-text.jsx'; + +import styles from './noise-field.module.css'; + +function NoiseField(props) { + const {children, ...field} = props; + return ( +
+ + +
+ + +
+ {children} +
+ ); +} + +export default NoiseField; diff --git a/app/routes/dev.gen._index/noise-field.module.css b/app/routes/dev.gen._index/noise-field.module.css new file mode 100644 index 0000000..921387d --- /dev/null +++ b/app/routes/dev.gen._index/noise-field.module.css @@ -0,0 +1,16 @@ +.noiseField { + gap: 8px; + &, label { + align-items: center; + display: flex; + } + [type="text"][name^="label"] { + width: 10em; + } + [type="text"][name^="percent"] { + width: 3em; + } + [type="text"][name^="scale"] { + width: 4em; + } +} diff --git a/app/routes/dev.gen._index/route.jsx b/app/routes/dev.gen._index/route.jsx new file mode 100644 index 0000000..5f4e200 --- /dev/null +++ b/app/routes/dev.gen._index/route.jsx @@ -0,0 +1,107 @@ +// import {Container, Sprite, Stage} from '@pixi/react'; +import {Form, json, redirect, useLoaderData} from '@remix-run/react'; +import {useState} from 'react'; + +import {commitSession, getSession, juggleSession} from '@/server/session.server.js'; + +import NoiseField from './noise-field.jsx'; + +function getFormSession(session) { + return session.get('formSession') || { + fields: [], + }; +} + +export async function action({request}) { + const session = await getSession(request.headers.get('Cookie')); + const formSession = getFormSession(session); + const formData = await request.formData(); + const op = formData.get('op'); + if ('add-field' === op) { + formSession.fields.push({ + label: '', + percent: 100, + scale: {x: 1, y: 1}, + }); + } + else if (op.startsWith('delete/')) { + const index = parseInt(op.slice('delete/'.length)); + if (index >= 0 && index < formSession.fields.length) { + formSession.fields.splice(index, 1); + } + else { + throw new Error('delete out of bounds'); + } + } + else if (op.startsWith('update/')) { + const index = parseInt(op.slice('update/'.length)); + if (index >= 0 && index < formSession.fields.length) { + formSession.fields[index] = { + label: formData.getAll('label[]')[index], + percent: formData.getAll('percent[]')[index], + scale: { + x: formData.getAll('scaleX[]')[index], + y: formData.getAll('scaleY[]')[index], + }, + } + } + else { + throw new Error('delete out of bounds'); + } + } + else { + throw new Error('unknown operation'); + } + session.set('formSession', formSession); + return json(null, { + headers: { + 'Set-Cookie': await commitSession(session), + }, + }); +} + +export async function loader({request}) { + const session = await juggleSession(request); + return json({ + formSession: getFormSession(session), + }); +} + +function Gen() { + const {formSession: {fields}} = useLoaderData(); + return ( + <> +
+ {fields.map((field, i) => ( + + + + + ))} + +
+ + ); +} + +export default Gen; diff --git a/app/routes/gen/route.jsx b/app/routes/dev.gen.forest/route.jsx similarity index 92% rename from app/routes/gen/route.jsx rename to app/routes/dev.gen.forest/route.jsx index 00b0ca1..f388542 100644 --- a/app/routes/gen/route.jsx +++ b/app/routes/dev.gen.forest/route.jsx @@ -1,6 +1,7 @@ import {Container, Sprite, Stage} from '@pixi/react'; import {useState} from 'react'; +import SliderText from '@/react/components/dev/slider-text.jsx'; import TileLayer from '@/react/components/pixi/tile-layer.jsx'; import AssetsContext from '@/react/context/assets.js'; import {CHUNK_SIZE} from '@/util/constants.js'; @@ -45,8 +46,8 @@ function Gen() { const area = {x: 80, y: 80}; const assetsTuple = useState({}); const [seed, setSeed] = useState(0); - const [dirtClump, setDirtClump] = useState(30); - const [dirtPer, setDirtPer] = useState(0.3); + const [dirtClump, setDirtClump] = useState(60); + const [dirtPer, setDirtPer] = useState(0.6); const dirtCheck = (x, y, noise) => noise(x / dirtClump, y / dirtClump) < dirtPer; @@ -163,21 +164,19 @@ function Gen() { setSeed(value || 0)} value={seed} /> - setDirtPer(value)} step="0.05" - value={dirtPer} - onChange={({currentTarget: {value}}) => setDirtPer(value)} + defaultValue={dirtPer} /> - setDirtClump(value)} step="1" - value={dirtClump} - onChange={({currentTarget: {value}}) => setDirtClump(value)} + defaultValue={dirtClump} /> );