Compare commits

...

4 Commits

Author SHA1 Message Date
Emma
e78e4304a4 Basic game system editor 2023-06-13 21:21:47 -06:00
Emma
a7337bd33a Default types and templates 2023-06-12 18:02:19 -06:00
Emma
8fb7494464 Fixes dev server issues, adds frontend proxy 2023-06-11 14:15:44 -06:00
Emma
b951d1970d Type editor and schema viewer. Poppables and help icon 2023-06-11 10:25:32 -06:00
45 changed files with 1559 additions and 100 deletions

View File

@ -51,7 +51,7 @@ import {parse, stringify} from 'yaml';
} else if (confirm('Permissions not specified, would you like to add specific permissions?')) {
let permsPrompt: string | null = '';
while (!permsPrompt) {
permsPrompt = prompt('Please enter the permission short code or names of permissions you would like');
permsPrompt = prompt('Please enter the permission short code or names of permissions you would like:');
if (!permsPrompt) continue
let permNames;
if (permsPrompt?.match(' ')) {

View File

@ -11,7 +11,7 @@
"middleware/": "./middleware/"
},
"tasks": {
"dev": "deno run -A startDev.ts",
"dev": "deno run -A --watch startDev.ts",
"createService": "deno run -A createService.ts"
}
}

32
deno.lock generated
View File

@ -580,6 +580,7 @@
"npm": {
"specifiers": {
"bcryptjs": "bcryptjs@2.4.3",
"create-vite-extra": "create-vite-extra@1.1.0",
"mongoose": "mongoose@7.0.4",
"play-sound": "play-sound@1.1.5",
"yaml": "yaml@2.2.2"
@ -608,6 +609,14 @@
"integrity": "sha512-HevkSpDbpUfsrHWmWiAsNavANKYIErV2ePXllp1bwq5CDreAaFVj6RVlZpJnxK4WWDCJ/5jMUpaY6G526q3Hjg==",
"dependencies": {}
},
"create-vite-extra@1.1.0": {
"integrity": "sha512-Gi5ZLFhgULy6DU9QpZZ6ko4STOrg5dT4/2sCqszjoMZTSyQl1B95eiZaeByBGt+HCSffXAFvhSzkt5iqlqW6eA==",
"dependencies": {
"kolorist": "kolorist@1.8.0",
"minimist": "minimist@1.2.8",
"prompts": "prompts@2.4.2"
}
},
"debug@4.3.4": {
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": {
@ -626,10 +635,22 @@
"integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==",
"dependencies": {}
},
"kleur@3.0.3": {
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
"dependencies": {}
},
"kolorist@1.8.0": {
"integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
"dependencies": {}
},
"memory-pager@1.5.0": {
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
"dependencies": {}
},
"minimist@1.2.8": {
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dependencies": {}
},
"mongodb-connection-string-url@2.6.0": {
"integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==",
"dependencies": {
@ -682,6 +703,13 @@
"find-exec": "find-exec@1.0.2"
}
},
"prompts@2.4.2": {
"integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
"dependencies": {
"kleur": "kleur@3.0.3",
"sisteransi": "sisteransi@1.0.5"
}
},
"punycode@2.3.0": {
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
"dependencies": {}
@ -696,6 +724,10 @@
"integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==",
"dependencies": {}
},
"sisteransi@1.0.5": {
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
"dependencies": {}
},
"smart-buffer@4.2.0": {
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
"dependencies": {}

View File

@ -22,3 +22,7 @@ services:
build:
context: ./
dockerfile: ./game-systems-service/Dockerfile
warstone-web:
build:
context: ./
dockerfile: ./warstone-web-service/Dockerfile

7
middleware/debugLog.ts Normal file
View File

@ -0,0 +1,7 @@
import { Context, Middleware } from "oak";
export const debugLog = (message: string | ((arg: Context) => string)): Middleware =>
async (ctx, next) => {
console.log(typeof message === 'function' ? message(ctx) : message);
await next();
}

View File

@ -10,5 +10,12 @@ module.exports = {
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': 'warn',
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_"
}
],
},
}

View File

