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.
- package/LICENSE +201 -0
- package/README.md +146 -0
- package/dist/soccer-jersey.min.js +8 -0
- package/dist/soccer-jersey.min.js.map +1 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.js +9 -0
- package/lib/index.umd.d.ts +3 -0
- package/lib/patterns/patterns.d.ts +9 -0
- package/lib/patterns/patterns.js +168 -0
- package/lib/stories/ReactTeamPage.d.ts +2 -0
- package/lib/stories/ReactTeamPage.js +6 -0
- package/lib/stories/ReactTeamPage.stories.d.ts +34 -0
- package/lib/stories/ReactTeamPage.stories.js +289 -0
- package/lib/types/index.d.ts +13 -0
- package/lib/types/index.js +1 -0
- package/lib/utils/draw-soccer-jersey.d.ts +30 -0
- package/lib/utils/draw-soccer-jersey.js +131 -0
- package/lib/utils/lighten-darken-color.d.ts +9 -0
- package/lib/utils/lighten-darken-color.js +31 -0
- package/package.json +64 -0
|
@@ -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
|
+
}
|