659 Commits

Author SHA1 Message Date
Dan Ditomaso
284ccd43f8 refactor: update ci/cd scripts, switch to pnpm (#763)
* refactor: update ci/cd scripts, switch to pnpm

* updated workflow

* add new packages github action. Bump package.json version (#762)

* Update packages/transport-deno/scripts/build_npm.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update packages/core/package.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update packages/transport-deno/scripts/build_npm.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update packages/transport-deno/scripts/build_npm.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update packages/transport-deno/scripts/build_npm.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update .github/workflows/release-packages.yml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* revert copilot suggestion

* adding lock file

* regenerate lock file

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-08 14:54:20 -04:00
Dan Ditomaso
5a66153dfc add new packages github action. Bump package.json version (#762) 2025-08-07 11:31:14 -04:00
Dan Ditomaso
363981a2f7 Conditional app title based on environment. (#760)
* conditionally set title based on environment.

* wip
2025-08-06 11:44:55 -04:00
Dan Ditomaso
7848aa2f0c Add CookieYes for GDPR/CCPA compliance (#759)
* feat: add CookieYes for GDPR/CCPA compliance

* refactor how cookieYes script is loaded
2025-08-06 10:54:40 -04:00
Henri Bergius
0a7b653ec8 Transport disconnect method (#753)
* Prevent reads from piling up

* Implement disconnect() method for all transports
2025-08-05 22:46:23 -04:00
Dan Ditomaso
313c4dbb71 Update README.md (#758) 2025-08-05 21:50:53 -04:00
github-actions[bot]
1927323fb7 chore(i18n): New Crowdin Translations by GitHub Action (#756)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-08-04 22:55:32 -04:00
Dan Ditomaso
41f11f3040 revert: package json changes (#750) 2025-07-28 22:39:15 -04:00
github-actions[bot]
9833628867 chore(i18n): New Crowdin Translations by GitHub Action (#748)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-07-28 20:38:35 -04:00
Dan Ditomaso
4dd911e73d Use workspace meshtastic packages (#749)
* refactor: updated web package.json to use workspace

* formatting fixes
2025-07-28 18:18:46 -04:00
Dan Ditomaso
56487d3832 fix: typo in position flags (#747) 2025-07-28 16:45:14 -04:00
Vasilj Milošević
a9f6afffc2 Add visually hidden DialogTitle to the CommandDialog (#742)
* Add visually hidden DialogTitle to the CommandDialog

Added a visually hidden DialogTitle to the CommandDialog component in Command.tsx  to maintain accessibility while keeping the clean UI of the command palette.

* add visually hidden component as explicit dependency
2025-07-28 16:44:25 -04:00
Dan Ditomaso
09f7f64099 fix: crowdin uploading (#746) 2025-07-28 13:28:20 -04:00
Dan Ditomaso
4ab06abefe fix: update directory paths for source files (#745) 2025-07-28 12:55:54 -04:00
Dan Ditomaso
ce15fd21ad add tsconfig to monorepo (#737)
* add tsconfigs to root

* Update tsconfig.base.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update tsconfig.base.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-26 14:51:34 -04:00
Dan Ditomaso
3c1399b44a Changed position of theme button, hiding tooltip after set time. (#735)
* fix: changed position of theme button, hiding tooltip after set time.

* feat: added usevisibility hook

* updating paths
2025-07-25 12:48:57 -04:00
Jeremy Gallant
50ca75da0e Send heartbeat package to keep serial alive (#732)
* Send heartbeat package to keep the serial connection alive

* Update meshDevice.ts

---------

Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-07-24 10:15:27 -04:00
Jeremy Gallant
5b417a321a Fix node mapping and unknown node display in traceroute dialogs (#728)
Corrects the mapping of 'from' and 'to' nodes in TracerouteResponseDialog to reflect the actual origin and destination of traceroute packets. Also updates TraceRoute to display a localized unknown name for node ID 4294967295 (0xffffff), improving clarity for unknown nodes.
2025-07-23 21:31:05 -04:00
Hunter Thornsberry
bbb43de87b Fix readme and remove broken git link attempting to be a hyperlink (#733) 2025-07-23 21:30:44 -04:00
Jeremy Gallant
2e4d306d79 Change HTTP transport intial connect attempt target (#729)
Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-07-22 12:56:30 -04:00
Jeremy Gallant
afb7f4bd2e Change chatId validation schema (#731)
Fixes #715

Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-07-22 10:01:31 -04:00
Jeremy Gallant
67db8b5be8 Update Switch color scheme (#730)
Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-07-22 09:58:25 -04:00
Dan Ditomaso
09d6556abd readd device num to serial page (#727) 2025-07-20 14:54:43 -04:00
Dan Ditomaso
bfe4e01c85 add tag version to footer (#725) 2025-07-20 14:53:44 -04:00
Hunter Thornsberry
d8304a3f00 Check config.display.use12hclock setting for displaying timestamps on messages, default to true (#723) 2025-07-20 02:13:04 -04:00
Dan Ditomaso
8a443e9cad Fix/add npm jsr building (#722)
* fixed github workflows to improve handling of mutl runtimes

* updating readme

* Update packages/core/src/meshDevice.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update packages/core/package.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update packages/transport-http/package.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-17 20:47:25 -04:00
Henri Bergius
0e29639222 Use the actual toDeviceStream (#721) 2025-07-17 18:38:55 -04:00
Dan Ditomaso
7b0725029f CI updates to support monorepo (#719) 2025-07-17 10:17:44 -04:00
Dan Ditomaso
704d06cfe7 refactor: switch to using Bun (#718) 2025-07-16 22:30:10 -04:00
Dan Ditomaso
acfd7ebd2d Update README.md (#716) 2025-07-15 22:25:01 -04:00
Dan Ditomaso
5fb5693792 feat: added disconnect method to core lib (#712) 2025-07-15 09:08:32 -04:00
Dan Ditomaso
dd3f3f0499 fix: include additional info in nightly container tag name (#709)
* fix: added latest build version into container tag

* updated tag format

* Update .github/workflows/nightly.yml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-14 11:29:58 -04:00
Dan Ditomaso
ff73ed2521 Update README.md (#707) 2025-07-11 10:32:13 -04:00
Dan Ditomaso
5efa1d1795 Prevented i18n package from escaping text (#704)
* fix: prevented i18n package from escaping text

* Update packages/web/vite.config.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: stupid copilot

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-11 08:23:47 -04:00
dependabot[bot]
f010365151 chore(deps): bump tj-actions/changed-files in /.github/workflows (#705)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 44 to 46.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v44...v46)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-version: '46'
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-10 15:29:08 -04:00
Dan Ditomaso
7f177f6b83 Add npm publishing of JS libs (#702)
* feat: publish js libs to npm

* changed license type

* updated readme

* added id

* added exclusion for web and deno packages

* update comment

* updating env var
2025-07-10 12:28:23 -04:00
Dan Ditomaso
66b839742a Add node-transport lib (#703)
* feat: add node transport

* updated readme

* Update packages/transport-node/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-09 22:02:10 -04:00
Dan Ditomaso
2e2b0074b1 Assorted Monorepo fixes (#698)
* add npmrc to root

* fix: associated updates related to monorepo updates

* removed deno plugin

* removed deno plugin

* updating ci
2025-07-07 14:14:41 -04:00
Dan Ditomaso
49283daa4f fix: updated nginx config to pass sub directories (#692) 2025-07-07 11:53:42 -04:00
Dan Ditomaso
3bcda37e66 update pr workflow (#697) 2025-07-07 11:52:48 -04:00
Dan Ditomaso
684cf30d2f add npmrc to root (#696) 2025-07-07 11:49:18 -04:00
Dan Ditomaso
8989478af4 update caching for ci/cd (#695) 2025-07-07 11:43:17 -04:00
Dan Ditomaso
d3446b64a3 removed tests from ci pipeline (#694) 2025-07-07 10:43:58 -04:00
Dan Ditomaso
87cd91b0f8 refactor: add svgs to sub folder (#687) 2025-07-03 07:10:12 -04:00
Dan Ditomaso
e01946a1e4 Update README.md (#685) 2025-06-27 12:09:58 -04:00
Dan Ditomaso
72edb1897f Feat/add js repo to monorepo (#683)
* feat: move js repo into web monorepo

* added readme

* Update packages/core/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update packages/transport-http/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update packages/transport-web-bluetooth/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-26 11:52:57 -04:00
Dan Ditomaso
1c13343e8a Add monorepo support to project (#682)
* feat: add monorepo support

* fix: correct relatedProjects structure in vercel.json

* update github actions with monorepo support

* removed legacy dep

* moved jsr config into web package
2025-06-25 21:56:55 -04:00
Dan Ditomaso
85ee0747d1 fix: move i18n languages to public folder (#681)
* fix: move i18n languages for best practices

* updating test setup

* removed static copy
2025-06-25 16:21:36 -04:00
Dan Ditomaso
e2f03aaf81 feat: add dependency injection using tanstack context (#680)
* feat: add dep injection using tanstack context

* fixed small typo
2025-06-24 18:19:26 -04:00
Dan Ditomaso
6c676fa8da add git sub module (#678) 2025-06-23 22:26:01 -04:00
github-actions[bot]
183b3ae8cc chore(i18n): New Crowdin Translations by GitHub Action (#677)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-06-22 13:57:29 -04:00
Dan Ditomaso
43143bfdf6 Device Name dialog validation (#676)
* fix: style on config page

* feat: added device name validation

* Update src/i18n/locales/en/dialog.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/components/Dialog/DeviceNameDialog.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/components/Dialog/DeviceNameDialog.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fixed typo

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-21 23:08:25 -04:00
Dan Ditomaso
c6a564f7e4 fix: style on config page (#674) 2025-06-20 12:39:11 -04:00
Dan Ditomaso
762aed50b7 Updated button styling on config header (#673)
* fix: updated button in config

* Update src/pages/Config/index.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-18 21:08:56 -04:00
Jeremy Gallant
bb91350ef5 fix: Crash when navigator.serial is undefined (#670)
* Fix crash when navigator.serial is undefined

* Change value

---------

Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-06-18 16:39:14 -04:00
Dan Ditomaso
ec9b299b37 fix: add missing i18n strings (#671)
* fix: added required i18n labels to UI

* added node i18n

* updated tests

* updated path to match github action
2025-06-18 16:25:14 -04:00
Jeremy Gallant
0e6a4818ea fix: Crowdin upload sources action (#672)
* Fix Crowdin upload sources action

* Replace biome with deno in vscode extension recommendations

---------

Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-06-18 15:48:41 -04:00
Jeremy Gallant
181c984b27 Config form improvements (#652)
* Config reset work WIP

* Config reset WIP

* Fix tests, tsc, linting

* Form reset adjustments

* Add ManagedModeDialog

* Remove debug logging

* Add Suspense

* Review fixes

---------

Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-06-18 10:04:17 -04:00
Jeremy Gallant
7adbe01723 Add advanced filters (#655)
* Add advanced filters

* Review edits

---------

Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-06-18 10:02:42 -04:00
Dan Ditomaso
a5339af0dd Fix language default in picker. Misc i18n fixes (#664)
* fix: fix language default in picker. Misc i18n fixes

* Update src/i18n/config.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* PR fixes

* duplicate key

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-17 16:23:57 -04:00
Dan Ditomaso
c91e5e6b7b fix: add rewrites to vercel.json (#662) 2025-06-17 11:09:43 -04:00
Jeremy Gallant
ccc4202aa4 Minor i18n fixes (#663)
* i18n fixes

Add PKI Backup Reminder dialog + ensure en-US is UI default

* Revert edits to i18n components
2025-06-17 10:24:58 -04:00
Dan Ditomaso
118f848308 feat: add support for 3 languages (#661) 2025-06-16 16:22:45 -04:00
github-actions[bot]
c36ff60778 chore(i18n): New Crowdin Translations by GitHub Action (#660)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-06-16 15:59:08 -04:00
Dan Ditomaso
474e610c3d fix: revert crowdin config (#659) 2025-06-16 15:55:29 -04:00
Dan Ditomaso
0b6ae0ce32 fix: update crowdin config (#658) 2025-06-16 15:14:59 -04:00
github-actions[bot]
fad1b984bf chore(i18n): New Crowdin Translations by GitHub Action (#653)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-06-16 09:41:50 -04:00
Dan Ditomaso
6cc6986904 fix: remove service worker (#654) 2025-06-16 09:39:13 -04:00
Dan Ditomaso
26d5c0a08a feat: added i18n translator & developer guides (#646) 2025-06-12 20:15:43 -04:00
Dan Ditomaso
78e1d1f81a fix: updated mqtt description (#647) 2025-06-12 20:14:59 -04:00
dependabot[bot]
48862141dc chore(deps): bump tj-actions/changed-files in /.github/workflows (#650)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 44 to 46.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v44...v46)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-version: '46'
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-12 20:10:08 -04:00
Dan Ditomaso
47f8264c31 Fix tsc errors (#649)
* fixed tsc errors

* fixed tsc errors

* fixed tsc errors

* fixing tsc errors

* fixing more tsc errors

* fixing more tsc errors

* fixed tsc errors

* fixing tsc errors

* fixing PR issues

* commented out tsc check

* completing tsc fixes

* updating lockfile

* removed react-hooks
2025-06-12 19:00:30 -04:00
Dan Ditomaso
851da0707c Fix broken tests (#648) 2025-06-12 16:08:08 -04:00
Jeremy Gallant
4275bdd0c0 Remove deprecated meshtastic/js dependency (#638)
* Remove deprecated meshtastic/js dependency

* Bump dependency version

* Fix linting

---------

Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-06-11 10:09:29 -04:00
Dan Ditomaso
828e5d0903 Replace zustand state management with URL-based routing (#640)
* feat: added router

* feat: added params to messages page

* fixing tests, added translation labels

* Update src/i18n/locales/en/ui.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/components/Dialog/NodeDetailsDialog/NodeDetailsDialog.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/components/PageComponents/Map/NodeDetail.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/pages/Messages.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* updated dev tools

* fixing tests

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-06 18:23:49 -04:00
Jeremy Gallant
1cbd98ec53 Zod config validation (#635)
* Zod WIP

* Zod form validation

* DynamicForm testing

* Fix linting

* Delete rasterSource.ts

---------

Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-06-04 08:10:59 -04:00
Dan Ditomaso
df036d3904 Add commit sha to footer. (#636)
* feat: added commit sha to footer.

* added translation

* added padding

* updated styling
2025-06-01 20:41:25 -04:00
Kimberly Graham
08dbe94679 fix i18n files missing and Toast messages (#634)
* fix Toast messages

* Copy i18n files to dist using
vite-plugin-static-copy
2025-05-28 13:55:45 -04:00
Dan Ditomaso
24e9764fcb fix: updated namespace module (#632)
N33d this merged.
2025-05-27 11:13:51 -04:00
Dan Ditomaso
eb2a2717b1 Internationalization (i18n) (#627)
* `feat: added internationalization lib, added english labels`
* `fixes from code review`
* `feat: add crowdin github actions`
* `fix: added support for i18n in testing. Fixed broken tests`
* `fix: missing translations`
* `removed unneded import`
* `more components updated with missing translations`
* `fixed lint issue`
* `Refactor: updated how translations are scoped, updated all references`
* `fixing broken tests`
* `feat: added language switcher, updated some translations`
* `fixed linting issues`
* `reverting vite config`
* `add english group id's to command palette`
* `updated PR template for i18n`
2025-05-27 08:33:43 -04:00
jamon
9d74fe2d6e Remove autocomplete from message box (#630)
* Remove autocomplete from message box

The message box has autocomplete turned on, which causes some browsers to suggest previously written messages in a really annoying way.   This fixes that issue.

* Update src/components/PageComponents/Messages/MessageInput.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-27 07:36:16 -04:00
philon-
8413f6345c Fix #624 (#631) 2025-05-27 07:35:47 -04:00
philon-
37a53b747c Fix NodeInfoDialog initiation (#626) 2025-05-27 07:14:57 -04:00
philon-
a642080b90 Filter rework (#623)
* Rework filtering

Created common FilterComponents
Created common FilterControl
Abstracted common map logic into Map component
Reworked Node filtering for map page
Added Node filtering for nodes list
Added test for node filtering
Added toggle group UI package

* Debounce filterState change

* UI adjustments

---------

Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-05-22 15:11:32 -04:00
Dan Ditomaso
9cb5cffdb1 Update README.md
Remove references to `master` replace with `main`
2025-05-21 11:58:03 -04:00
philon-
57b9942cce Add RSSI fields for Paxcounter module (#620)
Co-authored-by: philon- <philon-@users.noreply.github.com>
2025-05-19 12:36:39 -04:00
philon-
1274584497 Feature: Admin PKI fields (#619)
* Add admin PKI fields

* Renaming state ref

* WIP: Refactoring

* Refactoring Security Config

* Ensure admin keys have been set before allowing managed mode
2025-05-16 10:24:41 -04:00
philon-
513a285fee Feature: Node favourites (and ignores) (#618)
* Add favourite icon to node Avatar

* Favourites WIP

* Save isFavorite and isIgnored to device

* Fix spelling

* Clean up

* Always sort favorites first

* Add unread count to "Messages" top level menu

* Renaming, UI tweaks

* Add hook tests

* Handle undefined node better
2025-05-13 08:45:24 -04:00
philon-
b2bb3baa01 Add check for undefined hopsAway (#616)
* Add check for undefined hopsAway

Better UI for already "fixed" #351

* Change conditional
2025-05-12 11:54:06 -04:00
Aria Stewart
3f933dd166 Remove case-duplicated sidebarButton.tsx (#617) 2025-05-11 20:01:43 -04:00
Dan Ditomaso
1180b9afb0 fix: moved all svgs into public / dist folder (#615) 2025-05-09 20:57:38 -04:00
philon-
b4ce6efd7b Fix node list sorting, dark mode text colors (#613)
* Fix node list sorting, dark mode text colors

* Update tests

* Remove unused import

* Fix warnings for missing DialogDescription
2025-05-08 12:54:18 -04:00
Dan Ditomaso
da0ada925f fix: removed overly complex scrolling logic in channel chat (#612) 2025-05-06 12:40:07 -04:00
Dan Ditomaso
f9346931f8 update readme with deployment schedule (#611) 2025-05-06 10:10:24 -04:00
Dan Ditomaso
1d18abf6c1 fix: connect new node no longer crashes. (#610) 2025-05-06 10:08:42 -04:00
Dan Ditomaso
a644d30228 Add github action to release to stable (#590)
* feat: added github action workflow to release to stable

* updated trigger logic
2025-05-05 13:20:49 -04:00
Dan Ditomaso
1c453e2981 fix: couple of UI updates, fix: add pre release support to release workflow (#609) 2025-05-05 11:47:36 -04:00
philon-
170abfcc2f fix: Adjust table odd/even colors (#606) 2025-05-05 11:23:37 -04:00
philon-
0539b15ddc Fix #607 (#608) 2025-05-04 20:08:16 -04:00
Dan Ditomaso
bbadb1a917 chore: optimize deno workflow for CI/CD (#605)
* chore: optimize deno workflow for CI/CD

* add install step
2025-05-04 16:39:19 -04:00
Dan Ditomaso
480ca46a95 chore: lint/format all files (#604)
* chore: lint/format all files

* Fix config sidebar button state (#602)

* chore: Update deno.lock version and add Radix UI slider component (#601)

* fix: improve how table addresses even/odd rows

---------

Co-authored-by: philon- <philon-@users.noreply.github.com>
Co-authored-by: Kamil Dzieniszewski <kamil.dzieniszewski@gmail.com>
2025-05-04 15:55:04 -04:00
Kamil Dzieniszewski
b7bdb1a502 chore: Update deno.lock version and add Radix UI slider component (#601) 2025-05-04 15:29:34 -04:00
philon-
3be528d03a Fix config sidebar button state (#602) 2025-05-04 15:28:47 -04:00
Dan Ditomaso
ebc386cfa5 Merge pull request #599 from danditomaso/fix/update-telemetry-labels
fix: updated telemetry field labels
2025-05-04 11:50:58 -04:00
Dan Ditomaso
35f3a347ba fix: updated telemtry field labels 2025-05-03 21:27:26 -04:00
Dan Ditomaso
cfcc9f82d8 Merge pull request #596 from philon-/style-fixes
Minor style fixes
2025-05-03 13:28:22 -04:00
Dan Ditomaso
7ab4254cd0 Merge pull request #597 from danditomaso/fix/content-overflow-issue
fix: defined height to html/body elements
2025-05-03 13:27:54 -04:00
Dan Ditomaso
e3857e61c6 fix: defined height to html/body elements 2025-05-03 13:24:00 -04:00
philon-
a02579d6dd Minor style fixes 2025-05-03 00:27:12 +02:00
Dan Ditomaso
79910dfec7 fix: removed console logs in code (#592) 2025-05-02 11:48:18 -04:00
Austin
b40540b118 Fix upload build.tar (#591) 2025-05-02 10:57:17 -04:00
Dan Ditomaso
99711fc44e Remove duplicate node logic, UI Update, flatten build output (#586)
* refactor nodes to getNodes fn. ui updates

* fixed several styling issues

* fix: message specific styling/overflow

* added footer, fixed tests. styling

* fix: added theme support back to app component

* fix: hide emojis/reactions

* fix: added more padding to content element

* fix: fixed padding in content element

* updated color scheme

* fix: more dark mode styling improvements

* fix: padding and alignment fixes

* fix: prevent left sidebar collapse, added battery component

* fix: change scrollbars to "tiny" style, improved message scrolling, fixed bug with message input

* message store fixes, ui fixes

* fix: disabled message persistance until after release
2025-05-02 09:00:24 -04:00
Dan Ditomaso
3eafad7261 Merge pull request #585 from philon-/feature/map-filtering
Map filtering improvements
2025-04-29 15:29:06 -04:00
Jeremy Gallant
80905d9d29 Change colors to slate 2025-04-29 15:35:34 +02:00
Jeremy Gallant
34db0da87c Add map filter groups / more filters / update UI 2025-04-28 17:38:58 +02:00
Jeremy Gallant
ff33554716 Add hover: and active: styling 2025-04-24 20:30:31 +02:00
Jeremy Gallant
f399d17721 Added map filter indication
Added map filter indication
+ some more type fixes...
2025-04-24 20:12:41 +02:00
Dan Ditomaso
ce71f22316 Merge pull request #580 from philon-/feature/map-filtering
Add filters to node map
2025-04-24 08:52:55 -04:00
Dan Ditomaso
1f3f76373d Merge pull request #583 from danditomaso/fix-remove-assets-output-dir
fix: keep js and css assets in same output directory
2025-04-24 07:53:39 -04:00
Dan Ditomaso
c5fe2f5e68 fix: dont put js and css assets in sub-directory in output 2025-04-23 23:12:54 -04:00
Dan Ditomaso
c050998f3d Merge pull request #582 from meshtastic/danditomaso-patch-1
Update ci.yml
2025-04-23 15:48:37 -04:00
Dan Ditomaso
4802a8f6e6 Update ci.yml 2025-04-23 14:14:00 -04:00
Jeremy Gallant
03e516e568 Slider - additional props 2025-04-23 16:41:20 +02:00
Jeremy Gallant
ef37397969 Remove ! 2025-04-23 07:10:04 +02:00
Jeremy Gallant
c6d122008b Unique id 2025-04-22 23:26:49 +02:00
Jeremy Gallant
3dce031f8e Stricter typing, adjuster colors, mandatory props 2025-04-22 23:18:26 +02:00
philon-
91d8776637 Merge branch 'meshtastic:master' into feature/map-filtering 2025-04-22 20:28:05 +02:00
Dan Ditomaso
01f242b7c3 Merge pull request #577 from philon-/fix/495
Fix #495 - Rescale traceroute SNR
2025-04-22 14:09:45 -04:00
Jeremy Gallant
d5cf71c840 Add filters to node map 2025-04-22 19:04:42 +02:00
Jeremy Gallant
5ba70d9764 Fix #495 - Rescale traceroute SNR 2025-04-19 22:14:03 +02:00
Dan Ditomaso
673476d773 Merge pull request #573 from danditomaso/feat/add-copy-text-to-input
Add Copy to Clipboard option for input fields.
2025-04-13 17:09:40 -04:00
Dan Ditomaso
5eb9fda015 Merge pull request #574 from danditomaso/issue-557-transparent-background
fix: removed transparent toast background
2025-04-13 11:39:28 -04:00
Dan Ditomaso
81586caea0 fix: removed transparent toast background 2025-04-13 08:07:17 -04:00
Dan Ditomaso
a195126df1 fixed when grid collapose's to single column 2025-04-12 22:05:42 -04:00
Dan Ditomaso
b3783bab40 added longer field length 2025-04-12 21:59:58 -04:00
Dan Ditomaso
33d0f93e68 Merge branch 'master' into feat/add-copy-text-to-input 2025-04-12 21:36:11 -04:00
Dan Ditomaso
2050b05d6a feat: add copy text option to input fields. 2025-04-12 21:11:52 -04:00
Dan Ditomaso
38754b9d1a Merge pull request #572 from danditomaso/fix/improve-responsiveness
Improve form responsiveness
2025-04-12 20:26:44 -04:00
Dan Ditomaso
1867484032 fix: improve-responsiveness 2025-04-12 12:46:01 -04:00
Dan Ditomaso
b52ed19649 Merge pull request #571 from danditomaso/fix/improve-refresh-keys-dialog
fix: improvements to refresh dialog
2025-04-10 23:09:41 -04:00
Dan Ditomaso
d53ababf7d fix: improvements to refresh dialog 2025-04-10 16:51:29 -04:00
Hunter Thornsberry
ff43763721 Merge pull request #568 from Hunter275/clock-settings 2025-04-10 13:30:52 -04:00
Hunter Thornsberry
c44d7633f2 Merge pull request #570 from danditomaso/fix/minus-node-num 2025-04-10 13:30:09 -04:00
Dan Ditomaso
08d641eb42 fix: ensured node number on loading screen cant be negitive. 2025-04-10 12:19:15 -04:00
Hunter275
a243a044b9 add use12hClock support 2025-04-10 01:48:32 -04:00
Dan Ditomaso
c95a819eaf Merge pull request #566 from danditomaso/issue-564-multiple-connect-clicks-on-connect-dialog
Multiple clicks on "Connect" button, creates multiple nodes.
2025-04-08 08:20:36 -04:00
Dan Ditomaso
ce5ae675ea fix: hoisted state to parent in order to coordinate connection 2025-04-07 20:27:51 -04:00
Dan Ditomaso
0828618c0d Merge pull request #563 from danditomaso/issue-550-incorrect-text-in-dialog
Incorrect text in PKI dialog
2025-04-07 20:19:33 -04:00
Dan Ditomaso
7267101021 fix: extended dialog to allow for dynamic title/description 2025-04-07 15:02:12 -04:00
Dan Ditomaso
0e868cef58 renamed dialog, added reactions menu 2025-04-07 11:42:15 -04:00
Dan Ditomaso
e410ccb2f4 Merge pull request #562 from danditomaso/fix/missing-import
fix: added missing imports
2025-04-05 13:01:19 -04:00
Dan Ditomaso
c5b3f2ece6 fix: added missing imports 2025-04-05 12:57:42 -04:00
Dan Ditomaso
35353c58cb Merge pull request #561 from danditomaso/fix/failing-test
fix: refactor to fix merge issues with  messageStore and unread counts
2025-04-05 11:49:11 -04:00
Dan Ditomaso
e80d8e73ae fix: refactor to fix merge issues with messageStore and unread counts 2025-04-05 11:46:32 -04:00
Dan Ditomaso
494a35a0c3 Merge pull request #497 from Hunter275/unread-counts
Unread Counts
2025-04-05 08:40:54 -04:00
Dan Ditomaso
818bbb4a30 fix broken test 2025-04-05 08:39:27 -04:00
Dan Ditomaso
4755c0eeb9 refactor to integrate messageStore and unreadCounts 2025-04-04 22:22:35 -04:00
Dan Ditomaso
c8c89fdc95 Merge branch 'master' into unread-counts 2025-04-04 08:58:13 -04:00
Dan Ditomaso
52e0924f1c Merge pull request #560 from danditomaso/fix/node-detail-use-message-store
fix: update node details page to use message store
2025-04-03 22:42:48 -04:00
Dan Ditomaso
645c758b42 fixed: removed unneeded prop 2025-04-03 22:41:10 -04:00
Dan Ditomaso
4dc7788981 fixed typo 2025-04-03 22:40:30 -04:00
Dan Ditomaso
9fa945a863 fix: update node details page to use message store 2025-04-03 22:37:50 -04:00
Dan Ditomaso
38b8695441 Merge pull request #536 from danditomaso/add-message-persistance
Add message persistence using IndexedDB
2025-04-03 22:28:25 -04:00
Dan Ditomaso
eadadb5d1d keyed conversations against from/to, updated tests 2025-04-03 17:03:08 -04:00
Dan Ditomaso
5f424e2e0b Merge branch 'master' into add-message-persistance 2025-04-02 18:02:57 -04:00
James Thomas
d807cd2de7 Using existing Link component and standardizing colors 2025-04-02 18:00:44 -04:00
James Thomas
0b4e3a8da9 Cleanup and add link to official docs 2025-04-02 18:00:44 -04:00
James Thomas
31be5e9a25 Adding connection failure warning 2025-04-02 18:00:44 -04:00
vidplace7
367538eeea GHA: Attach build.tar to release 2025-04-02 18:00:33 -04:00
Dan Ditomaso
442c1cb5f1 fix: moved meshtastic packages into package.json 2025-04-02 18:00:33 -04:00
Dan Ditomaso
a333e4524f updated deps 2025-04-02 18:00:12 -04:00
Hunter275
1e54f7d99b fix for non-Primary channels 2025-04-02 17:59:59 -04:00
Dan Ditomaso
9f2aa8282d adding tests 2025-04-02 17:59:59 -04:00
Dan Ditomaso
8d5dc440d0 feat: add udp over mesh toggle 2025-04-02 17:59:59 -04:00
Dan Ditomaso
8fffde0165 wip 2025-04-02 17:59:59 -04:00
James Thomas
1a6e99971a Extended loading 2025-04-02 17:58:40 -04:00
Dan Ditomaso
4de88c3add fixed: import issue 2025-04-02 17:58:40 -04:00
Dan Ditomaso
76374893e3 added tests 2025-04-02 17:58:40 -04:00
Dan Ditomaso
edc17b304a feat: added reboot to OTA in command menu 2025-04-02 17:58:40 -04:00
Dan Ditomaso
ec7b4528f6 added reboot to command menu 2025-04-02 17:58:30 -04:00
Dan Ditomaso
8d75c4afb1 fix: docker build process 2025-04-02 17:58:30 -04:00
James Thomas
b30fbf90b9 Prevent tooltip from appearing by default 2025-04-02 17:58:30 -04:00
James Thomas
8fb95e1b06 Lint 2025-04-02 17:58:30 -04:00
James Thomas
f5e1a0569f Lint 2025-04-02 17:58:30 -04:00
James Thomas
929f87b411 Adding DM from Map function 2025-04-02 17:58:30 -04:00
Dan Ditomaso
59d97008f2 feat: added tzdef to device config 2025-04-02 17:58:30 -04:00
Dan Ditomaso
540b8ebb4d Merge pull request #548 from James9074/tls-warning
Adding UX Feedback For Failed Device Connections Over HTTP/s
2025-04-02 13:12:39 -04:00
Dan Ditomaso
109d4afce2 Merge pull request #556 from vidplace7/release-buildtar
GHA: Attach build.tar to release
2025-04-02 10:09:17 -04:00
vidplace7
aab8bce78e GHA: Attach build.tar to release 2025-04-02 09:18:20 -04:00
James Thomas
d2c33b4caf Merge branch 'meshtastic:master' into tls-warning 2025-04-02 08:32:23 -04:00
Dan Ditomaso
633b99d6b2 Merge pull request #554 from danditomaso/fix-pkg-import-issue
fix: moved meshtastic packages into package.json
2025-04-01 20:48:17 -04:00
Dan Ditomaso
87159b4eee fix: moved meshtastic packages into package.json 2025-04-01 20:45:36 -04:00
Dan Ditomaso
6d39ecc7b9 Merge pull request #553 from danditomaso/update-deps-to-latest
updated deps to latest
2025-04-01 16:51:29 -04:00
Dan Ditomaso
7738661b7c updated deps 2025-04-01 16:50:39 -04:00
Dan Ditomaso
6443544a6b added dialog to warn before clearing all messages 2025-04-01 14:50:41 -04:00
Dan Ditomaso
4689ebe3ce Merge pull request #551 from Hunter275/position-precision-v2
Fix Position Precision for non-Primary channels
2025-04-01 11:19:33 -04:00
Hunter275
6cd8ce5102 fix for non-Primary channels 2025-03-31 23:14:20 -04:00
Dan Ditomaso
a56ac84186 add enums, improve tests, add styling 2025-03-31 21:28:58 -04:00
James Thomas
443a9ea101 Merge branch 'meshtastic:master' into tls-warning 2025-03-31 09:29:45 -04:00
James Thomas
0faafe8bc4 Using existing Link component and standardizing colors 2025-03-30 21:43:25 -04:00
James Thomas
9948701127 Cleanup and add link to official docs 2025-03-30 21:01:25 -04:00
James Thomas
ffae92d233 Adding connection failure warning 2025-03-30 20:52:04 -04:00
Dan Ditomaso
fed65d9c8b Merge pull request #547 from danditomaso/issue-523-add-udp-toggle
feat: Add udp over mesh toggle
2025-03-30 20:13:03 -04:00
Dan Ditomaso
8f225f4d28 Merge pull request #544 from James9074/loading-device
Cleaner Device Loading UX
2025-03-30 17:26:10 -04:00
Dan Ditomaso
11e820d1d0 Merge pull request #543 from danditomaso/issue-542-add-reboot-to-command-menu
added reboot to command menu
2025-03-30 17:25:30 -04:00
Dan Ditomaso
95fc72173f adding tests 2025-03-29 22:59:46 -04:00
Dan Ditomaso
03b5c639fb feat: add udp over mesh toggle 2025-03-29 22:19:53 -04:00
Dan Ditomaso
4d30558aca Merge pull request #546 from danditomaso/issue-545-nightly-docker-not-starting
Fixed Docker Builds Not Serving Site on 8080
2025-03-29 17:02:06 -04:00
Dan Ditomaso
7f376186b4 Merge pull request #540 from James9074/dm-from-map
Allow users to DM nodes directly from the map
2025-03-29 16:00:56 -04:00
Dan Ditomaso
0de24c41ed fix: docker build process 2025-03-29 15:54:15 -04:00
James Thomas
88c4f84edb Extended loading 2025-03-28 22:49:21 -04:00
Dan Ditomaso
74db087d7d updated node details with new messaging features. 2025-03-28 21:22:10 -04:00
Dan Ditomaso
e00239562c Update src/components/PageComponents/Config/Position.tsx
Co-authored-by: James Thomas <james9074@gmail.com>
2025-03-28 21:14:42 -04:00
Dan Ditomaso
bf9557040f fixed: import issue 2025-03-28 21:12:13 -04:00
Dan Ditomaso
6d9a44a0e3 added tests 2025-03-28 21:11:01 -04:00
Dan Ditomaso
35aabdc900 feat: added reboot to OTA in command menu 2025-03-28 21:06:37 -04:00
Dan Ditomaso
163502156d Merge pull request #541 from danditomaso/add-tzdef
feat: added tzdef to device config
2025-03-28 14:27:12 -04:00
Dan Ditomaso
8baa5d84b9 added reboot to command menu 2025-03-28 12:12:56 -04:00
Dan Ditomaso
c55fdbd982 wip 2025-03-28 11:45:48 -04:00
James Thomas
8da38ab2e4 Prevent tooltip from appearing by default 2025-03-28 09:57:35 -04:00
Dan Ditomaso
dddb781627 feat: added tzdef to device config 2025-03-27 20:50:27 -04:00
James Thomas
77b3a7ac85 Lint 2025-03-27 17:35:18 -04:00
James Thomas
626970865f Lint 2025-03-27 17:34:42 -04:00
James Thomas
c0308532a1 Adding DM from Map function 2025-03-27 17:21:40 -04:00
Dan Ditomaso
8df67bf76a Merge branch 'master' into add-message-persistance 2025-03-26 16:09:12 -04:00
Dan Ditomaso
80d4670204 state store cleanup, added tests 2025-03-26 15:22:14 -04:00
Dan Ditomaso
a378cce0be Merge pull request #538 from danditomaso/issue-537-position-flags-undefined
fix: ensured undefined position flags are handled
2025-03-26 13:08:55 -04:00
Dan Ditomaso
488fd61558 fix: ensured undefined position flags are handled 2025-03-25 15:49:44 -04:00
Dan Ditomaso
ed2ab36ed4 feat: added message persistance 2025-03-25 15:23:24 -04:00
Dan Ditomaso
0d6c5878fc WIP 2025-03-24 15:37:51 -04:00
Dan Ditomaso
dcbfb08f26 Merge pull request #528 from danditomaso/add-dismiss-to-key-reminder
Refactor useBackupReminder hook
2025-03-23 22:20:57 -04:00
Hunter275
dab76df131 reorder tests so they don't step on each other 2025-03-21 23:43:57 -04:00
Dan Ditomaso
a7a448cbcd refactor: improved how reminder expiry dates are handled. 2025-03-21 23:34:20 -04:00
Dan Ditomaso
1780c6fb2a refactor: updated how expiry dates are handled. 2025-03-21 22:39:40 -04:00
Hunter Thornsberry
2d54df7dba Merge pull request #532 from Hunter275/node-count-off-by-one
Subtract one from node count
2025-03-21 14:39:24 -04:00
Hunter Thornsberry
890674eea3 subtract one from node count 2025-03-21 14:26:19 -04:00
Hunter Thornsberry
d1c19d9d3e add hasNodeError for tests 2025-03-21 14:20:27 -04:00
Hunter Thornsberry
11b052e5bb Merge branch 'master' into unread-counts 2025-03-21 10:36:09 -04:00
Dan Ditomaso
93a70dfd47 Merge pull request #529 from danditomaso/feat/update-readme
Updated repo readme
2025-03-21 07:53:24 -04:00
Dan Ditomaso
6ac8646323 Merge pull request #500 from Hunter275/browser-feature-rework
Update style and wording of browser support for connection types
2025-03-20 21:40:12 -04:00
Dan Ditomaso
a215da1ebe Merge pull request #526 from bkimmel/bkimmel/reorder-nodes-columns
reorder columns in Nodes page
2025-03-20 16:54:51 -04:00
Dan Ditomaso
22dbfbcc09 feat: added never remind me to key reminder. 2025-03-20 14:40:15 -04:00
Dan Ditomaso
6341d564d3 feat: update readme with domain changes 2025-03-20 12:06:21 -04:00
bkimmel
28cc7b9800 reorder columns in Nodes page 2025-03-19 17:50:20 -04:00
Dan Ditomaso
5a142e671d Merge pull request #525 from danditomaso/fix/remove-react-scan
Revert: Remove react scan
2025-03-19 14:55:33 -04:00
Dan Ditomaso
ba3d45584d adding lock file 2025-03-19 13:52:25 -04:00
Dan Ditomaso
f54c0dd836 fix: removed react-scan due to issues with bluetooth 2025-03-19 13:46:56 -04:00
Dan Ditomaso
a6427a9ed1 Merge pull request #520 from bkimmel/bkimmel/labels-on-icons
add a label to theme icon
2025-03-19 13:26:40 -04:00
Dan Ditomaso
11058dbf3b Merge pull request #516 from danditomaso/feat/add-key-mismatch-error-handling
feat: add error handling for key mismatch
2025-03-19 12:42:38 -04:00
Dan Ditomaso
d062c2f1ab Merge pull request #522 from danditomaso/fix-node-details-styling
fix: styling issues in NodeDialog & TraceRoute components
2025-03-19 08:11:08 -04:00
bkimmel
1f109d161f deno format 2025-03-18 23:28:44 -04:00
bkimmel
f2d6daa9fc safety coalesce 2025-03-18 22:57:22 -04:00
bkimmel
9634e1ce39 PR Feedback: h/t Dan & Hunter 2025-03-18 22:52:58 -04:00
Dan Ditomaso
64055a5aeb fixed spacing and updated wording on dialog 2025-03-18 22:09:20 -04:00
Dan Ditomaso
ad366e6bab added additional routing packet error handler 2025-03-18 19:44:09 -04:00
Dan Ditomaso
9399104914 fix: resolved issues with styling 2025-03-18 15:21:58 -04:00
bkimmel
f82bc660b0 add a label to theme icon 2025-03-18 00:06:38 -04:00
Dan Ditomaso
ed13af2382 Merge pull request #514 from bkimmel/bkimmel/nodespage-fixes-1
small-scale Nodes page fixes
2025-03-17 22:49:53 -04:00
bkimmel
e4c2952e49 dark mode adjustments 2025-03-17 18:15:43 -04:00
Dan Ditomaso
0830eb9971 Merge pull request #518 from danditomaso/issue-515-add-node-count
feat: added node count to sidebar
2025-03-17 17:10:06 -04:00
Dan Ditomaso
be9b61ec0c feat: added node count to sidebar 2025-03-17 13:20:21 -04:00
Hunter Thornsberry
be0fe08f2f Merge pull request #513 from Hunter275/position-precision-fix
Position Precision Rework
2025-03-16 23:06:55 -04:00
Dan Ditomaso
3f8d3389d5 feat: add error handling for key mismatch 2025-03-16 22:56:58 -04:00
Hunter Thornsberry
7e1ba42873 remove defined css class and just use tailwind 2025-03-16 19:45:27 -04:00
Hunter Thornsberry
20af1b4d34 change submit to be outlined 2025-03-16 19:35:26 -04:00
bkimmel
207061e9d8 small-scale Nodes page fixes 2025-03-16 09:41:50 -04:00
Hunter Thornsberry
6633fc9c55 Merge branch 'master' into position-precision-fix 2025-03-16 01:34:57 -04:00
Hunter275
52b80613f8 position precision rework 2025-03-16 01:33:05 -04:00
Hunter Thornsberry
0bef82ec32 don't update unred if the channel/dm is active 2025-03-14 15:44:02 -04:00
Hunter Thornsberry
f80bb6c42d DM vs Channel message detection 2025-03-14 15:28:45 -04:00
Hunter275
db2cb8cb42 update style and wording of browser support for connection types 2025-03-13 01:29:03 -04:00
Dan Ditomaso
c320d7d173 Merge pull request #499 from Hunter275/position_precision_stop_gap
Stop Gap: Remove Position Precision
2025-03-12 23:42:44 -04:00
Hunter Thornsberry
db50bb5c1b stop gap for channel position precision until fix is worked out 2025-03-12 22:32:01 -04:00
Hunter Thornsberry
01a74829fc Merge branch 'master' into unread-counts 2025-03-11 16:25:58 -04:00
Hunter Thornsberry
7b77b7f5e9 remove test values 2025-03-11 16:21:44 -04:00
Hunter Thornsberry
ce8fcd2269 simplify device list and tests 2025-03-11 16:20:22 -04:00
Hunter Thornsberry
f6f64eca10 tests 2025-03-10 23:33:39 -04:00
Dan Ditomaso
3240ac57f7 Merge pull request #492 from bkimmel/issue459/direct_nodes
Fix: issue 459 / sort direct nodes
2025-03-10 21:57:08 -04:00
Dan Ditomaso
2008b09ca3 Merge pull request #494 from danditomaso/issue-486-are-you-sure-dialog
Issue 486 are you sure dialog
2025-03-10 21:06:30 -04:00
Dan Ditomaso
491f72b426 fix for broken test 2025-03-10 21:00:01 -04:00
Dan Ditomaso
a6f46bd38a commit lock 2025-03-10 20:56:32 -04:00
Hunter275
c103d7012b tests 2025-03-10 20:54:42 -04:00
Dan Ditomaso
2cebb8eee2 refactor: added close button back to dialog 2025-03-10 20:53:09 -04:00
Dan Ditomaso
33ad9f989c fix: fixed vitest file after merge conflict 2025-03-10 20:46:46 -04:00
bkimmel
c590ab2ff5 Fix: issue 459 / sort direct nodes 2025-03-10 20:31:52 -04:00
Dan Ditomaso
9da949d27a Merge branch 'master' into issue-486-are-you-sure-dialog 2025-03-10 20:31:33 -04:00
Dan Ditomaso
f1a58f0434 refactor: fixed unsafe roles dialog and hook logic, added tests 2025-03-10 20:30:04 -04:00
Dan Ditomaso
0296b241e4 Merge pull request #487 from danditomaso/issue-455-cant-scroll-up-in-chat
fix: resolved issue with being unable to scroll up in the input field
2025-03-10 15:11:15 -04:00
Dan Ditomaso
344ad48858 fix: improved style of the message input field 2025-03-10 09:26:01 -04:00
Dan Ditomaso
97f2abb582 fix: added tests to branch 2025-03-09 12:57:51 -04:00
Dan Ditomaso
eca5d780c1 feat: added are you sure dialog 2025-03-09 12:57:37 -04:00
Hunter275
1f1a3c5de8 spread on the map 2025-03-09 00:57:52 -05:00
Dan Ditomaso
844a6316f6 fix: remove unneeded role 2025-03-08 21:15:34 -05:00
Dan Ditomaso
d39c5ed079 Merge pull request #490 from danditomaso/issue-489-bluetooth-uuid-not-set
fix: restored correct BLE service uuid to BLE devices filter
2025-03-08 21:01:22 -05:00
Dan Ditomaso
09bb0bc43a fix: added ble header to vercel config 2025-03-08 16:28:20 -05:00
Dan Ditomaso
266e27bfe9 fix: added BLE uuid back to BLE connection component 2025-03-08 16:26:26 -05:00
Dan Ditomaso
5b11131e08 fix: remove unneeded role 2025-03-08 12:19:26 -05:00
Hunter Thornsberry
3bfd96defe wip 2025-03-07 23:59:52 -05:00
Hunter275
cad590f993 wip 2025-03-07 22:01:34 -05:00
Dan Ditomaso
d70b14b12b fix: failing tests 2025-03-06 16:09:22 -05:00
Dan Ditomaso
c115ac0749 fix: improved hover state for message input button 2025-03-06 14:39:09 -05:00
Dan Ditomaso
d54a612e0b fix: restore aliased paths to vite config 2025-03-06 14:28:07 -05:00
Dan Ditomaso
d379769672 fix: resolved issue with being unable to scroll up in the input field 2025-03-06 14:09:47 -05:00
Dan Ditomaso
b670ffe407 Merge pull request #484 from varanauskas/patch-1
Update HTTP.test.tsx to ensure "https://" prefix is used if needed
2025-03-05 20:28:54 -05:00
Tadas Varanauskas
4ffbe03b22 Update HTTP.test.tsx to ensure "https://" prefix is used if needed
Small test update to prevent regression of #481 

#482 fixed the issue, this new test would have failed before, and will prevent reoccurrence of the issue
2025-03-05 20:09:11 +02:00
Dan Ditomaso
6a438470cf Merge pull request #483 from danditomaso/fix/restore-window-to-http
fix: remove GlobalThis and use window instead
2025-03-05 10:53:52 -05:00
Dan Ditomaso
4d0d1da691 fix: remove GlobalThis and use window instead 2025-03-05 08:54:26 -05:00
Dan Ditomaso
39f26f475b Merge pull request #482 from danditomaso/issue-481-node-connecting-on-https
fix: update TLS setting if URL is using HTTPS

Fixes #481
2025-03-05 08:30:18 -05:00
Dan Ditomaso
35fed173af fix: update TLS setting if URL is using HTTPS 2025-03-05 08:14:59 -05:00
Dan Ditomaso
a8b0515949 Merge pull request #480 from danditomaso/issue-479-node-connecting-on-https
fix: restored https toggle functionality. added tests
2025-03-04 14:38:29 -05:00
Dan Ditomaso
bd9d599934 fix: if url is already https, toggle should be checked 2025-03-04 14:10:46 -05:00
Dan Ditomaso
b40079cdc9 fix: restored https toggle functionality. added tests 2025-03-04 13:43:02 -05:00
Dan Ditomaso
b1cf4ef645 Merge pull request #477 from danditomaso/refactor/use-deno
Switch from Bun to Deno for dev environment
2025-03-03 20:56:00 -05:00
Dan Ditomaso
237c7bec3e Merge branch 'master' into refactor/use-deno 2025-03-03 20:55:16 -05:00
Dan Ditomaso
75596e7153 chore: fixes from deno linting/formatting 2025-03-03 20:42:46 -05:00
Hunter275
7968994090 fix for 'never' as well 2025-03-03 20:33:23 -05:00
Hunter275
7c84a582ba fix padding on last heard 2025-03-03 20:33:23 -05:00
Hunter275
9ad6c049f2 fix nodes page error, more cleanup is probably required for "undefined" hops away 2025-03-03 20:33:14 -05:00
Dan Ditomaso
04ecdd55fe fix overflow issue with stack trace 2025-03-03 20:33:05 -05:00
Dan Ditomaso
dbad25814c Reduced code duplication of ErrorBoundary, wrapped PageLayout with ErrorBoundary. 2025-03-03 20:33:05 -05:00
Dan Ditomaso
5af5364668 feat: add chirpy to error page 2025-03-03 20:32:56 -05:00
Dan Ditomaso
d28b4ce6d9 feat: add error boundary 2025-03-03 20:32:47 -05:00
Dan Ditomaso
f9066eced0 fix: added a notes fild to Dynamic form allowing for notes to inform users about using BLE and wifi at the same time. (#474) 2025-03-03 20:32:01 -05:00
Hunter Thornsberry
a60db5521d Merge pull request #478 from Hunter275/fix-nodes-page
Fix Nodes page
2025-03-03 09:39:47 -05:00
Hunter275
e1d4490d62 fix for 'never' as well 2025-03-02 22:44:59 -05:00
Hunter275
cc24605cdb fix padding on last heard 2025-03-02 22:42:55 -05:00
Hunter275
2647604798 fix nodes page error, more cleanup is probably required for "undefined" hops away 2025-03-02 22:22:02 -05:00
Hunter Thornsberry
6e3d326abb Merge pull request #458 from danditomaso/feat/add-error-boundary
feat: add error boundary
2025-03-02 22:12:17 -05:00
Dan Ditomaso
fc713f55fe fix: update package json scripts commands 2025-03-02 15:54:30 -05:00
Dan Ditomaso
81a1e0e550 fix: update process.env to import.meta 2025-03-02 15:23:57 -05:00
Dan Ditomaso
88587f358d refactor: move tsconfig into deno.json 2025-03-02 15:23:22 -05:00
Dan Ditomaso
99a66bfdc7 chore: updated readme 2025-03-02 14:52:46 -05:00
Dan Ditomaso
50eb2a827f chore: fixes from deno linting/formatting 2025-03-02 14:46:02 -05:00
Dan Ditomaso
db08542b39 refactor: switch to deno 2025-03-02 14:25:29 -05:00
Dan Ditomaso
cbcbafc4a3 fix: added a notes fild to Dynamic form allowing for notes to inform users about using BLE and wifi at the same time. (#474) 2025-03-02 14:43:07 +08:00
Tilen Komel
7e66dc7cac Merge pull request #476 from meshtastic/chore/removal-of-mapbox
Chore: Removal of mapbox-gl
2025-03-01 22:52:13 +01:00
Tilen Komel
62fa8df8d2 bun remove mapbox-gl 2025-03-01 22:08:37 +01:00
Dan Ditomaso
b888d8f4cf Merge branch 'master' into feat/add-error-boundary 2025-03-01 09:09:57 -05:00
Sacha Weatherstone
e224a4ebdf migrate to new transport-http 2025-03-01 16:12:56 +08:00
Sacha Weatherstone
977b5647f6 format 2025-03-01 14:14:21 +08:00
Sacha Weatherstone
5a62b67e79 use new packages for imports & new webserial transport 2025-03-01 14:00:06 +08:00
Sacha Weatherstone
f31ac24707 fix formatting 2025-03-01 13:34:05 +08:00
Sacha Weatherstone
a5589e232b update dependencies 2025-03-01 13:33:35 +08:00
Hunter Thornsberry
f65f750b7f Merge pull request #475 from danditomaso/issue-473-label-inputs-not-connected
fix: connected labels to inputs, improving accessibility and testability
2025-02-28 21:38:46 -05:00
Dan Ditomaso
fa85e83817 fix: connected labels to inputs, improving accessibility and testability 2025-02-28 14:59:17 -05:00
Dan Ditomaso
d978978677 Merge branch 'master' into feat/add-error-boundary 2025-02-28 09:05:03 -05:00
Dan Ditomaso
593c08f3e0 Merge pull request #469 from danditomaso/feat/add-react-scan-debugging
feat: add react scan debugging
2025-02-26 21:15:33 -05:00
Dan Ditomaso
801f8f38d2 Merge branch 'master' into feat/add-react-scan-debugging 2025-02-26 21:10:02 -05:00
Dan Ditomaso
8be849d982 Merge pull request #468 from danditomaso/issue-182-pwa-funcionality
feat: add PWA functionality to vite
2025-02-26 20:51:30 -05:00
Dan Ditomaso
8bfa58540b updated readme to discuss react scan 2025-02-26 20:47:47 -05:00
Dan Ditomaso
4a6eb0d3f8 feat: add react scan debugging 2025-02-26 14:24:56 -05:00
Dan Ditomaso
5c6ba38655 updated readme for pwa changes 2025-02-26 09:33:10 -05:00
Dan Ditomaso
5831967603 feat: added pwa functionality to vite 2025-02-26 09:27:08 -05:00
Dan Ditomaso
fe2360baf6 Merge pull request #466 from danditomaso/fix/tailwind-4-styling-updates
dark mode styling updates
2025-02-25 20:01:53 -05:00
Dan Ditomaso
3db2ede9d6 Merge pull request #462 from danditomaso/feat/add-support-for-unit-testing
feat: adding unit/ui testing support
2025-02-25 20:01:37 -05:00
Dan Ditomaso
25cd448d69 Merge pull request #460 from danditomaso/issue-389-admin-key-not-taking
fix: admin key can be saved/restored inside of web ui.
2025-02-25 20:01:22 -05:00
Tilen Komel
c6bb11ccc8 Merge pull request #467 from KomelT/fix/issue-465
Fix/issue 465
2025-02-25 21:44:41 +01:00
Dan Ditomaso
d8bf2f7d8e fix: updates to overall site styling in dark mode 2025-02-25 15:42:14 -05:00
Tilen Komel
079e60677e Biome 2025-02-25 20:55:15 +01:00
Tilen Komel
379ac46ec8 Add fix 2025-02-25 20:54:53 +01:00
Dan Ditomaso
f4417f984b fixed unsafe array access in component 2025-02-25 11:53:32 -05:00
Dan Ditomaso
9f8d88bb4e fix overflow issue with stack trace 2025-02-25 11:47:51 -05:00
Dan Ditomaso
cf4c3c1376 fixed unsafe array access in component 2025-02-25 09:40:59 -05:00
Dan Ditomaso
c39ef5916f running tests in CI/CD pipeline 2025-02-25 08:00:40 -05:00
Tilen Komel
edee3571be Merge pull request #464 from meshtastic/fix-readme-update
Update README.md
2025-02-25 13:48:08 +01:00
Tilen Komel
d039f7fd79 Fix readme warning section 2025-02-25 13:37:36 +01:00
Tilen Komel
34abbcb467 Update README.md 2025-02-25 13:22:13 +01:00
Dan Ditomaso
1d93e358ed Merge pull request #461 from danditomaso/fix/improve-github-issue-templates
fix: improved github feature request and bug templates
2025-02-24 19:42:40 -05:00
Dan Ditomaso
b4ada0449c Merge pull request #463 from meshtastic/revert-436-feat-add-formatting-github-action
Revert "feat: apply formatting as github action"
2025-02-24 15:17:16 -05:00
Dan Ditomaso
4490d178d0 Revert "feat: apply formatting as github action" 2025-02-24 15:14:57 -05:00
Dan Ditomaso
c9536c9ffd added some tests to utils folder 2025-02-24 12:39:25 -05:00
Dan Ditomaso
14e9bd304a feat: adding unit/ui testing support 2025-02-24 11:46:35 -05:00
Dan Ditomaso
5df409475e feat: adding unit/ui testing support 2025-02-24 11:45:34 -05:00
Dan Ditomaso
7427623c6e feat: added PR template 2025-02-24 11:25:14 -05:00
Dan Ditomaso
16d04bb878 fix: improved github feature request and bug templates 2025-02-24 10:05:58 -05:00
Dan Ditomaso
9eda22b5db Reduced code duplication of ErrorBoundary, wrapped PageLayout with ErrorBoundary. 2025-02-24 09:38:49 -05:00
Dan Ditomaso
ebf64b5bcb fix: admin key can be saved/restored inside of web ui. 2025-02-23 22:17:08 -05:00
Dan Ditomaso
fb2a057c05 feat: add chirpy to error page 2025-02-22 15:14:44 -05:00
Dan Ditomaso
635d0673bf feat: add error boundary 2025-02-22 13:51:50 -05:00
Hunter Thornsberry
864f8075d9 Merge pull request #454 from danditomaso/feat/add-nightly-gh-action 2025-02-22 11:42:49 -05:00
Dan Ditomaso
92a84af454 feat: added nightly github action. updated docs 2025-02-21 16:30:48 -05:00
Tilen Komel
1560d1e18c Merge pull request #452 from danditomaso/fix/switch-pnpm-to-bun
fix: changed pnpm to bun
2025-02-21 18:50:11 +01:00
Dan Ditomaso
bbb8384d66 fix: changed pnpm to bun 2025-02-21 12:39:46 -05:00
Dan Ditomaso
b23e197178 Merge pull request #451 from meshtastic/revert-446-fix/update-lock-file-version
Revert "fix: update pnpm lock file version"
2025-02-21 12:24:16 -05:00
Dan Ditomaso
ff6515269b Revert "fix: update pnpm lock file version" 2025-02-21 12:24:00 -05:00
Dan Ditomaso
d6f2d3a73f Merge pull request #450 from meshtastic/revert-448-fix/try-bun-package-manager
Revert "fix: Try using bun package manager to fix lock files issues in vercel"
2025-02-21 12:23:30 -05:00
Dan Ditomaso
9b598aa3d7 Revert "fix: Try using bun package manager to fix lock files issues in vercel" 2025-02-21 12:23:00 -05:00
Dan Ditomaso
88e0c6deda Merge pull request #448 from danditomaso/fix/try-bun-package-manager
fix: Try using bun package manager to fix lock files issues in vercel
2025-02-21 08:20:44 -05:00
Dan Ditomaso
1f3ff3dc03 fix: try using bun package manager with vercel 2025-02-21 08:17:30 -05:00
Dan Ditomaso
9cb449aa31 Merge pull request #446 from danditomaso/fix/update-lock-file-version
fix: update pnpm lock file version
2025-02-20 22:07:58 -05:00
Dan Ditomaso
3afbc9a693 manually specify pnpm version in gh workflows 2025-02-20 22:06:06 -05:00
Dan Ditomaso
4ce84549c7 fix: update pnpm lock file version 2025-02-20 22:03:23 -05:00
Dan Ditomaso
ac550d3b44 Merge pull request #445 from danditomaso/fix/switch-style-issue
fix: improve switch dark mode style, fixed merge conflict bug in HTTP component.
2025-02-20 21:23:13 -05:00
Dan Ditomaso
c9dab8d83c fix: improved dark mode styles, fixed bug in http. 2025-02-20 21:21:33 -05:00
Dan Ditomaso
5e18c8d256 Merge pull request #417 from danditomaso/switch-rsbuild-to-vite
feat: switch to Vite 6.x
2025-02-20 21:02:30 -05:00
Dan Ditomaso
349a2bf855 Merge branch 'master' into switch-rsbuild-to-vite 2025-02-20 21:01:58 -05:00
Dan Ditomaso
3928d378f5 feat: updated app to tailwind 4.x 2025-02-20 20:54:19 -05:00
Dan Ditomaso
36d4f22007 feat: add required engines to package.json 2025-02-20 20:54:09 -05:00
Dan Ditomaso
cbbe9be819 fix: validate bluetooth pin is 6 characters. 2025-02-20 20:52:08 -05:00
Dan Ditomaso
ede6523678 feat: updated app to tailwind 4.x 2025-02-20 20:51:08 -05:00
Dan Ditomaso
ce086ffa82 fix: fixing styling issues 2025-02-20 19:00:47 -05:00
Dan Ditomaso
a1715ef686 feat: switch to vite 6.1 2025-02-20 15:59:00 -05:00
Justin
2c8b206903 fixed tls switch for http connections 2025-02-20 15:57:54 -05:00
Dan Ditomaso
5938f91861 fix: validate bluetooth pin is 6 characters. 2025-02-20 15:57:38 -05:00
Dan Ditomaso
b959a59e7b feat: updated app to tailwind 4.x 2025-02-20 15:56:51 -05:00
Dan Ditomaso
39c1176311 feat: add required engines to package.json 2025-02-20 15:40:08 -05:00
Dan Ditomaso
a10230b412 Merge pull request #442 from justinforlenza/tls-switch-fix
fix: tls switch for http connections
2025-02-20 15:34:47 -05:00
Dan Ditomaso
c9416a31a2 Merge pull request #444 from danditomaso/hotfix/remove-unneeded-import
fix: removed hook from device config
2025-02-20 14:12:36 -05:00
Dan Ditomaso
f7fe56535d fix: removed hook from device config 2025-02-20 14:12:01 -05:00
Justin
ec10b63d11 fixed tls switch for http connections 2025-02-20 18:09:48 +00:00
Dan Ditomaso
a5131352c7 Merge pull request #441 from danditomaso/fix/refresh-lock-file
fix: refreshed lock file
2025-02-20 13:09:37 -05:00
Dan Ditomaso
9f0a794f22 fix: refreshed lock file 2025-02-20 13:09:03 -05:00
Dan Ditomaso
63ecb12fcf Merge pull request #432 from danditomaso/feat/update-tailwind
feat: update to tailwind 4.x
2025-02-20 13:03:53 -05:00
Dan Ditomaso
5a4774e9f3 Merge branch 'master' into feat/update-tailwind 2025-02-20 13:03:40 -05:00
Dan Ditomaso
35be1bee59 Merge pull request #439 from danditomaso/fix/validate-ble-pin
fix: Add 6-digit BLE PIN validation and error management
2025-02-19 22:45:10 -05:00
Dan Ditomaso
a7a9ba0463 fix: validate bluetooth pin is 6 characters. 2025-02-19 22:29:42 -05:00
Tom Fifield
0b7bdda4bf Merge branch 'master' into switch-rsbuild-to-vite 2025-02-20 08:40:29 +08:00
Tom Fifield
2612997355 Merge pull request #436 from danditomaso/feat-add-formatting-github-action
feat: apply formatting as github action
2025-02-20 08:24:16 +08:00
Dan Ditomaso
84ca90ae97 fix: further action changes. 2025-02-19 11:47:07 -05:00
Dan Ditomaso
8c693f1956 fix: improve action to fix checkout issue 2025-02-19 11:44:36 -05:00
Dan Ditomaso
764328593d changed name of github action 2025-02-19 11:33:20 -05:00
Dan Ditomaso
e9b6c2495c feat: apply biome formatting as github action 2025-02-19 11:28:23 -05:00
Hunter Thornsberry
f4bddefd33 Merge pull request #435 from danditomaso/fix/allow-building-without-formatting 2025-02-19 10:29:45 -05:00
Dan Ditomaso
033409351e fix: allow app to build without require formatting 2025-02-19 10:22:21 -05:00
Dan Ditomaso
a6a66a7672 Merge pull request #434 from danditomaso/chore/fix-formatting-issue
chore: format http file
2025-02-19 10:13:50 -05:00
Dan Ditomaso
1f55d08adf Merge branch 'master' into chore/fix-formatting-issue 2025-02-19 10:13:12 -05:00
Dan Ditomaso
664fd1c2d0 chore: format file 2025-02-19 10:11:42 -05:00
Dan Ditomaso
c9572af445 Merge branch 'master' into feat/update-tailwind 2025-02-19 09:24:08 -05:00
Dan Ditomaso
98edd30360 Merge pull request #250 from Hunter275/issue-249-cors
add ability to enable/disable HTTPS connections
2025-02-19 09:09:18 -05:00
Dan Ditomaso
ab311bfa86 Merge branch 'master' into issue-249-cors 2025-02-19 09:07:08 -05:00
Dan Ditomaso
f4d58a9ea9 feat: updated app to tailwind 4.x 2025-02-19 07:47:02 -05:00
Dan Ditomaso
e769143e58 Merge pull request #430 from PhotoNomad0/bugfix-fixMapCrashHwModel
bugfix for Map crash
2025-02-18 13:03:14 -05:00
Dan Ditomaso
3c37899fe4 Merge pull request #307 from KomelT/feature/node-quick-options
[Feature request]: Nodes quick options
2025-02-18 13:02:08 -05:00
Tilen Komel
30d36789c1 Biome 2025-02-18 16:51:29 +01:00
Tilen Komel
971541a516 Merge branch 'master' into feature/node-quick-options 2025-02-18 16:50:56 +01:00
Dan Ditomaso
ca9e7d5c73 Merge pull request #429 from skeemer/add-avatar-to-node-table
Add Avator to nodes table
2025-02-18 10:21:26 -05:00
PhotoNomad0
61529675ec fix for Map crash on unsupported hwModel in Node. 2025-02-18 07:17:29 -05:00
Leo Lutz
22887b4dd6 Add avator to nodes table 2025-02-17 23:36:21 -07:00
Dan Ditomaso
c4383f4bd2 Merge pull request #423 from danditomaso/issue-407-text-style-messages
feat: added text style chat messages
2025-02-17 23:20:31 -05:00
Dan Ditomaso
0f0751e4d2 Merge pull request #409 from danditomaso/fix/map-zooms-on-click
Fixed map zooming when clicking on map marker. Fixed popup alignment to Map Marker
2025-02-17 23:20:13 -05:00
Dan Ditomaso
2a460dfdba Merge branch 'master' into issue-407-text-style-messages 2025-02-17 13:00:27 -05:00
Dan Ditomaso
2e42620d67 Merge pull request #426 from danditomaso/issue-425-toasts-in-light-mode
fix: fixed issue with toast background opacity in light mode
2025-02-16 20:05:50 -05:00
Dan Ditomaso
5cc24fd6ab fix: added border around markers 2025-02-14 11:41:06 -05:00
Dan Ditomaso
1c59d0451a fix: lighted border of outline button in dark mode 2025-02-14 11:30:28 -05:00
Dan Ditomaso
6d26996d65 fix: fixed issue with toast background opacity in light mode 2025-02-14 11:26:12 -05:00
Hunter Thornsberry
5f2f929af8 Merge pull request #416 from danditomaso/issue-415-message-input-allows-empty-messages
fix: prevent empty/blank messages from being sent.
2025-02-13 23:25:27 -05:00
Hunter Thornsberry
e129b7b469 Merge pull request #411 from danditomaso/issue-399-wrong-measurement-unit-in-map
feat: adding pluralizer util. fix: measurement unit in marker popup
2025-02-13 23:22:56 -05:00
Dan Ditomaso
c6f70a7b77 feat: added text style chat messages 2025-02-13 15:36:44 -05:00
Tom Fifield
f2a2e5ddf2 Merge pull request #285 from sgtwilko/patch-1
Use window.location.host so that websites run on non-standard ports i…
2025-02-12 08:48:17 +08:00
Dan Ditomaso
b7f92388c5 fix: added dark modifer to message input (#414) 2025-02-11 21:03:20 +01:00
Dan Ditomaso
8105f89c55 feat: switch to vite 6.1 2025-02-10 13:31:33 -05:00
Dan Ditomaso
467effa62e fix: prevent empty/blank messages from being sent. fix: count chars during copy/paste action 2025-02-10 12:24:57 -05:00
Dan Ditomaso
2627b9035d feat: adding pluralizer util. fix: measurement unit in marker popup 2025-02-08 23:11:54 -05:00
Dan Ditomaso
d9aff93993 fix: removed map zoom on marker click. feat: lined up popup with map marker 2025-02-08 21:49:17 -05:00
Dan Ditomaso
1fc72aa7be fix: keep existing zoom on map ndoe click 2025-02-08 08:32:29 -05:00
Hunter Thornsberry
b7067923c0 Merge pull request #394 from danditomaso/feat/add-multi-select
Feat: Add MultiSelect component
2025-02-07 23:42:35 -05:00
Hunter Thornsberry
ed3ae2622e Merge pull request #390 from danditomaso/fix/improve-styling-of-chat
fix: improve styling of messages
2025-02-07 23:34:43 -05:00
Hunter275
e3cc95cfd8 add missing maxBytes to MessageInput 2025-02-07 23:28:55 -05:00
Dan Ditomaso
9456495a3d Merge pull request #406 from danditomaso/feat--update-required-pnpm-version
fix: Updated required pnpm version to use latest 10.x version
2025-02-07 20:10:03 -05:00
Dan Ditomaso
53fe300fe9 fix: updating position flags to be more readable 2025-02-07 11:08:59 -05:00
Dan Ditomaso
76aea1a038 fix: updated required package manager to use latest vrsion 2025-02-07 10:45:40 -05:00
Dan Ditomaso
921f9b21a2 fix: added overflow scroll back to page layout 2025-02-07 10:39:23 -05:00
Dan Ditomaso
d552dcd137 Merge branch 'master' into fix/improve-styling-of-chat 2025-02-07 10:25:15 -05:00
Tilen Komel
9505284e61 Merge remote-tracking branch 'origin/HEAD' into feature/node-quick-options 2025-02-06 07:33:48 +01:00
Tom Fifield
d53acf204c Merge pull request #405 from Hunter275/issue-402-message-length-limit
Limit the length of messages to 200 bytes
2025-02-06 08:23:26 +08:00
Tilen Komel
175e98a080 Add location respone dialog 2025-02-05 21:45:31 +01:00
Tilen Komel
b8c1096568 Add short name row to nodes page 2025-02-05 21:06:55 +01:00
Hunter275
430e0cbd46 Limit the length of messages to 200 bytes 2025-02-04 23:30:39 -05:00
Tilen Komel
c2a2e0ac19 Add direct message button 2025-02-04 22:52:14 +01:00
Tilen Komel
5a1c207ffc Remove useEffect 2025-02-04 21:50:11 +01:00
Dan Ditomaso
1c7b466e64 fix: styling fixes from code review 2025-02-04 14:46:46 -05:00
Hunter Thornsberry
30158ca5c5 Merge pull request #401 from danditomaso/feat--add-formatting-linting-on-staging 2025-02-03 21:04:06 -05:00
Dan Ditomaso
e896555694 added: added lint-staged so linting runs when a file is staged. 2025-02-03 20:35:31 -05:00
Dan Ditomaso
87ddaad966 fix: styling updates, chat conversation moved to bottom of chat window. 2025-02-03 20:28:01 -05:00
Dan Ditomaso
4736fa6b50 fix: increasing size of clickable area for navigation items 2025-02-03 16:06:24 -05:00
Tilen Komel
44b8dd308a Update tooltip 2025-02-03 21:23:08 +01:00
Dan Ditomaso
a4e21ed343 feat: added hover tooltip on message status 2025-02-03 13:17:57 -05:00
Tilen Komel
48eb931c37 Add time toltip to timeAgo 2025-02-03 19:07:27 +01:00
Dan Ditomaso
794d214636 feat: removed traceroute from message screen. 2025-02-03 12:36:33 -05:00
Tilen Komel
fb1b4c6cc5 Update according to change request 2025-02-03 18:27:22 +01:00
Tilen Komel
76de3e0e02 Biome 2025-02-03 17:19:27 +01:00
Thomas Göttgens
3f49dc2595 Merge branch 'master' into feature/node-quick-options 2025-02-03 13:55:33 +01:00
Tilen Komel
28c5fd64fe Add overflow-x-scroll to Node details dialog raw metrics 2025-02-02 16:05:35 +01:00
Tilen Komel
9d9c46f732 Remove unused ariables from Nodes.tsx 2025-02-02 14:10:48 +01:00
Tilen Komel
358f8a94d0 Update timeAgo to use Intl.RelativeTimeFormat 2025-02-02 14:02:47 +01:00
Tilen Komel
0c8901b5b2 Make all raw data accordion in node details dialog 2025-02-02 12:58:35 +01:00
Tilen Komel
4abc78fff3 Add basic accordion element 2025-02-02 12:56:07 +01:00
Hunter Thornsberry
095f1fde27 Merge pull request #349 from cmorg3/add_search_nodes
feat: Add search functionality for nodes in Messages and Nodes pages
2025-02-02 00:12:55 -05:00
Hunter Thornsberry
c2c7510dc4 Merge branch 'master' into add_search_nodes 2025-02-01 13:26:02 -05:00
Hunter Thornsberry
1c70fb8606 Merge pull request #391 from dzienisz/map-key
fix: Map Action Buttons key
2025-02-01 13:17:10 -05:00
Dan Ditomaso
75d6817012 chore: linting fix 2025-01-31 16:17:59 -05:00
Dan Ditomaso
3d3b59686c feat: add multi select component. feat: add multi select to position flags section 2025-01-31 16:11:10 -05:00
Hunter Thornsberry
963deeca75 Merge pull request #393 from danditomaso/fix/fix-tak-tracker-role-value
fix: update value for tak tracker device role
2025-01-30 16:02:07 -05:00
Dan Ditomaso
991405c7aa fix: update value for tak tracker device role 2025-01-30 14:21:24 -05:00
Kamil Dzieniszewski
ce66e55196 fix: Map Action Buttons key 2025-01-30 19:53:04 +01:00
Tilen Komel
7142f0f8d5 Add dialog Node Details 2025-01-30 18:03:56 +01:00
Tilen Komel
8ac714a5b5 Update TimeAgo 2025-01-30 18:03:28 +01:00
Tilen Komel
97d206a9d4 Add Uptime.tsx 2025-01-30 15:25:54 +01:00
Tilen Komel
fad6f72dd1 Add DeviceImage.tsx and hardware svgs 2025-01-30 15:17:05 +01:00
Tilen Komel
3f09e6de93 Remove timeago-react 2025-01-30 15:04:07 +01:00
Hunter Thornsberry
547b86f98e Merge pull request #366 from kylewistrand/dashboard-node-links
feat: Make nodes on dashboard clickable
2025-01-29 23:51:42 -05:00
Hunter275
2bdfbedeea add dark mode classes and biome fixes 2025-01-29 23:50:38 -05:00
Hunter Thornsberry
68da810a85 Merge pull request #387 from danditomaso/feat/add-build-analyze-script
feat: add bundle analyzer script
2025-01-29 23:23:17 -05:00
Dan Ditomaso
d9ad044ecd fix: improve styling of messsges 2025-01-29 16:08:55 -05:00
Dan Ditomaso
5b7b770aee feat: add bundle analyzer script 2025-01-29 09:07:57 -05:00
Tilen Komel
b3cde1bcd7 Move remove button to quick options 2025-01-29 13:56:48 +01:00
Tilen Komel
9eeed9630b Fix 2025-01-29 13:15:52 +01:00
Tilen Komel
617b452da5 Merge branch 'master' into feature/node-quick-options 2025-01-29 11:50:33 +01:00
Dan Ditomaso
eb0ea4ea24 Merge branch 'master' into issue-249-cors 2025-01-28 21:32:34 -05:00
Hunter Thornsberry
c7e2baea1b Merge pull request #385 from danditomaso/fix/update-project-deps-to-latest
fix: update packages to latest version
2025-01-28 15:53:52 -05:00
Dan Ditomaso
172e0c70c8 Merge pull request #383 from danditomaso/feat/debounce-messages-input
Add debounce to message input field
2025-01-28 15:36:53 -05:00
Dan Ditomaso
9b843f6483 chore: update packages to latest version. feat: replace hashicon lib with vanilla component 2025-01-28 12:15:04 -05:00
Dan Ditomaso
e405a91ba8 Merge branch 'master' into feat/debounce-messages-input 2025-01-27 13:01:34 -05:00
Dan Ditomaso
cdc2554af6 fix: update lock file 2025-01-27 08:31:31 -05:00
Hunter Thornsberry
2808b6f26a Merge pull request #384 from danditomaso/feat/force-format-lint-before-commit
Added simple-git-hooks to run linting/formatting script prior to commit
2025-01-25 22:47:58 -05:00
Hunter Thornsberry
41ff10c653 Merge pull request #374 from tdhawk/fix-readme
update container port
2025-01-25 22:43:42 -05:00
Dan Ditomaso
4508428160 feat: add simple-git-hooks to run linting/formatting prior to commit 2025-01-25 21:49:37 -05:00
Dan Ditomaso
f0dd426055 chore: linting 2025-01-25 21:24:43 -05:00
Dan Ditomaso
d0ca24ae6f feat: debounce message draft state updates to reduce zustand/immer store writes on Messages page 2025-01-25 16:41:42 -05:00
Dan Ditomaso
fe2b76eeb9 fix: moving tailwind libs to dev dependency, removed unused deps 2025-01-25 16:09:59 -05:00
Tilen Komel
2fbf2a1173 Fix show ?? if null 2025-01-24 12:26:28 +01:00
Tilen Komel
c9377295db Merge branch 'master' into feature/node-quick-options 2025-01-24 12:18:10 +01:00
Tilen Komel
54c73a8c0d Add snr to traceroute 2025-01-24 12:15:57 +01:00
Hunter Thornsberry
5d0f2e4403 Merge pull request #381 from KomelT/fix/biome
Fix Biome
2025-01-23 22:54:52 -05:00
Tilen Komel
47150c649f Add back pnpm check into build command 2025-01-24 01:50:41 +01:00
Tilen Komel
7930f44109 Try to fix old stuff 2025-01-24 01:42:01 +01:00
Tilen Komel
ec6906a5c3 Fixes by hand 2025-01-24 01:27:33 +01:00
Tilen Komel
891a1a9503 pnpm check:fix 2025-01-24 01:26:15 +01:00
Tilen Komel
965e3247b0 Added 2way traceroute 2025-01-24 00:49:27 +01:00
Tilen Komel
f24041651c Fix legacy import 2025-01-24 00:03:55 +01:00
Tilen Komel
3f88373dd8 Merge branch 'master' into feature/node-quick-options 2025-01-23 23:57:05 +01:00
Tilen Komel
aa66e1f73c Biome 2025-01-23 23:45:24 +01:00
Hunter Thornsberry
cf79f3b07e Merge pull request #379 from KomelT/add-package-manager
Add packageManager in package.json
2025-01-23 16:25:58 -05:00
Tilen Komel
9493649a69 This works now 2025-01-23 14:02:21 +01:00
Tilen Komel
c8cd5b0eaa Define package_json_file: package.json in CI 2025-01-23 13:49:44 +01:00
Tilen Komel
c16b3a3ce0 Add version 2025-01-23 13:35:12 +01:00
Tilen Komel
2967a74480 Blank version 2025-01-23 13:33:13 +01:00
Tilen Komel
ea648ca887 Just for joke without actions/checkout@v4 2025-01-23 13:30:16 +01:00
Tilen Komel
8d35b57d19 Add packageManager in package.json 2025-01-23 12:59:57 +01:00
Hunter Thornsberry
be9a07bc4b Merge pull request #360 from danditomaso/add_pki_backup_dialog
Add PKI backup dialog, add reminder toast to suggest backing up private key.
2025-01-22 22:35:41 -05:00
Tom Fifield
7d37c6e728 Merge pull request #378 from Hunter275/ci-pnpm-version
remove version spec
2025-01-21 13:54:11 +11:00
Hunter275
42ccd953c0 remove version spec 2025-01-20 20:20:50 -05:00
Hunter Thornsberry
578405d5d3 Merge pull request #362 from danditomaso/update_ble_serial_wording_https
fix: update connect dialog messaging to describe requirement for https
2025-01-20 14:59:51 -05:00
Dan Ditomaso
ebb32f0893 fix: changed position of error message, disabled buttons when error is showing 2025-01-19 22:42:38 -05:00
Hunter Thornsberry
9cef18b82a Merge pull request #370 from PhotoNomad0/feature-addDateToDisplayedMessages
Feature / Added date to messages displayed
2025-01-19 02:25:14 -05:00
Hunter Thornsberry
88510a6ffe Merge pull request #367 from danielhogstrom/sidebar-close-button
feat: Add sidebar close button
2025-01-19 02:21:10 -05:00
Hunter275
be6acc5ef2 add right border 2025-01-19 00:50:23 -05:00
Anthony Hawk
4e35cf326e updated container port 2025-01-18 14:10:30 -06:00
Dan Ditomaso
225d6055d4 Improved error messaging based on feature missing from browser 2025-01-15 20:11:46 -05:00
Dan Ditomaso
7884991ac6 Refactor based on code review. Improved typing of useCookie hook. Added duration/delay to control length of toast. 2025-01-14 21:51:06 -05:00
PhotoNomad0
2d041ab6d0 Added date to messages displayed 2025-01-13 06:37:18 -05:00
Daniel
c2cdc92ae9 feat: Add sidebar close button 2025-01-12 18:59:12 +01:00
Tom Fifield
6b10d35e1a Merge pull request #365 from kylewistrand/fix-node-detail-dark-mode
fix: Node map detail dark mode
2025-01-12 13:38:45 +08:00
Kyle Wistrand
790f93322e feat: Make nodes on dashboard clickable 2025-01-11 20:56:03 -08:00
Kyle Wistrand
b50edb2762 fix: Node map detail dark mode 2025-01-11 20:31:33 -08:00
Hunter Thornsberry
88e06a1bea Merge pull request #350 from kylewistrand/add_map_node_detail
feat: Add Node detail popup in Map view
2025-01-10 14:17:48 -05:00
Dan Ditomaso
07d4204e86 Merge branch 'add_pki_backup_dialog' of https://github.com/danditomaso/meshtastic-web into add_pki_backup_dialog 2025-01-07 15:11:58 -05:00
Dan Ditomaso
0e78d0bd50 feat: added delay to toast appearing to avoid conflicting with messages/node loading. 2025-01-07 15:09:00 -05:00
Dan Ditomaso
f3a3741216 feat: Add key backup reminder. Refactor Toast component to handle dark mode better 2025-01-07 15:08:01 -05:00
Dan Ditomaso
74e33d09b1 feat: Add pki backup dialog, refactor Channels pre-shared key to support regenerate dialog 2025-01-07 15:08:01 -05:00
Tom Fifield
ecd50148de Merge pull request #363 from danditomaso/add_empty_psk_size
Added empty value to pre-shared key size. Feature parity with IOS app
2025-01-07 13:58:20 +08:00
Hunter Thornsberry
08a28eeb68 Merge branch 'master' into add_map_node_detail 2025-01-07 00:05:45 -05:00
Dan Ditomaso
cbabcd4782 feat: added delay to toast appearing to avoid conflicting with messages/node loading. 2025-01-06 16:00:13 -05:00
Dan Ditomaso
63be65a487 feat: added empty value to pre-shared key size. 2025-01-06 13:45:45 -05:00
Dan Ditomaso
1c8476df53 refactor: consolidate browser feature detection into typed hook. Update connect dialog messaging to describe requirement for https when conneecting 2025-01-06 11:43:36 -05:00
Dan Ditomaso
7cd03c6a52 feat: Add key backup reminder. Refactor Toast component to handle dark mode better 2025-01-03 21:40:56 -05:00
Dan Ditomaso
db09711be5 feat: Add pki backup dialog, refactor Channels pre-shared key to support regenerate dialog 2025-01-03 12:05:29 -05:00
Hunter Thornsberry
94c6eea20b Merge pull request #317 from jangrewe/master
Update Containerfile to use plain Nginx
2024-12-30 14:46:52 -05:00
Jan Grewe
1ec3aa07d3 Merge branch 'meshtastic:master' into master 2024-12-30 16:19:16 +01:00
Tom Fifield
1087c68541 Merge pull request #356 from danditomaso/add_attribution_control_to_map
feat: Add AttributionControl to Map to comply with OSM license requirements
2024-12-29 13:01:53 +11:00
Dan Ditomaso
856556c12b feat: Add AttributionControl to Map to comply with OSM license requirements 2024-12-28 20:21:40 -05:00
Tom Fifield
fc24a389c0 Merge pull request #353 from meshtastic/dependabot/npm_and_yarn/nanoid-3.3.8
Bump nanoid from 3.3.7 to 3.3.8
2024-12-14 22:16:31 +11:00
dependabot[bot]
5687485154 Bump nanoid from 3.3.7 to 3.3.8
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.7 to 3.3.8.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.7...3.3.8)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-14 09:37:41 +00:00
Jan Grewe
654d6c64c1 Merge remote-tracking branch 'upstream/master' 2024-12-02 11:28:43 +01:00
Kyle Wistrand
fed6b2a6da feat: Add Node detail popup in Map view 2024-11-26 18:45:59 -08:00
Connor Morgan
79806cc6a2 feat: Add search functionality for nodes in Messages and Nodes pages 2024-11-24 22:17:17 -06:00
Hunter Thornsberry
e78aa2df61 Merge pull request #332 from Nestpebble/patch-1
Improve Managed Node description
2024-11-24 17:16:25 -05:00
Hunter Thornsberry
03173f6a37 Merge pull request #347 from meshtastic/dependabot/npm_and_yarn/cross-spawn-7.0.6
Bump cross-spawn from 7.0.3 to 7.0.6
2024-11-24 17:11:10 -05:00
dependabot[bot]
3fa73894ed Bump cross-spawn from 7.0.3 to 7.0.6
Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6.
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-20 15:01:05 +00:00
Tom Fifield
a147324913 Merge pull request #344 from meshtastic/CVE-2024-45812
Update vite to 5.3.6
2024-11-12 10:42:30 +08:00
Tom Fifield
0fc4211c13 Update vite to 5.3.6
Fixes CVE-2024-45812
2024-11-12 10:40:47 +08:00
Tom Fifield
6df0b287ef Update vite to 5.3.6
Fixes CVE-2024-45812
2024-11-12 10:33:02 +08:00
Tom Fifield
2f9af111c8 Update vite to 5.3.6
Fixes CVE-2024-45812
2024-11-12 10:29:27 +08:00
Hunter Thornsberry
615045be9f Merge pull request #339 from hectorthemonk/patch-1
Add ledHeartbeatDisabled to Device Settings in Radio Config
2024-11-10 15:05:51 -05:00
Tom
6fc183ff15 Update Security.tsx 2024-11-10 12:58:54 +00:00
hectorthemonk
9aafa681e8 Add ledHeartbeatDisabled to Device Settings in Radio Config
`led_heartbeat_disabled` in https://buf.build/meshtastic/protobufs/docs/main:meshtastic#meshtastic.Config.DeviceConfig
2024-11-10 21:34:33 +13:00
Tom Fifield
f48f9ccd62 Merge pull request #338 from Hunter275/bluetooth-pin-validation
Add bluetooth pin validation
2024-11-10 11:54:22 +08:00
Hunter275
2bd80bb5b4 Add pin validation 2024-11-09 22:39:57 -05:00
Tom Fifield
de597d2c28 Merge pull request #337 from Hunter275/issue-335-charging
If the batteryLevel is over 100, its charging
2024-11-10 10:14:15 +08:00
Hunter275
94cca88e2e If the batteryLevel is over 100, its charging 2024-11-09 21:10:55 -05:00
Hunter Thornsberry
443c7fcd48 Merge pull request #331 from fmoessbauer/master
document scalar clamping of curve25519 keys
2024-11-09 20:25:38 -05:00
Hunter Thornsberry
6138d9f8c8 Merge pull request #314 from meshtastic/dependabot/npm_and_yarn/micromatch-4.0.8
Bump micromatch from 4.0.7 to 4.0.8
2024-11-09 20:19:00 -05:00
Hunter Thornsberry
37547b54e9 Merge pull request #330 from meshtastic/dependabot/npm_and_yarn/elliptic-6.6.0
Bump elliptic from 6.5.7 to 6.6.0
2024-11-09 20:18:45 -05:00
Hunter Thornsberry
618e2f619b Merge pull request #313 from meshtastic/dependabot/npm_and_yarn/rollup-4.24.0
Bump rollup from 4.18.0 to 4.24.0
2024-11-09 20:18:34 -05:00
rcarteraz
72fc3ea337 Merge pull request #336 from rcarteraz/master
Fix Title
2024-11-09 10:43:00 -07:00
rcarteraz
82f4784107 Merge pull request #2 from rcarteraz/fix-title
Fix Title
2024-11-09 10:38:35 -07:00
rcarteraz
4f9fb9976d fix title 2024-11-09 10:37:06 -07:00
Tom
2cf7655562 Update Security.tsx 2024-11-02 01:37:28 +00:00
Felix Moessbauer
79c5638e10 document scalar clamping of curve25519 keys
The "scalars" are just random bytes. To make them secure curve25519
keys, they need to be clamped according to rfc7748 section 5.
As this is not obvious, we need to add a reference to the RFC.

No functional change.

Closes: #324
2024-11-01 12:55:54 +01:00
dependabot[bot]
f53d53ea20 Bump elliptic from 6.5.7 to 6.6.0
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.7 to 6.6.0.
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.7...v6.6.0)

---
updated-dependencies:
- dependency-name: elliptic
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-31 02:19:04 +00:00
Jan Grewe
f2760a941b Update Containerfile to use plain Nginx
Only add required files to container
Fix HTML title
2024-10-14 16:38:30 +02:00
dependabot[bot]
1e26eed861 Bump micromatch from 4.0.7 to 4.0.8
Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.7 to 4.0.8.
- [Release notes](https://github.com/micromatch/micromatch/releases)
- [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/micromatch/compare/4.0.7...4.0.8)

---
updated-dependencies:
- dependency-name: micromatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-06 11:35:29 +00:00
dependabot[bot]
2da4a44505 Bump rollup from 4.18.0 to 4.24.0
Bumps [rollup](https://github.com/rollup/rollup) from 4.18.0 to 4.24.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.18.0...v4.24.0)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-06 11:35:24 +00:00
Sacha Weatherstone
42068ad3d8 move to RsBuild 2024-10-06 21:24:12 +10:00
Hunter Thornsberry
62f8c4509e Merge pull request #311 from medentem/master
Added Password Visibility Toggle
2024-10-02 23:07:11 -04:00
Hunter Thornsberry
d699764546 biome 2024-10-02 22:07:45 -04:00
medentem
8549d56c21 biome 2024-10-02 19:33:09 -05:00
medentem
4b532fc7f8 added password visibility toggle 2024-10-02 15:54:53 -05:00
Hunter Thornsberry
06d2c393ce Merge pull request #310 from Hunter275/remove-client-router
Remove router-client
2024-09-22 19:54:57 -04:00
Hunter Thornsberry
cecdf9758b remove router-client 2024-09-22 18:25:35 -04:00
Tilen Komel
a2b9a33f6a Cursor pointer 2024-09-19 10:37:48 +02:00
Hunter Thornsberry
02cb4f2584 Merge pull request #303 from Hunter275/gps-precision 2024-09-18 13:45:17 -04:00
Tilen Komel
56ac1d55f4 Implement on nodes page 2024-09-18 11:34:47 +02:00
Tilen Komel
2a5acb8771 Add node dialog 2024-09-18 11:34:27 +02:00
Tilen Komel
93e04e1b69 Add traceroute dialog 2024-09-18 11:21:15 +02:00
Tilen Komel
bd48b02ef3 Updated traceroute response 2024-09-18 11:17:18 +02:00
Hunter Thornsberry
8cfcd7b1af Merge pull request #306 from KomelT/feature/better-unknown
Unknown nodes
2024-09-17 16:26:56 -04:00
Tilen Komel
c0cb059f52 Merge branch 'meshtastic:master' into feature/better-unknown 2024-09-17 21:10:29 +02:00
Tilen Komel
a2a9b37238 Unknown to node hex on other missing places 2024-09-17 21:08:35 +02:00
Hunter Thornsberry
57d0d27bbb Merge pull request #304 from KomelT/feature/better-unknown
Unknown nodes
2024-09-17 14:54:05 -04:00
Hunter Thornsberry
0e92dd9bea There is no longer a setting here 2024-09-17 13:53:36 -04:00
Tilen Komel
c16ebf3917 Show hex on map instead of empty 2024-09-17 19:50:27 +02:00
Hunter Thornsberry
3d3a08a23f replace with select 2024-09-17 13:47:07 -04:00
Hunter Thornsberry
4d1227a942 Merge pull request #269 from KomelT/fix/static-ip-display
Fix/static ip display
2024-09-17 13:27:12 -04:00
Hunter Thornsberry
a8ee273b24 biome 2024-09-17 12:36:49 -04:00
Hunter Thornsberry
3ee7a57480 rewrite convertIpAddressToInt 2024-09-17 12:35:51 -04:00
Tilen Komel
2f2c777c56 Optimize 2024-09-17 07:32:12 +02:00
Tilen Komel
2f36118e9d Merge branch 'meshtastic:master' into fix/static-ip-display 2024-09-17 07:16:54 +02:00
Hunter Thornsberry
a6d161581f Merge pull request #300 from Hunter275/primary-channel
Only allow channel index 0 to be PRIMARY
2024-09-15 19:55:24 -04:00
Hunter Thornsberry
d05ea5a2cc Merge remote-tracking branch 'meshtastic-remote/master' into fix/static-ip-display 2024-09-15 19:39:13 -04:00
Hunter Thornsberry
471db94242 Merge branch 'master' into fix/static-ip-display 2024-09-15 19:38:03 -04:00
Hunter Thornsberry
2654e4fbc9 biome manual fixes 2024-09-15 19:24:16 -04:00
Hunter Thornsberry
f2aa5bfbee biome 2024-09-15 19:23:44 -04:00
Hunter Thornsberry
3b018b0c70 Only allow channel index 0 to be PRIMARY 2024-09-15 19:23:07 -04:00
Hunter Thornsberry
921db10d91 Merge pull request #297 from Hunter275/js-version-bump
js version bump
2024-09-12 17:20:09 -04:00
Hunter Thornsberry
bf4f593e3a use new js and remove polyfills 2024-09-12 14:20:32 -04:00
Hunter Thornsberry
1e061a1e19 polyfill 2024-09-11 23:07:52 -04:00
Hunter Thornsberry
9b9f537e2c js version bump 2024-09-11 22:13:46 -04:00
Hunter Thornsberry
985cce0b0d Merge pull request #294 from meshtastic/pki
PKI
2024-09-11 17:51:31 -04:00
Hunter Thornsberry
3fe38eb506 Merge pull request #295 from meshtastic/master
Update release.yml
2024-09-10 20:53:31 -04:00
Hunter Thornsberry
51081d3052 Update release.yml
Create a build artifact on release
2024-09-10 20:51:50 -04:00
Hunter Thornsberry
c08f6d16bb Merge branch 'master' into pki 2024-09-09 18:55:02 -04:00
Hunter Thornsberry
62ad4c49f8 Merge pull request #293 from Hunter275/pki-nodelist
Node List & DMs
2024-09-09 18:50:29 -04:00
Hunter Thornsberry
3b0a1e6108 biome 2024-09-09 18:37:22 -04:00
Hunter Thornsberry
c2f2205626 cleanup 2024-09-09 18:25:58 -04:00
Hunter Thornsberry
87c729d694 Merge branch 'pki' into pki-nodelist 2024-09-09 18:01:17 -04:00
Hunter Thornsberry
8e4f60edf3 biome 2024-09-09 16:36:56 -04:00
Hunter Thornsberry
8811eee9f5 Remove bluetooth debugging and reword generic debug 2024-09-09 16:36:17 -04:00
Hunter Thornsberry
2af93f1acd Fix protobufs, add configOkToMqtt, add PKI icons 2024-09-09 16:22:48 -04:00
Hunter Thornsberry
78a35544c7 Node list and DMs now show icons 2024-09-08 19:48:42 -04:00
Hunter Thornsberry
3ad2d650b0 update protobufs 2024-09-08 18:59:57 -04:00
Hunter Thornsberry
bf425a8ec7 Merge pull request #291 from Kongduino/patch-1 2024-09-07 12:21:47 -04:00
Kongduino
a7d0d36086 Update index.tsx
"at least", two words. Thanks...
2024-09-07 13:32:16 +08:00
sgtwilko
fd9e327c85 Use window.location.host so that websites run on non-standard ports include the port 2024-08-30 01:01:44 +01:00
Tilen Komel
8ed3ce8203 Error & Format fixing 2024-08-21 23:13:35 +02:00
Tilen Komel
ebd5a3d3a6 Implemented IP utils 2024-08-21 21:53:07 +02:00
Tilen Komel
1cdf18747d Added ip utils 2024-08-21 21:53:07 +02:00
Hunter Thornsberry
d8261a649b add disabled 2024-06-21 15:09:29 -04:00
Hunter Thornsberry
c4565d97b0 add ability to enable/disable HTTPS connections 2024-06-21 15:06:19 -04:00
644 changed files with 115996 additions and 12327 deletions

12
.githooks/_/pre-commit Executable file
View 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

View File

@@ -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!

View File

@@ -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
View 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)

View File

@@ -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
View 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 }}

View 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 }}

View 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
View 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 }}"

View File

@@ -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
View 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
View 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 }}"

View File

@@ -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 }}"

View 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
View File

@@ -1,5 +1,10 @@
dist
node_modules
dist
stats.html
.vercel
dev-dist
.vite
dev-dist
__screenshots__*
*.diff
npm/
.idea

2
.npmrc
View File

@@ -1 +1 @@
@buf:registry=https://buf.build/gen/npm/v1
@jsr:registry=https://npm.jsr.io

View File

@@ -1,3 +1,3 @@
{
"recommendations": ["bradlc.vscode-tailwindcss", "biomejs.biome"]
"recommendations": ["bradlc.vscode-tailwindcss", "denoland.vscode-deno"]
}

View File

@@ -1,7 +1,6 @@
{
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"quickfix.biome": "explicit"
},
"editor.formatOnSave": true
"source.fixAll.biome": "explicit",
}
}

View File

@@ -1,5 +0,0 @@
FROM registry.access.redhat.com/ubi9/nginx-122:1-45
ADD dist .
CMD nginx -g "daemon off;"

121
README.md
View File

@@ -1,61 +1,112 @@
# Meshtastic Web
# Meshtastic Web Monorepo
<!--Project specific badges here-->
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/web/ci.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/web/actions/workflows/ci.yml)
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/web/ci.yml?branch=main&label=Web%20CI&logo=github&color=yellow)](https://github.com/meshtastic/web/actions/workflows/ci.yml)
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/js/ci.yml?branch=master&label=JS%20CI&logo=github&color=yellow)](https://github.com/meshtastic/js/actions/workflows/ci.yml)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/web)](https://cla-assistant.io/meshtastic/web)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](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
![Alt](https://repobeats.axiom.co/api/embed/e5b062db986cb005d83e81724c00cb2b9cce8e4c.svg "Repobeats analytics image")
| Project | Repobeats |
| :------------- | :-------------------------------------------------------------------------------------------------------------------- |
| Meshtastic Web | ![Alt](https://repobeats.axiom.co/api/embed/e5b062db986cb005d83e81724c00cb2b9cce8e4c.svg "Repobeats analytics image") |
## 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! Heres 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!

View File

@@ -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
}
}
}

View File

@@ -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
View File

@@ -0,0 +1,27 @@
# @meshtastic/core
[![JSR](https://jsr.io/badges/@meshtastic/core)](https://jsr.io/@meshtastic/core)
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/js/ci.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/js/actions/workflows/ci.yml)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/meshtastic.js)](https://cla-assistant.io/meshtastic/meshtastic.js)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](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
![Alt](https://repobeats.axiom.co/api/embed/5330641586e92a2ec84676fedb98f6d4a7b25d69.svg "Repobeats analytics image")

7
packages/core/jsr.json Normal file
View File

@@ -0,0 +1,7 @@
{
"name": "@meshtastic/core",
"version": "2.6.6",
"exports": {
".": "./mod.ts"
}
}

5
packages/core/mod.ts Normal file
View 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";

View 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"
}
}

View 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
View File

File diff suppressed because it is too large Load Diff

130
packages/core/src/types.ts Normal file
View 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;
}

View 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>();
}

View 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";

View 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;
}
}
}

View 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}`,
);
}
}
}
}
},
});

View 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;
}
}
},
});
};

View 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]));
},
});

View 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 = [];
}
}

View 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"]
}

View File

@@ -0,0 +1,28 @@
# @meshtastic/transport-deno
[![JSR](https://jsr.io/badges/@meshtastic/transport-deno)](https://jsr.io/@meshtastic/transport-deno)
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/js/ci.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/js/actions/workflows/ci.yml)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/meshtastic.js)](https://cla-assistant.io/meshtastic/meshtastic.js)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](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
![Alt](https://repobeats.axiom.co/api/embed/5330641586e92a2ec84676fedb98f6d4a7b25d69.svg "Repobeats analytics image")

View File

@@ -0,0 +1,5 @@
{
"imports": {
"@deno/dnt": "jsr:@deno/dnt@^0.42.3"
}
}

View File

@@ -0,0 +1 @@
export { TransportDeno } from "./src/transport.ts";

View 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"
}
}

View 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");
},
});

View 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();
}
}

View 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>.

View File

@@ -0,0 +1,28 @@
# @meshtastic/transport-http
[![JSR](https://jsr.io/badges/@meshtastic/transport-http)](https://jsr.io/@meshtastic/transport-http)
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/js/ci.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/js/actions/workflows/ci.yml)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/meshtastic.js)](https://cla-assistant.io/meshtastic/meshtastic.js)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](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
![Alt](https://repobeats.axiom.co/api/embed/5330641586e92a2ec84676fedb98f6d4a7b25d69.svg "Repobeats analytics image")

View File

@@ -0,0 +1 @@
export { TransportHTTP } from "./src/transport.ts";

View 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
View File

File diff suppressed because it is too large Load Diff

View 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();
}
}

View 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"]
}

View File

@@ -0,0 +1,28 @@
# @meshtastic/transport-node
[![JSR](https://jsr.io/badges/@meshtastic/transport-node)](https://jsr.io/@meshtastic/transport-node)
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/js/ci.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/js/actions/workflows/ci.yml)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/meshtastic.js)](https://cla-assistant.io/meshtastic/meshtastic.js)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](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
![Alt](https://repobeats.axiom.co/api/embed/5330641586e92a2ec84676fedb98f6d4a7b25d69.svg "Repobeats analytics image")

View File

@@ -0,0 +1 @@
export { TransportNode } from "./src/transport.ts";

View 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"
}
}

View 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();
}
}

View 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"]
}

View File

@@ -0,0 +1,35 @@
# @meshtastic/transport-web-bluetooth
[![JSR](https://jsr.io/badges/@meshtastic/transport-web-bluetooth)](https://jsr.io/@meshtastic/transport-web-bluetooth)
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/js/ci.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/js/actions/workflows/ci.yml)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/meshtastic.js)](https://cla-assistant.io/meshtastic/meshtastic.js)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](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
![Alt](https://repobeats.axiom.co/api/embed/5330641586e92a2ec84676fedb98f6d4a7b25d69.svg "Repobeats analytics image")
### Compatibility
The Web Bluetooth API's have limited support in browsers, compatibility is
represented in the matrix below.
![Web Bluetooth compatability matrix](https://caniuse.bitsofco.de/image/web-bluetooth.png)

View File

@@ -0,0 +1 @@
export { TransportWebBluetooth } from "./src/transport.ts";

View 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"
}
}

View 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();
}
}

View 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"]
}

View File

@@ -0,0 +1,35 @@
# @meshtastic/transport-web-serial
[![JSR](https://jsr.io/badges/@meshtastic/transport-web-serial)](https://jsr.io/@meshtastic/transport-web-serial)
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/js/ci.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/js/actions/workflows/ci.yml)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/meshtastic.js)](https://cla-assistant.io/meshtastic/meshtastic.js)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](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
![Alt](https://repobeats.axiom.co/api/embed/5330641586e92a2ec84676fedb98f6d4a7b25d69.svg "Repobeats analytics image")
### Compatibility
The Web Serial API's have limited support in browsers, compatibility is
represented in the matrix below.
![Web Serial compatability matrix](https://caniuse.bitsofco.de/image/web-serial.png)

View File

@@ -0,0 +1 @@
export { TransportWebSerial } from "./src/transport.ts";

View 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"
}
}

View 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();
}
}

View 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
View File

@@ -0,0 +1 @@
@jsr:registry=https://npm.jsr.io

View 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>;
```

View 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
View File

@@ -0,0 +1,156 @@
# Meshtastic Web
<!--Project specific badges here-->
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/web/ci.yml?branch=main&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/web/actions/workflows/ci.yml)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/web)](https://cla-assistant.io/meshtastic/web)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](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
![Alt](https://repobeats.axiom.co/api/embed/e5b062db986cb005d83e81724c00cb2b9cce8e4c.svg "Repobeats analytics image")
## 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! Heres 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
View 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%"

View File

@@ -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>

View File

@@ -0,0 +1,2 @@
../dist/build.tar
../dist/output

View 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;"]

View 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
View 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"
}
}

View 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

View 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

View 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

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View 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

View File

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 102 KiB

View File

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 77 KiB

View 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

View 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

View 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

View File

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 40 KiB

View 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

View 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

View 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

View 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

View 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

View File

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 95 KiB

View File

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 95 KiB

View File

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 47 KiB

View 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

View File

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 102 KiB

View File

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 86 KiB

View 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

View File

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 164 KiB

View 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

Some files were not shown because too many files have changed in this diff Show More