@ -7,17 +7,21 @@
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
"preview": "vite preview",
"build-dev": "vite build"
},
"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",
"tailwindcss": "^3.3.2"
"recoilize": "^3.2.0",
"tailwindcss": "^3.3.2",
"vite-plugin-svgr": "^3.2.0"
},
"devDependencies": {
"@types/react": "^18.0.37",

View File

@ -1,12 +1,14 @@
import { RecoilRoot } from 'recoil'
import { TextMapper } from './components/Importer/text-mapper'
import { SchemaBuilder } from './components/SchemaBuilder'
import { GameSystemEditor } from './components/GameSystemEditor'
import RecoilizeDebugger from 'recoilize';
function App() {
return (
<RecoilRoot>
{/* <TextMapper /> */}
<SchemaBuilder />
<RecoilizeDebugger />
{/* <SchemaBuilder /> */}
<GameSystemEditor />
</RecoilRoot>
)
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" stroke="#fff" fill="#fff" height="28" width="28"><circle stroke-width="3" fill="none" stroke="inherit" r="12.5" cy="14" cx="14"/><path fill="inherit" d="M12.004 17.816v-.867c0-.531.074-1 .223-1.406.148-.414.386-.805.714-1.172.328-.375.762-.758 1.301-1.148.485-.344.871-.653 1.16-.926.297-.274.512-.543.645-.809.14-.273.21-.582.21-.925 0-.508-.187-.895-.562-1.16-.375-.266-.898-.4-1.57-.4s-1.34.106-2.004.317c-.656.211-1.324.489-2.004.832L8.84 7.586c.781-.438 1.629-.79 2.543-1.055.914-.273 1.914-.41 3-.41 1.672 0 2.965.402 3.879 1.207.922.797 1.382 1.813 1.382 3.047 0 .656-.105 1.227-.316 1.71a4.165 4.165 0 01-.937 1.337c-.414.406-.934.836-1.559 1.289-.469.344-.828.633-1.078.867-.25.235-.422.469-.516.703a2.356 2.356 0 00-.129.832v.703zm-.375 4.008c0-.734.2-1.25.598-1.547.406-.297.894-.445 1.464-.445.555 0 1.032.148 1.43.445.406.297.61.813.61 1.547 0 .703-.204 1.211-.61 1.524-.398.312-.875.468-1.43.468-.57 0-1.058-.156-1.464-.468-.399-.313-.598-.82-.598-1.524z"/></svg>

After

Width:  |  Height:  |  Size: 1017 B

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="Help Icon.svg"
id="svg6"
version="1.1"
viewBox="0 0 28 28"
stroke="#ffffff"
fill="#ffffff"
height="28"
width="28">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
inkscape:current-layer="svg6"
inkscape:window-maximized="1"
inkscape:window-y="1432"
inkscape:window-x="-8"
inkscape:cy="14"
inkscape:cx="14"
inkscape:zoom="27.222222"
fit-margin-bottom="0"
fit-margin-right="0"
fit-margin-left="0"
fit-margin-top="0"
showgrid="false"
id="namedview8"
inkscape:window-height="1369"
inkscape:window-width="3440"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" />
<circle
id="circle2"
stroke-width="3"
fill="none"
stroke="inherit"
r="12.5"
cy="14"
cx="14" />
<!-- <path d="M0.5,13.5a12.5,12.5 0 1,0 25,0a12.5,12.5 0 1,0 -25,0" fill="none" stroke="inherit" /> -->
<path
id="path4"
fill="inherit"
d="m 12.0039,17.8164 v -0.8672 c 0,-0.5312 0.0742,-1 0.2227,-1.4062 0.1484,-0.4141 0.3867,-0.8047 0.7148,-1.1719 0.3281,-0.375 0.7617,-0.7578 1.3008,-1.1484 0.4844,-0.3438 0.8711,-0.6524 1.1601,-0.9258 0.2969,-0.2735 0.5118,-0.543 0.6446,-0.8086 0.1406,-0.2735 0.2109,-0.5821 0.2109,-0.9258 0,-0.50781 -0.1875,-0.89453 -0.5625,-1.16016 -0.375,-0.26562 -0.8984,-0.39843 -1.5703,-0.39843 -0.6719,0 -1.3398,0.10547 -2.0039,0.3164 -0.6563,0.21094 -1.3242,0.48828 -2.00391,0.83203 L 8.83984,7.58594 c 0.78125,-0.4375 1.62891,-0.78906 2.54296,-1.05469 0.9141,-0.27344 1.9141,-0.41016 3,-0.41016 1.6719,0 2.9649,0.40235 3.8789,1.20703 0.9219,0.79688 1.3828,1.8125 1.3828,3.04688 0,0.6562 -0.1054,1.2266 -0.3164,1.7109 -0.2031,0.4766 -0.5156,0.9219 -0.9375,1.336 -0.414,0.4062 -0.9336,0.8359 -1.5586,1.289 -0.4687,0.3438 -0.8281,0.6329 -1.0781,0.8672 -0.25,0.2344 -0.4219,0.4688 -0.5156,0.7031 -0.086,0.2266 -0.1289,0.504 -0.1289,0.8321 v 0.7031 z m -0.375,4.0078 c 0,-0.7344 0.1992,-1.25 0.5977,-1.5469 0.4062,-0.2968 0.8945,-0.4453 1.4648,-0.4453 0.5547,0 1.0313,0.1485 1.4297,0.4453 0.4062,0.2969 0.6094,0.8125 0.6094,1.5469 0,0.7031 -0.2032,1.211 -0.6094,1.5235 -0.3984,0.3125 -0.875,0.4687 -1.4297,0.4687 -0.5703,0 -1.0586,-0.1562 -1.4648,-0.4687 -0.3985,-0.3125 -0.5977,-0.8204 -0.5977,-1.5235 z" />
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="Help Icon.svg"
id="svg6"
version="1.1"
viewBox="0 0 28 28"
stroke="#ffffff"
fill="#ffffff"
height="28"
width="28">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
inkscape:current-layer="svg6"
inkscape:window-maximized="1"
inkscape:window-y="1432"
inkscape:window-x="-8"
inkscape:cy="14"
inkscape:cx="14"
inkscape:zoom="27.222222"
fit-margin-bottom="0"
fit-margin-right="0"
fit-margin-left="0"
fit-margin-top="0"
showgrid="false"
id="namedview8"
inkscape:window-height="1369"
inkscape:window-width="3440"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" />
<circle
id="circle2"
stroke-width="3"
fill="none"
stroke="inherit"
r="12.5"
cy="14"
cx="14" />
<!-- <path d="M0.5,13.5a12.5,12.5 0 1,0 25,0a12.5,12.5 0 1,0 -25,0" fill="none" stroke="inherit" /> -->
<path
id="path4"
fill="inherit"
d="m 12.0039,17.8164 v -0.8672 c 0,-0.5312 0.0742,-1 0.2227,-1.4062 0.1484,-0.4141 0.3867,-0.8047 0.7148,-1.1719 0.3281,-0.375 0.7617,-0.7578 1.3008,-1.1484 0.4844,-0.3438 0.8711,-0.6524 1.1601,-0.9258 0.2969,-0.2735 0.5118,-0.543 0.6446,-0.8086 0.1406,-0.2735 0.2109,-0.5821 0.2109,-0.9258 0,-0.50781 -0.1875,-0.89453 -0.5625,-1.16016 -0.375,-0.26562 -0.8984,-0.39843 -1.5703,-0.39843 -0.6719,0 -1.3398,0.10547 -2.0039,0.3164 -0.6563,0.21094 -1.3242,0.48828 -2.00391,0.83203 L 8.83984,7.58594 c 0.78125,-0.4375 1.62891,-0.78906 2.54296,-1.05469 0.9141,-0.27344 1.9141,-0.41016 3,-0.41016 1.6719,0 2.9649,0.40235 3.8789,1.20703 0.9219,0.79688 1.3828,1.8125 1.3828,3.04688 0,0.6562 -0.1054,1.2266 -0.3164,1.7109 -0.2031,0.4766 -0.5156,0.9219 -0.9375,1.336 -0.414,0.4062 -0.9336,0.8359 -1.5586,1.289 -0.4687,0.3438 -0.8281,0.6329 -1.0781,0.8672 -0.25,0.2344 -0.4219,0.4688 -0.5156,0.7031 -0.086,0.2266 -0.1289,0.504 -0.1289,0.8321 v 0.7031 z m -0.375,4.0078 c 0,-0.7344 0.1992,-1.25 0.5977,-1.5469 0.4062,-0.2968 0.8945,-0.4453 1.4648,-0.4453 0.5547,0 1.0313,0.1485 1.4297,0.4453 0.4062,0.2969 0.6094,0.8125 0.6094,1.5469 0,0.7031 -0.2032,1.211 -0.6094,1.5235 -0.3984,0.3125 -0.875,0.4687 -1.4297,0.4687 -0.5703,0 -1.0586,-0.1562 -1.4648,-0.4687 -0.3985,-0.3125 -0.5977,-0.8204 -0.5977,-1.5235 z" />
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -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<GameSystem>({
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 (
<div className="container p-8">
<div className="flex gap-1">
<input className="no-default text-white bg-transparent header border-b-2 border-falcon w-1/2" type="text" {...bindGameSystemProperty('name')} placeholder="Game Name" />
<select className="no-default text-white bg-transparent header border-b-2 border-falcon" {...bindGameSystemProperty('schemaId')}>
<option value=""></option>
{schemas.map(s => (
<option value={s.id}>{s.name}</option>
))}
</select>
<button onClick={saveGameSystem} disabled={lastSaved === gameSystem}>Save Game System</button>
</div>
<div>
<p>Accolades</p>
<div className="grid grid-cols-3">
{gameSystem.accolades.map(a => (
<div>
<p>{a.name}</p>
<p>{a.description}</p>
</div>
))}
</div>
</div>
</div>
)
}

View File

@ -0,0 +1,19 @@
import { FC } from 'react'
import { ReactComponent as help } from '../../assets/icons/Help Icon.svg';
const library = {
help
}
interface IProps {
className: string;
icon: keyof typeof library;
}
export const Icon: FC<IProps> = ({ className, icon }) => {
const ICON = library[icon];
return (
<ICON className={className} />
)
}

View File

@ -0,0 +1,16 @@
import { FC, PropsWithChildren } from 'react'
import { Poppable } from '../../lib/poppables/components/poppable'
import { Icon } from '../Icon'
export const HelpPopper: FC<PropsWithChildren> = ({children}) => {
return (
<Poppable
content={children}
preferredAlign="centered"
preferredEdge="bottom"
>
<Icon icon="help" className="svg-white w-4 h-4" />
</Poppable>
)
}

View File

@ -1,9 +1,8 @@
import { FC, useCallback, useEffect } from 'react'
import { FieldType, FieldTypes, fieldTypeOptions, fieldTypesWithValues } from '../../types/schema'
import { useObjectStateWrapper } from '../../hooks/useObjectState';
import { FieldTypeInput } from './field-type-input';
import { InputBinder } from '../../types/inputBinder';
import { ValueField } from './value-field';
import { HelpPopper } from '../Poppables/help';
interface IProps {
update: (arg: FieldType) => void;
@ -12,7 +11,7 @@ interface IProps {
}
export const FieldEditor: FC<IProps> = ({ update, field, fieldName }) => {
const { update: updateField, bindProperty, bindPropertyCheck } = useObjectStateWrapper(field, (e) => update(typeof e === 'function' ? e(field) : e))
const { bindProperty, bindPropertyCheck } = useObjectStateWrapper(field, (e) => update(typeof e === 'function' ? e(field) : e))
const shouldShowValueField = useCallback(() => fieldTypesWithValues.includes(field.type) || field.isConstant, [field.isConstant, field.type]);
@ -21,33 +20,31 @@ export const FieldEditor: FC<IProps> = ({ update, field, fieldName }) => {
}, [field])
return (
<li className="odd:bg-black/50 flex gap-4 items-center p-2">
<li className="odd:bg-black/50">
<p>{fieldName}</p>
<select className="capitalize" {...bindProperty('type')}>
{fieldTypeOptions.map(o => (
<option className="capitalize" value={FieldTypes[o]}>{o}</option>
))}
</select>
{shouldShowValueField() && (
// <>
// {field.type === FieldTypes.dice && (
// <label>
// Sides:&nbsp;
// <select {...bindProperty('value')}>
// {diceSides.map(d => (
// <option value={'d' + d}>{d}</option>
// ))}
// </select>
// </label>
// )}
// {field.type === FieldTypes.type && (
// <FieldTypeInput bind={bindProperty('value')} />
// )}
// </>
<ValueField type={field.type} bind={bindProperty('value')} />
)}
<label><input type="checkbox" {...bindPropertyCheck('isConstant')} /> Is constant</label>
<div className=" flex gap-x-4 items-center p-2">
<label className="w-min">
Field Type:&nbsp;
<select className="capitalize" {...bindProperty('type')}>
{fieldTypeOptions.map(o => (
<option className="capitalize" value={FieldTypes[o]}>{o}</option>
))}
</select>
</label>
{shouldShowValueField() && (
<ValueField type={field.type} bind={bindProperty('value')} />
)}
<span className="flex items-center gap-2">
<label><input type="checkbox" {...bindPropertyCheck('isConstant')} /> Is constant</label>
<HelpPopper>
<p className="text-sm">Constant values can't be overwritten in publications. When a dice field is set to a constant value, it instead rolls a dice of that value whenever this field is displayed (unless exported). This could be useful for a randomly generated scenario or for cards being drawn as the dice value will automatically be determined by the dice roll.</p>
</HelpPopper>
</span>
<label className="w-min">
Limit:
<input className="w-12" type="number" {...bindProperty('limit')} />
</label>
</div>
</li>
)
}

View File

@ -2,22 +2,27 @@ import { useRecoilValue } from 'recoil';
import { SchemaEditAtom } from '../../recoil/atoms/schema';
import { FCC } from '../../types'
import { InputBinder } from '../../types/inputBinder'
import { TEMPLATE_TYPES } from '../../constants/TemplateTypes';
interface IProps {
bind: InputBinder
}
export const FieldTypeInput: FCC<IProps> = ({ bind }) => {
const Schema = useRecoilValue(SchemaEditAtom);
const schema = useRecoilValue(SchemaEditAtom);
return (
<>
<label className="w-min">
Type:
<input type="text" {...bind} list="type-editor-type-list" />
<optgroup id="type-editor-type-list">
{Object.keys(Schema.types).map(k => (
<datalist id="type-editor-type-list">
{Object.keys(TEMPLATE_TYPES).map(k => (
<option className="capitalize" value={k}>{k}</option>
))}
</optgroup>
</>
{Object.keys(schema.types).map(k => (
<option className="capitalize" value={k}>{k}</option>
))}
</datalist>
</label>
)
}

View File

@ -1,44 +1,125 @@
import { FC, useCallback, useState } from 'react'
import { FC, useCallback, useEffect, useState } from 'react'
import AnimatedPageContainer from '../AnimatedPageContainer';
import { TypeEditor } from './type-editor';
import { useObjectState, useObjectStateWrapper } from '../../hooks/useObjectState';
import { Schema, TypeType } from '../../types/schema';
import { FieldTypes, Schema, Template, TypeType } from '../../types/schema';
import { useInput } from '../../hooks/useInput';
import { useRecoilState } from 'recoil';
import { SchemaEditAtom } from '../../recoil/atoms/schema';
import { GameSystemsService } from '../../services/game-systems';
import { SchemaViewer } from './schema-viewer';
import { TemplateEditor } from './template-editor';
export const SchemaBuilder: FC = () => {
const [schema, setSchema] = useRecoilState(SchemaEditAtom);
const {update: updateSchema} = useObjectStateWrapper<Schema>(schema, setSchema);
const { update: updateSchema } = useObjectStateWrapper<Schema>(schema, setSchema);
const {value: typeName, bind: bindTypeName, reset: resetTypeName} = useInput('');
const { value: typeName, bind: bindTypeName, reset: resetTypeName } = useInput('');
const [pageNumber, setPageNumber] = useState(1);
const [pageNumber, setPageNumber] = useState(0);
const [lastSaved, setLastSaved] = useState(schema);
const fetchSchema = useCallback(async () => {
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;
if (!fetchedSchema.templates) fetchedSchema.templates = {}
setSchema(fetchedSchema);
setLastSaved(fetchedSchema);
}, [setSchema])
useEffect(() => {
fetchSchema();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
const [selectedType, setSelectedType] = useState('');
const saveType = useCallback((name: string, type: TypeType) => {
updateSchema(e => ({
types: {
...e.types,
[name]: type
}
}));
resetTypeName();
setPageNumber(0);
setSelectedType('');
}, [resetTypeName, updateSchema]);
const saveSchema = useCallback(() => {
GameSystemsService.saveSchema(schema);
setLastSaved(schema);
}, [schema])
const selectTypeForEdit = useCallback((typeKey: string) => {
setSelectedType(typeKey);
setPageNumber(1);
}, [])
const { value: templateName, bind: bindTemplateName, reset: resetTemplateName } = useInput('');
const addTemplate = useCallback(() => {
updateSchema(s => ({
templates: {
...s.templates,
[templateName]: {
publishable: false,
type: FieldTypes.any
}
}
}));
resetTemplateName();
}, [resetTemplateName, templateName, updateSchema])
const updateTemplate = useCallback((key: string, template: Template) => {
updateSchema(s => ({
templates: {
...s.templates,
[key]: template
}
}))
}, [updateSchema])
return (
<div className="container flex gap-4 p-8">
<div className="panel w-2/3 h-full">
<p className="subheader">Add a template</p>
<input type="text" {...bindTemplateName} />
<button onClick={addTemplate} disabled={!templateName}>Add</button>
<ul>
{Object.entries(schema.templates).map(([templateKey, template]) => (
<TemplateEditor templateKey={templateKey} template={template} update={updateTemplate} />
))}
</ul>
<AnimatedPageContainer currentPage={pageNumber}>
<div>
<p className="subheader">Add A Type</p>
<p className="subheader">Add a type</p>
<input type="text" {...bindTypeName} />
<button className="interactive" disabled={!typeName} onClick={() => setPageNumber(1)}>Configure</button>
</div>
<TypeEditor name={typeName} saveType={saveType} />
<TypeEditor name={selectedType || typeName} saveType={saveType} type={selectedType ? schema.types[selectedType as keyof typeof schema.types] : undefined} />
</AnimatedPageContainer>
</div>
<div className="panel w-1/3 whitespace-pre-wrap">
{JSON.stringify(schema, null, 2)}
<div className="panel basis-1/3">
<SchemaViewer schema={schema} onTypeClick={selectTypeForEdit} />
<div className="flex gap-2 mt-2">
<button
onClick={saveSchema}
disabled={lastSaved === schema}
>
Save Schema
</button>
<button
className="bg-red-800"
onClick={() => setSchema(lastSaved)}
disabled={lastSaved === schema}
>
Discard Changes
</button>
</div>
</div>
</div>
)

View File

@ -0,0 +1,66 @@
import { FC, useCallback } from 'react'
import { FieldType, FieldTypes, Schema, TypeType, fieldTypesWithValues } from '../../types/schema'
interface IProps {
schema: Schema;
onTypeClick?: (arg: string, arg1: TypeType) => void;
}
export const SchemaViewer: FC<IProps> = ({ schema, onTypeClick }) => {
const createValueLable = useCallback((field: FieldType) => {
if (field.isConstant) {
if (field.type === FieldTypes.dice) return 'Auto-rolled'
return 'Constant value:'
}
switch (field.type) {
case FieldTypes.type: return 'Type:'
case FieldTypes.dice: return 'Dice:'
default: return '';
}
}, [])
return (
<>
{/* <div className="whitespace-pre-wrap">{JSON.stringify(schema, null, 2)}</div> */}
<div>
<p className="font-bold text-lg">{schema.name}</p>
<hr />
<p className="font-bold italic">Templates</p>
<ul>
{Object.entries(schema.templates).map(([templateKey, template]) => (
<li>
<p className="font-bold">{templateKey}</p>
<p className="font-thin text-xs">{template.type}</p>
{template.publishable && <p className="font-thin text-xs">This template can create publications</p>}
</li>
))}
</ul>
<hr />
<p className="font-bold italic">Types</p>
<ul className="rounded-lg overflow-hidden">
{Object.entries(schema.types).map(([typeKey, type]) => (
<li
key={'type viewer' + typeKey}
onClick={() => onTypeClick && onTypeClick(typeKey, type)}
data-clickable={!!onTypeClick}
className="odd:bg-black/50 p-2 data-[clickable=true]:cursor-pointer"
>
<p className="mb-2 font-bold">{typeKey}</p>
<div className="grid grid-cols-3 gap-2">
{Object.entries(type).map(([fieldKey, field]) => (
<div key={'field viewer' + fieldKey} className="rounded-lg border border-olive-drab p-2">
<p className="font-bold">{fieldKey}</p>
<p className="font-thin capitalize text-xs">{field.type}</p>
<p className="font-thin capitalize text-xs">Maximum entries: {field.limit === 0 ? 'unlimited ' : field.limit}</p>
{(field.isConstant || fieldTypesWithValues.includes(field.type)) && <p className="font-thin capitalize text-xs">{createValueLable(field)} {field.value}</p>}
</div>
))}
</div>
</li>
))}
</ul>
</div>
</>
)
}

View File

@ -0,0 +1,45 @@
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;
update: (arg0: string, arg1: Template) => void;
template: Template
}
export const TemplateEditor: FC<IProps> = ({ 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])
const { bindProperty, bindPropertyCheck } = useObjectStateWrapper(template, updateTemplate)
return (
<li>
<p className="font-bold">{templateKey}</p>
<div className="flex gap-4">
<label className="w-min">
Type
<input type="text" {...bindProperty('type')} list="type-editor-type-list" />
<datalist id="type-editor-type-list">
{Object.keys(TEMPLATE_TYPES).map(k => (
<option className="capitalize" value={k}>{k}</option>
))}
{Object.keys(schema.types).map(k => (
<option className="capitalize" value={k}>{k}</option>
))}
</datalist>
</label>
<label>
<input type="checkbox" {...bindPropertyCheck('publishable')} />
Can create publications
</label>
</div>
</li>
)
}

View File

@ -1,4 +1,4 @@
import { FC, useCallback } from 'react'
import { FC, useCallback, useEffect } from 'react'
import { FCC } from '../../types'
import { FieldType, FieldTypes, TypeType } from '../../types/schema'
import { useObjectState } from '../../hooks/useObjectState';
@ -8,12 +8,13 @@ import { FieldEditor } from './field-editor';
interface IProps {
name: string;
saveType: (arg0: string, arg1: TypeType) => void;
type?: TypeType
}
const constantProperties = ['metadata'];
export const TypeEditor: FCC<IProps> = ({ saveType, name }) => {
const { update: updateType, reset: resetType, state: type } = useObjectState<TypeType>({});
export const TypeEditor: FCC<IProps> = ({ saveType, name, type: passedType }) => {
const { update: updateType, reset: resetType, state: type, setState: setType } = useObjectState<TypeType>({});
const { value: propertyName, setValue: setPropertyName, bind: bindPropertyName, reset: resetPropertyName } = useInput('');
@ -30,23 +31,31 @@ export const TypeEditor: FCC<IProps> = ({ saveType, name }) => {
isConstant: false,
limit: 1,
}
})
}, [propertyName, updateType])
});
resetPropertyName();
}, [propertyName, updateType, resetPropertyName]);
const updateField = useCallback((k: keyof typeof type) => (field: FieldType) => {
updateType({ [k]: field })
}, [updateType])
}, [updateType]);
useEffect(() => {
passedType && setType(passedType);
}, [passedType, setType]);
return (
<div>
<p className="subheader">Creating type "{name}"</p>
<p className="subheader">{passedType ? 'Editing' : 'Creating'} type "{name}"</p>
<input type="text" {...bindPropertyName} />
<button disabled={!propertyName} onClick={addField}>Add Field</button>
<ul>
<ul className="rounded-lg overflow-hidden">
{Object.entries(type).filter(([k]) => !constantProperties.includes(k)).map(([key, value]) => (
<FieldEditor field={value} update={updateField(key)} fieldName={key} />
))}
</ul>
<div>
<button onClick={save} disabled={!Object.keys(type).length}>Save Type</button>
</div>
</div>
)
}

