♻️ 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 path from "path";
|
||||
import * as core from "@actions/core";
|
||||
import { generateContributionSnake } from "./generateContributionSnake";
|
||||
import { parseOutputsOption } from "./outputsOptions";
|
||||
|
||||
(async () => {
|
||||
@@ -14,6 +13,9 @@ import { parseOutputsOption } from "./outputsOptions";
|
||||
]
|
||||
);
|
||||
|
||||
const { generateContributionSnake } = await import(
|
||||
"./generateContributionSnake"
|
||||
);
|
||||
const results = await generateContributionSnake(userName, outputs);
|
||||
|
||||
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 { Point } from "@snk/types/point";
|
||||
import { h } from "./utils";
|
||||
import { createAnimation } from "./css-utils";
|
||||
import { h } from "./xml-utils";
|
||||
|
||||
export type Options = {
|
||||
colorDots: Record<Color, string>;
|
||||
@@ -11,8 +12,6 @@ export type Options = {
|
||||
sizeDotBorderRadius: number;
|
||||
};
|
||||
|
||||
const percent = (x: number) => (x * 100).toFixed(2);
|
||||
|
||||
export const createGrid = (
|
||||
cells: (Point & { t: number | null; color: Color | Empty })[],
|
||||
{ sizeDotBorderRadius, sizeDot, sizeCell }: Options,
|
||||
@@ -26,38 +25,40 @@ export const createGrid = (
|
||||
stroke-width: 1px;
|
||||
stroke: var(--cb);
|
||||
animation: none ${duration}ms linear infinite;
|
||||
width: ${sizeDot}px;
|
||||
height: ${sizeDot}px;
|
||||
}`,
|
||||
];
|
||||
|
||||
let i = 0;
|
||||
for (const { x, y, color, t } of cells) {
|
||||
const id = t && "c" + (i++).toString(36);
|
||||
const s = sizeCell;
|
||||
const d = sizeDot;
|
||||
const m = (s - d) / 2;
|
||||
const m = (sizeCell - sizeDot) / 2;
|
||||
|
||||
if (t !== null) {
|
||||
if (t !== null && id) {
|
||||
const animationName = id;
|
||||
|
||||
styles.push(
|
||||
`@keyframes ${animationName} {` +
|
||||
`${percent(t - 0.0001)}%{fill:var(--c${color})}` +
|
||||
`${percent(t + 0.0001)}%,100%{fill:var(--ce)}` +
|
||||
"}",
|
||||
createAnimation(animationName, [
|
||||
{ t: t - 0.0001, style: `fill:var(--c${color})` },
|
||||
{ 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(
|
||||
h("rect", {
|
||||
class: ["c", id].filter(Boolean).join(" "),
|
||||
x: x * s + m,
|
||||
y: y * s + m,
|
||||
x: x * sizeCell + m,
|
||||
y: y * sizeCell + m,
|
||||
rx: 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 { Grid, Color, Empty } from "@snk/types/grid";
|
||||
import type { Point } from "@snk/types/point";
|
||||
import type { AnimationOptions } from "@snk/gif-creator";
|
||||
import { createSnake } from "./snake";
|
||||
import { createGrid } from "./grid";
|
||||
import { createStack } from "./stack";
|
||||
import { h } from "./utils";
|
||||
import * as csso from "csso";
|
||||
import { AnimationOptions } from "@snk/gif-creator";
|
||||
import { h } from "./xml-utils";
|
||||
import { minifyCss } from "./css-utils";
|
||||
|
||||
export type DrawOptions = {
|
||||
colorDots: Record<Color, string>;
|
||||
@@ -132,7 +132,7 @@ export const createSvg = (
|
||||
return optimizeSvg(svg);
|
||||
};
|
||||
|
||||
const optimizeCss = (css: string) => csso.minify(css).css;
|
||||
const optimizeCss = (css: string) => minifyCss(css);
|
||||
const optimizeSvg = (svg: string) => svg;
|
||||
|
||||
const generateColorVar = (drawOptions: DrawOptions) =>
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
"name": "@snk/svg-creator",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@snk/solver": "1.0.0",
|
||||
"csso": "5.0.3"
|
||||
"@snk/solver": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/csso": "5.0.0"
|
||||
}
|
||||
"devDependencies": {}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { getSnakeLength, snakeToCells } from "@snk/types/snake";
|
||||
import type { Snake } from "@snk/types/snake";
|
||||
import type { Point } from "@snk/types/point";
|
||||
import { h } from "./utils";
|
||||
import { h } from "./xml-utils";
|
||||
import { createAnimation } from "./css-utils";
|
||||
|
||||
export type Options = {
|
||||
colorSnake: string;
|
||||
@@ -9,8 +10,6 @@ export type Options = {
|
||||
sizeDot: number;
|
||||
};
|
||||
|
||||
const percent = (x: number) => (x * 100).toFixed(2);
|
||||
|
||||
const lerp = (k: number, a: number, b: number) => (1 - k) * a + k * b;
|
||||
|
||||
export const createSnake = (
|
||||
@@ -55,8 +54,8 @@ export const createSnake = (
|
||||
|
||||
const styles = [
|
||||
`.s{
|
||||
shape-rendering:geometricPrecision;
|
||||
fill:var(--cs);
|
||||
shape-rendering: geometricPrecision;
|
||||
fill: var(--cs);
|
||||
animation: none linear ${duration}ms infinite
|
||||
}`,
|
||||
|
||||
@@ -64,16 +63,17 @@ export const createSnake = (
|
||||
const id = `s${i}`;
|
||||
const animationName = id;
|
||||
|
||||
return [
|
||||
`@keyframes ${animationName} {` +
|
||||
removeInterpolatedPositions(
|
||||
positions.map((tr, i, { length }) => ({ ...tr, t: i / length }))
|
||||
)
|
||||
.map((p) => `${percent(p.t)}%{${transform(p)}}`)
|
||||
.join("") +
|
||||
"}",
|
||||
const keyframes = removeInterpolatedPositions(
|
||||
positions.map((tr, i, { length }) => ({ ...tr, t: i / length }))
|
||||
).map(({ t, ...p }) => ({ t, style: transform(p) }));
|
||||
|
||||
`.s.${id}{${transform(positions[0])};animation-name: ${animationName}}`,
|
||||
return [
|
||||
createAnimation(animationName, keyframes),
|
||||
|
||||
`.s.${id}{
|
||||
${transform(positions[0])};
|
||||
animation-name: ${animationName}
|
||||
}`,
|
||||
];
|
||||
}),
|
||||
].flat();
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
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 = {
|
||||
sizeDot: number;
|
||||
};
|
||||
|
||||
const percent = (x: number) => (x * 100).toFixed(2);
|
||||
|
||||
export const createStack = (
|
||||
cells: { t: number | null; color: Color | Empty }[],
|
||||
{ sizeDot }: Options,
|
||||
@@ -56,23 +55,28 @@ export const createStack = (
|
||||
);
|
||||
|
||||
styles.push(
|
||||
`@keyframes ${animationName} {` +
|
||||
createAnimation(
|
||||
animationName,
|
||||
[
|
||||
...ts.map((t, i, { length }) => [
|
||||
{ scale: i / length, t: t - 0.0001 },
|
||||
{ scale: (i + 1) / length, t: t + 0.0001 },
|
||||
]),
|
||||
[{ scale: 1, t: 1 }],
|
||||
]
|
||||
.flat()
|
||||
.map(
|
||||
({ scale, t }) =>
|
||||
`${percent(t)}%{transform:scale(${scale.toFixed(2)},1)}`
|
||||
)
|
||||
.join("\n") +
|
||||
"}",
|
||||
...ts
|
||||
.map((t, i, { length }) => [
|
||||
{ scale: i / length, t: t - 0.0001 },
|
||||
{ scale: (i + 1) / length, t: t + 0.0001 },
|
||||
])
|
||||
.flat(),
|
||||
{ scale: 1, t: 1 },
|
||||
].map(({ scale, t }) => ({
|
||||
t,
|
||||
style: `transform:scale(${scale.toFixed(3)},1)`,
|
||||
}))
|
||||
),
|
||||
|
||||
`.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