change options, drop svg_out_path in favor of outputs list

This commit is contained in:
Platane
2022-04-11 23:19:33 +02:00
committed by GitHub
parent 579bcf1afe
commit 6b320a1ac4
25 changed files with 296 additions and 154 deletions

View File

@@ -45,14 +45,17 @@ jobs:
uses: ./ uses: ./
with: with:
github_user_name: platane github_user_name: platane
gif_out_path: dist/github-contribution-grid-snake.gif outputs: |
svg_out_path: dist/github-contribution-grid-snake.svg dist/github-contribution-grid-snake.svg
dist/github-contribution-grid-snake-dark.svg?palette=github-dark
dist/github-contribution-grid-snake.gif?color_snake=orange&color_dots=#bfd6f6,#8dbdff,#64a1f4,#4b91f1,#3c7dd9
- name: ensure the generated file exists - name: ensure the generated file exists
run: | run: |
ls dist ls dist
test -f ${{ steps.generate-snake.outputs.gif_out_path }} test -f dist/github-contribution-grid-snake.svg
test -f ${{ steps.generate-snake.outputs.svg_out_path }} test -f dist/github-contribution-grid-snake-dark.svg
test -f dist/github-contribution-grid-snake.gif
- uses: crazy-max/ghaction-github-pages@v2.5.0 - uses: crazy-max/ghaction-github-pages@v2.5.0
with: with:
@@ -76,7 +79,7 @@ jobs:
GITHUB_USER_CONTRIBUTION_API_ENDPOINT: https://snk-one.vercel.app/api/github-user-contribution/ GITHUB_USER_CONTRIBUTION_API_ENDPOINT: https://snk-one.vercel.app/api/github-user-contribution/
- uses: crazy-max/ghaction-github-pages@v2.6.0 - uses: crazy-max/ghaction-github-pages@v2.6.0
if: success() && github.ref == 'refs/heads/master' if: success() && github.ref.name == 'main'
with: with:
target_branch: gh-pages target_branch: gh-pages
build_dir: packages/demo/dist build_dir: packages/demo/dist

View File

@@ -65,7 +65,7 @@ jobs:
git add package.json svg-only/dist action.yml git add package.json svg-only/dist action.yml
git commit -m "📦 $VERSION" git commit -m "📦 $VERSION"
git tag v$VERSION git tag v$VERSION
git push origin master --tags git push origin main --tags
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
git tag v$( echo $VERSION | cut -d. -f 1-1 ) git tag v$( echo $VERSION | cut -d. -f 1-1 )

View File