View File

@ -1,37 +1,68 @@
import { FC } from 'react';
import { ChangeEvent, EventHandler, FC, useCallback, useEffect, useRef } from 'react';
import { FieldTypes } from '../../types/schema';
import { InputBinder } from '../../types/inputBinder';
import { FieldTypeInput } from './field-type-input';
import { useInput } from '../../hooks/useInput';
interface IValueProps {
type: FieldTypes;
bind: InputBinder;
}
const diceSides = [3, 4, 6, 8, 10, 12, 20, 100];
const DICE_SIDES = [3, 4, 6, 8, 10, 12, 20, 100];
export const ValueField: FC<IValueProps> = ({ type, bind }) => {
const { value: diceCount, bind: bindDiceCount } = useInput(1);
const { value: diceSides, bind: bindDiceSides } = useInput('');
const diceInputRef = useRef<HTMLInputElement>(null);
export const ValueField: FC<IValueProps> = ({type, bind}) => {
switch (type) {
case FieldTypes.dice:
case FieldTypes.dice: {
const onChange = (handler: (arg: ChangeEvent<HTMLInputElement | HTMLSelectElement>) => void) => (e: ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
handler(e)
setTimeout(() => {
if (!diceInputRef.current) return;
e.target = diceInputRef.current;
bind.onChange(e);
}, 0)
}
return (
<label>
Sides:&nbsp;
<select {...bind}>
{diceSides.map(d => (
<option value={'d' + d}>{d}</option>
))}
</select>
</label>
<>
<label className="w-min">
Count:&nbsp;
<input className="w-12" type="number" {...bindDiceCount}
onChange={onChange(bindDiceCount.onChange)}
/>
</label>
<label className="w-min">
Sides:&nbsp;
<select {...bindDiceSides}
onChange={onChange(bindDiceSides.onChange)}
>
<option value=""></option>
{DICE_SIDES.map(d => (
<option value={'d' + d}>{d}</option>
))}
</select>
</label>
<input ref={diceInputRef} className="hidden" type="text" name={bind.name} value={diceCount + diceSides} readOnly />
</>
);
}
case FieldTypes.type:
return (
<FieldTypeInput bind={bind} />
)
case FieldTypes.number:
return (
<input type="number" {...bind} />
<label className="w-min">Value:<input className="w-16" type="number" {...bind} /></label>
)
case FieldTypes.text:
return (
<label className="w-min">Value:<input type="number" {...bind} /></label>
)
default:
return <></>;
return <></>;
}
}

View File

@ -0,0 +1,70 @@
import { FieldTypes, TypeType } from '../types/schema';
export const TEMPLATE_TYPES: Record<string, TypeType> = {
section: {
name: {
isConstant: false,
limit: 1,
type: FieldTypes.text,
value: ''
},
body: {
isConstant: false,
limit: 0,
type: FieldTypes['long text'],
value: ''
},
},
steps: {
steps: {
isConstant: false,
limit: 0,
type: FieldTypes.type,
value: 'section'
}
},
image: {
name: {
isConstant: false,
limit: 1,
type: FieldTypes.text,
value: ''
},
link: {
isConstant: false,
limit: 1,
type: FieldTypes.text,
value: ''
},
},
list: {
items: {
isConstant: false,
limit: 0,
type: FieldTypes['long text'],
value: ''
}
},
tableRow: {
columns: {
isConstant: false,
limit: 0,
type: FieldTypes.any,
value: ''
}
},
table: {
rows: {
isConstant: false,
limit: 0,
type: FieldTypes.type,
value: 'tableRow'
},
header: {
isConstant: false,
limit: 1,
type: FieldTypes.type,
value: 'tableRow'
}
}
};

View File

@ -0,0 +1,12 @@
import { useEffect, useState } from 'react';
export const useDebounce = (value: any, delay: number) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
};

