soccer-jersey-fork 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,131 @@
1
+ /* eslint-disable max-len */
2
+ import { SVG } from '@svgdotjs/svg.js';
3
+ import lightenDarkenColor from './lighten-darken-color';
4
+ import { drawHoops, drawSingleBand, drawStriped, drawCheckered, drawTwoColor, drawWaves, drawDashes, } from '../patterns/patterns';
5
+ /**
6
+ *
7
+ * @param {object} specs Specifications of the soccer jersey.
8
+ * @param {string} specs.shirtText The text to be displayed on the shirt.
9
+ * Recommended 3 letter team initials
10
+ * @param {string} specs.textColor The color (HTML Color Code) for the
11
+ * text displayed on the shirt
12
+ * @param {string} specs.textOutlineColor Optional. The outline color (HTML Color Code) for the
13
+ * text displayed on the shirt
14
+ * @param {string} specs.textBackgroundColor Optional. The background color (HTML Color Code) for the
15
+ * text displayed on the shirt
16
+ * @param {string} specs.shirtColor The main color (HTML Color Code) of
17
+ * the shirt.
18
+ * @param {string} specs.sleeveColor The color (HTML Color Code) of the shirt
19
+ * sleeves;
20
+ * @param {string} specs.shirtStyle The Style of the shirt (torso region).
21
+ * Supports "plain", "two-color", "striped", "striped-thin","striped-thick","checkered",
22
+ * "hoops","single-band", "waves", "dashed";
23
+ * @param {string} specs.shirtStyleColor The color (HTML Color Code) of
24
+ * used for the shirt style.
25
+ * @param {string} specs.shirtStyleDirection The style of the single band.
26
+ * Required when using the "single-band" shirt style. Supports
27
+ * "diagonal-right", "diagonal-left","horizontal", "vertical"
28
+ * @param {boolean} specs.isBack Set to true to draw the shirt from the
29
+ * back (different neck shape, no badges). Defaults to false.
30
+ * @return {string} A data URL ready for direct use as src attribute
31
+ * on <img />
32
+ */
33
+ export default function drawSoccerJersey({ shirtText, textColor, textOutlineColor, textBackgroundColor, shirtColor = 'plain', sleeveColor, shirtStyle, shirtStyleColor, shirtStyleDirection, isBack = false, shirtWidth = 200, }) {
34
+ // Colors and Color Optimizations
35
+ const optimizedSleeveColor = lightenDarkenColor(sleeveColor, -10);
36
+ const optimizedShirtColor = lightenDarkenColor(shirtColor, -10);
37
+ // paths
38
+ const pathLeftSleeve = 'm18 8.5c-4 3-6.1 7.7-8.9 12-3.1 4.9-6 9.9-8.8 15 6 4 12 8.2 19 10 4.1.38 4.3-5.3 3.8-8.2-.29-9.7-3-19-5-29z';
39
+ const pathRightSleeve = 'm83 8.1c4 3 6.1 7.7 8.9 12 3.1 4.9 6 9.9 8.8 15-6 4-12 8.2-19 10-4.1.38-4.3-5.3-3.8-8.2.3-9.7 3-19 5-29z';
40
+ const pathMainBody = 'm83 8c-6.4-2.3-13-5.3-19-8 1.4 5.4-5.4 8.2-10 8.7-5.8.68-13-.075-17-5-1.2-2.1.62-5.1-2.8-2.6-5.6 2.6-11 5.5-17 7.9 5.6 21 3.3 17 6.2 40-.14 15 .16 30-.79 45 1.6 4.7 9.5 4 14 5.2 13 1.8 26 1.2 39-2.3 5.7-1.5 1.5-8.1 2.5-12-.32-15-.32-29-.32-44 5.5-37 1.6-12 4.9-33z';
41
+ const pathNeck = 'm63 .064c-3.8.47-7.5 1.9-11 1.9-5 .31-11-.47-16-1.9-1.7.6-.78 2.8-1.8 4.1-3 5.1-6 10-9 15h50c-3.8-6.4-7.6-13-11-19z';
42
+ const pathNeckBack = 'm63 .064C 60.12,5.3 53.35,6.6 49.86 6.6 44.86 7 40.4 4 36 .064c-1.7.6-.78 2.8-1.8 4.1-3 5.1-6 10-9 15h50c-3.8-6.4-7.6-13-11-19z';
43
+ // eslint-disable-next-line new-cap
44
+ const page = SVG();
45
+ let shirtFill;
46
+ switch (shirtStyle) {
47
+ case 'two-color':
48
+ shirtFill = drawTwoColor(page, optimizedShirtColor, (shirtStyleColor ? shirtStyleColor : '#222'), (shirtStyleDirection ? shirtStyleDirection : 'vertical'));
49
+ break;
50
+ case 'striped-thin':
51
+ shirtFill = drawStriped(page, optimizedShirtColor, (shirtStyleColor ? shirtStyleColor : '#222'), 'thin');
52
+ break;
53
+ case 'striped-thick':
54
+ shirtFill = drawStriped(page, optimizedShirtColor, (shirtStyleColor ? shirtStyleColor : '#222'), 'thick');
55
+ break;
56
+ case 'striped':
57
+ shirtFill = drawStriped(page, optimizedShirtColor, (shirtStyleColor ? shirtStyleColor : '#222'));
58
+ break;
59
+ case 'dashed':
60
+ shirtFill = drawDashes(page, optimizedShirtColor, (shirtStyleColor ? shirtStyleColor : '#222'), (shirtStyleDirection ? shirtStyleDirection : 'vertical'));
61
+ break;
62
+ case 'checkered':
63
+ shirtFill = drawCheckered(page, optimizedShirtColor, (shirtStyleColor ? shirtStyleColor : '#222'));
64
+ break;
65
+ case 'single-band':
66
+ shirtFill = drawSingleBand(page, optimizedShirtColor, (shirtStyleColor ? shirtStyleColor : '#222'), (shirtStyleDirection ? shirtStyleDirection : 'horizontal'));
67
+ break;
68
+ case 'hoops':
69
+ shirtFill = drawHoops(page, optimizedShirtColor, (shirtStyleColor ? shirtStyleColor : '#222'));
70
+ break;
71
+ case 'waves':
72
+ shirtFill = drawWaves(page, optimizedShirtColor, (shirtStyleColor ? shirtStyleColor : '#222'), (shirtStyleDirection == 'vertical' || shirtStyleDirection == 'horizontal' ? shirtStyleDirection : 'vertical'));
73
+ break;
74
+ default:
75
+ shirtFill = optimizedShirtColor;
76
+ }
77
+ // neck
78
+ page.path(isBack ? pathNeckBack : pathNeck).fill(lightenDarkenColor(shirtColor, -50));
79
+ // shirt
80
+ page.path(pathMainBody).fill(shirtFill);
81
+ page.path(pathMainBody).fill(page
82
+ .gradient('linear', function (add) {
83
+ add.stop(0, '#000', 0.2);
84
+ add.stop(0.44, '#ddd', 0.1);
85
+ add.stop(1, '#fff', 0.1);
86
+ })
87
+ .from(1, 1)
88
+ .to(1, 0));
89
+ // badge
90
+ if (!isBack) {
91
+ page.circle(8).fill(lightenDarkenColor(optimizedShirtColor, 60)).move(64, 18);
92
+ page.polygon('0,3 3,0 4,3').fill(lightenDarkenColor(optimizedShirtColor, -20)).move(30, 21);
93
+ }
94
+ // left sleeve
95
+ page.path(pathLeftSleeve).fill(page
96
+ .gradient('linear', function (add) {
97
+ add.stop(0.21, lightenDarkenColor(optimizedSleeveColor, -10));
98
+ add.stop(1, optimizedSleeveColor);
99
+ })
100
+ .from(1, 1)
101
+ .to(0, 0));
102
+ // right sleeve
103
+ page.path(pathRightSleeve).fill(page
104
+ .gradient('linear', function (add) {
105
+ add.stop(0.21, lightenDarkenColor(optimizedSleeveColor, -10));
106
+ add.stop(1, optimizedSleeveColor);
107
+ })
108
+ .from(0, 1)
109
+ .to(1, 0));
110
+ // text
111
+ const optimizedFontSize = (20 / shirtText.length) * 3;
112
+ const drawText = (elem) => elem.text(shirtText)
113
+ .fill(lightenDarkenColor((textColor ? textColor : '#fff'), -50))
114
+ .font({
115
+ family: 'Monospace',
116
+ size: optimizedFontSize > 30 ? 30 : optimizedFontSize,
117
+ style: 'bold',
118
+ })
119
+ .stroke({ color: textOutlineColor ? textOutlineColor : lightenDarkenColor((textColor ? textColor : '#fff'), 10), width: 0.5 })
120
+ .center(50, 35);
121
+ if (textBackgroundColor) {
122
+ // eslint-disable-next-line new-cap
123
+ const draftShirtTextElem = drawText(SVG());
124
+ const dimens = draftShirtTextElem.bbox();
125
+ page.rect(dimens.width + 4, dimens.height + 4).fill(lightenDarkenColor(textBackgroundColor, 10)).center(50, 35);
126
+ }
127
+ drawText(page);
128
+ page.width(shirtWidth);
129
+ page.viewbox('0 0 102 100');
130
+ return page.svg();
131
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Lighten or Darken a color
3
+ * @param {string} color HEX color value
4
+ * @param {number} amount Amount of color shift.
5
+ * For example a value of -10 to darken or 10 to lighten
6
+ * @return {string} a HEX color string
7
+ */
8
+ declare const lightenDarkenColor: (color: string, amount: number) => string;
9
+ export default lightenDarkenColor;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Lighten or Darken a color
3
+ * @param {string} color HEX color value
4
+ * @param {number} amount Amount of color shift.
5
+ * For example a value of -10 to darken or 10 to lighten
6
+ * @return {string} a HEX color string
7
+ */
8
+ const lightenDarkenColor = (color, amount) => {
9
+ color = color.replace(/^#/, '');
10
+ if (color.length === 3) {
11
+ color = color[0] + color[0] + color[1] + color[1] + color[2] + color[2];
12
+ }
13
+ const letterMatch = color.match(/.{2}/g);
14
+ if (!letterMatch) {
15
+ return color;
16
+ }
17
+ const [or, og, ob] = letterMatch;
18
+ const [pr, pg, pb] = [
19
+ parseInt(or, 16) + amount,
20
+ parseInt(og, 16) + amount,
21
+ parseInt(ob, 16) + amount,
22
+ ];
23
+ const r = Math.max(Math.min(255, pr), 0).toString(16);
24
+ const g = Math.max(Math.min(255, pg), 0).toString(16);
25
+ const b = Math.max(Math.min(255, pb), 0).toString(16);
26
+ const rr = (r.length < 2 ? '0' : '') + r;
27
+ const gg = (g.length < 2 ? '0' : '') + g;
28
+ const bb = (b.length < 2 ? '0' : '') + b;
29
+ return `#${rr}${gg}${bb}`;
30
+ };
31
+ export default lightenDarkenColor;
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "soccer-jersey-fork",
3
+ "version": "1.0.15",
4
+ "description": "Generate soccer jerseys in SVG format",
5
+ "main": "lib/index.js",
6
+ "scripts": {
7
+ "build": "./node_modules/typescript/bin/tsc -p .",
8
+ "build:umd": "webpack --mode=production",
9
+ "dev:umd": "webpack serve --mode=development --watch-content-base --progress --open=true",
10
+ "build:deploy": "npm version patch && npm run build-storybook && npm run build:umd && npm run build",
11
+ "doc": "typedoc src/index.ts",
12
+ "test": "echo \"Error: no test specified\" && exit 1",
13
+ "storybook": "storybook dev -p 6006",
14
+ "build-storybook": "storybook build"
15
+ },
16
+ "keywords": [
17
+ "soccer",
18
+ "shirt",
19
+ "svg",
20
+ "fpl"
21
+ ],
22
+ "author": "nadchif (https://github.com/nadchif)",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/nadchif/soccer-jersey.git"
26
+ },
27
+ "license": "MIT",
28
+ "files": [
29
+ "lib",
30
+ "dist"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "devDependencies": {
36
+ "@babel/preset-env": "^7.21.5",
37
+ "@babel/preset-react": "^7.18.6",
38
+ "@babel/preset-typescript": "^7.21.5",
39
+ "@storybook/addon-essentials": "^7.0.17",
40
+ "@storybook/addon-interactions": "^7.0.17",
41
+ "@storybook/addon-links": "^7.0.17",
42
+ "@storybook/blocks": "^7.0.17",
43
+ "@storybook/react": "^9.1.3",
44
+ "@storybook/react-webpack5": "^7.0.17",
45
+ "@storybook/testing-library": "^0.0.14-next.2",
46
+ "@typescript-eslint/eslint-plugin": "^4.15.1",
47
+ "@typescript-eslint/parser": "^4.15.1",
48
+ "eslint": "^7.20.0",
49
+ "eslint-config-google": "^0.14.0",
50
+ "prop-types": "^15.8.1",
51
+ "react": "^19.1.1",
52
+ "react-dom": "^19.1.1",
53
+ "storybook": "^7.0.17",
54
+ "ts-loader": "^8.0.17",
55
+ "typedoc": "^0.24.7",
56
+ "typescript": "^5.9.2",
57
+ "webpack": "^5.23.0",
58
+ "webpack-cli": "^4.5.0",
59
+ "webpack-dev-server": "^4.15.0"
60
+ },
61
+ "dependencies": {
62
+ "@svgdotjs/svg.js": "github:svgdotjs/svg.js"
63
+ }
64
+ }