Switch to deno

This commit is contained in:
Dylan Pizzo 2024-12-29 23:00:38 -05:00
parent 5ec05e3db7
commit b81144153b
15 changed files with 232 additions and 1116 deletions

5
.gitignore vendored
View File

@ -1 +1,6 @@
node_modules
# dotenv environment variable files
.env
**/dist/**/*

39
deno.json Normal file
View File

@ -0,0 +1,39 @@
{
"lock": false,
"tasks": {
"build": "deno run -A tools/build.ts",
"serve": "deno run -A src/server/index.ts"
},
"lint": {
"rules": {
"tags": [
"recommended"
]
}
},
"exclude": [
"dist"
],
"imports": {
"react/": "https://esm.sh/react@18.3.1/",
"react-dom/": "https://esm.sh/react-dom@18.3.1/client/",
"react": "https://esm.sh/react@18.3.1",
"react-dom": "https://esm.sh/react-dom@18.3.1/client",
"canvas": "https://esm.sh/canvas@3.0.0"
},
"compilerOptions": {
"lib": ["deno.ns", "DOM"],
"jsx": "react-jsx",
"jsxImportSource": "react",
"strict": true,
"exactOptionalPropertyTypes": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"allowUnusedLabels": false
},
"fmt": {
"useTabs": true
}
}

1048
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
{
"dependencies": {
"canvas": "^2.11.2"
}
}

3
root.ts Normal file
View File

@ -0,0 +1,3 @@
import { dirname, fromFileUrl } from "jsr:@std/path";
export const projectRootDir = dirname(fromFileUrl(import.meta.url));

6
src/client/App.tsx Normal file
View File

@ -0,0 +1,6 @@
import { sampleCard } from "../sampleData.ts";
import { Card } from "./Card.tsx";
export const App = () => {
return <div><Card card={sampleCard}/></div>;
};

26
src/client/Card.tsx Normal file
View File

@ -0,0 +1,26 @@
import { drawCard } from "../draw.ts";
import { DominionCard } from "../types.ts";
const sizeMap = {
card: {
width: 1403,
height: 2151,
},
landscape: {
width: 2151,
height: 1403,
}
}
export const Card = (props: {card: DominionCard}) => {
const {card} = props;
const {width, height} = sizeMap[card.orientation];
return <canvas style={{width: "2.5in"}} width={width} height={height} ref={(canvasElement) => {
if (canvasElement) {
const context = canvasElement.getContext("2d");
if (context) {
drawCard(context, card);
}
}
}}></canvas>
}

14
src/client/index.tsx Normal file
View File

@ -0,0 +1,14 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom";
import { App } from "./App.tsx";
const rootElement = document.getElementById("root");
if (!rootElement) {
throw Error("No root element to attach react to.");
}
createRoot(rootElement).render(
<StrictMode>
<App />
</StrictMode>,
);

View File

@ -1,22 +1,31 @@
import { DominionCard } from "./types"
import { createCanvas } from "canvas"
import { DominionCard } from "./types.ts";
export const drawCard = (card: DominionCard): Promise<string> => {
export const drawCard = (
context: CanvasRenderingContext2D,
card: DominionCard
): Promise<void> => {
if (card.orientation === "card") {
return drawStandardCard(card);
return drawStandardCard(context, card);
} else {
return drawLandscapeCard(card);
return drawLandscapeCard(context, card);
}
}
};
const drawStandardCard = async (card: DominionCard): Promise<string> => {
const canvas = createCanvas(1403, 2151);
const context = canvas.getContext("2d");
return "";
}
const drawStandardCard = async (
context: CanvasRenderingContext2D,
card: DominionCard
): Promise<void> => {
const w = context.canvas.width;
const h = context.canvas.height;
context.save();
context.fillStyle = "brown";
context.fillRect(0, 0, w, h);
context.restore();
};
const drawLandscapeCard = async (card: DominionCard): Promise<string> => {
const drawLandscapeCard = async (
context: CanvasRenderingContext2D,
card: DominionCard
): Promise<void> => {
// TODO: everything
return "";
}
};

0
src/isocanvas.ts Normal file
View File

View File

@ -1,4 +1,4 @@
import { DominionCard, TYPE_ACTION } from "./types";
import { DominionCard, TYPE_ACTION } from "./types.ts";
export const sampleCard: DominionCard = {
orientation: "card",
@ -11,4 +11,4 @@ export const sampleCard: DominionCard = {
version: "",
price: "",
preview: "",
}
};

14
src/server/index.ts Normal file
View File

@ -0,0 +1,14 @@
import { serveDir, serveFile } from "jsr:@std/http/file-server";
Deno.serve((req: Request) => {
const pathname = new URL(req.url).pathname;
if (pathname.startsWith("/static")) {
return serveDir(req, {
fsRoot: "src/static",
urlRoot: "static",
});
} else {
return serveFile(req, "src/static/index.html");
}
});

12
src/static/index.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dominionator</title>
</head>
<body>
<div id="root"></div>
<script src="/static/dist/bundle.js"></script>
</body>
</html>

View File

