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 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 { DominionCard } from "./types.ts";
import { createCanvas } from "canvas"
export const drawCard = (card: DominionCard): Promise<string> => { export const drawCard = (
context: CanvasRenderingContext2D,
card: DominionCard
): Promise<void> => {
if (card.orientation === "card") { if (card.orientation === "card") {
return drawStandardCard(card); return drawStandardCard(context, card);
} else { } else {
return drawLandscapeCard(card); return drawLandscapeCard(context, card);
} }
} };
const drawStandardCard = async (card: DominionCard): Promise<string> => { const drawStandardCard = async (
const canvas = createCanvas(1403, 2151); context: CanvasRenderingContext2D,
const context = canvas.getContext("2d"); 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();
};
return ""; const drawLandscapeCard = async (
} context: CanvasRenderingContext2D,
card: DominionCard
const drawLandscapeCard = async (card: DominionCard): Promise<string> => { ): Promise<void> => {
// TODO: everything // 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 = { export const sampleCard: DominionCard = {
orientation: "card", orientation: "card",
@ -11,4 +11,4 @@ export const sampleCard: DominionCard = {
version: "", version: "",
price: "", price: "",
preview: "", 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 = { export type DominionBasicCardType = {
typeType: "basic"; 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; color: null | DominionColor;
}; };
export type DominionBasicLandscapeType = { export type DominionBasicLandscapeType = {
@ -19,9 +28,12 @@ export type DominionBasicLandscapeType = {
}; };
export type DominionCardType = DominionBasicCardType | DominionCustomCardType; export type DominionCardType = DominionBasicCardType | DominionCustomCardType;
export type DominionLandscapeType = DominionBasicLandscapeType | DominionCustomLandscapeType; export type DominionLandscapeType =
| DominionBasicLandscapeType
| DominionCustomLandscapeType;
export type DominionCard = { export type DominionCard =
| {
orientation: "card"; orientation: "card";
title: string; title: string;
description: DominionText; description: DominionText;
@ -32,7 +44,8 @@ export type DominionCard = {
version: string; version: string;
price: DominionText; price: DominionText;
preview?: DominionText; preview?: DominionText;
} | { }
| {
orientation: "landscape"; orientation: "landscape";
title: string; title: string;
description: DominionText; description: DominionText;
@ -42,7 +55,7 @@ export type DominionCard = {
author: string; author: string;
version: string; version: string;
price: DominionText; price: DominionText;
}; };
export type DominionCustomSymbol = { export type DominionCustomSymbol = {
image: string; image: string;
@ -51,12 +64,12 @@ export type DominionCustomSymbol = {
export type DominionCustomCardType = { export type DominionCustomCardType = {
typeType: "custom"; typeType: "custom";
name: string; name: string;
color: DominionColor color: DominionColor;
}; };
export type DominionCustomLandscapeType = { export type DominionCustomLandscapeType = {
typeType: "custom"; typeType: "custom";
name: string; name: string;
color: DominionColor color: DominionColor;
}; };
export type DominionExpansion = { export type DominionExpansion = {
@ -65,7 +78,7 @@ export type DominionExpansion = {
customSymbols: Array<DominionCustomSymbol>; customSymbols: Array<DominionCustomSymbol>;
customCardTypes: Array<DominionCustomCardType>; customCardTypes: Array<DominionCustomCardType>;
customLandscapeTypes: Array<DominionCustomLandscapeType>; customLandscapeTypes: Array<DominionCustomLandscapeType>;
} };
export const TYPE_ACTION: DominionBasicCardType = { export const TYPE_ACTION: DominionBasicCardType = {
typeType: "basic", typeType: "basic",
@ -73,8 +86,8 @@ export const TYPE_ACTION: DominionBasicCardType = {
color: { color: {
value: "white", value: "white",
priority: 6, priority: 6,
} },
} };
export const TYPE_TREASURE: DominionBasicCardType = { export const TYPE_TREASURE: DominionBasicCardType = {
typeType: "basic", typeType: "basic",
@ -82,8 +95,8 @@ export const TYPE_TREASURE: DominionBasicCardType = {
color: { color: {
value: "yellow", value: "yellow",
priority: 5, priority: 5,
} },
} };
export const TYPE_VICTORY: DominionBasicCardType = { export const TYPE_VICTORY: DominionBasicCardType = {
typeType: "basic", typeType: "basic",
@ -91,8 +104,8 @@ export const TYPE_VICTORY: DominionBasicCardType = {
color: { color: {
value: "green", value: "green",
priority: 4, priority: 4,
} },
} };
export const TYPE_REACTION: DominionBasicCardType = { export const TYPE_REACTION: DominionBasicCardType = {
typeType: "basic", typeType: "basic",
@ -101,8 +114,8 @@ export const TYPE_REACTION: DominionBasicCardType = {
value: "blue", value: "blue",
priority: 1, priority: 1,
overridesAction: true, overridesAction: true,
} },
} };
export const TYPE_DURATION: DominionBasicCardType = { export const TYPE_DURATION: DominionBasicCardType = {
typeType: "basic", typeType: "basic",
@ -111,18 +124,18 @@ export const TYPE_DURATION: DominionBasicCardType = {
value: "orange", value: "orange",
priority: 3, priority: 3,
overridesAction: true, overridesAction: true,
} },
} };
export const TYPE_RESERVE: DominionBasicCardType = { export const TYPE_RESERVE: DominionBasicCardType = {
typeType: "basic", typeType: "basic",
name: "Duration", name: "Duration",
color: { color: {
value: "orange", value: "brown",
priority: 2, // unknown whether this should be above or below reaction/duration? priority: 2, // unknown whether this should be above or below reaction/duration?
overridesAction: true, overridesAction: true,
} },
} };
export const TYPE_NIGHT: DominionBasicCardType = { export const TYPE_NIGHT: DominionBasicCardType = {
typeType: "basic", typeType: "basic",
@ -131,17 +144,17 @@ export const TYPE_NIGHT: DominionBasicCardType = {
value: "black", value: "black",
priority: 6, priority: 6,
onConflictDescriptionOnly: true, onConflictDescriptionOnly: true,
} },
} };
export const TYPE_ATTACK: DominionBasicCardType = { export const TYPE_ATTACK: DominionBasicCardType = {
typeType: "basic", typeType: "basic",
name: "Attack", name: "Attack",
color: null color: null,
} };
export const TYPE_COMMAND: DominionBasicCardType = { export const TYPE_COMMAND: DominionBasicCardType = {
typeType: "basic", typeType: "basic",
name: "Command", 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();