From 6484d42dabf1482e2ea538d2512537690180b8d2 Mon Sep 17 00:00:00 2001
From: Matthias Schiffer <mschiffer@universe-factory.net>
Date: Sun, 22 Mar 2020 01:43:54 +0100
Subject: editor: list tiles in project directory

---
 src/renderer/editor/library.tsx | 111 ++++++++++++++++++++++++++--------------
 1 file changed, 74 insertions(+), 37 deletions(-)

(limited to 'src/renderer/editor/library.tsx')

diff --git a/src/renderer/editor/library.tsx b/src/renderer/editor/library.tsx
index 4b7dac7..840bdc9 100644
--- a/src/renderer/editor/library.tsx
+++ b/src/renderer/editor/library.tsx
@@ -1,46 +1,65 @@
 import * as React from 'react';
+const { useCallback, useMemo } = React;
 
 import { makeStyles, Theme } from '@material-ui/core/styles';
 
 import Box from '@material-ui/core/Box';
+import Button from '@material-ui/core/Button';
 import Container from '@material-ui/core/Container';
 
-import { Tiling } from './types';
-import { useReadFile } from './util';
+import * as Color from 'color';
+import * as glob from 'fast-glob';
+
+import { Tiling, TilingMeta } from './types';
+import { usePromise, useReadFile, readJSON } from './util';
 
 const useStyles = makeStyles((theme: Theme) => ({
-	container: {
+	grid: {
 		display: 'flex',
 		flexWrap: 'wrap',
+		margin: theme.spacing(-0.5),
 	},
 	tile: {
 		imageRendering: 'pixelated',
-		border: `solid 1px ${theme.palette.divider}`,
+		borderStyle: 'solid',
+		borderWidth: 1,
+		borderColor: theme.palette.divider,
 		background: theme.palette.background.paper,
+		position: 'relative',
+		width: 130,
+		height: 130,
+		margin: theme.spacing(0.5),
+		// cursor: 'pointer',
+		// '&:hover': {
+		// 	borderColor: theme.palette.text.secondary,
+		// 	boxShadow: `0 0 2px 1px ${theme.palette.text.secondary}`,
+		// },
+	},
+	img: {
+		position: 'absolute',
+		zIndex: 1,
 		width: 128,
 		height: 128,
-		margin: 4,
+	},
+	label: {
+		position: 'absolute',
+		zIndex: 2,
+		left: 0,
+		right: 0,
+		bottom: 0,
+		height: '37.5%',
+		padding: theme.spacing(1),
+		background: Color(theme.palette.background.default)
+			.fade(0.3)
+			.string(),
 	},
 }));
 
-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' },
-	},
-];
+function tilingSprite(tiling: Tiling): string {
+	const x = (tiling.meta.width - 1) / 2;
+	const y = (tiling.meta.height - 1) / 2;
+	return `project/tiling/${tiling.id}/${x}_${y}.png`;
+}
 
 interface TilingDisplayProps {
 	tiling: Tiling;
@@ -49,35 +68,53 @@ interface TilingDisplayProps {
 function TilingDisplay({ tiling }: TilingDisplayProps): JSX.Element | null {
 	const classes = useStyles();
 
-	let name: string;
+	const path = tilingSprite(tiling);
+	const image = useReadFile(path);
+	const src = useMemo(() => (image ? `data:image/png;base64,${image.toString('base64')}` : undefined), [image]);
+	return (
+		<div className={classes.tile}>
+			<img className={classes.img} src={src} />
+			<div className={classes.label}>{tiling.meta.name}</div>
+		</div>
+	);
+}
 
-	switch (tiling.size) {
-		case 1:
-			name = tiling.sprite.name;
-			break;
-		case 3:
-			name = tiling.sprites[1][1].name;
-			break;
-	}
+async function listTilings(): Promise<string[]> {
+	const matches = await glob('project/tiling/*/meta.json');
+	return matches.map((m) => m.split('/')[2]);
+}
 
-	const path = `static/resources/sprite/tile/${name}.png`;
-	const image = useReadFile(path, 'base64');
+async function loadTilingMeta(id: string): Promise<TilingMeta> {
+	const path = `project/tiling/${id}/meta.json`;
+	const meta = await readJSON(path);
+	return meta as TilingMeta;
+}
 
-	return <img src={image ? `data:image/png;base64,${image}` : undefined} className={classes.tile} />;
+async function loadTilings(): Promise<Tiling[]> {
+	const tilings = await listTilings();
+	return Promise.all(
+		tilings.map((id) => [id, loadTilingMeta(id)] as const).map(async ([id, p]) => ({ id, meta: await p })),
+	);
 }
 
 export function Library(): JSX.Element {
 	const classes = useStyles();
 
+	const mkLoadTilings = useCallback(() => loadTilings(), []);
+	const tilings = usePromise(mkLoadTilings) ?? [];
+
 	return (
 		<Container>
-			<Box display='inline-block'>
-				<div className={classes.container}>
+			<Box mb={2}>
+				<div className={classes.grid}>
 					{tilings.map((tiling, i) => (
 						<TilingDisplay key={i} tiling={tiling} />
 					))}
 				</div>
 			</Box>
+			<Button variant='contained' color='primary'>
+				Add
+			</Button>
 		</Container>
 	);
 }
-- 
cgit v1.2.3

