diff --git a/project-warstone/package.json b/project-warstone/package.json index c78782c..9f9289e 100644 --- a/project-warstone/package.json +++ b/project-warstone/package.json @@ -12,12 +12,14 @@ }, "dependencies": { "@types/react-router-dom": "^5.3.3", + "@types/recoilize": "^0.8.0", "autoprefixer": "^10.4.14", "postcss": "^8.4.24", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.12.0", "recoil": "^0.7.7", + "recoilize": "^3.2.0", "tailwindcss": "^3.3.2", "vite-plugin-svgr": "^3.2.0" }, diff --git a/project-warstone/src/App.tsx b/project-warstone/src/App.tsx index 91a0005..2bcdc80 100644 --- a/project-warstone/src/App.tsx +++ b/project-warstone/src/App.tsx @@ -1,10 +1,14 @@ import { RecoilRoot } from 'recoil' import { SchemaBuilder } from './components/SchemaBuilder' +import { GameSystemEditor } from './components/GameSystemEditor' +import RecoilizeDebugger from 'recoilize'; function App() { return ( - + + {/* */} + ) } diff --git a/project-warstone/src/components/GameSystemEditor/index.tsx b/project-warstone/src/components/GameSystemEditor/index.tsx new file mode 100644 index 0000000..995f57d --- /dev/null +++ b/project-warstone/src/components/GameSystemEditor/index.tsx @@ -0,0 +1,87 @@ +import { FC, useCallback, useEffect, useState } from 'react' +import { GameSystem } from '../../types/gameSystem'; +import { useObjectState } from '../../hooks/useObjectState'; +import { GameSystemsService } from '../../services/game-systems'; + +export const GameSystemEditor: FC = () => { + const { state: gameSystem, update: updateGameSystem, bindProperty: bindGameSystemProperty, setState: setGameSystem } = useObjectState({ + id: '', + schema: { + id: '', + name: '', + templates: {}, + types: {} + }, + schemaId: '286f4c18-d280-444b-8d7e-9a3dd09f64ef', + name: 'Asshammer 40x a day', + accolades: [], + }); + const [schemas, setSchemas] = useState<{ name: string, id: string }[]>([]); + + const [lastSaved, setLastSaved] = useState(gameSystem); + + const fetchSchema = useCallback(async (id: string) => { + const res = await GameSystemsService.getSchema(id); + + if (res.status !== 200) return; + const schema = await res.json() + + updateGameSystem({ + schema + }); + }, [updateGameSystem]) + + useEffect(() => { + if (gameSystem.schemaId === gameSystem.schema.id) return; + fetchSchema(gameSystem.schemaId); + }, [fetchSchema, gameSystem.schema.id, gameSystem.schemaId]); + + useEffect(() => { + GameSystemsService.getSchemaList() + .then(res => res.json()) + .then(schemas => setSchemas(schemas)); + }, []); + + const saveGameSystem = useCallback(() => { + GameSystemsService.saveGameSystem(gameSystem); + setLastSaved(gameSystem); + }, [gameSystem]) + + const fetchGameSystem = useCallback(async () => { + const res = await GameSystemsService.getGameSystem(''); + const gs = await res.json(); + setGameSystem(gs); + setLastSaved(gs); + }, [setGameSystem]); + + useEffect(() => { + fetchGameSystem() + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + + + + + {schemas.map(s => ( + {s.name} + ))} + + Save Game System + + + Accolades + + {gameSystem.accolades.map(a => ( + + {a.name} + {a.description} + + ))} + + + + ) +} \ No newline at end of file diff --git a/project-warstone/src/components/SchemaBuilder/field-type-input.tsx b/project-warstone/src/components/SchemaBuilder/field-type-input.tsx index 05a7854..9a9004d 100644 --- a/project-warstone/src/components/SchemaBuilder/field-type-input.tsx +++ b/project-warstone/src/components/SchemaBuilder/field-type-input.tsx @@ -9,7 +9,7 @@ interface IProps { } export const FieldTypeInput: FCC = ({ bind }) => { - const Schema = useRecoilValue(SchemaEditAtom); + const schema = useRecoilValue(SchemaEditAtom); return ( @@ -19,7 +19,7 @@ export const FieldTypeInput: FCC = ({ bind }) => { {Object.keys(TEMPLATE_TYPES).map(k => ( {k} ))} - {Object.keys(Schema.types).map(k => ( + {Object.keys(schema.types).map(k => ( {k} ))} diff --git a/project-warstone/src/components/SchemaBuilder/index.tsx b/project-warstone/src/components/SchemaBuilder/index.tsx index 23d0bba..4f3a511 100644 --- a/project-warstone/src/components/SchemaBuilder/index.tsx +++ b/project-warstone/src/components/SchemaBuilder/index.tsx @@ -22,7 +22,7 @@ export const SchemaBuilder: FC = () => { const [lastSaved, setLastSaved] = useState(schema); const fetchSchema = useCallback(async () => { - const result = await GameSystemsService.getSchema('') + const result = await GameSystemsService.getSchema('286f4c18-d280-444b-8d7e-9a3dd09f64ef') if (result.status !== 200) return; const fetchedSchema = await result.json(); // if (fetchedSchema.name === schema.name) return; diff --git a/project-warstone/src/components/SchemaBuilder/template-editor.tsx b/project-warstone/src/components/SchemaBuilder/template-editor.tsx index f81cd7a..30082d5 100644 --- a/project-warstone/src/components/SchemaBuilder/template-editor.tsx +++ b/project-warstone/src/components/SchemaBuilder/template-editor.tsx @@ -1,6 +1,9 @@ import { FC, useCallback } from 'react' import { Template } from '../../types/schema'; import { useObjectStateWrapper } from '../../hooks/useObjectState'; +import { TEMPLATE_TYPES } from '../../constants/TemplateTypes'; +import { SchemaEditAtom } from '../../recoil/atoms/schema'; +import { useRecoilValue } from 'recoil'; interface IProps { templateKey: string; @@ -9,7 +12,7 @@ interface IProps { } export const TemplateEditor: FC = ({ templateKey, update, template }) => { - + const schema = useRecoilValue(SchemaEditAtom); const updateTemplate = useCallback((t: Template | ((arg: Template) => Template)) => { update(templateKey, typeof t === 'function' ? t(template) : t) }, [templateKey, update, template]) @@ -22,7 +25,15 @@ export const TemplateEditor: FC = ({ templateKey, update, template }) => Type - + + + {Object.keys(TEMPLATE_TYPES).map(k => ( + {k} + ))} + {Object.keys(schema.types).map(k => ( + {k} + ))} + diff --git a/project-warstone/src/index.css b/project-warstone/src/index.css index 02a28a2..aceae0a 100644 --- a/project-warstone/src/index.css +++ b/project-warstone/src/index.css @@ -11,7 +11,16 @@ input, select { - @apply p-1 rounded-lg text-cinder-500 interactive + @apply p-1 + } + + option { + @apply text-cinder-500 + } + + input:not(.no-default), + select:not(.no-default) { + @apply rounded-lg text-cinder-500 interactive } * { @@ -52,6 +61,7 @@ animation: fade 300ms forwards ease-in; animation-delay: 300ms; } + .fade-out { animation: fade 300ms forwards ease-in reverse; } @@ -63,7 +73,8 @@ from { opacity: 0; } + to { opacity: 1; } -} +} \ No newline at end of file diff --git a/project-warstone/src/recoil/atoms/schema.ts b/project-warstone/src/recoil/atoms/schema.ts index 1a6fdc5..7444eff 100644 --- a/project-warstone/src/recoil/atoms/schema.ts +++ b/project-warstone/src/recoil/atoms/schema.ts @@ -3,5 +3,5 @@ import { Schema } from '../../types/schema'; export const SchemaEditAtom = atom({ key: 'schema-edit', - default: {name: '', types: {}, templates: {}} + default: {name: '', types: {}, templates: {}, id: ''} }); \ No newline at end of file diff --git a/project-warstone/src/services/game-systems.ts b/project-warstone/src/services/game-systems.ts index 5de199c..ec95e1d 100644 --- a/project-warstone/src/services/game-systems.ts +++ b/project-warstone/src/services/game-systems.ts @@ -1,15 +1,18 @@ +import { GameSystem } from '../types/gameSystem'; import { Schema } from '../types/schema'; +const emptySchema = { name: '', types: {}, templates: {}, id: crypto.randomUUID() }; + export const GameSystemsService = { // todo - connect to service to save schema for game saveSchema: async (schema: Schema) => { - localStorage.setItem('schema', JSON.stringify(schema)); + localStorage.setItem('schema ' + schema.id, JSON.stringify(schema)); return { status: 200 } }, // todo - connect to service to fetch schema for game - getSchema: async (id: string): Promise<{status: 200 | 404, json: () => Promise}> => { - const schema = localStorage.getItem('schema'); + getSchema: async (id: string): Promise<{ status: 200 | 404, json: () => Promise }> => { + const schema = localStorage.getItem('schema ' + id); if (schema) return { @@ -19,7 +22,30 @@ export const GameSystemsService = { return { status: 404, - json: async () => ({name:'', types: {}, templates: {}}) + json: async () => (emptySchema) } + }, + getSchemaList: async () => { + return { + status: 200, json: async () => [{ + name: 'Test Schema', + id: '286f4c18-d280-444b-8d7e-9a3dd09f64ef' + }] + } + }, + saveGameSystem: async (gs: GameSystem) => { + localStorage.setItem('game-system ' + gs.id, JSON.stringify(gs)); + return { status: 200 } + }, + getGameSystem: async (id: string): Promise<{ status: 200 | 404, json: () => Promise }> => { + const gs = localStorage.getItem('game-system ' + id); + if (!gs) return {status: 404, json:async () => ({ + accolades: [], + name: '', + id: crypto.randomUUID(), + schema: emptySchema, + schemaId: '' + })} + return { status: 200, json:async () => (JSON.parse(gs))} } } \ No newline at end of file diff --git a/project-warstone/src/types/gameSystem.ts b/project-warstone/src/types/gameSystem.ts new file mode 100644 index 0000000..ecfd07e --- /dev/null +++ b/project-warstone/src/types/gameSystem.ts @@ -0,0 +1,15 @@ +import { Schema } from './schema'; + +export type Accolade = { + id: string; + name: string; + description: string; +} + +export type GameSystem = { + id: string; + schemaId: string; + schema: Schema; + name: string; + accolades: Accolade[]; +} diff --git a/project-warstone/src/types/schema.ts b/project-warstone/src/types/schema.ts index 1aef0e6..9410201 100644 --- a/project-warstone/src/types/schema.ts +++ b/project-warstone/src/types/schema.ts @@ -17,6 +17,7 @@ export type Template = { } export type Schema = { + id: string; name: string; templates: Record; types: Record; diff --git a/project-warstone/yarn.lock b/project-warstone/yarn.lock index e174b6c..f88b193 100644 --- a/project-warstone/yarn.lock +++ b/project-warstone/yarn.lock @@ -630,6 +630,11 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/recoilize@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@types/recoilize/-/recoilize-0.8.0.tgz#7351f7a048bcef9c712f39d05696ce7fd2a414fe" + integrity sha512-h4Rm8J/8XH1wZIZC5gOeN9EDJWBhK2sLEs5voSHyZKB5cynIDbohuYS6rEdv2kNPrwoYQyt7D3yeXI9ODvZDlw== + "@types/scheduler@*": version "0.16.3" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" @@ -1825,6 +1830,11 @@ recoil@^0.7.7: dependencies: hamt_plus "1.0.2" +recoilize@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/recoilize/-/recoilize-3.2.0.tgz#aaf4c76390293a105a73b74dced7a49dfbeb1c84" + integrity sha512-2J0SEzefl8rKe5iaJ2vVg6AgWy5aQ8NFPfZbZfXagycF5ohUzCQA2c2SZDz5jtZfYmendR8hsILstPyofxfg7g== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
Accolades
{a.name}
{a.description}