♻️ remove csso dependency
do a custom css optimization instead
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import * as fs from "fs";
|
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 { parseOutputsOption } from "./outputsOptions";
|
import { parseOutputsOption } from "./outputsOptions";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
@@ -14,6 +13,9 @@ import { parseOutputsOption } from "./outputsOptions";
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { generateContributionSnake } = await import(
|
||||||
|
"./generateContributionSnake"
|
||||||
|
);
|
||||||
const results = await generateContributionSnake(userName, outputs);
|
const results = await generateContributionSnake(userName, outputs);
|
||||||
|
|
||||||
outputs.forEach((out, i) => {
|
outputs.forEach((out, i) => {
|
||||||
|
|||||||
26
packages/svg-creator/__tests__/minifyCss.spec.ts
Normal file
26
packages/svg-creator/__tests__/minifyCss.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { minifyCss } from "../css-utils";
|
||||||
|
|
||||||
|
it("should minify css", () => {
|
||||||
|
expect(
|
||||||
|
minifyCss(`
|
||||||
|
.c {
|
||||||
|
color : red ;
|
||||||
|
}
|
||||||
|
|
||||||
|
`)
|
||||||
|
).toBe(".c{color:red}");
|
||||||
|
|
||||||
|
expect(
|
||||||
|
minifyCss(`
|
||||||
|
.c {
|
||||||
|
top : 0;
|
||||||
|
color : red ;
|
||||||
|
}
|
||||||
|
|
||||||
|
# {
|
||||||
|
animation: linear 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
`)
|
||||||
|
).toBe(".c{top:0;color:red}#{animation:linear 10}");
|
||||||
|
});
|
||||||
38
packages/svg-creator/css-utils.ts
Normal file
38
packages/svg-creator/css-utils.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
const percent = (x: number) =>
|
||||||
|
parseFloat((x * 100).toFixed(2)).toString() + "%";
|
||||||
|
|
||||||
|
const mergeKeyFrames = (keyframes: { t: number; style: string }[]) => {
|
||||||
|
const s = new Map<string, number[]>();
|
||||||
|
for (const { t, style } of keyframes) {
|
||||||
|
s.set(style, [...(s.get(style) ?? []), t]);
|
||||||
|
}
|
||||||
|
return Array.from(s.entries())
|
||||||
|
.map(([style, ts]) => ({ style, ts }))
|
||||||
|
.sort((a, b) => a.ts[0] - b.ts[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generate the keyframe animation from a list of keyframe
|
||||||
|
*/
|
||||||
|
export const createAnimation = (
|
||||||
|
name: string,
|
||||||
|
keyframes: { t: number; style: string }[]
|
||||||
|
) =>
|
||||||
|
`@keyframes ${name}{` +
|
||||||
|
mergeKeyFrames(keyframes)
|
||||||
|
.map(({ style, ts }) => ts.map(percent).join(",") + `{${style}}`)
|
||||||
|
.join("") +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove white spaces
|
||||||
|
*/
|
||||||
|
export const minifyCss = (css: string) =>
|
||||||
|
css
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
.replace(/.\s+[,;:{}()]/g, (a) => a.replace(/\s+/g, ""))
|
||||||
|
.replace(/[,;:{}()]\s+./g, (a) => a.replace(/\s+/g, ""))
|
||||||
|
.replace(/.\s+[,;:{}()]/g, (a) => a.replace(/\s+/g, ""))
|
||||||
|
.replace(/[,;:{}()]\s+./g, (a) => a.replace(/\s+/g, ""))
|
||||||
|
.replace(/\;\s*\}/g, "}")
|
||||||
|
.trim();
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { Color, Empty } from "@snk/types/grid";
|
import type { Color, Empty } from "@snk/types/grid";
|
||||||
import type { Point } from "@snk/types/point";
|
import type { Point } from "@snk/types/point";
|
||||||
import { h } from "./utils";
|
import { createAnimation } from "./css-utils";
|
||||||
|
import { h } from "./xml-utils";
|
||||||
|
|
||||||
export type Options = {
|
export type Options = {
|
||||||
colorDots: Record<Color, string>;
|
colorDots: Record<Color, string>;
|
||||||
@@ -11,8 +12,6 @@ export type Options = {
|
|||||||
sizeDotBorderRadius: number;
|
sizeDotBorderRadius: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
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 })[],
|
||||||
{ sizeDotBorderRadius, sizeDot, sizeCell }: Options,
|
{ sizeDotBorderRadius, sizeDot, sizeCell }: Options,
|
||||||
@@ -26,38 +25,40 @@ export const createGrid = (
|
|||||||
stroke-width: 1px;
|
stroke-width: 1px;
|
||||||
stroke: var(--cb);
|
stroke: var(--cb);
|
||||||
animation: none ${duration}ms linear infinite;
|
animation: none ${duration}ms linear infinite;
|
||||||
|
width: ${sizeDot}px;
|
||||||
|
height: ${sizeDot}px;
|
||||||
}`,
|
}`,
|
||||||
];
|
];
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (const { x, y, color, t } of cells) {
|
for (const { x, y, color, t } of cells) {
|
||||||
const id = t && "c" + (i++).toString(36);
|
const id = t && "c" + (i++).toString(36);
|
||||||
const s = sizeCell;
|
const m = (sizeCell - sizeDot) / 2;
|
||||||
const d = sizeDot;
|
|
||||||
const m = (s - d) / 2;
|
|
||||||
|
|
||||||
if (t !== null) {
|
if (t !== null && id) {
|
||||||
const animationName = id;
|
const animationName = id;
|
||||||
|
|
||||||
styles.push(
|
styles.push(
|
||||||
`@keyframes ${animationName} {` +
|
createAnimation(animationName, [
|
||||||
`${percent(t - 0.0001)}%{fill:var(--c${color})}` +
|
{ t: t - 0.0001, style: `fill:var(--c${color})` },
|
||||||
`${percent(t + 0.0001)}%,100%{fill:var(--ce)}` +
|
{ t: t + 0.0001, style: `fill:var(--ce)` },
|
||||||
"}",
|
{ t: 1, style: `fill:var(--ce)` },
|
||||||
|
]),
|
||||||
|
|
||||||
`.c.${id}{fill: var(--c${color}); animation-name: ${animationName}}`
|
`.c.${id}{
|
||||||
|
fill: var(--c${color});
|
||||||
|
animation-name: ${animationName}
|
||||||
|
}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
svgElements.push(
|
svgElements.push(
|
||||||
h("rect", {
|
h("rect", {
|
||||||
class: ["c", id].filter(Boolean).join(" "),
|
class: ["c", id].filter(Boolean).join(" "),
|
||||||
x: x * s + m,
|
x: x * sizeCell + m,
|
||||||
y: y * s + m,
|
y: y * sizeCell + m,
|
||||||
rx: sizeDotBorderRadius,
|
rx: sizeDotBorderRadius,
|
||||||
ry: sizeDotBorderRadius,
|
ry: sizeDotBorderRadius,
|
||||||
width: d,
|
|
||||||
height: d,
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import { getHeadX, getHeadY } from "@snk/types/snake";
|
|||||||
import type { Snake } from "@snk/types/snake";
|
import type { Snake } from "@snk/types/snake";
|
||||||
import type { Grid, Color, Empty } from "@snk/types/grid";
|
import type { Grid, Color, Empty } from "@snk/types/grid";
|
||||||
import type { Point } from "@snk/types/point";
|
import type { Point } from "@snk/types/point";
|
||||||
|
import type { AnimationOptions } from "@snk/gif-creator";
|
||||||
import { createSnake } from "./snake";
|
import { createSnake } from "./snake";
|
||||||
import { createGrid } from "./grid";
|
import { createGrid } from "./grid";
|
||||||
import { createStack } from "./stack";
|
import { createStack } from "./stack";
|
||||||
import { h } from "./utils";
|
import { h } from "./xml-utils";
|
||||||
import * as csso from "csso";
|
import { minifyCss } from "./css-utils";
|
||||||
import { AnimationOptions } from "@snk/gif-creator";
|
|
||||||
|
|
||||||
export type DrawOptions = {
|
export type DrawOptions = {
|
||||||
colorDots: Record<Color, string>;
|
colorDots: Record<Color, string>;
|
||||||
@@ -132,7 +132,7 @@ export const createSvg = (
|
|||||||
return optimizeSvg(svg);
|
return optimizeSvg(svg);
|
||||||
};
|
};
|
||||||
|
|
||||||
const optimizeCss = (css: string) => csso.minify(css).css;
|
const optimizeCss = (css: string) => minifyCss(css);
|
||||||
const optimizeSvg = (svg: string) => svg;
|
const optimizeSvg = (svg: string) => svg;
|
||||||
|
|
||||||
const generateColorVar = (drawOptions: DrawOptions) =>
|
const generateColorVar = (drawOptions: DrawOptions) =>
|
||||||
|
|||||||
@@ -2,10 +2,7 @@
|
|||||||
"name": "@snk/svg-creator",
|
"name": "@snk/svg-creator",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@snk/solver": "1.0.0",
|
"@snk/solver": "1.0.0"
|
||||||
"csso": "5.0.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {}
|
||||||
"@types/csso": "5.0.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
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 { Point } from "@snk/types/point";
|
import type { Point } from "@snk/types/point";
|
||||||
import { h } from "./utils";
|
import { h } from "./xml-utils";
|
||||||
|
import { createAnimation } from "./css-utils";
|
||||||
|
|
||||||
export type Options = {
|
export type Options = {
|
||||||
colorSnake: string;
|
colorSnake: string;
|
||||||
@@ -9,8 +10,6 @@ export type Options = {
|
|||||||
sizeDot: number;
|
sizeDot: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const percent = (x: number) => (x * 100).toFixed(2);
|
|
||||||
|
|
||||||
const lerp = (k: number, a: number, b: number) => (1 - k) * a + k * b;
|
const lerp = (k: number, a: number, b: number) => (1 - k) * a + k * b;
|
||||||
|
|
||||||
export const createSnake = (
|
export const createSnake = (
|
||||||
@@ -55,8 +54,8 @@ export const createSnake = (
|
|||||||
|
|
||||||
const styles = [
|
const styles = [
|
||||||
`.s{
|
`.s{
|
||||||
shape-rendering:geometricPrecision;
|
shape-rendering: geometricPrecision;
|
||||||
fill:var(--cs);
|
fill: var(--cs);
|
||||||
animation: none linear ${duration}ms infinite
|
animation: none linear ${duration}ms infinite
|
||||||
}`,
|
}`,
|
||||||
|
|
||||||
@@ -64,16 +63,17 @@ export const createSnake = (
|
|||||||
const id = `s${i}`;
|
const id = `s${i}`;
|
||||||
const animationName = id;
|
const animationName = id;
|
||||||
|
|
||||||
return [
|
const keyframes = removeInterpolatedPositions(
|
||||||
`@keyframes ${animationName} {` +
|
positions.map((tr, i, { length }) => ({ ...tr, t: i / length }))
|
||||||
removeInterpolatedPositions(
|
).map(({ t, ...p }) => ({ t, style: transform(p) }));
|
||||||
positions.map((tr, i, { length }) => ({ ...tr, t: i / length }))
|
|
||||||
)
|
|
||||||
.map((p) => `${percent(p.t)}%{${transform(p)}}`)
|
|
||||||
.join("") +
|
|
||||||
"}",
|
|
||||||
|
|
||||||
`.s.${id}{${transform(positions[0])};animation-name: ${animationName}}`,
|
return [
|
||||||
|
createAnimation(animationName, keyframes),
|
||||||
|
|
||||||
|
`.s.${id}{
|
||||||
|
${transform(positions[0])};
|
||||||
|
animation-name: ${animationName}
|
||||||
|
}`,
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
].flat();
|
].flat();
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import type { Color, Empty } from "@snk/types/grid";
|
import type { Color, Empty } from "@snk/types/grid";
|
||||||
import { h } from "./utils";
|
import { createAnimation } from "./css-utils";
|
||||||
|
import { h } from "./xml-utils";
|
||||||
|
|
||||||
export type Options = {
|
export type Options = {
|
||||||
sizeDot: number;
|
sizeDot: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const percent = (x: number) => (x * 100).toFixed(2);
|
|
||||||
|
|
||||||
export const createStack = (
|
export const createStack = (
|
||||||
cells: { t: number | null; color: Color | Empty }[],
|
cells: { t: number | null; color: Color | Empty }[],
|
||||||
{ sizeDot }: Options,
|
{ sizeDot }: Options,
|
||||||
@@ -56,23 +55,28 @@ export const createStack = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
styles.push(
|
styles.push(
|
||||||
`@keyframes ${animationName} {` +
|
createAnimation(
|
||||||
|
animationName,
|
||||||
[
|
[
|
||||||
...ts.map((t, i, { length }) => [
|
...ts
|
||||||
{ scale: i / length, t: t - 0.0001 },
|
.map((t, i, { length }) => [
|
||||||
{ scale: (i + 1) / length, t: t + 0.0001 },
|
{ scale: i / length, t: t - 0.0001 },
|
||||||
]),
|
{ scale: (i + 1) / length, t: t + 0.0001 },
|
||||||
[{ scale: 1, t: 1 }],
|
])
|
||||||
]
|
.flat(),
|
||||||
.flat()
|
{ scale: 1, t: 1 },
|
||||||
.map(
|
].map(({ scale, t }) => ({
|
||||||
({ scale, t }) =>
|
t,
|
||||||
`${percent(t)}%{transform:scale(${scale.toFixed(2)},1)}`
|
style: `transform:scale(${scale.toFixed(3)},1)`,
|
||||||
)
|
}))
|
||||||
.join("\n") +
|
),
|
||||||
"}",
|
|
||||||
|
|
||||||
`.u.${id}{fill:var(--c${color});animation-name:${animationName};transform-origin:${x}px 0}`
|
`.u.${id} {
|
||||||
|
fill: var(--c${color});
|
||||||
|
animation-name: ${animationName};
|
||||||
|
transform-origin: ${x}px 0
|
||||||
|
}
|
||||||
|
`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user