View File

@ -1,3 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Chakra+Petch:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&family=Open+Sans:ital,wght@0,300;0,400;0,500;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&family=Orbitron:wght@400;500;600;700;800;900&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;
@ -6,8 +8,23 @@
body {
@apply bg-bastille text-white
}
input, select {
@apply p-1 rounded-lg text-cinder-500
input,
select {
@apply p-1
}
option {
@apply text-cinder-500
}
input:not(.no-default),
select:not(.no-default) {
@apply rounded-lg text-cinder-500 interactive
}
* {
font-family: 'Open Sans', sans-serif;
}
}
@ -15,25 +32,49 @@
.panel {
@apply bg-cinder shadow-xl p-8 rounded-xl
}
.header {
@apply text-2xl font-bold
}
.subheader {
@apply text-xl font-bold
}
button {
@apply interactive bg-olive-drab p-1
}
}
@layer utilities {
.interactive {
@apply border-2 rounded-lg border-falcon cursor-pointer
}
.interactive svg {
@apply fill-falcon
}
.interactive:disabled {
@apply border-falcon-300 brightness-50 cursor-default
}
.fade-in {
animation: fade 300ms forwards ease-in;
animation-delay: 300ms;
}
.fade-out {
animation: fade 300ms forwards ease-in reverse;
}
}
@layer utilities {}
@keyframes fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