@@ -21,24 +21,23 @@ Available as github action. Automatically generate a new image at the end of the
**github action** **github action**
```yaml ```yaml
- uses: Platane/snk@v1 - uses: Platane/snk@v2
with: with:
# github user name to read the contribution graph from (**required**) # github user name to read the contribution graph from (**required**)
# using action context var `github.repository_owner` or specified user # using action context var `github.repository_owner` or specified user
github_user_name: ${{ github.repository_owner }} github_user_name: ${{ github.repository_owner }}
# path of the generated gif file # list of files to generate.
# If left empty, the gif file will not be generated # one file per line. Each output can be customized with options as query string.
gif_out_path: dist/github-snake.gif outputs: |
dist/github-snake.svg
# path of the generated svg file dist/github-snake.svg?palette=github-dark
# If left empty, the svg file will not be generated dist/ocean.gif?color_snake=orange&color_dots=#bfd6f6,#8dbdff,#64a1f4,#4b91f1,#3c7dd9
svg_out_path: dist/github-snake.svg
``` ```
[example with cron job](https://github.com/Platane/Platane/blob/master/.github/workflows/main.yml#L24-L29) [example with cron job](https://github.com/Platane/Platane/blob/master/.github/workflows/main.yml#L24-L29)
If you are only interested in generating a svg, you can use this other faster action: `uses: Platane/snk/svg-only@v1` If you are only interested in generating a svg, you can use this other faster action: `uses: Platane/snk/svg-only@v2`
**interactive demo** **interactive demo**

View File

@@ -10,17 +10,22 @@ inputs:
github_user_name: github_user_name:
description: "github user name" description: "github user name"
required: true required: true
gif_out_path: outputs:
description: "path of the generated gif file. If left empty, the gif file will not be generated."
required: false
default: null
svg_out_path:
description: "path of the generated svg file. If left empty, the svg file will not be generated."
required: false required: false
default: null default: null
description: |
list of files to generate.
Generates one file per line. Each output can be customized with query string.
following this pattern: path/to/file.<gif or svg>?palette=<github or github-dark>&color_snake=<color>&color_dots=<color>,<color>,<color>,<color>,<color>
outputs: supported query string options:
gif_out_path:
description: "path of the generated gif" - palette: a preset of color, one of [github, github-dark, github-light]
svg_out_path: - color_snake: color of the snake
description: "path of the generated svg" - color_dots: coma separated list of dots color. The first one is the empty cell color, the second one is the lightest shade, the third one is the second lightest shade ect ...
example:
outputs: |
dark.svg?palette=github-dark&color_snake=blue
light.svg?color_snake=#7845ab
ocean.gif?color_snake=orange&color_dots=#bfd6f6,#8dbdff,#64a1f4,#4b91f1,#3c7dd9

View File

@@ -1,7 +1,7 @@
{ {
"name": "snk", "name": "snk",
"description": "Generates a snake game from a github user contributions grid", "description": "Generates a snake game from a github user contributions grid",
"version": "1.1.3", "version": "2.0.0",
"private": true, "private": true,
"repository": "github:platane/snk", "repository": "github:platane/snk",
"devDependencies": { "devDependencies": {

View File

@@ -1,2 +1,3 @@
* *
!.gitignore !.gitignore
!*.snap

View File

@@ -0,0 +1,66 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should parse /out.svg?color_snake=orange&color_dots=#bfd6f6,#8dbdff,#64a1f4,#4b91f1,#3c7dd9 1`] = `
Object {
"drawOptions": Object {
"colorDotBorder": "#1b1f230a",
"colorDots": Array [
"#bfd6f6",
"#8dbdff",
"#64a1f4",
"#4b91f1",
"#3c7dd9",
],
"colorEmpty": "#bfd6f6",
"colorSnake": "orange",
"dark": undefined,
"sizeCell": 16,
"sizeDot": 12,
"sizeDotBorderRadius": 2,
},
"filename": "/out.svg",
"format": "svg",
"gifOptions": Object {
"frameDuration": 100,
"step": 1,
},
}
`;
exports[`should parse path/to/out.gif 1`] = `
Object {
"drawOptions": Object {
"colorDotBorder": "#1b1f230a",
"colorDots": Array [
"#ebedf0",
"#9be9a8",
"#40c463",
"#30a14e",
"#216e39",
],
"colorEmpty": "#ebedf0",
"colorSnake": "purple",
"dark": Object {
"colorDotBorder": "#1b1f230a",
"colorDots": Array [
"#161b22",
"#01311f",
"#034525",
"#0f6d31",
"#00c647",
],
"colorEmpty": "#161b22",
"colorSnake": "purple",
},
"sizeCell": 16,
"sizeDot": 12,
"sizeDotBorderRadius": 2,
},
"filename": "path/to/out.gif",
"format": "gif",
"gifOptions": Object {
"frameDuration": 100,
"step": 1,
},
}
`;

View File

@@ -1,19 +0,0 @@
import * as fs from "fs";
import * as path from "path";
import { generateContributionSnake } from "../generateContributionSnake";
(async () => {
const outputSvg = path.join(__dirname, "__snapshots__/out.svg");
const outputGif = path.join(__dirname, "__snapshots__/out.gif");
const buffer = await generateContributionSnake("platane", {
svg: true,
gif: true,
});
console.log("💾 writing to", outputSvg);
fs.writeFileSync(outputSvg, buffer.svg);
console.log("💾 writing to", outputGif);
fs.writeFileSync(outputGif, buffer.gif);
})();

View File

@@ -1,6 +1,7 @@
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import { generateContributionSnake } from "../generateContributionSnake"; import { generateContributionSnake } from "../generateContributionSnake";
import { parseOutputsOption } from "../outputsOptions";
jest.setTimeout(2 * 60 * 1000); jest.setTimeout(2 * 60 * 1000);
@@ -17,22 +18,26 @@ const silent = (handler: () => void | Promise<void>) => async () => {
it( it(
"should generate contribution snake", "should generate contribution snake",
silent(async () => { silent(async () => {
const outputSvg = path.join(__dirname, "__snapshots__/out.svg"); const entries = [
const outputGif = path.join(__dirname, "__snapshots__/out.gif"); path.join(__dirname, "__snapshots__/out.svg"),
console.log = () => undefined; path.join(__dirname, "__snapshots__/out-dark.svg") +
const buffer = await generateContributionSnake("platane", { "?palette=github-dark&color_snake=orange",
svg: true,
gif: true,
});
expect(buffer.svg).toBeDefined(); path.join(__dirname, "__snapshots__/out.gif") +
expect(buffer.gif).toBeDefined(); "?color_snake=orange&color_dots=#d4e0f0,#8dbdff,#64a1f4,#4b91f1,#3c7dd9",
];
console.log("💾 writing to", outputSvg); const outputs = parseOutputsOption(entries);
fs.writeFileSync(outputSvg, buffer.svg);
console.log("💾 writing to", outputGif); const results = await generateContributionSnake("platane", outputs);
fs.writeFileSync(outputGif, buffer.gif);
expect(results[0]).toBeDefined();
expect(results[1]).toBeDefined();
expect(results[2]).toBeDefined();
fs.writeFileSync(outputs[0]!.filename, results[0]!);
fs.writeFileSync(outputs[1]!.filename, results[1]!);
fs.writeFileSync(outputs[2]!.filename, results[2]!);
}) })
); );

View File

@@ -0,0 +1,11 @@
import { parseEntry } from "../outputsOptions";
[
"path/to/out.gif",
"/out.svg?color_snake=orange&color_dots=#bfd6f6,#8dbdff,#64a1f4,#4b91f1,#3c7dd9",
].forEach((entry) =>
it(`should parse ${entry}`, () => {
expect(parseEntry(entry)).toMatchSnapshot();
})
);

View File

@@ -3,10 +3,18 @@ import { userContributionToGrid } from "./userContributionToGrid";
import { getBestRoute } from "@snk/solver/getBestRoute"; import { getBestRoute } from "@snk/solver/getBestRoute";
import { snake4 } from "@snk/types/__fixtures__/snake"; import { snake4 } from "@snk/types/__fixtures__/snake";
import { getPathToPose } from "@snk/solver/getPathToPose"; import { getPathToPose } from "@snk/solver/getPathToPose";
import { Options as DrawOptions } from "@snk/svg-creator";
export const generateContributionSnake = async ( export const generateContributionSnake = async (
userName: string, userName: string,
format: { svg?: boolean; gif?: boolean } outputs: ({
format: "svg" | "gif";
drawOptions: DrawOptions;
gifOptions: {
frameDuration: number;
step: number;
};
} | null)[]
) => { ) => {
console.log("🎣 fetching github user contribution"); console.log("🎣 fetching github user contribution");
const { cells, colorScheme } = await getGithubUserContribution(userName); const { cells, colorScheme } = await getGithubUserContribution(userName);
@@ -14,40 +22,26 @@ export const generateContributionSnake = async (
const grid = userContributionToGrid(cells, colorScheme); const grid = userContributionToGrid(cells, colorScheme);
const snake = snake4; const snake = snake4;
const drawOptions = {
sizeBorderRadius: 2,
sizeCell: 16,
sizeDot: 12,
colorBorder: "#1b1f230a",
colorDots: colorScheme as any,
colorEmpty: colorScheme[0],
colorSnake: "purple",
cells,
dark: {
colorEmpty: "#161b22",
colorDots: { 1: "#01311f", 2: "#034525", 3: "#0f6d31", 4: "#00c647" },
},
};
const gifOptions = { frameDuration: 100, step: 1 };
console.log("📡 computing best route"); console.log("📡 computing best route");
const chain = getBestRoute(grid, snake)!; const chain = getBestRoute(grid, snake)!;
chain.push(...getPathToPose(chain.slice(-1)[0], snake)!); chain.push(...getPathToPose(chain.slice(-1)[0], snake)!);
const output: Record<string, Buffer | string> = {}; return Promise.all(
outputs.map(async (out, i) => {
if (format.gif) { if (!out) return;
console.log("📹 creating gif"); const { format, drawOptions, gifOptions } = out;
const { createGif } = await import("@snk/gif-creator"); switch (format) {
output.gif = await createGif(grid, chain, drawOptions, gifOptions); case "svg": {
} console.log(`🖌 creating svg (outputs[${i}])`);
const { createSvg } = await import("@snk/svg-creator");
if (format.svg) { return createSvg(grid, chain, drawOptions, gifOptions);
console.log("🖌 creating svg"); }
const { createSvg } = await import("@snk/svg-creator"); case "gif": {
output.svg = createSvg(grid, chain, drawOptions, gifOptions); console.log(`📹 creating gif (outputs[${i}])`);
} const { createGif } = await import("@snk/gif-creator");
return await createGif(grid, chain, drawOptions, gifOptions);
return output; }
}
})
);
}; };

View File

@@ -2,30 +2,28 @@ import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { generateContributionSnake } from "./generateContributionSnake"; import { generateContributionSnake } from "./generateContributionSnake";
import { parseOutputsOption } from "./outputsOptions";
(async () => { (async () => {
try { try {
const userName = core.getInput("github_user_name"); const userName = core.getInput("github_user_name");
const format = { const outputs = parseOutputsOption(
svg: core.getInput("svg_out_path"), core.getMultilineInput("outputs") ?? [
gif: core.getInput("gif_out_path"), core.getInput("gif_out_path"),
}; core.getInput("svg_out_path"),
]
const { svg, gif } = await generateContributionSnake(
userName,
format as any
); );
if (svg) { const results = await generateContributionSnake(userName, outputs);
fs.mkdirSync(path.dirname(format.svg), { recursive: true });
fs.writeFileSync(format.svg, svg); outputs.forEach((out, i) => {
core.setOutput("svg_out_path", format.svg); const result = results[i];
} if (out?.filename && result) {
if (gif) { console.log(`💾 writing to ${out?.filename}`);
fs.mkdirSync(path.dirname(format.gif), { recursive: true }); fs.mkdirSync(path.dirname(out?.filename), { recursive: true });
fs.writeFileSync(format.gif, gif); fs.writeFileSync(out?.filename, result);
core.setOutput("gif_out_path", format.gif); }
} });
} catch (e: any) { } catch (e: any) {
core.setFailed(`Action failed with "${e.message}"`); core.setFailed(`Action failed with "${e.message}"`);
} }

View File

@@ -0,0 +1,54 @@
import { Options as DrawOptions } from "@snk/svg-creator";
import { palettes } from "./palettes";
export const parseOutputsOption = (lines: string[]) => lines.map(parseEntry);
export const parseEntry = (entry: string) => {
const m = entry.trim().match(/^(.+\.(svg|gif))(\?.*)?$/);
if (!m) return null;
const [_, filename, format, query] = m;
const sp = new URLSearchParams(query || "");
const drawOptions: DrawOptions = {
sizeDotBorderRadius: 2,
sizeCell: 16,
sizeDot: 12,
...palettes["default"],
};
const gifOptions = { step: 1, frameDuration: 100 };
{
const palette = palettes[sp.get("palette")!];
if (palette) {
Object.assign(drawOptions, palette);
drawOptions.dark = palette.dark && { ...palette.dark };
}
}
if (sp.has("color_snake")) drawOptions.colorSnake = sp.get("color_snake")!;
if (sp.has("color_dots")) {
const colors = sp.get("color_dots")!.split(/[,;]/);
drawOptions.colorDots = colors;
drawOptions.colorEmpty = colors[0];
drawOptions.dark = undefined;
}
if (sp.has("color_dot_border"))
drawOptions.colorDotBorder = sp.get("color_dot_border")!;
if (sp.has("dark_color_dots")) {
const colors = sp.get("dark_color_dots")!.split(/[,;]/);
drawOptions.dark = {
...drawOptions.dark,
colorDots: colors,
colorEmpty: colors[0],
};
}
if (sp.has("dark_color_dot_border") && drawOptions.dark)
drawOptions.dark.colorDotBorder = sp.get("color_dot_border")!;
if (sp.has("dark_color_snake") && drawOptions.dark)
drawOptions.dark.colorSnake = sp.get("color_snake")!;
return { filename, format: format as "svg" | "gif", drawOptions, gifOptions };
};

View File

@@ -10,11 +10,9 @@
"@snk/types": "1.0.0" "@snk/types": "1.0.0"
}, },
"devDependencies": { "devDependencies": {
"@vercel/ncc": "0.24.1", "@vercel/ncc": "0.24.1"
"ts-node": "10.7.0"
}, },
"scripts": { "scripts": {
"build": "ncc build --external canvas --external gifsicle --out dist ./index.ts", "build": "ncc build --external canvas --external gifsicle --out dist ./index.ts"
"dev": "ts-node __tests__/dev.ts"
} }
} }

View File

@@ -0,0 +1,29 @@
import { Options as DrawOptions } from "@snk/svg-creator";
export const palettes: Record<
string,
Pick<
DrawOptions,
"colorDotBorder" | "colorEmpty" | "colorSnake" | "colorDots" | "dark"
>
> = {
"github-light": {
colorDotBorder: "#1b1f230a",
colorDots: ["#ebedf0", "#9be9a8", "#40c463", "#30a14e", "#216e39"],
colorEmpty: "#ebedf0",
colorSnake: "purple",
},
"github-dark": {
colorDotBorder: "#1b1f230a",
colorEmpty: "#161b22",
colorDots: ["#161b22", "#01311f", "#034525", "#0f6d31", "#00c647"],
colorSnake: "purple",
},
};
// aliases
palettes["github"] = {
...palettes["github-light"],
dark: { ...palettes["github-dark"] },
};
palettes["default"] = palettes["github"];

View File

@@ -1,12 +1,13 @@
import { Color, Grid } from "@snk/types/grid"; import { Color, Grid } from "@snk/types/grid";
import { drawLerpWorld, drawWorld } from "@snk/draw/drawWorld"; import { drawLerpWorld, drawWorld } from "@snk/draw/drawWorld";
import { Snake } from "@snk/types/snake"; import { Snake } from "@snk/types/snake";
import type { Options as DrawOptions } from "@snk/svg-creator";
export const drawOptions = { export const drawOptions: DrawOptions = {
sizeBorderRadius: 2, sizeDotBorderRadius: 2,
sizeCell: 16, sizeCell: 16,
sizeDot: 12, sizeDot: 12,
colorBorder: "#1b1f230a", colorDotBorder: "#1b1f230a",
colorDots: { colorDots: {
1: "#9be9a8", 1: "#9be9a8",
2: "#40c463", 2: "#40c463",

View File

@@ -6,7 +6,7 @@ import type { Snake } from "@snk/types/snake";
import { import {
drawLerpWorld, drawLerpWorld,
getCanvasWorldSize, getCanvasWorldSize,
Options, Options as DrawOptions,
} from "@snk/draw/drawWorld"; } from "@snk/draw/drawWorld";
import { userContributionToGrid } from "@snk/action/userContributionToGrid"; import { userContributionToGrid } from "@snk/action/userContributionToGrid";
import { createSvg } from "@snk/svg-creator"; import { createSvg } from "@snk/svg-creator";
@@ -120,7 +120,7 @@ const createViewer = ({
}: { }: {
grid0: Grid; grid0: Grid;
chain: Snake[]; chain: Snake[];
drawOptions: Options; drawOptions: DrawOptions;
}) => { }) => {
// //
// canvas // canvas
@@ -229,11 +229,11 @@ const onSubmit = async (userName: string) => {
); );
const { cells, colorScheme } = (await res.json()) as Res; const { cells, colorScheme } = (await res.json()) as Res;
const drawOptions = { const drawOptions: DrawOptions = {
sizeBorderRadius: 2, sizeDotBorderRadius: 2,
sizeCell: 16, sizeCell: 16,
sizeDot: 12, sizeDot: 12,
colorBorder: "#1b1f230a", colorDotBorder: "#1b1f230a",
colorDots: colorScheme as any, colorDots: colorScheme as any,
colorEmpty: colorScheme[0], colorEmpty: colorScheme[0],
colorSnake: "purple", colorSnake: "purple",

View File

@@ -6,10 +6,10 @@ import type { Point } from "@snk/types/point";
type Options = { type Options = {
colorDots: Record<Color, string>; colorDots: Record<Color, string>;
colorEmpty: string; colorEmpty: string;
colorBorder: string; colorDotBorder: string;
sizeCell: number; sizeCell: number;
sizeDot: number; sizeDot: number;
sizeBorderRadius: number; sizeDotBorderRadius: number;
cells?: Point[]; cells?: Point[];
}; };
@@ -31,11 +31,11 @@ export const drawGrid = (
); );
ctx.fillStyle = color; ctx.fillStyle = color;
ctx.strokeStyle = o.colorBorder; ctx.strokeStyle = o.colorDotBorder;
ctx.lineWidth = 1; ctx.lineWidth = 1;
ctx.beginPath(); ctx.beginPath();
pathRoundedRect(ctx, o.sizeDot, o.sizeDot, o.sizeBorderRadius); pathRoundedRect(ctx, o.sizeDot, o.sizeDot, o.sizeDotBorderRadius);
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();

View File

@@ -7,11 +7,11 @@ import type { Snake } from "@snk/types/snake";
export type Options = { export type Options = {
colorDots: Record<Color, string>; colorDots: Record<Color, string>;
colorEmpty: string; colorEmpty: string;
colorBorder: string; colorDotBorder: string;
colorSnake: string; colorSnake: string;
sizeCell: number; sizeCell: number;
sizeDot: number; sizeDot: number;
sizeBorderRadius: number; sizeDotBorderRadius: number;
cells?: Point[]; cells?: Point[];
}; };

View File

@@ -5,6 +5,7 @@ import { realistic as grid } from "@snk/types/__fixtures__/grid";
import { createGif } from ".."; import { createGif } from "..";
import { getBestRoute } from "@snk/solver/getBestRoute"; import { getBestRoute } from "@snk/solver/getBestRoute";
import { getPathToPose } from "@snk/solver/getPathToPose"; import { getPathToPose } from "@snk/solver/getPathToPose";
import type { Options as DrawOptions } from "@snk/draw/drawWorld";
let snake = createSnakeFromCells( let snake = createSnakeFromCells(
Array.from({ length: 4 }, (_, i) => ({ x: i, y: -1 })) Array.from({ length: 4 }, (_, i) => ({ x: i, y: -1 }))
@@ -24,11 +25,11 @@ let snake = createSnakeFromCells(
const chain = getBestRoute(grid, snake)!; const chain = getBestRoute(grid, snake)!;
chain.push(...getPathToPose(chain.slice(-1)[0], snake)!); chain.push(...getPathToPose(chain.slice(-1)[0], snake)!);
const drawOptions = { const drawOptions: DrawOptions = {
sizeBorderRadius: 2, sizeDotBorderRadius: 2,
sizeCell: 16, sizeCell: 16,
sizeDot: 12, sizeDot: 12,
colorBorder: "#1b1f230a", colorDotBorder: "#1b1f230a",
colorDots: { 1: "#9be9a8", 2: "#40c463", 3: "#30a14e", 4: "#216e39" }, colorDots: { 1: "#9be9a8", 2: "#40c463", 3: "#30a14e", 4: "#216e39" },
colorEmpty: "#ebedf0", colorEmpty: "#ebedf0",
colorSnake: "purple", colorSnake: "purple",

View File

@@ -5,15 +5,16 @@ import * as grids from "@snk/types/__fixtures__/grid";
import { snake3 as snake } from "@snk/types/__fixtures__/snake"; import { snake3 as snake } from "@snk/types/__fixtures__/snake";
import { createSnakeFromCells, nextSnake } from "@snk/types/snake"; import { createSnakeFromCells, nextSnake } from "@snk/types/snake";
import { getBestRoute } from "@snk/solver/getBestRoute"; import { getBestRoute } from "@snk/solver/getBestRoute";
import type { Options as DrawOptions } from "@snk/draw/drawWorld";
jest.setTimeout(20 * 1000); jest.setTimeout(20 * 1000);
const upscale = 1; const upscale = 1;
const drawOptions = { const drawOptions: DrawOptions = {
sizeBorderRadius: 2 * upscale, sizeDotBorderRadius: 2 * upscale,
sizeCell: 16 * upscale, sizeCell: 16 * upscale,
sizeDot: 12 * upscale, sizeDot: 12 * upscale,
colorBorder: "#1b1f230a", colorDotBorder: "#1b1f230a",
colorDots: { 1: "#9be9a8", 2: "#40c463", 3: "#30a14e", 4: "#216e39" }, colorDots: { 1: "#9be9a8", 2: "#40c463", 3: "#30a14e", 4: "#216e39" },
colorEmpty: "#ebedf0", colorEmpty: "#ebedf0",
colorSnake: "purple", colorSnake: "purple",

View File

@@ -1,15 +1,15 @@
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import { createSvg } from ".."; import { createSvg, Options } from "..";
import * as grids from "@snk/types/__fixtures__/grid"; import * as grids from "@snk/types/__fixtures__/grid";
import { snake3 as snake } from "@snk/types/__fixtures__/snake"; import { snake3 as snake } from "@snk/types/__fixtures__/snake";
import { getBestRoute } from "@snk/solver/getBestRoute"; import { getBestRoute } from "@snk/solver/getBestRoute";
const drawOptions = { const drawOptions: Options = {
sizeBorderRadius: 2, sizeDotBorderRadius: 2,
sizeCell: 16, sizeCell: 16,
sizeDot: 12, sizeDot: 12,
colorBorder: "#1b1f230a", colorDotBorder: "#1b1f230a",
colorDots: { 1: "#9be9a8", 2: "#40c463", 3: "#30a14e", 4: "#216e39" }, colorDots: { 1: "#9be9a8", 2: "#40c463", 3: "#30a14e", 4: "#216e39" },
colorEmpty: "#ebedf0", colorEmpty: "#ebedf0",
colorSnake: "purple", colorSnake: "purple",

View File

@@ -5,17 +5,17 @@ import { h } from "./utils";
export type Options = { export type Options = {
colorDots: Record<Color, string>; colorDots: Record<Color, string>;
colorEmpty: string; colorEmpty: string;
colorBorder: string; colorDotBorder: string;
sizeCell: number; sizeCell: number;
sizeDot: number; sizeDot: number;
sizeBorderRadius: number; sizeDotBorderRadius: number;
}; };
const percent = (x: number) => (x * 100).toFixed(2); const percent = (x: number) => (x * 100).toFixed(2);
export const createGrid = ( export const createGrid = (
cells: (Point & { t: number | null; color: Color | Empty })[], cells: (Point & { t: number | null; color: Color | Empty })[],
{ sizeBorderRadius, sizeDot, sizeCell }: Options, { sizeDotBorderRadius, sizeDot, sizeCell }: Options,
duration: number duration: number
) => { ) => {
const svgElements: string[] = []; const svgElements: string[] = [];
@@ -54,8 +54,8 @@ export const createGrid = (
class: ["c", id].filter(Boolean).join(" "), class: ["c", id].filter(Boolean).join(" "),
x: x * s + m, x: x * s + m,
y: y * s + m, y: y * s + m,
rx: sizeBorderRadius, rx: sizeDotBorderRadius,
ry: sizeBorderRadius, ry: sizeDotBorderRadius,
width: d, width: d,
height: d, height: d,
}) })

View File

@@ -18,16 +18,16 @@ import * as csso from "csso";
export type Options = { export type Options = {
colorDots: Record<Color, string>; colorDots: Record<Color, string>;
colorEmpty: string; colorEmpty: string;
colorBorder: string; colorDotBorder: string;
colorSnake: string; colorSnake: string;
sizeCell: number; sizeCell: number;
sizeDot: number; sizeDot: number;
sizeBorderRadius: number; sizeDotBorderRadius: number;
cells?: Point[]; cells?: Point[];
dark?: { dark?: {
colorDots: Record<Color, string>; colorDots: Record<Color, string>;
colorEmpty: string; colorEmpty: string;
colorBorder?: string; colorDotBorder?: string;
colorSnake?: string; colorSnake?: string;
}; };
}; };
@@ -137,7 +137,7 @@ const optimizeSvg = (svg: string) => svg;
const generateColorVar = (drawOptions: Options) => const generateColorVar = (drawOptions: Options) =>
` `
:root { :root {
--cb: ${drawOptions.colorBorder}; --cb: ${drawOptions.colorDotBorder};
--cs: ${drawOptions.colorSnake}; --cs: ${drawOptions.colorSnake};
--ce: ${drawOptions.colorEmpty}; --ce: ${drawOptions.colorEmpty};
${Object.entries(drawOptions.colorDots) ${Object.entries(drawOptions.colorDots)
@@ -149,7 +149,7 @@ const generateColorVar = (drawOptions: Options) =>
? ` ? `
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
--cb: ${drawOptions.dark.colorBorder || drawOptions.colorBorder}; --cb: ${drawOptions.dark.colorDotBorder || drawOptions.colorDotBorder};
--cs: ${drawOptions.dark.colorSnake || drawOptions.colorSnake}; --cs: ${drawOptions.dark.colorSnake || drawOptions.colorSnake};
--ce: ${drawOptions.dark.colorEmpty}; --ce: ${drawOptions.dark.colorEmpty};
${Object.entries(drawOptions.dark.colorDots) ${Object.entries(drawOptions.dark.colorDots)

View File

@@ -1,17 +1,12 @@
import { getSnakeLength, snakeToCells } from "@snk/types/snake"; import { getSnakeLength, snakeToCells } from "@snk/types/snake";
import type { Snake } from "@snk/types/snake"; import type { Snake } from "@snk/types/snake";
import type { Color } from "@snk/types/grid";
import type { Point } from "@snk/types/point"; import type { Point } from "@snk/types/point";
import { h } from "./utils"; import { h } from "./utils";
export type Options = { export type Options = {
colorDots: Record<Color, string>;
colorEmpty: string;
colorBorder: string;
colorSnake: string; colorSnake: string;
sizeCell: number; sizeCell: number;
sizeDot: number; sizeDot: number;
sizeBorderRadius: number;
}; };
const percent = (x: number) => (x * 100).toFixed(2); const percent = (x: number) => (x * 100).toFixed(2);