@ -9,7 +9,16 @@ export type DominionColor = {
export type DominionBasicCardType = {
typeType: "basic";
name: "Action" | "Treasure" | "Victory" | "Reaction" | "Duration" | "Reserve" | "Night" | "Attack" | "Command";
name:
| "Action"
| "Treasure"
| "Victory"
| "Reaction"
| "Duration"
| "Reserve"
| "Night"
| "Attack"
| "Command";
color: null | DominionColor;
};
export type DominionBasicLandscapeType = {
@ -19,30 +28,34 @@ export type DominionBasicLandscapeType = {
};
export type DominionCardType = DominionBasicCardType | DominionCustomCardType;
export type DominionLandscapeType = DominionBasicLandscapeType | DominionCustomLandscapeType;
export type DominionLandscapeType =
| DominionBasicLandscapeType
| DominionCustomLandscapeType;
export type DominionCard = {
orientation: "card";
title: string;
description: DominionText;
types: Array<DominionCardType>;
image: string;
artist: string;
author: string;
version: string;
price: DominionText;
preview?: DominionText;
} | {
orientation: "landscape";
title: string;
description: DominionText;
types: Array<DominionLandscapeType>;
image: string;
artist: string;
author: string;
version: string;
price: DominionText;
};
export type DominionCard =
| {
orientation: "card";
title: string;
description: DominionText;
types: Array<DominionCardType>;
image: string;
artist: string;
author: string;
version: string;
price: DominionText;
preview?: DominionText;
}
| {
orientation: "landscape";
title: string;
description: DominionText;
types: Array<DominionLandscapeType>;
image: string;
artist: string;
author: string;
version: string;
price: DominionText;
};
export type DominionCustomSymbol = {
image: string;
@ -51,12 +64,12 @@ export type DominionCustomSymbol = {
export type DominionCustomCardType = {
typeType: "custom";
name: string;
color: DominionColor
color: DominionColor;
};
export type DominionCustomLandscapeType = {
typeType: "custom";
name: string;
color: DominionColor
color: DominionColor;
};
export type DominionExpansion = {
@ -65,7 +78,7 @@ export type DominionExpansion = {
customSymbols: Array<DominionCustomSymbol>;
customCardTypes: Array<DominionCustomCardType>;
customLandscapeTypes: Array<DominionCustomLandscapeType>;
}
};
export const TYPE_ACTION: DominionBasicCardType = {
typeType: "basic",
@ -73,8 +86,8 @@ export const TYPE_ACTION: DominionBasicCardType = {
color: {
value: "white",
priority: 6,
}
}
},
};
export const TYPE_TREASURE: DominionBasicCardType = {
typeType: "basic",
@ -82,8 +95,8 @@ export const TYPE_TREASURE: DominionBasicCardType = {
color: {
value: "yellow",
priority: 5,
}
}
},
};
export const TYPE_VICTORY: DominionBasicCardType = {
typeType: "basic",
@ -91,8 +104,8 @@ export const TYPE_VICTORY: DominionBasicCardType = {
color: {
value: "green",
priority: 4,
}
}
},
};
export const TYPE_REACTION: DominionBasicCardType = {
typeType: "basic",
@ -101,8 +114,8 @@ export const TYPE_REACTION: DominionBasicCardType = {
value: "blue",
priority: 1,
overridesAction: true,
}
}
},
};
export const TYPE_DURATION: DominionBasicCardType = {
typeType: "basic",
@ -111,18 +124,18 @@ export const TYPE_DURATION: DominionBasicCardType = {
value: "orange",
priority: 3,
overridesAction: true,
}
}
},
};
export const TYPE_RESERVE: DominionBasicCardType = {
typeType: "basic",
name: "Duration",
color: {
value: "orange",
value: "brown",
priority: 2, // unknown whether this should be above or below reaction/duration?
overridesAction: true,
}
}
},
};
export const TYPE_NIGHT: DominionBasicCardType = {
typeType: "basic",
@ -131,17 +144,17 @@ export const TYPE_NIGHT: DominionBasicCardType = {
value: "black",
priority: 6,
onConflictDescriptionOnly: true,
}
}
},
};
export const TYPE_ATTACK: DominionBasicCardType = {
typeType: "basic",
name: "Attack",
color: null
}
color: null,
};
export const TYPE_COMMAND: DominionBasicCardType = {
typeType: "basic",
name: "Command",
color: null
}
color: null,
};

28
tools/build.ts Normal file
View File

@ -0,0 +1,28 @@
import * as esbuild from "npm:esbuild";
import { denoPlugins } from "jsr:@luca/esbuild-deno-loader";
import browserslist from "npm:browserslist";
import { projectRootDir } from "../root.ts";
const browsers = browserslist([
"last 4 Chrome versions",
"last 4 Edge versions",
"last 4 Opera versions",
"last 4 Firefox versions",
"last 4 Safari versions",
]).map((browser: string) => browser.replace(" ", ""));
// esbuild target is fine-grained: https://esbuild.github.io/api/#target
const target = [...browsers, "ios18", "ios17", "ios16", "ios14"];
await esbuild.build({
plugins: [...denoPlugins()],
absWorkingDir: projectRootDir,
entryPoints: ["src/client/index.tsx"],
outfile: "src/static/dist/bundle.js",
bundle: true,
format: "esm",
target,
jsx: "automatic",
jsxImportSource: "react",
});
esbuild.stop();