View File

@ -0,0 +1,117 @@
import { Dispatch, SetStateAction, useCallback, useEffect, useState } from 'react';
import { FCC } from '../../../types';
import { bulkRound } from '../../utils/bulkRound';
import { clamp } from '../../utils/clamp';
import { Portal } from '../../portal/components';
type edge = 'top' | 'bottom' | 'left' | 'right';
type alignment = edge | 'centered';
interface IProps {
preferredEdge: edge;
preferredAlign: alignment;
relativeElement: HTMLElement;
spacing?: number;
isClosing: boolean;
isClosed: boolean;
setHover: Dispatch<SetStateAction<boolean>>;
}
type position = { top: number, left: number, width?: number };
export const PoppableContent: FCC<IProps> = ({ preferredAlign, preferredEdge, children, relativeElement, spacing = 10, setHover, isClosing, isClosed }) => {
const [popRef, setPopRef] = useState<HTMLDivElement>();
const updateRef = useCallback((node: HTMLDivElement) => {
if (!node) return;
setPopRef(node);
}, [])
const getAlignment = useCallback((relX: number, relY: number, relWidth: number, relHeight: number, popWidth: number, popHeight: number, edge: edge, align: alignment): position => {
const pos = {
top: relY,
left: relX,
}
switch (align) {
case 'centered':
pos.top = relY + (relHeight / 2) - (popHeight / 2);
pos.left = relX + (relWidth / 2) - (popWidth / 2);
break;
case 'top':
pos.top = relY;
break;
case 'bottom':
pos.top = relY + relHeight - popHeight;
break;
case 'left':
pos.left = relX;
break;
case 'right':
pos.left = relX + relWidth - popWidth;
break;
}
return pos;
}, [])
const getPosition = useCallback((popWidth: number, popHeight: number, edge: edge, align: alignment) => {
const rel = relativeElement.getBoundingClientRect();
const [relX, relY, relWidth, relHeight] = bulkRound(rel.x, rel.y, rel.width, rel.height);
const pos: position = { top: 100, left: 100 };
const alignment = getAlignment(relX, relY, relWidth, relHeight, popWidth, popHeight, edge, align);
switch (edge) {
case 'top':
pos.top = relY - popHeight - spacing + document.documentElement.scrollTop;
pos.left = alignment.left;
break;
case 'bottom':
pos.top = relY + relHeight + spacing + document.documentElement.scrollTop;
pos.left = alignment.left;
break;
case 'left':
pos.left = relX - popWidth - spacing;
pos.top = alignment.top + document.documentElement.scrollTop;
break;
case 'right':
pos.left = relX + relWidth + spacing;
pos.top = alignment.top + document.documentElement.scrollTop;
break;
}
return pos;
}, [getAlignment, relativeElement, spacing])
const getClampedPosition = useCallback(() => {
if (!popRef) return { opacity: 0 }
const pop = popRef.getBoundingClientRect();
const [popWidth, popHeight] = bulkRound(pop.width, pop.height);
const pos = getPosition(popWidth, popHeight, preferredEdge, preferredAlign);
const { innerHeight, innerWidth } = window;
pos.top = ['left', 'right'].includes(preferredEdge) ? clamp(pos.top, spacing, innerHeight - popHeight - spacing) : pos.top;
pos.left = ['top', 'bottom'].includes(preferredEdge) ? clamp(pos.left, spacing, innerWidth - popWidth - spacing): pos.left;
return pos;
}, [popRef, getPosition, preferredEdge, preferredAlign, spacing])
return (
<Portal>
<div
ref={updateRef}
style={getClampedPosition()}
data-fading={isClosing}
data-visible={!isClosing}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
// className="absolute w-[400px] border"
className="bg-cinder border-2 border-falcon p-2 rounded-lg absolute transition-opacity data-[visible=true]:z-10 data-[visible=true]:opacity-100 data-[visible=false]:opacity-0 -z-10 max-w-[400px]"
>
{children}
</div>
</Portal>
)
}

View File

@ -0,0 +1,47 @@
import { FC, ReactNode, useCallback, useEffect, useState } from 'react'
import { PoppableContent } from './poppable-content';
import { FCC } from '../../../types';
import { useDebounce } from '../../../hooks/useDebounce';
interface IProps {
content: ReactNode;
className?: string;
preferredEdge: 'top' | 'bottom' | 'left' | 'right';
preferredAlign: 'centered' | 'top' | 'bottom' | 'left' | 'right';
spacing?: number;
}
export const Poppable: FCC<IProps> = ({ className, content, children, preferredEdge, preferredAlign, spacing }) => {
const [isHovered, setIsHovered] = useState(false);
const closing = useDebounce(!isHovered, 1000);
const closed = useDebounce(closing, 300);
const [ref, setRef] = useState<HTMLElement>();
const updateRef = useCallback((node: HTMLElement) => {
if (!node) return;
setRef(node)
}, [])
return (
<>
<span
ref={updateRef}
className={className}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{children}
</span>
{!!ref && <PoppableContent
preferredAlign={preferredAlign}
preferredEdge={preferredEdge}
spacing={spacing}
isClosing={closing}
isClosed={closed}
relativeElement={ref}
setHover={setIsHovered}
>{content}</PoppableContent>}
</>
)
}

