Compare commits
659 Commits
pre-releas
...
v2.6.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
284ccd43f8 | ||
|
|
5a66153dfc | ||
|
|
363981a2f7 | ||
|
|
7848aa2f0c | ||
|
|
0a7b653ec8 | ||
|
|
313c4dbb71 | ||
|
|
1927323fb7 | ||
|
|
41f11f3040 | ||
|
|
9833628867 | ||
|
|
4dd911e73d | ||
|
|
56487d3832 | ||
|
|
a9f6afffc2 | ||
|
|
09f7f64099 | ||
|
|
4ab06abefe | ||
|
|
ce15fd21ad | ||
|
|
3c1399b44a | ||
|
|
50ca75da0e | ||
|
|
5b417a321a | ||
|
|
bbb43de87b | ||
|
|
2e4d306d79 | ||
|
|
afb7f4bd2e | ||
|
|
67db8b5be8 | ||
|
|
09d6556abd | ||
|
|
bfe4e01c85 | ||
|
|
d8304a3f00 | ||
|
|
8a443e9cad | ||
|
|
0e29639222 | ||
|
|
7b0725029f | ||
|
|
704d06cfe7 | ||
|
|
acfd7ebd2d | ||
|
|
5fb5693792 | ||
|
|
dd3f3f0499 | ||
|
|
ff73ed2521 | ||
|
|
5efa1d1795 | ||
|
|
f010365151 | ||
|
|
7f177f6b83 | ||
|
|
66b839742a | ||
|
|
2e2b0074b1 | ||
|
|
49283daa4f | ||
|
|
3bcda37e66 | ||
|
|
684cf30d2f | ||
|
|
8989478af4 | ||
|
|
d3446b64a3 | ||
|
|
87cd91b0f8 | ||
|
|
e01946a1e4 | ||
|
|
72edb1897f | ||
|
|
1c13343e8a | ||
|
|
85ee0747d1 | ||
|
|
e2f03aaf81 | ||
|
|
6c676fa8da | ||
|
|
183b3ae8cc | ||
|
|
43143bfdf6 | ||
|
|
c6a564f7e4 | ||
|
|
762aed50b7 | ||
|
|
bb91350ef5 | ||
|
|
ec9b299b37 | ||
|
|
0e6a4818ea | ||
|
|
181c984b27 | ||
|
|
7adbe01723 | ||
|
|
a5339af0dd | ||
|
|
c91e5e6b7b | ||
|
|
ccc4202aa4 | ||
|
|
118f848308 | ||
|
|
c36ff60778 | ||
|
|
474e610c3d | ||
|
|
0b6ae0ce32 | ||
|
|
fad1b984bf | ||
|
|
6cc6986904 | ||
|
|
26d5c0a08a | ||
|
|
78e1d1f81a | ||
|
|
48862141dc | ||
|
|
47f8264c31 | ||
|
|
851da0707c | ||
|
|
4275bdd0c0 | ||
|
|
828e5d0903 | ||
|
|
1cbd98ec53 | ||
|
|
df036d3904 | ||
|
|
08dbe94679 | ||
|
|
24e9764fcb | ||
|
|
eb2a2717b1 | ||
|
|
9d74fe2d6e | ||
|
|
8413f6345c | ||
|
|
37a53b747c | ||
|
|
a642080b90 | ||
|
|
9cb5cffdb1 | ||
|
|
57b9942cce | ||
|
|
1274584497 | ||
|
|
513a285fee | ||
|
|
b2bb3baa01 | ||
|
|
3f933dd166 | ||
|
|
1180b9afb0 | ||
|
|
b4ce6efd7b | ||
|
|
da0ada925f | ||
|
|
f9346931f8 | ||
|
|
1d18abf6c1 | ||
|
|
a644d30228 | ||
|
|
1c453e2981 | ||
|
|
170abfcc2f | ||
|
|
0539b15ddc | ||
|
|
bbadb1a917 | ||
|
|
480ca46a95 | ||
|
|
b7bdb1a502 | ||
|
|
3be528d03a | ||
|
|
ebc386cfa5 | ||
|
|
35f3a347ba | ||
|
|
cfcc9f82d8 | ||
|
|
7ab4254cd0 | ||
|
|
e3857e61c6 | ||
|
|
a02579d6dd | ||
|
|
79910dfec7 | ||
|
|
b40540b118 | ||
|
|
99711fc44e | ||
|
|
3eafad7261 | ||
|
|
80905d9d29 | ||
|
|
34db0da87c | ||
|
|
ff33554716 | ||
|
|
f399d17721 | ||
|
|
ce71f22316 | ||
|
|
1f3f76373d | ||
|
|
c5fe2f5e68 | ||
|
|
c050998f3d | ||
|
|
4802a8f6e6 | ||
|
|
03e516e568 | ||
|
|
ef37397969 | ||
|
|
c6d122008b | ||
|
|
3dce031f8e | ||
|
|
91d8776637 | ||
|
|
01f242b7c3 | ||
|
|
d5cf71c840 | ||
|
|
5ba70d9764 | ||
|
|
673476d773 | ||
|
|
5eb9fda015 | ||
|
|
81586caea0 | ||
|
|
a195126df1 | ||
|
|
b3783bab40 | ||
|
|
33d0f93e68 | ||
|
|
2050b05d6a | ||
|
|
38754b9d1a | ||
|
|
1867484032 | ||
|
|
b52ed19649 | ||
|
|
d53ababf7d | ||
|
|
ff43763721 | ||
|
|
c44d7633f2 | ||
|
|
08d641eb42 | ||
|
|
a243a044b9 | ||
|
|
c95a819eaf | ||
|
|
ce5ae675ea | ||
|
|
0828618c0d | ||
|
|
7267101021 | ||
|
|
0e868cef58 | ||
|
|
e410ccb2f4 | ||
|
|
c5b3f2ece6 | ||
|
|
35353c58cb | ||
|
|
e80d8e73ae | ||
|
|
494a35a0c3 | ||
|
|
818bbb4a30 | ||
|
|
4755c0eeb9 | ||
|
|
c8c89fdc95 | ||
|
|
52e0924f1c | ||
|
|
645c758b42 | ||
|
|
4dc7788981 | ||
|
|
9fa945a863 | ||
|
|
38b8695441 | ||
|
|
eadadb5d1d | ||
|
|
5f424e2e0b | ||
|
|
d807cd2de7 | ||
|
|
0b4e3a8da9 | ||
|
|
31be5e9a25 | ||
|
|
367538eeea | ||
|
|
442c1cb5f1 | ||
|
|
a333e4524f | ||
|
|
1e54f7d99b | ||
|
|
9f2aa8282d | ||
|
|
8d5dc440d0 | ||
|
|
8fffde0165 | ||
|
|
1a6e99971a | ||
|
|
4de88c3add | ||
|
|
76374893e3 | ||
|
|
edc17b304a | ||
|
|
ec7b4528f6 | ||
|
|
8d75c4afb1 | ||
|
|
b30fbf90b9 | ||
|
|
8fb95e1b06 | ||
|
|
f5e1a0569f | ||
|
|
929f87b411 | ||
|
|
59d97008f2 | ||
|
|
540b8ebb4d | ||
|
|
109d4afce2 | ||
|
|
aab8bce78e | ||
|
|
d2c33b4caf | ||
|
|
633b99d6b2 | ||
|
|
87159b4eee | ||
|
|
6d39ecc7b9 | ||
|
|
7738661b7c | ||
|
|
6443544a6b | ||
|
|
4689ebe3ce | ||
|
|
6cd8ce5102 | ||
|
|
a56ac84186 | ||
|
|
443a9ea101 | ||
|
|
0faafe8bc4 | ||
|
|
9948701127 | ||
|
|
ffae92d233 | ||
|
|
fed65d9c8b | ||
|
|
8f225f4d28 | ||
|
|
11e820d1d0 | ||
|
|
95fc72173f | ||
|
|
03b5c639fb | ||
|
|
4d30558aca | ||
|
|
7f376186b4 | ||
|
|
0de24c41ed | ||
|
|
88c4f84edb | ||
|
|
74db087d7d | ||
|
|
e00239562c | ||
|
|
bf9557040f | ||
|
|
6d9a44a0e3 | ||
|
|
35aabdc900 | ||
|
|
163502156d | ||
|
|
8baa5d84b9 | ||
|
|
c55fdbd982 | ||
|
|
8da38ab2e4 | ||
|
|
dddb781627 | ||
|
|
77b3a7ac85 | ||
|
|
626970865f | ||
|
|
c0308532a1 | ||
|
|
8df67bf76a | ||
|
|
80d4670204 | ||
|
|
a378cce0be | ||
|
|
488fd61558 | ||
|
|
ed2ab36ed4 | ||
|
|
0d6c5878fc | ||
|
|
dcbfb08f26 | ||
|
|
dab76df131 | ||
|
|
a7a448cbcd | ||
|
|
1780c6fb2a | ||
|
|
2d54df7dba | ||
|
|
890674eea3 | ||
|
|
d1c19d9d3e | ||
|
|
11b052e5bb | ||
|
|
93a70dfd47 | ||
|
|
6ac8646323 | ||
|
|
a215da1ebe | ||
|
|
22dbfbcc09 | ||
|
|
6341d564d3 | ||
|
|
28cc7b9800 | ||
|
|
5a142e671d | ||
|
|
ba3d45584d | ||
|
|
f54c0dd836 | ||
|
|
a6427a9ed1 | ||
|
|
11058dbf3b | ||
|
|
d062c2f1ab | ||
|
|
1f109d161f | ||
|
|
f2d6daa9fc | ||
|
|
9634e1ce39 | ||
|
|
64055a5aeb | ||
|
|
ad366e6bab | ||
|
|
9399104914 | ||
|
|
f82bc660b0 | ||
|
|
ed13af2382 | ||
|
|
e4c2952e49 | ||
|
|
0830eb9971 | ||
|
|
be9b61ec0c | ||
|
|
be0fe08f2f | ||
|
|
3f8d3389d5 | ||
|
|
7e1ba42873 | ||
|
|
20af1b4d34 | ||
|
|
207061e9d8 | ||
|
|
6633fc9c55 | ||
|
|
52b80613f8 | ||
|
|
0bef82ec32 | ||
|
|
f80bb6c42d | ||
|
|
db2cb8cb42 | ||
|
|
c320d7d173 | ||
|
|
db50bb5c1b | ||
|
|
01a74829fc | ||
|
|
7b77b7f5e9 | ||
|
|
ce8fcd2269 | ||
|
|
f6f64eca10 | ||
|
|
3240ac57f7 | ||
|
|
2008b09ca3 | ||
|
|
491f72b426 | ||
|
|
a6f46bd38a | ||
|
|
c103d7012b | ||
|
|
2cebb8eee2 | ||
|
|
33ad9f989c | ||
|
|
c590ab2ff5 | ||
|
|
9da949d27a | ||
|
|
f1a58f0434 | ||
|
|
0296b241e4 | ||
|
|
344ad48858 | ||
|
|
97f2abb582 | ||
|
|
eca5d780c1 | ||
|
|
1f1a3c5de8 | ||
|
|
844a6316f6 | ||
|
|
d39c5ed079 | ||
|
|
09bb0bc43a | ||
|
|
266e27bfe9 | ||
|
|
5b11131e08 | ||
|
|
3bfd96defe | ||
|
|
cad590f993 | ||
|
|
d70b14b12b | ||
|
|
c115ac0749 | ||
|
|
d54a612e0b | ||
|
|
d379769672 | ||
|
|
b670ffe407 | ||
|
|
4ffbe03b22 | ||
|
|
6a438470cf | ||
|
|
4d0d1da691 | ||
|
|
39f26f475b | ||
|
|
35fed173af | ||
|
|
a8b0515949 | ||
|
|
bd9d599934 | ||
|
|
b40079cdc9 | ||
|
|
b1cf4ef645 | ||
|
|
237c7bec3e | ||
|
|
75596e7153 | ||
|
|
7968994090 | ||
|
|
7c84a582ba | ||
|
|
9ad6c049f2 | ||
|
|
04ecdd55fe | ||
|
|
dbad25814c | ||
|
|
5af5364668 | ||
|
|
d28b4ce6d9 | ||
|
|
f9066eced0 | ||
|
|
a60db5521d | ||
|
|
e1d4490d62 | ||
|
|
cc24605cdb | ||
|
|
2647604798 | ||
|
|
6e3d326abb | ||
|
|
fc713f55fe | ||
|
|
81a1e0e550 | ||
|
|
88587f358d | ||
|
|
99a66bfdc7 | ||
|
|
50eb2a827f | ||
|
|
db08542b39 | ||
|
|
cbcbafc4a3 | ||
|
|
7e66dc7cac | ||
|
|
62fa8df8d2 | ||
|
|
b888d8f4cf | ||
|
|
e224a4ebdf | ||
|
|
977b5647f6 | ||
|
|
5a62b67e79 | ||
|
|
f31ac24707 | ||
|
|
a5589e232b | ||
|
|
f65f750b7f | ||
|
|
fa85e83817 | ||
|
|
d978978677 | ||
|
|
593c08f3e0 | ||
|
|
801f8f38d2 | ||
|
|
8be849d982 | ||
|
|
8bfa58540b | ||
|
|
4a6eb0d3f8 | ||
|
|
5c6ba38655 | ||
|
|
5831967603 | ||
|
|
fe2360baf6 | ||
|
|
3db2ede9d6 | ||
|
|
25cd448d69 | ||
|
|
c6bb11ccc8 | ||
|
|
d8bf2f7d8e | ||
|
|
079e60677e | ||
|
|
379ac46ec8 | ||
|
|
f4417f984b | ||
|
|
9f8d88bb4e | ||
|
|
cf4c3c1376 | ||
|
|
c39ef5916f | ||
|
|
edee3571be | ||
|
|
d039f7fd79 | ||
|
|
34abbcb467 | ||
|
|
1d93e358ed | ||
|
|
b4ada0449c | ||
|
|
4490d178d0 | ||
|
|
c9536c9ffd | ||
|
|
14e9bd304a | ||
|
|
5df409475e | ||
|
|
7427623c6e | ||
|
|
16d04bb878 | ||
|
|
9eda22b5db | ||
|
|
ebf64b5bcb | ||
|
|
fb2a057c05 | ||
|
|
635d0673bf | ||
|
|
864f8075d9 | ||
|
|
92a84af454 | ||
|
|
1560d1e18c | ||
|
|
bbb8384d66 | ||
|
|
b23e197178 | ||
|
|
ff6515269b | ||
|
|
d6f2d3a73f | ||
|
|
9b598aa3d7 | ||
|
|
88e0c6deda | ||
|
|
1f3ff3dc03 | ||
|
|
9cb449aa31 | ||
|
|
3afbc9a693 | ||
|
|
4ce84549c7 | ||
|
|
ac550d3b44 | ||
|
|
c9dab8d83c | ||
|
|
5e18c8d256 | ||
|
|
349a2bf855 | ||
|
|
3928d378f5 | ||
|
|
36d4f22007 | ||
|
|
cbbe9be819 | ||
|
|
ede6523678 | ||
|
|
ce086ffa82 | ||
|
|
a1715ef686 | ||
|
|
2c8b206903 | ||
|
|
5938f91861 | ||
|
|
b959a59e7b | ||
|
|
39c1176311 | ||
|
|
a10230b412 | ||
|
|
c9416a31a2 | ||
|
|
f7fe56535d | ||
|
|
ec10b63d11 | ||
|
|
a5131352c7 | ||
|
|
9f0a794f22 | ||
|
|
63ecb12fcf | ||
|
|
5a4774e9f3 | ||
|
|
35be1bee59 | ||
|
|
a7a9ba0463 | ||
|
|
0b7bdda4bf | ||
|
|
2612997355 | ||
|
|
84ca90ae97 | ||
|
|
8c693f1956 | ||
|
|
764328593d | ||
|
|
e9b6c2495c | ||
|
|
f4bddefd33 | ||
|
|
033409351e | ||
|
|
a6a66a7672 | ||
|
|
1f55d08adf | ||
|
|
664fd1c2d0 | ||
|
|
c9572af445 | ||
|
|
98edd30360 | ||
|
|
ab311bfa86 | ||
|
|
f4d58a9ea9 | ||
|
|
e769143e58 | ||
|
|
3c37899fe4 | ||
|
|
30d36789c1 | ||
|
|
971541a516 | ||
|
|
ca9e7d5c73 | ||
|
|
61529675ec | ||
|
|
22887b4dd6 | ||
|
|
c4383f4bd2 | ||
|
|
0f0751e4d2 | ||
|
|
2a460dfdba | ||
|
|
2e42620d67 | ||
|
|
5cc24fd6ab | ||
|
|
1c59d0451a | ||
|
|
6d26996d65 | ||
|
|
5f2f929af8 | ||
|
|
e129b7b469 | ||
|
|
c6f70a7b77 | ||
|
|
f2a2e5ddf2 | ||
|
|
b7f92388c5 | ||
|
|
8105f89c55 | ||
|
|
467effa62e | ||
|
|
2627b9035d | ||
|
|
d9aff93993 | ||
|
|
1fc72aa7be | ||
|
|
b7067923c0 | ||
|
|
ed3ae2622e | ||
|
|
e3cc95cfd8 | ||
|
|
9456495a3d | ||
|
|
53fe300fe9 | ||
|
|
76aea1a038 | ||
|
|
921f9b21a2 | ||
|
|
d552dcd137 | ||
|
|
9505284e61 | ||
|
|
d53acf204c | ||
|
|
175e98a080 | ||
|
|
b8c1096568 | ||
|
|
430e0cbd46 | ||
|
|
c2a2e0ac19 | ||
|
|
5a1c207ffc | ||
|
|
1c7b466e64 | ||
|
|
30158ca5c5 | ||
|
|
e896555694 | ||
|
|
87ddaad966 | ||
|
|
4736fa6b50 | ||
|
|
44b8dd308a | ||
|
|
a4e21ed343 | ||
|
|
48eb931c37 | ||
|
|
794d214636 | ||
|
|
fb1b4c6cc5 | ||
|
|
76de3e0e02 | ||
|
|
3f49dc2595 | ||
|
|
28c5fd64fe | ||
|
|
9d9c46f732 | ||
|
|
358f8a94d0 | ||
|
|
0c8901b5b2 | ||
|
|
4abc78fff3 | ||
|
|
095f1fde27 | ||
|
|
c2c7510dc4 | ||
|
|
1c70fb8606 | ||
|
|
75d6817012 | ||
|
|
3d3b59686c | ||
|
|
963deeca75 | ||
|
|
991405c7aa | ||
|
|
ce66e55196 | ||
|
|
7142f0f8d5 | ||
|
|
8ac714a5b5 | ||
|
|
97d206a9d4 | ||
|
|
fad6f72dd1 | ||
|
|
3f09e6de93 | ||
|
|
547b86f98e | ||
|
|
2bdfbedeea | ||
|
|
68da810a85 | ||
|
|
d9ad044ecd | ||
|
|
5b7b770aee | ||
|
|
b3cde1bcd7 | ||
|
|
9eeed9630b | ||
|
|
617b452da5 | ||
|
|
eb0ea4ea24 | ||
|
|
c7e2baea1b | ||
|
|
172e0c70c8 | ||
|
|
9b843f6483 | ||
|
|
e405a91ba8 | ||
|
|
cdc2554af6 | ||
|
|
2808b6f26a | ||
|
|
41ff10c653 | ||
|
|
4508428160 | ||
|
|
f0dd426055 | ||
|
|
d0ca24ae6f | ||
|
|
fe2b76eeb9 | ||
|
|
2fbf2a1173 | ||
|
|
c9377295db | ||
|
|
54c73a8c0d | ||
|
|
5d0f2e4403 | ||
|
|
47150c649f | ||
|
|
7930f44109 | ||
|
|
ec6906a5c3 | ||
|
|
891a1a9503 | ||
|
|
965e3247b0 | ||
|
|
f24041651c | ||
|
|
3f88373dd8 | ||
|
|
aa66e1f73c | ||
|
|
cf79f3b07e | ||
|
|
9493649a69 | ||
|
|
c8cd5b0eaa | ||
|
|
c16b3a3ce0 | ||
|
|
2967a74480 | ||
|
|
ea648ca887 | ||
|
|
8d35b57d19 | ||
|
|
be9a07bc4b | ||
|
|
7d37c6e728 | ||
|
|
42ccd953c0 | ||
|
|
578405d5d3 | ||
|
|
ebb32f0893 | ||
|
|
9cef18b82a | ||
|
|
88510a6ffe | ||
|
|
be6acc5ef2 | ||
|
|
4e35cf326e | ||
|
|
225d6055d4 | ||
|
|
7884991ac6 | ||
|
|
2d041ab6d0 | ||
|
|
c2cdc92ae9 | ||
|
|
6b10d35e1a | ||
|
|
790f93322e | ||
|
|
b50edb2762 | ||
|
|
88e06a1bea | ||
|
|
07d4204e86 | ||
|
|
0e78d0bd50 | ||
|
|
f3a3741216 | ||
|
|
74e33d09b1 | ||
|
|
ecd50148de | ||
|
|
08a28eeb68 | ||
|
|
cbabcd4782 | ||
|
|
63be65a487 | ||
|
|
1c8476df53 | ||
|
|
7cd03c6a52 | ||
|
|
db09711be5 | ||
|
|
94c6eea20b | ||
|
|
1ec3aa07d3 | ||
|
|
1087c68541 | ||
|
|
856556c12b | ||
|
|
fc24a389c0 | ||
|
|
5687485154 | ||
|
|
654d6c64c1 | ||
|
|
fed6b2a6da | ||
|
|
79806cc6a2 | ||
|
|
e78aa2df61 | ||
|
|
03173f6a37 | ||
|
|
3fa73894ed | ||
|
|
a147324913 | ||
|
|
0fc4211c13 | ||
|
|
6df0b287ef | ||
|
|
2f9af111c8 | ||
|
|
615045be9f | ||
|
|
6fc183ff15 | ||
|
|
9aafa681e8 | ||
|
|
f48f9ccd62 | ||
|
|
2bd80bb5b4 | ||
|
|
de597d2c28 | ||
|
|
94cca88e2e | ||
|
|
443c7fcd48 | ||
|
|
6138d9f8c8 | ||
|
|
37547b54e9 | ||
|
|
618e2f619b | ||
|
|
72fc3ea337 | ||
|
|
82f4784107 | ||
|
|
4f9fb9976d | ||
|
|
2cf7655562 | ||
|
|
79c5638e10 | ||
|
|
f53d53ea20 | ||
|
|
f2760a941b | ||
|
|
1e26eed861 | ||
|
|
2da4a44505 | ||
|
|
42068ad3d8 | ||
|
|
62f8c4509e | ||
|
|
d699764546 | ||
|
|
8549d56c21 | ||
|
|
4b532fc7f8 | ||
|
|
06d2c393ce | ||
|
|
cecdf9758b | ||
|
|
a2b9a33f6a | ||
|
|
02cb4f2584 | ||
|
|
56ac1d55f4 | ||
|
|
2a5acb8771 | ||
|
|
93e04e1b69 | ||
|
|
bd48b02ef3 | ||
|
|
8cfcd7b1af | ||
|
|
c0cb059f52 | ||
|
|
a2a9b37238 | ||
|
|
57d0d27bbb | ||
|
|
0e92dd9bea | ||
|
|
c16ebf3917 | ||
|
|
3d3a08a23f | ||
|
|
4d1227a942 | ||
|
|
a8ee273b24 | ||
|
|
3ee7a57480 | ||
|
|
2f2c777c56 | ||
|
|
2f36118e9d | ||
|
|
a6d161581f | ||
|
|
d05ea5a2cc | ||
|
|
471db94242 | ||
|
|
2654e4fbc9 | ||
|
|
f2aa5bfbee | ||
|
|
3b018b0c70 | ||
|
|
921db10d91 | ||
|
|
bf4f593e3a | ||
|
|
1e061a1e19 | ||
|
|
9b9f537e2c | ||
|
|
985cce0b0d | ||
|
|
3fe38eb506 | ||
|
|
51081d3052 | ||
|
|
c08f6d16bb | ||
|
|
62ad4c49f8 | ||
|
|
3b0a1e6108 | ||
|
|
c2f2205626 | ||
|
|
87c729d694 | ||
|
|
8e4f60edf3 | ||
|
|
8811eee9f5 | ||
|
|
2af93f1acd | ||
|
|
78a35544c7 | ||
|
|
3ad2d650b0 | ||
|
|
bf425a8ec7 | ||
|
|
a7d0d36086 | ||
|
|
fd9e327c85 | ||
|
|
8ed3ce8203 | ||
|
|
ebd5a3d3a6 | ||
|
|
1cdf18747d | ||
|
|
d8261a649b | ||
|
|
c4565d97b0 |
12
.githooks/_/pre-commit
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ "$SKIP_SIMPLE_GIT_HOOKS" = "1" ]; then
|
||||
echo "[INFO] SKIP_SIMPLE_GIT_HOOKS is set to 1, skipping hook."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f "$SIMPLE_GIT_HOOKS_RC" ]; then
|
||||
. "$SIMPLE_GIT_HOOKS_RC"
|
||||
fi
|
||||
|
||||
# cd packages/web && bun run lint && bun run format
|
||||
84
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -6,8 +6,20 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
|
||||
# Bug Report
|
||||
Thanks for taking the time to fill out this bug report! The more information you provide, the faster we can diagnose and fix the issue.
|
||||
- type: checkboxes
|
||||
id: prerequisites
|
||||
attributes:
|
||||
label: Before submitting
|
||||
description: Please confirm you've completed the following steps
|
||||
options:
|
||||
- label: I have searched existing issues to make sure this bug hasn't already been reported
|
||||
required: true
|
||||
- label: I have updated to the latest version of the software to verify the issue still exists
|
||||
required: true
|
||||
- label: I have cleared cache/cookies/storage or tried in a private/incognito window (if applicable)
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: hardware
|
||||
attributes:
|
||||
@@ -41,7 +53,6 @@ body:
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: category
|
||||
attributes:
|
||||
@@ -54,7 +65,6 @@ body:
|
||||
- Serial
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: local
|
||||
attributes:
|
||||
@@ -66,7 +76,6 @@ body:
|
||||
- https://client.meshtastic.org
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
@@ -75,15 +84,50 @@ body:
|
||||
placeholder: x.x.x.yyyyyyy
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: body
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please provide details on what steps you performed for this to happen.
|
||||
label: Operating System
|
||||
description: What OS are you running? Include version if possible.
|
||||
placeholder: e.g., Windows 11, macOS 13.1, Android 13, iOS 16.2
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: browser
|
||||
attributes:
|
||||
label: Browser
|
||||
description: What browser are you using? Include version if possible.
|
||||
placeholder: e.g., Chrome 108, Firefox 107, Safari 16.2
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: What did you expect to happen?
|
||||
placeholder: Describe what you expected to occur...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual
|
||||
attributes:
|
||||
label: Actual Behavior
|
||||
description: What actually happened?
|
||||
placeholder: Describe what occurred instead...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: Provide clear steps to reproduce the issue
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
@@ -92,3 +136,21 @@ body:
|
||||
render: Shell
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any other context about the problem here.
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for helping improve our project by reporting this bug!
|
||||
|
||||
60
.github/ISSUE_TEMPLATE/feature.yml
vendored
@@ -6,12 +6,60 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for your request this will not gurantee that we will implement it, but it will be reviewed.
|
||||
|
||||
- type: textarea
|
||||
id: body
|
||||
Thanks for your request. While we can't guarantee implementation, all requests will be carefully reviewed.
|
||||
- type: checkboxes
|
||||
id: prerequisites
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please provide details about your enhancement.
|
||||
label: Prerequisites
|
||||
description: Please confirm the following before submitting your feature request
|
||||
options:
|
||||
- label: I have searched existing issues to ensure this feature hasn't already been requested
|
||||
required: true
|
||||
- label: I have checked the documentation to verify this feature doesn't already exist
|
||||
required: true
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Problem Statement
|
||||
description: What problem are you trying to solve? Describe the challenge or limitation you're facing.
|
||||
placeholder: I'm frustrated when...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Proposed Solution
|
||||
description: Describe your idea for solving the problem. What would you like to see implemented?
|
||||
placeholder: It would be great if...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Current Alternatives
|
||||
description: Are there any workarounds or alternative solutions you're currently using?
|
||||
placeholder: Currently, I'm working around this by...
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: importance
|
||||
attributes:
|
||||
label: Importance
|
||||
description: How important is this feature to you?
|
||||
options:
|
||||
- Nice to have
|
||||
- Important
|
||||
- Critical
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any other context, screenshots, mockups, or examples that might help us understand your request better.
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking the time to fill out this feature request!
|
||||
|
||||
50
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<!--
|
||||
Thank you for your contribution to our project!
|
||||
-->
|
||||
|
||||
## Description
|
||||
|
||||
<!--
|
||||
Provide a clear and concise description of what this PR does. Explain the problem it solves or the feature it adds.
|
||||
-->
|
||||
|
||||
## Related Issues
|
||||
|
||||
<!--
|
||||
Link any related issues here using the GitHub syntax: "Fixes #123" or "Relates to #456".
|
||||
If there are no related issues, you can remove this section.
|
||||
-->
|
||||
|
||||
## Changes Made
|
||||
|
||||
<!--
|
||||
List the key changes you've made. Focus on the most important aspects that reviewers should understand.
|
||||
-->
|
||||
|
||||
-
|
||||
-
|
||||
-
|
||||
|
||||
## Testing Done
|
||||
|
||||
<!--
|
||||
Describe how you tested these changes (added new tests, etc).
|
||||
-->
|
||||
|
||||
## Screenshots (if applicable)
|
||||
|
||||
<!--
|
||||
If your changes affect the UI, include screenshots or screencasts showing the before and after.
|
||||
-->
|
||||
|
||||
## Checklist
|
||||
|
||||
<!--
|
||||
Check all that apply. If an item doesn't apply to your PR, you can leave it unchecked or remove it.
|
||||
-->
|
||||
|
||||
- [ ] Code follows project style guidelines
|
||||
- [ ] Documentation has been updated or added
|
||||
- [ ] Tests have been added or updated
|
||||
- [ ] All i18n translation labels have been added (read
|
||||
CONTRIBUTING_I18N_DEVELOPER_GUIDE.md for more details)
|
||||
56
.github/workflows/ci.yml
vendored
@@ -1,9 +1,9 @@
|
||||
name: CI
|
||||
name: Push to Main CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -13,14 +13,54 @@ jobs:
|
||||
build-and-package:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
- name: Setup Deno
|
||||
uses: denoland/setup-deno@v2
|
||||
with:
|
||||
deno-version: v2.x
|
||||
|
||||
- name: Build Package
|
||||
run: pnpm build
|
||||
- name: Cache Deno dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/deno
|
||||
key: ${{ runner.os }}-deno-${{ hashFiles('**/deno.lock', '**/package.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-deno-
|
||||
|
||||
- name: Cache pnpm dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.pnpm-store
|
||||
packages/web/node_modules
|
||||
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-
|
||||
|
||||
- name: Build All Packages
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
for pkg_dir in packages/*/; do
|
||||
pkg_dir=${pkg_dir%/} # Remove trailing slash
|
||||
echo "🔍 Inspecting $pkg_dir..."
|
||||
|
||||
if [[ -f "$pkg_dir/package.json" ]] && [[ "$pkg_dir" != "packages/web" ]]; then
|
||||
echo "🔧 Building with pnpm: $pkg_dir"
|
||||
(cd "$pkg_dir" && pnpm install && pnpm run build:npm)
|
||||
else
|
||||
echo "⚠️ Skipping $pkg_dir (web package or no package.json)"
|
||||
fi
|
||||
done
|
||||
|
||||
35
.github/workflows/crowdin-download.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: Crowdin Download Translations Action
|
||||
|
||||
on:
|
||||
schedule: # Every Sunday at midnight
|
||||
- cron: "0 0 * * 0"
|
||||
workflow_dispatch: # Allow manual triggering
|
||||
|
||||
jobs:
|
||||
synchronize-with-crowdin:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download translations with Crowdin
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_url: "https://meshtastic.crowdin.com/api/v2"
|
||||
config: "./packages/web/crowdin.yml"
|
||||
upload_sources: false
|
||||
upload_translations: false
|
||||
download_translations: true
|
||||
localization_branch_name: i18n_crowdin_translations
|
||||
commit_message: "chore(i18n): New Crowdin Translations by GitHub Action"
|
||||
create_pull_request: true
|
||||
pull_request_title: "chore(i18n): New Crowdin Translations"
|
||||
pull_request_body: "New Crowdin translations by [Crowdin GH Action](https://github.com/crowdin/github-action)"
|
||||
pull_request_base_branch_name: "main"
|
||||
pull_request_labels: "i18n"
|
||||
crowdin_branch_name: "main"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
32
.github/workflows/crowdin-upload-sources.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Crowdin Upload Sources Action
|
||||
|
||||
on:
|
||||
push:
|
||||
# Monitor all .json files within the /i18n/locales/en/ directory.
|
||||
# This ensures the workflow triggers if any the English namespace files are modified on the main branch.
|
||||
paths:
|
||||
- "/packages/web/public/i18n/locales/en/*.json"
|
||||
branches: [main]
|
||||
workflow_dispatch: # Allow manual triggering
|
||||
|
||||
jobs:
|
||||
synchronize-with-crowdin:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Upload sources with Crowdin
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_url: "https://meshtastic.crowdin.com/api/v2"
|
||||
config: "./packages/web/crowdin.yml"
|
||||
upload_sources: true
|
||||
upload_translations: false
|
||||
download_translations: false
|
||||
crowdin_branch_name: "main"
|
||||
|
||||
env:
|
||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
25
.github/workflows/crowdin-upload-translations.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Crowdin Upload Translations Action
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Allow manual triggering
|
||||
|
||||
jobs:
|
||||
synchronize-with-crowdin:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Upload translations with Crowdin
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_url: "https://meshtastic.crowdin.com/api/v2"
|
||||
config: "./packages/web/crowdin.yml"
|
||||
upload_sources: false
|
||||
upload_translations: true
|
||||
download_translations: false
|
||||
crowdin_branch_name: "main"
|
||||
env:
|
||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
101
.github/workflows/nightly.yml
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
name: "Nightly Release"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 5 * * *" # Run every day at 5am UTC
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
nightly-build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Cache pnpm dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.pnpm-store
|
||||
packages/web/node_modules
|
||||
key: ${{ runner.os }}-pnpm-${{ hashFiles('packages/web/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-
|
||||
|
||||
# - name: Run tests
|
||||
# working-directory: packages/web
|
||||
# run: deno task test
|
||||
|
||||
- name: Install Dependencies
|
||||
working-directory: packages/web
|
||||
run: pnpm install
|
||||
|
||||
- name: Build Package
|
||||
working-directory: packages/web
|
||||
run: pnpm run build
|
||||
|
||||
- name: Package Output
|
||||
working-directory: packages/web
|
||||
run: pnpm run package
|
||||
|
||||
- name: Archive compressed build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build
|
||||
path: packages/web/dist/build.tar
|
||||
|
||||
- name: Get latest release version
|
||||
id: get_release
|
||||
run: |
|
||||
LATEST_TAG=$(curl -sL \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
|
||||
https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r ".tag_name")
|
||||
# Fallback to a default if no release is found
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
LATEST_TAG="2.6.0"
|
||||
fi
|
||||
echo "tag=${LATEST_TAG}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Buildah Build
|
||||
id: build-container
|
||||
uses: redhat-actions/buildah-build@v2
|
||||
with:
|
||||
containerfiles: |
|
||||
./packages/web/infra/Containerfile
|
||||
image: ${{ github.event.repository.full_name }}
|
||||
tags: nightly-${{ steps.get_release.outputs.tag }}-${{ github.sha }}
|
||||
|
||||
|
||||
oci: true
|
||||
platforms: linux/amd64, linux/arm64
|
||||
|
||||
- name: Push To Registry
|
||||
id: push-to-registry
|
||||
uses: redhat-actions/push-to-registry@v2
|
||||
with:
|
||||
image: ${{ steps.build-container.outputs.image }}
|
||||
tags: ${{ steps.build-container.outputs.tags }}
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Print image url
|
||||
run: echo "Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}"
|
||||
|
||||
43
.github/workflows/pr.yml
vendored
@@ -1,30 +1,49 @@
|
||||
name: Pull Request
|
||||
name: Pull Request CI
|
||||
|
||||
on: pull_request
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build-and-package:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Install Dependencies
|
||||
# Commands will run from 'packages/web'
|
||||
working-directory: packages/web
|
||||
run: pnpm install
|
||||
|
||||
- name: Build Package
|
||||
run: pnpm build
|
||||
|
||||
- name: Compress build
|
||||
run: pnpm package
|
||||
|
||||
- name: Archive compressed build
|
||||
uses: actions/upload-artifact@v4
|
||||
- name: Cache pnpm dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
name: build
|
||||
path: dist/build.tar
|
||||
path: |
|
||||
~/.pnpm-store
|
||||
packages/web/node_modules
|
||||
key: ${{ runner.os }}-pnpm-${{ hashFiles('packages/web/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-
|
||||
|
||||
- name: Run linter
|
||||
run: pnpm run lint
|
||||
|
||||
- name: Check formatter
|
||||
run: pnpm run check
|
||||
|
||||
- name: Build Package
|
||||
working-directory: packages/web
|
||||
run: pnpm run build
|
||||
|
||||
86
.github/workflows/release-packages.yml
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
name: Release Packages
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
packages:
|
||||
description: 'Packages to release (comma-separated, or "all" for all packages)'
|
||||
required: false
|
||||
default: 'all'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# --- Setup Node.js and pnpm ---
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
# --- Setup Deno ---
|
||||
- name: Setup Deno
|
||||
uses: denoland/setup-deno@v2
|
||||
with:
|
||||
deno-version: v2.x
|
||||
|
||||
# --- Cache pnpm Dependencies ---
|
||||
- name: Cache pnpm Dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.pnpm-store
|
||||
packages/web/node_modules
|
||||
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-
|
||||
|
||||
# --- Cache Deno Dependencies ---
|
||||
- name: Cache Deno Dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/deno
|
||||
key: ${{ runner.os }}-deno-${{ hashFiles('**/deno.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-deno-
|
||||
|
||||
- name: Configure pnpm registry
|
||||
run: pnpm config set registry https://registry.npmjs.org/
|
||||
|
||||
- name: Configure pnpm auth
|
||||
run: pnpm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Publish packages to npm and JSR
|
||||
run: |
|
||||
for dir in packages/*; do
|
||||
echo "Processing $dir"
|
||||
|
||||
cd $dir
|
||||
|
||||
# Build and publish to npm if package.json exists
|
||||
if [ -f "package.json" ]; then
|
||||
echo "Building and publishing $dir to npm..."
|
||||
pnpm run build:npm
|
||||
pnpm run publish:npm || echo "npm publish failed for $dir"
|
||||
fi
|
||||
|
||||
pnpm run prepare:jsr
|
||||
|
||||
# Publish to JSR if jsr.json exists
|
||||
if [ -f "jsr.json" ]; then
|
||||
echo "Publishing $dir to jsr..."
|
||||
deno publish || echo "JSR publish failed for $dir"
|
||||
fi
|
||||
|
||||
cd - > /dev/null
|
||||
done
|
||||
|
||||
|
||||
79
.github/workflows/release-web.yml
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
name: Release Web
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [released, prereleased]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release-web:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Cache Bun Dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.bun/install/cache
|
||||
packages/web/node_modules
|
||||
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-bun-
|
||||
|
||||
- name: Run Web App Tests
|
||||
working-directory: packages/web
|
||||
run: bun run test
|
||||
|
||||
- name: Create Web App Release Archive
|
||||
working-directory: packages/web
|
||||
run: bun run package
|
||||
|
||||
- name: Upload Web App Archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: web-build
|
||||
if-no-files-found: error
|
||||
path: packages/web/dist/build.tar
|
||||
|
||||
- name: Attach Web Archive to GitHub Release
|
||||
run: gh release upload ${{ github.event.release.tag_name }} packages/web/dist/build.tar
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Build Container Image
|
||||
id: build-container
|
||||
uses: redhat-actions/buildah-build@v2
|
||||
with:
|
||||
containerfiles: |
|
||||
./infra/Containerfile
|
||||
image: ghcr.io/${{ github.repository }}
|
||||
tags: latest, ${{ github.event.release.tag_name }}
|
||||
oci: true
|
||||
platforms: linux/amd64, linux/arm64
|
||||
|
||||
- name: Push Container to GHCR
|
||||
id: push-to-registry
|
||||
uses: redhat-actions/push-to-registry@v2
|
||||
with:
|
||||
image: ${{ steps.build-container.outputs.image }}
|
||||
tags: ${{ steps.build-container.outputs.tags }}
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Output Image URL
|
||||
run: echo "🖼️ Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}"
|
||||
55
.github/workflows/release.yml
vendored
@@ -1,55 +0,0 @@
|
||||
name: 'Release'
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build-and-package:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Build Package
|
||||
run: pnpm build
|
||||
|
||||
- name: Package Output
|
||||
run: pnpm package
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Buildah Build
|
||||
id: build-container
|
||||
uses: redhat-actions/buildah-build@v2
|
||||
with:
|
||||
containerfiles: |
|
||||
./Containerfile
|
||||
image: ${{github.event.repository.full_name}}
|
||||
tags: latest ${{ github.sha }}
|
||||
oci: true
|
||||
platforms: linux/amd64, linux/arm64
|
||||
|
||||
- name: Push To Registry
|
||||
id: push-to-registry
|
||||
uses: redhat-actions/push-to-registry@v2
|
||||
with:
|
||||
image: ${{ steps.build-container.outputs.image }}
|
||||
tags: ${{ steps.build-container.outputs.tags }}
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Print image url
|
||||
run: echo "Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}"
|
||||
50
.github/workflows/update-stable-from-master.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Update Stable Branch from Main on Latest Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
update-stable-branch:
|
||||
name: Update Stable Branch from Main
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name "GitHub Actions Bot"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Fetch latest main and stable branches
|
||||
run: |
|
||||
git fetch origin main:main
|
||||
git fetch origin stable:stable || echo "Stable branch not found remotely, will create."
|
||||
|
||||
- name: Get latest main commit SHA
|
||||
id: get_main_sha
|
||||
run: echo "MAIN_SHA=$(git rev-parse main)" >> $GITHUB_ENV
|
||||
|
||||
- name: Check out stable branch
|
||||
run: |
|
||||
if git show-ref --verify --quiet refs/heads/stable; then
|
||||
git checkout stable
|
||||
git pull origin stable # Sync with remote stable if it exists
|
||||
else
|
||||
echo "Creating local stable branch based on main HEAD."
|
||||
git checkout -b stable ${{ env.MAIN_SHA }}
|
||||
fi
|
||||
|
||||
- name: Reset stable branch to latest main
|
||||
run: git reset --hard ${{ env.MAIN_SHA }}
|
||||
|
||||
- name: Force push stable branch
|
||||
run: git push origin stable --force
|
||||
9
.gitignore
vendored
@@ -1,5 +1,10 @@
|
||||
dist
|
||||
node_modules
|
||||
dist
|
||||
stats.html
|
||||
.vercel
|
||||
dev-dist
|
||||
.vite
|
||||
dev-dist
|
||||
__screenshots__*
|
||||
*.diff
|
||||
npm/
|
||||
.idea
|
||||
|
||||
2
.npmrc
@@ -1 +1 @@
|
||||
@buf:registry=https://buf.build/gen/npm/v1
|
||||
@jsr:registry=https://npm.jsr.io
|
||||
|
||||
2
.vscode/extensions.json
vendored
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"recommendations": ["bradlc.vscode-tailwindcss", "biomejs.biome"]
|
||||
"recommendations": ["bradlc.vscode-tailwindcss", "denoland.vscode-deno"]
|
||||
}
|
||||
|
||||
7
.vscode/settings.json
vendored
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"quickfix.biome": "explicit"
|
||||
},
|
||||
"editor.formatOnSave": true
|
||||
"source.fixAll.biome": "explicit",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
FROM registry.access.redhat.com/ubi9/nginx-122:1-45
|
||||
|
||||
ADD dist .
|
||||
|
||||
CMD nginx -g "daemon off;"
|
||||
121
README.md
@@ -1,61 +1,112 @@
|
||||
# Meshtastic Web
|
||||
# Meshtastic Web Monorepo
|
||||
|
||||
<!--Project specific badges here-->
|
||||
|
||||
[](https://github.com/meshtastic/web/actions/workflows/ci.yml)
|
||||
[](https://github.com/meshtastic/web/actions/workflows/ci.yml)
|
||||
[](https://github.com/meshtastic/js/actions/workflows/ci.yml)
|
||||
[](https://cla-assistant.io/meshtastic/web)
|
||||
[](https://opencollective.com/meshtastic/)
|
||||
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||
|
||||
## Overview
|
||||
|
||||
Official [Meshtastic](https://meshtastic.org) web interface, that can be hosted or served from a node
|
||||
This monorepo consolidates the official [Meshtastic](https://meshtastic.org) web
|
||||
interface and its supporting JavaScript libraries. It aims to provide a unified
|
||||
development experience for interacting with Meshtastic devices.
|
||||
|
||||
**[Hosted version](https://client.meshtastic.org)**
|
||||
### Projects within this Monorepo (`packages/`)
|
||||
|
||||
All projects are located within the `packages/` directory:
|
||||
|
||||
- **`packages/web` (Meshtastic Web Client):** The official web interface,
|
||||
designed to be hosted or served directly from a Meshtastic node.
|
||||
- **[Hosted version](https://client.meshtastic.org)**
|
||||
- **`packages/core`:** Core functionality for Meshtastic JS.
|
||||
- **`packages/transport-node`:** TCP Transport for the NodeJS runtime.
|
||||
- **`packages/transport-deno`:** TCP Transport for the Deno runtime.
|
||||
- **`packages/transport-http`:** HTTP Transport.
|
||||
- **`packages/transport-web-bluetooth`:** Web Bluetooth Transport.
|
||||
- **`packages/transport-web-serial`:** Web Serial Transport.
|
||||
|
||||
All `Meshtastic JS` packages (core and transports) are published both to
|
||||
[JSR](https://jsr.io/@meshtastic). [NPM](https://www.npmjs.com/org/meshtastic)
|
||||
|
||||
---
|
||||
|
||||
## Stats
|
||||
|
||||

|
||||
| Project | Repobeats |
|
||||
| :------------- | :-------------------------------------------------------------------------------------------------------------------- |
|
||||
| Meshtastic Web |  |
|
||||
|
||||
## Self-host
|
||||
---
|
||||
|
||||
The client can be self hosted using the precompiled container images with an OCI compatible runtime such as [Docker](https://www.docker.com/) or [Podman](https://podman.io/).
|
||||
The base image used is [UBI9 Nginx 1.22](https://catalog.redhat.com/software/containers/ubi9/nginx-122/63f7653b9b0ca19f84f7e9a1)
|
||||
## Tech Stack
|
||||
|
||||
```bash
|
||||
# With Docker
|
||||
docker run -d -p 8080:8080 -p 8443:8443 --restart always --name Meshtastic-Web ghcr.io/meshtastic/web
|
||||
This monorepo leverages the following technologies:
|
||||
|
||||
#With Podman
|
||||
podman run -d -p 8080:8080 -p 8443:8443 --restart always --name Meshtastic-Web ghcr.io/meshtastic/web
|
||||
```
|
||||
- **Runtime:** pnpm / Deno
|
||||
- **Web Client:** React.js
|
||||
- **Styling:** Tailwind CSS
|
||||
- **Bundling:** Vite
|
||||
- **Language:** TypeScript
|
||||
- **Testing:** Vitest, React Testing Library
|
||||
|
||||
## Development & Building
|
||||
---
|
||||
|
||||
### Building and Packaging
|
||||
## Getting Started
|
||||
|
||||
Build the project:
|
||||
### Prerequisites
|
||||
|
||||
```bash
|
||||
pnpm build
|
||||
```
|
||||
You'll need to have [pnpm](https://pnpm.io/) installed to work with this monorepo.
|
||||
Follow the installation instructions on their home page.
|
||||
|
||||
GZip the output:
|
||||
### Development Setup
|
||||
|
||||
```bash
|
||||
pnpm package
|
||||
```
|
||||
1. **Clone the repository:**
|
||||
```bash
|
||||
git clone https://github.com/meshtastic/meshtastic-web.git
|
||||
cd meshtastic-web
|
||||
```
|
||||
2. **Install dependencies for all packages:**
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
This command installs all necessary dependencies for all packages within the
|
||||
monorepo.
|
||||
|
||||
### Development
|
||||
### Running Projects
|
||||
|
||||
Install the dependencies.
|
||||
#### Meshtastic Web Client
|
||||
|
||||
```bash
|
||||
pnpm i
|
||||
```
|
||||
Please refer to the [Meshtastic Web README](packages/web/README.md) for setup and usage.
|
||||
|
||||
Start the development server:
|
||||
### Feedback
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
If you encounter any issues, please report them in our
|
||||
[issues tracker](https://github.com/meshtastic/web/issues). Your feedback helps
|
||||
improve the stability of future releases
|
||||
|
||||
### Contributing
|
||||
|
||||
We welcome contributions! Here’s how the deployment flow works for pull
|
||||
requests:
|
||||
|
||||
- **Preview Deployments:**\
|
||||
Every pull request automatically generates a preview deployment on Vercel.
|
||||
This allows you and reviewers to easily preview changes before merging.
|
||||
|
||||
- **Staging Environment (`client-test`):**\
|
||||
Once your PR is merged, your changes will be available on our staging site:
|
||||
[client-test.meshtastic.org](https://client-test.meshtastic.org/).\
|
||||
This environment supports rapid feature iteration and testing without
|
||||
impacting the production site.
|
||||
|
||||
- **Production Releases:**\
|
||||
At regular intervals, stable and fully tested releases are promoted to our
|
||||
production site: [client.meshtastic.org](https://client.meshtastic.org/).\
|
||||
This is the primary interface used by the public to connect with their
|
||||
Meshtastic nodes.
|
||||
|
||||
Please review our
|
||||
[Contribution Guidelines](https://github.com/meshtastic/web/blob/main/CONTRIBUTING.md)
|
||||
before submitting a pull request. We appreciate your help in making the project
|
||||
better!
|
||||
|
||||
63
biome.json
@@ -1,27 +1,44 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.7.3/schema.json",
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": true,
|
||||
"ignore": ["vercel.json"]
|
||||
},
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true,
|
||||
"defaultBranch": "master"
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true
|
||||
"files": {
|
||||
"includes": ["**/*.ts", "**/*.tsx", "!**/*.test.ts", "!**/*.test.tsx", "!npm_modules/**", "!dist/**", "!npm/**"],
|
||||
"ignoreUnknown": false
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": false,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 80,
|
||||
"attributePosition": "auto"
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"includes": ["**", "!test/**"],
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"suspicious": {
|
||||
"noExplicitAny": "error",
|
||||
"noDebugger": "error"
|
||||
},
|
||||
"style": {
|
||||
"useBlockStatements": "error",
|
||||
"useSingleVarDeclarator": "off"
|
||||
},
|
||||
"correctness": {
|
||||
"noUnusedVariables": "error",
|
||||
"noUnusedImports": "error"
|
||||
}
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "double",
|
||||
"semicolons": "always"
|
||||
}
|
||||
},
|
||||
"json": {
|
||||
"formatter": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
124
package.json
@@ -1,86 +1,42 @@
|
||||
{
|
||||
"name": "meshtastic-web",
|
||||
"version": "2.3.3-0",
|
||||
"type": "module",
|
||||
"description": "Meshtastic web client",
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"build": "tsc && pnpm check && vite build ",
|
||||
"check": "biome check .",
|
||||
"check:fix": "pnpm check --write",
|
||||
"preview": "vite preview",
|
||||
"package": "gzipper c -i html,js,css,png,ico,svg,webmanifest,txt dist dist/output && tar -cvf dist/build.tar -C ./dist/output/ $(ls ./dist/output/)"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/meshtastic/web.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/meshtastic/web/issues"
|
||||
},
|
||||
"homepage": "https://meshtastic.org",
|
||||
"dependencies": {
|
||||
"@bufbuild/protobuf": "^1.10.0",
|
||||
"@emeraldpay/hashicon-react": "^0.5.2",
|
||||
"@meshtastic/js": "2.3.7-1",
|
||||
"@noble/curves": "^1.5.0",
|
||||
"@radix-ui/react-accordion": "^1.2.0",
|
||||
"@radix-ui/react-checkbox": "^1.1.0",
|
||||
"@radix-ui/react-dialog": "^1.1.1",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-menubar": "^1.1.1",
|
||||
"@radix-ui/react-popover": "^1.1.1",
|
||||
"@radix-ui/react-scroll-area": "^1.1.0",
|
||||
"@radix-ui/react-select": "^2.1.1",
|
||||
"@radix-ui/react-separator": "^1.1.0",
|
||||
"@radix-ui/react-switch": "^1.1.0",
|
||||
"@radix-ui/react-tabs": "^1.1.0",
|
||||
"@radix-ui/react-toast": "^1.2.1",
|
||||
"@radix-ui/react-tooltip": "^1.1.1",
|
||||
"@turf/turf": "^6.5.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"crypto-random-string": "^5.0.0",
|
||||
"immer": "^10.1.1",
|
||||
"lucide-react": "^0.363.0",
|
||||
"mapbox-gl": "npm:empty-npm-package@^1.0.0",
|
||||
"maplibre-gl": "4.1.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-hook-form": "^7.52.0",
|
||||
"react-map-gl": "7.1.7",
|
||||
"react-qrcode-logo": "^2.10.0",
|
||||
"rfc4648": "^1.5.3",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"timeago-react": "^3.0.6",
|
||||
"zustand": "4.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.8.2",
|
||||
"@buf/meshtastic_protobufs.bufbuild_es": "1.10.0-20240820152623-fac6975bbc78.1",
|
||||
"@types/chrome": "^0.0.263",
|
||||
"@types/node": "^20.14.9",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/w3c-web-serial": "^1.0.6",
|
||||
"@types/web-bluetooth": "^0.0.20",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"gzipper": "^7.2.0",
|
||||
"postcss": "^8.4.38",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"tar": "^6.2.1",
|
||||
"tslib": "^2.6.3",
|
||||
"typescript": "^5.5.2",
|
||||
"vite": "^5.3.1",
|
||||
"vite-plugin-environment": "^1.1.3"
|
||||
}
|
||||
"name": "meshtastic-web",
|
||||
"version": "2.7.0-0",
|
||||
"type": "module",
|
||||
"description": "Meshtastic web client monorepo",
|
||||
"license": "GPL-3.0-only",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/meshtastic/web.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/meshtastic/web/issues"
|
||||
},
|
||||
"homepage": "https://meshtastic.org",
|
||||
"simple-git-hooks": {
|
||||
"pre-commit": "pnpm run check:fix"
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"lint": "biome lint",
|
||||
"lint:fix": "biome lint --write",
|
||||
"format": "biome format",
|
||||
"format:fix": "biome format . --write",
|
||||
"check": "biome check",
|
||||
"check:fix": "biome check --write",
|
||||
"build:all": "pnpm run --filter '*' build",
|
||||
"clean:all": "pnpm run --filter '*' clean",
|
||||
"publish:packages": "pnpm run --filter 'packages/transport-* packages/core' build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bufbuild/protobuf": "^2.6.1",
|
||||
"@meshtastic/protobufs": "npm:@jsr/meshtastic__protobufs@^2.7.0",
|
||||
"ste-simple-events": "^3.0.11",
|
||||
"tslog": "^4.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.16.4",
|
||||
"biome": "^0.3.3",
|
||||
"tsdown": "^0.13.4",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
|
||||
27
packages/core/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# @meshtastic/core
|
||||
|
||||
[](https://jsr.io/@meshtastic/core)
|
||||
[](https://github.com/meshtastic/js/actions/workflows/ci.yml)
|
||||
[](https://cla-assistant.io/meshtastic/meshtastic.js)
|
||||
[](https://opencollective.com/meshtastic/)
|
||||
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||
|
||||
## Overview
|
||||
|
||||
`@meshtastic/core` Provides core functionality for interfacing with Meshtastic
|
||||
devices. Installation instructions are available at
|
||||
[JSR](https://jsr.io/@meshtastic/core)
|
||||
[NPM](https://www.npmjs.com/org/meshtastic)
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { MeshDevice } from "@meshtastic/core";
|
||||
|
||||
// Transport if provided by one of the available transport adapters
|
||||
const device = new MeshDevice(transport);
|
||||
```
|
||||
|
||||
## Stats
|
||||
|
||||

|
||||
7
packages/core/jsr.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "@meshtastic/core",
|
||||
"version": "2.6.6",
|
||||
"exports": {
|
||||
".": "./mod.ts"
|
||||
}
|
||||
}
|
||||
5
packages/core/mod.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * as Protobuf from "@meshtastic/protobufs";
|
||||
export { Constants } from "./src/constants.ts";
|
||||
export { MeshDevice } from "./src/meshDevice.ts";
|
||||
export * as Types from "./src/types.ts";
|
||||
export * as Utils from "./src/utils/mod.ts";
|
||||
31
packages/core/package.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "@meshtastic/core",
|
||||
"version": "2.6.6",
|
||||
"description": "Core functionalities for Meshtastic web applications.",
|
||||
"exports": {
|
||||
".": "./mod.ts"
|
||||
},
|
||||
"main": "./dist/mod.mjs",
|
||||
"module": "./dist/mod.mjs",
|
||||
"types": "./dist/mod.d.mts",
|
||||
"license": "GPL-3.0-only",
|
||||
"tsdown": {
|
||||
"entry": ["mod.ts"],
|
||||
"dts": true,
|
||||
"format": ["esm"],
|
||||
"splitting": false,
|
||||
"clean": true
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"prepack": "cp ../../LICENSE ./LICENSE",
|
||||
"clean": "rm -rf dist LICENSE",
|
||||
"build:npm": "tsdown",
|
||||
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
|
||||
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
|
||||
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
|
||||
},
|
||||
"dependencies": {
|
||||
"crc": "npm:crc@^4.3.2"
|
||||
}
|
||||
}
|
||||
10
packages/core/src/constants.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
/** Broadcast destination number */
|
||||
const broadcastNum = 0xffffffff;
|
||||
|
||||
/** Minimum device firmware version supported by this version of the library. */
|
||||
const minFwVer = 2.2;
|
||||
|
||||
export const Constants = {
|
||||
broadcastNum,
|
||||
minFwVer,
|
||||
};
|
||||
1180
packages/core/src/meshDevice.ts
Executable file
130
packages/core/src/types.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import type * as Protobuf from "@meshtastic/protobufs";
|
||||
|
||||
interface Packet {
|
||||
type: "packet";
|
||||
data: Uint8Array;
|
||||
}
|
||||
|
||||
interface DebugLog {
|
||||
type: "debug";
|
||||
data: string;
|
||||
}
|
||||
|
||||
export type DeviceOutput = Packet | DebugLog;
|
||||
|
||||
export interface Transport {
|
||||
toDevice: WritableStream<Uint8Array>;
|
||||
fromDevice: ReadableStream<DeviceOutput>;
|
||||
disconnect(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface QueueItem {
|
||||
id: number;
|
||||
data: Uint8Array;
|
||||
sent: boolean;
|
||||
added: Date;
|
||||
promise: Promise<number>;
|
||||
}
|
||||
|
||||
export interface HttpRetryConfig {
|
||||
maxRetries: number;
|
||||
initialDelayMs: number;
|
||||
maxDelayMs: number;
|
||||
backoffFactor: number;
|
||||
}
|
||||
|
||||
export enum DeviceStatusEnum {
|
||||
DeviceRestarting = 1,
|
||||
DeviceDisconnected = 2,
|
||||
DeviceConnecting = 3,
|
||||
DeviceReconnecting = 4,
|
||||
DeviceConnected = 5,
|
||||
DeviceConfiguring = 6,
|
||||
DeviceConfigured = 7,
|
||||
}
|
||||
|
||||
export type LogEventPacket = LogEvent & { date: Date };
|
||||
|
||||
export type PacketDestination = "broadcast" | "direct";
|
||||
|
||||
export interface PacketMetadata<T> {
|
||||
id: number;
|
||||
rxTime: Date;
|
||||
type: PacketDestination;
|
||||
from: number;
|
||||
to: number;
|
||||
channel: ChannelNumber;
|
||||
data: T;
|
||||
}
|
||||
|
||||
export enum EmitterScope {
|
||||
MeshDevice = 1,
|
||||
SerialConnection = 2,
|
||||
NodeSerialConnection = 3,
|
||||
BleConnection = 4,
|
||||
HttpConnection = 5,
|
||||
}
|
||||
|
||||
export enum Emitter {
|
||||
Constructor = 0,
|
||||
SendText = 1,
|
||||
SendWaypoint = 2,
|
||||
SendPacket = 3,
|
||||
SendRaw = 4,
|
||||
SetConfig = 5,
|
||||
SetModuleConfig = 6,
|
||||
ConfirmSetConfig = 7,
|
||||
SetOwner = 8,
|
||||
SetChannel = 9,
|
||||
ConfirmSetChannel = 10,
|
||||
ClearChannel = 11,
|
||||
GetChannel = 12,
|
||||
GetAllChannels = 13,
|
||||
GetConfig = 14,
|
||||
GetModuleConfig = 15,
|
||||
GetOwner = 16,
|
||||
Configure = 17,
|
||||
HandleFromRadio = 18,
|
||||
HandleMeshPacket = 19,
|
||||
Connect = 20,
|
||||
Ping = 21,
|
||||
ReadFromRadio = 22,
|
||||
WriteToRadio = 23,
|
||||
SetDebugMode = 24,
|
||||
GetMetadata = 25,
|
||||
ResetNodes = 26,
|
||||
Shutdown = 27,
|
||||
Reboot = 28,
|
||||
RebootOta = 29,
|
||||
FactoryReset = 30,
|
||||
EnterDfuMode = 31,
|
||||
RemoveNodeByNum = 32,
|
||||
SetCannedMessages = 33,
|
||||
Disconnect = 34,
|
||||
}
|
||||
|
||||
export interface LogEvent {
|
||||
scope: EmitterScope;
|
||||
emitter: Emitter;
|
||||
message: string;
|
||||
level: Protobuf.Mesh.LogRecord_Level;
|
||||
packet?: Uint8Array;
|
||||
}
|
||||
|
||||
export enum ChannelNumber {
|
||||
Primary = 0,
|
||||
Channel1 = 1,
|
||||
Channel2 = 2,
|
||||
Channel3 = 3,
|
||||
Channel4 = 4,
|
||||
Channel5 = 5,
|
||||
Channel6 = 6,
|
||||
Admin = 7,
|
||||
}
|
||||
|
||||
export type Destination = number | "self" | "broadcast";
|
||||
|
||||
export interface PacketError {
|
||||
id: number;
|
||||
error: Protobuf.Mesh.Routing_Error;
|
||||
}
|
||||
381
packages/core/src/utils/eventSystem.ts
Normal file
@@ -0,0 +1,381 @@
|
||||
import type * as Protobuf from "@meshtastic/protobufs";
|
||||
import { SimpleEventDispatcher } from "ste-simple-events";
|
||||
import type * as Types from "../types.ts";
|
||||
import type { PacketMetadata } from "../types.ts";
|
||||
|
||||
export class EventSystem {
|
||||
/**
|
||||
* Fires when a new FromRadio message has been received from the device
|
||||
*
|
||||
* @event onLogEvent
|
||||
*/
|
||||
public readonly onLogEvent: SimpleEventDispatcher<Types.LogEventPacket> =
|
||||
new SimpleEventDispatcher<Types.LogEventPacket>();
|
||||
|
||||
/**
|
||||
* Fires when a new FromRadio message has been received from the device
|
||||
*
|
||||
* @event onFromRadio
|
||||
*/
|
||||
public readonly onFromRadio: SimpleEventDispatcher<Protobuf.Mesh.FromRadio> =
|
||||
new SimpleEventDispatcher<Protobuf.Mesh.FromRadio>();
|
||||
|
||||
/**
|
||||
* Fires when a new FromRadio message containing a Data packet has been
|
||||
* received from the device
|
||||
*
|
||||
* @event onMeshPacket
|
||||
*/
|
||||
public readonly onMeshPacket: SimpleEventDispatcher<Protobuf.Mesh.MeshPacket> =
|
||||
new SimpleEventDispatcher<Protobuf.Mesh.MeshPacket>();
|
||||
|
||||
/**
|
||||
* Fires when a new MyNodeInfo message has been received from the device
|
||||
*
|
||||
* @event onMyNodeInfo
|
||||
*/
|
||||
public readonly onMyNodeInfo: SimpleEventDispatcher<Protobuf.Mesh.MyNodeInfo> =
|
||||
new SimpleEventDispatcher<Protobuf.Mesh.MyNodeInfo>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a NodeInfo packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onNodeInfoPacket
|
||||
*/
|
||||
public readonly onNodeInfoPacket: SimpleEventDispatcher<Protobuf.Mesh.NodeInfo> =
|
||||
new SimpleEventDispatcher<Protobuf.Mesh.NodeInfo>();
|
||||
|
||||
/**
|
||||
* Fires when a new Channel message is received
|
||||
*
|
||||
* @event onChannelPacket
|
||||
*/
|
||||
public readonly onChannelPacket: SimpleEventDispatcher<Protobuf.Channel.Channel> =
|
||||
new SimpleEventDispatcher<Protobuf.Channel.Channel>();
|
||||
|
||||
/**
|
||||
* Fires when a new Config message is received
|
||||
*
|
||||
* @event onConfigPacket
|
||||
*/
|
||||
public readonly onConfigPacket: SimpleEventDispatcher<Protobuf.Config.Config> =
|
||||
new SimpleEventDispatcher<Protobuf.Config.Config>();
|
||||
|
||||
/**
|
||||
* Fires when a new ModuleConfig message is received
|
||||
*
|
||||
* @event onModuleConfigPacket
|
||||
*/
|
||||
public readonly onModuleConfigPacket: SimpleEventDispatcher<Protobuf.ModuleConfig.ModuleConfig> =
|
||||
new SimpleEventDispatcher<Protobuf.ModuleConfig.ModuleConfig>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a ATAK packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onAtakPacket
|
||||
*/
|
||||
public readonly onAtakPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Text packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onMessagePacket
|
||||
*/
|
||||
public readonly onMessagePacket: SimpleEventDispatcher<
|
||||
PacketMetadata<string>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<string>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Remote Hardware packet has
|
||||
* been received from device
|
||||
*
|
||||
* @event onRemoteHardwarePacket
|
||||
*/
|
||||
public readonly onRemoteHardwarePacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Protobuf.RemoteHardware.HardwareMessage>
|
||||
> = new SimpleEventDispatcher<
|
||||
PacketMetadata<Protobuf.RemoteHardware.HardwareMessage>
|
||||
>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Position packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onPositionPacket
|
||||
*/
|
||||
public readonly onPositionPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Protobuf.Mesh.Position>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.Position>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a User packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onUserPacket
|
||||
*/
|
||||
public readonly onUserPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Protobuf.Mesh.User>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.User>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Routing packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onRoutingPacket
|
||||
*/
|
||||
public readonly onRoutingPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Protobuf.Mesh.Routing>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.Routing>>();
|
||||
|
||||
/**
|
||||
* Fires when the device receives a Metadata packet
|
||||
*
|
||||
* @event onDeviceMetadataPacket
|
||||
*/
|
||||
public readonly onDeviceMetadataPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Protobuf.Mesh.DeviceMetadata>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.DeviceMetadata>>();
|
||||
|
||||
/**
|
||||
* Fires when the device receives a Canned Message Module message packet
|
||||
*
|
||||
* @event onCannedMessageModulePacket
|
||||
*/
|
||||
public readonly onCannedMessageModulePacket: SimpleEventDispatcher<
|
||||
PacketMetadata<string>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<string>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Waypoint packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onWaypointPacket
|
||||
*/
|
||||
public readonly onWaypointPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Protobuf.Mesh.Waypoint>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.Waypoint>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing an Audio packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onAudioPacket
|
||||
*/
|
||||
public readonly onAudioPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Detection Sensor packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onDetectionSensorPacket
|
||||
*/
|
||||
public readonly onDetectionSensorPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Ping packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onPingPacket
|
||||
*/
|
||||
public readonly onPingPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a IP Tunnel packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onIpTunnelPacket
|
||||
*/
|
||||
public readonly onIpTunnelPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Paxcounter packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onPaxcounterPacket
|
||||
*/
|
||||
public readonly onPaxcounterPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Protobuf.PaxCount.Paxcount>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.PaxCount.Paxcount>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Serial packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onSerialPacket
|
||||
*/
|
||||
public readonly onSerialPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Store and Forward packet
|
||||
* has been received from device
|
||||
*
|
||||
* @event onStoreForwardPacket
|
||||
*/
|
||||
public readonly onStoreForwardPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Store and Forward packet
|
||||
* has been received from device
|
||||
*
|
||||
* @event onRangeTestPacket
|
||||
*/
|
||||
public readonly onRangeTestPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Telemetry packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onTelemetryPacket
|
||||
*/
|
||||
public readonly onTelemetryPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Protobuf.Telemetry.Telemetry>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Telemetry.Telemetry>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a ZPS packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onZPSPacket
|
||||
*/
|
||||
public readonly onZpsPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Simulator packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onSimulatorPacket
|
||||
*/
|
||||
public readonly onSimulatorPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Trace Route packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onTraceRoutePacket
|
||||
*/
|
||||
public readonly onTraceRoutePacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Protobuf.Mesh.RouteDiscovery>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.RouteDiscovery>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Neighbor Info packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onNeighborInfoPacket
|
||||
*/
|
||||
public readonly onNeighborInfoPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Protobuf.Mesh.NeighborInfo>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.NeighborInfo>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing an ATAK packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onAtakPluginPacket
|
||||
*/
|
||||
public readonly onAtakPluginPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Map Report packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onMapReportPacket
|
||||
*/
|
||||
public readonly onMapReportPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing a Private packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onPrivatePacket
|
||||
*/
|
||||
public readonly onPrivatePacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when a new MeshPacket message containing an ATAK Forwarder packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onAtakForwarderPacket
|
||||
*/
|
||||
public readonly onAtakForwarderPacket: SimpleEventDispatcher<
|
||||
PacketMetadata<Uint8Array>
|
||||
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||
|
||||
/**
|
||||
* Fires when the devices connection or configuration status changes
|
||||
*
|
||||
* @event onDeviceStatus
|
||||
*/
|
||||
public readonly onDeviceStatus: SimpleEventDispatcher<Types.DeviceStatusEnum> =
|
||||
new SimpleEventDispatcher<Types.DeviceStatusEnum>();
|
||||
|
||||
/**
|
||||
* Fires when a new FromRadio message containing a LogRecord packet has been
|
||||
* received from device
|
||||
*
|
||||
* @event onLogRecord
|
||||
*/
|
||||
public readonly onLogRecord: SimpleEventDispatcher<Protobuf.Mesh.LogRecord> =
|
||||
new SimpleEventDispatcher<Protobuf.Mesh.LogRecord>();
|
||||
|
||||
/**
|
||||
* Fires when the device receives a meshPacket, returns a timestamp
|
||||
*
|
||||
* @event onMeshHeartbeat
|
||||
*/
|
||||
public readonly onMeshHeartbeat: SimpleEventDispatcher<Date> =
|
||||
new SimpleEventDispatcher<Date>();
|
||||
|
||||
/**
|
||||
* Outputs any debug log data (currently serial connections only)
|
||||
*
|
||||
* @event onDeviceDebugLog
|
||||
*/
|
||||
public readonly onDeviceDebugLog: SimpleEventDispatcher<Uint8Array> =
|
||||
new SimpleEventDispatcher<Uint8Array>();
|
||||
|
||||
/**
|
||||
* Outputs status of pending settings changes
|
||||
*
|
||||
* @event onpendingSettingsChange
|
||||
*/
|
||||
public readonly onPendingSettingsChange: SimpleEventDispatcher<boolean> =
|
||||
new SimpleEventDispatcher<boolean>();
|
||||
|
||||
/**
|
||||
* Fires when a QueueStatus message is generated
|
||||
*
|
||||
* @event onQueueStatus
|
||||
*/
|
||||
public readonly onQueueStatus: SimpleEventDispatcher<Protobuf.Mesh.QueueStatus> =
|
||||
new SimpleEventDispatcher<Protobuf.Mesh.QueueStatus>();
|
||||
}
|
||||
5
packages/core/src/utils/mod.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export { EventSystem } from "./eventSystem.ts";
|
||||
export { Queue } from "./queue.ts";
|
||||
export { fromDeviceStream } from "./transform/fromDevice.ts";
|
||||
export { toDeviceStream } from "./transform/toDevice.ts";
|
||||
export { Xmodem } from "./xmodem.ts";
|
||||
129
packages/core/src/utils/queue.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { fromBinary } from "@bufbuild/protobuf";
|
||||
import * as Protobuf from "@meshtastic/protobufs";
|
||||
import { SimpleEventDispatcher } from "ste-simple-events";
|
||||
import type { PacketError, QueueItem } from "../types.ts";
|
||||
|
||||
export class Queue {
|
||||
private queue: QueueItem[] = [];
|
||||
private lock = false;
|
||||
private ackNotifier = new SimpleEventDispatcher<number>();
|
||||
private errorNotifier = new SimpleEventDispatcher<PacketError>();
|
||||
private timeout: number;
|
||||
|
||||
constructor() {
|
||||
this.timeout = 60000;
|
||||
}
|
||||
|
||||
public getState(): QueueItem[] {
|
||||
return this.queue;
|
||||
}
|
||||
|
||||
public clear(): void {
|
||||
this.queue = [];
|
||||
}
|
||||
|
||||
public push(item: Omit<QueueItem, "promise" | "sent" | "added">): void {
|
||||
const queueItem: QueueItem = {
|
||||
...item,
|
||||
sent: false,
|
||||
added: new Date(),
|
||||
promise: new Promise<number>((resolve, reject) => {
|
||||
this.ackNotifier.subscribe((id) => {
|
||||
if (item.id === id) {
|
||||
this.remove(item.id);
|
||||
resolve(id);
|
||||
}
|
||||
});
|
||||
this.errorNotifier.subscribe((e) => {
|
||||
if (item.id === e.id) {
|
||||
this.remove(item.id);
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (this.queue.findIndex((qi) => qi.id === item.id) !== -1) {
|
||||
this.remove(item.id);
|
||||
const decoded = fromBinary(Protobuf.Mesh.ToRadioSchema, item.data);
|
||||
|
||||
if (
|
||||
decoded.payloadVariant.case === "heartbeat" ||
|
||||
decoded.payloadVariant.case === "wantConfigId"
|
||||
) {
|
||||
// heartbeat and wantConfigId packets are not acknowledged by the device, assume success after timeout
|
||||
resolve(item.id);
|
||||
return;
|
||||
}
|
||||
|
||||
console.warn(
|
||||
`Packet ${item.id} of type ${decoded.payloadVariant.case} timed out`,
|
||||
);
|
||||
|
||||
reject({
|
||||
id: item.id,
|
||||
error: Protobuf.Mesh.Routing_Error.TIMEOUT,
|
||||
});
|
||||
}
|
||||
}, this.timeout);
|
||||
}),
|
||||
};
|
||||
this.queue.push(queueItem);
|
||||
}
|
||||
|
||||
public remove(id: number): void {
|
||||
if (this.lock) {
|
||||
setTimeout(() => this.remove(id), 100);
|
||||
return;
|
||||
}
|
||||
this.queue = this.queue.filter((item) => item.id !== id);
|
||||
}
|
||||
|
||||
public processAck(id: number): void {
|
||||
this.ackNotifier.dispatch(id);
|
||||
}
|
||||
|
||||
public processError(e: PacketError): void {
|
||||
console.error(
|
||||
`Error received for packet ${e.id}: ${
|
||||
Protobuf.Mesh.Routing_Error[e.error]
|
||||
}`,
|
||||
);
|
||||
this.errorNotifier.dispatch(e);
|
||||
}
|
||||
|
||||
public wait(id: number): Promise<number> {
|
||||
const queueItem = this.queue.find((qi) => qi.id === id);
|
||||
if (!queueItem) {
|
||||
throw new Error("Packet does not exist");
|
||||
}
|
||||
return queueItem.promise;
|
||||
}
|
||||
|
||||
public async processQueue(
|
||||
outputStream: WritableStream<Uint8Array>,
|
||||
): Promise<void> {
|
||||
if (this.lock) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lock = true;
|
||||
const writer = outputStream.getWriter();
|
||||
|
||||
try {
|
||||
while (this.queue.filter((p) => !p.sent).length > 0) {
|
||||
const item = this.queue.filter((p) => !p.sent)[0];
|
||||
if (item) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||
try {
|
||||
await writer.write(item.data);
|
||||
item.sent = true;
|
||||
} catch (error) {
|
||||
console.error(`Error sending packet ${item.id}`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
writer.releaseLock();
|
||||
this.lock = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
222
packages/core/src/utils/transform/decodePacket.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
import { fromBinary } from "@bufbuild/protobuf";
|
||||
import type { MeshDevice } from "../../../mod.ts";
|
||||
import { Constants, Protobuf, Types } from "../../../mod.ts";
|
||||
import type { DeviceOutput } from "../../types.ts";
|
||||
|
||||
export const decodePacket = (device: MeshDevice) =>
|
||||
new WritableStream<DeviceOutput>({
|
||||
write(chunk) {
|
||||
switch (chunk.type) {
|
||||
case "debug": {
|
||||
break;
|
||||
}
|
||||
case "packet": {
|
||||
const decodedMessage = fromBinary(
|
||||
Protobuf.Mesh.FromRadioSchema,
|
||||
chunk.data,
|
||||
);
|
||||
device.events.onFromRadio.dispatch(decodedMessage);
|
||||
|
||||
/** @todo Add map here when `all=true` gets fixed. */
|
||||
switch (decodedMessage.payloadVariant.case) {
|
||||
case "packet": {
|
||||
device.handleMeshPacket(decodedMessage.payloadVariant.value);
|
||||
break;
|
||||
}
|
||||
|
||||
case "myInfo": {
|
||||
device.events.onMyNodeInfo.dispatch(
|
||||
decodedMessage.payloadVariant.value,
|
||||
);
|
||||
device.log.info(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
"📱 Received Node info for this device",
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "nodeInfo": {
|
||||
device.log.info(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
`📱 Received Node Info packet for node: ${decodedMessage.payloadVariant.value.num}`,
|
||||
);
|
||||
|
||||
device.events.onNodeInfoPacket.dispatch(
|
||||
decodedMessage.payloadVariant.value,
|
||||
);
|
||||
|
||||
//TODO: HERE
|
||||
if (decodedMessage.payloadVariant.value.position) {
|
||||
device.events.onPositionPacket.dispatch({
|
||||
id: decodedMessage.id,
|
||||
rxTime: new Date(),
|
||||
from: decodedMessage.payloadVariant.value.num,
|
||||
to: decodedMessage.payloadVariant.value.num,
|
||||
type: "direct",
|
||||
channel: Types.ChannelNumber.Primary,
|
||||
data: decodedMessage.payloadVariant.value.position,
|
||||
});
|
||||
}
|
||||
|
||||
//TODO: HERE
|
||||
if (decodedMessage.payloadVariant.value.user) {
|
||||
device.events.onUserPacket.dispatch({
|
||||
id: decodedMessage.id,
|
||||
rxTime: new Date(),
|
||||
from: decodedMessage.payloadVariant.value.num,
|
||||
to: decodedMessage.payloadVariant.value.num,
|
||||
type: "direct",
|
||||
channel: Types.ChannelNumber.Primary,
|
||||
data: decodedMessage.payloadVariant.value.user,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "config": {
|
||||
if (decodedMessage.payloadVariant.value.payloadVariant.case) {
|
||||
device.log.trace(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
`💾 Received Config packet of variant: ${decodedMessage.payloadVariant.value.payloadVariant.case}`,
|
||||
);
|
||||
} else {
|
||||
device.log.warn(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
`⚠️ Received Config packet of variant: ${"UNK"}`,
|
||||
);
|
||||
}
|
||||
|
||||
device.events.onConfigPacket.dispatch(
|
||||
decodedMessage.payloadVariant.value,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "logRecord": {
|
||||
device.log.trace(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
"Received onLogRecord",
|
||||
);
|
||||
device.events.onLogRecord.dispatch(
|
||||
decodedMessage.payloadVariant.value,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "configCompleteId": {
|
||||
if (decodedMessage.payloadVariant.value !== device.configId) {
|
||||
device.log.error(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
`❌ Invalid config id received from device, expected ${device.configId} but received ${decodedMessage.payloadVariant.value}`,
|
||||
);
|
||||
}
|
||||
|
||||
device.log.info(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
`⚙️ Valid config id received from device: ${device.configId}`,
|
||||
);
|
||||
|
||||
device.updateDeviceStatus(
|
||||
Types.DeviceStatusEnum.DeviceConfigured,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "rebooted": {
|
||||
device.configure().catch(() => {
|
||||
// TODO: FIX, workaround for `wantConfigId` not getting acks.
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case "moduleConfig": {
|
||||
if (decodedMessage.payloadVariant.value.payloadVariant.case) {
|
||||
device.log.trace(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
`💾 Received Module Config packet of variant: ${decodedMessage.payloadVariant.value.payloadVariant.case}`,
|
||||
);
|
||||
} else {
|
||||
device.log.warn(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
"⚠️ Received Module Config packet of variant: UNK",
|
||||
);
|
||||
}
|
||||
|
||||
device.events.onModuleConfigPacket.dispatch(
|
||||
decodedMessage.payloadVariant.value,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "channel": {
|
||||
device.log.trace(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
`🔐 Received Channel: ${decodedMessage.payloadVariant.value.index}`,
|
||||
);
|
||||
|
||||
device.events.onChannelPacket.dispatch(
|
||||
decodedMessage.payloadVariant.value,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "queueStatus": {
|
||||
device.log.trace(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
`🚧 Received Queue Status: ${decodedMessage.payloadVariant.value}`,
|
||||
);
|
||||
|
||||
device.events.onQueueStatus.dispatch(
|
||||
decodedMessage.payloadVariant.value,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "xmodemPacket": {
|
||||
device.xModem.handlePacket(decodedMessage.payloadVariant.value);
|
||||
break;
|
||||
}
|
||||
|
||||
case "metadata": {
|
||||
if (
|
||||
Number.parseFloat(
|
||||
decodedMessage.payloadVariant.value.firmwareVersion,
|
||||
) < Constants.minFwVer
|
||||
) {
|
||||
device.log.fatal(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
`Device firmware outdated. Min supported: ${Constants.minFwVer} got : ${decodedMessage.payloadVariant.value.firmwareVersion}`,
|
||||
);
|
||||
}
|
||||
device.log.debug(
|
||||
Types.Emitter[Types.Emitter.GetMetadata],
|
||||
"🏷️ Received metadata packet",
|
||||
);
|
||||
|
||||
device.events.onDeviceMetadataPacket.dispatch({
|
||||
id: decodedMessage.id,
|
||||
rxTime: new Date(),
|
||||
from: 0,
|
||||
to: 0,
|
||||
type: "direct",
|
||||
channel: Types.ChannelNumber.Primary,
|
||||
data: decodedMessage.payloadVariant.value,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case "mqttClientProxyMessage": {
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
device.log.warn(
|
||||
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||
`⚠️ Unhandled payload variant: ${decodedMessage.payloadVariant.case}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
71
packages/core/src/utils/transform/fromDevice.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import type { DeviceOutput } from "../../types.ts";
|
||||
|
||||
export const fromDeviceStream: () => TransformStream<Uint8Array, DeviceOutput> =
|
||||
(
|
||||
// onReleaseEvent: SimpleEventDispatcher<boolean>,
|
||||
) => {
|
||||
let byteBuffer = new Uint8Array([]);
|
||||
const textDecoder = new TextDecoder();
|
||||
return new TransformStream<Uint8Array, DeviceOutput>({
|
||||
transform(chunk: Uint8Array, controller): void {
|
||||
// onReleaseEvent.subscribe(() => {
|
||||
// controller.terminate();
|
||||
// });
|
||||
byteBuffer = new Uint8Array([...byteBuffer, ...chunk]);
|
||||
let processingExhausted = false;
|
||||
while (byteBuffer.length !== 0 && !processingExhausted) {
|
||||
const framingIndex = byteBuffer.findIndex((byte) => byte === 0x94);
|
||||
const framingByte2 = byteBuffer[framingIndex + 1];
|
||||
if (framingByte2 === 0xc3) {
|
||||
if (byteBuffer.subarray(0, framingIndex).length) {
|
||||
controller.enqueue({
|
||||
type: "debug",
|
||||
data: textDecoder.decode(byteBuffer.subarray(0, framingIndex)),
|
||||
});
|
||||
byteBuffer = byteBuffer.subarray(framingIndex);
|
||||
}
|
||||
|
||||
const msb = byteBuffer[2];
|
||||
const lsb = byteBuffer[3];
|
||||
|
||||
if (
|
||||
msb !== undefined &&
|
||||
lsb !== undefined &&
|
||||
byteBuffer.length >= 4 + (msb << 8) + lsb
|
||||
) {
|
||||
const packet = byteBuffer.subarray(4, 4 + (msb << 8) + lsb);
|
||||
|
||||
const malformedDetectorIndex = packet.findIndex(
|
||||
(byte) => byte === 0x94,
|
||||
);
|
||||
if (
|
||||
malformedDetectorIndex !== -1 &&
|
||||
packet[malformedDetectorIndex + 1] === 0xc3
|
||||
) {
|
||||
console.warn(
|
||||
`⚠️ Malformed packet found, discarding: ${byteBuffer
|
||||
.subarray(0, malformedDetectorIndex - 1)
|
||||
.toString()}`,
|
||||
);
|
||||
|
||||
byteBuffer = byteBuffer.subarray(malformedDetectorIndex);
|
||||
} else {
|
||||
byteBuffer = byteBuffer.subarray(3 + (msb << 8) + lsb + 1);
|
||||
|
||||
controller.enqueue({
|
||||
type: "packet",
|
||||
data: packet,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
/** Only partioal message in buffer, wait for the rest */
|
||||
processingExhausted = true;
|
||||
}
|
||||
} else {
|
||||
/** Message not complete, only 1 byte in buffer */
|
||||
processingExhausted = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
16
packages/core/src/utils/transform/toDevice.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Pads packets with appropriate framing information before writing to the output stream.
|
||||
*/
|
||||
export const toDeviceStream: TransformStream<Uint8Array, Uint8Array> =
|
||||
new TransformStream<Uint8Array, Uint8Array>({
|
||||
transform(chunk: Uint8Array, controller): void {
|
||||
const bufLen = chunk.length;
|
||||
const header = new Uint8Array([
|
||||
0x94,
|
||||
0xc3,
|
||||
(bufLen >> 8) & 0xff,
|
||||
bufLen & 0xff,
|
||||
]);
|
||||
controller.enqueue(new Uint8Array([...header, ...chunk]));
|
||||
},
|
||||
});
|
||||
135
packages/core/src/utils/xmodem.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import { create, toBinary } from "@bufbuild/protobuf";
|
||||
import * as Protobuf from "@meshtastic/protobufs";
|
||||
import crc16ccitt from "crc/calculators/crc16ccitt";
|
||||
|
||||
//if counter > 35 then reset counter/clear/error/reject promise
|
||||
type XmodemProps = (toRadio: Uint8Array, id?: number) => Promise<number>;
|
||||
|
||||
export class Xmodem {
|
||||
private sendRaw: XmodemProps;
|
||||
private rxBuffer: Uint8Array[];
|
||||
private txBuffer: Uint8Array[];
|
||||
private textEncoder: TextEncoder;
|
||||
private counter: number;
|
||||
|
||||
constructor(sendRaw: XmodemProps) {
|
||||
this.sendRaw = sendRaw;
|
||||
this.rxBuffer = [];
|
||||
this.txBuffer = [];
|
||||
this.textEncoder = new TextEncoder();
|
||||
this.counter = 0;
|
||||
}
|
||||
|
||||
async downloadFile(filename: string): Promise<number> {
|
||||
return await this.sendCommand(
|
||||
Protobuf.Xmodem.XModem_Control.STX,
|
||||
this.textEncoder.encode(filename),
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
async uploadFile(filename: string, data: Uint8Array): Promise<number> {
|
||||
for (let i = 0; i < data.length; i += 128) {
|
||||
this.txBuffer.push(data.slice(i, i + 128));
|
||||
}
|
||||
|
||||
return await this.sendCommand(
|
||||
Protobuf.Xmodem.XModem_Control.SOH,
|
||||
this.textEncoder.encode(filename),
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
async sendCommand(
|
||||
command: Protobuf.Xmodem.XModem_Control,
|
||||
buffer?: Uint8Array,
|
||||
sequence?: number,
|
||||
crc16?: number,
|
||||
): Promise<number> {
|
||||
const toRadio = create(Protobuf.Mesh.ToRadioSchema, {
|
||||
payloadVariant: {
|
||||
case: "xmodemPacket",
|
||||
value: {
|
||||
buffer,
|
||||
control: command,
|
||||
seq: sequence,
|
||||
crc16: crc16,
|
||||
},
|
||||
},
|
||||
});
|
||||
return await this.sendRaw(toBinary(Protobuf.Mesh.ToRadioSchema, toRadio));
|
||||
}
|
||||
|
||||
async handlePacket(packet: Protobuf.Xmodem.XModem): Promise<number> {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
switch (packet.control) {
|
||||
case Protobuf.Xmodem.XModem_Control.NUL: {
|
||||
// nothing
|
||||
break;
|
||||
}
|
||||
case Protobuf.Xmodem.XModem_Control.SOH: {
|
||||
this.counter = packet.seq;
|
||||
if (this.validateCrc16(packet)) {
|
||||
this.rxBuffer[this.counter] = packet.buffer;
|
||||
return this.sendCommand(Protobuf.Xmodem.XModem_Control.ACK);
|
||||
}
|
||||
return await this.sendCommand(
|
||||
Protobuf.Xmodem.XModem_Control.NAK,
|
||||
undefined,
|
||||
packet.seq,
|
||||
);
|
||||
}
|
||||
case Protobuf.Xmodem.XModem_Control.STX: {
|
||||
break;
|
||||
}
|
||||
case Protobuf.Xmodem.XModem_Control.EOT: {
|
||||
// end of transmission
|
||||
break;
|
||||
}
|
||||
case Protobuf.Xmodem.XModem_Control.ACK: {
|
||||
this.counter++;
|
||||
if (this.txBuffer[this.counter - 1]) {
|
||||
return this.sendCommand(
|
||||
Protobuf.Xmodem.XModem_Control.SOH,
|
||||
this.txBuffer[this.counter - 1],
|
||||
this.counter,
|
||||
crc16ccitt(this.txBuffer[this.counter - 1] ?? new Uint8Array()),
|
||||
);
|
||||
}
|
||||
if (this.counter === this.txBuffer.length + 1) {
|
||||
return this.sendCommand(Protobuf.Xmodem.XModem_Control.EOT);
|
||||
}
|
||||
this.clear();
|
||||
break;
|
||||
}
|
||||
case Protobuf.Xmodem.XModem_Control.NAK: {
|
||||
return this.sendCommand(
|
||||
Protobuf.Xmodem.XModem_Control.SOH,
|
||||
this.txBuffer[this.counter],
|
||||
this.counter,
|
||||
crc16ccitt(this.txBuffer[this.counter - 1] ?? new Uint8Array()),
|
||||
);
|
||||
}
|
||||
case Protobuf.Xmodem.XModem_Control.CAN: {
|
||||
this.clear();
|
||||
break;
|
||||
}
|
||||
case Protobuf.Xmodem.XModem_Control.CTRLZ: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
validateCrc16(packet: Protobuf.Xmodem.XModem): boolean {
|
||||
return crc16ccitt(packet.buffer) === packet.crc16;
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.counter = 0;
|
||||
this.rxBuffer = [];
|
||||
this.txBuffer = [];
|
||||
}
|
||||
}
|
||||
18
packages/core/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"target": "ES2020",
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"moduleResolution": "bundler",
|
||||
"emitDeclarationOnly": false,
|
||||
"esModuleInterop": true,
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
28
packages/transport-deno/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# @meshtastic/transport-deno
|
||||
|
||||
[](https://jsr.io/@meshtastic/transport-deno)
|
||||
[](https://github.com/meshtastic/js/actions/workflows/ci.yml)
|
||||
[](https://cla-assistant.io/meshtastic/meshtastic.js)
|
||||
[](https://opencollective.com/meshtastic/)
|
||||
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||
|
||||
## Overview
|
||||
|
||||
`@meshtastic/transport-deno` Provides TCP transport (Deno) for Meshtastic
|
||||
devices. Installation instructions are avaliable at
|
||||
[JSR](https://jsr.io/@meshtastic/transport-deno)
|
||||
[NPM](https://www.npmjs.com/org/meshtastic/transport-deno)
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { MeshDevice } from "@meshtastic/core";
|
||||
import { TransportDeno } from "@meshtastic/transport-deno";
|
||||
|
||||
const transport = await TransportDeno.create("10.10.0.57");
|
||||
const device = new MeshDevice(transport);
|
||||
```
|
||||
|
||||
## Stats
|
||||
|
||||

|
||||
5
packages/transport-deno/deno.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"imports": {
|
||||
"@deno/dnt": "jsr:@deno/dnt@^0.42.3"
|
||||
}
|
||||
}
|
||||
1
packages/transport-deno/mod.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { TransportDeno } from "./src/transport.ts";
|
||||
22
packages/transport-deno/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "@meshtastic/transport-deno",
|
||||
"version": "0.1.1",
|
||||
"description": "Deno-specific transport layer for Meshtastic web applications.",
|
||||
"exports": {
|
||||
".": "./mod.ts"
|
||||
},
|
||||
"main": "./dist/mod.mjs",
|
||||
"module": "./dist/mod.mjs",
|
||||
"types": "./dist/mod.d.mts",
|
||||
"files": ["dist/*", "mod.ts", "README.md", "../../LICENSE"],
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"prepack": "cp ../../LICENSE ./LICENSE",
|
||||
"clean": "rm -rf dist LICENSE",
|
||||
"build:npm": "tsdown",
|
||||
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
|
||||
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
|
||||
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
|
||||
}
|
||||
}
|
||||
31
packages/transport-deno/scripts/build_npm.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { build, emptyDir } from "@deno/dnt";
|
||||
|
||||
await emptyDir("./npm");
|
||||
|
||||
await build({
|
||||
entryPoints: ["./mod.ts"],
|
||||
outDir: "./npm",
|
||||
shims: {
|
||||
// see JS docs for overview and more options
|
||||
deno: true,
|
||||
},
|
||||
package: {
|
||||
// package.json properties
|
||||
name: "@meshtastic/transport-deno",
|
||||
version: Deno.args[0],
|
||||
description: "A Deno transport layer for your project, enabling seamless integration with npm.",
|
||||
license: "GPL-3.0-only",
|
||||
repository: {
|
||||
type: "git",
|
||||
url: "git+https://github.com/username/repo.git",
|
||||
},
|
||||
bugs: {
|
||||
url: "https://github.com/meshtastic/web/issues",
|
||||
},
|
||||
},
|
||||
postBuild() {
|
||||
// steps to run after building and before running the tests
|
||||
Deno.copyFileSync("../../LICENSE", "npm/LICENSE");
|
||||
Deno.copyFileSync("README.md", "npm/README.md");
|
||||
},
|
||||
});
|
||||
40
packages/transport-deno/src/transport.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import type { Types } from "@meshtastic/core";
|
||||
import { Utils } from "@meshtastic/core";
|
||||
|
||||
export class TransportDeno implements Types.Transport {
|
||||
private _toDevice: WritableStream<Uint8Array>;
|
||||
private _fromDevice: ReadableStream<Types.DeviceOutput>;
|
||||
private connection: Deno.Conn | undefined;
|
||||
|
||||
public static async create(hostname: string): Promise<TransportDeno> {
|
||||
const connection = await Deno.connect({
|
||||
hostname,
|
||||
port: 4403,
|
||||
});
|
||||
return new TransportDeno(connection);
|
||||
}
|
||||
|
||||
constructor(connection: Deno.Conn) {
|
||||
this.connection = connection;
|
||||
Utils.toDeviceStream.readable.pipeTo(this.connection.writable);
|
||||
|
||||
this._toDevice = Utils.toDeviceStream.writable;
|
||||
this._fromDevice = this.connection.readable.pipeThrough(
|
||||
Utils.fromDeviceStream(),
|
||||
);
|
||||
}
|
||||
|
||||
get toDevice(): WritableStream<Uint8Array> {
|
||||
return this._toDevice;
|
||||
}
|
||||
|
||||
get fromDevice(): ReadableStream<Types.DeviceOutput> {
|
||||
return this._fromDevice;
|
||||
}
|
||||
|
||||
disconnect(): Promise<void> {
|
||||
this.connection.close();
|
||||
this.connection = undefined;
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
674
packages/transport-http/LICENSE
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
28
packages/transport-http/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# @meshtastic/transport-http
|
||||
|
||||
[](https://jsr.io/@meshtastic/transport-http)
|
||||
[](https://github.com/meshtastic/js/actions/workflows/ci.yml)
|
||||
[](https://cla-assistant.io/meshtastic/meshtastic.js)
|
||||
[](https://opencollective.com/meshtastic/)
|
||||
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||
|
||||
## Overview
|
||||
|
||||
`@meshtastic/transport-http` Provides HTTP(S) transport for Meshtastic devices.
|
||||
Installation instructions are available at
|
||||
[JSR](https://jsr.io/@meshtastic/transport-http)
|
||||
[NPM](https://www.npmjs.com/package/@meshtastic/transport-http)
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { MeshDevice } from "@meshtastic/core";
|
||||
import { TransportHTTP } from "@meshtastic/transport-http";
|
||||
|
||||
const transport = await TransportHTTP.create("10.10.0.57");
|
||||
const device = new MeshDevice(transport);
|
||||
```
|
||||
|
||||
## Stats
|
||||
|
||||

|
||||
1
packages/transport-http/mod.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { TransportHTTP } from "./src/transport.ts";
|
||||
32
packages/transport-http/package.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "@meshtastic/transport-http",
|
||||
"version": "0.2.3",
|
||||
"description": "A transport layer for Meshtastic applications using HTTP.",
|
||||
"exports": {".": "./mod.ts"},
|
||||
"main": "./dist/mod.mjs",
|
||||
"module": "./dist/mod.mjs",
|
||||
"types": "./dist/mod.d.mts",
|
||||
"license": "GPL-3.0-only",
|
||||
"tsdown": {
|
||||
"entry": ["mod.ts"],
|
||||
"dts": true,
|
||||
"format": ["esm"],
|
||||
"splitting": false,
|
||||
"clean": true
|
||||
},
|
||||
"files": [
|
||||
"package.json",
|
||||
"README.md",
|
||||
"LICENSE",
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"prepack": "cp ../../LICENSE ./LICENSE",
|
||||
"clean": "rm -rf dist LICENSE",
|
||||
"build:npm": "tsdown",
|
||||
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
|
||||
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
|
||||
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
|
||||
}
|
||||
}
|
||||
1135
packages/transport-http/pnpm-lock.yaml
generated
Normal file
113
packages/transport-http/src/transport.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import type { Types } from "@meshtastic/core";
|
||||
|
||||
export class TransportHTTP implements Types.Transport {
|
||||
private _toDevice: WritableStream<Uint8Array>;
|
||||
private _fromDevice: ReadableStream<Types.DeviceOutput>;
|
||||
private url: string;
|
||||
private receiveBatchRequests: boolean;
|
||||
private fetchInterval: number;
|
||||
private fetching: boolean;
|
||||
private interval: ReturnType<typeof setInterval> | undefined;
|
||||
|
||||
public static async create(
|
||||
address: string,
|
||||
tls?: boolean,
|
||||
): Promise<TransportHTTP> {
|
||||
const connectionUrl = `${tls ? "https" : "http"}://${address}`;
|
||||
await fetch(`${connectionUrl}/api/v1/toradio`, {
|
||||
method: "OPTIONS",
|
||||
});
|
||||
await Promise.resolve();
|
||||
return new TransportHTTP(connectionUrl);
|
||||
}
|
||||
|
||||
constructor(url: string) {
|
||||
this.url = url;
|
||||
this.receiveBatchRequests = false;
|
||||
this.fetchInterval = 3000;
|
||||
this.fetching = false;
|
||||
|
||||
this._toDevice = new WritableStream<Uint8Array>({
|
||||
write: async (chunk) => {
|
||||
await this.writeToRadio(chunk);
|
||||
},
|
||||
});
|
||||
|
||||
let controller: ReadableStreamDefaultController<Types.DeviceOutput>;
|
||||
|
||||
this._fromDevice = new ReadableStream<Types.DeviceOutput>({
|
||||
start: (ctrl) => {
|
||||
controller = ctrl;
|
||||
},
|
||||
});
|
||||
|
||||
this.interval = setInterval(async () => {
|
||||
if (this.fetching) {
|
||||
// We still have the previous request open
|
||||
return;
|
||||
}
|
||||
this.fetching = true;
|
||||
try {
|
||||
await this.readFromRadio(controller);
|
||||
} catch {
|
||||
// TODO: Emit disconnection events for certain types of errors
|
||||
}
|
||||
this.fetching = false;
|
||||
}, this.fetchInterval);
|
||||
}
|
||||
|
||||
private async readFromRadio(
|
||||
controller: ReadableStreamDefaultController<Types.DeviceOutput>,
|
||||
): Promise<void> {
|
||||
let readBuffer = new ArrayBuffer(1);
|
||||
while (readBuffer.byteLength > 0) {
|
||||
const response = await fetch(
|
||||
`${this.url}/api/v1/fromradio?all=${
|
||||
this.receiveBatchRequests ? "true" : "false"
|
||||
}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
Accept: "application/x-protobuf",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
readBuffer = await response.arrayBuffer();
|
||||
|
||||
if (readBuffer.byteLength > 0) {
|
||||
controller.enqueue({
|
||||
type: "packet",
|
||||
data: new Uint8Array(readBuffer),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async writeToRadio(data: Uint8Array): Promise<void> {
|
||||
await fetch(`${this.url}/api/v1/toradio`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/x-protobuf",
|
||||
},
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
get toDevice(): WritableStream<Uint8Array> {
|
||||
return this._toDevice;
|
||||
}
|
||||
|
||||
get fromDevice(): ReadableStream<Types.DeviceOutput> {
|
||||
return this._fromDevice;
|
||||
}
|
||||
|
||||
disconnect(): Promise<void> {
|
||||
this.fetching = false;
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
this.interval = undefined;
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
13
packages/transport-http/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"target": "ES2020",
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"moduleResolution": "bundler",
|
||||
"emitDeclarationOnly": false,
|
||||
"esModuleInterop": true,
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
28
packages/transport-node/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# @meshtastic/transport-node
|
||||
|
||||
[](https://jsr.io/@meshtastic/transport-node)
|
||||
[](https://github.com/meshtastic/js/actions/workflows/ci.yml)
|
||||
[](https://cla-assistant.io/meshtastic/meshtastic.js)
|
||||
[](https://opencollective.com/meshtastic/)
|
||||
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||
|
||||
## Overview
|
||||
|
||||
`@meshtastic/transport-node` Provides TCP transport (Node) for Meshtastic
|
||||
devices. Installation instructions are available at
|
||||
[JSR](https://jsr.io/@meshtastic/transport-node)
|
||||
[NPM](https://www.npmjs.com/package/@meshtastic/transport-node)
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { MeshDevice } from "@meshtastic/core";
|
||||
import { TransportNode } from "@meshtastic/transport-node";
|
||||
|
||||
const transport = await TransportNode.create("10.10.0.57");
|
||||
const device = new MeshDevice(transport);
|
||||
```
|
||||
|
||||
## Stats
|
||||
|
||||

|
||||
1
packages/transport-node/mod.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { TransportNode } from "./src/transport.ts";
|
||||
35
packages/transport-node/package.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "@meshtastic/transport-node",
|
||||
"version": "0.0.1",
|
||||
"description": "NodeJS-specific transport layer for Meshtastic web applications.",
|
||||
"exports": {
|
||||
".": "./mod.ts"
|
||||
},
|
||||
"main": "./dist/mod.mjs",
|
||||
"module": "./dist/mod.mjs",
|
||||
"types": "./dist/mod.d.mts",
|
||||
|
||||
"license": "GPL-3.0-only",
|
||||
"tsdown": {
|
||||
"entry": ["mod.ts"],
|
||||
"dts": true,
|
||||
"format": ["esm"],
|
||||
"splitting": false,
|
||||
"clean": true
|
||||
},
|
||||
"files": [
|
||||
"package.json",
|
||||
"README.md",
|
||||
"LICENSE",
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"prepack": "cp ../../LICENSE ./LICENSE",
|
||||
"clean": "rm -rf dist LICENSE",
|
||||
"build:npm": "tsdown",
|
||||
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
|
||||
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
|
||||
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
|
||||
}
|
||||
}
|
||||
84
packages/transport-node/src/transport.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { Socket } from "node:net";
|
||||
import { Readable, Writable } from "node:stream";
|
||||
import type { Types } from "@meshtastic/core";
|
||||
import { Utils } from "@meshtastic/core";
|
||||
|
||||
export class TransportNode implements Types.Transport {
|
||||
private readonly _toDevice: WritableStream<Uint8Array>;
|
||||
private readonly _fromDevice: ReadableStream<Types.DeviceOutput>;
|
||||
private socket: Socket | undefined;
|
||||
|
||||
/**
|
||||
* Creates and connects a new TransportNode instance.
|
||||
* @param hostname - The IP address or hostname of the Meshtastic device.
|
||||
* @param port - The port number for the TCP connection (defaults to 4403).
|
||||
* @returns A promise that resolves with a connected TransportNode instance.
|
||||
*/
|
||||
public static create(hostname: string, port = 4403): Promise<TransportNode> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const socket = new Socket();
|
||||
|
||||
const onError = (err: Error) => {
|
||||
socket.destroy();
|
||||
reject(err);
|
||||
};
|
||||
|
||||
socket.once("error", onError);
|
||||
|
||||
socket.connect(port, hostname, () => {
|
||||
socket.removeListener("error", onError);
|
||||
resolve(new TransportNode(socket));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new TransportNode.
|
||||
* @param connection - An active Node.js net.Socket connection.
|
||||
*/
|
||||
constructor(connection: Socket) {
|
||||
this.socket = connection;
|
||||
this.socket.on("error", (err) => {
|
||||
console.error("Socket connection error:", err);
|
||||
});
|
||||
|
||||
const fromDeviceSource = Readable.toWeb(
|
||||
connection,
|
||||
) as ReadableStream<Uint8Array>;
|
||||
this._fromDevice = fromDeviceSource.pipeThrough(Utils.fromDeviceStream());
|
||||
|
||||
// Stream for data going FROM the application TO the Meshtastic device.
|
||||
const toDeviceTransform = Utils.toDeviceStream;
|
||||
this._toDevice = toDeviceTransform.writable;
|
||||
|
||||
// The readable end of the transform is then piped to the Node.js socket.
|
||||
// A similar assertion is needed here because `Writable.toWeb` also returns
|
||||
// a generically typed stream (`WritableStream<any>`).
|
||||
toDeviceTransform.readable
|
||||
.pipeTo(Writable.toWeb(connection) as WritableStream<Uint8Array>)
|
||||
.catch((err) => {
|
||||
console.error("Error piping data to socket:", err);
|
||||
this.socket.destroy(err as Error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The WritableStream to send data to the Meshtastic device.
|
||||
*/
|
||||
public get toDevice(): WritableStream<Uint8Array> {
|
||||
return this._toDevice;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ReadableStream to receive data from the Meshtastic device.
|
||||
*/
|
||||
public get fromDevice(): ReadableStream<Types.DeviceOutput> {
|
||||
return this._fromDevice;
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.socket.destroy();
|
||||
this.socket = undefined;
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
18
packages/transport-node/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"target": "ES2020",
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"moduleResolution": "bundler",
|
||||
"emitDeclarationOnly": false,
|
||||
"esModuleInterop": true,
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
35
packages/transport-web-bluetooth/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# @meshtastic/transport-web-bluetooth
|
||||
|
||||
[](https://jsr.io/@meshtastic/transport-web-bluetooth)
|
||||
[](https://github.com/meshtastic/js/actions/workflows/ci.yml)
|
||||
[](https://cla-assistant.io/meshtastic/meshtastic.js)
|
||||
[](https://opencollective.com/meshtastic/)
|
||||
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||
|
||||
## Overview
|
||||
|
||||
`@meshtastic/transport-web-bluetooth` Provides Web Bluetooth transport for
|
||||
Meshtastic devices. Installation instructions are available at
|
||||
[JSR](https://jsr.io/@meshtastic/transport-web-bluetooth)
|
||||
[NPM](https://www.npmjs.com/org/meshtastic/transport-web-bluetooth)
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { MeshDevice } from "@meshtastic/core";
|
||||
import { TransportWebBluetooth } from "@meshtastic/transport-web-bluetooth";
|
||||
|
||||
const transport = await TransportWebBluetooth.create();
|
||||
const device = new MeshDevice(transport);
|
||||
```
|
||||
|
||||
## Stats
|
||||
|
||||

|
||||
|
||||
### Compatibility
|
||||
|
||||
The Web Bluetooth API's have limited support in browsers, compatibility is
|
||||
represented in the matrix below.
|
||||
|
||||

|
||||
1
packages/transport-web-bluetooth/mod.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { TransportWebBluetooth } from "./src/transport.ts";
|
||||
33
packages/transport-web-bluetooth/package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "@meshtastic/transport-web-bluetooth",
|
||||
"version": "0.1.4",
|
||||
"description": "A transport layer for Meshtastic applications using Web Bluetooth.",
|
||||
"exports": {
|
||||
".": "./mod.ts"
|
||||
},
|
||||
"main": "./dist/mod.mjs",
|
||||
"module": "./dist/mod.mjs",
|
||||
"types": "./dist/mod.d.mts",
|
||||
"files": ["dist/*", "mod.ts", "README.md", "../../LICENSE"],
|
||||
"license": "GPL-3.0-only",
|
||||
"tsdown": {
|
||||
"entry": ["mod.ts"],
|
||||
"dts": true,
|
||||
"format": ["esm"],
|
||||
"splitting": false,
|
||||
"clean": true
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"prepack": "cp ../../LICENSE ./LICENSE",
|
||||
"clean": "rm -rf dist LICENSE",
|
||||
"build:npm": "tsdown",
|
||||
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
|
||||
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
|
||||
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/web-bluetooth": "npm:@types/web-bluetooth@^0.0.20"
|
||||
}
|
||||
|
||||
}
|
||||
145
packages/transport-web-bluetooth/src/transport.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import type { Types } from "@meshtastic/core";
|
||||
|
||||
export class TransportWebBluetooth implements Types.Transport {
|
||||
private _toDevice: WritableStream<Uint8Array>;
|
||||
private _fromDevice: ReadableStream<Types.DeviceOutput>;
|
||||
private _fromDeviceController?: ReadableStreamDefaultController<Types.DeviceOutput>;
|
||||
private _isFirstWrite = true;
|
||||
|
||||
private toRadioCharacteristic: BluetoothRemoteGATTCharacteristic;
|
||||
private fromRadioCharacteristic: BluetoothRemoteGATTCharacteristic;
|
||||
private fromNumCharacteristic: BluetoothRemoteGATTCharacteristic;
|
||||
private gattServer: BluetoothRemoteGATTServer;
|
||||
|
||||
static ToRadioUuid = "f75c76d2-129e-4dad-a1dd-7866124401e7";
|
||||
static FromRadioUuid = "2c55e69e-4993-11ed-b878-0242ac120002";
|
||||
static FromNumUuid = "ed9da18c-a800-4f66-a670-aa7547e34453";
|
||||
static ServiceUuid = "6ba1b218-15a8-461f-9fa8-5dcae273eafd";
|
||||
|
||||
public static async create(): Promise<TransportWebBluetooth> {
|
||||
const device = await navigator.bluetooth.requestDevice({
|
||||
filters: [{ services: [TransportWebBluetooth.ServiceUuid] }],
|
||||
});
|
||||
return await TransportWebBluetooth.prepareConnection(device);
|
||||
}
|
||||
|
||||
public static async createFromDevice(
|
||||
device: BluetoothDevice,
|
||||
): Promise<TransportWebBluetooth> {
|
||||
return await TransportWebBluetooth.prepareConnection(device);
|
||||
}
|
||||
|
||||
public static async prepareConnection(
|
||||
device: BluetoothDevice,
|
||||
): Promise<TransportWebBluetooth> {
|
||||
const gattServer = await device.gatt?.connect();
|
||||
|
||||
if (!gattServer) {
|
||||
throw new Error("Failed to connect to GATT server");
|
||||
}
|
||||
|
||||
const service = await gattServer.getPrimaryService(
|
||||
TransportWebBluetooth.ServiceUuid,
|
||||
);
|
||||
|
||||
const toRadioCharacteristic = await service.getCharacteristic(
|
||||
TransportWebBluetooth.ToRadioUuid,
|
||||
);
|
||||
const fromRadioCharacteristic = await service.getCharacteristic(
|
||||
TransportWebBluetooth.FromRadioUuid,
|
||||
);
|
||||
const fromNumCharacteristic = await service.getCharacteristic(
|
||||
TransportWebBluetooth.FromNumUuid,
|
||||
);
|
||||
|
||||
if (
|
||||
!toRadioCharacteristic ||
|
||||
!fromRadioCharacteristic ||
|
||||
!fromNumCharacteristic
|
||||
) {
|
||||
throw new Error("Failed to find required characteristics");
|
||||
}
|
||||
|
||||
console.log("Connected to device", device.name);
|
||||
|
||||
return new TransportWebBluetooth(
|
||||
toRadioCharacteristic,
|
||||
fromRadioCharacteristic,
|
||||
fromNumCharacteristic,
|
||||
gattServer,
|
||||
);
|
||||
}
|
||||
|
||||
constructor(
|
||||
toRadioCharacteristic: BluetoothRemoteGATTCharacteristic,
|
||||
fromRadioCharacteristic: BluetoothRemoteGATTCharacteristic,
|
||||
fromNumCharacteristic: BluetoothRemoteGATTCharacteristic,
|
||||
gattServer: BluetoothRemoteGATTServer,
|
||||
) {
|
||||
this.toRadioCharacteristic = toRadioCharacteristic;
|
||||
this.fromRadioCharacteristic = fromRadioCharacteristic;
|
||||
this.fromNumCharacteristic = fromNumCharacteristic;
|
||||
this.gattServer = gattServer;
|
||||
|
||||
this._fromDevice = new ReadableStream({
|
||||
start: (ctrl) => {
|
||||
this._fromDeviceController = ctrl;
|
||||
},
|
||||
});
|
||||
|
||||
this._toDevice = new WritableStream({
|
||||
write: async (chunk) => {
|
||||
await this.toRadioCharacteristic.writeValue(chunk);
|
||||
|
||||
if (this._isFirstWrite && this._fromDeviceController) {
|
||||
this._isFirstWrite = false;
|
||||
|
||||
setTimeout(() => {
|
||||
this.readFromRadio(this._fromDeviceController!);
|
||||
}, 50);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.fromNumCharacteristic.addEventListener(
|
||||
"characteristicvaluechanged",
|
||||
() => {
|
||||
if (this._fromDeviceController) {
|
||||
this.readFromRadio(this._fromDeviceController);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
this.fromNumCharacteristic.startNotifications();
|
||||
}
|
||||
|
||||
get toDevice(): WritableStream<Uint8Array> {
|
||||
return this._toDevice;
|
||||
}
|
||||
|
||||
get fromDevice(): ReadableStream<Types.DeviceOutput> {
|
||||
return this._fromDevice;
|
||||
}
|
||||
|
||||
protected async readFromRadio(
|
||||
controller: ReadableStreamDefaultController<Types.DeviceOutput>,
|
||||
): Promise<void> {
|
||||
let hasMoreData = true;
|
||||
while (hasMoreData && this.fromRadioCharacteristic) {
|
||||
const value = await this.fromRadioCharacteristic.readValue();
|
||||
if (value.byteLength === 0) {
|
||||
hasMoreData = false;
|
||||
continue;
|
||||
}
|
||||
controller.enqueue({
|
||||
type: "packet",
|
||||
data: new Uint8Array(value.buffer),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
disconnect(): Promise<void> {
|
||||
this.gattServer.disconnect();
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
19
packages/transport-web-bluetooth/tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"target": "ES2020",
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"moduleResolution": "bundler",
|
||||
"emitDeclarationOnly": false,
|
||||
"esModuleInterop": true,
|
||||
"types": ["@types/web-bluetooth"],
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
35
packages/transport-web-serial/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# @meshtastic/transport-web-serial
|
||||
|
||||
[](https://jsr.io/@meshtastic/transport-web-serial)
|
||||
[](https://github.com/meshtastic/js/actions/workflows/ci.yml)
|
||||
[](https://cla-assistant.io/meshtastic/meshtastic.js)
|
||||
[](https://opencollective.com/meshtastic/)
|
||||
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||
|
||||
## Overview
|
||||
|
||||
`@meshtastic/transport-web-serial` Provides Web Serial transport for Meshtastic
|
||||
devices. Installation instructions are avaliable at
|
||||
[JSR](https://jsr.io/@meshtastic/transport-web-serial)
|
||||
[NPM](https://www.npmjs.com/package/@meshtastic/transport-web-serial)
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { MeshDevice } from "@meshtastic/core";
|
||||
import { TransportWebSerial } from "@meshtastic/transport-web-serial";
|
||||
|
||||
const transport = await TransportWebSerial.create();
|
||||
const device = new MeshDevice(transport);
|
||||
```
|
||||
|
||||
## Stats
|
||||
|
||||

|
||||
|
||||
### Compatibility
|
||||
|
||||
The Web Serial API's have limited support in browsers, compatibility is
|
||||
represented in the matrix below.
|
||||
|
||||

|
||||
1
packages/transport-web-serial/mod.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { TransportWebSerial } from "./src/transport.ts";
|
||||
32
packages/transport-web-serial/package.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "@meshtastic/transport-web-serial",
|
||||
"version": "0.2.3",
|
||||
"description": "A transport layer for Meshtastic applications using Web Serial API.",
|
||||
"exports": {
|
||||
".": "./mod.ts"
|
||||
},
|
||||
"main": "./dist/mod.mjs",
|
||||
"module": "./dist/mod.mjs",
|
||||
"types": "./dist/mod.d.mts",
|
||||
"files": ["dist/*", "mod.ts", "README.md", "../../LICENSE"],
|
||||
"license": "GPL-3.0-only",
|
||||
"tsdown": {
|
||||
"entry": ["mod.ts"],
|
||||
"dts": true,
|
||||
"format": ["esm"],
|
||||
"splitting": false,
|
||||
"clean": true
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"prepack": "cp ../../LICENSE ./LICENSE",
|
||||
"clean": "rm -rf dist LICENSE",
|
||||
"build:npm": "tsdown",
|
||||
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
|
||||
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
|
||||
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/w3c-web-serial": "npm:@types/w3c-web-serial@^1.0.7"
|
||||
}
|
||||
}
|
||||
49
packages/transport-web-serial/src/transport.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import type { Types } from "@meshtastic/core";
|
||||
import { Utils } from "@meshtastic/core";
|
||||
|
||||
export class TransportWebSerial implements Types.Transport {
|
||||
private _toDevice: WritableStream<Uint8Array>;
|
||||
private _fromDevice: ReadableStream<Types.DeviceOutput>;
|
||||
private connection: SerialPort;
|
||||
|
||||
public static async create(baudRate?: number): Promise<TransportWebSerial> {
|
||||
const port = await navigator.serial.requestPort();
|
||||
await port.open({ baudRate: baudRate || 115200 });
|
||||
return new TransportWebSerial(port);
|
||||
}
|
||||
|
||||
public static async createFromPort(
|
||||
port: SerialPort,
|
||||
baudRate?: number,
|
||||
): Promise<TransportWebSerial> {
|
||||
await port.open({ baudRate: baudRate || 115200 });
|
||||
return new TransportWebSerial(port);
|
||||
}
|
||||
|
||||
constructor(connection: SerialPort) {
|
||||
if (!connection.readable || !connection.writable) {
|
||||
throw new Error("Stream not accessible");
|
||||
}
|
||||
|
||||
this.connection = connection;
|
||||
|
||||
Utils.toDeviceStream.readable.pipeTo(connection.writable);
|
||||
|
||||
this._toDevice = Utils.toDeviceStream.writable;
|
||||
this._fromDevice = connection.readable.pipeThrough(
|
||||
Utils.fromDeviceStream(),
|
||||
);
|
||||
}
|
||||
|
||||
get toDevice(): WritableStream<Uint8Array> {
|
||||
return this._toDevice;
|
||||
}
|
||||
|
||||
get fromDevice(): ReadableStream<Types.DeviceOutput> {
|
||||
return this._fromDevice;
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
return this.connection.close();
|
||||
}
|
||||
}
|
||||
19
packages/transport-web-serial/tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"target": "ES2020",
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"moduleResolution": "bundler",
|
||||
"emitDeclarationOnly": false,
|
||||
"esModuleInterop": true,
|
||||
"types": ["@types/w3c-web-serial"],
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1
packages/web/.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
@jsr:registry=https://npm.jsr.io
|
||||
111
packages/web/CONTRIBUTING_I18N_DEVELOPER_GUIDE.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# i18n Developer Guide
|
||||
|
||||
When developing new components, all user-facing text must be added as an i18n
|
||||
key and rendered using our translation functions. This ensures your UI can be
|
||||
translated into multiple languages.
|
||||
|
||||
## Adding New i18n Keys
|
||||
|
||||
### Search Before Creating
|
||||
|
||||
Before adding a new key, please perform a quick search to see if one that fits
|
||||
your needs already exists. Many common labels like "Save," "Cancel," "Name,"
|
||||
"Description," "Loading...," or "Error" are likely already present, especially
|
||||
in the common.json namespace. Reusing existing keys prevents duplication and
|
||||
ensures consistency across the application. Using your code editor's search
|
||||
function across the /i18n/locales/en/ directory is an effective way to do this.
|
||||
|
||||
### Key Naming and Structure Rules
|
||||
|
||||
To maintain consistency and ease of use, please adhere to the following rules
|
||||
when creating new keys in the JSON files.
|
||||
|
||||
- **Keys are camelCase:** `exampleKey`, `anotherExampleKey`.
|
||||
- **Avoid Deep Nesting:** One or two levels of nesting are acceptable for
|
||||
grouping related keys (e.g., all labels for a specific menu). However, nesting
|
||||
deeper than two levels should be avoided to maintain readability and ease of
|
||||
use.
|
||||
- **Good (1 level):**
|
||||
```json
|
||||
"buttons": {
|
||||
"save": "Save",
|
||||
"cancel": "Cancel"
|
||||
}
|
||||
```
|
||||
- **Acceptable (2 levels):**
|
||||
```json
|
||||
"userMenu": {
|
||||
"items": {
|
||||
"profile": "Profile",
|
||||
"settings": "Settings"
|
||||
}
|
||||
}
|
||||
```
|
||||
- **Avoid (3+ levels):**
|
||||
```json
|
||||
"userMenu": {
|
||||
"items": {
|
||||
"actions": {
|
||||
"viewProfile": "View Profile"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
- **Organize for Retrieval, Not UI Layout:** Keys should be named logically for
|
||||
easy retrieval, not to mirror the layout of your component.
|
||||
|
||||
### Namespace Rules
|
||||
|
||||
We use namespaces to organize keys. All source keys are added to the English
|
||||
(`en`) files located at `/packages/web/public/i18n/locales/en/`. Place your new keys in the
|
||||
appropriate file based on these rules:
|
||||
|
||||
- `common.json`:
|
||||
- All button labels (`save`, `cancel`, `submit`, etc.).
|
||||
- Any text that is repeated and used throughout the application (e.g.,
|
||||
"Loading...", "Error").
|
||||
- `ui.json`:
|
||||
- Labels and text specific to a distinct UI element or view that isn't a
|
||||
dialog or a config page.
|
||||
- `dialog.json`:
|
||||
- All text specific to modal dialogs (titles, body text, prompts).
|
||||
- `messages.json`:
|
||||
- Text specifically related to the messaging interface.
|
||||
- `deviceConfig.json` & `moduleConfig.json`:
|
||||
- Labels and descriptions for the settings on the Device and Module
|
||||
configuration pages.
|
||||
|
||||
## Using i18n Keys in Components
|
||||
|
||||
We use the `useTranslation` hook from `react-i18next` to access the translation
|
||||
function, `t`.
|
||||
|
||||
### Default Namespaces
|
||||
|
||||
Our i18next configuration has fallback namespaces configured which includes
|
||||
`common`, `ui`, and `dialog`. This means you **do not** need to explicitly
|
||||
specify these namespaces when calling the hook. The system will automatically
|
||||
check these files for your key.
|
||||
|
||||
For any keys in `common.json`, `ui.json`, or `dialog.json`, you can instantiate
|
||||
the hook simply:
|
||||
|
||||
```typescript
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
// In your component
|
||||
const { t } = useTranslation(["messages"]);
|
||||
|
||||
// Usage
|
||||
return <p>{t("someMessageLabel")}</p>;
|
||||
```
|
||||
|
||||
You can also specify the namespace on a per-call basis using the options object.
|
||||
This is useful if a component primarily uses a default namespace but needs a
|
||||
single key from another.
|
||||
|
||||
```typescript
|
||||
const { t } = useTranslation();
|
||||
|
||||
return <p>{t("someMessageLabel", { ns: "messages" })}</p>;
|
||||
```
|
||||
31
packages/web/CONTRIBUTING_TRANSLATIONS.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Contributing Translations
|
||||
|
||||
Thank you for your interest in making the Meshtastic Web Client accessible to a
|
||||
global audience! Your translation efforts are greatly appreciated.
|
||||
|
||||
## Our Translation Platform: Crowdin
|
||||
|
||||
We manage all our translations through a platform called
|
||||
[Crowdin](https://crowdin.com/). This allows for a collaborative and streamlined
|
||||
translation process. All translation work should be done on our Crowdin project,
|
||||
not directly in the code repository via Pull Requests.
|
||||
|
||||
### How to Get Started
|
||||
|
||||
1. **Create a Crowdin Account:** If you don't already have one, sign up for a
|
||||
free account on Crowdin.
|
||||
2. **Join Our Project:** Please ask for a link to our specific Crowdin project
|
||||
on the Meshtastic Discord.
|
||||
3. **Request Translator Role:** Once you have an account, join the Meshtastic
|
||||
Discord and notify an admin in the `#web` channel. They will grant you the
|
||||
necessary permissions to start translating.
|
||||
4. **Start Translating:** Once you have your role, you can begin translating the
|
||||
source labels into your native language directly on the Crowdin platform.
|
||||
|
||||
### Language Activation
|
||||
|
||||
A new language will only be added to the web client and appear in the language
|
||||
picker once its translation is 100% complete on Crowdin. The repository
|
||||
maintainers will handle this process once the milestone is reached.
|
||||
|
||||
Thank you for helping us bring Meshtastic to more users around the world!
|
||||
156
packages/web/README.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# Meshtastic Web
|
||||
|
||||
<!--Project specific badges here-->
|
||||
|
||||
[](https://github.com/meshtastic/web/actions/workflows/ci.yml)
|
||||
[](https://cla-assistant.io/meshtastic/web)
|
||||
[](https://opencollective.com/meshtastic/)
|
||||
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||
|
||||
## Overview
|
||||
|
||||
Official [Meshtastic](https://meshtastic.org) web interface, that can be hosted
|
||||
or served from a node
|
||||
|
||||
**[Hosted version](https://client.meshtastic.org)**
|
||||
|
||||
## Stats
|
||||
|
||||

|
||||
|
||||
## Self-host
|
||||
|
||||
The client can be self hosted using the precompiled container images with an OCI
|
||||
compatible runtime such as [Docker](https://www.docker.com/) or
|
||||
[Podman](https://podman.io/). The base image used is
|
||||
[Nginx 1.27](https://hub.docker.com/_/nginx)
|
||||
|
||||
```bash
|
||||
# With Docker
|
||||
docker run -d -p 8080:8080 --restart always --name Meshtastic-Web ghcr.io/meshtastic/web
|
||||
|
||||
#With Podman
|
||||
podman run -d -p 8080:8080 --restart always --name Meshtastic-Web ghcr.io/meshtastic/web
|
||||
```
|
||||
|
||||
## Release Schedule
|
||||
|
||||
Our release process follows these guidelines:
|
||||
|
||||
- **Versioning:** We use Semantic Versioning (`Major.Minor.Patch`).
|
||||
- **Stable Releases:** Published around the beginning of each month (e.g.,
|
||||
`v2.6.1`).
|
||||
- **Pre-releases:** A pre-release is typically issued mid-month for testing and
|
||||
early adoption.
|
||||
- **Nightly Builds:** An experimental Docker image containing the latest
|
||||
cutting-edge features and fixes is automatically built nightly from the `main`
|
||||
branch.
|
||||
|
||||
### Nightly Builds
|
||||
|
||||
```bash
|
||||
# With Docker
|
||||
docker run -d -p 8080:8080 --restart always --name Meshtastic-Web ghcr.io/meshtastic/web:nightly
|
||||
#With Podman
|
||||
podman run -d -p 8080:8080 --restart always --name Meshtastic-Web ghcr.io/meshtastic/web:nightly
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
>
|
||||
> - Nightly builds represent the latest development state and may contain
|
||||
> breaking changes
|
||||
> - These builds undergo automated testing but may be less stable than tagged
|
||||
> release versions
|
||||
> - Not recommended for production environments unless you are actively testing
|
||||
> new features
|
||||
> - No guarantee of backward compatibility between nightly builds
|
||||
|
||||
#### Version Information
|
||||
|
||||
Each nightly build is tagged with:
|
||||
|
||||
- The nightly tag for the latest build
|
||||
- A specific SHA for build reproducibility
|
||||
|
||||
### Feedback
|
||||
|
||||
If you encounter any issues with nightly builds, please report them in our
|
||||
[issues tracker](https://github.com/meshtastic/web/issues). Your feedback helps
|
||||
improve the stability of future releases
|
||||
|
||||
## Development & Building
|
||||
|
||||
You'll need to download the package manager used with this repo. You can install
|
||||
it by visiting [pnpm.io](https://pnpm.io/) and following the installation
|
||||
instructions listed on the home page.
|
||||
|
||||
### Development
|
||||
|
||||
Install the dependencies.
|
||||
|
||||
```bash
|
||||
cd packages/web &&
|
||||
pnpm install
|
||||
```
|
||||
|
||||
Start the development server:
|
||||
|
||||
```bash
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
### Building and Packaging
|
||||
|
||||
Build the project:
|
||||
|
||||
```bash
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
GZip the output:
|
||||
|
||||
```bash
|
||||
pnpm run package
|
||||
```
|
||||
|
||||
### Why pnpm?
|
||||
|
||||
Meshtastic Web uses pnpm as its package manager for several compelling
|
||||
reasons:
|
||||
|
||||
- **Efficient Storage**: pnpm uses content-addressable storage, avoiding duplication
|
||||
of packages across projects and saving significant disk space.
|
||||
- **Fast Performance**: Faster package installation compared to other package
|
||||
managers through symlinks and efficient dependency resolution.
|
||||
- **Strict Dependency Management**: Prevents access to unlisted dependencies,
|
||||
ensuring better project reliability and security.
|
||||
- **Workspace Support**: Excellent monorepo support with workspaces for managing
|
||||
multiple packages efficiently.
|
||||
- **Reproducible Builds**: Lockfile ensures consistent builds across all
|
||||
environments.
|
||||
|
||||
### Contributing
|
||||
|
||||
We welcome contributions! Here’s how the deployment flow works for pull
|
||||
requests:
|
||||
|
||||
- **Preview Deployments:**\
|
||||
Every pull request automatically generates a preview deployment on Vercel.
|
||||
This allows you and reviewers to easily preview changes before merging.
|
||||
|
||||
- **Staging Environment (`client-test`):**\
|
||||
Once your PR is merged, your changes will be available on our staging site:
|
||||
[client-test.meshtastic.org](https://client-test.meshtastic.org/).\
|
||||
This environment supports rapid feature iteration and testing without
|
||||
impacting the production site.
|
||||
|
||||
- **Production Releases:**\
|
||||
At regular intervals, stable and fully tested releases are promoted to our
|
||||
production site: [client.meshtastic.org](https://client.meshtastic.org/).\
|
||||
This is the primary interface used by the public to connect with their
|
||||
Meshtastic nodes.
|
||||
|
||||
Please review our
|
||||
[Contribution Guidelines](https://github.com/meshtastic/web/blob/main/CONTRIBUTING.md)
|
||||
before submitting a pull request. We appreciate your help in making the project
|
||||
better!
|
||||
10
packages/web/crowdin.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
project_id_env: CROWDIN_PROJECT_ID
|
||||
api_token_env: CROWDIN_PERSONAL_TOKEN
|
||||
base_path: "."
|
||||
base_url: "https://meshtastic.crowdin.com/api/v2"
|
||||
|
||||
preserve_hierarchy: true
|
||||
|
||||
files:
|
||||
- source: "/public/i18n/locales/en/*.json"
|
||||
translation: "/public/i18n/locales/%locale%/%original_file_name%"
|
||||
@@ -1,25 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="en" data-theme="system">
|
||||
<head>
|
||||
<!-- CookieYes banner -->
|
||||
<%- cookieYesScript %>
|
||||
<!-- End of CookieYes banner -->
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180" />
|
||||
|
||||
<link rel="manifest" href="site.webmanifest" />
|
||||
<link rel="mask-icon" href="Logo_Black.svg" color="#67ea94" />
|
||||
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
|
||||
<link rel="mask-icon" href="logo_black.svg" color="#67ea94" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://rsms.me/inter/inter.css"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@xz/fonts@1/serve/cascadia-code.min.css"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="src/index.css"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<meta name="theme-color" content="#67ea94" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0"
|
||||
/>
|
||||
<meta name="description" content="Meshtastic Web App" />
|
||||
<title>Meshtastic Web</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="Meshtastic Web Client" />
|
||||
<title><%- title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
2
packages/web/infra/.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
||||
../dist/build.tar
|
||||
../dist/output
|
||||
15
packages/web/infra/Containerfile
Normal file
@@ -0,0 +1,15 @@
|
||||
FROM nginx:1.27-alpine
|
||||
|
||||
RUN rm -r /usr/share/nginx/html \
|
||||
&& mkdir -p /usr/share/nginx/html \
|
||||
&& mkdir -p /etc/nginx/conf.d
|
||||
|
||||
WORKDIR /usr/share/nginx/html
|
||||
|
||||
ADD dist .
|
||||
|
||||
COPY ./infra/default.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
42
packages/web/infra/default.conf
Normal file
@@ -0,0 +1,42 @@
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
internal;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
|
||||
gzip on;
|
||||
gzip_disable "msie6";
|
||||
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_buffers 16 8k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/x-javascript
|
||||
application/json
|
||||
application/xml
|
||||
application/xml+rss
|
||||
font/ttf
|
||||
font/otf
|
||||
image/svg+xml;
|
||||
}
|
||||
112
packages/web/package.json
Normal file
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"name": "meshtastic-web",
|
||||
"version": "2.7.0-0",
|
||||
"type": "module",
|
||||
"description": "Meshtastic web client",
|
||||
"license": "GPL-3.0-only",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/meshtastic/web.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/meshtastic/web/issues"
|
||||
},
|
||||
"homepage": "https://meshtastic.org",
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"build": "vite build",
|
||||
"build:analyze": "BUNDLE_ANALYZE=true bun run build",
|
||||
"check": "biome check src/",
|
||||
"check:fix": "biome check --write src/",
|
||||
"dev": "vite",
|
||||
"test": "vitest",
|
||||
"ts:check": "bun run tsc --noEmit",
|
||||
"preview": "vite preview",
|
||||
"generate:routes": "bun @tanstack/router-cli generate --outDir src/ routes --rootRoutePath /",
|
||||
"package": "gzipper c -i html,js,css,png,ico,svg,json,webmanifest,txt dist dist/output && tar -cvf dist/build.tar -C ./dist/output/ ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@bufbuild/protobuf": "^2.6.0",
|
||||
"@hookform/resolvers": "^5.1.1",
|
||||
"@meshtastic/core": "workspace:*",
|
||||
"@meshtastic/transport-http": "npm:@jsr/meshtastic__transport-http",
|
||||
"@meshtastic/transport-web-bluetooth": "npm:@jsr/meshtastic__transport-web-bluetooth",
|
||||
"@meshtastic/transport-web-serial": "npm:@jsr/meshtastic__transport-web-serial",
|
||||
"@noble/curves": "^1.9.2",
|
||||
"@radix-ui/react-accordion": "^1.2.11",
|
||||
"@radix-ui/react-checkbox": "^1.3.2",
|
||||
"@radix-ui/react-dialog": "^1.1.14",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-menubar": "^1.1.15",
|
||||
"@radix-ui/react-popover": "^1.1.14",
|
||||
"@radix-ui/react-scroll-area": "^1.2.9",
|
||||
"@radix-ui/react-select": "^2.2.5",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@radix-ui/react-slider": "^1.3.5",
|
||||
"@radix-ui/react-switch": "^1.2.5",
|
||||
"@radix-ui/react-tabs": "^1.1.12",
|
||||
"@radix-ui/react-toast": "^1.2.14",
|
||||
"@radix-ui/react-toggle-group": "^1.1.10",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@radix-ui/react-visually-hidden": "^1.2.3",
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"@tanstack/react-router": "^1.127.9",
|
||||
"@tanstack/react-router-devtools": "^1.127.9",
|
||||
"@tanstack/router-cli": "^1.127.8",
|
||||
"@tanstack/router-devtools": "^1.127.9",
|
||||
"@turf/turf": "^7.2.0",
|
||||
"@types/node": "^24.0.14",
|
||||
"@types/web-bluetooth": "^0.0.21",
|
||||
"base64-js": "^1.5.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"crypto-random-string": "^5.0.0",
|
||||
"i18next": "^25.3.2",
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
"idb-keyval": "^6.2.2",
|
||||
"immer": "^10.1.1",
|
||||
"js-cookie": "^3.0.5",
|
||||
"lucide-react": "^0.525.0",
|
||||
"maplibre-gl": "5.6.1",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-error-boundary": "^6.0.0",
|
||||
"react-hook-form": "^7.60.0",
|
||||
"react-i18next": "^15.6.0",
|
||||
"react-map-gl": "8.0.4",
|
||||
"react-qrcode-logo": "^3.0.0",
|
||||
"rfc4648": "^1.5.4",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vite": "^7.0.4",
|
||||
"zod": "^4.0.5",
|
||||
"zustand": "5.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.0.6",
|
||||
"@tanstack/router-plugin": "^1.127.9",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/chrome": "^0.1.0",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/react": "^19.1.8",
|
||||
"@types/react-dom": "^19.1.6",
|
||||
"@types/serviceworker": "^0.0.142",
|
||||
"@types/w3c-web-serial": "^1.0.8",
|
||||
"@vitejs/plugin-react": "^4.6.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"gzipper": "^8.2.1",
|
||||
"happy-dom": "^18.0.1",
|
||||
"simple-git-hooks": "^2.13.0",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tar": "^7.4.3",
|
||||
"testing-library": "^0.0.2",
|
||||
"typescript": "^5.8.3",
|
||||
"vitest": "^3.2.4"
|
||||
}
|
||||
}
|
||||
41
packages/web/public/Logo.svg
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 512 512"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<desc>Created with Fabric.js 4.6.0</desc>
|
||||
<defs> </defs>
|
||||
<g transform="matrix(1 0 0 1 256 256)" id="xYQ9Gk9Jwpgj_HMOXB3F_">
|
||||
<path
|
||||
style="stroke: rgb(213, 130, 139); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(103, 234, 148); fill-rule: nonzero; opacity: 1"
|
||||
vector-effect="non-scaling-stroke"
|
||||
transform=" translate(-256, -256)"
|
||||
d="M 0 0 L 512 0 L 512 512 L 0 512 z"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1.79 0 0 1.79 313.74 258.36)" id="1xBsk2n9FZp60Rz1O-ceJ">
|
||||
<path
|
||||
style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: round; stroke-miterlimit: 2; fill: rgb(44, 45, 60); fill-rule: evenodd; opacity: 1"
|
||||
vector-effect="non-scaling-stroke"
|
||||
transform=" translate(-250.97, -362.41)"
|
||||
d="M 250.908 330.267 L 193.126 415.005 L 180.938 406.694 L 244.802 313.037 C 246.174 311.024 248.453 309.819 250.889 309.816 C 253.326 309.814 255.606 311.015 256.982 313.026 L 320.994 406.536 L 308.821 414.869 L 250.908 330.267 Z"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1.81 0 0 1.81 145 256.15)" id="KxN7E9YpbyPgz0S4z4Cl6">
|
||||
<path
|
||||
style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: round; stroke-miterlimit: 2; fill: rgb(44, 45, 60); fill-rule: evenodd; opacity: 1"
|
||||
vector-effect="non-scaling-stroke"
|
||||
transform=" translate(-115.14, -528.06)"
|
||||
d="M 87.642 581.398 L 154.757 482.977 L 142.638 474.713 L 75.523 573.134 L 87.642 581.398 Z"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
26
packages/web/public/Logo_Black.svg
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 100 55"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:space="preserve"
|
||||
xmlns:serif="http://www.serif.com/"
|
||||
style="fill-rule: evenodd; clip-rule: evenodd; stroke-linejoin: round; stroke-miterlimit: 2"
|
||||
>
|
||||
<g transform="matrix(0.802386,0,0,0.460028,-421.748,-122.127)">
|
||||
<g transform="matrix(0.579082,0,0,1.01004,460.975,-39.6867)">
|
||||
<path
|
||||
d="M250.908,330.267L193.126,415.005L180.938,406.694L244.802,313.037C246.174,311.024 248.453,309.819 250.889,309.816C253.326,309.814 255.606,311.015 256.982,313.026L320.994,406.536L308.821,414.869L250.908,330.267Z"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(0.582378,0,0,1.01579,485.019,-211.182)">
|
||||
<path
|
||||
d="M87.642,581.398L154.757,482.977L142.638,474.713L75.523,573.134L87.642,581.398Z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
28
packages/web/public/Logo_White.svg
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 100 55"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:space="preserve"
|
||||
xmlns:serif="http://www.serif.com/"
|
||||
style="fill-rule: evenodd; clip-rule: evenodd; stroke-linejoin: round; stroke-miterlimit: 2"
|
||||
>
|
||||
<g transform="matrix(0.802386,0,0,0.460028,-421.748,-122.127)">
|
||||
<g transform="matrix(0.579082,0,0,1.01004,460.975,-39.6867)">
|
||||
<path
|
||||
d="M250.908,330.267L193.126,415.005L180.938,406.694L244.802,313.037C246.174,311.024 248.453,309.819 250.889,309.816C253.326,309.814 255.606,311.015 256.982,313.026L320.994,406.536L308.821,414.869L250.908,330.267Z"
|
||||
style="fill: white"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(0.582378,0,0,1.01579,485.019,-211.182)">
|
||||
<path
|
||||
d="M87.642,581.398L154.757,482.977L142.638,474.713L75.523,573.134L87.642,581.398Z"
|
||||
style="fill: white"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
64
packages/web/public/chirpy.svg
Normal file
@@ -0,0 +1,64 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="Layer_1"
|
||||
data-name="Layer 1"
|
||||
viewBox="0 0 1871.69 2607.94"
|
||||
>
|
||||
<defs><style>
|
||||
.cls-1, .cls-4 {
|
||||
fill: #2c2d3c;
|
||||
stroke-width: 0;
|
||||
}
|
||||
.cls-4 {
|
||||
fill: #fff;
|
||||
}
|
||||
</style></defs><path
|
||||
id="Body_background"
|
||||
fill="#67ea94"
|
||||
stroke-width="0"
|
||||
d="M1349.07 573.19h-855.5c-11.05 0-20.01 8.96-20.01 20.01v1219.19c0 10.12 8.21 18.33 18.33 18.33h854.27c8.7 0 15.75-7.05 15.75-15.75V586.04c0-7.1-5.75-12.85-12.85-12.85Zm-220.55 569.8h-411V787h411v355.99Z"
|
||||
data-name="Body background"
|
||||
/><path
|
||||
id="Body"
|
||||
d="M1166.62 5.54c-21.2 13.2-31.7 24.3-34.1 36-2.2 10.6-1.8 11.4 13.6 26.9 7.7 7.6 15.3 15.7 17.1 18l3.2 4.1-13.7 5.8c-26.6 11.4-109.5 54-125.2 64.4-4.6 3-5.5 4.1-5.5 6.5 0 3.5 2.7 5.6 5.1 4.1 1.3-.8 2.9-.5 6.4 1.2 9.4 4.5 34.3 10.5 59 14.3 6.9 1.1 27.6 3.3 46 5 49.1 4.5 71 8 71 11.5 0 2.2-21.1 23.5-37.5 38-8.2 7.2-24.4 20.9-36 30.5-29 24-42.2 35.9-62 56.1-27.2 27.7-54.4 60.8-60.9 74.1-2.5 5-2.7 6.1-1.7 9.1.7 1.9 8.9 12.6 18.4 23.9 9.5 11.2 24.2 29.2 32.8 39.9 30.8 38.2 48.3 56.9 75.2 80.4l13.7 12-118.2.6c-65.1.3-203.8.7-308.4.8-182.2.3-221.1.8-237.2 3.1-11.6 1.6-16.2 4.8-18.1 12.7-.9 3.3-1.3 130.7-1.6 479.6-.3 261.4-.7 530.3-.9 597.7-.5 142.7-.1 152.6 6.6 163.8 2.6 4.2 6.9 6.4 13.7 6.8 3.1.2 55 .6 115.4 1 99.7.6 109.7.8 109.7 2.3.2 11.7-9.3 741.7-9.6 742-.2.3-75.5-1.9-167.2-4.8-158.1-4.9-167.1-5.1-171-3.5-11.6 4.6-12.2 20.8-1 26.3 4.1 1.9 10.2 2.2 165.3 7.1 88.6 2.8 168.2 5.1 177 5.1h16l4.7-5.3c2.6-2.9 5.2-6.2 5.7-7.3.7-1.5 10.4-722.4 10.1-757.4v-4.4l159.2.7c87.6.4 159.3.8 159.4.9 0 .1 2.7 169.2 5.9 375.7l5.7 375.5 3 6c1.6 3.3 4.2 7.6 5.8 9.5l2.9 3.5 167.8-.3c158.5-.4 168-.5 171.9-2.2 11.2-4.9 12.1-19.9 1.5-25.8l-3.9-2.2h-318.7l-.3-7.7c-.3-10.8-11.2-710.5-11.2-722.6v-9.7h121.8c85.3.1 123.8-.2 128.7-1 12.4-2 18.1-6.1 21.9-15.8 1.5-4 1.6-46.7 1.6-608.5 0-332.3-.3-610.5-.6-618.2-.7-15.7-1.6-20-4.7-21.8-1.7-.9-24.6-1.3-101.2-1.5l-99-.2-3-3.4c-1.6-1.9-9.1-8.8-16.5-15.4-24.3-21.5-43.4-42.2-71.5-77.2-8.2-10.2-21.9-26.8-30.5-37-8.5-10.2-16.8-20-18.3-21.9-3.4-4.1-3.2-5.1 3.8-15.6 11.1-16.9 35.8-45.8 59-69 16.8-16.9 30.6-29.2 57-51 36-29.7 54.9-46.8 67.7-60.9 8.5-9.4 8.9-10.1 8.6-14-.3-3.8-.7-4.3-5-6.4-8-4-29.7-7.2-76.3-11.2-36.5-3.1-62.7-7.4-84.3-13.6-8.9-2.6-17.8-6.1-17.1-6.8 1.4-1.3 31.8-17.6 56.9-30.4 31.9-16.3 56.3-27.9 73.3-34.8l10.7-4.5 6.3 5.2c11.6 9.7 23.7 13.6 38.1 12.1 8.3-.8 10-2.6 11.7-11.7 2.1-11.2-.9-22.9-12-47.4-9.8-21.7-19.8-36.9-31.4-47.9-7.3-6.8-8.8-6.8-20.6.5Zm190.1 570.1c1.1 1.1 1.3 114 1.6 619.5l.2 618.3-2.2 4.4c-3.2 6.3-8.1 8.7-19.8 10-9.2.9-48.7.8-618.5-.9-254.3-.8-236.4-.3-239.4-6.6-3.2-6.6-4.2-16-4.7-44-.2-15.4 0-283.4.4-595.5.5-312.1.5-569.2 0-571.3-.9-4.2.5-18.4 2.5-24.5 1-3.2 1.9-3.9 6.3-5.4 10.9-3.6 32.3-3.9 396.9-4.7 448.7-1 475-1 476.7.7Z"
|
||||
class="cls-1"
|
||||
/><path d="M717.52 787h411v355.99h-411z" class="cls-4" /><path
|
||||
id="Dot"
|
||||
fill="#454656"
|
||||
stroke="#2c2d3c"
|
||||
stroke-miterlimit="10"
|
||||
stroke-width="7"
|
||||
d="M1246.61 622.56c-10.79 3.78-18.53 10.79-23.69 21.39-2.77 5.62-2.95 6.45-2.95 16.59s.18 10.97 2.95 16.87c7.56 15.86 22.03 24.34 40.29 23.51 7.38-.28 9.31-.74 15.58-3.69 8.67-4.15 15.4-10.6 18.99-18.25 9.96-21.02 1.94-43.79-19.18-54.21-6.55-3.23-7.47-3.41-17.06-3.69-8.02-.18-11.25.18-14.94 1.48Z"
|
||||
/><path
|
||||
id="Eyes"
|
||||
d="M651.62 705.94c-8 1.6-10.3 5.2-12 19.4-1.4 12-1.8 452.5-.4 459.2 1.4 6.4 2.7 8.9 5.7 10.8 2.1 1.4 31.7 1.6 275.1 1.5 150 0 275.3-.3 278.4-.6 6.8-.7 9.6-1.9 10.7-4.8.5-1.1.7-106.1.4-235.6-.6-263.8.3-239.2-8.5-243.1-5.2-2.3-17.1-5-23-5.1-8-.3-489.4-2.8-505.5-2.7-9.1.1-18.5.5-20.9 1Zm186.5 82c6.5 1.2 8.4 2.3 8.4 4.9s-2.3 3.1-11.3 1.8c-12.3-1.6-35.6-.4-50.4 2.7-14.5 3-33.7 9.1-43.7 13.9-7.3 3.5-16.6 10-16.6 11.6 0 .5 1.7 1 3.8 1.2 3.2.3 3.7.6 3.7 2.8s-.4 2.5-5.8 2.8c-7 .4-8.7-.8-8.7-5.6 0-10.9 30.8-26.7 65.5-33.7 6.6-1.3 13.6-2.6 15.5-2.8 7.9-.9 34-.6 39.6.4Zm224.9 3.3c35.7 7.5 65.5 22.9 65.5 33.8 0 4.8-1.7 6-8.7 5.6-5.4-.3-5.8-.5-5.8-2.8s.5-2.5 3.8-2.8c2-.2 3.7-.7 3.7-1.2 0-1.6-9.3-8.1-16.6-11.6-10-4.8-29.2-10.9-43.7-13.9-14.8-3.1-38.1-4.3-50.4-2.7-9 1.3-11.3.9-11.3-1.8 0-4.7 7.5-6 32-5.5 16.1.3 21.6.8 31.5 2.9Zm-238.5 58.4c4.6 2.3 5.9 3.6 8.4 8.4 3.2 6.3 3.7 10.2 5.6 42.3.6 9.9 1.5 26.3 2.1 36.5 1.2 20.5.5 96.3-1.1 122.6-3.3 53.9-5 74.5-6.1 76.6-.5 1-1.6 1.8-2.5 1.8-.8 0-4.1.9-7.3 2-17.1 5.7-43.2-.5-50.3-12-6-9.7-7.6-27-8.8-97-.5-27.2-1.4-56.5-2.2-65-.7-8.5-1.3-29-1.3-45.5 0-40.5 1.5-46.7 14.4-59.6 5.3-5.2 8.2-7.2 14.6-9.9 10.4-4.3 13.6-5 22-4.4 4.9.3 8.6 1.3 12.5 3.2Zm230.7 1.9c7.3 3 10 4.8 15.4 10.2 12.9 12.9 14.4 19.1 14.4 59.6 0 16.5-.6 37-1.3 45.5-.8 8.5-1.7 37.8-2.2 65-1.2 70-2.8 87.3-8.8 97-7.1 11.5-33.2 17.7-50.3 12-3.2-1.1-6.5-2-7.3-2-.9 0-2-.8-2.5-1.8-1.1-2.1-2.8-22.7-6.1-76.6-1.6-26.3-2.3-102.1-1.1-122.6 4.3-73.4 4.1-71.4 7.5-78.5 6.2-12.6 23.2-15.8 42.3-7.8Z"
|
||||
class="cls-1"
|
||||
/><path
|
||||
id="Meshtastic_M"
|
||||
fill="#2c2d3c"
|
||||
fill-rule="evenodd"
|
||||
stroke-width="0"
|
||||
d="m1034.49 1359.63-215.84 316.53-45.53-31.04 238.56-349.85c5.12-7.52 13.64-12.02 22.74-12.03 9.1 0 17.62 4.48 22.76 11.99l239.11 349.3-45.47 31.13-216.33-316.02Zm-452.9 316.2 252.13-369.74-45.53-31.05-252.13 369.73 45.53 31.05Z"
|
||||
data-name="Meshtastic M"
|
||||
/><path
|
||||
id="Left_hand_background"
|
||||
d="M407.1 1220.22v-6.7h-23.16v-8.98c0-11.12-1.6-21.87-4.56-32.04-3.4-45.86-33.88-84.17-75.5-99.01v-2.21c0-10.27-5.04-19.37-12.77-24.96v-2.05c0-10.55-5.65-19.77-14.08-24.82v-5.24c0-6.87-2.64-13.12-6.95-17.81l-39.54-206.2c-1.2-6.26-4.31-11.66-8.6-15.74-.62-15.68-13.52-28.2-29.35-28.2-15.68 0-28.49 12.29-29.33 27.76-5.01 5.27-8.1 12.39-8.1 20.24v3.47c-5.03 6.13-8.05 13.97-8.05 22.52v146.27c0 8.02 2.66 15.43 7.15 21.38h-10.15c-6.08-10.25-17.26-17.12-30.04-17.12h-10.13c-13.97 0-25.55 10.26-27.61 23.65-16.09 8.06-28.16 22.94-32.44 40.85-9.36 8.59-16.53 19.51-20.63 31.83-11.66 13.48-18.74 31.05-18.74 50.28v32.99c0 18.66 10.95 34.76 26.77 42.23 6.87 11.27 18.91 19.02 32.83 19.97 8.64 8.63 20.58 13.97 33.76 13.97h.65c.06 18.39 10.27 34.39 25.32 42.7v2.98l-31.54 15.79c-3.23 1.62-4.54 5.54-2.92 8.77l27.13 54.21c2.71 5.41 8.24 8.47 13.91 8.31 7.05 12.52 19.2 21.77 33.64 24.94 4.35 8.18 12.87 13.82 22.79 14.02l45.97.91c12.54.25 23.88-5.09 31.68-13.72h2.9c19.87 0 38.76-4.16 55.88-11.64 57.39-6.54 101.98-55.26 101.98-114.4v-12.05c0-12.25-7.5-22.75-18.16-27.16Z"
|
||||
class="cls-4"
|
||||
data-name="Left hand background"
|
||||
/><path
|
||||
id="Left_Hand"
|
||||
d="M180.02 744.24c-2.7 1.3-7.1 4.6-9.7 7.3-9.1 9.9-19.7 35.8-25.5 63l-2.8 12.8.1 49.5c0 52.1 1.1 75.2 4.5 94.8 1 6.3 1.9 11.9 1.9 12.4 0 .6-3.7-2.5-8.3-6.9-11.1-10.6-15.7-12.8-26.7-12.7-9.8.1-14.6 1.8-24.4 8.8-13 9.3-34.8 35.8-54.7 66.6-19 29.4-26.9 47.1-32 71.5-3.4 16.1-3.2 36.1.5 50 3.2 12.1 8.1 22.9 13.1 28.3 2 2.3 7.1 6.3 11.3 9 10.8 6.9 43 22.9 53.6 26.6l8.8 3.1 7.2 12.8c9 16.1 14.1 22.7 21.1 27.4l5.6 3.7-4.3 1.6c-26.9 10.4-28.9 11.3-30.8 14-1.1 1.6-2 3.7-2 4.7 0 2.4 13.9 34.6 18.7 43.3 7.2 13.2 15.8 23.2 29.7 34.7 16.4 13.7 26.1 20.2 39 26.4 13.9 6.6 25.5 9.3 36.6 8.4 12.4-1 22.4-3.1 38.5-8.1 7.9-2.4 19.1-5.5 24.9-6.9 5.8-1.4 14.7-3.8 19.9-5.5 5.1-1.6 18-5.2 28.5-8 30.2-7.9 59.5-19.7 70.7-28.7 6.4-5.1 16.6-19.3 22.2-31 2.7-5.6 6-15.4 8.6-25 4.1-15.4 4.2-16.2 4.2-31.8 0-17.1-1.1-23.6-5.1-31.6-5.5-11-13.1-16.3-23.4-16.4-3.6 0-8 .3-9.8.7-3.1.7-3.2.7-2.5-2 .5-1.5.8-7.7.7-13.7 0-9.7-.4-12.4-3.8-23.5-11.8-39.3-19.9-57.4-34.4-76.7-5.3-7.1-7.6-8.8-10.3-7.8-.8.3-2.6-.3-4-1.2-17.5-11.7-23-17.7-35.4-38.4-22.6-38.2-34.7-77-44.4-143.4-1.7-11.6-4.2-28.7-5.6-38-1.4-9.4-3.2-21.6-4-27.2-1.5-10.9-3-17.4-10.1-43.3-4.9-17.7-6.8-22.3-14.2-33.4-12.9-19.5-16.9-22.6-29.3-22.6-5.7 0-8.6.6-12.4 2.4Zm20.1 5.5c4.4 2 8.2 6.5 16.6 19.7 6.8 10.5 7.4 12.1 11.7 27.1 7 24.4 10.2 38.5 12.1 52.8 1 7.7 2.5 18 3.4 23 .8 4.9 1.8 11.7 2.1 15 1.1 10.6 7.4 49 10.1 61.7 6.9 33.1 15.3 59.9 24.9 79.7 6.6 13.4 16.5 31.1 19.3 34.3 1.9 2.2 1.8 2.2-4.6-.2-7.7-3-21-2.8-27.7.4-9.8 4.6-18.9 16.8-23.6 31.6-3.8 12.3-4.7 20.2-3.7 32.3 1 12.7 3 21.2 7.2 30.2 7.3 15.7 16.1 25.9 30.2 35.2 22.4 14.5 47.8 22.4 82.1 25.5l13.7 1.2-4.3 1.8c-2.3 1-9.9 2.9-16.9 4.4-7 1.5-20.3 5.3-29.5 8.5-29.2 10.1-50.1 14.5-99.7 20.9-28.9 3.7-62.9 9.1-78.5 12.4-8.3 1.7-11.4 1.2-19.9-3.3-8.1-4.3-16.2-14.3-23.5-28.9l-3.1-6.2h8.2c4.6 0 12.8-.7 18.2-1.5 5.5-.8 11.6-1.5 13.7-1.5 6.1 0 18.1-4.3 26.1-9.4 4.2-2.7 13.4-10.5 21.5-18.4 15.9-15.4 18.4-19.4 23.9-38.2 3.9-13.5 3.8-22.5-.3-35-1.7-5.2-4.8-15.1-6.8-22-11.3-38.1-20.2-61.5-30.5-80.3-3.7-6.8-7-13.5-7.3-14.9-.4-1.4-2.2-5.1-4.1-8.2-8.9-14.9-12.5-50.6-12.9-128.4-.1-34.8.1-38.6 2-49.2 5.5-28.9 16.4-57.2 26-66.7 6.7-6.7 16.2-8.9 23.9-5.4Zm-75.9 223.2c2.5 1.2 9.2 6.6 15.1 12 9 8.4 11.4 11.3 15.2 18.4 2.5 4.6 6.1 11.2 8.1 14.7 7.3 12.8 9.2 16.5 13.5 26.9 8.3 20.2 30.1 88.8 29 91.4-.7 1.9-3.2 1.9-13.9 0-19.4-3.4-34.8-11.1-53.2-26.5-22.6-19.1-38.4-35.1-53.4-54.5-8.7-11.1-23.7-33.2-25-36.7-1.6-4.3 23.2-33.2 35.5-41.3 10.2-6.8 20.9-8.4 29.1-4.4Zm-59.7 65.4c18.6 28 33.5 45.1 59.5 68.3 17.3 15.5 25.2 21.1 38 27.3 12.8 6.1 22.5 8.8 34.8 9.6 8.2.5 9.7.9 9.7 2.3 0 2.5-5.9 21.7-8.5 27.5-2.4 5.6-10.9 15.2-19.9 22.7l-5.8 4.9-8.2-.6c-14.7-1.2-43.1-12.1-64-24.5-33.2-19.8-62.4-49.6-77.6-79.3-2.7-5.4-5-10.5-5-11.3 0-5.6 35-63.9 37.1-61.7.3.5 4.8 7.1 9.9 14.8Zm231.1 31.7c5.3 2.4 22.2 13.2 33.5 21.3 3.1 2.2 6.6 3.8 8.5 4 3.1.2 4.1 1.2 10.2 10.1 11.9 17.3 19 34.1 29.6 69.9 4 13.7 5.2 21.9 4.2 28.2-1.3 8.5-1.6 8.7-16.1 8-40.6-1.9-82-17.7-99.4-37.8-5-5.9-11.1-16.4-14.2-24.6-3.3-8.8-5.7-24.9-5-33.8.6-8.7 5.8-25.5 9.7-31.6 3.9-6.2 13-14.7 16.5-15.4 1.6-.4 3.4-.8 3.9-1.1 3-1.1 13.5.4 18.6 2.8Zm-268.6 46.6c16.2 24.3 40.8 47.5 67.1 63.5 22.1 13.5 49.9 24.7 65.5 26.5l6.4.8-4.5 2.9c-6.7 4.3-15.9 7.8-21.5 8.1-2.7.2-9.2 1.1-14.2 2-6.8 1.2-12.9 1.5-23 1.2-16.4-.6-20.1-1.7-44.8-14-29.6-14.8-38-21-42.9-31.8-10-22-11.1-45.9-3.4-74.3l2.1-7.9 4.3 8.2c2.4 4.5 6.4 11.1 8.9 14.8Zm378.2 103.3c1.5.5 4.3 2.5 6.1 4.2 7.3 6.9 10.2 17.1 10.2 35.8 0 10.9-.4 14.3-3.4 26.5-1.9 7.7-4.7 17.2-6.1 21-5.1 13.4-16.7 30.6-24.8 36.5-11.8 8.6-40.4 19.8-69 26.9-6.7 1.7-17.8 4.9-24.7 7-6.9 2.2-17.4 5.1-23.5 6.5-6 1.4-15.7 4.1-21.5 6-14.3 4.8-26.7 7.4-38 8.1-8 .6-10.8.3-17.5-1.5-15.3-4.2-33.7-14.7-51.3-29.3-16.7-14-22.8-21.2-31.4-36.8-5.1-9.3-17.1-37.9-16.5-39.4s30.2-12.6 39.7-15c17-4.1 61-11.4 95.5-15.6 43.6-5.4 62.3-9.3 93.5-19.6 12.4-4 27.7-8.4 34-9.8 6.3-1.3 14.4-3.6 18-5.1 18.2-7.7 24.1-8.9 30.7-6.4Z"
|
||||
class="cls-1"
|
||||
data-name="Left Hand"
|
||||
/><path
|
||||
id="Right_hand_background"
|
||||
d="M1819.8 966.37c-25.94-6.6-55.37 12.34-80.21 47.23-7.22 2.11-13.85 6.48-18.71 12.96l-62.66 83.5c-3.95 5.27-6.58 11.11-7.97 17.13l-5.41 1.59c-13.38 3.92-23.69 13.25-29.27 24.9-5.72 2.53-10.71 6.15-14.76 10.55-3.12-3.5-6.87-6.34-11.02-8.41l-8.6-29.33c-2.43-8.29-7.39-15.15-13.8-19.98-1.3-3.05-2.95-5.86-4.89-8.42l-1.83-6.25c-5.53-18.87-25.32-29.69-44.19-24.16l-1.17.34c-17.05 5-27.52 21.63-25.3 38.71-2.25 3.8-4 7.88-5.2 12.14-6.93 11-9.29 24.81-5.34 38.27l4.28 14.6c-2.84 8.7-3.18 18.32-.41 27.76l43.82 149.44-4.59-1.51c-5.42-1.79-11.01-1.75-16.1-.23l-5.24-1.73c-6.73-2.22-14 1.43-16.22 8.17-1.95 5.9-1.07 12.05 1.87 17.01-2.25 10.55-.41 21.21 4.6 30.14 1.2 12.02 7.42 23.12 17.2 30.4 5.03 12.25 15.17 22.32 28.74 26.8l6.25 2.06c4.14 7.04 10.75 12.68 19.12 15.44l20.53 6.78 1.08 3.7 5.36-1.57 15.54 5.13 1.09 3.73 5.4-1.58 78.79 26.01c6.91 2.28 14.02 2.19 20.48.2l18.24 6.02c18.8 6.21 39.08-4 45.29-22.81 6.21-18.8-4-39.08-22.81-45.29l-4.43-1.46c-1.72-4.44-4.32-8.51-7.65-11.96l13.47-3.95-.5-1.72c10.19-4.24 17.61-12.72 20.8-22.72l4.6 3.75 41.26-50.64c3.18-3.9 5.25-8.34 6.27-12.94 25.27-12.22 42.7-38.1 42.7-68.05v-186.05c5.89-69.09-12.51-124.56-48.47-133.71Z"
|
||||
class="cls-4"
|
||||
data-name="Right hand background"
|
||||
/><path
|
||||
id="Right_Hand"
|
||||
d="M1797.02 960.24c-13.1 3.3-25.8 12.9-52.1 39.1-30.1 30-54.1 58.2-80.5 94.5-15.4 21.1-16.2 22.5-15.6 25.7.5 2.7.2 2.9-5.5 4.7-3.3 1-7.2 2.9-8.7 4-1.4 1.2-3.9 3-5.6 4-7.2 4.5-16.8 13.3-22.5 20.7-5.2 6.7-6.5 7.8-7.6 6.7-2.9-3-12.7-23.3-17.8-37.1-3-8.1-7.4-18.3-9.7-22.7-7.7-14.4-23.3-30.5-34.8-35.8-7.3-3.4-18-2.9-26.1 1.3-7.9 4-17.1 13.8-21.3 22.7-8.5 17.7-11.2 34-11.1 66.8 0 24.7 1.1 36.1 6 62.9 5.7 31.1 21.6 85.9 33.3 114.6 2.2 5.4 3.8 10.1 3.6 10.3s-5.8-.1-12.4-.7c-14.8-1.5-18.2-.9-22 3.5-6.6 7.5-6.7 17.7-.6 51.3 1.2 6.6 2.8 10.9 7.1 19 3.1 5.8 6.4 11.7 7.3 13.1s2.3 3.8 3.1 5.4 4.9 6.3 9 10.5c6.7 6.8 10.1 9.1 32.5 21.8 32.7 18.6 41.4 22.6 69.5 32.1 41.9 14.1 68.2 21 94.5 24.6 6.1.8 16.3 2.4 22.8 3.6 20.4 3.5 26.1 2.6 34.3-5.1 2.8-2.8 6.3-6.7 7.7-8.7 3.8-5.5 6.8-15.6 7-23.3.2-5.7-.2-7.2-2.1-9.6-1.2-1.5-4.4-5.7-7-9.3-8.5-11.8-35.6-37.2-44.4-41.6-7.5-3.8-22.4-9-33.6-11.8-10.4-2.6-27.5-9.1-46.7-17.9-43.6-19.9-57.9-26.8-76.7-36.6-11.6-6.2-23.4-11.9-26.2-12.8s-5.5-2-6-2.4c-.6-.5-1.8-.9-2.8-.9s-1.8-.5-1.8-1.1-1.6-2.5-3.5-4.4c-4-3.7-8-13.2-16.3-38.5-25.9-79.2-34.5-139.3-26.7-185 4-23.4 13.7-40 27.2-46.7 11.6-5.6 20.3-3.1 33.6 9.6s18.2 20.7 26.2 42.6c5.2 14.3 17.1 38.5 21.8 44.3 4 5 16.6 30.8 21.1 43.4 9.7 26.8 16.6 65.4 16.6 92.4v13.4h2.4c1.9 0 2.7-.8 3.7-3.7 2.5-7.8-.7-41.8-6.8-70.8-4.5-21.7-12.8-44.4-23.8-65l-5.4-10 2.7-3.1c1.5-1.7 3.9-4.7 5.4-6.6 1.5-1.9 6-6.1 10.2-9.2 4.1-3.1 7.7-6.4 8-7.4.9-2.6 10.3-8 19.3-11 12.9-4.2 20.3-3.7 39.3 2.8 8.5 2.9 18.3 6.6 21.8 8.2 6.9 3.3 9.6 3.3 10 .2.4-2.6-5-6.9-11.3-9.1-2.5-.8-4.7-1.9-5.1-2.4-.3-.5-1.6-.9-2.9-.9s-4.8-.9-7.7-2c-11.8-4.3-21.7-6.2-30.8-5.8l-8.8.3 1-2.4c1.1-3.1 26.2-37 39.2-53 16.1-19.8 40.9-47.2 59.2-65.2 34.3-33.6 47-39.6 65.4-30.8 10.3 4.9 16.8 11.2 25.6 24.6 13.3 20.1 15.3 26.3 19.9 61.4l.5 3.5-14.3 3.9c-26.3 7-48.8 16-84.2 33.6-24.9 12.4-33 17.4-33 20.4 0 3.5 4.1 2.9 12.3-1.8 20.3-11.7 60.9-30.7 81.9-38.3 13.4-4.9 36.3-11.5 37.4-10.8 1 .6 1.2 89.5.3 93.1-.4 1.6-1.7 2.3-4.7 2.8-14.3 2.5-43.6 18.3-57.9 31.4-6.7 6.1-8.6 9.4-6.8 11.6.7.8 1.6 1.5 2.1 1.5s3.7-2.7 7-6c11.7-11.3 37.2-26.7 51.7-31 4-1.2 7.5-2.1 7.6-1.9.4.4 1 78.5.8 89.4l-.2 7-5.2 1.9c-7.2 2.5-19.6 9.4-20.7 11.4-2 4 2.3 5.7 6.8 2.6 1.2-.9 5.7-3.4 9.9-5.5l7.7-3.9.3 12.3c.1 6.7-.1 17.2-.7 23.3-.7 9.4-1.3 12-3.7 16-6 10.6-16.7 21.8-24.9 26.1-2 1.1-2 .7-2.3-13.5-.3-15.1-1.1-18-4.4-16.7-1.4.5-1.7 3.1-2 15.3-.4 13.5-.6 15.3-3.3 21.7-3.7 8.8-18.4 28.6-28.4 38-4 3.8-9.4 9.2-11.9 12-9.2 10-16 16.1-25 22.5-6.8 4.7-9.2 7-9.2 8.6 0 2.9 2.5 3.7 5.9 1.9 6.1-3.1 23.6-17.7 29.6-24.6 3.5-4.1 9.4-10.1 13.1-13.4 8.2-7.2 24.8-27.9 28.9-35.8 2.8-5.4 3.6-6.1 10.5-9.6 4.1-2 8.7-4.5 10.2-5.5 4.3-2.9 16.4-18 19.7-24.8 2.9-5.9 3.2-7.6 4.3-22.8.6-9.1 1.2-44.9 1.3-79.5.1-34.7.4-84.4.6-110.5.3-50.6-.2-59.6-5.2-84.4-2.9-14.5-11.3-31-23.8-46.9-11.9-15.3-31.5-24-45.6-20.3Zm-287 388.6c6.1.6 13.3 1.7 16 2.5 2.8.8 7.5 2.1 10.5 3 3 .8 16.3 7.1 29.5 14 13.2 7 30.1 15.3 37.5 18.7 7.4 3.3 20.9 9.5 30 13.8 22.9 10.8 46.9 20.5 57 22.8 9.6 2.3 27.5 8.4 33.1 11.3 7.5 3.8 36.6 30.4 39.5 36.2.8 1.5 3.7 5.2 6.4 8.3 6 6.5 6.4 9.6 2.5 21.3-2.1 6.3-3.6 8.6-8.2 13.5-6.5 6.7-8.4 7.6-15.6 7.6-12.4 0-68.1-10.2-90.2-16.6-28.9-8.3-65.5-21.3-79-27.9-13.3-6.5-40.2-21.3-51-28-7.7-4.8-16.5-15.2-24.2-28.5-10.7-18.5-10.8-18.9-14.9-47.9-1.7-11.8-.8-18.9 2.8-22.8 2.4-2.6 3.3-2.7 18.3-1.3Z"
|
||||
class="cls-1"
|
||||
data-name="Right Hand"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
2233
packages/web/public/devices/diy.svg
Normal file
|
After Width: | Height: | Size: 102 KiB |
2604
packages/web/public/devices/heltec-ht62-esp32c3-sx1262.svg
Normal file
|
After Width: | Height: | Size: 77 KiB |
271
packages/web/public/devices/heltec-mesh-node-t114-case.svg
Normal file
@@ -0,0 +1,271 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="795.27 277.13 409.46 1319.35">
|
||||
<defs><style>
|
||||
.cls-1 {
|
||||
fill: #353535;
|
||||
}
|
||||
.cls-2 {
|
||||
fill: #1e1e1d;
|
||||
}
|
||||
.cls-3 {
|
||||
fill: #b1a368;
|
||||
}
|
||||
.cls-10, .cls-11, .cls-4, .cls-6, .cls-8, .cls-9 {
|
||||
fill: none;
|
||||
}
|
||||
.cls-4, .cls-6 {
|
||||
stroke: #050606;
|
||||
}
|
||||
.cls-10, .cls-11, .cls-4, .cls-6, .cls-8 {
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
.cls-4 {
|
||||
stroke-width: 2.41px;
|
||||
}
|
||||
.cls-5 {
|
||||
fill: #30c2db;
|
||||
}
|
||||
.cls-6 {
|
||||
stroke-width: 3.91px;
|
||||
}
|
||||
.cls-7 {
|
||||
fill: #dcf0f2;
|
||||
}
|
||||
.cls-10, .cls-11, .cls-8 {
|
||||
stroke: #dcf0f2;
|
||||
}
|
||||
.cls-8 {
|
||||
stroke-width: 1.81px;
|
||||
}
|
||||
.cls-9 {
|
||||
stroke: #17afbf;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-width: 7.23px;
|
||||
}
|
||||
.cls-10 {
|
||||
stroke-width: 1.78px;
|
||||
}
|
||||
.cls-11 {
|
||||
stroke-width: 1.81px;
|
||||
}
|
||||
</style></defs><g id="Layer_7" data-name="Layer 7"><path
|
||||
class="cls-1"
|
||||
d="M915.62,278.34h22.61a35,35,0,0,1,35,35V715.74a0,0,0,0,1,0,0H880.6a0,0,0,0,1,0,0V313.36A35,35,0,0,1,915.62,278.34Z"
|
||||
></path><rect
|
||||
class="cls-2"
|
||||
x="880.6"
|
||||
y="340.15"
|
||||
width="92.65"
|
||||
height="7.54"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="880.6"
|
||||
y="356.68"
|
||||
width="92.65"
|
||||
height="7.54"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="885.8"
|
||||
y="844.3"
|
||||
width="84.14"
|
||||
height="19.02"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="880.6"
|
||||
y="819.07"
|
||||
width="92.65"
|
||||
height="25.23"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="885.8"
|
||||
y="790.65"
|
||||
width="84.14"
|
||||
height="28.41"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="880.6"
|
||||
y="723.02"
|
||||
width="92.65"
|
||||
height="67.63"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="885.8"
|
||||
y="715.74"
|
||||
width="84.14"
|
||||
height="7.28"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="885.8"
|
||||
y="844.3"
|
||||
width="84.14"
|
||||
height="19.02"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="880.6"
|
||||
y="819.07"
|
||||
width="92.65"
|
||||
height="25.23"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="885.8"
|
||||
y="790.65"
|
||||
width="84.14"
|
||||
height="28.41"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="880.6"
|
||||
y="723.02"
|
||||
width="92.65"
|
||||
height="67.63"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="885.8"
|
||||
y="715.74"
|
||||
width="84.14"
|
||||
height="7.28"
|
||||
></rect><path
|
||||
class="cls-4"
|
||||
d="M915.62,278.34h22.61a35,35,0,0,1,35,35V715.74a0,0,0,0,1,0,0H880.6a0,0,0,0,1,0,0V313.36A35,35,0,0,1,915.62,278.34Z"
|
||||
></path><rect
|
||||
class="cls-4"
|
||||
x="880.6"
|
||||
y="340.15"
|
||||
width="92.65"
|
||||
height="7.54"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="880.6"
|
||||
y="356.68"
|
||||
width="92.65"
|
||||
height="7.54"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="796.48"
|
||||
y="856.3"
|
||||
width="407.05"
|
||||
height="738.98"
|
||||
rx="47.74"
|
||||
></rect><rect
|
||||
class="cls-1"
|
||||
x="900.05"
|
||||
y="973.19"
|
||||
width="202.03"
|
||||
height="354.65"
|
||||
rx="16.4"
|
||||
></rect><rect
|
||||
class="cls-6"
|
||||
x="900.05"
|
||||
y="973.19"
|
||||
width="202.03"
|
||||
height="354.65"
|
||||
rx="16.4"
|
||||
></rect><rect
|
||||
class="cls-7"
|
||||
x="871.51"
|
||||
y="890.41"
|
||||
width="55.42"
|
||||
height="31.12"
|
||||
rx="15.56"
|
||||
></rect><rect
|
||||
class="cls-7"
|
||||
x="1070.16"
|
||||
y="890.41"
|
||||
width="55.42"
|
||||
height="31.12"
|
||||
rx="15.56"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="871.51"
|
||||
y="890.41"
|
||||
width="55.42"
|
||||
height="31.12"
|
||||
rx="15.56"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="1070.16"
|
||||
y="890.41"
|
||||
width="55.42"
|
||||
height="31.12"
|
||||
rx="15.56"
|
||||
></rect><circle
|
||||
class="cls-8"
|
||||
cx="841.7"
|
||||
cy="1537.01"
|
||||
r="16.25"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="841.7"
|
||||
cy="913.26"
|
||||
r="16.25"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="1157.32"
|
||||
cy="913.26"
|
||||
r="16.25"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="1157.32"
|
||||
cy="1504.51"
|
||||
r="16.25"
|
||||
></circle><line
|
||||
class="cls-9"
|
||||
x1="942.51"
|
||||
y1="1592.42"
|
||||
x2="942.51"
|
||||
y2="1381.55"
|
||||
></line><line
|
||||
class="cls-9"
|
||||
x1="966.52"
|
||||
y1="1592.42"
|
||||
x2="966.52"
|
||||
y2="1381.55"
|
||||
></line><line
|
||||
class="cls-9"
|
||||
x1="990.57"
|
||||
y1="1592.42"
|
||||
x2="990.57"
|
||||
y2="1381.55"
|
||||
></line><line
|
||||
class="cls-9"
|
||||
x1="1014.59"
|
||||
y1="1592.42"
|
||||
x2="1014.59"
|
||||
y2="1381.55"
|
||||
></line><line
|
||||
class="cls-9"
|
||||
x1="1038.63"
|
||||
y1="1592.42"
|
||||
x2="1038.63"
|
||||
y2="1381.55"
|
||||
></line><line
|
||||
class="cls-9"
|
||||
x1="1062.65"
|
||||
y1="1592.42"
|
||||
x2="1062.65"
|
||||
y2="1381.55"
|
||||
></line><rect
|
||||
class="cls-4"
|
||||
x="796.48"
|
||||
y="856.3"
|
||||
width="407.05"
|
||||
height="738.98"
|
||||
rx="47.74"
|
||||
></rect><path
|
||||
class="cls-10"
|
||||
d="M1040.1,947.74H960.65A13.93,13.93,0,0,1,947,936.64l-10.23-49.2a13.93,13.93,0,0,1,13.64-16.77h97.72a13.93,13.93,0,0,1,13.75,16.18l-8,49.2A13.94,13.94,0,0,1,1040.1,947.74Z"
|
||||
></path><rect
|
||||
class="cls-11"
|
||||
x="816.35"
|
||||
y="870.67"
|
||||
width="365.51"
|
||||
height="703.12"
|
||||
rx="32.37"
|
||||
></rect><rect
|
||||
class="cls-11"
|
||||
x="888.77"
|
||||
y="963.84"
|
||||
width="223.2"
|
||||
height="374.66"
|
||||
rx="25.21"
|
||||
></rect></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
398
packages/web/public/devices/heltec-mesh-node-t114.svg
Normal file
@@ -0,0 +1,398 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="502.65 765.65 1000.06 433.43">
|
||||
<defs><style>
|
||||
.cls-1 {
|
||||
fill: #8e8d8e;
|
||||
}
|
||||
.cls-2 {
|
||||
fill: #cccccb;
|
||||
}
|
||||
.cls-3 {
|
||||
fill: #ddd;
|
||||
}
|
||||
.cls-4 {
|
||||
fill: #2b2b2b;
|
||||
}
|
||||
.cls-5 {
|
||||
fill: #383839;
|
||||
}
|
||||
.cls-6 {
|
||||
fill: #599cbd;
|
||||
}
|
||||
.cls-10, .cls-11, .cls-14, .cls-7, .cls-9 {
|
||||
fill: none;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
.cls-7 {
|
||||
stroke: #fff;
|
||||
}
|
||||
.cls-10, .cls-14, .cls-7 {
|
||||
stroke-width: 1.65px;
|
||||
}
|
||||
.cls-8 {
|
||||
fill: #cbcccb;
|
||||
}
|
||||
.cls-10, .cls-11, .cls-9 {
|
||||
stroke: #050606;
|
||||
}
|
||||
.cls-9 {
|
||||
stroke-width: 2px;
|
||||
}
|
||||
.cls-11 {
|
||||
stroke-width: 1.67px;
|
||||
}
|
||||
.cls-12 {
|
||||
fill: #fff;
|
||||
}
|
||||
.cls-13 {
|
||||
fill: #eecc42;
|
||||
}
|
||||
.cls-14 {
|
||||
stroke: #eecc42;
|
||||
}
|
||||
</style></defs><g id="Layer_4" data-name="Layer 4"><path
|
||||
class="cls-1"
|
||||
d="M554.23,774h907.26a0,0,0,0,1,0,0v415.1a0,0,0,0,1,0,0H554.23a32.53,32.53,0,0,1-32.53-32.53v-350A32.53,32.53,0,0,1,554.23,774Z"
|
||||
></path><path
|
||||
class="cls-2"
|
||||
d="M1363,985.65v82.44a8.42,8.42,0,0,0,8.42,8.42h75.41a18.61,18.61,0,0,1,18.61,18.62v82.15a20.79,20.79,0,0,1-20.79,20.79h-37.14a15,15,0,0,1-15-15v-40.46a23.46,23.46,0,0,0-23.46-23.47h-22.26a4.57,4.57,0,0,0-4.57,4.58h0a4.57,4.57,0,0,0,4.57,4.57h22.31a15.19,15.19,0,0,1,15.19,15.19V1181a17.08,17.08,0,0,1-17.08,17.08H549a45.49,45.49,0,0,1-45.35-42h37.39a57.24,57.24,0,0,0,57.24-57.23V864.62a57.24,57.24,0,0,0-57.24-57.23H503.79A45.49,45.49,0,0,1,549,766.65h818.24a17.08,17.08,0,0,1,17.08,17.08v37.46a15.19,15.19,0,0,1-15.19,15.18h-22.31a4.57,4.57,0,0,0-4.57,4.58h0a4.57,4.57,0,0,0,4.57,4.57h22.26a23.46,23.46,0,0,0,23.46-23.46V781.6a15,15,0,0,1,15-15h37.14a20.79,20.79,0,0,1,20.79,20.79v82.15a18.62,18.62,0,0,1-18.61,18.62h-75.41a8.41,8.41,0,0,0-8.42,8.41v89Z"
|
||||
></path><path
|
||||
class="cls-3"
|
||||
d="M1363,897.36h130.87a8,8,0,0,1,8,8v155.38a8,8,0,0,1-8,8H1363a0,0,0,0,1,0,0V897.36A0,0,0,0,1,1363,897.36Z"
|
||||
></path><rect
|
||||
class="cls-4"
|
||||
x="1404.64"
|
||||
y="937.34"
|
||||
width="10.03"
|
||||
height="22.38"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="1404.64"
|
||||
y="1003.72"
|
||||
width="10.03"
|
||||
height="22.38"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="1363.01"
|
||||
y="1001.56"
|
||||
width="23.63"
|
||||
height="34.15"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="1363.01"
|
||||
y="930.05"
|
||||
width="23.63"
|
||||
height="34.15"
|
||||
></rect><path
|
||||
class="cls-5"
|
||||
d="M598.31,864.62v234.21a57.24,57.24,0,0,1-57.24,57.23H521.7V807.39h19.37A57.24,57.24,0,0,1,598.31,864.62Z"
|
||||
></path><rect
|
||||
class="cls-5"
|
||||
x="728.25"
|
||||
y="817.13"
|
||||
width="158.2"
|
||||
height="330.36"
|
||||
></rect><path
|
||||
class="cls-6"
|
||||
d="M572.27,1146.81v-26.49a1.33,1.33,0,0,0-1.33-1.33H540.27a1.33,1.33,0,0,0-1.33,1.33v35.74a43.86,43.86,0,0,0,15.13-1.49C561.47,1152.31,572.27,1146.81,572.27,1146.81Z"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M538.94,1156.06v-35.74a1.33,1.33,0,0,1,1.33-1.33h30.67a1.33,1.33,0,0,1,1.33,1.33v26.49"
|
||||
></path><path
|
||||
class="cls-8"
|
||||
d="M528.57,837.41h3.59a0,0,0,0,1,0,0v38.22a0,0,0,0,1,0,0h-3.59a3,3,0,0,1-3-3V840.39A3,3,0,0,1,528.57,837.41Z"
|
||||
></path><path
|
||||
class="cls-9"
|
||||
d="M503.68,1156.06h37.39a57.24,57.24,0,0,0,57.24-57.23V864.62a57.24,57.24,0,0,0-57.24-57.23H503.79"
|
||||
></path><line
|
||||
class="cls-10"
|
||||
x1="521.7"
|
||||
y1="807.39"
|
||||
x2="521.7"
|
||||
y2="1156.06"
|
||||
></line><path
|
||||
class="cls-9"
|
||||
d="M1363,979.06V896.62a8.41,8.41,0,0,1,8.42-8.41h75.41a18.62,18.62,0,0,0,18.61-18.62V787.44a20.79,20.79,0,0,0-20.79-20.79h-37.14a15,15,0,0,0-15,15v40.46a23.46,23.46,0,0,1-23.46,23.46h-22.26a4.57,4.57,0,0,1-4.57-4.57h0a4.57,4.57,0,0,1,4.57-4.58h22.31a15.19,15.19,0,0,0,15.19-15.18V783.73a17.08,17.08,0,0,0-17.08-17.08H549a45.49,45.49,0,0,0-45.24,40.74"
|
||||
></path><path
|
||||
class="cls-9"
|
||||
d="M1363,985.65v82.44a8.42,8.42,0,0,0,8.42,8.42h75.41a18.61,18.61,0,0,1,18.61,18.62v82.15a20.79,20.79,0,0,1-20.79,20.79h-37.14a15,15,0,0,1-15-15v-40.46a23.46,23.46,0,0,0-23.46-23.47h-22.26a4.57,4.57,0,0,0-4.57,4.58h0a4.57,4.57,0,0,0,4.57,4.57h22.31a15.19,15.19,0,0,1,15.19,15.19V1181a17.08,17.08,0,0,1-17.08,17.08H549a45.49,45.49,0,0,1-45.35-42"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M618.9,981.73V862.12a6.16,6.16,0,0,1,6.16-6.17h87.49A10.48,10.48,0,0,0,723,845.48v-28a7.08,7.08,0,0,1,7.08-7.08H833.83A14.5,14.5,0,0,0,844,806.25l23.23-22.52a15.93,15.93,0,0,1,11.11-4.5h273.84a16,16,0,0,1,11.73,5.13l19.69,21.32a14.55,14.55,0,0,0,10.69,4.68h122.44a5.85,5.85,0,0,1,5.86,5.85v331.55a5.86,5.86,0,0,1-5.86,5.86H730.11a7.08,7.08,0,0,1-7.08-7.08v-74A10.48,10.48,0,0,0,712.55,1062H625.06a6.16,6.16,0,0,1-6.16-6.16V982.25"
|
||||
></path><circle
|
||||
class="cls-7"
|
||||
cx="1012.63"
|
||||
cy="1176.42"
|
||||
r="15.95"
|
||||
></circle><circle
|
||||
class="cls-7"
|
||||
cx="1347.86"
|
||||
cy="1165.18"
|
||||
r="15.95"
|
||||
></circle><circle
|
||||
class="cls-7"
|
||||
cx="1347.86"
|
||||
cy="801.82"
|
||||
r="15.95"
|
||||
></circle><rect
|
||||
class="cls-7"
|
||||
x="1406.28"
|
||||
y="1109.79"
|
||||
width="43.15"
|
||||
height="63.43"
|
||||
rx="21.58"
|
||||
></rect><rect
|
||||
class="cls-7"
|
||||
x="1406.28"
|
||||
y="796.41"
|
||||
width="43.15"
|
||||
height="63.43"
|
||||
rx="21.58"
|
||||
></rect><path
|
||||
class="cls-11"
|
||||
d="M1363,897.36h130.87a8,8,0,0,1,8,8v155.38a8,8,0,0,1-8,8H1363a0,0,0,0,1,0,0V897.36A0,0,0,0,1,1363,897.36Z"
|
||||
></path><rect
|
||||
class="cls-11"
|
||||
x="1404.64"
|
||||
y="937.34"
|
||||
width="10.03"
|
||||
height="22.38"
|
||||
></rect><rect
|
||||
class="cls-11"
|
||||
x="1404.64"
|
||||
y="1003.72"
|
||||
width="10.03"
|
||||
height="22.38"
|
||||
></rect><rect
|
||||
class="cls-11"
|
||||
x="1363.01"
|
||||
y="1001.56"
|
||||
width="23.63"
|
||||
height="34.15"
|
||||
></rect><rect
|
||||
class="cls-11"
|
||||
x="1363.01"
|
||||
y="930.05"
|
||||
width="23.63"
|
||||
height="34.15"
|
||||
></rect><line
|
||||
class="cls-11"
|
||||
x1="1461.49"
|
||||
y1="881.06"
|
||||
x2="1461.49"
|
||||
y2="897.36"
|
||||
></line><line
|
||||
class="cls-11"
|
||||
x1="1461.49"
|
||||
y1="1068.83"
|
||||
x2="1461.49"
|
||||
y2="1083.65"
|
||||
></line><line
|
||||
class="cls-11"
|
||||
x1="1381.33"
|
||||
y1="774.04"
|
||||
x2="1394.21"
|
||||
y2="774.04"
|
||||
></line><line
|
||||
class="cls-11"
|
||||
x1="1382.28"
|
||||
y1="1189.14"
|
||||
x2="1394.21"
|
||||
y2="1189.14"
|
||||
></line><rect
|
||||
class="cls-12"
|
||||
x="532.16"
|
||||
y="831.98"
|
||||
width="49.07"
|
||||
height="49.07"
|
||||
rx="2.75"
|
||||
></rect><rect
|
||||
class="cls-10"
|
||||
x="532.16"
|
||||
y="831.98"
|
||||
width="49.07"
|
||||
height="49.07"
|
||||
rx="2.75"
|
||||
></rect><circle
|
||||
class="cls-13"
|
||||
cx="556.69"
|
||||
cy="856.52"
|
||||
r="9.63"
|
||||
></circle><circle
|
||||
class="cls-14"
|
||||
cx="556.69"
|
||||
cy="856.52"
|
||||
r="19.11"
|
||||
></circle><path
|
||||
class="cls-10"
|
||||
d="M528.57,837.41h3.59a0,0,0,0,1,0,0v38.22a0,0,0,0,1,0,0h-3.59a3,3,0,0,1-3-3V840.39A3,3,0,0,1,528.57,837.41Z"
|
||||
></path><path
|
||||
class="cls-8"
|
||||
d="M584.21,837.41h3.59a0,0,0,0,1,0,0v38.22a0,0,0,0,1,0,0h-3.59a3,3,0,0,1-3-3V840.39A3,3,0,0,1,584.21,837.41Z"
|
||||
transform="translate(1169.02 1713.04) rotate(-180)"
|
||||
></path><path
|
||||
class="cls-10"
|
||||
d="M584.21,837.41h3.59a0,0,0,0,1,0,0v38.22a0,0,0,0,1,0,0h-3.59a3,3,0,0,1-3-3V840.39A3,3,0,0,1,584.21,837.41Z"
|
||||
transform="translate(1169.02 1713.04) rotate(-180)"
|
||||
></path><rect
|
||||
class="cls-7"
|
||||
x="525.59"
|
||||
y="961.1"
|
||||
width="31.1"
|
||||
height="17.96"
|
||||
rx="0.79"
|
||||
></rect><rect
|
||||
class="cls-7"
|
||||
x="525.59"
|
||||
y="985.65"
|
||||
width="31.1"
|
||||
height="17.96"
|
||||
rx="0.79"
|
||||
></rect><path
|
||||
class="cls-12"
|
||||
d="M576.68,978.9h-2V962h2Zm8.64-7.59H575.6v-1.93h9.72Zm1.3,7.59h-2V962h2Z"
|
||||
></path><path
|
||||
class="cls-12"
|
||||
d="M569.32,978.9h-9.47V977h9.47Zm0-7.7h-8.19v-1.9h8.19Zm1.16,7.7h-2V962h2Z"
|
||||
></path><path
|
||||
class="cls-12"
|
||||
d="M585.44,988.92h-9.67V987h9.67Zm1.18,15h-2V987h2Z"
|
||||
></path><path
|
||||
class="cls-12"
|
||||
d="M571.82,1003.9h-9.46V1002h9.46Zm0-7.7h-8.19v-1.9h8.19Zm1.17,7.7h-2V987h2Z"
|
||||
></path><rect
|
||||
class="cls-8"
|
||||
x="530.71"
|
||||
y="989.79"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="546"
|
||||
y="989.79"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="530.71"
|
||||
y="965.24"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="556.69"
|
||||
y="913.16"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="583.14"
|
||||
y="913.16"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="546"
|
||||
y="965.24"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
></rect><path
|
||||
class="cls-7"
|
||||
d="M552.28,913.61v-5.5a1.36,1.36,0,0,1,1.36-1.36H590.7a1.36,1.36,0,0,1,1.36,1.36v5.5"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M565.9,922.84v5.63a1.36,1.36,0,0,1-1.37,1.36H553.64a1.36,1.36,0,0,1-1.36-1.36v-5.63"
|
||||
></path><rect
|
||||
class="cls-8"
|
||||
x="541.49"
|
||||
y="1082.41"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
transform="translate(1697.94 1471.19) rotate(135)"
|
||||
></rect><path
|
||||
class="cls-7"
|
||||
d="M536.32,1088.36l-4-4a1.36,1.36,0,0,1,0-1.92l7.7-7.7a1.35,1.35,0,0,1,1.93,0l4,4"
|
||||
></path><rect
|
||||
class="cls-8"
|
||||
x="571.96"
|
||||
y="1050.39"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
transform="translate(1727.32 1394.99) rotate(135)"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="583.85"
|
||||
y="1059.62"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
transform="translate(1754.13 1402.34) rotate(135)"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="574.63"
|
||||
y="1068.83"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
transform="translate(1744.92 1424.58) rotate(135)"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="561.03"
|
||||
y="1083.6"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
transform="translate(1732.15 1459.41) rotate(135)"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="551.82"
|
||||
y="1092.82"
|
||||
width="5.58"
|
||||
height="9.68"
|
||||
rx="1.05"
|
||||
transform="translate(1722.93 1481.65) rotate(135)"
|
||||
></rect><path
|
||||
class="cls-7"
|
||||
d="M566.79,1056.35l-4-4a1.36,1.36,0,0,1,0-1.92l7.71-7.71a1.36,1.36,0,0,1,1.92,0l4,4"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M592.06,922.84v5.63a1.36,1.36,0,0,1-1.36,1.36H581a1.36,1.36,0,0,1-1.36-1.36v-5.63"
|
||||
></path><line
|
||||
class="cls-7"
|
||||
x1="565.9"
|
||||
y1="918.69"
|
||||
x2="579.63"
|
||||
y2="918.69"
|
||||
></line><path
|
||||
class="cls-7"
|
||||
d="M551,1103.25l3.72,3.21a3.16,3.16,0,0,0,4.33-.19l35.69-36.8a3.15,3.15,0,0,0,0-4.44l-3.79-3.76"
|
||||
></path><line
|
||||
class="cls-7"
|
||||
x1="573.31"
|
||||
y1="1065.02"
|
||||
x2="553.89"
|
||||
y2="1084.25"
|
||||
></line><path
|
||||
class="cls-7"
|
||||
d="M569.42,1116.78V1115a1.89,1.89,0,0,0-1.89-1.89h-23.2a1.88,1.88,0,0,0-1.89,1.89v1.8"
|
||||
></path><rect
|
||||
class="cls-12"
|
||||
x="542.44"
|
||||
y="1121.36"
|
||||
width="26.13"
|
||||
height="7.79"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="790.91"
|
||||
y="817.13"
|
||||
width="522.47"
|
||||
height="330.36"
|
||||
></rect></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
74
packages/web/public/devices/heltec-v3-case.svg
Normal file
@@ -0,0 +1,74 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="404.68 390.65 1217.15 959.26">
|
||||
<defs><style>
|
||||
.cls-1 {
|
||||
fill: #dfeaf7;
|
||||
}
|
||||
.cls-2 {
|
||||
fill: #17907f;
|
||||
}
|
||||
.cls-3 {
|
||||
fill: #2b2b2b;
|
||||
}
|
||||
.cls-4, .cls-5 {
|
||||
fill: none;
|
||||
stroke: #050606;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
.cls-4 {
|
||||
stroke-width: 2.25px;
|
||||
}
|
||||
.cls-5 {
|
||||
stroke-width: 4px;
|
||||
}
|
||||
.cls-6 {
|
||||
fill: #050606;
|
||||
}
|
||||
</style></defs><g id="Layer_5" data-name="Layer 5"><path
|
||||
class="cls-1"
|
||||
d="M1517.73,392.65h0a102.1,102.1,0,0,0-102.1,102.1V770.37A40.62,40.62,0,0,1,1375,811H455.16a48.49,48.49,0,0,0-48.48,48.48v126a11.85,11.85,0,0,0,3.46,8.37l15.34,15.34a11.81,11.81,0,0,1,3.47,8.37v137.16a11.81,11.81,0,0,1-3.47,8.37l-15.34,15.34a11.85,11.85,0,0,0-3.46,8.37v112.67a48.49,48.49,0,0,0,48.48,48.49H1571.34a48.51,48.51,0,0,0,48.49-48.5V494.75A102.1,102.1,0,0,0,1517.73,392.65Zm-110.61,815V954a33.14,33.14,0,0,1,66.27,0v253.65a33.14,33.14,0,0,1-66.27,0Z"
|
||||
></path><path
|
||||
class="cls-2"
|
||||
d="M1516,439.16c-30.23.91-53.92,26.54-53.92,56.79V770.37A87.11,87.11,0,0,1,1375,857.48H732.31A27.51,27.51,0,0,0,704.8,885v388.93a27.51,27.51,0,0,0,27.51,27.51h828.38a12.7,12.7,0,0,0,12.65-12.65v-794A55.69,55.69,0,0,0,1516,439.16Zm-108.9,768.47V954a33.14,33.14,0,0,1,66.27,0v253.65a33.14,33.14,0,0,1-66.27,0Z"
|
||||
></path><rect
|
||||
class="cls-3"
|
||||
x="787.14"
|
||||
y="943.38"
|
||||
width="429.45"
|
||||
height="224.42"
|
||||
></rect><path
|
||||
class="cls-1"
|
||||
d="M1478.6,915.35A54.23,54.23,0,0,0,1386,953.69v254.23a54.23,54.23,0,1,0,108.45,0V953.69A54,54,0,0,0,1478.6,915.35Zm-5.21,292.28a33.14,33.14,0,0,1-66.27,0V954a33.14,33.14,0,0,1,66.27,0Z"
|
||||
></path></g><g id="Layer_2" data-name="Layer 2"><path
|
||||
class="cls-4"
|
||||
d="M1573.34,494.75v794a12.68,12.68,0,0,1-12.65,12.65H732.31a27.51,27.51,0,0,1-27.51-27.51V885a27.51,27.51,0,0,1,27.51-27.51H1375a87.11,87.11,0,0,0,87.11-87.11V496c0-30.25,23.69-55.88,53.92-56.79A55.69,55.69,0,0,1,1573.34,494.75Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M410.14,1178.39,425.49,1163a11.78,11.78,0,0,0,3.46-8.35V1017.5a11.8,11.8,0,0,0-3.46-8.35l-15.35-15.36a11.77,11.77,0,0,1-3.46-8.35v-126A48.47,48.47,0,0,1,455.16,811H1375a40.63,40.63,0,0,0,40.63-40.63V494.75a102.1,102.1,0,0,1,102.1-102.1h0a102.1,102.1,0,0,1,102.1,102.1v804.66a48.51,48.51,0,0,1-48.49,48.5H455.16a48.48,48.48,0,0,1-48.48-48.49V1186.74A11.78,11.78,0,0,1,410.14,1178.39Z"
|
||||
></path><rect
|
||||
class="cls-4"
|
||||
x="1407.12"
|
||||
y="920.85"
|
||||
width="66.26"
|
||||
height="319.9"
|
||||
rx="33.13"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="1386.03"
|
||||
y="899.46"
|
||||
width="108.46"
|
||||
height="362.69"
|
||||
rx="54.23"
|
||||
></rect><path
|
||||
class="cls-6"
|
||||
d="M639.76,1070.55a2.91,2.91,0,0,1-2.91-2.91v-30.53a5.42,5.42,0,0,0-1.6-3.86l-32.44-32.44a11.86,11.86,0,0,1-3.5-8.44V901a12.52,12.52,0,0,0-12.51-12.51H483.92a12.7,12.7,0,0,0-12.68,12.69v76.78a24.13,24.13,0,0,0,7.11,17.18l14.33,14.33a24.13,24.13,0,0,0,17.18,7.11h50.75a11.86,11.86,0,0,1,8.44,3.5l24.26,24.26a12.47,12.47,0,0,1,3.68,8.88v14.46a2.91,2.91,0,1,1-5.81,0v-14.46a6.72,6.72,0,0,0-2-4.77l-24.26-24.26a6.09,6.09,0,0,0-4.33-1.8H509.86a29.91,29.91,0,0,1-21.29-8.81l-14.33-14.33a29.87,29.87,0,0,1-8.81-21.29V901.14a18.51,18.51,0,0,1,18.49-18.5H586.8A18.34,18.34,0,0,1,605.12,901v91.41a6.09,6.09,0,0,0,1.8,4.33l32.44,32.44a11.19,11.19,0,0,1,3.3,8v30.53A2.9,2.9,0,0,1,639.76,1070.55Z"
|
||||
></path><path
|
||||
class="cls-6"
|
||||
d="M586.8,1289.46H483.92a18.51,18.51,0,0,1-18.49-18.5v-76.78a29.87,29.87,0,0,1,8.81-21.29l14.33-14.34a29.91,29.91,0,0,1,21.29-8.81h50.75a6.09,6.09,0,0,0,4.33-1.8l24.26-24.25a6.74,6.74,0,0,0,2-4.78v-14.46a2.91,2.91,0,0,1,5.81,0v14.46a12.51,12.51,0,0,1-3.68,8.89l-24.26,24.25a11.86,11.86,0,0,1-8.44,3.5H509.86a24.17,24.17,0,0,0-17.18,7.11L478.35,1177a24.09,24.09,0,0,0-7.11,17.18V1271a12.71,12.71,0,0,0,12.68,12.69H586.8a12.53,12.53,0,0,0,12.51-12.52v-91.4a11.83,11.83,0,0,1,3.5-8.44l32.44-32.44a5.46,5.46,0,0,0,1.6-3.87v-30.53a2.91,2.91,0,0,1,5.81,0V1135a11.19,11.19,0,0,1-3.3,8l-32.44,32.45a6.06,6.06,0,0,0-1.8,4.33v91.4A18.35,18.35,0,0,1,586.8,1289.46Z"
|
||||
></path><rect
|
||||
class="cls-4"
|
||||
x="787.14"
|
||||
y="943.38"
|
||||
width="429.45"
|
||||
height="224.42"
|
||||
></rect></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
1496
packages/web/public/devices/heltec-v3.svg
Normal file
|
After Width: | Height: | Size: 40 KiB |
149
packages/web/public/devices/heltec-vision-master-e213.svg
Normal file
@@ -0,0 +1,149 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="528.89 806.04 942.22 446.84">
|
||||
<defs><style>
|
||||
.cls-1 {
|
||||
fill: #e8eae8;
|
||||
}
|
||||
.cls-2 {
|
||||
fill: #dbdddb;
|
||||
}
|
||||
.cls-3 {
|
||||
fill: #c6842a;
|
||||
}
|
||||
.cls-4, .cls-5, .cls-7, .cls-9 {
|
||||
fill: none;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
.cls-4, .cls-5 {
|
||||
stroke: #050606;
|
||||
}
|
||||
.cls-4, .cls-9 {
|
||||
stroke-width: 2.44px;
|
||||
}
|
||||
.cls-5, .cls-7 {
|
||||
stroke-width: 1.22px;
|
||||
}
|
||||
.cls-6 {
|
||||
fill: #b7b7b7;
|
||||
}
|
||||
.cls-7, .cls-9 {
|
||||
stroke: #b7b7b7;
|
||||
}
|
||||
.cls-8 {
|
||||
fill: #cbcccb;
|
||||
}
|
||||
.cls-10 {
|
||||
fill: #434543;
|
||||
}
|
||||
</style></defs><g id="Layer_4" data-name="Layer 4"><path
|
||||
class="cls-1"
|
||||
d="M1469.9,826.68v390.94a19.43,19.43,0,0,1-19.43,19.43H549.53a19.43,19.43,0,0,1-19.43-19.43V826.68a19.42,19.42,0,0,1,19.43-19.42h900.94A19.42,19.42,0,0,1,1469.9,826.68Z"
|
||||
></path><path
|
||||
class="cls-2"
|
||||
d="M574.23,807.26v429.79h-24.7a19.43,19.43,0,0,1-19.43-19.43V826.68a19.42,19.42,0,0,1,19.43-19.42Z"
|
||||
></path><path
|
||||
class="cls-2"
|
||||
d="M1469.9,826.68v390.94a19.43,19.43,0,0,1-19.43,19.43h-37.56V807.26h37.56A19.42,19.42,0,0,1,1469.9,826.68Z"
|
||||
></path><path
|
||||
class="cls-3"
|
||||
d="M574.23,1129.8h-7.47a4.55,4.55,0,0,1-4.55-4.54V919.05a4.55,4.55,0,0,1,4.55-4.55h7.47"
|
||||
></path><rect
|
||||
class="cls-4"
|
||||
x="530.11"
|
||||
y="807.26"
|
||||
width="939.78"
|
||||
height="429.79"
|
||||
rx="19.42"
|
||||
></rect><line
|
||||
class="cls-5"
|
||||
x1="574.23"
|
||||
y1="807.26"
|
||||
x2="574.23"
|
||||
y2="1237.05"
|
||||
></line><path
|
||||
class="cls-5"
|
||||
d="M574.23,1129.8h-7.47a4.55,4.55,0,0,1-4.55-4.54V919.05a4.55,4.55,0,0,1,4.55-4.55h7.47"
|
||||
></path><rect
|
||||
class="cls-6"
|
||||
x="599.01"
|
||||
y="970.1"
|
||||
width="11.52"
|
||||
height="104.11"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="599.01"
|
||||
y="970.1"
|
||||
width="11.52"
|
||||
height="104.11"
|
||||
></rect><path
|
||||
class="cls-2"
|
||||
d="M610.53,816.78V935.32l38.37,11.55a7.85,7.85,0,0,1,5.6,7.53V1107a7.87,7.87,0,0,1-7.87,7.87h-36.1v110.58H1406V816.78Zm775.41,384.75H631.43a3.66,3.66,0,0,1-3.66-3.66V1138a3.65,3.65,0,0,1,3.66-3.65h28.3a14.7,14.7,0,0,0,14.71-14.71V931a14.7,14.7,0,0,0-14.71-14.71h-28.3a3.65,3.65,0,0,1-3.66-3.66V844.11a3.66,3.66,0,0,1,3.66-3.66h754.51Z"
|
||||
></path><path
|
||||
class="cls-1"
|
||||
d="M1385.94,840.45v361.08H631.43a3.66,3.66,0,0,1-3.66-3.66V1138a3.65,3.65,0,0,1,3.66-3.65h28.3a14.7,14.7,0,0,0,14.71-14.71V931a14.7,14.7,0,0,0-14.71-14.71h-28.3a3.65,3.65,0,0,1-3.66-3.66V844.11a3.66,3.66,0,0,1,3.66-3.66Z"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M610.53,816.78V935.32l38.37,11.55a7.85,7.85,0,0,1,5.6,7.53V1107a7.87,7.87,0,0,1-7.87,7.87h-36.1v110.58H1406V816.78Zm775.41,384.75H631.43a3.66,3.66,0,0,1-3.66-3.66V1138a3.65,3.65,0,0,1,3.66-3.65h28.3a14.7,14.7,0,0,0,14.71-14.71V931a14.7,14.7,0,0,0-14.71-14.71h-28.3a3.65,3.65,0,0,1-3.66-3.66V844.11a3.66,3.66,0,0,1,3.66-3.66h754.51Z"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M1385.94,840.45v361.08H631.43a3.66,3.66,0,0,1-3.66-3.66V1138a3.65,3.65,0,0,1,3.66-3.65h28.3a14.7,14.7,0,0,0,14.71-14.71V931a14.7,14.7,0,0,0-14.71-14.71h-28.3a3.65,3.65,0,0,1-3.66-3.66V844.11a3.66,3.66,0,0,1,3.66-3.66Z"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M1385.94,840.45v361.08H631.43a3.66,3.66,0,0,1-3.66-3.66V1138a3.65,3.65,0,0,1,3.66-3.65h28.3a14.7,14.7,0,0,0,14.71-14.71V931a14.7,14.7,0,0,0-14.71-14.71h-28.3a3.65,3.65,0,0,1-3.66-3.66V844.11a3.66,3.66,0,0,1,3.66-3.66Z"
|
||||
></path><line
|
||||
class="cls-7"
|
||||
x1="666.4"
|
||||
y1="1132.79"
|
||||
x2="666.4"
|
||||
y2="1201.53"
|
||||
></line><line
|
||||
class="cls-7"
|
||||
x1="663.66"
|
||||
y1="916.86"
|
||||
x2="663.66"
|
||||
y2="840.45"
|
||||
></line><circle
|
||||
class="cls-8"
|
||||
cx="644.99"
|
||||
cy="878.66"
|
||||
r="10.7"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="644.99"
|
||||
cy="1171.55"
|
||||
r="10.7"
|
||||
></circle><circle
|
||||
class="cls-9"
|
||||
cx="644.99"
|
||||
cy="878.66"
|
||||
r="10.7"
|
||||
></circle><circle
|
||||
class="cls-9"
|
||||
cx="644.99"
|
||||
cy="1171.55"
|
||||
r="10.7"
|
||||
></circle><path
|
||||
class="cls-10"
|
||||
d="M1225,1237.05l2.23,11.19a4.25,4.25,0,0,0,4.17,3.42H1249a4.26,4.26,0,0,0,4.18-3.42l2.22-11.19"
|
||||
></path><path
|
||||
class="cls-10"
|
||||
d="M1306.87,1237.05l2.22,11.19a4.26,4.26,0,0,0,4.18,3.42h17.62a4.25,4.25,0,0,0,4.17-3.42l2.22-11.19"
|
||||
></path><path
|
||||
class="cls-10"
|
||||
d="M1388.77,1237.05l2.23,11.19a4.24,4.24,0,0,0,4.17,3.42h17.62a4.25,4.25,0,0,0,4.17-3.42l2.23-11.19"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M1225,1237.05l2.23,11.19a4.25,4.25,0,0,0,4.17,3.42H1249a4.26,4.26,0,0,0,4.18-3.42l2.22-11.19"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M1306.87,1237.05l2.22,11.19a4.26,4.26,0,0,0,4.18,3.42h17.62a4.25,4.25,0,0,0,4.17-3.42l2.22-11.19"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M1388.77,1237.05l2.23,11.19a4.24,4.24,0,0,0,4.17,3.42h17.62a4.25,4.25,0,0,0,4.17-3.42l2.23-11.19"
|
||||
></path><line
|
||||
class="cls-4"
|
||||
x1="1412.9"
|
||||
y1="807.26"
|
||||
x2="1412.9"
|
||||
y2="1237.05"
|
||||
></line></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
221
packages/web/public/devices/heltec-vision-master-e290.svg
Normal file
@@ -0,0 +1,221 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="479.87 739.66 1073.46 452.36">
|
||||
<defs><style>
|
||||
.cls-1 {
|
||||
fill: #e8eae8;
|
||||
}
|
||||
.cls-2 {
|
||||
fill: #2b2b2b;
|
||||
}
|
||||
.cls-3, .cls-5, .cls-7, .cls-8 {
|
||||
fill: none;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
.cls-3, .cls-5 {
|
||||
stroke: #050606;
|
||||
}
|
||||
.cls-3, .cls-7 {
|
||||
stroke-width: 2.44px;
|
||||
}
|
||||
.cls-4 {
|
||||
fill: #cbcccb;
|
||||
}
|
||||
.cls-5 {
|
||||
stroke-width: 1.73px;
|
||||
}
|
||||
.cls-6 {
|
||||
fill: #434543;
|
||||
}
|
||||
.cls-7, .cls-8 {
|
||||
stroke: #b7b7b7;
|
||||
}
|
||||
.cls-8 {
|
||||
stroke-width: 1.22px;
|
||||
}
|
||||
.cls-9 {
|
||||
fill: #dbdddb;
|
||||
}
|
||||
.cls-10 {
|
||||
fill: #b7b7b7;
|
||||
}
|
||||
</style></defs><g id="Layer_4" data-name="Layer 4"><rect
|
||||
class="cls-1"
|
||||
x="541.37"
|
||||
y="740.89"
|
||||
width="950.47"
|
||||
height="441.77"
|
||||
></rect><path
|
||||
class="cls-2"
|
||||
d="M1511.86,740.89h-20V907.47h13.88a4.83,4.83,0,1,1,0,9.65h-13.88v87h13.88a4.82,4.82,0,0,1,4.82,4.83,4.81,4.81,0,0,1-4.82,4.82h-13.88v168.83h20a40.25,40.25,0,0,0,40.25-40.25V781.15A40.25,40.25,0,0,0,1511.86,740.89Zm22.9,400.64a10.68,10.68,0,0,1-21.36,0v-17.4a10.68,10.68,0,1,1,21.36,0Zm0-343.24a10.68,10.68,0,1,1-21.36,0v-17.4a10.68,10.68,0,0,1,21.36,0Z"
|
||||
></path><path
|
||||
class="cls-3"
|
||||
d="M1532.09,740.89h20a0,0,0,0,1,0,0v441.77a0,0,0,0,1,0,0h-20a40.25,40.25,0,0,1-40.25-40.25V781.14a40.25,40.25,0,0,1,40.25-40.25Z"
|
||||
transform="translate(3043.95 1923.54) rotate(-180)"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M1508.36,780.88V798.3a15.89,15.89,0,0,0,31.78,0V780.88a15.89,15.89,0,1,0-31.78,0Zm5,0a10.68,10.68,0,0,1,21.36,0v17.4a10.68,10.68,0,1,1-21.36,0Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M1508.36,1124.11v17.42a15.89,15.89,0,1,0,31.78,0v-17.42a15.89,15.89,0,0,0-31.78,0Zm5,0a10.68,10.68,0,1,1,21.36,0v17.4a10.68,10.68,0,0,1-21.36,0Z"
|
||||
></path><rect
|
||||
class="cls-5"
|
||||
x="1513.41"
|
||||
y="770.21"
|
||||
width="21.36"
|
||||
height="38.76"
|
||||
rx="10.68"
|
||||
transform="translate(3048.18 1579.19) rotate(-180)"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="1508.36"
|
||||
y="764.99"
|
||||
width="31.78"
|
||||
height="49.2"
|
||||
rx="15.89"
|
||||
transform="translate(3048.5 1579.18) rotate(-180)"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="1513.41"
|
||||
y="1113.44"
|
||||
width="21.36"
|
||||
height="38.76"
|
||||
rx="10.68"
|
||||
transform="translate(3048.18 2265.65) rotate(-180)"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="1508.36"
|
||||
y="1108.22"
|
||||
width="31.78"
|
||||
height="49.2"
|
||||
rx="15.89"
|
||||
transform="translate(3048.5 2265.65) rotate(-180)"
|
||||
></rect><path
|
||||
class="cls-4"
|
||||
d="M1513.13,912.3a6.95,6.95,0,0,1-7,7h-14.33v-2.15h13.88a4.83,4.83,0,0,0,0-9.65h-13.88v-2.14h14.33A7,7,0,0,1,1513.13,912.3Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M1513.13,1009a6.95,6.95,0,0,1-7,7h-14.33v-2.15h13.88a4.83,4.83,0,0,0,0-9.65h-13.88V1002h14.33A7,7,0,0,1,1513.13,1009Z"
|
||||
></path><path
|
||||
class="cls-2"
|
||||
d="M521.33,740.89a40.26,40.26,0,0,0-40.25,40.26V1142.4a40.26,40.26,0,0,0,40.25,40.25h20V740.89Zm-1.53,400.64a10.68,10.68,0,0,1-21.36,0v-17.4a10.68,10.68,0,1,1,21.36,0ZM498.44,780.89a10.68,10.68,0,0,1,21.36,0v17.4a10.68,10.68,0,1,1-21.36,0Z"
|
||||
></path><rect
|
||||
class="cls-3"
|
||||
x="541.37"
|
||||
y="740.89"
|
||||
width="950.47"
|
||||
height="441.77"
|
||||
></rect><path
|
||||
class="cls-3"
|
||||
d="M521.34,740.89h20a0,0,0,0,1,0,0v441.77a0,0,0,0,1,0,0h-20a40.25,40.25,0,0,1-40.25-40.25V781.14A40.25,40.25,0,0,1,521.34,740.89Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M520.19,769.64a15.9,15.9,0,0,0-27.13,11.24V798.3a15.89,15.89,0,0,0,31.78,0V780.88A15.87,15.87,0,0,0,520.19,769.64Zm-.39,28.65a10.68,10.68,0,1,1-21.36,0v-17.4a10.68,10.68,0,0,1,21.36,0Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M520.19,1112.88a15.89,15.89,0,0,0-27.13,11.23v17.42a15.89,15.89,0,1,0,31.78,0v-17.42A15.85,15.85,0,0,0,520.19,1112.88Zm-.39,28.65a10.68,10.68,0,0,1-21.36,0v-17.4a10.68,10.68,0,1,1,21.36,0Z"
|
||||
></path><rect
|
||||
class="cls-5"
|
||||
x="498.43"
|
||||
y="770.21"
|
||||
width="21.36"
|
||||
height="38.76"
|
||||
rx="10.68"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="493.06"
|
||||
y="764.99"
|
||||
width="31.78"
|
||||
height="49.2"
|
||||
rx="15.89"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="498.43"
|
||||
y="1113.44"
|
||||
width="21.36"
|
||||
height="38.76"
|
||||
rx="10.68"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="493.06"
|
||||
y="1108.22"
|
||||
width="31.78"
|
||||
height="49.2"
|
||||
rx="15.89"
|
||||
></rect><rect
|
||||
class="cls-4"
|
||||
x="501.66"
|
||||
y="859.82"
|
||||
width="14.3"
|
||||
height="198.79"
|
||||
rx="7.15"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="501.66"
|
||||
y="859.82"
|
||||
width="14.3"
|
||||
height="198.79"
|
||||
rx="7.15"
|
||||
></rect><path
|
||||
class="cls-6"
|
||||
d="M528.29,869.68h13.07a0,0,0,0,1,0,0v179.06a0,0,0,0,1,0,0H528.29a3.45,3.45,0,0,1-3.45-3.45V873.13A3.45,3.45,0,0,1,528.29,869.68Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M528.29,869.68h13.07a0,0,0,0,1,0,0v179.06a0,0,0,0,1,0,0H528.29a3.45,3.45,0,0,1-3.45-3.45V873.13A3.45,3.45,0,0,1,528.29,869.68Z"
|
||||
></path><path
|
||||
class="cls-6"
|
||||
d="M1213.75,1182.65h22.83a0,0,0,0,1,0,0v6.15a2,2,0,0,1-2,2h-18.8a2,2,0,0,1-2-2v-6.15A0,0,0,0,1,1213.75,1182.65Z"
|
||||
></path><path
|
||||
class="cls-6"
|
||||
d="M1297.35,1182.65h22.83a0,0,0,0,1,0,0v6.15a2,2,0,0,1-2,2h-18.8a2,2,0,0,1-2-2v-6.15A0,0,0,0,1,1297.35,1182.65Z"
|
||||
></path><path
|
||||
class="cls-6"
|
||||
d="M1381,1182.65h22.83a0,0,0,0,1,0,0v6.15a2,2,0,0,1-2,2H1383a2,2,0,0,1-2-2v-6.15A0,0,0,0,1,1381,1182.65Z"
|
||||
></path><path
|
||||
class="cls-3"
|
||||
d="M1213.75,1182.65h22.83a0,0,0,0,1,0,0v6.15a2,2,0,0,1-2,2h-18.8a2,2,0,0,1-2-2v-6.15A0,0,0,0,1,1213.75,1182.65Z"
|
||||
></path><path
|
||||
class="cls-3"
|
||||
d="M1297.35,1182.65h22.83a0,0,0,0,1,0,0v6.15a2,2,0,0,1-2,2h-18.8a2,2,0,0,1-2-2v-6.15A0,0,0,0,1,1297.35,1182.65Z"
|
||||
></path><path
|
||||
class="cls-3"
|
||||
d="M1381,1182.65h22.83a0,0,0,0,1,0,0v6.15a2,2,0,0,1-2,2H1383a2,2,0,0,1-2-2v-6.15A0,0,0,0,1,1381,1182.65Z"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M1465.76,777.61v370.21H637.27V831.44a9.18,9.18,0,0,0-9.18-9.18H605.76a4.34,4.34,0,0,1-4.34-4.33V782a4.34,4.34,0,0,1,4.34-4.34Z"
|
||||
></path><line
|
||||
class="cls-8"
|
||||
x1="637.28"
|
||||
y1="831.44"
|
||||
x2="637.28"
|
||||
y2="777.61"
|
||||
></line><path
|
||||
class="cls-9"
|
||||
d="M1472.8,766.19H588.58a2.34,2.34,0,0,0-2.34,2.34v63.55a2.34,2.34,0,0,0,2.34,2.34h29.94a4.74,4.74,0,0,1,4.74,4.74v312.71a5.55,5.55,0,0,0,5.57,5.55h844a4.87,4.87,0,0,0,4.88-4.87V771.07A4.87,4.87,0,0,0,1472.8,766.19Zm-7,381.63H637.27V831.44a9.18,9.18,0,0,0-9.18-9.18H605.76a4.34,4.34,0,0,1-4.34-4.33V782a4.34,4.34,0,0,1,4.34-4.34h860Z"
|
||||
></path><circle
|
||||
class="cls-4"
|
||||
cx="620.54"
|
||||
cy="798.13"
|
||||
r="8.42"
|
||||
></circle><circle
|
||||
class="cls-7"
|
||||
cx="620.54"
|
||||
cy="798.13"
|
||||
r="8.42"
|
||||
></circle><rect
|
||||
class="cls-10"
|
||||
x="564.75"
|
||||
y="905.43"
|
||||
width="11.84"
|
||||
height="114.57"
|
||||
rx="2.32"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="564.75"
|
||||
y="905.43"
|
||||
width="11.84"
|
||||
height="114.57"
|
||||
rx="2.32"
|
||||
></rect><path
|
||||
class="cls-8"
|
||||
d="M1472.8,766.19H588.58a2.34,2.34,0,0,0-2.34,2.34v63.55a2.34,2.34,0,0,0,2.34,2.34h29.94a4.74,4.74,0,0,1,4.74,4.74v312.71a5.55,5.55,0,0,0,5.57,5.55h844a4.87,4.87,0,0,0,4.88-4.87V771.07A4.87,4.87,0,0,0,1472.8,766.19Zm-7,381.63H637.27V831.44a9.18,9.18,0,0,0-9.18-9.18H605.76a4.34,4.34,0,0,1-4.34-4.33V782a4.34,4.34,0,0,1,4.34-4.34h860Z"
|
||||
></path></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.4 KiB |
213
packages/web/public/devices/heltec-vision-master-t190.svg
Normal file
@@ -0,0 +1,213 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="479.57 786.58 1040.84 433.17">
|
||||
<defs><style>
|
||||
.cls-1 {
|
||||
fill: #cccccb;
|
||||
}
|
||||
.cls-2 {
|
||||
fill: #2b2b2b;
|
||||
}
|
||||
.cls-3, .cls-6, .cls-7, .cls-8 {
|
||||
fill: none;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
.cls-3, .cls-6, .cls-7 {
|
||||
stroke: #050606;
|
||||
}
|
||||
.cls-3, .cls-8 {
|
||||
stroke-width: 1.65px;
|
||||
}
|
||||
.cls-4 {
|
||||
fill: #40403f;
|
||||
}
|
||||
.cls-5 {
|
||||
fill: #ddd;
|
||||
}
|
||||
.cls-6 {
|
||||
stroke-width: 1.62px;
|
||||
}
|
||||
.cls-7 {
|
||||
stroke-width: 1.64px;
|
||||
}
|
||||
.cls-8 {
|
||||
stroke: #fff;
|
||||
}
|
||||
.cls-9 {
|
||||
fill: #353535;
|
||||
}
|
||||
.cls-10 {
|
||||
fill: #c08c2d;
|
||||
}
|
||||
</style></defs><g id="Layer_4" data-name="Layer 4"><path
|
||||
class="cls-1"
|
||||
d="M595,923.44H519.6A10.46,10.46,0,0,1,509.14,913V802.7a15.28,15.28,0,0,1,15.28-15.28h979.89a15.29,15.29,0,0,1,15.29,15.29v400.93a15.3,15.3,0,0,1-15.29,15.29H524.42a15.28,15.28,0,0,1-15.28-15.28V1102.1a10.46,10.46,0,0,1,10.46-10.46H595"
|
||||
></path><rect
|
||||
class="cls-2"
|
||||
x="611.37"
|
||||
y="796.48"
|
||||
width="819.83"
|
||||
height="411.47"
|
||||
></rect><line
|
||||
class="cls-3"
|
||||
x1="1441.99"
|
||||
y1="787.41"
|
||||
x2="1441.99"
|
||||
y2="1218.92"
|
||||
></line><path
|
||||
class="cls-4"
|
||||
d="M620.91,851.7v302.78a1.87,1.87,0,0,1-1.87,1.87h-13.8a8.7,8.7,0,0,1-.89,0,10.23,10.23,0,0,1-9.35-10.2v-286a10.24,10.24,0,0,1,9.35-10.2,8.7,8.7,0,0,1,.89,0H619A1.87,1.87,0,0,1,620.91,851.7Z"
|
||||
></path><rect
|
||||
class="cls-5"
|
||||
x="480.4"
|
||||
y="942.42"
|
||||
width="114.6"
|
||||
height="127.58"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="480.4"
|
||||
y="942.42"
|
||||
width="114.6"
|
||||
height="127.58"
|
||||
></rect><path
|
||||
class="cls-6"
|
||||
d="M595,923.44H519.6A10.46,10.46,0,0,1,509.14,913V802.7a15.28,15.28,0,0,1,15.28-15.28h979.89a15.29,15.29,0,0,1,15.29,15.29v400.93a15.3,15.3,0,0,1-15.29,15.29H524.42a15.28,15.28,0,0,1-15.28-15.28V1102.1a10.46,10.46,0,0,1,10.46-10.46H595"
|
||||
></path><path
|
||||
class="cls-2"
|
||||
d="M584.65,970.14H595a0,0,0,0,1,0,0v24.44a0,0,0,0,1,0,0H584.65a3,3,0,0,1-3-3V973.11A3,3,0,0,1,584.65,970.14Z"
|
||||
></path><rect
|
||||
class="cls-2"
|
||||
x="560.58"
|
||||
y="976.5"
|
||||
width="9.04"
|
||||
height="16.58"
|
||||
rx="2.72"
|
||||
></rect><path
|
||||
class="cls-2"
|
||||
d="M584.65,1026.63H595a0,0,0,0,1,0,0v24.44a0,0,0,0,1,0,0H584.65a3,3,0,0,1-3-3v-18.49A3,3,0,0,1,584.65,1026.63Z"
|
||||
></path><rect
|
||||
class="cls-2"
|
||||
x="560.58"
|
||||
y="1028.91"
|
||||
width="9.04"
|
||||
height="16.58"
|
||||
rx="2.72"
|
||||
></rect><path
|
||||
class="cls-3"
|
||||
d="M584.65,970.14H595a0,0,0,0,1,0,0v24.44a0,0,0,0,1,0,0H584.65a3,3,0,0,1-3-3V973.11A3,3,0,0,1,584.65,970.14Z"
|
||||
></path><rect
|
||||
class="cls-3"
|
||||
x="560.58"
|
||||
y="976.5"
|
||||
width="9.04"
|
||||
height="16.58"
|
||||
rx="2.72"
|
||||
></rect><path
|
||||
class="cls-3"
|
||||
d="M584.65,1026.63H595a0,0,0,0,1,0,0v24.44a0,0,0,0,1,0,0H584.65a3,3,0,0,1-3-3v-18.49A3,3,0,0,1,584.65,1026.63Z"
|
||||
></path><rect
|
||||
class="cls-3"
|
||||
x="560.58"
|
||||
y="1028.91"
|
||||
width="9.04"
|
||||
height="16.58"
|
||||
rx="2.72"
|
||||
></rect><polyline
|
||||
class="cls-7"
|
||||
points="611.37 1156.35 611.37 1207.95 1431.2 1207.95 1431.2 796.48 611.37 796.48 611.37 849.83"
|
||||
></polyline><line
|
||||
class="cls-3"
|
||||
x1="611.37"
|
||||
y1="1207.95"
|
||||
x2="611.37"
|
||||
y2="1218.93"
|
||||
></line><line
|
||||
class="cls-3"
|
||||
x1="611.37"
|
||||
y1="796.48"
|
||||
x2="611.37"
|
||||
y2="787.42"
|
||||
></line><rect
|
||||
class="cls-8"
|
||||
x="560.58"
|
||||
y="1107.17"
|
||||
width="18.37"
|
||||
height="41.67"
|
||||
rx="4.91"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="528.51"
|
||||
y="1107.17"
|
||||
width="18.37"
|
||||
height="41.67"
|
||||
rx="4.91"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="560.58"
|
||||
y="1166.28"
|
||||
width="18.37"
|
||||
height="41.67"
|
||||
rx="4.91"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="528.51"
|
||||
y="1166.28"
|
||||
width="18.37"
|
||||
height="41.67"
|
||||
rx="4.91"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="560.58"
|
||||
y="804.46"
|
||||
width="18.37"
|
||||
height="41.67"
|
||||
rx="4.91"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="528.51"
|
||||
y="804.46"
|
||||
width="18.37"
|
||||
height="41.67"
|
||||
rx="4.91"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="560.58"
|
||||
y="863.57"
|
||||
width="18.37"
|
||||
height="41.67"
|
||||
rx="4.91"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="528.51"
|
||||
y="863.57"
|
||||
width="18.37"
|
||||
height="41.67"
|
||||
rx="4.91"
|
||||
></rect><circle
|
||||
class="cls-8"
|
||||
cx="1476.63"
|
||||
cy="831.74"
|
||||
r="27.15"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="1476.63"
|
||||
cy="1173.49"
|
||||
r="27.15"
|
||||
></circle><rect
|
||||
class="cls-9"
|
||||
x="676.15"
|
||||
y="804.6"
|
||||
width="742.79"
|
||||
height="396.03"
|
||||
></rect><path
|
||||
class="cls-10"
|
||||
d="M604.35,849.87v306.44a10.23,10.23,0,0,1-9.35-10.2v-286A10.24,10.24,0,0,1,604.35,849.87Z"
|
||||
></path><path
|
||||
class="cls-3"
|
||||
d="M605.24,849.83H619a1.87,1.87,0,0,1,1.87,1.87v302.78a1.87,1.87,0,0,1-1.87,1.87h-13.8A10.24,10.24,0,0,1,595,1146.11v-286A10.24,10.24,0,0,1,605.24,849.83Z"
|
||||
></path><rect
|
||||
class="cls-6"
|
||||
x="676.15"
|
||||
y="804.6"
|
||||
width="742.79"
|
||||
height="396.03"
|
||||
></rect></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.2 KiB |
510
packages/web/public/devices/heltec-wireless-paper-V1_0.svg
Normal file
@@ -0,0 +1,510 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="505.33 784.55 1040.95 426.95">
|
||||
<defs><style>
|
||||
.cls-1 {
|
||||
fill: #e8eae8;
|
||||
}
|
||||
.cls-2 {
|
||||
fill: #c5c9c9;
|
||||
}
|
||||
.cls-3 {
|
||||
fill: #d3d3d3;
|
||||
}
|
||||
.cls-4 {
|
||||
fill: #c6842a;
|
||||
}
|
||||
.cls-5 {
|
||||
fill: #353535;
|
||||
}
|
||||
.cls-6 {
|
||||
fill: #dbdddb;
|
||||
}
|
||||
.cls-11, .cls-12, .cls-13, .cls-15, .cls-7, .cls-8 {
|
||||
fill: none;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
.cls-12, .cls-13, .cls-7, .cls-8 {
|
||||
stroke: #050606;
|
||||
}
|
||||
.cls-7 {
|
||||
stroke-width: 2.44px;
|
||||
}
|
||||
.cls-11, .cls-15, .cls-8 {
|
||||
stroke-width: 1.22px;
|
||||
}
|
||||
.cls-9 {
|
||||
fill: #ffe091;
|
||||
}
|
||||
.cls-10 {
|
||||
fill: #cbcccb;
|
||||
}
|
||||
.cls-11 {
|
||||
stroke: #b7b7b7;
|
||||
}
|
||||
.cls-12 {
|
||||
stroke-width: 2.36px;
|
||||
}
|
||||
.cls-13 {
|
||||
stroke-width: 1.25px;
|
||||
}
|
||||
.cls-14 {
|
||||
fill: #050606;
|
||||
}
|
||||
.cls-15 {
|
||||
stroke: #ffe091;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
</style></defs><g id="Layer_4" data-name="Layer 4"><path
|
||||
class="cls-1"
|
||||
d="M1421.48,785.78h91.06A22.44,22.44,0,0,1,1535,808.22v379.61a22.45,22.45,0,0,1-22.44,22.45h-91.06"
|
||||
></path><rect
|
||||
class="cls-2"
|
||||
x="1435.08"
|
||||
y="1005.05"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1494.51"
|
||||
y="1005.05"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1435.08"
|
||||
y="1128.44"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1494.51"
|
||||
y="1128.44"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="506.55"
|
||||
y="858.91"
|
||||
width="88.59"
|
||||
height="276.51"
|
||||
></rect><rect
|
||||
class="cls-1"
|
||||
x="579.58"
|
||||
y="785.78"
|
||||
width="191.61"
|
||||
height="424.5"
|
||||
></rect><path
|
||||
class="cls-1"
|
||||
d="M595.13,1210.27H528.66a22.1,22.1,0,0,1-22.11-22.11v-65.81l52.68-22.79-1.8-192.37L506.55,884V807.9a22.11,22.11,0,0,1,22.11-22.12h66.47Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M595.13,901.4H571.68a20,20,0,0,0-13.93,5.48,58.89,58.89,0,0,1-20,12.61,7,7,0,0,0-4.53,6.57v153a7,7,0,0,0,4.53,6.57,58.89,58.89,0,0,1,20,12.61,20,20,0,0,0,13.93,5.49h23.45"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M1535,1014.12h5.26a4.8,4.8,0,0,1,4.8,4.8v104.72a4.8,4.8,0,0,1-4.8,4.8H1535a0,0,0,0,1,0,0V1014.12A0,0,0,0,1,1535,1014.12Z"
|
||||
></path><path
|
||||
class="cls-6"
|
||||
d="M1429.58,785.78v424.49H632.82V1097.4a4.66,4.66,0,0,1,4.67-4.65h28.16a11.68,11.68,0,0,0,11.67-11.68V916.93a12.75,12.75,0,0,0-12.24-12.74l-27.79-7.41a4.66,4.66,0,0,1-4.47-4.64V785.78Z"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M557.43,907.19,506.55,884V807.9a22.11,22.11,0,0,1,22.11-22.12h66.47"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M559.23,1099.56l-52.68,22.79v65.81a22.1,22.1,0,0,0,22.11,22.11h66.47"
|
||||
></path><path
|
||||
class="cls-2"
|
||||
d="M529.59,841.87h22.9a5.13,5.13,0,0,0,4.43-2.56l11.45-19.83a5.12,5.12,0,0,0,0-5.11l-11.45-19.83a5.13,5.13,0,0,0-4.43-2.56h-22.9a5.11,5.11,0,0,0-4.42,2.56l-11.45,19.83a5.08,5.08,0,0,0,0,5.11l11.45,19.83A5.11,5.11,0,0,0,529.59,841.87Z"
|
||||
></path><path
|
||||
class="cls-8"
|
||||
d="M529.59,841.87h22.9a5.13,5.13,0,0,0,4.43-2.56l11.45-19.83a5.12,5.12,0,0,0,0-5.11l-11.45-19.83a5.13,5.13,0,0,0-4.43-2.56h-22.9a5.11,5.11,0,0,0-4.42,2.56l-11.45,19.83a5.08,5.08,0,0,0,0,5.11l11.45,19.83A5.11,5.11,0,0,0,529.59,841.87Z"
|
||||
></path><circle
|
||||
class="cls-9"
|
||||
cx="541.04"
|
||||
cy="816.93"
|
||||
r="14.1"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="541.04"
|
||||
cy="816.93"
|
||||
r="14.1"
|
||||
></circle><path
|
||||
class="cls-2"
|
||||
d="M529.59,1202h22.9a5.12,5.12,0,0,0,4.43-2.55l11.45-19.83a5.12,5.12,0,0,0,0-5.11l-11.45-19.84a5.12,5.12,0,0,0-4.43-2.55h-22.9a5.1,5.1,0,0,0-4.42,2.55l-11.45,19.84a5.08,5.08,0,0,0,0,5.11l11.45,19.83A5.1,5.1,0,0,0,529.59,1202Z"
|
||||
></path><path
|
||||
class="cls-8"
|
||||
d="M529.59,1202h22.9a5.12,5.12,0,0,0,4.43-2.55l11.45-19.83a5.12,5.12,0,0,0,0-5.11l-11.45-19.84a5.12,5.12,0,0,0-4.43-2.55h-22.9a5.1,5.1,0,0,0-4.42,2.55l-11.45,19.84a5.08,5.08,0,0,0,0,5.11l11.45,19.83A5.1,5.1,0,0,0,529.59,1202Z"
|
||||
></path><circle
|
||||
class="cls-9"
|
||||
cx="541.04"
|
||||
cy="1177.09"
|
||||
r="14.1"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="541.04"
|
||||
cy="1177.09"
|
||||
r="14.1"
|
||||
></circle><path
|
||||
class="cls-2"
|
||||
d="M1494.14,841.87H1517a5.11,5.11,0,0,0,4.42-2.56l11.45-19.83a5.08,5.08,0,0,0,0-5.11l-11.45-19.83A5.11,5.11,0,0,0,1517,792h-22.9a5.13,5.13,0,0,0-4.43,2.56l-11.45,19.83a5.12,5.12,0,0,0,0,5.11l11.45,19.83A5.13,5.13,0,0,0,1494.14,841.87Z"
|
||||
></path><path
|
||||
class="cls-8"
|
||||
d="M1494.14,841.87H1517a5.11,5.11,0,0,0,4.42-2.56l11.45-19.83a5.08,5.08,0,0,0,0-5.11l-11.45-19.83A5.11,5.11,0,0,0,1517,792h-22.9a5.13,5.13,0,0,0-4.43,2.56l-11.45,19.83a5.12,5.12,0,0,0,0,5.11l11.45,19.83A5.13,5.13,0,0,0,1494.14,841.87Z"
|
||||
></path><circle
|
||||
class="cls-9"
|
||||
cx="1505.59"
|
||||
cy="816.93"
|
||||
r="14.1"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="1505.59"
|
||||
cy="816.93"
|
||||
r="14.1"
|
||||
></circle><path
|
||||
class="cls-2"
|
||||
d="M1494.14,1202H1517a5.1,5.1,0,0,0,4.42-2.55l11.45-19.83a5.08,5.08,0,0,0,0-5.11l-11.45-19.84a5.1,5.1,0,0,0-4.42-2.55h-22.9a5.12,5.12,0,0,0-4.43,2.55l-11.45,19.84a5.12,5.12,0,0,0,0,5.11l11.45,19.83A5.12,5.12,0,0,0,1494.14,1202Z"
|
||||
></path><path
|
||||
class="cls-8"
|
||||
d="M1494.14,1202H1517a5.1,5.1,0,0,0,4.42-2.55l11.45-19.83a5.08,5.08,0,0,0,0-5.11l-11.45-19.84a5.1,5.1,0,0,0-4.42-2.55h-22.9a5.12,5.12,0,0,0-4.43,2.55l-11.45,19.84a5.12,5.12,0,0,0,0,5.11l11.45,19.83A5.12,5.12,0,0,0,1494.14,1202Z"
|
||||
></path><circle
|
||||
class="cls-9"
|
||||
cx="1505.59"
|
||||
cy="1177.09"
|
||||
r="14.1"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="1505.59"
|
||||
cy="1177.09"
|
||||
r="14.1"
|
||||
></circle><path
|
||||
class="cls-1"
|
||||
d="M1412.61,816.13v360.16h-755a2.5,2.5,0,0,1-2.51-2.5v-64.32a2.5,2.5,0,0,1,2.51-2.5h30.47a12.81,12.81,0,0,0,12.81-12.82V894.25a12.81,12.81,0,0,0-12.81-12.82H657.58a2.5,2.5,0,0,1-2.51-2.5V818.64a2.51,2.51,0,0,1,2.51-2.51Z"
|
||||
></path><circle
|
||||
class="cls-10"
|
||||
cx="672.06"
|
||||
cy="1154.92"
|
||||
r="8.89"
|
||||
></circle><circle
|
||||
class="cls-11"
|
||||
cx="672.06"
|
||||
cy="1154.92"
|
||||
r="8.89"
|
||||
></circle><circle
|
||||
class="cls-10"
|
||||
cx="672.06"
|
||||
cy="838.98"
|
||||
r="8.89"
|
||||
></circle><circle
|
||||
class="cls-11"
|
||||
cx="672.06"
|
||||
cy="838.98"
|
||||
r="8.89"
|
||||
></circle><line
|
||||
class="cls-7"
|
||||
x1="506.55"
|
||||
y1="884.01"
|
||||
x2="506.55"
|
||||
y2="1122.35"
|
||||
></line><path
|
||||
class="cls-12"
|
||||
d="M595.13,901.4H571.68a20,20,0,0,0-13.93,5.48,58.89,58.89,0,0,1-20,12.61,7,7,0,0,0-4.53,6.57v153a7,7,0,0,0,4.53,6.57,58.89,58.89,0,0,1,20,12.61,20,20,0,0,0,13.93,5.49h23.45"
|
||||
></path><rect
|
||||
class="cls-2"
|
||||
x="621.34"
|
||||
y="935.2"
|
||||
width="11.49"
|
||||
height="113.49"
|
||||
></rect><rect
|
||||
class="cls-13"
|
||||
x="621.34"
|
||||
y="935.2"
|
||||
width="11.49"
|
||||
height="113.49"
|
||||
></rect><rect
|
||||
class="cls-1"
|
||||
x="712.79"
|
||||
y="826.99"
|
||||
width="685.79"
|
||||
height="336.38"
|
||||
></rect><path
|
||||
class="cls-7"
|
||||
d="M1421.48,785.78h91.06A22.44,22.44,0,0,1,1535,808.22v379.61a22.45,22.45,0,0,1-22.44,22.45h-91.06"
|
||||
></path><rect
|
||||
class="cls-8"
|
||||
x="1435.08"
|
||||
y="1005.05"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="1494.51"
|
||||
y="1005.05"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="1435.08"
|
||||
y="1128.44"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="1494.51"
|
||||
y="1128.44"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><path
|
||||
class="cls-7"
|
||||
d="M1535,1014.12h5.26a4.8,4.8,0,0,1,4.8,4.8v104.72a4.8,4.8,0,0,1-4.8,4.8H1535a0,0,0,0,1,0,0V1014.12A0,0,0,0,1,1535,1014.12Z"
|
||||
></path><circle
|
||||
class="cls-14"
|
||||
cx="1453.85"
|
||||
cy="1032.4"
|
||||
r="5.56"
|
||||
></circle><circle
|
||||
class="cls-14"
|
||||
cx="1453.85"
|
||||
cy="1114.38"
|
||||
r="5.56"
|
||||
></circle><line
|
||||
class="cls-11"
|
||||
x1="688.05"
|
||||
y1="1106.97"
|
||||
x2="688.05"
|
||||
y2="1176.29"
|
||||
></line><line
|
||||
class="cls-11"
|
||||
x1="688.05"
|
||||
y1="881.43"
|
||||
x2="688.05"
|
||||
y2="816.13"
|
||||
></line><rect
|
||||
class="cls-11"
|
||||
x="712.79"
|
||||
y="826.99"
|
||||
width="685.79"
|
||||
height="336.38"
|
||||
></rect><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="928.91"
|
||||
x2="568.22"
|
||||
y2="928.91"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="933.4"
|
||||
x2="568.22"
|
||||
y2="933.4"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="937.89"
|
||||
x2="568.22"
|
||||
y2="937.89"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="942.37"
|
||||
x2="568.22"
|
||||
y2="942.37"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="946.86"
|
||||
x2="568.22"
|
||||
y2="946.86"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="951.35"
|
||||
x2="568.22"
|
||||
y2="951.35"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="955.83"
|
||||
x2="568.22"
|
||||
y2="955.83"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="960.32"
|
||||
x2="568.22"
|
||||
y2="960.32"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="964.81"
|
||||
x2="568.22"
|
||||
y2="964.81"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="969.29"
|
||||
x2="568.22"
|
||||
y2="969.29"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="973.78"
|
||||
x2="568.22"
|
||||
y2="973.78"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="978.26"
|
||||
x2="568.22"
|
||||
y2="978.26"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="982.75"
|
||||
x2="568.22"
|
||||
y2="982.75"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="987.24"
|
||||
x2="568.22"
|
||||
y2="987.24"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="991.72"
|
||||
x2="568.22"
|
||||
y2="991.72"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="996.21"
|
||||
x2="568.22"
|
||||
y2="996.21"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1000.7"
|
||||
x2="568.22"
|
||||
y2="1000.7"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1005.18"
|
||||
x2="568.22"
|
||||
y2="1005.18"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1009.67"
|
||||
x2="568.22"
|
||||
y2="1009.67"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1014.16"
|
||||
x2="568.22"
|
||||
y2="1014.16"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1018.64"
|
||||
x2="568.22"
|
||||
y2="1018.64"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1023.13"
|
||||
x2="568.22"
|
||||
y2="1023.13"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1027.62"
|
||||
x2="568.22"
|
||||
y2="1027.62"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1032.1"
|
||||
x2="568.22"
|
||||
y2="1032.1"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1036.59"
|
||||
x2="568.22"
|
||||
y2="1036.59"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1041.08"
|
||||
x2="568.22"
|
||||
y2="1041.08"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1045.56"
|
||||
x2="568.22"
|
||||
y2="1045.56"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1050.05"
|
||||
x2="568.22"
|
||||
y2="1050.05"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1054.53"
|
||||
x2="568.22"
|
||||
y2="1054.53"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1059.02"
|
||||
x2="568.22"
|
||||
y2="1059.02"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1063.51"
|
||||
x2="568.22"
|
||||
y2="1063.51"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1067.99"
|
||||
x2="568.22"
|
||||
y2="1067.99"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1072.48"
|
||||
x2="568.22"
|
||||
y2="1072.48"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1076.97"
|
||||
x2="568.22"
|
||||
y2="1076.97"
|
||||
></line><path
|
||||
class="cls-11"
|
||||
d="M632.82,1210.27V1097.4a4.66,4.66,0,0,1,4.67-4.65h28.16a11.68,11.68,0,0,0,11.67-11.68V916.93c0-6.85-5.05-10.17-12.24-12.74l-27.79-7.41a4.66,4.66,0,0,1-4.47-4.64V785.78"
|
||||
></path><path
|
||||
class="cls-11"
|
||||
d="M1412.61,816.13v360.16h-755a2.5,2.5,0,0,1-2.51-2.5v-64.32a2.5,2.5,0,0,1,2.51-2.5h30.47a12.81,12.81,0,0,0,12.81-12.82V894.25a12.81,12.81,0,0,0-12.81-12.82H657.58a2.5,2.5,0,0,1-2.51-2.5V818.64a2.51,2.51,0,0,1,2.51-2.51Z"
|
||||
></path><polyline
|
||||
class="cls-7"
|
||||
points="632.82 785.77 1429.58 785.77 1429.58 1210.27 632.82 1210.27"
|
||||
></polyline><polyline
|
||||
class="cls-7"
|
||||
points="632.82 1210.27 595.13 1210.27 595.13 785.77 632.82 785.77"
|
||||
></polyline></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
510
packages/web/public/devices/heltec-wireless-paper.svg
Normal file
@@ -0,0 +1,510 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="505.33 784.55 1040.95 426.95">
|
||||
<defs><style>
|
||||
.cls-1 {
|
||||
fill: #e8eae8;
|
||||
}
|
||||
.cls-2 {
|
||||
fill: #c5c9c9;
|
||||
}
|
||||
.cls-3 {
|
||||
fill: #d3d3d3;
|
||||
}
|
||||
.cls-4 {
|
||||
fill: #c6842a;
|
||||
}
|
||||
.cls-5 {
|
||||
fill: #353535;
|
||||
}
|
||||
.cls-6 {
|
||||
fill: #dbdddb;
|
||||
}
|
||||
.cls-11, .cls-12, .cls-13, .cls-15, .cls-7, .cls-8 {
|
||||
fill: none;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
.cls-12, .cls-13, .cls-7, .cls-8 {
|
||||
stroke: #050606;
|
||||
}
|
||||
.cls-7 {
|
||||
stroke-width: 2.44px;
|
||||
}
|
||||
.cls-11, .cls-15, .cls-8 {
|
||||
stroke-width: 1.22px;
|
||||
}
|
||||
.cls-9 {
|
||||
fill: #ffe091;
|
||||
}
|
||||
.cls-10 {
|
||||
fill: #cbcccb;
|
||||
}
|
||||
.cls-11 {
|
||||
stroke: #b7b7b7;
|
||||
}
|
||||
.cls-12 {
|
||||
stroke-width: 2.36px;
|
||||
}
|
||||
.cls-13 {
|
||||
stroke-width: 1.25px;
|
||||
}
|
||||
.cls-14 {
|
||||
fill: #050606;
|
||||
}
|
||||
.cls-15 {
|
||||
stroke: #ffe091;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
</style></defs><g id="Layer_4" data-name="Layer 4"><path
|
||||
class="cls-1"
|
||||
d="M1421.48,785.78h91.06A22.44,22.44,0,0,1,1535,808.22v379.61a22.45,22.45,0,0,1-22.44,22.45h-91.06"
|
||||
></path><rect
|
||||
class="cls-2"
|
||||
x="1435.08"
|
||||
y="1005.05"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1494.51"
|
||||
y="1005.05"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1435.08"
|
||||
y="1128.44"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1494.51"
|
||||
y="1128.44"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="506.55"
|
||||
y="858.91"
|
||||
width="88.59"
|
||||
height="276.51"
|
||||
></rect><rect
|
||||
class="cls-1"
|
||||
x="579.58"
|
||||
y="785.78"
|
||||
width="191.61"
|
||||
height="424.5"
|
||||
></rect><path
|
||||
class="cls-1"
|
||||
d="M595.13,1210.27H528.66a22.1,22.1,0,0,1-22.11-22.11v-65.81l52.68-22.79-1.8-192.37L506.55,884V807.9a22.11,22.11,0,0,1,22.11-22.12h66.47Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M595.13,901.4H571.68a20,20,0,0,0-13.93,5.48,58.89,58.89,0,0,1-20,12.61,7,7,0,0,0-4.53,6.57v153a7,7,0,0,0,4.53,6.57,58.89,58.89,0,0,1,20,12.61,20,20,0,0,0,13.93,5.49h23.45"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M1535,1014.12h5.26a4.8,4.8,0,0,1,4.8,4.8v104.72a4.8,4.8,0,0,1-4.8,4.8H1535a0,0,0,0,1,0,0V1014.12A0,0,0,0,1,1535,1014.12Z"
|
||||
></path><path
|
||||
class="cls-6"
|
||||
d="M1429.58,785.78v424.49H632.82V1097.4a4.66,4.66,0,0,1,4.67-4.65h28.16a11.68,11.68,0,0,0,11.67-11.68V916.93a12.75,12.75,0,0,0-12.24-12.74l-27.79-7.41a4.66,4.66,0,0,1-4.47-4.64V785.78Z"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M557.43,907.19,506.55,884V807.9a22.11,22.11,0,0,1,22.11-22.12h66.47"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M559.23,1099.56l-52.68,22.79v65.81a22.1,22.1,0,0,0,22.11,22.11h66.47"
|
||||
></path><path
|
||||
class="cls-2"
|
||||
d="M529.59,841.87h22.9a5.13,5.13,0,0,0,4.43-2.56l11.45-19.83a5.12,5.12,0,0,0,0-5.11l-11.45-19.83a5.13,5.13,0,0,0-4.43-2.56h-22.9a5.11,5.11,0,0,0-4.42,2.56l-11.45,19.83a5.08,5.08,0,0,0,0,5.11l11.45,19.83A5.11,5.11,0,0,0,529.59,841.87Z"
|
||||
></path><path
|
||||
class="cls-8"
|
||||
d="M529.59,841.87h22.9a5.13,5.13,0,0,0,4.43-2.56l11.45-19.83a5.12,5.12,0,0,0,0-5.11l-11.45-19.83a5.13,5.13,0,0,0-4.43-2.56h-22.9a5.11,5.11,0,0,0-4.42,2.56l-11.45,19.83a5.08,5.08,0,0,0,0,5.11l11.45,19.83A5.11,5.11,0,0,0,529.59,841.87Z"
|
||||
></path><circle
|
||||
class="cls-9"
|
||||
cx="541.04"
|
||||
cy="816.93"
|
||||
r="14.1"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="541.04"
|
||||
cy="816.93"
|
||||
r="14.1"
|
||||
></circle><path
|
||||
class="cls-2"
|
||||
d="M529.59,1202h22.9a5.12,5.12,0,0,0,4.43-2.55l11.45-19.83a5.12,5.12,0,0,0,0-5.11l-11.45-19.84a5.12,5.12,0,0,0-4.43-2.55h-22.9a5.1,5.1,0,0,0-4.42,2.55l-11.45,19.84a5.08,5.08,0,0,0,0,5.11l11.45,19.83A5.1,5.1,0,0,0,529.59,1202Z"
|
||||
></path><path
|
||||
class="cls-8"
|
||||
d="M529.59,1202h22.9a5.12,5.12,0,0,0,4.43-2.55l11.45-19.83a5.12,5.12,0,0,0,0-5.11l-11.45-19.84a5.12,5.12,0,0,0-4.43-2.55h-22.9a5.1,5.1,0,0,0-4.42,2.55l-11.45,19.84a5.08,5.08,0,0,0,0,5.11l11.45,19.83A5.1,5.1,0,0,0,529.59,1202Z"
|
||||
></path><circle
|
||||
class="cls-9"
|
||||
cx="541.04"
|
||||
cy="1177.09"
|
||||
r="14.1"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="541.04"
|
||||
cy="1177.09"
|
||||
r="14.1"
|
||||
></circle><path
|
||||
class="cls-2"
|
||||
d="M1494.14,841.87H1517a5.11,5.11,0,0,0,4.42-2.56l11.45-19.83a5.08,5.08,0,0,0,0-5.11l-11.45-19.83A5.11,5.11,0,0,0,1517,792h-22.9a5.13,5.13,0,0,0-4.43,2.56l-11.45,19.83a5.12,5.12,0,0,0,0,5.11l11.45,19.83A5.13,5.13,0,0,0,1494.14,841.87Z"
|
||||
></path><path
|
||||
class="cls-8"
|
||||
d="M1494.14,841.87H1517a5.11,5.11,0,0,0,4.42-2.56l11.45-19.83a5.08,5.08,0,0,0,0-5.11l-11.45-19.83A5.11,5.11,0,0,0,1517,792h-22.9a5.13,5.13,0,0,0-4.43,2.56l-11.45,19.83a5.12,5.12,0,0,0,0,5.11l11.45,19.83A5.13,5.13,0,0,0,1494.14,841.87Z"
|
||||
></path><circle
|
||||
class="cls-9"
|
||||
cx="1505.59"
|
||||
cy="816.93"
|
||||
r="14.1"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="1505.59"
|
||||
cy="816.93"
|
||||
r="14.1"
|
||||
></circle><path
|
||||
class="cls-2"
|
||||
d="M1494.14,1202H1517a5.1,5.1,0,0,0,4.42-2.55l11.45-19.83a5.08,5.08,0,0,0,0-5.11l-11.45-19.84a5.1,5.1,0,0,0-4.42-2.55h-22.9a5.12,5.12,0,0,0-4.43,2.55l-11.45,19.84a5.12,5.12,0,0,0,0,5.11l11.45,19.83A5.12,5.12,0,0,0,1494.14,1202Z"
|
||||
></path><path
|
||||
class="cls-8"
|
||||
d="M1494.14,1202H1517a5.1,5.1,0,0,0,4.42-2.55l11.45-19.83a5.08,5.08,0,0,0,0-5.11l-11.45-19.84a5.1,5.1,0,0,0-4.42-2.55h-22.9a5.12,5.12,0,0,0-4.43,2.55l-11.45,19.84a5.12,5.12,0,0,0,0,5.11l11.45,19.83A5.12,5.12,0,0,0,1494.14,1202Z"
|
||||
></path><circle
|
||||
class="cls-9"
|
||||
cx="1505.59"
|
||||
cy="1177.09"
|
||||
r="14.1"
|
||||
></circle><circle
|
||||
class="cls-8"
|
||||
cx="1505.59"
|
||||
cy="1177.09"
|
||||
r="14.1"
|
||||
></circle><path
|
||||
class="cls-1"
|
||||
d="M1412.61,816.13v360.16h-755a2.5,2.5,0,0,1-2.51-2.5v-64.32a2.5,2.5,0,0,1,2.51-2.5h30.47a12.81,12.81,0,0,0,12.81-12.82V894.25a12.81,12.81,0,0,0-12.81-12.82H657.58a2.5,2.5,0,0,1-2.51-2.5V818.64a2.51,2.51,0,0,1,2.51-2.51Z"
|
||||
></path><circle
|
||||
class="cls-10"
|
||||
cx="672.06"
|
||||
cy="1154.92"
|
||||
r="8.89"
|
||||
></circle><circle
|
||||
class="cls-11"
|
||||
cx="672.06"
|
||||
cy="1154.92"
|
||||
r="8.89"
|
||||
></circle><circle
|
||||
class="cls-10"
|
||||
cx="672.06"
|
||||
cy="838.98"
|
||||
r="8.89"
|
||||
></circle><circle
|
||||
class="cls-11"
|
||||
cx="672.06"
|
||||
cy="838.98"
|
||||
r="8.89"
|
||||
></circle><line
|
||||
class="cls-7"
|
||||
x1="506.55"
|
||||
y1="884.01"
|
||||
x2="506.55"
|
||||
y2="1122.35"
|
||||
></line><path
|
||||
class="cls-12"
|
||||
d="M595.13,901.4H571.68a20,20,0,0,0-13.93,5.48,58.89,58.89,0,0,1-20,12.61,7,7,0,0,0-4.53,6.57v153a7,7,0,0,0,4.53,6.57,58.89,58.89,0,0,1,20,12.61,20,20,0,0,0,13.93,5.49h23.45"
|
||||
></path><rect
|
||||
class="cls-2"
|
||||
x="621.34"
|
||||
y="935.2"
|
||||
width="11.49"
|
||||
height="113.49"
|
||||
></rect><rect
|
||||
class="cls-13"
|
||||
x="621.34"
|
||||
y="935.2"
|
||||
width="11.49"
|
||||
height="113.49"
|
||||
></rect><rect
|
||||
class="cls-1"
|
||||
x="712.79"
|
||||
y="826.99"
|
||||
width="685.79"
|
||||
height="336.38"
|
||||
></rect><path
|
||||
class="cls-7"
|
||||
d="M1421.48,785.78h91.06A22.44,22.44,0,0,1,1535,808.22v379.61a22.45,22.45,0,0,1-22.44,22.45h-91.06"
|
||||
></path><rect
|
||||
class="cls-8"
|
||||
x="1435.08"
|
||||
y="1005.05"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="1494.51"
|
||||
y="1005.05"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="1435.08"
|
||||
y="1128.44"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><rect
|
||||
class="cls-8"
|
||||
x="1494.51"
|
||||
y="1128.44"
|
||||
width="26.44"
|
||||
height="11.33"
|
||||
rx="5.67"
|
||||
></rect><path
|
||||
class="cls-7"
|
||||
d="M1535,1014.12h5.26a4.8,4.8,0,0,1,4.8,4.8v104.72a4.8,4.8,0,0,1-4.8,4.8H1535a0,0,0,0,1,0,0V1014.12A0,0,0,0,1,1535,1014.12Z"
|
||||
></path><circle
|
||||
class="cls-14"
|
||||
cx="1453.85"
|
||||
cy="1032.4"
|
||||
r="5.56"
|
||||
></circle><circle
|
||||
class="cls-14"
|
||||
cx="1453.85"
|
||||
cy="1114.38"
|
||||
r="5.56"
|
||||
></circle><line
|
||||
class="cls-11"
|
||||
x1="688.05"
|
||||
y1="1106.97"
|
||||
x2="688.05"
|
||||
y2="1176.29"
|
||||
></line><line
|
||||
class="cls-11"
|
||||
x1="688.05"
|
||||
y1="881.43"
|
||||
x2="688.05"
|
||||
y2="816.13"
|
||||
></line><rect
|
||||
class="cls-11"
|
||||
x="712.79"
|
||||
y="826.99"
|
||||
width="685.79"
|
||||
height="336.38"
|
||||
></rect><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="928.91"
|
||||
x2="568.22"
|
||||
y2="928.91"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="933.4"
|
||||
x2="568.22"
|
||||
y2="933.4"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="937.89"
|
||||
x2="568.22"
|
||||
y2="937.89"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="942.37"
|
||||
x2="568.22"
|
||||
y2="942.37"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="946.86"
|
||||
x2="568.22"
|
||||
y2="946.86"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="951.35"
|
||||
x2="568.22"
|
||||
y2="951.35"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="955.83"
|
||||
x2="568.22"
|
||||
y2="955.83"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="960.32"
|
||||
x2="568.22"
|
||||
y2="960.32"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="964.81"
|
||||
x2="568.22"
|
||||
y2="964.81"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="969.29"
|
||||
x2="568.22"
|
||||
y2="969.29"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="973.78"
|
||||
x2="568.22"
|
||||
y2="973.78"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="978.26"
|
||||
x2="568.22"
|
||||
y2="978.26"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="982.75"
|
||||
x2="568.22"
|
||||
y2="982.75"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="987.24"
|
||||
x2="568.22"
|
||||
y2="987.24"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="991.72"
|
||||
x2="568.22"
|
||||
y2="991.72"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="996.21"
|
||||
x2="568.22"
|
||||
y2="996.21"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1000.7"
|
||||
x2="568.22"
|
||||
y2="1000.7"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1005.18"
|
||||
x2="568.22"
|
||||
y2="1005.18"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1009.67"
|
||||
x2="568.22"
|
||||
y2="1009.67"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1014.16"
|
||||
x2="568.22"
|
||||
y2="1014.16"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1018.64"
|
||||
x2="568.22"
|
||||
y2="1018.64"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1023.13"
|
||||
x2="568.22"
|
||||
y2="1023.13"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1027.62"
|
||||
x2="568.22"
|
||||
y2="1027.62"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1032.1"
|
||||
x2="568.22"
|
||||
y2="1032.1"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1036.59"
|
||||
x2="568.22"
|
||||
y2="1036.59"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1041.08"
|
||||
x2="568.22"
|
||||
y2="1041.08"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1045.56"
|
||||
x2="568.22"
|
||||
y2="1045.56"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1050.05"
|
||||
x2="568.22"
|
||||
y2="1050.05"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1054.53"
|
||||
x2="568.22"
|
||||
y2="1054.53"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1059.02"
|
||||
x2="568.22"
|
||||
y2="1059.02"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1063.51"
|
||||
x2="568.22"
|
||||
y2="1063.51"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1067.99"
|
||||
x2="568.22"
|
||||
y2="1067.99"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1072.48"
|
||||
x2="568.22"
|
||||
y2="1072.48"
|
||||
></line><line
|
||||
class="cls-15"
|
||||
x1="538.46"
|
||||
y1="1076.97"
|
||||
x2="568.22"
|
||||
y2="1076.97"
|
||||
></line><path
|
||||
class="cls-11"
|
||||
d="M632.82,1210.27V1097.4a4.66,4.66,0,0,1,4.67-4.65h28.16a11.68,11.68,0,0,0,11.67-11.68V916.93c0-6.85-5.05-10.17-12.24-12.74l-27.79-7.41a4.66,4.66,0,0,1-4.47-4.64V785.78"
|
||||
></path><path
|
||||
class="cls-11"
|
||||
d="M1412.61,816.13v360.16h-755a2.5,2.5,0,0,1-2.51-2.5v-64.32a2.5,2.5,0,0,1,2.51-2.5h30.47a12.81,12.81,0,0,0,12.81-12.82V894.25a12.81,12.81,0,0,0-12.81-12.82H657.58a2.5,2.5,0,0,1-2.51-2.5V818.64a2.51,2.51,0,0,1,2.51-2.51Z"
|
||||
></path><polyline
|
||||
class="cls-7"
|
||||
points="632.82 785.77 1429.58 785.77 1429.58 1210.27 632.82 1210.27"
|
||||
></polyline><polyline
|
||||
class="cls-7"
|
||||
points="632.82 1210.27 595.13 1210.27 595.13 785.77 632.82 785.77"
|
||||
></polyline></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
2031
packages/web/public/devices/heltec-wireless-tracker-V1-0.svg
Normal file
|
After Width: | Height: | Size: 95 KiB |
2031
packages/web/public/devices/heltec-wireless-tracker.svg
Normal file
|
After Width: | Height: | Size: 95 KiB |
1068
packages/web/public/devices/heltec-wsl-v3.svg
Normal file
|
After Width: | Height: | Size: 47 KiB |
216
packages/web/public/devices/nano-g2-ultra.svg
Normal file
@@ -0,0 +1,216 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="340.47 241 263.8 451.32">
|
||||
<defs><style>
|
||||
.cls-1 {
|
||||
fill: #434143;
|
||||
}
|
||||
.cls-2, .cls-6, .cls-7 {
|
||||
fill: none;
|
||||
}
|
||||
.cls-2 {
|
||||
stroke: #050606;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
.cls-3 {
|
||||
fill: #2b2b2b;
|
||||
}
|
||||
.cls-4 {
|
||||
fill: #181818;
|
||||
}
|
||||
.cls-5 {
|
||||
fill: #e8eae8;
|
||||
}
|
||||
.cls-6, .cls-7 {
|
||||
stroke: #e8eae8;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.cls-7 {
|
||||
stroke-width: 2px;
|
||||
}
|
||||
</style></defs><g id="Layer_2" data-name="Layer 2"><rect
|
||||
class="cls-1"
|
||||
x="340.97"
|
||||
y="241.5"
|
||||
width="262.8"
|
||||
height="450.32"
|
||||
rx="27.43"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="340.97"
|
||||
y="241.5"
|
||||
width="262.8"
|
||||
height="450.32"
|
||||
rx="27.43"
|
||||
></rect><circle
|
||||
class="cls-3"
|
||||
cx="364.66"
|
||||
cy="264.01"
|
||||
r="10.92"
|
||||
></circle><circle
|
||||
class="cls-2"
|
||||
cx="364.66"
|
||||
cy="264.01"
|
||||
r="10.92"
|
||||
></circle><path
|
||||
class="cls-4"
|
||||
d="M372.05,264a2.39,2.39,0,0,1-2.39,2.38h-2.61V269a2.38,2.38,0,1,1-4.76,0v-2.62h-2.63a2.39,2.39,0,1,1,0-4.77h2.63V259a2.38,2.38,0,0,1,2.37-2.38,2.39,2.39,0,0,1,2.39,2.38v2.62h2.61A2.4,2.4,0,0,1,372.05,264Z"
|
||||
></path><circle
|
||||
class="cls-3"
|
||||
cx="579.41"
|
||||
cy="264.01"
|
||||
r="10.92"
|
||||
></circle><circle
|
||||
class="cls-2"
|
||||
cx="579.41"
|
||||
cy="264.01"
|
||||
r="10.92"
|
||||
></circle><path
|
||||
class="cls-4"
|
||||
d="M586.79,264a2.39,2.39,0,0,1-2.38,2.38h-2.62V269a2.38,2.38,0,1,1-4.76,0v-2.62h-2.62a2.39,2.39,0,1,1,0-4.77H577V259a2.38,2.38,0,0,1,4.76,0v2.62h2.62A2.39,2.39,0,0,1,586.79,264Z"
|
||||
></path><circle
|
||||
class="cls-3"
|
||||
cx="364.66"
|
||||
cy="666.6"
|
||||
r="10.92"
|
||||
></circle><circle
|
||||
class="cls-2"
|
||||
cx="364.66"
|
||||
cy="666.6"
|
||||
r="10.92"
|
||||
></circle><path
|
||||
class="cls-4"
|
||||
d="M372.05,666.61a2.39,2.39,0,0,1-2.39,2.38h-2.61v2.62a2.38,2.38,0,1,1-4.76,0V669h-2.63a2.39,2.39,0,1,1,0-4.77h2.63V661.6a2.38,2.38,0,0,1,2.37-2.38,2.39,2.39,0,0,1,2.39,2.38v2.62h2.61A2.4,2.4,0,0,1,372.05,666.61Z"
|
||||
></path><circle
|
||||
class="cls-3"
|
||||
cx="579.41"
|
||||
cy="666.6"
|
||||
r="10.92"
|
||||
></circle><circle
|
||||
class="cls-2"
|
||||
cx="579.41"
|
||||
cy="666.6"
|
||||
r="10.92"
|
||||
></circle><path
|
||||
class="cls-4"
|
||||
d="M586.79,666.61a2.39,2.39,0,0,1-2.38,2.38h-2.62v2.62a2.38,2.38,0,0,1-4.76,0V669h-2.62a2.39,2.39,0,1,1,0-4.77H577V661.6a2.38,2.38,0,0,1,4.76,0v2.62h2.62A2.39,2.39,0,0,1,586.79,666.61Z"
|
||||
></path><circle
|
||||
class="cls-3"
|
||||
cx="579.41"
|
||||
cy="440.79"
|
||||
r="10.92"
|
||||
></circle><circle
|
||||
class="cls-2"
|
||||
cx="579.41"
|
||||
cy="440.79"
|
||||
r="10.92"
|
||||
></circle><path
|
||||
class="cls-4"
|
||||
d="M586.79,440.79a2.39,2.39,0,0,1-2.38,2.38h-2.62v2.62a2.38,2.38,0,1,1-4.76,0v-2.62h-2.62a2.39,2.39,0,1,1,0-4.77H577v-2.62a2.38,2.38,0,0,1,4.76,0v2.62h2.62A2.39,2.39,0,0,1,586.79,440.79Z"
|
||||
></path><circle
|
||||
class="cls-3"
|
||||
cx="361.13"
|
||||
cy="442.81"
|
||||
r="10.92"
|
||||
></circle><circle
|
||||
class="cls-2"
|
||||
cx="361.13"
|
||||
cy="442.81"
|
||||
r="10.92"
|
||||
></circle><path
|
||||
class="cls-4"
|
||||
d="M368.51,442.81a2.39,2.39,0,0,1-2.38,2.38h-2.62v2.62a2.38,2.38,0,1,1-4.76,0v-2.62h-2.62a2.39,2.39,0,1,1,0-4.77h2.62V437.8a2.38,2.38,0,0,1,4.76,0v2.62h2.62A2.39,2.39,0,0,1,368.51,442.81Z"
|
||||
></path><rect
|
||||
class="cls-5"
|
||||
x="442.52"
|
||||
y="591.7"
|
||||
width="6.5"
|
||||
height="54.62"
|
||||
transform="translate(432.79 -143.7) rotate(34.78)"
|
||||
></rect><path
|
||||
class="cls-5"
|
||||
d="M521.39,639.18l-5.34,3.71L489,604.34l-26.94,39-5.34-3.71,28.32-41,1.06-1.53a3.53,3.53,0,0,1,5.8,0l1.06,1.53Z"
|
||||
></path><rect
|
||||
class="cls-3"
|
||||
x="407.64"
|
||||
y="511.78"
|
||||
width="135.85"
|
||||
height="67.27"
|
||||
rx="3.52"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="407.64"
|
||||
y="511.78"
|
||||
width="135.85"
|
||||
height="67.27"
|
||||
rx="3.52"
|
||||
></rect><circle class="cls-6" cx="586.93" cy="479.19" r="9.9"></circle><rect
|
||||
class="cls-5"
|
||||
x="581.12"
|
||||
y="478.38"
|
||||
width="9.09"
|
||||
height="1.63"
|
||||
rx="0.82"
|
||||
></rect><circle
|
||||
class="cls-5"
|
||||
cx="591.91"
|
||||
cy="479.19"
|
||||
r="0.83"
|
||||
></circle><path
|
||||
class="cls-7"
|
||||
d="M592.84,629.48a7.9,7.9,0,1,1-.29-6.3"
|
||||
></path><line
|
||||
class="cls-7"
|
||||
x1="586.78"
|
||||
y1="626.67"
|
||||
x2="594.43"
|
||||
y2="626.67"
|
||||
></line><path
|
||||
class="cls-5"
|
||||
d="M408.88,655.16h3.51l4.58,7.29v-7.29h3.55v13.18H417l-4.56-7.24v7.24h-3.53Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M425.87,661.88l-3.23-.37a4.06,4.06,0,0,1,.53-1.44,3,3,0,0,1,1-.91,3.82,3.82,0,0,1,1.28-.43,8.86,8.86,0,0,1,1.76-.16,13.09,13.09,0,0,1,2.44.19,3,3,0,0,1,1.54.77,2.86,2.86,0,0,1,.68,1.14,4.67,4.67,0,0,1,.25,1.42v4.22a5.74,5.74,0,0,0,.07,1.05,5.4,5.4,0,0,0,.35,1h-3.17a3.65,3.65,0,0,1-.25-.56,4.32,4.32,0,0,1-.12-.61,4.38,4.38,0,0,1-1.32,1,5.18,5.18,0,0,1-2.08.39,3.32,3.32,0,0,1-2.4-.79,2.61,2.61,0,0,1-.81-2A2.71,2.71,0,0,1,423,664a3.89,3.89,0,0,1,2.18-1c1.27-.28,2.09-.47,2.47-.58a11.09,11.09,0,0,0,1.19-.44,1.35,1.35,0,0,0-.26-.94,1.21,1.21,0,0,0-.9-.27,2.22,2.22,0,0,0-1.25.29A1.6,1.6,0,0,0,425.87,661.88Zm2.93,1.93a12.94,12.94,0,0,1-1.45.47,3.35,3.35,0,0,0-1.31.59,1,1,0,0,0,0,1.38,1.14,1.14,0,0,0,.82.27,2,2,0,0,0,1.05-.3,1.7,1.7,0,0,0,.69-.72,2.66,2.66,0,0,0,.2-1.11Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M434.13,658.79h3.15v1.55A5,5,0,0,1,438.7,659a3.58,3.58,0,0,1,1.76-.41,2.75,2.75,0,0,1,2.2.91,4.13,4.13,0,0,1,.79,2.79v6.07h-3.39v-5.25a2,2,0,0,0-.31-1.27,1,1,0,0,0-.86-.38,1.2,1.2,0,0,0-1,.51,3.12,3.12,0,0,0-.38,1.8v4.59h-3.38Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M445.06,663.59a5,5,0,0,1,1.36-3.6,5.55,5.55,0,0,1,7.68.25,5.08,5.08,0,0,1,1.08,3.3,5,5,0,0,1-1.35,3.61,5.64,5.64,0,0,1-7.16.23A4.81,4.81,0,0,1,445.06,663.59Zm3.38,0a3.06,3.06,0,0,0,.48,1.89,1.49,1.49,0,0,0,2.4,0,3.18,3.18,0,0,0,.47-1.93,3,3,0,0,0-.47-1.85,1.43,1.43,0,0,0-1.17-.61,1.51,1.51,0,0,0-1.23.62A3,3,0,0,0,448.44,663.58Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M468.82,663.56v-2.74h5.81v5.62a11.64,11.64,0,0,1-2.95,1.68,9.47,9.47,0,0,1-3,.44,6.86,6.86,0,0,1-3.53-.8,5.31,5.31,0,0,1-2.12-2.38,8.38,8.38,0,0,1-.75-3.63,8.11,8.11,0,0,1,.82-3.76,5.53,5.53,0,0,1,2.41-2.42,7.36,7.36,0,0,1,3.33-.64,8.56,8.56,0,0,1,3,.4,3.89,3.89,0,0,1,1.66,1.23,5.54,5.54,0,0,1,1,2.1l-3.63.71a2.15,2.15,0,0,0-.76-1.15,2.26,2.26,0,0,0-1.36-.39,2.39,2.39,0,0,0-2,.93,4.74,4.74,0,0,0-.73,2.94,4.94,4.94,0,0,0,.74,3.06,2.53,2.53,0,0,0,2.07.92,3.74,3.74,0,0,0,1.21-.2,6.12,6.12,0,0,0,1.31-.68v-1.24Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M486.22,668.34H476.07a7.23,7.23,0,0,1,1.06-3.06,14.61,14.61,0,0,1,3.32-3.39,10.56,10.56,0,0,0,1.9-1.81,2.21,2.21,0,0,0,.41-1.18,1.4,1.4,0,0,0-.41-1,1.35,1.35,0,0,0-1-.43,1.39,1.39,0,0,0-1.06.44,2.84,2.84,0,0,0-.55,1.56l-3.39-.3a6.13,6.13,0,0,1,.73-2.41,3.41,3.41,0,0,1,1.5-1.33,6.28,6.28,0,0,1,2.68-.47,7.05,7.05,0,0,1,2.77.44,3.44,3.44,0,0,1,1.56,1.36,3.76,3.76,0,0,1,.57,2,4.36,4.36,0,0,1-.65,2.3,9.09,9.09,0,0,1-2.37,2.41c-.68.51-1.13.87-1.36,1.07s-.5.47-.81.8h5.28Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M501.8,655.16h3.75V663a7,7,0,0,1-.34,2.21,4.76,4.76,0,0,1-1,1.81,4.16,4.16,0,0,1-1.51,1.09,6.89,6.89,0,0,1-2.63.44,15.27,15.27,0,0,1-1.94-.13,4.69,4.69,0,0,1-1.75-.54,4.38,4.38,0,0,1-1.29-1.13,4.22,4.22,0,0,1-.8-1.52,8.17,8.17,0,0,1-.35-2.23v-7.85h3.75v8a2.38,2.38,0,0,0,.55,1.68,2,2,0,0,0,1.53.61,2,2,0,0,0,1.53-.6,2.44,2.44,0,0,0,.55-1.69Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M507.93,655.16h3.39v13.18h-3.39Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M517.56,655.16v3.63h1.86v2.68h-1.86v3.38a2,2,0,0,0,.1.81.61.61,0,0,0,.58.3,3.33,3.33,0,0,0,1-.23l.25,2.53a10.1,10.1,0,0,1-2.34.29,3.74,3.74,0,0,1-1.86-.35,2,2,0,0,1-.88-1.06,6.52,6.52,0,0,1-.29-2.31v-3.36h-1.25v-2.68h1.25V657Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M521.06,658.79h3.16v1.56a3.81,3.81,0,0,1,.94-1.39,1.88,1.88,0,0,1,1.2-.39,3.33,3.33,0,0,1,1.64.51l-1,2.6a2.43,2.43,0,0,0-.94-.26,1.12,1.12,0,0,0-1,.59,6.43,6.43,0,0,0-.53,3.13v3.2h-3.39Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M531.94,661.88l-3.23-.37a4.06,4.06,0,0,1,.53-1.44,3,3,0,0,1,1-.91,3.82,3.82,0,0,1,1.28-.43,8.86,8.86,0,0,1,1.76-.16,13.09,13.09,0,0,1,2.44.19,3,3,0,0,1,1.54.77,2.86,2.86,0,0,1,.68,1.14,4.67,4.67,0,0,1,.25,1.42v4.22a4.85,4.85,0,0,0,.08,1.05,4.6,4.6,0,0,0,.34,1h-3.17a3.65,3.65,0,0,1-.25-.56,4.32,4.32,0,0,1-.12-.61,4.38,4.38,0,0,1-1.32,1,5.15,5.15,0,0,1-2.08.39,3.28,3.28,0,0,1-2.39-.79,2.58,2.58,0,0,1-.82-2A2.67,2.67,0,0,1,529,664a3.86,3.86,0,0,1,2.17-1c1.27-.28,2.09-.47,2.47-.58a11.09,11.09,0,0,0,1.19-.44,1.36,1.36,0,0,0-.25-.94,1.25,1.25,0,0,0-.91-.27,2.18,2.18,0,0,0-1.24.29A1.6,1.6,0,0,0,531.94,661.88Zm2.93,1.93a12.94,12.94,0,0,1-1.45.47,3.21,3.21,0,0,0-1.3.59,1,1,0,0,0-.29.67,1,1,0,0,0,.28.71,1.14,1.14,0,0,0,.82.27,1.94,1.94,0,0,0,1.05-.3,1.7,1.7,0,0,0,.69-.72,2.51,2.51,0,0,0,.2-1.11Z"
|
||||
></path><path
|
||||
class="cls-6"
|
||||
d="M579.88,583.57v16l.41-.47a7.4,7.4,0,0,1,5.54-2.48h.24a8.27,8.27,0,0,0,6.37-3l.18-.21a3.11,3.11,0,0,0,.14-3.78l-.24-.34a8.29,8.29,0,0,0-6.76-3.49h-.57a7.4,7.4,0,0,1-4.87-1.83Z"
|
||||
></path><path
|
||||
class="cls-6"
|
||||
d="M579.87,594.24a2.68,2.68,0,1,1,0-5.35"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M588.69,547.89a6.85,6.85,0,0,0-3.84,1.17l-.15.11-8,5.63,8,5.63.15.11a6.91,6.91,0,1,0,3.84-12.65Zm0,9.72a2.81,2.81,0,1,1,2.81-2.81A2.81,2.81,0,0,1,588.69,557.61Z"
|
||||
></path><polygon
|
||||
class="cls-6"
|
||||
points="582.55 520.31 588.06 528.85 577.03 528.85 577.03 511.78 588.06 511.78 582.55 520.31"
|
||||
></polygon><polygon
|
||||
class="cls-6"
|
||||
points="594.05 520.03 588.06 528.85 582.55 520.31 588.06 511.78 594.05 520.03"
|
||||
></polygon></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.5 KiB |
3510
packages/web/public/devices/pico.svg
Normal file
|
After Width: | Height: | Size: 102 KiB |
2619
packages/web/public/devices/promicro.svg
Normal file
|
After Width: | Height: | Size: 86 KiB |
264
packages/web/public/devices/rak-wismeshtap.svg
Normal file
@@ -0,0 +1,264 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="663.59 325.94 640.35 1015.71">
|
||||
<defs><style>
|
||||
.cls-1 {
|
||||
fill: #353535;
|
||||
}
|
||||
.cls-2 {
|
||||
fill: #1d1e1e;
|
||||
}
|
||||
.cls-3 {
|
||||
fill: #9f9f9e;
|
||||
}
|
||||
.cls-4 {
|
||||
fill: #434343;
|
||||
}
|
||||
.cls-5, .cls-7 {
|
||||
fill: none;
|
||||
stroke: #050606;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
.cls-5 {
|
||||
stroke-width: 2px;
|
||||
}
|
||||
.cls-6 {
|
||||
fill: #b1a368;
|
||||
}
|
||||
</style></defs><g id="Layer_7" data-name="Layer 7"><rect
|
||||
class="cls-1"
|
||||
x="1079.47"
|
||||
y="834.15"
|
||||
width="56.53"
|
||||
height="9.97"
|
||||
></rect><rect
|
||||
class="cls-1"
|
||||
x="1075.53"
|
||||
y="800.89"
|
||||
width="63.83"
|
||||
height="33.26"
|
||||
></rect><path
|
||||
class="cls-1"
|
||||
d="M1079.93,800.89v-5.28a2.81,2.81,0,0,1,2.81-2.81h50.45a2.81,2.81,0,0,1,2.82,2.81v5.28"
|
||||
></path><rect
|
||||
class="cls-1"
|
||||
x="1076.7"
|
||||
y="718.27"
|
||||
width="62.66"
|
||||
height="70.68"
|
||||
rx="3.45"
|
||||
></rect><rect
|
||||
class="cls-1"
|
||||
x="1082.84"
|
||||
y="788.94"
|
||||
width="50.73"
|
||||
height="3.86"
|
||||
></rect><path
|
||||
class="cls-2"
|
||||
d="M1085.24,695.85s-2.75-3.82-4.5-3.27-3.94.3-1.53,2.72l12.9,13s.75.76.61,3.43.07,5.63.65,5.91,30.43,1.59,30.64-.79.67-6.25-.74-5.68-11.35,4.43-19.55.05S1085.24,695.85,1085.24,695.85Z"
|
||||
></path><path
|
||||
class="cls-1"
|
||||
d="M1282,938.23v321.64a59.85,59.85,0,0,1-59.78,59.78H745.37a59.84,59.84,0,0,1-59.78-59.78V938.23a59.84,59.84,0,0,1,59.78-59.78h476.8A59.84,59.84,0,0,1,1282,938.23Z"
|
||||
></path><path
|
||||
class="cls-3"
|
||||
d="M1222.17,857.45H745.37a80.77,80.77,0,0,0-80.78,80.78v321.64a80.77,80.77,0,0,0,80.78,80.78h476.8a80.78,80.78,0,0,0,80.78-80.78V938.23A80.78,80.78,0,0,0,1222.17,857.45ZM1282,1259.87a59.85,59.85,0,0,1-59.78,59.78H745.37a59.84,59.84,0,0,1-59.78-59.78V938.23a59.84,59.84,0,0,1,59.78-59.78h476.8A59.84,59.84,0,0,1,1282,938.23Z"
|
||||
></path><rect
|
||||
class="cls-4"
|
||||
x="819.33"
|
||||
y="971.15"
|
||||
width="328.86"
|
||||
height="250.93"
|
||||
></rect><path
|
||||
class="cls-5"
|
||||
d="M1222.17,878.45a59.83,59.83,0,0,1,59.77,59.77v321.65a59.84,59.84,0,0,1-59.77,59.78H745.36a59.84,59.84,0,0,1-59.77-59.78V938.22a59.83,59.83,0,0,1,59.77-59.77h476.81m0-21H745.36a80.77,80.77,0,0,0-80.77,80.77v321.65a80.78,80.78,0,0,0,80.77,80.78h476.81a80.78,80.78,0,0,0,80.77-80.78V938.22a80.77,80.77,0,0,0-80.77-80.77Z"
|
||||
></path><rect
|
||||
class="cls-5"
|
||||
x="819.33"
|
||||
y="971.15"
|
||||
width="328.86"
|
||||
height="250.93"
|
||||
></rect><rect
|
||||
class="cls-6"
|
||||
x="1080.45"
|
||||
y="847.88"
|
||||
width="55.55"
|
||||
height="9.57"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="1080.45"
|
||||
y="847.88"
|
||||
width="55.55"
|
||||
height="9.57"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="1079.47"
|
||||
y="834.15"
|
||||
width="56.53"
|
||||
height="9.97"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="1075.53"
|
||||
y="800.89"
|
||||
width="63.83"
|
||||
height="33.26"
|
||||
></rect><path
|
||||
class="cls-5"
|
||||
d="M1079.93,800.89v-5.28a2.81,2.81,0,0,1,2.81-2.81h50.45a2.81,2.81,0,0,1,2.82,2.81v5.28"
|
||||
></path><rect
|
||||
class="cls-5"
|
||||
x="1076.7"
|
||||
y="718.27"
|
||||
width="62.66"
|
||||
height="70.68"
|
||||
rx="3.45"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="1082.84"
|
||||
y="788.94"
|
||||
width="50.73"
|
||||
height="3.86"
|
||||
></rect><line
|
||||
class="cls-5"
|
||||
x1="1093.01"
|
||||
y1="718.27"
|
||||
x2="1093.01"
|
||||
y2="703.17"
|
||||
></line><line
|
||||
class="cls-5"
|
||||
x1="1124.56"
|
||||
y1="718.27"
|
||||
x2="1124.56"
|
||||
y2="710.55"
|
||||
></line><path
|
||||
class="cls-1"
|
||||
d="M784.41,333.86l363.94,355.78-18.09,16.92a24.62,24.62,0,0,1-33.69,0l-14.9-14a.44.44,0,0,0-.5-.09h0a13.35,13.35,0,0,1-14.85-2.89L750.32,368a24.13,24.13,0,0,1,1.18-35h0A24.13,24.13,0,0,1,784.41,333.86Z"
|
||||
></path><path
|
||||
class="cls-2"
|
||||
d="M818.35,367.13c-2.26-2.12-11.86,3.59-21.07,13.42s-15.34,19.55-13.08,21.67l-2.53-2.8c-2.26-2.12,3.87-11.84,13.08-21.67s18.8-15.54,21.07-13.42l-4.24-3.58c-2.27-2.12-11.86,3.6-21.07,13.42s-15.34,19.56-13.08,21.68l-2.53-2.8c-2.26-2.12,3.87-11.85,13.08-21.68s18.8-15.54,21.07-13.42"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M784.41,333.86l363.94,355.78-18.09,16.92a24.62,24.62,0,0,1-33.69,0l-14.9-14a.44.44,0,0,0-.5-.09h0a13.35,13.35,0,0,1-14.85-2.89L750.32,368a24.13,24.13,0,0,1,1.18-35h0A24.13,24.13,0,0,1,784.41,333.86Z"
|
||||
></path><line
|
||||
class="cls-5"
|
||||
x1="1077.35"
|
||||
y1="693.43"
|
||||
x2="1093.01"
|
||||
y2="709.21"
|
||||
></line><circle
|
||||
class="cls-2"
|
||||
cx="1111.17"
|
||||
cy="687.29"
|
||||
r="6"
|
||||
></circle><circle
|
||||
class="cls-5"
|
||||
cx="1111.17"
|
||||
cy="687.29"
|
||||
r="6"
|
||||
></circle><path
|
||||
class="cls-7"
|
||||
d="M774.9,393.05c-2.26-2.12,3.87-11.85,13.08-21.68s18.8-15.54,21.07-13.42"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M777.43,395.85c-2.26-2.12,3.87-11.85,13.08-21.68s18.8-15.54,21.07-13.42"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M781.67,399.42c-2.26-2.12,3.87-11.84,13.08-21.67s18.8-15.54,21.07-13.42"
|
||||
></path><path
|
||||
class="cls-7"
|
||||
d="M784.2,402.22c-2.26-2.12,3.87-11.84,13.08-21.67s18.81-15.54,21.07-13.42"
|
||||
></path><rect
|
||||
class="cls-6"
|
||||
x="1086.52"
|
||||
y="844.12"
|
||||
width="41.63"
|
||||
height="3.76"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="1086.52"
|
||||
y="844.12"
|
||||
width="41.63"
|
||||
height="3.76"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1079.47"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1083.7"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1087.92"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1092.15"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1096.38"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1100.6"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1104.83"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1109.05"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1113.28"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1117.51"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1121.73"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1125.96"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1130.18"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect><rect
|
||||
class="cls-2"
|
||||
x="1134.41"
|
||||
y="805.49"
|
||||
width="1.59"
|
||||
height="25.02"
|
||||
></rect></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.8 KiB |
2794
packages/web/public/devices/rak11310.svg
Normal file
|
After Width: | Height: | Size: 164 KiB |
379
packages/web/public/devices/rak2560.svg
Normal file
@@ -0,0 +1,379 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="281.97 168.43 271.78 510.19">
|
||||
<defs><style>
|
||||
.cls-1 {
|
||||
fill: #1c60ac;
|
||||
}
|
||||
.cls-2 {
|
||||
fill: #33353d;
|
||||
}
|
||||
.cls-3 {
|
||||
fill: #0e5796;
|
||||
}
|
||||
.cls-4 {
|
||||
fill: #fff;
|
||||
}
|
||||
.cls-5 {
|
||||
fill: none;
|
||||
stroke: #050606;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
.cls-6 {
|
||||
fill: #9e9d9e;
|
||||
}
|
||||
</style></defs><g id="Layer_3" data-name="Layer 3"><rect
|
||||
class="cls-1"
|
||||
x="355.63"
|
||||
y="645.72"
|
||||
width="37.63"
|
||||
height="25.23"
|
||||
rx="3.38"
|
||||
></rect><rect
|
||||
class="cls-1"
|
||||
x="352.62"
|
||||
y="581.71"
|
||||
width="44.76"
|
||||
height="25.23"
|
||||
rx="3.69"
|
||||
></rect><path
|
||||
class="cls-1"
|
||||
d="M389.88,671h0a7.12,7.12,0,0,1-7.12,7.12H366.14A7.12,7.12,0,0,1,359,671h0"
|
||||
></path><rect
|
||||
class="cls-2"
|
||||
x="356.31"
|
||||
y="576.3"
|
||||
width="37.38"
|
||||
height="5.41"
|
||||
></rect><path
|
||||
class="cls-2"
|
||||
d="M392.3,606.94s-4.84,14.19-4.84,38.78H361.15c0-24.59-4.84-38.78-4.84-38.78Z"
|
||||
></path><rect
|
||||
class="cls-3"
|
||||
x="355.63"
|
||||
y="584.04"
|
||||
width="4.39"
|
||||
height="20.14"
|
||||
rx="0.9"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="364.31"
|
||||
y="584.04"
|
||||
width="4.39"
|
||||
height="20.14"
|
||||
rx="0.9"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="372.98"
|
||||
y="584.04"
|
||||
width="4.39"
|
||||
height="20.14"
|
||||
rx="0.9"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="381.65"
|
||||
y="584.04"
|
||||
width="4.39"
|
||||
height="20.14"
|
||||
rx="0.9"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="390.32"
|
||||
y="584.04"
|
||||
width="4.39"
|
||||
height="20.14"
|
||||
rx="0.9"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="357.21"
|
||||
y="648.27"
|
||||
width="3.9"
|
||||
height="20.14"
|
||||
rx="0.85"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="364.91"
|
||||
y="648.27"
|
||||
width="3.9"
|
||||
height="20.14"
|
||||
rx="0.85"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="372.6"
|
||||
y="648.27"
|
||||
width="3.9"
|
||||
height="20.14"
|
||||
rx="0.85"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="380.3"
|
||||
y="648.27"
|
||||
width="3.9"
|
||||
height="20.14"
|
||||
rx="0.85"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="388"
|
||||
y="648.27"
|
||||
width="3.9"
|
||||
height="20.14"
|
||||
rx="0.85"
|
||||
></rect><rect
|
||||
class="cls-1"
|
||||
x="432.13"
|
||||
y="645.72"
|
||||
width="37.63"
|
||||
height="25.23"
|
||||
rx="3.38"
|
||||
></rect><rect
|
||||
class="cls-1"
|
||||
x="429.12"
|
||||
y="581.71"
|
||||
width="44.76"
|
||||
height="25.23"
|
||||
rx="3.69"
|
||||
></rect><path
|
||||
class="cls-1"
|
||||
d="M466.38,671h0a7.12,7.12,0,0,1-7.12,7.12H442.63a7.11,7.11,0,0,1-7.11-7.12h0"
|
||||
></path><rect
|
||||
class="cls-2"
|
||||
x="432.81"
|
||||
y="576.3"
|
||||
width="37.38"
|
||||
height="5.41"
|
||||
></rect><path
|
||||
class="cls-2"
|
||||
d="M468.79,606.94S464,621.13,464,645.72H437.64c0-24.59-4.83-38.78-4.83-38.78Z"
|
||||
></path><rect
|
||||
class="cls-3"
|
||||
x="432.13"
|
||||
y="584.04"
|
||||
width="4.39"
|
||||
height="20.14"
|
||||
rx="0.9"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="440.8"
|
||||
y="584.04"
|
||||
width="4.39"
|
||||
height="20.14"
|
||||
rx="0.9"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="449.48"
|
||||
y="584.04"
|
||||
width="4.39"
|
||||
height="20.14"
|
||||
rx="0.9"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="458.15"
|
||||
y="584.04"
|
||||
width="4.39"
|
||||
height="20.14"
|
||||
rx="0.9"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="466.82"
|
||||
y="584.04"
|
||||
width="4.39"
|
||||
height="20.14"
|
||||
rx="0.9"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="433.71"
|
||||
y="648.27"
|
||||
width="3.9"
|
||||
height="20.14"
|
||||
rx="0.85"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="441.4"
|
||||
y="648.27"
|
||||
width="3.9"
|
||||
height="20.14"
|
||||
rx="0.85"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="449.1"
|
||||
y="648.27"
|
||||
width="3.9"
|
||||
height="20.14"
|
||||
rx="0.85"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="456.8"
|
||||
y="648.27"
|
||||
width="3.9"
|
||||
height="20.14"
|
||||
rx="0.85"
|
||||
></rect><rect
|
||||
class="cls-3"
|
||||
x="464.5"
|
||||
y="648.27"
|
||||
width="3.9"
|
||||
height="20.14"
|
||||
rx="0.85"
|
||||
></rect></g><g id="Layer_2" data-name="Layer 2"><path
|
||||
class="cls-4"
|
||||
d="M553.25,218.93V526.3a50,50,0,0,1-50,50H332.47a50,50,0,0,1-50-50V218.93a50,50,0,0,1,50-50H503.24A50,50,0,0,1,553.25,218.93Z"
|
||||
></path><path
|
||||
class="cls-1"
|
||||
d="M553.25,218.93V328.61H282.47V218.93a50,50,0,0,1,50-50H503.24A50,50,0,0,1,553.25,218.93Z"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M553.25,218.93V526.3a50,50,0,0,1-50,50H332.47a50,50,0,0,1-50-50V218.93a50,50,0,0,1,50-50H503.24A50,50,0,0,1,553.25,218.93Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M356.47,248.86a8.83,8.83,0,0,0-5.13.45s-1.27-2.38-.86-7.18c.16-1.81.47-4.26,2.63-4.63l.1,0a2.54,2.54,0,0,1,3.26,3.1C355.85,246.23,356.69,248.83,356.47,248.86Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M346.81,236.93a2.33,2.33,0,0,1,2.16,2.94,13,13,0,0,0-.33,4.26c.27,4.34,1.76,5.88,1.76,5.88a4.28,4.28,0,0,0-1.49,2.75,16.14,16.14,0,0,1-4.74-13,3.29,3.29,0,0,1,.94-2.14,2.34,2.34,0,0,1,1.41-.69A1.42,1.42,0,0,1,346.81,236.93Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M348.3,260.57A18.32,18.32,0,0,1,338,249.31a20.24,20.24,0,0,1-1-7.95,4.84,4.84,0,0,1,1-3.08,2.87,2.87,0,0,1,4.25,1,5.05,5.05,0,0,1,.08,2.19,14.84,14.84,0,0,0,.62,5.95c1.39,4.89,6.95,9.07,6.95,9.07A5.94,5.94,0,0,0,348.3,260.57Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M358,242.89a8.93,8.93,0,0,0-.45-5.13s2.38-1.26,7.18-.86c1.81.16,4.26.48,4.63,2.64a.29.29,0,0,0,0,.09,2.55,2.55,0,0,1-3.1,3.27C360.62,242.28,358,243.12,358,242.89Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M369.93,233.24a2.33,2.33,0,0,1-2.94,2.15,13.43,13.43,0,0,0-4.26-.32c-4.34.27-5.88,1.75-5.88,1.75a4.24,4.24,0,0,0-2.75-1.48,16.14,16.14,0,0,1,13-4.74,3.28,3.28,0,0,1,2.14.93,2.36,2.36,0,0,1,.69,1.41A1.51,1.51,0,0,1,369.93,233.24Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M346.29,234.73a18.29,18.29,0,0,1,11.26-10.34,20.05,20.05,0,0,1,7.95-1,4.77,4.77,0,0,1,3.08,1,2.87,2.87,0,0,1-1,4.25,4.77,4.77,0,0,1-2.19.08,15.07,15.07,0,0,0-5.95.63c-4.89,1.39-9.07,7-9.07,7A5.94,5.94,0,0,0,346.29,234.73Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M363.86,244.84a8.93,8.93,0,0,0,5.13-.45s1.26,2.38.86,7.17c-.16,1.82-.48,4.27-2.64,4.63l-.09,0a2.53,2.53,0,0,1-3.26-3.09C364.48,247.46,363.64,244.87,363.86,244.84Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M373.51,256.77a2.33,2.33,0,0,1-2.15-2.94,13.37,13.37,0,0,0,.33-4.26c-.27-4.34-1.76-5.88-1.76-5.88a4.28,4.28,0,0,0,1.49-2.75,16.14,16.14,0,0,1,4.74,13,3.29,3.29,0,0,1-.94,2.14,2.36,2.36,0,0,1-1.41.69Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M372,233.13a18.29,18.29,0,0,1,10.34,11.26,19.87,19.87,0,0,1,1,8,4.77,4.77,0,0,1-1,3.08,2.87,2.87,0,0,1-4.25-1,4.91,4.91,0,0,1-.08-2.19,15.21,15.21,0,0,0-.62-5.95c-1.39-4.89-7-9.07-7-9.07A5.89,5.89,0,0,0,372,233.13Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M362.33,250.81a8.79,8.79,0,0,0,.45,5.12s-2.38,1.27-7.18.87c-1.81-.16-4.26-.48-4.63-2.64a.29.29,0,0,0,0-.09,3,3,0,0,1,.8-2.79,3,3,0,0,1,2.3-.48C359.7,251.42,362.3,250.58,362.33,250.81Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M350.4,260.46a2.32,2.32,0,0,1,2.93-2.15,13.5,13.5,0,0,0,4.27.32c4.34-.27,5.87-1.75,5.87-1.75a4.24,4.24,0,0,0,2.76,1.48,16.14,16.14,0,0,1-13,4.74,3.23,3.23,0,0,1-2.14-.93,2.43,2.43,0,0,1-.7-1.41C350.4,260.66,350.4,260.56,350.4,260.46Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M374,259a18.29,18.29,0,0,1-11.26,10.34,20.26,20.26,0,0,1-7.95,1,4.76,4.76,0,0,1-3.08-1,2.87,2.87,0,0,1,1-4.25,4.86,4.86,0,0,1,2.18-.07,15.11,15.11,0,0,0,6-.63c4.89-1.39,9.06-7,9.06-7A6,6,0,0,0,374,259Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M400.1,250.29v13h-7.47V230.88h15.53c7.7,0,11.84,3.89,11.84,8.88a7.75,7.75,0,0,1-5.13,7.66c1.75.59,4.39,2.26,4.39,8.05v1.6a23.55,23.55,0,0,0,.51,6.17h-7.24c-.62-1.41-.74-3.83-.74-7.27v-.47c0-3.54-1-5.21-6.67-5.21Zm0-5.57h6.4c4.18,0,5.8-1.46,5.8-4.17s-1.88-4.1-5.62-4.1H400.1Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M430.81,255.76l-2.43,7.48h-6.65l10.62-32.36h8.48l11.07,32.36h-7.1l-2.57-7.48Zm10-5.73c-2.22-6.83-3.64-11.19-4.39-14.1h-.05c-.77,3.19-2.33,8.26-4.11,14.1Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M454.41,230.88h6.68v14.44c2.06-2.49,8.49-9.79,12.44-14.44h8.09l-12.56,13.45,13,18.91H474l-9.59-14.38-3.29,3.27v11.11h-6.68Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M487.73,235.1V237h-.79v-4.39h2.15c1.12,0,1.72.5,1.72,1.18a1.06,1.06,0,0,1-.89,1,1,1,0,0,1,.79,1.11v.2a2.79,2.79,0,0,0,.07.86H490a2.67,2.67,0,0,1-.09-.95V236c0-.6-.21-.86-1.15-.86Zm0-.54h1.13c.79,0,1.13-.24,1.13-.71s-.36-.7-1.06-.7h-1.2Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M488.62,239.49a4.7,4.7,0,1,1,4.71-4.7A4.71,4.71,0,0,1,488.62,239.49Zm0-8.74a4,4,0,1,0,4,4A4,4,0,0,0,488.62,230.75Z"
|
||||
></path><path class="cls-4" d="M396.73,277.19v-7.92h1v7.92Z"></path><path
|
||||
class="cls-4"
|
||||
d="M403.93,274.43c0,1.6-.9,2.89-2.54,2.89s-2.48-1.22-2.48-2.87.92-2.89,2.54-2.89S403.93,272.71,403.93,274.43Zm-4,0c0,1.18.56,2,1.47,2s1.44-.79,1.44-2-.52-2-1.46-2S400,273.2,400,274.44Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M405.89,270.63h-2.32v-.94h5.72v.94H407v6.56h-1.08Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M419.12,274.07c0-1.38,0-2.8.05-3.6h0c-.32,1.28-1.41,4.36-2.21,6.72h-1c-.61-1.94-1.74-5.41-2.06-6.73h0c.06.87.09,2.51.09,3.8v2.93h-1v-7.5h1.61c.77,2.26,1.71,5.16,1.95,6.14h0c.17-.77,1.29-3.94,2.09-6.14h1.56v7.5h-1.05Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M425.77,276a9.39,9.39,0,0,0,.08,1.24h-1a2.46,2.46,0,0,1-.09-.68,1.88,1.88,0,0,1-3.41-.88c0-1.23.94-1.8,2.52-1.8h.88v-.44c0-.47-.15-1-1.09-1s-1,.42-1.07.85h-1c.07-.8.55-1.66,2.1-1.66,1.32,0,2,.56,2,1.82Zm-1-1.41H424c-1,0-1.55.3-1.55,1a.9.9,0,0,0,1,.94c1.21,0,1.37-.85,1.37-1.8Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M431.82,269.27v6.38c0,.51,0,1,0,1.54h-1c0-.15,0-.54,0-.74a1.63,1.63,0,0,1-1.64.87c-1.36,0-2.21-1.14-2.21-2.82s.91-2.94,2.39-2.94c.91,0,1.33.37,1.46.67v-3Zm-3.81,5.2c0,1.27.57,2,1.38,2,1.2,0,1.44-.94,1.44-2.06s-.22-1.93-1.37-1.93C428.55,272.45,428,273.19,428,274.47Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M433.73,274.64c0,1,.51,1.81,1.38,1.81a1.15,1.15,0,0,0,1.21-.8h1a2.19,2.19,0,0,1-2.27,1.67c-1.69,0-2.39-1.39-2.39-2.82,0-1.65.81-2.94,2.44-2.94a2.33,2.33,0,0,1,2.32,2.63,3.24,3.24,0,0,1,0,.45Zm2.68-.72c0-.85-.42-1.54-1.29-1.54s-1.28.64-1.36,1.54Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M446,273.74h-3.59v2.51h3.94l-.13.94h-4.86v-7.5h4.81v.94h-3.76v2.16H446Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M451.59,276a9.9,9.9,0,0,0,.07,1.24h-1a2.93,2.93,0,0,1-.09-.68,1.88,1.88,0,0,1-3.41-.88c0-1.23.94-1.8,2.52-1.8h.88v-.44c0-.47-.15-1-1.08-1s-1,.42-1.08.85h-1c.07-.8.55-1.66,2.1-1.66,1.33,0,2.06.56,2.06,1.82Zm-1-1.41h-.81c-1,0-1.55.3-1.55,1a.91.91,0,0,0,1,.94c1.21,0,1.37-.85,1.37-1.8Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M453.63,275.6a1.16,1.16,0,0,0,1.25.9c.74,0,1-.32,1-.78s-.24-.7-1.2-1c-1.57-.39-1.88-.89-1.88-1.64s.56-1.57,2-1.57a1.8,1.8,0,0,1,2,1.6h-1a1,1,0,0,0-1.1-.8c-.69,0-.9.35-.9.68s.21.58,1.16.81c1.65.4,2,1,2,1.79s-.73,1.68-2.11,1.68a2,2,0,0,1-2.23-1.72Z"
|
||||
></path><path
|
||||
class="cls-4"
|
||||
d="M458.65,271.69c.8,2.49,1.28,4,1.41,4.55h0c.16-.61.52-1.87,1.35-4.55h1l-1.89,5.74c-.53,1.6-.94,2-2.07,2a4.38,4.38,0,0,1-.59,0v-.9a2.9,2.9,0,0,0,.43,0c.65,0,.91-.29,1.2-1.15l-2-5.7Z"
|
||||
></path><path
|
||||
class="cls-6"
|
||||
d="M437,480.69v22.45a6.83,6.83,0,0,1-6.83,6.83h-11.1a8,8,0,0,1-5.42-2.38,9.05,9.05,0,0,1-2.56-6.44V482.62l11.73,11.74v-3.69l-11.73-11.74-3-3v25.17c0,3.22,1.82,8.05,4,8.9h-5.75a6.83,6.83,0,0,1-6.83-6.83V480.69a6.83,6.83,0,0,1,6.83-6.83H418a8,8,0,0,1,5.42,2.38,9.05,9.05,0,0,1,2.56,6.44v18.53l-11.73-11.74v3.69L426,504.9l3,3V482.76c0-3.22-1.82-8.05-4-8.9h5.22A6.83,6.83,0,0,1,437,480.69Z"
|
||||
></path><rect
|
||||
class="cls-5"
|
||||
x="355.63"
|
||||
y="645.72"
|
||||
width="37.63"
|
||||
height="25.23"
|
||||
rx="3.38"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="352.62"
|
||||
y="581.71"
|
||||
width="44.76"
|
||||
height="25.23"
|
||||
rx="3.69"
|
||||
></rect><path
|
||||
class="cls-5"
|
||||
d="M389.88,671h0a7.12,7.12,0,0,1-7.12,7.12H366.14A7.12,7.12,0,0,1,359,671h0"
|
||||
></path><line
|
||||
class="cls-5"
|
||||
x1="356.31"
|
||||
y1="581.71"
|
||||
x2="356.31"
|
||||
y2="576.3"
|
||||
></line><line
|
||||
class="cls-5"
|
||||
x1="393.69"
|
||||
y1="581.71"
|
||||
x2="393.69"
|
||||
y2="576.3"
|
||||
></line><path
|
||||
class="cls-5"
|
||||
d="M356.31,606.94s4.84,14.19,4.84,38.78"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M392.3,606.94s-4.84,14.19-4.84,38.78"
|
||||
></path><rect
|
||||
class="cls-5"
|
||||
x="432.13"
|
||||
y="645.72"
|
||||
width="37.63"
|
||||
height="25.23"
|
||||
rx="3.38"
|
||||
></rect><rect
|
||||
class="cls-5"
|
||||
x="429.12"
|
||||
y="581.71"
|
||||
width="44.76"
|
||||
height="25.23"
|
||||
rx="3.69"
|
||||
></rect><path
|
||||
class="cls-5"
|
||||
d="M466.38,671h0a7.12,7.12,0,0,1-7.12,7.12H442.63a7.11,7.11,0,0,1-7.11-7.12h0"
|
||||
></path><line
|
||||
class="cls-5"
|
||||
x1="432.81"
|
||||
y1="581.71"
|
||||
x2="432.81"
|
||||
y2="576.3"
|
||||
></line><line
|
||||
class="cls-5"
|
||||
x1="470.19"
|
||||
y1="581.71"
|
||||
x2="470.19"
|
||||
y2="576.3"
|
||||
></line><path
|
||||
class="cls-5"
|
||||
d="M432.81,606.94s4.83,14.19,4.83,38.78"
|
||||
></path><path
|
||||
class="cls-5"
|
||||
d="M468.79,606.94S464,621.13,464,645.72"
|
||||
></path></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |