@inglorious/logo 1.0.0

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.
Files changed (71) hide show
  1. package/.babelrc +6 -0
  2. package/.eslintrc.cjs +33 -0
  3. package/.storybook/main.js +18 -0
  4. package/.storybook/preview.js +14 -0
  5. package/LICENSE.md +1 -0
  6. package/dist/eye.svg +36 -0
  7. package/dist/faces/A.svg +30 -0
  8. package/dist/faces/B.svg +35 -0
  9. package/dist/faces/C.svg +26 -0
  10. package/dist/faces/D.svg +28 -0
  11. package/dist/faces/E.svg +30 -0
  12. package/dist/faces/F.svg +28 -0
  13. package/dist/faces/G.svg +28 -0
  14. package/dist/faces/H.svg +28 -0
  15. package/dist/faces/I.svg +24 -0
  16. package/dist/faces/J.svg +26 -0
  17. package/dist/faces/K.svg +27 -0
  18. package/dist/faces/L.svg +24 -0
  19. package/dist/faces/M.svg +28 -0
  20. package/dist/faces/N.svg +26 -0
  21. package/dist/faces/O.svg +26 -0
  22. package/dist/faces/P.svg +30 -0
  23. package/dist/faces/Q.svg +33 -0
  24. package/dist/faces/R.svg +32 -0
  25. package/dist/faces/S.svg +30 -0
  26. package/dist/faces/T.svg +26 -0
  27. package/dist/faces/U.svg +24 -0
  28. package/dist/faces/V.svg +23 -0
  29. package/dist/faces/W.svg +28 -0
  30. package/dist/faces/X.svg +28 -0
  31. package/dist/faces/Y.svg +25 -0
  32. package/dist/faces/Z.svg +28 -0
  33. package/dist/faces/index.js +188 -0
  34. package/dist/index.js +138 -0
  35. package/dist/logo.js +95 -0
  36. package/dist/logo.module.css +43 -0
  37. package/dist/logo.stories.js +56 -0
  38. package/package.json +51 -0
  39. package/src/eye.svg +36 -0
  40. package/src/faces/A.svg +30 -0
  41. package/src/faces/B.svg +35 -0
  42. package/src/faces/C.svg +26 -0
  43. package/src/faces/D.svg +28 -0
  44. package/src/faces/E.svg +30 -0
  45. package/src/faces/F.svg +28 -0
  46. package/src/faces/G.svg +28 -0
  47. package/src/faces/H.svg +28 -0
  48. package/src/faces/I.svg +24 -0
  49. package/src/faces/J.svg +26 -0
  50. package/src/faces/K.svg +27 -0
  51. package/src/faces/L.svg +24 -0
  52. package/src/faces/M.svg +28 -0
  53. package/src/faces/N.svg +26 -0
  54. package/src/faces/O.svg +26 -0
  55. package/src/faces/P.svg +30 -0
  56. package/src/faces/Q.svg +33 -0
  57. package/src/faces/R.svg +32 -0
  58. package/src/faces/S.svg +30 -0
  59. package/src/faces/T.svg +26 -0
  60. package/src/faces/U.svg +24 -0
  61. package/src/faces/V.svg +23 -0
  62. package/src/faces/W.svg +28 -0
  63. package/src/faces/X.svg +28 -0
  64. package/src/faces/Y.svg +25 -0
  65. package/src/faces/Z.svg +28 -0
  66. package/src/faces/index.js +55 -0
  67. package/src/index.jsx +148 -0
  68. package/src/logo.jsx +101 -0
  69. package/src/logo.module.css +43 -0
  70. package/src/logo.stories.jsx +38 -0
  71. package/vite.config.js +8 -0
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 6 6">
3
+ <style>
4
+ #letter {
5
+ fill: rgb(127, 127, 255);
6
+ fill-opacity: 0.5;
7
+ stroke: rgb(127, 127, 192);
8
+ stroke-width: 0.25;
9
+ stroke-opacity: 0.5;
10
+ }
11
+ </style>
12
+
13
+ <path id="letter" d="
14
+ M 0 0
15
+ L 6 0
16
+ L 6 2
17
+ L 4 1
18
+ L 2 1
19
+ L 2 2
20
+ L 6 3
21
+ L 6 6
22
+ L 0 6
23
+ L 0 4
24
+ L 2 5
25
+ L 4 5
26
+ L 4 4
27
+ L 0 3
28
+ Z
29
+ " />
30
+ </svg>
@@ -0,0 +1,26 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 6 6">
3
+ <style>
4
+ #letter {
5
+ fill: rgb(127, 127, 255);
6
+ fill-opacity: 0.5;
7
+ stroke: rgb(127, 127, 192);
8
+ stroke-width: 0.25;
9
+ stroke-opacity: 0.5;
10
+ }
11
+ </style>
12
+
13
+ <path id="letter" d="
14
+ M 0 0
15
+ L 6 0
16
+ L 6 2
17
+ L 4 1
18
+ L 4 5
19
+ L 6 6
20
+ L 0 6
21
+ L 2 5
22
+ L 2 1
23
+ L 0 2
24
+ Z
25
+ " />
26
+ </svg>
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 6 6">
3
+ <style>
4
+ #letter {
5
+ fill: rgb(127, 127, 255);
6
+ fill-opacity: 0.5;
7
+ stroke: rgb(127, 127, 192);
8
+ stroke-width: 0.25;
9
+ stroke-opacity: 0.5;
10
+ }
11
+ </style>
12
+
13
+ <path id="letter" d="
14
+ M 0 0
15
+ L 2 0
16
+ L 2 4
17
+ L 4 4
18
+ L 4 0
19
+ L 6 0
20
+ L 6 6
21
+ L 0 6
22
+ Z
23
+ " />
24
+ </svg>
@@ -0,0 +1,23 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 6 6">
3
+ <style>
4
+ #letter {
5
+ fill: rgb(127, 127, 255);
6
+ fill-opacity: 0.5;
7
+ stroke: rgb(127, 127, 192);
8
+ stroke-width: 0.25;
9
+ stroke-opacity: 0.5;
10
+ }
11
+ </style>
12
+
13
+ <path id="letter" d="
14
+ M 0 0
15
+ L 2 0
16
+ L 3 4
17
+ L 4 0
18
+ L 6 0
19
+ L 4 6
20
+ L 2 6
21
+ Z
22
+ " />
23
+ </svg>
@@ -0,0 +1,28 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 6 6">
3
+ <style>
4
+ #letter {
5
+ fill: rgb(127, 127, 255);
6
+ fill-opacity: 0.5;
7
+ stroke: rgb(127, 127, 192);
8
+ stroke-width: 0.25;
9
+ stroke-opacity: 0.5;
10
+ }
11
+ </style>
12
+
13
+ <path id="letter" d="
14
+ M 0 0
15
+ L 2 0
16
+ L 2 3
17
+ L 3 1
18
+ L 4 3
19
+ L 4 0
20
+ L 6 0
21
+ L 6 6
22
+ L 4 6
23
+ L 3 4
24
+ L 2 6
25
+ L 0 6
26
+ Z
27
+ " />
28
+ </svg>
@@ -0,0 +1,28 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 6 6">
3
+ <style>
4
+ #letter {
5
+ fill: rgb(127, 127, 255);
6
+ fill-opacity: 0.5;
7
+ stroke: rgb(127, 127, 192);
8
+ stroke-width: 0.25;
9
+ stroke-opacity: 0.5;
10
+ }
11
+ </style>
12
+
13
+ <path id="letter" d="
14
+ M 0 0
15
+ L 2 0
16
+ L 3 2
17
+ L 4 0
18
+ L 6 0
19
+ L 4 3
20
+ L 6 6
21
+ L 4 6
22
+ L 3 4
23
+ L 2 6
24
+ L 0 6
25
+ L 2 3
26
+ Z
27
+ " />
28
+ </svg>
@@ -0,0 +1,25 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 6 6">
3
+ <style>
4
+ #letter {
5
+ fill: rgb(127, 127, 255);
6
+ fill-opacity: 0.5;
7
+ stroke: rgb(127, 127, 192);
8
+ stroke-width: 0.25;
9
+ stroke-opacity: 0.5;
10
+ }
11
+ </style>
12
+
13
+ <path id="letter" d="
14
+ M 0 0
15
+ L 2 0
16
+ L 3 2
17
+ L 4 0
18
+ L 6 0
19
+ L 4 3
20
+ L 4 6
21
+ L 2 6
22
+ L 2 3
23
+ Z
24
+ " />
25
+ </svg>
@@ -0,0 +1,28 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 6 6">
3
+ <style>
4
+ #letter {
5
+ fill: rgb(127, 127, 255);
6
+ fill-opacity: 0.5;
7
+ stroke: rgb(127, 127, 192);
8
+ stroke-width: 0.25;
9
+ stroke-opacity: 0.5;
10
+ }
11
+ </style>
12
+
13
+ <path id="letter" d="
14
+ M 0 0
15
+ L 6 0
16
+ L 6 1
17
+ L 2 5
18
+ L 4 5
19
+ L 6 4
20
+ L 6 6
21
+ L 0 6
22
+ L 0 5
23
+ L 4 1
24
+ L 2 1
25
+ L 0 2
26
+ Z
27
+ " />
28
+ </svg>
@@ -0,0 +1,55 @@
1
+ import A from "./A.svg";
2
+ import B from "./B.svg";
3
+ import C from "./C.svg";
4
+ import D from "./D.svg";
5
+ import E from "./E.svg";
6
+ import F from "./F.svg";
7
+ import G from "./G.svg";
8
+ import H from "./H.svg";
9
+ import I from "./I.svg";
10
+ import J from "./J.svg";
11
+ import K from "./K.svg";
12
+ import L from "./L.svg";
13
+ import M from "./M.svg";
14
+ import N from "./N.svg";
15
+ import O from "./O.svg";
16
+ import P from "./P.svg";
17
+ import Q from "./Q.svg";
18
+ import R from "./R.svg";
19
+ import S from "./S.svg";
20
+ import T from "./T.svg";
21
+ import U from "./U.svg";
22
+ import V from "./V.svg";
23
+ import W from "./W.svg";
24
+ import X from "./X.svg";
25
+ import Y from "./Y.svg";
26
+ import Z from "./Z.svg";
27
+
28
+ export {
29
+ A,
30
+ B,
31
+ C,
32
+ D,
33
+ E,
34
+ F,
35
+ G,
36
+ H,
37
+ I,
38
+ J,
39
+ K,
40
+ L,
41
+ M,
42
+ N,
43
+ O,
44
+ P,
45
+ Q,
46
+ R,
47
+ S,
48
+ T,
49
+ U,
50
+ V,
51
+ W,
52
+ X,
53
+ Y,
54
+ Z,
55
+ };
package/src/index.jsx ADDED
@@ -0,0 +1,148 @@
1
+ import PropTypes from "prop-types";
2
+ import { memo, useEffect, useRef, useState } from "react";
3
+
4
+ import LogoComponent from "./logo";
5
+
6
+ const MAX_HEAD_TILT_X = 400;
7
+ const MAX_HEAD_TILT_Y = 400;
8
+ const HALF = 0.5;
9
+ const FIRST_ITEM = 0;
10
+
11
+ const Logo = memo(function Logo({ size, faces, isInteractive, preventScroll }) {
12
+ const [coords, setCoords] = useState({ x: 0, y: 0 });
13
+
14
+ const logo = useRef();
15
+
16
+ useEffect(() => {
17
+ if (!isInteractive) {
18
+ return;
19
+ }
20
+
21
+ const { left, top, width, height } = logo.current.getBoundingClientRect();
22
+
23
+ const center = {
24
+ x: window.scrollX + left + width * HALF,
25
+ y: window.scrollY + top + height * HALF,
26
+ };
27
+
28
+ const moveEvent = isTouchDevice() ? "touchmove" : "mousemove";
29
+ document.addEventListener(moveEvent, onMove, {
30
+ passive: !preventScroll,
31
+ });
32
+
33
+ return () => {
34
+ document.removeEventListener(moveEvent, onMove);
35
+ };
36
+
37
+ function onMove(event) {
38
+ const { target, pageX, pageY } =
39
+ moveEvent.current === "touchmove" ? event.touches[FIRST_ITEM] : event;
40
+
41
+ if (preventScroll && closestAncestor(target, "logo")) {
42
+ event.preventDefault();
43
+ }
44
+
45
+ setCoords({
46
+ x: saturate(pageX - center.x, MAX_HEAD_TILT_X),
47
+ y: saturate(pageY - center.y, MAX_HEAD_TILT_Y),
48
+ });
49
+ }
50
+ }, [isInteractive, preventScroll]);
51
+
52
+ return <LogoComponent size={size} faces={faces} {...coords} ref={logo} />;
53
+ });
54
+
55
+ Logo.propTypes = {
56
+ size: PropTypes.number.isRequired,
57
+ faces: PropTypes.arrayOf(
58
+ PropTypes.shape({
59
+ image: PropTypes.oneOf([
60
+ "A",
61
+ "B",
62
+ "C",
63
+ "D",
64
+ "E",
65
+ "F",
66
+ "G",
67
+ "H",
68
+ "I",
69
+ "J",
70
+ "K",
71
+ "L",
72
+ "M",
73
+ "N",
74
+ "O",
75
+ "P",
76
+ "Q",
77
+ "R",
78
+ "S",
79
+ "T",
80
+ "U",
81
+ "V",
82
+ "W",
83
+ "X",
84
+ "Y",
85
+ "Z",
86
+ ]),
87
+ reverse: PropTypes.bool,
88
+ eye: PropTypes.bool,
89
+ }).isRequired
90
+ ).isRequired,
91
+ isInteractive: PropTypes.bool.isRequired,
92
+ preventScroll: PropTypes.bool.isRequired,
93
+ };
94
+
95
+ Logo.defaultProps = {
96
+ size: 64,
97
+ faces: [
98
+ { image: "I", reverse: false, eye: true },
99
+ { image: "C", reverse: false, eye: false },
100
+ ],
101
+ isInteractive: false,
102
+ preventScroll: false,
103
+ };
104
+
105
+ export default Logo;
106
+
107
+ function isTouchDevice() {
108
+ if (
109
+ "ontouchstart" in window ||
110
+ (window.DocumentTouch && document instanceof window.DocumentTouch)
111
+ ) {
112
+ return true;
113
+ }
114
+
115
+ // include the 'heartz' as a way to have a non matching mediaQuery to help terminate the join
116
+ // https://git.io/vznFH
117
+ const prefixes = " -webkit- -moz- -o- -ms- ".split(" ");
118
+ var query = ["(", prefixes.join("touch-enabled),("), "heartz", ")"].join("");
119
+ return window.matchMedia(query).matches;
120
+ }
121
+
122
+ function saturate(num, limit) {
123
+ if (num < -limit) return -limit;
124
+ if (num > limit) return limit;
125
+ return num;
126
+ }
127
+
128
+ function closestAncestor(el, className) {
129
+ const limit = 4;
130
+ let i = 0;
131
+ let closest = el;
132
+ while (closest && i < limit) {
133
+ if (
134
+ closest.className == null ||
135
+ typeof closest.className.split !== "function"
136
+ ) {
137
+ return null;
138
+ }
139
+
140
+ const classes = closest.className.split(" ");
141
+ if (classes.includes(className)) {
142
+ return closest;
143
+ }
144
+
145
+ closest = closest.parentNode;
146
+ i++;
147
+ }
148
+ }
package/src/logo.jsx ADDED
@@ -0,0 +1,101 @@
1
+ import PropTypes from "prop-types";
2
+ import { forwardRef, memo } from "react";
3
+
4
+ import eye from "./eye.svg";
5
+ import * as faceSvgs from "./faces";
6
+ import classes from "./logo.module.css";
7
+
8
+ const MINUS_FORTY_DEGREES = -0.6981;
9
+ const MINUS_FORTY_FIVE_DEGREES = -0.7854;
10
+ const STEP = 0.001;
11
+ const HALF = 0.5;
12
+
13
+ const Logo = memo(
14
+ forwardRef(function Logo({ size, faces, x, y }, ref) {
15
+ const [left, right] = faces;
16
+
17
+ return (
18
+ <div
19
+ className={classes.logo}
20
+ ref={ref}
21
+ style={{
22
+ "--size": `${size}px`,
23
+ "--transform": `scaleY(1.2) translateZ(-${size}px) rotateX(${
24
+ MINUS_FORTY_DEGREES - STEP * y
25
+ }rad)
26
+ rotateY(${MINUS_FORTY_FIVE_DEGREES + STEP * x}rad)`,
27
+ "--z-translation": `${size * HALF}px`,
28
+ "--left-face-flip": left.reverse ? "rotateY(180deg);" : "none",
29
+ "--right-face-flip": right.reverse ? "rotateY(180deg);" : "none",
30
+ }}
31
+ >
32
+ <div className={classes.cube}>
33
+ <div className={`${classes.face} ${classes.left}`}>
34
+ <img src={faceSvgs[left.image]} alt={left.image} />
35
+ {left.eye && (
36
+ <img className={classes.eye} src={eye} alt="left eye" />
37
+ )}
38
+ </div>
39
+ <div className={`${classes.face} ${classes.right}`}>
40
+ <img src={faceSvgs[right.image]} alt={right.image} />
41
+ {right.eye && (
42
+ <img className={classes.eye} src={eye} alt="right eye" />
43
+ )}
44
+ </div>
45
+ </div>
46
+ </div>
47
+ );
48
+ })
49
+ );
50
+
51
+ Logo.propTypes = {
52
+ size: PropTypes.number.isRequired,
53
+ faces: PropTypes.arrayOf(
54
+ PropTypes.shape({
55
+ image: PropTypes.oneOf([
56
+ "A",
57
+ "B",
58
+ "C",
59
+ "D",
60
+ "E",
61
+ "F",
62
+ "G",
63
+ "H",
64
+ "I",
65
+ "J",
66
+ "K",
67
+ "L",
68
+ "M",
69
+ "N",
70
+ "O",
71
+ "P",
72
+ "Q",
73
+ "R",
74
+ "S",
75
+ "T",
76
+ "U",
77
+ "V",
78
+ "W",
79
+ "X",
80
+ "Y",
81
+ "Z",
82
+ ]),
83
+ reverse: PropTypes.bool,
84
+ eye: PropTypes.bool,
85
+ })
86
+ ).isRequired,
87
+ x: PropTypes.number.isRequired,
88
+ y: PropTypes.number.isRequired,
89
+ };
90
+
91
+ Logo.defaultProps = {
92
+ size: 64,
93
+ faces: [
94
+ { image: "I", reverse: false, eye: true },
95
+ { image: "C", reverse: false, eye: false },
96
+ ],
97
+ x: 0,
98
+ y: 0,
99
+ };
100
+
101
+ export default Logo;
@@ -0,0 +1,43 @@
1
+ .logo {
2
+ width: var(--size);
3
+ perspective: var(--size);
4
+ margin: 0 auto;
5
+ }
6
+
7
+ .cube {
8
+ height: var(--size);
9
+ transform-style: preserve-3d;
10
+ transform: var(--transform);
11
+ transition: ease-out 0.2s;
12
+ }
13
+
14
+ .face {
15
+ position: absolute;
16
+ width: 100%;
17
+ height: 100%;
18
+ transform-origin: bottom center;
19
+ }
20
+
21
+ .face > img {
22
+ position: absolute;
23
+ }
24
+
25
+ .left {
26
+ transform: rotateY(0deg) translateZ(var(--z-translation)) skew(12deg);
27
+ }
28
+
29
+ .right {
30
+ transform: rotateY(90deg) translateZ(var(--z-translation)) skew(-12deg);
31
+ }
32
+
33
+ .right > .eye {
34
+ transform: rotateY(180deg);
35
+ }
36
+
37
+ .left > img:first-of-type {
38
+ transform: var(--left-face-flip);
39
+ }
40
+
41
+ .right > img:first-of-type {
42
+ transform: var(--right-face-flip);
43
+ }
@@ -0,0 +1,38 @@
1
+ import Logo from ".";
2
+
3
+ export default {
4
+ title: "Inglorious Logo",
5
+ component: Logo,
6
+ };
7
+
8
+ export const Default = {
9
+ args: {},
10
+ };
11
+
12
+ export const Big = {
13
+ args: { size: 320 },
14
+ };
15
+
16
+ export const Interactive = {
17
+ args: { ...Big.args, isInteractive: true },
18
+ };
19
+
20
+ export const IngloriousEngine = {
21
+ decorators: [
22
+ (Story) => (
23
+ <div
24
+ style={{
25
+ background: "black",
26
+ width: 320,
27
+ height: 240,
28
+ display: "flex",
29
+ justifyContent: "center",
30
+ alignItems: "center",
31
+ }}
32
+ >
33
+ <Story />
34
+ </div>
35
+ ),
36
+ ],
37
+ args: { size: 128, faces: [{ image: "I", eye: true }, { image: "E" }] },
38
+ };
package/vite.config.js ADDED
@@ -0,0 +1,8 @@
1
+ import react from "@vitejs/plugin-react";
2
+ import { defineConfig } from "vite";
3
+ import svgrPlugin from "vite-plugin-svgr";
4
+
5
+ // https://vitejs.dev/config/
6
+ export default defineConfig({
7
+ plugins: [react(), svgrPlugin()],
8
+ });