View File

@ -0,0 +1,26 @@
import { useEffect, useState } from 'react';
import { FCC } from '../../../types';
import { createPortal } from 'react-dom';
interface IProps {
className?: string;
el?: string;
}
export const Portal: FCC<IProps> = ({ children, className = 'root-portal', el = 'div' }) => {
const [container] = useState(() => {
// This will be executed only on the initial render
// https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
return document.createElement(el);
});
useEffect(() => {
container.classList.add(className);
document.body.appendChild(container);
return () => {
document.body.removeChild(container);
}
}, [className, container]);
return createPortal(children, container);
}

View File

@ -0,0 +1 @@
export const bulkRound = (...args: number[]): number[] => args.map(n => Math.round(n));

View File

@ -0,0 +1,2 @@
export const clamp = (value: number, min: number, max: number) =>
Math.max(Math.min(value, max), min)

View File

@ -1,7 +1,7 @@
import { atom } from 'recoil';
import { Schema, TypeType } from '../../types/schema';
import { Schema } from '../../types/schema';
export const SchemaEditAtom = atom<Schema>({
key: 'schema-edit',
default: {name: '', types: {}}
default: {name: '', types: {}, templates: {}, id: ''}
});

View File

@ -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) => {
const schema = localStorage.getItem('schema');
getSchema: async (id: string): Promise<{ status: 200 | 404, json: () => Promise<Schema> }> => {
const schema = localStorage.getItem('schema ' + id);
if (schema)
return {
@ -18,7 +21,31 @@ export const GameSystemsService = {
}
return {
status: 404
status: 404,
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<GameSystem> }> => {
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))}
}
}

7
project-warstone/src/svg.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
declare module "*.svg" {
import * as React from "react";
export const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
const src: string;
export default src;
}

View File

@ -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[];
}

View File

@ -1,5 +1,5 @@
export type MetadataType = {
[key: string]: string
[key: string]: string;
}
export type FieldType = {
@ -11,18 +11,27 @@ export type FieldType = {
export type TypeType = Record<string, FieldType>;
export type Template = {
type: string;
publishable: boolean;
}
export type Schema = {
id: string;
name: string;
types: Record<string, TypeType>
templates: Record<string, Template>;
types: Record<string, TypeType>;
}
export enum FieldTypes {
number = 'number',
text = 'text',
'long text' = 'long text',
checkbox = 'checkbox',
type = '@type',
dice = 'dice'
dice = 'dice',
any = '@select'
}
export const fieldTypeOptions: (keyof typeof FieldTypes)[] = ['number', 'text', 'checkbox', 'type', 'dice']
export const fieldTypeOptions: (keyof typeof FieldTypes)[] = ['number', 'text', 'long text', 'checkbox', 'type', 'dice']
export const fieldTypesWithValues = [FieldTypes.dice, FieldTypes.type];

View File

@ -0,0 +1,4 @@
export const urlBuilder = (path: string) => {
const isDev = import.meta.env.DEV;
return encodeURI(isDev ? '/dev' : '' + path)
}

View File

@ -1,3 +1,7 @@
import plugin from 'tailwindcss/plugin';
import flattenColorPalette from 'tailwindcss/lib/util/flattenColorPalette'
import {parseColor} from 'tailwindcss/lib/util/color'
/** @type {import('tailwindcss').Config} */
export default {
content: [
@ -49,6 +53,26 @@ export default {
}
},
},
plugins: [],
plugins: [
plugin(({matchUtilities, theme}) => {
matchUtilities({
'svg': (value) => {
const ignored = ['inherit', 'currentColor',]
if (ignored.includes(value)) {
return {
fill: value,
stroke: value,
}
}
const {color, alpha} = parseColor(value)
return {
fill: `rgba(${color[0]} ${color[1]} ${color[2]} / ${alpha || 1})`,
stroke: `rgba(${color[0]} ${color[1]} ${color[2]} / ${alpha || 1})`
}
}
}, {values: flattenColorPalette(theme('colors')), type: 'color'})
})
],
}

View File

@ -18,8 +18,9 @@
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
"noFallthroughCasesInSwitch": true,
},
"include": ["src"],
"include": ["src", "src/svg.d.ts"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -1,11 +1,20 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import svgr from 'vite-plugin-svgr'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
plugins: [react(), svgr()],
appType: 'spa',
preview: {
port: 6969
},
server: {
proxy: {
'/dev': {
target: 'http://localhost:3000',
rewrite: (p) => p.replace('/dev', '')
}
}
}
})

View File

