diff options
-rw-r--r-- | build/webpack.renderer.js | 4 | ||||
-rw-r--r-- | package.json | 5 | ||||
-rw-r--r-- | src/renderer/editor/editor.tsx | 62 | ||||
-rw-r--r-- | src/renderer/editor/library.tsx | 83 | ||||
-rw-r--r-- | src/renderer/editor/types.ts | 16 | ||||
-rw-r--r-- | src/renderer/editor/util.ts | 31 | ||||
-rw-r--r-- | src/renderer/index.html | 6 | ||||
-rw-r--r-- | yarn.lock | 38 |
8 files changed, 238 insertions, 7 deletions
diff --git a/build/webpack.renderer.js b/build/webpack.renderer.js index 2cfd371..ab56930 100644 --- a/build/webpack.renderer.js +++ b/build/webpack.renderer.js @@ -14,6 +14,10 @@ module.exports = { use: [{ loader: 'style-loader' }, { loader: 'css-loader' }], }, { + test: /\.(woff|woff2|eot|ttf|otf)$/, + use: 'file-loader', + }, + { test: /\.(vs|fs)$/, use: 'raw-loader', }, diff --git a/package.json b/package.json index b1ce26b..b196d25 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "eslint-plugin-prettier": "^3.1.2", "eslint-plugin-react": "^7.19.0", "eslint-plugin-react-hooks": "^2.5.0", + "file-loader": "^6.0.0", "prettier": "^1.19.1", "raw-loader": "^4.0.0", "style-loader": "^1.1.3", @@ -55,7 +56,9 @@ "dependencies": { "@material-ui/core": "^4.9.5", "gl-matrix": "^3.2.1", + "immutable": "^4.0.0-rc.12", "react": "^16.13.0", - "react-dom": "^16.13.0" + "react-dom": "^16.13.0", + "typeface-roboto": "^0.0.75" } } diff --git a/src/renderer/editor/editor.tsx b/src/renderer/editor/editor.tsx index fd8360a..2c57afc 100644 --- a/src/renderer/editor/editor.tsx +++ b/src/renderer/editor/editor.tsx @@ -1,10 +1,64 @@ import * as React from 'react'; -import Button from '@material-ui/core/Button'; + +import 'typeface-roboto'; + +import { createMuiTheme, makeStyles, Theme, ThemeProvider } from '@material-ui/core/styles'; + +import CssBaseline from '@material-ui/core/CssBaseline'; +import Drawer from '@material-ui/core/Drawer'; + +import { Library } from './library'; + +const drawerWidth = 240; + +const useStyles = makeStyles((theme: Theme) => ({ + root: { + display: 'flex', + }, + drawer: { + width: drawerWidth, + flexShrink: 0, + }, + drawerPaper: { + width: drawerWidth, + }, + content: { + flexGrow: 1, + padding: theme.spacing(3), + }, +})); + +function EditorLayout(): JSX.Element { + const classes = useStyles(); + + return ( + <div className={classes.root}> + <CssBaseline /> + <Drawer + className={classes.drawer} + variant='permanent' + classes={{ + paper: classes.drawerPaper, + }} + anchor='left' + ></Drawer> + <main className={classes.content}> + <Library /> + </main> + </div> + ); +} + +const theme = createMuiTheme({ + palette: { + type: 'dark', + }, +}); export function Editor(): JSX.Element { return ( - <Button variant='contained' color='primary'> - Hello World - </Button> + <ThemeProvider theme={theme}> + <EditorLayout /> + </ThemeProvider> ); } diff --git a/src/renderer/editor/library.tsx b/src/renderer/editor/library.tsx new file mode 100644 index 0000000..4b7dac7 --- /dev/null +++ b/src/renderer/editor/library.tsx @@ -0,0 +1,83 @@ +import * as React from 'react'; + +import { makeStyles, Theme } from '@material-ui/core/styles'; + +import Box from '@material-ui/core/Box'; +import Container from '@material-ui/core/Container'; + +import { Tiling } from './types'; +import { useReadFile } from './util'; + +const useStyles = makeStyles((theme: Theme) => ({ + container: { + display: 'flex', + flexWrap: 'wrap', + }, + tile: { + imageRendering: 'pixelated', + border: `solid 1px ${theme.palette.divider}`, + background: theme.palette.background.paper, + width: 128, + height: 128, + margin: 4, + }, +})); + +const tilings: Tiling[] = [ + { + size: 1, + sprite: { name: 'dirt' }, + }, + { + size: 1, + sprite: { name: 'grass' }, + }, + { + size: 1, + sprite: { name: 'road_left' }, + }, + { + size: 1, + sprite: { name: 'road_right' }, + }, +]; + +interface TilingDisplayProps { + tiling: Tiling; +} + +function TilingDisplay({ tiling }: TilingDisplayProps): JSX.Element | null { + const classes = useStyles(); + + let name: string; + + switch (tiling.size) { + case 1: + name = tiling.sprite.name; + break; + case 3: + name = tiling.sprites[1][1].name; + break; + } + + const path = `static/resources/sprite/tile/${name}.png`; + const image = useReadFile(path, 'base64'); + + return <img src={image ? `data:image/png;base64,${image}` : undefined} className={classes.tile} />; +} + +export function Library(): JSX.Element { + const classes = useStyles(); + + return ( + <Container> + <Box display='inline-block'> + <div className={classes.container}> + {tilings.map((tiling, i) => ( + <TilingDisplay key={i} tiling={tiling} /> + ))} + </div> + </Box> + </Container> + ); +} diff --git a/src/renderer/editor/types.ts b/src/renderer/editor/types.ts new file mode 100644 index 0000000..95e1bd2 --- /dev/null +++ b/src/renderer/editor/types.ts @@ -0,0 +1,16 @@ +export type Tuple3<T> = [T, T, T]; +export type Grid3x3<T> = Tuple3<Tuple3<T>>; + +export type Sprite = { + name: string; +}; + +export type Tiling = + | { + size: 1; + sprite: Sprite; + } + | { + size: 3; + sprites: Grid3x3<Sprite>; + }; diff --git a/src/renderer/editor/util.ts b/src/renderer/editor/util.ts new file mode 100644 index 0000000..b2331bb --- /dev/null +++ b/src/renderer/editor/util.ts @@ -0,0 +1,31 @@ +import { useCallback, useEffect, useState } from 'react'; + +import * as fs from 'fs'; + +export function usePromise<T>(f: () => Promise<T>): T | null { + const [value, setValue] = useState<T | null>(null); + + useEffect(() => { + setValue(null); + + let cancelled = false; + + (async (): Promise<void> => { + const v = await f(); + if (!cancelled) { + setValue(v); + } + })(); + + return (): void => { + cancelled = true; + }; + }, [f]); + + return value; +} + +export function useReadFile(path: string, encoding: BufferEncoding): string | null { + const readFile = useCallback(() => fs.promises.readFile(path, encoding), [path, encoding]); + return usePromise(readFile); +} diff --git a/src/renderer/index.html b/src/renderer/index.html index e775d3e..3dce6f3 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -5,6 +5,12 @@ <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" /> <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" /> <title>RPGedit</title> + <style> + html, body, #app { + height: 100%; + overflow: hidden; + } + </style> </head> <body> <div id="app"></div> @@ -2535,6 +2535,14 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" +file-loader@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.0.0.tgz#97bbfaab7a2460c07bcbd72d3a6922407f67649f" + integrity sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ== + dependencies: + loader-utils "^2.0.0" + schema-utils "^2.6.5" + file-uri-to-path@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" @@ -3205,6 +3213,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +immutable@^4.0.0-rc.12: + version "4.0.0-rc.12" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217" + integrity sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A== + import-fresh@^3.0.0: version "3.2.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" @@ -3609,6 +3622,13 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +json5@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.2.tgz#43ef1f0af9835dd624751a6b7fa48874fb2d608e" + integrity sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ== + dependencies: + minimist "^1.2.5" + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -3792,6 +3812,15 @@ loader-utils@^1.0.2, loader-utils@^1.2.3: emojis-list "^3.0.0" json5 "^1.0.1" +loader-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" + integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -4091,7 +4120,7 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: +minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== @@ -5525,7 +5554,7 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.4: +schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.4, schema-utils@^2.6.5: version "2.6.5" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.5.tgz#c758f0a7e624263073d396e29cd40aa101152d8a" integrity sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ== @@ -6322,6 +6351,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typeface-roboto@^0.0.75: + version "0.0.75" + resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-0.0.75.tgz#98d5ba35ec234bbc7172374c8297277099cc712b" + integrity sha512-VrR/IiH00Z1tFP4vDGfwZ1esNqTiDMchBEXYY9kilT6wRGgFoCAlgkEUMHb1E3mB0FsfZhv756IF0+R+SFPfdg== + typescript@^3.8.3: version "3.8.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" |