@ -7,6 +7,195 @@
resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
"@ampproject/remapping@^2.2.0":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630"
integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==
dependencies:
"@jridgewell/gen-mapping" "^0.3.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658"
integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==
dependencies:
"@babel/highlight" "^7.22.5"
"@babel/compat-data@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.5.tgz#b1f6c86a02d85d2dd3368a2b67c09add8cd0c255"
integrity sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==
"@babel/core@^7.21.3":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.5.tgz#d67d9747ecf26ee7ecd3ebae1ee22225fe902a89"
integrity sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==
dependencies:
"@ampproject/remapping" "^2.2.0"
"@babel/code-frame" "^7.22.5"
"@babel/generator" "^7.22.5"
"@babel/helper-compilation-targets" "^7.22.5"
"@babel/helper-module-transforms" "^7.22.5"
"@babel/helpers" "^7.22.5"
"@babel/parser" "^7.22.5"
"@babel/template" "^7.22.5"
"@babel/traverse" "^7.22.5"
"@babel/types" "^7.22.5"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.2"
semver "^6.3.0"
"@babel/generator@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.5.tgz#1e7bf768688acfb05cf30b2369ef855e82d984f7"
integrity sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==
dependencies:
"@babel/types" "^7.22.5"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
"@babel/helper-compilation-targets@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz#fc7319fc54c5e2fa14b2909cf3c5fd3046813e02"
integrity sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==
dependencies:
"@babel/compat-data" "^7.22.5"
"@babel/helper-validator-option" "^7.22.5"
browserslist "^4.21.3"
lru-cache "^5.1.1"
semver "^6.3.0"
"@babel/helper-environment-visitor@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98"
integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==
"@babel/helper-function-name@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be"
integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==
dependencies:
"@babel/template" "^7.22.5"
"@babel/types" "^7.22.5"
"@babel/helper-hoist-variables@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-module-imports@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c"
integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-module-transforms@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz#0f65daa0716961b6e96b164034e737f60a80d2ef"
integrity sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==
dependencies:
"@babel/helper-environment-visitor" "^7.22.5"
"@babel/helper-module-imports" "^7.22.5"
"@babel/helper-simple-access" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.5"
"@babel/helper-validator-identifier" "^7.22.5"
"@babel/template" "^7.22.5"
"@babel/traverse" "^7.22.5"
"@babel/types" "^7.22.5"
"@babel/helper-simple-access@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de"
integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-split-export-declaration@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz#88cf11050edb95ed08d596f7a044462189127a08"
integrity sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-string-parser@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
"@babel/helper-validator-identifier@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==
"@babel/helper-validator-option@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac"
integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==
"@babel/helpers@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.5.tgz#74bb4373eb390d1ceed74a15ef97767e63120820"
integrity sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==
dependencies:
"@babel/template" "^7.22.5"
"@babel/traverse" "^7.22.5"
"@babel/types" "^7.22.5"
"@babel/highlight@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031"
integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==
dependencies:
"@babel/helper-validator-identifier" "^7.22.5"
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.5.tgz#721fd042f3ce1896238cf1b341c77eb7dee7dbea"
integrity sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==
"@babel/template@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec"
integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==
dependencies:
"@babel/code-frame" "^7.22.5"
"@babel/parser" "^7.22.5"
"@babel/types" "^7.22.5"
"@babel/traverse@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.5.tgz#44bd276690db6f4940fdb84e1cb4abd2f729ccd1"
integrity sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==
dependencies:
"@babel/code-frame" "^7.22.5"
"@babel/generator" "^7.22.5"
"@babel/helper-environment-visitor" "^7.22.5"
"@babel/helper-function-name" "^7.22.5"
"@babel/helper-hoist-variables" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.5"
"@babel/parser" "^7.22.5"
"@babel/types" "^7.22.5"
debug "^4.1.0"
globals "^11.1.0"
"@babel/types@^7.21.3", "@babel/types@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe"
integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==
dependencies:
"@babel/helper-string-parser" "^7.22.5"
"@babel/helper-validator-identifier" "^7.22.5"
to-fast-properties "^2.0.0"
"@esbuild/android-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
@ -168,7 +357,7 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@jridgewell/gen-mapping@^0.3.2":
"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098"
integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
@ -197,7 +386,7 @@
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@jridgewell/trace-mapping@^0.3.9":
"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
version "0.3.18"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6"
integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==
@ -231,6 +420,97 @@
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.6.3.tgz#8205baf6e17ef93be35bf62c37d2d594e9be0dad"
integrity sha512-EXJysQ7J3veRECd0kZFQwYYd5sJMcq2O/m60zu1W2l3oVQ9xtub8jTOtYRE0+M2iomyG/W3Ps7+vp2kna0C27Q==
"@rollup/pluginutils@^5.0.2":
version "5.0.2"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33"
integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==
dependencies:
"@types/estree" "^1.0.0"
estree-walker "^2.0.2"
picomatch "^2.3.1"
"@svgr/babel-plugin-add-jsx-attribute@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-7.0.0.tgz#80856c1b7a3b7422d232f6e079f0beb90c4a13e9"
integrity sha512-khWbXesWIP9v8HuKCl2NU2HNAyqpSQ/vkIl36Nbn4HIwEYSRWL0H7Gs6idJdha2DkpFDWlsqMELvoCE8lfFY6Q==
"@svgr/babel-plugin-remove-jsx-attribute@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-7.0.0.tgz#91da77a009dc38e8d30da45d9b62ef8736f2d90a"
integrity sha512-iiZaIvb3H/c7d3TH2HBeK91uI2rMhZNwnsIrvd7ZwGLkFw6mmunOCoVnjdYua662MqGFxlN9xTq4fv9hgR4VXQ==
"@svgr/babel-plugin-remove-jsx-empty-expression@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-7.0.0.tgz#5154ff1213509e36ab315974c8c2fd48dafb827b"
integrity sha512-sQQmyo+qegBx8DfFc04PFmIO1FP1MHI1/QEpzcIcclo5OAISsOJPW76ZIs0bDyO/DBSJEa/tDa1W26pVtt0FRw==
"@svgr/babel-plugin-replace-jsx-attribute-value@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-7.0.0.tgz#7e72f44ee57fdbcb02fb0d4a7629466c5242725e"
integrity sha512-i6MaAqIZXDOJeikJuzocByBf8zO+meLwfQ/qMHIjCcvpnfvWf82PFvredEZElErB5glQFJa2KVKk8N2xV6tRRA==
"@svgr/babel-plugin-svg-dynamic-title@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-7.0.0.tgz#8caf0449c678ea29be756b89960b2b16c9f33f00"
integrity sha512-BoVSh6ge3SLLpKC0pmmN9DFlqgFy4NxNgdZNLPNJWBUU7TQpDWeBuyVuDW88iXydb5Cv0ReC+ffa5h3VrKfk1w==
"@svgr/babel-plugin-svg-em-dimensions@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-7.0.0.tgz#4db6b5af6d29e93db236b1a013fa953754071d41"
integrity sha512-tNDcBa+hYn0gO+GkP/AuNKdVtMufVhU9fdzu+vUQsR18RIJ9RWe7h/pSBY338RO08wArntwbDk5WhQBmhf2PaA==
"@svgr/babel-plugin-transform-react-native-svg@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-7.0.0.tgz#236995e58b5e36ff06365d5310509ce5391aeec9"
integrity sha512-qw54u8ljCJYL2KtBOjI5z7Nzg8LnSvQOP5hPKj77H4VQL4+HdKbAT5pnkkZLmHKYwzsIHSYKXxHouD8zZamCFQ==
"@svgr/babel-plugin-transform-svg-component@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-7.0.0.tgz#a9b62730acf10d22a2aa57e0f701c0ecbc270430"
integrity sha512-CcFECkDj98daOg9jE3Bh3uyD9kzevCAnZ+UtzG6+BQG/jOQ2OA3jHnX6iG4G1MCJkUQFnUvEv33NvQfqrb/F3A==
"@svgr/babel-preset@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-7.0.0.tgz#55aaca4cec2ff6515a571715b6b6fa98675b66d9"
integrity sha512-EX/NHeFa30j5UjldQGVQikuuQNHUdGmbh9kEpBKofGUtF0GUPJ4T4rhoYiqDAOmBOxojyot36JIFiDUHUK1ilQ==
dependencies:
"@svgr/babel-plugin-add-jsx-attribute" "^7.0.0"
"@svgr/babel-plugin-remove-jsx-attribute" "^7.0.0"
"@svgr/babel-plugin-remove-jsx-empty-expression" "^7.0.0"
"@svgr/babel-plugin-replace-jsx-attribute-value" "^7.0.0"
"@svgr/babel-plugin-svg-dynamic-title" "^7.0.0"
"@svgr/babel-plugin-svg-em-dimensions" "^7.0.0"
"@svgr/babel-plugin-transform-react-native-svg" "^7.0.0"
"@svgr/babel-plugin-transform-svg-component" "^7.0.0"
"@svgr/core@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/core/-/core-7.0.0.tgz#def863d2670c682615583c80b408e83c095c2233"
integrity sha512-ztAoxkaKhRVloa3XydohgQQCb0/8x9T63yXovpmHzKMkHO6pkjdsIAWKOS4bE95P/2quVh1NtjSKlMRNzSBffw==
dependencies:
"@babel/core" "^7.21.3"
"@svgr/babel-preset" "^7.0.0"
camelcase "^6.2.0"
cosmiconfig "^8.1.3"
"@svgr/hast-util-to-babel-ast@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-7.0.0.tgz#d457dfbe74ebc1e5a6daf97ded49e9576a3a00cf"
integrity sha512-42Ej9sDDEmsJKjrfQ1PHmiDiHagh/u9AHO9QWbeNx4KmD9yS5d1XHmXUNINfUcykAU+4431Cn+k6Vn5mWBYimQ==
dependencies:
"@babel/types" "^7.21.3"
entities "^4.4.0"
"@svgr/plugin-jsx@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-7.0.0.tgz#b9e0c7d05bc890d70163ac0490ba8c41f1afab90"
integrity sha512-SWlTpPQmBUtLKxXWgpv8syzqIU8XgFRvyhfkam2So8b3BE0OS0HPe5UfmlJ2KIC+a7dpuuYovPR2WAQuSyMoPw==
dependencies:
"@babel/core" "^7.21.3"
"@svgr/babel-preset" "^7.0.0"
"@svgr/hast-util-to-babel-ast" "^7.0.0"
svg-parser "^2.0.4"
"@swc/core-darwin-arm64@1.3.62":
version "1.3.62"
resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.62.tgz#dafb50bf784c6b7b40dce6d8cf0605f6729812cb"
@ -297,6 +577,11 @@
"@swc/core-win32-ia32-msvc" "1.3.62"
"@swc/core-win32-x64-msvc" "1.3.62"
"@types/estree@^1.0.0":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194"
integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==
"@types/history@^4.7.11":
version "4.7.11"
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64"
@ -345,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"
@ -471,6 +761,13 @@ ansi-regex@^5.0.1:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
ansi-styles@^4.1.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
@ -543,7 +840,7 @@ braces@^3.0.2, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
browserslist@^4.21.5:
browserslist@^4.21.3, browserslist@^4.21.5:
version "4.21.7"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.7.tgz#e2b420947e5fb0a58e8f4668ae6e23488127e551"
integrity sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==
@ -563,11 +860,25 @@ camelcase-css@^2.0.1:
resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
camelcase@^6.2.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001489:
version "1.0.30001495"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz#64a0ccef1911a9dcff647115b4430f8eff1ef2d9"
integrity sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==
chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chalk@^4.0.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
@ -591,6 +902,13 @@ chokidar@^3.5.3:
optionalDependencies:
fsevents "~2.3.2"
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
dependencies:
color-name "1.1.3"
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
@ -598,6 +916,11 @@ color-convert@^2.0.1:
dependencies:
color-name "~1.1.4"
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
@ -613,6 +936,21 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
convert-source-map@^1.7.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
cosmiconfig@^8.1.3:
version "8.2.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.2.0.tgz#f7d17c56a590856cd1e7cee98734dca272b0d8fd"
integrity sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==
dependencies:
import-fresh "^3.2.1"
js-yaml "^4.1.0"
parse-json "^5.0.0"
path-type "^4.0.0"
cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@ -632,7 +970,7 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -673,6 +1011,18 @@ electron-to-chromium@^1.4.411:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.421.tgz#2b8c0ef98ba00d4aef4c664933d570922da52161"
integrity sha512-wZOyn3s/aQOtLGAwXMZfteQPN68kgls2wDAnYOA8kCjBvKVrW5RwmWVspxJYTqrcN7Y263XJVsC66VCIGzDO3g==
entities@^4.4.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
dependencies:
is-arrayish "^0.2.1"
esbuild@^0.17.5:
version "0.17.19"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.19.tgz#087a727e98299f0462a3d0bcdd9cd7ff100bd955"
@ -706,6 +1056,11 @@ escalade@^3.1.1:
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
@ -820,6 +1175,11 @@ estraverse@^5.1.0, estraverse@^5.2.0:
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
estree-walker@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
@ -913,6 +1273,11 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
@ -951,6 +1316,11 @@ glob@^7.1.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
globals@^13.19.0:
version "13.20.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82"
@ -985,6 +1355,11 @@ hamt_plus@1.0.2:
resolved "https://registry.yarnpkg.com/hamt_plus/-/hamt_plus-1.0.2.tgz#e21c252968c7e33b20f6a1b094cd85787a265601"
integrity sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
@ -1028,6 +1403,11 @@ inherits@2:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
@ -1074,7 +1454,7 @@ jiti@^1.18.2:
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.18.2.tgz#80c3ef3d486ebf2450d9335122b32d121f2a83cd"
integrity sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==
"js-tokens@^3.0.0 || ^4.0.0":
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
@ -1086,6 +1466,16 @@ js-yaml@^4.1.0:
dependencies:
argparse "^2.0.1"
jsesc@^2.5.1:
version "2.5.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json-parse-even-better-errors@^2.3.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
@ -1096,6 +1486,11 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
json5@^2.2.2:
version "2.2.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
@ -1133,6 +1528,13 @@ loose-envify@^1.1.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
dependencies:
yallist "^3.0.2"
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
@ -1254,6 +1656,16 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
parse-json@^5.0.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
dependencies:
"@babel/code-frame" "^7.0.0"
error-ex "^1.3.1"
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
@ -1418,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"
@ -1465,6 +1882,11 @@ scheduler@^0.23.0:
dependencies:
loose-envify "^1.1.0"
semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.7:
version "7.5.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.1.tgz#c90c4d631cf74720e46b21c1d37ea07edfab91ec"
@ -1519,6 +1941,13 @@ sucrase@^3.32.0:
pirates "^4.0.1"
ts-interface-checker "^0.1.9"
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
supports-color@^7.1.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
@ -1531,6 +1960,11 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
svg-parser@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5"
integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==
tailwindcss@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.2.tgz#2f9e35d715fdf0bbf674d90147a0684d7054a2d3"
@ -1579,6 +2013,11 @@ thenify-all@^1.0.0:
dependencies:
any-promise "^1.0.0"
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
@ -1640,6 +2079,15 @@ util-deprecate@^1.0.2:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
vite-plugin-svgr@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/vite-plugin-svgr/-/vite-plugin-svgr-3.2.0.tgz#920375aaf6635091c9ac8e467825f92d32544476"
integrity sha512-Uvq6niTvhqJU6ga78qLKBFJSDvxWhOnyfQSoKpDPMAGxJPo5S3+9hyjExE5YDj6Lpa4uaLkGc1cBgxXov+LjSw==
dependencies:
"@rollup/pluginutils" "^5.0.2"
"@svgr/core" "^7.0.0"
"@svgr/plugin-jsx" "^7.0.0"
vite@^4.3.9:
version "4.3.9"
resolved "https://registry.yarnpkg.com/vite/-/vite-4.3.9.tgz#db896200c0b1aa13b37cdc35c9e99ee2fdd5f96d"
@ -1668,6 +2116,11 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
yallist@^3.0.2:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"

View File

@ -1,7 +1,6 @@
import { proxy } from "https://deno.land/x/oak_http_proxy@2.1.0/mod.ts";
import { fileExists } from "./lib/fileExists.ts";
import { Application, Context, Router } from "oak";
import { path } from "https://deno.land/x/compress@v0.4.1/deps.ts";
const app = new Application();
@ -21,6 +20,7 @@ for await (const dirEntry of Deno.readDir(Deno.cwd())) {
args: [
'run',
...perms,
'--watch',
filename,
port
]
@ -28,8 +28,8 @@ for await (const dirEntry of Deno.readDir(Deno.cwd())) {
const prefix = Deno.readTextFileSync(prefixfile);
const routes = new Router()
.all(`/${prefix}/(.*)`, proxy((ctx: Context) => `http://localhost:${port}${ctx.request.url.pathname}`, {}))
.all(prefix ? `/${prefix}/(.*)` : '/(.*)', proxy((ctx: Context) => `http://localhost:${port}${ctx.request.url.pathname}`))
app.use(routes.allowedMethods());
app.use(routes.routes());

View File

@ -0,0 +1,15 @@
FROM denoland/deno:1.33.2
EXPOSE 6904
WORKDIR /warstone-web
ADD ./warstone-web-service/ .
ADD ./deno.jsonc .
ADD ./secrets.json .
ADD ./key.txt .
ADD ./common ./common
ADD ./lib ./lib
ADD ./middleware ./middleware
CMD ["run", "[object Object]", "[object Object]", main.ts, "6904"]

View File

@ -0,0 +1,23 @@
import { CGGService } from 'cgg/Application.ts';
import { Router, send } from 'oak';
const prefix = ''
const app = new CGGService({ prefix: `/${prefix}` });
// app.route(new Router()
// .get('/', ctx => ctx.response.body = 'warstone-web service')
// );
const ROOT_DIR = "./project-warstone/dist";
app.use(async (ctx) => {
if (ctx.request.url.pathname.includes('favicon')) return ctx.response.status = 404;
const filePath = ctx.request.url.pathname.replace(prefix, "");
await send(ctx, filePath, {
root: ROOT_DIR,
index: 'index.html'
});
});
app.start();
console.log('warstone-web service running on ' + Deno.args.at(0));

View File

@ -0,0 +1,2 @@
--allow-read
--allow-net

View File

@ -0,0 +1 @@
6904

View File