Initial
3
.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
* text=auto eol=lf
|
||||
*.{cmd,[cC][mM][dD]} text eol=crlf
|
||||
*.{bat,[bB][aA][tT]} text eol=crlf
|
28
.gitignore
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
# Project specific
|
||||
node_modules/
|
||||
*.Identifier
|
||||
.docusaurus
|
||||
build
|
||||
.vercel
|
||||
.env
|
||||
.pnpm-debug.log
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
*.iml
|
||||
out
|
||||
gen
|
||||
|
||||
# VS Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
.history/
|
||||
*.vsix
|
||||
*.code-workspace
|
7
.trunk/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
*out
|
||||
*logs
|
||||
*actions
|
||||
*notifications
|
||||
plugins
|
||||
user_trunk.yaml
|
||||
user.yaml
|
10
.trunk/configs/.markdownlint.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
# Autoformatter friendly markdownlint config (all formatting rules disabled)
|
||||
default: true
|
||||
blank_lines: false
|
||||
bullet: false
|
||||
html: false
|
||||
indentation: false
|
||||
line_length: false
|
||||
spaces: false
|
||||
url: false
|
||||
whitespace: false
|
7
.trunk/configs/.shellcheckrc
Normal file
@ -0,0 +1,7 @@
|
||||
enable=all
|
||||
source-path=SCRIPTDIR
|
||||
disable=SC2154
|
||||
|
||||
# If you're having issues with shellcheck following source, disable the errors via:
|
||||
# disable=SC1090
|
||||
# disable=SC1091
|
17
.trunk/configs/rome.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "../../node_modules/rome/configuration_schema.json",
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "space",
|
||||
"indentSize": 2
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true
|
||||
}
|
||||
},
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
14
.trunk/configs/svgo.config.js
Normal file
@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
{
|
||||
name: "preset-default",
|
||||
params: {
|
||||
overrides: {
|
||||
removeViewBox: false, // https://github.com/svg/svgo/issues/1128
|
||||
sortAttrs: true,
|
||||
removeOffCanvasPaths: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
25
.trunk/trunk.yaml
Normal file
@ -0,0 +1,25 @@
|
||||
version: 0.1
|
||||
cli:
|
||||
version: 1.3.1
|
||||
plugins:
|
||||
sources:
|
||||
- id: trunk
|
||||
ref: v0.0.8
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
disabled:
|
||||
- eslint
|
||||
- prettier
|
||||
enabled:
|
||||
- rome@12.0.0
|
||||
- markdownlint@0.33.0
|
||||
- actionlint@1.6.22
|
||||
- gitleaks@8.15.2
|
||||
- git-diff-check
|
||||
- shellcheck@0.9.0
|
||||
- shfmt@3.5.0
|
||||
- svgo@3.0.2
|
||||
runtimes:
|
||||
enabled:
|
||||
- go@1.18.3
|
||||
- node@18.12.1
|
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["trunk.io"]
|
||||
}
|
7
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "trunk.io",
|
||||
"files.associations": {
|
||||
"*.mdx": "markdown"
|
||||
}
|
||||
}
|
674
LICENSE
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
28
README.md
Normal file
@ -0,0 +1,28 @@
|
||||
# network
|
||||
|
||||
## Overview
|
||||
|
||||
Website and documentation source for the Dead Network project.
|
||||
|
||||
|
||||
## Development & Building
|
||||
|
||||
nodejs is required in your dev. environment. The method for installing nodejs depends on your operating system. This software is built using [Docusaurus](https://docusaurus.io).
|
||||
|
||||
Go to the root directory of your repository and install dependencies:
|
||||
|
||||
```shell
|
||||
pnpm install
|
||||
```
|
||||
|
||||
Build the project with the following command
|
||||
|
||||
```shell
|
||||
pnpm build
|
||||
```
|
||||
|
||||
Start a local dev. instance with the following command
|
||||
|
||||
```shell
|
||||
pnpm start
|
||||
```
|
119
config.toml
Normal file
@ -0,0 +1,119 @@
|
||||
[general]
|
||||
|
||||
#### Address & Root dir
|
||||
host = "::"
|
||||
port = 80
|
||||
root = "/app"
|
||||
|
||||
#### Logging
|
||||
log-level = "error"
|
||||
|
||||
#### Cache Control headers
|
||||
cache-control-headers = true
|
||||
|
||||
#### Auto Compression
|
||||
compression = true
|
||||
|
||||
#### Error pages
|
||||
page404 = "/app/404.html"
|
||||
page50x = "/app/404.html"
|
||||
|
||||
#### HTTP/2 + TLS
|
||||
http2 = false
|
||||
http2-tls-cert = ""
|
||||
http2-tls-key = ""
|
||||
https-redirect = false
|
||||
https-redirect-host = "localhost"
|
||||
https-redirect-from-port = 80
|
||||
https-redirect-from-hosts = "localhost"
|
||||
|
||||
#### CORS & Security headers
|
||||
# security-headers = true
|
||||
# cors-allow-origins = ""
|
||||
|
||||
#### Directory listing
|
||||
directory-listing = false
|
||||
|
||||
#### Directory listing sorting code
|
||||
directory-listing-order = 1
|
||||
|
||||
#### Directory listing content format
|
||||
directory-listing-format = "html"
|
||||
|
||||
#### Basic Authentication
|
||||
# basic-auth = ""
|
||||
|
||||
#### File descriptor binding
|
||||
# fd = ""
|
||||
|
||||
#### Worker threads
|
||||
threads-multiplier = 1
|
||||
|
||||
#### Grace period after a graceful shutdown
|
||||
grace-period = 0
|
||||
|
||||
#### Page fallback for 404s
|
||||
# page-fallback = ""
|
||||
|
||||
#### Log request Remote Address if available
|
||||
log-remote-address = false
|
||||
|
||||
#### Redirect to trailing slash in the requested directory uri
|
||||
redirect-trailing-slash = true
|
||||
|
||||
#### Check for existing pre-compressed files
|
||||
compression-static = true
|
||||
|
||||
#### Health-check endpoint (GET or HEAD `/health`)
|
||||
health = false
|
||||
|
||||
### Windows Only
|
||||
|
||||
#### Run the web server as a Windows Service
|
||||
# windows-service = false
|
||||
|
||||
|
||||
[advanced]
|
||||
|
||||
#### HTTP Headers customization (examples only)
|
||||
|
||||
#### a. Oneline version
|
||||
# [[advanced.headers]]
|
||||
# source = "**/*.{js,css}"
|
||||
# headers = { Access-Control-Allow-Origin = "*" }
|
||||
|
||||
#### b. Multiline version
|
||||
# [[advanced.headers]]
|
||||
# source = "/index.html"
|
||||
# [advanced.headers.headers]
|
||||
# Cache-Control = "public, max-age=36000"
|
||||
# Content-Security-Policy = "frame-ancestors 'self'"
|
||||
# Strict-Transport-Security = "max-age=63072000; includeSubDomains; preload"
|
||||
|
||||
#### c. Multiline version with explicit key (dotted)
|
||||
# [[advanced.headers]]
|
||||
# source = "**/*.{jpg,jpeg,png,ico,gif}"
|
||||
# headers.Strict-Transport-Security = "max-age=63072000; includeSubDomains; preload"
|
||||
|
||||
|
||||
### URL Redirects (examples only)
|
||||
|
||||
# [[advanced.redirects]]
|
||||
# source = "**/*.{jpg,jpeg}"
|
||||
# destination = "/images/generic1.png"
|
||||
# kind = 301
|
||||
|
||||
# [[advanced.redirects]]
|
||||
# source = "/index.html"
|
||||
# destination = "https://static-web-server.net"
|
||||
# kind = 302
|
||||
|
||||
### URL Rewrites (examples only)
|
||||
|
||||
# [[advanced.rewrites]]
|
||||
# source = "**/*.{png,ico,gif}"
|
||||
# destination = "/assets/favicon.ico"
|
||||
|
||||
# [[advanced.rewrites]]
|
||||
# source = "**/*.{jpg,jpeg}"
|
||||
# destination = "/images/sws.png"
|
22
docker-compose.yml
Normal file
@ -0,0 +1,22 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
dead_net:
|
||||
image: joseluisq/static-web-server:2
|
||||
restart: always
|
||||
environment:
|
||||
# Note: those envs are customizable but also optional
|
||||
- SERVER_HOST=127.0.0.1
|
||||
- SERVER_PORT=80
|
||||
- SERVER_ROOT=/app
|
||||
volumes:
|
||||
- ./build:/app
|
||||
networks:
|
||||
- caddy
|
||||
labels:
|
||||
caddy.address: "https://network.dead.guru"
|
||||
caddy.tls: "assada.ua@gmail.com"
|
||||
networks:
|
||||
caddy:
|
||||
external:
|
||||
name: assada-services
|
7
docs/about/_category_.yml
Normal file
@ -0,0 +1,7 @@
|
||||
position: 1 # float position is supported
|
||||
label: About
|
||||
collapsible: true # make the category collapsible
|
||||
link:
|
||||
type: generated-index
|
||||
title: About Dead Network
|
||||
slug: /about
|
10
docs/about/faq.mdx
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
id: faq
|
||||
title: FAQs
|
||||
slug: /faq
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
## TBA
|
||||
|
||||
...
|
8
docs/about/introduction.mdx
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Introduction
|
||||
sidebar_label: Introduction
|
||||
slug: /introduction
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
## TBA
|
8
docs/about/overview/index.mdx
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Overview
|
||||
sidebar_label: Overview
|
||||
slug: /overview
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
## TBA
|
22
docs/blocks/_lora-regions.mdx
Normal file
@ -0,0 +1,22 @@
|
||||
| Region Code | Description |
|
||||
| :---------: | :---------------------: |
|
||||
| `UNSET` | Unset |
|
||||
| `US` | United States |
|
||||
| `EU_433` | European Union 433MHz |
|
||||
| `EU_868` | European Union 868MHz |
|
||||
| `CN` | China |
|
||||
| `JP` | Japan |
|
||||
| `ANZ` | Australia & New Zealand |
|
||||
| `KR` | Korea |
|
||||
| `TW` | Taiwan |
|
||||
| `RU` | Russia |
|
||||
| `IN` | India |
|
||||
| `NZ_865` | New Zealand 865MHz |
|
||||
| `UA_433` | Ukraine 433MHz |
|
||||
| `UA_868` | Ukraine 868MHz |
|
||||
| `TH` | Thailand |
|
||||
| `LORA_24` | 2.4 GHz band worldwide |
|
||||
|
||||
:::info
|
||||
EU_433 and EU_868 have to adhere to an hourly duty cycle limitation of 10%. Your device will stop transmitting if you reach it, until it is allowed again.
|
||||
:::
|
9
docs/getting-started/index.mdx
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
id: getting-started
|
||||
title: Getting Started
|
||||
sidebar_label: Getting Started
|
||||
slug: /getting-started
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
## TBA
|
8
docs/legal/index.mdx
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Legal
|
||||
sidebar_label: Legal
|
||||
slug: /legal
|
||||
sidebar_position: 9
|
||||
---
|
||||
|
||||
## TBA
|
7
docs/legal/licensing.mdx
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
id: licensing
|
||||
title: Licensing & Commercial Projects Usage
|
||||
sidebar_label: Licensing
|
||||
---
|
||||
|
||||
## TBA
|
8
docs/legal/privacy.mdx
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
id: privacy
|
||||
title: Dead privacy policy
|
||||
sidebar_label: Privacy
|
||||
custom_edit_url: null
|
||||
---
|
||||
|
||||
## TBA
|
7
docs/software/_category_.yml
Normal file
@ -0,0 +1,7 @@
|
||||
label: Software
|
||||
collapsible: true
|
||||
position: 6
|
||||
link:
|
||||
type: generated-index
|
||||
title: Software
|
||||
slug: /software
|
129
docusaurus.config.js
Normal file
@ -0,0 +1,129 @@
|
||||
// @ts-check
|
||||
|
||||
require("dotenv").config();
|
||||
|
||||
/** @type {import('@docusaurus/types').Config} */
|
||||
const config = {
|
||||
title: "Dead Network",
|
||||
tagline:
|
||||
"Мережа сервісів і платформ, які дають змогу окремим особам і спільнотам спілкуватися, ділитися та розвиватися разом.",
|
||||
url: "https://dead.guru",
|
||||
baseUrl: "/",
|
||||
onBrokenLinks: "throw",
|
||||
onBrokenMarkdownLinks: "warn",
|
||||
favicon: "design/web/favicon.ico",
|
||||
organizationName: "dead",
|
||||
projectName: "dead",
|
||||
themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ {
|
||||
announcementBar: {
|
||||
id: "2_0",
|
||||
content:
|
||||
'🎉 Зя`вився XMPP сервер доєднатися можна <a href="/doc/xmpp">тут</a> 🎉',
|
||||
},
|
||||
docs: {
|
||||
sidebar: {
|
||||
autoCollapseCategories: true,
|
||||
},
|
||||
},
|
||||
navbar: {
|
||||
title: "Dead Network",
|
||||
hideOnScroll: true,
|
||||
logo: {
|
||||
alt: "Dead Logo",
|
||||
src: "img/logo.svg",
|
||||
srcDark: "img/logo-white.svg",
|
||||
},
|
||||
items: [
|
||||
{
|
||||
label: "Документація",
|
||||
to: "docs/introduction",
|
||||
},
|
||||
{
|
||||
label: "Клієнти",
|
||||
to: "downloads",
|
||||
},
|
||||
{
|
||||
label: "Інформація",
|
||||
position: "right",
|
||||
items: [
|
||||
{
|
||||
label: "Вступ",
|
||||
to: "docs/introduction",
|
||||
},
|
||||
{
|
||||
label: "Як почати",
|
||||
to: "docs/getting-started",
|
||||
},
|
||||
{
|
||||
label: "ЗІВі",
|
||||
to: "docs/faq",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
href: "https://git.dead.guru/DeadGuru/network",
|
||||
position: "right",
|
||||
className: "header-github-link",
|
||||
"aria-label": "GitHub Репозиторій",
|
||||
},
|
||||
],
|
||||
},
|
||||
footer: {
|
||||
copyright: `<a href="https://vercel.com/?utm_source=meshtastic&utm_campaign=oss">Powered by ▲ Vercel</a>.`,
|
||||
},
|
||||
colorMode: {
|
||||
respectPrefersColorScheme: true,
|
||||
},
|
||||
mermaid: {
|
||||
theme: { light: "base", dark: "base" },
|
||||
options: {
|
||||
themeVariables: {
|
||||
primaryColor: "#f03131",
|
||||
primaryTextColor: "var(--tw-prose-headings)",
|
||||
primaryBorderColor: "#4D4D4D",
|
||||
lineColor: "#EAD667",
|
||||
secondaryColor: "#EA67BD",
|
||||
tertiaryColor: "#677CEA",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
() => {
|
||||
return {
|
||||
name: "docusaurus-tailwindcss",
|
||||
configurePostCss(postcssOptions) {
|
||||
postcssOptions.plugins.push(require("tailwindcss"));
|
||||
postcssOptions.plugins.push(require("autoprefixer"));
|
||||
return postcssOptions;
|
||||
},
|
||||
};
|
||||
},
|
||||
],
|
||||
presets: [
|
||||
[
|
||||
"@docusaurus/preset-classic",
|
||||
/** @type {import('@docusaurus/preset-classic').Options} */
|
||||
{
|
||||
docs: {
|
||||
sidebarPath: require.resolve("./sidebars.js"),
|
||||
editUrl: "https://github.com/dead/dead/edit/master/",
|
||||
breadcrumbs: false,
|
||||
showLastUpdateAuthor: true,
|
||||
},
|
||||
theme: {
|
||||
customCss: require.resolve("./src/css/custom.css"),
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
customFields: {
|
||||
API_URL: process.env.API_URL,
|
||||
},
|
||||
markdown: {
|
||||
mermaid: true,
|
||||
},
|
||||
themes: ["@docusaurus/theme-mermaid"],
|
||||
};
|
||||
|
||||
module.exports = config;
|
49
package.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "dead",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"serve": "docusaurus serve",
|
||||
"clear": "docusaurus clear"
|
||||
},
|
||||
"dependencies": {
|
||||
"@algolia/client-search": "^4.17.0",
|
||||
"@docusaurus/core": "2.4.1",
|
||||
"@docusaurus/plugin-content-docs": "2.4.1",
|
||||
"@docusaurus/preset-classic": "2.4.1",
|
||||
"@docusaurus/theme-common": "^2.4.1",
|
||||
"@docusaurus/theme-mermaid": "^2.4.1",
|
||||
"@headlessui/react": "^1.7.14",
|
||||
"@heroicons/react": "^2.0.18",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"@meshtastic/meshtasticjs": "2.1.9-0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"base64-js": "^1.5.1",
|
||||
"dotenv": "^16.0.3",
|
||||
"framer-motion": "^6.5.1",
|
||||
"postcss": "^8.4.23",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-icons": "^4.8.0",
|
||||
"react-responsive-carousel": "^3.2.23",
|
||||
"swr": "^2.1.5",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"url-search-params-polyfill": "^8.1.1",
|
||||
"use-breakpoint": "^3.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.4.1",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@tsconfig/docusaurus": "^1.0.7",
|
||||
"@types/node": "^20.1.7",
|
||||
"@types/react": "^18.2.6",
|
||||
"@types/react-dom": "^18.2.4",
|
||||
"rome": "^12.1.0",
|
||||
"typescript": "^5.0.4"
|
||||
}
|
||||
}
|
9319
pnpm-lock.yaml
Normal file
11
sidebars.js
Normal file
@ -0,0 +1,11 @@
|
||||
// @ts-check
|
||||
|
||||
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
|
||||
module.exports = {
|
||||
Sidebar: [
|
||||
{
|
||||
type: "autogenerated",
|
||||
dirName: ".",
|
||||
},
|
||||
],
|
||||
};
|
27
src/components/BatteryCalculator.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
|
||||
export const BatteryCalculator = (): JSX.Element => {
|
||||
return (
|
||||
<div className="card">
|
||||
<div className="card__header">
|
||||
<h3>Battery Calculator</h3>
|
||||
</div>
|
||||
<div className="card__body" style={{ display: "flex", gap: "2rem" }}>
|
||||
<div>
|
||||
<input placeholder="Search" />
|
||||
<input placeholder="Search" />
|
||||
<input placeholder="Search" />
|
||||
<input placeholder="Search" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__footer">
|
||||
<button
|
||||
type="button"
|
||||
className="button button--secondary button--block"
|
||||
>
|
||||
See All
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
16
src/components/Button.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React from "react";
|
||||
|
||||
import { HTMLMotionProps, motion } from "framer-motion";
|
||||
|
||||
export const Button = ({ children, ...props }: HTMLMotionProps<"div">) => {
|
||||
return (
|
||||
<motion.div
|
||||
{...props}
|
||||
whileHover={{ scale: 1.1, backgroundColor: "var(--tertiary)" }}
|
||||
whileTap={{ scale: 1.0 }}
|
||||
className="m-auto flex cursor-pointer rounded-full bg-secondary p-3 shadow-md"
|
||||
>
|
||||
<div className="m-auto">{children}</div>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
13
src/components/ColorMode.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import React from "react";
|
||||
|
||||
export interface ColorModeProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Dark = ({ children }: ColorModeProps): JSX.Element => {
|
||||
return <div className="hideLight">{children}</div>;
|
||||
};
|
||||
|
||||
export const Light = ({ children }: ColorModeProps): JSX.Element => {
|
||||
return <div className="hideDark">{children}</div>;
|
||||
};
|
274
src/components/HardwareComponents.tsx
Normal file
@ -0,0 +1,274 @@
|
||||
// import React from 'react';
|
||||
// import data from '/docs/hardware/supported/devices.json'
|
||||
|
||||
// function checkVersionOverrides(selectedDevice, version, value) {
|
||||
|
||||
// var versionOverride = selectedDevice.versionOverrides[version]
|
||||
// var device = selectedDevice
|
||||
// var objectSegment = value.split('.')
|
||||
|
||||
// while (objectSegment.length > 1) {
|
||||
// console.log(objectSegment)
|
||||
// let test = objectSegment.shift()
|
||||
// console.log('test', test, 'og objectSegment', objectSegment)
|
||||
// versionOverride = versionOverride[test]
|
||||
// device = device[test]
|
||||
// }
|
||||
// if (versionOverride) {
|
||||
// return versionOverride
|
||||
// } else return device
|
||||
|
||||
// // if (selectedDevice.versionOverrides[version][value]) {
|
||||
// // return selectedDevice.versionOverrides[version][value]
|
||||
// // } else {
|
||||
// // console.log("no", selectedDevice, value, selectedDevice[value])
|
||||
// // return selectedDevice[value]
|
||||
// // }
|
||||
// }
|
||||
|
||||
// export const MeshtasticFeatures = ({device, version}): JSX.Element => {
|
||||
|
||||
// const selectedDevice = data[device]
|
||||
|
||||
// return (
|
||||
// <table>
|
||||
// <thead>
|
||||
// <th style={{align: "center"}}>
|
||||
// Meshtastic Feature
|
||||
// </th>
|
||||
// <th style={{align: "center"}}>
|
||||
// Device Support
|
||||
// </th>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Support Status
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// {checkVersionOverrides(selectedDevice, version, 'supportStatus')}
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Bluetooth
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// {checkVersionOverrides(selectedDevice, version, "features.bluetoothCapable")}
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Module - Canned Message
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Module - External Notification
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Module - Range Test
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Module - Rotary Encoder
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Module - Store and Forward
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Module - Telemetry (aka Environmental Measurement)
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Router - Always Powered
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Router - Solar Powered
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// WiFi
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export const HardwareSpecifications = ({device, version}): JSX.Element => {
|
||||
|
||||
// const selectedDevice = data[device]
|
||||
|
||||
// return (
|
||||
// <table>
|
||||
// <thead>
|
||||
// <th style={{align: "center"}}>
|
||||
// Specification
|
||||
// </th>
|
||||
// <th style={{align: "center"}}>
|
||||
// Value
|
||||
// </th>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Bluetooth
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Bluetooth Antenna
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Chipset
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Driver
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// GPS
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Flash
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Frequency - 433MHz
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Frequency - 868MHz
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Frequency - 915MHz
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// Frequency - 923MHz
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// LoRa Transceiver
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// PSRAM
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// RAM
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// WiFi
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style={{align: "center"}}>
|
||||
// WiFi Antenna
|
||||
// </td>
|
||||
// <td style={{align: "center"}}>
|
||||
// VALUE
|
||||
// </td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
// );
|
||||
// };
|
49
src/components/Modal.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import React from "react";
|
||||
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
|
||||
import { Dialog } from "@headlessui/react";
|
||||
|
||||
export interface ModalProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Modal = ({ open, onClose, children }: ModalProps): JSX.Element => {
|
||||
return (
|
||||
<AnimatePresence initial={false} exitBeforeEnter={true}>
|
||||
<Dialog
|
||||
as="div"
|
||||
className="fixed inset-0 z-10 overflow-y-auto"
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className="min-h-screen px-0.5 text-center md:px-4">
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<Dialog.Overlay className="fixed inset-0 backdrop-blur-md" />
|
||||
</motion.div>
|
||||
|
||||
<span
|
||||
className="inline-block h-screen align-middle"
|
||||
aria-hidden="true"
|
||||
>
|
||||
​
|
||||
</span>
|
||||
<div className="inline-block w-full transform text-left align-middle transition-all 2xl:max-w-7xl">
|
||||
<div className="group relative">
|
||||
<div className="animate-tilt absolute -inset-0.5 rotate-2 rounded-lg bg-accent shadow-md transition duration-1000 group-hover:opacity-100 group-hover:duration-200" />
|
||||
<div className="relative flex flex-col overflow-hidden rounded-2xl bg-base shadow-md md:aspect-[2/1] md:flex-row md:bg-primary">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</AnimatePresence>
|
||||
);
|
||||
};
|
25
src/components/PageLayout.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import React from "react";
|
||||
|
||||
import Layout from "@theme/Layout";
|
||||
|
||||
export interface PageLayoutProps {
|
||||
title: string;
|
||||
description: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const PageLayout = ({
|
||||
title,
|
||||
description,
|
||||
children,
|
||||
}: PageLayoutProps): JSX.Element => {
|
||||
return (
|
||||
<Layout title={title} description={description}>
|
||||
{children}
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export interface ColorModeProps {
|
||||
children: React.ReactNode;
|
||||
}
|
31
src/components/homepage/SocialCard.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import React from "react";
|
||||
|
||||
import { FiExternalLink } from "react-icons/fi";
|
||||
|
||||
export interface SocialCardProps {
|
||||
children: React.ReactNode;
|
||||
color: string;
|
||||
link: string;
|
||||
}
|
||||
|
||||
export const SocialCard = ({
|
||||
children,
|
||||
color,
|
||||
link,
|
||||
}: SocialCardProps): JSX.Element => {
|
||||
return (
|
||||
<div
|
||||
className={`group relative flex h-24 w-36 min-w-max flex-shrink-0 rounded-xl shadow-xl ${color} m-2`}
|
||||
>
|
||||
{children}
|
||||
<a
|
||||
className="absolute top-0 left-0 right-0 bottom-0 hidden rounded-xl border border-accent bg-secondary bg-opacity-95 text-2xl shadow-xl group-hover:flex"
|
||||
href={link}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<FiExternalLink className="m-auto" />
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
};
|
345
src/components/tools/FrequencyCalculator.tsx
Normal file
@ -0,0 +1,345 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Protobuf, Types } from "@meshtastic/meshtasticjs";
|
||||
|
||||
interface Region {
|
||||
freq_start: number;
|
||||
freq_end: number;
|
||||
duty_cycle: number;
|
||||
spacing: number;
|
||||
power_limit: number;
|
||||
}
|
||||
|
||||
interface Modem {
|
||||
bw: number;
|
||||
cr: number;
|
||||
sf: number;
|
||||
}
|
||||
|
||||
const RegionData = new Map<Protobuf.Config_LoRaConfig_RegionCode, Region>([
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.US,
|
||||
{
|
||||
freq_start: 902.0,
|
||||
freq_end: 928.0,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 30,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.EU_433,
|
||||
{
|
||||
freq_start: 433.0,
|
||||
freq_end: 434.0,
|
||||
duty_cycle: 10,
|
||||
spacing: 0,
|
||||
power_limit: 12,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.EU_868,
|
||||
{
|
||||
freq_start: 869.4,
|
||||
freq_end: 869.65,
|
||||
duty_cycle: 10,
|
||||
spacing: 0,
|
||||
power_limit: 27,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.CN,
|
||||
{
|
||||
freq_start: 470.0,
|
||||
freq_end: 510.0,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 19,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.JP,
|
||||
{
|
||||
freq_start: 920.8,
|
||||
freq_end: 927.8,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 16,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.ANZ,
|
||||
{
|
||||
freq_start: 915.0,
|
||||
freq_end: 928.0,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 30,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.RU,
|
||||
{
|
||||
freq_start: 868.7,
|
||||
freq_end: 869.2,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 20,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.KR,
|
||||
{
|
||||
freq_start: 920.0,
|
||||
freq_end: 923.0,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 0,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.TW,
|
||||
{
|
||||
freq_start: 920.0,
|
||||
freq_end: 925.0,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 0,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.IN,
|
||||
{
|
||||
freq_start: 865.0,
|
||||
freq_end: 867.0,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 30,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.NZ_865,
|
||||
{
|
||||
freq_start: 864.0,
|
||||
freq_end: 868.0,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 36,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.TH,
|
||||
{
|
||||
freq_start: 920.0,
|
||||
freq_end: 925.0,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 16,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.UA_433,
|
||||
{
|
||||
freq_start: 433.0,
|
||||
freq_end: 434.7,
|
||||
duty_cycle: 10,
|
||||
spacing: 0,
|
||||
power_limit: 10,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.UA_868,
|
||||
{
|
||||
freq_start: 868.0,
|
||||
freq_end: 868.6,
|
||||
duty_cycle: 1,
|
||||
spacing: 0,
|
||||
power_limit: 14,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.LORA_24,
|
||||
{
|
||||
freq_start: 2400.0,
|
||||
freq_end: 2483.5,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 10,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_RegionCode.UNSET,
|
||||
{
|
||||
freq_start: 902.0,
|
||||
freq_end: 928.0,
|
||||
duty_cycle: 100,
|
||||
spacing: 0,
|
||||
power_limit: 30,
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
const modemPresets = new Map<Protobuf.Config_LoRaConfig_ModemPreset, Modem>([
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_ModemPreset.SHORT_FAST,
|
||||
{
|
||||
bw: 250,
|
||||
cr: 8,
|
||||
sf: 7,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_ModemPreset.SHORT_SLOW,
|
||||
{
|
||||
bw: 250,
|
||||
cr: 8,
|
||||
sf: 8,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_ModemPreset.MEDIUM_FAST,
|
||||
{
|
||||
bw: 250,
|
||||
cr: 8,
|
||||
sf: 9,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_ModemPreset.MEDIUM_SLOW,
|
||||
{
|
||||
bw: 250,
|
||||
cr: 8,
|
||||
sf: 10,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_ModemPreset.LONG_FAST,
|
||||
{
|
||||
bw: 250,
|
||||
cr: 8,
|
||||
sf: 11,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_ModemPreset.LONG_MODERATE,
|
||||
{
|
||||
bw: 125,
|
||||
cr: 8,
|
||||
sf: 11,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_ModemPreset.LONG_SLOW,
|
||||
{
|
||||
bw: 125,
|
||||
cr: 8,
|
||||
sf: 12,
|
||||
},
|
||||
],
|
||||
[
|
||||
Protobuf.Config_LoRaConfig_ModemPreset.VERY_LONG_SLOW,
|
||||
{
|
||||
bw: 62.5,
|
||||
cr: 8,
|
||||
sf: 12,
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
export const FrequencyCalculator = (): JSX.Element => {
|
||||
const [modemPreset, setModemPreset] =
|
||||
React.useState<Protobuf.Config_LoRaConfig_ModemPreset>(
|
||||
Protobuf.Config_LoRaConfig_ModemPreset.LONG_FAST,
|
||||
);
|
||||
const [region, setRegion] =
|
||||
React.useState<Protobuf.Config_LoRaConfig_RegionCode>(
|
||||
Protobuf.Config_LoRaConfig_RegionCode.US,
|
||||
);
|
||||
const [channel, setChannel] = React.useState<Types.ChannelNumber>(
|
||||
Types.ChannelNumber.PRIMARY,
|
||||
);
|
||||
const [numChannels, setNumChannels] = React.useState<number>(0);
|
||||
const [channelFrequency, setChannelFrequency] = React.useState<number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
const selectedRegion = RegionData.get(region);
|
||||
const selectedModemPreset = modemPresets.get(modemPreset);
|
||||
const calculatedNumChannels = Math.floor(
|
||||
(selectedRegion.freq_end - selectedRegion.freq_start) /
|
||||
(selectedRegion.spacing + selectedModemPreset.bw / 1000),
|
||||
);
|
||||
|
||||
setNumChannels(calculatedNumChannels);
|
||||
|
||||
let updatedChannel = channel;
|
||||
if (updatedChannel >= calculatedNumChannels) {
|
||||
updatedChannel = 0;
|
||||
}
|
||||
|
||||
setChannel(updatedChannel);
|
||||
|
||||
setChannelFrequency(
|
||||
selectedRegion.freq_start +
|
||||
selectedModemPreset.bw / 2000 +
|
||||
updatedChannel * (selectedModemPreset.bw / 1000),
|
||||
);
|
||||
}, [modemPreset, region, channel]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col border-l-[5px] shadow-md my-4 border-accent rounded-lg p-4 bg-secondary gap-2">
|
||||
<div className="flex gap-2">
|
||||
<label>Modem Preset:</label>
|
||||
<select
|
||||
value={modemPreset}
|
||||
onChange={(e) =>
|
||||
setModemPreset(
|
||||
parseInt(
|
||||
e.target.value,
|
||||
) as Protobuf.Config_LoRaConfig_ModemPreset,
|
||||
)
|
||||
}
|
||||
>
|
||||
{Array.from(modemPresets.keys()).map((key) => (
|
||||
<option key={key} value={key}>
|
||||
{Protobuf.Config_LoRaConfig_ModemPreset[key]}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<label>Region:</label>
|
||||
<select
|
||||
value={region}
|
||||
onChange={(e) => setRegion(parseInt(e.target.value))}
|
||||
>
|
||||
{Array.from(RegionData.keys()).map((key) => (
|
||||
<option key={key} value={key}>
|
||||
{Protobuf.Config_LoRaConfig_RegionCode[key]}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<label>Channel:</label>
|
||||
<select
|
||||
value={channel}
|
||||
onChange={(e) => setChannel(parseInt(e.target.value))}
|
||||
>
|
||||
{Array.from(Array(numChannels).keys()).map((key) => (
|
||||
<option key={key} value={key}>
|
||||
{key + 1}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<label className="font-semibold">Number of channels:</label>
|
||||
<input type="number" disabled value={numChannels} />
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<label className="font-semibold">Channel Frequency:</label>
|
||||
<input type="number" disabled value={channelFrequency} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
208
src/css/custom.css
Normal file
@ -0,0 +1,208 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* You can override the default Infima variables here. */
|
||||
:root {
|
||||
--ifm-color-primary: #eab167;
|
||||
--ifm-color-primary-dark: rgb(175, 102, 33);
|
||||
--ifm-color-primary-darker: rgb(165, 85, 31);
|
||||
--ifm-color-primary-darkest: rgb(136, 75, 26);
|
||||
--ifm-color-primary-light: rgb(203, 130, 70);
|
||||
--ifm-color-primary-lighter: rgb(212, 164, 102);
|
||||
--ifm-color-primary-lightest: rgb(224, 199, 146);
|
||||
--ifm-list-item-margin: 0;
|
||||
--ifm-code-font-size: 95%;
|
||||
--ifm-z-index-fixed: 1;
|
||||
--accent: #eab167;
|
||||
--base: #f3f4f6;
|
||||
--primary: #ffffff;
|
||||
--secondary: #e5e7eb;
|
||||
--tertiary: #d1d5db;
|
||||
--mute: #6b7280;
|
||||
--primaryInv: #242526;
|
||||
--secondaryInv: #18191a;
|
||||
--tertiaryInv: #4c4e50;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--base: #38393b;
|
||||
--primary: #242526;
|
||||
--secondary: #18191a;
|
||||
--tertiary: #4c4e50;
|
||||
--mute: #9ca3af;
|
||||
--primaryInv: #ffffff;
|
||||
--secondaryInv: #e5e7eb;
|
||||
--tertiaryInv: #d1d5db;
|
||||
}
|
||||
|
||||
.docusaurus-highlight-code-line {
|
||||
background-color: rgb(72, 77, 91);
|
||||
display: block;
|
||||
margin: 0 calc(-1 * var(--ifm-pre-padding));
|
||||
padding: 0 var(--ifm-pre-padding);
|
||||
}
|
||||
|
||||
.header-github-link:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.header-github-link:before {
|
||||
content: "";
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")
|
||||
no-repeat;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .header-github-link:before {
|
||||
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")
|
||||
no-repeat;
|
||||
}
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
70% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 0 10px rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.cta--button {
|
||||
--ifm-button-border-color: var(--ifm-link-color);
|
||||
color: var(--ifm-link-color);
|
||||
}
|
||||
|
||||
.split-container {
|
||||
display: flex;
|
||||
}
|
||||
.split-item {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.indexCtasBody {
|
||||
--ifm-button-size-multiplier: 1.6;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.indexCtasBody a:last-of-type {
|
||||
margin: 20px 36px;
|
||||
}
|
||||
|
||||
.indexCtas {
|
||||
--ifm-button-size-multiplier: 1.6;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.indexCtas a {
|
||||
color: var(--ifm-font-color-base-inverse);
|
||||
--ifm-button-border-color: var(--ifm-font-color-base-inverse);
|
||||
}
|
||||
|
||||
.indexCtas a:hover {
|
||||
color: rgb(77, 77, 77);
|
||||
--ifm-button-border-color: rgb(77, 77, 77);
|
||||
}
|
||||
|
||||
.indexCtas a:last-of-type {
|
||||
margin: 20px 36px;
|
||||
}
|
||||
|
||||
.theme-doc-markdown {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
a + .navbar__link {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
a + .navbar__link > svg {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
.markdown {
|
||||
@apply prose prose-lg;
|
||||
}
|
||||
.markdown img {
|
||||
@apply rounded-lg mx-auto;
|
||||
}
|
||||
[data-theme="dark"] .markdown {
|
||||
@apply prose-invert;
|
||||
}
|
||||
[data-theme="dark"] .hideDark {
|
||||
@apply hidden;
|
||||
}
|
||||
[data-theme="dark"] .hideLight {
|
||||
@apply block;
|
||||
}
|
||||
.hideLight {
|
||||
@apply hidden;
|
||||
}
|
||||
.hideDark {
|
||||
@apply block;
|
||||
}
|
||||
}
|
||||
|
||||
.markdown :where(li):not(:where([class~="not-prose"] *)) {
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.markdown
|
||||
:where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"] *)) {
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-weight: var(--ifm-heading-font-weight);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: var(--ifm-h1-font-size);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: var(--ifm-h2-font-size);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: var(--ifm-h3-font-size);
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: var(--ifm-h4-font-size);
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: var(--ifm-h5-font-size);
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: var(--ifm-h6-font-size);
|
||||
}
|
29
src/hooks/useFilteredNetworks.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
|
||||
import { Showcase } from "../utils/apiTypes";
|
||||
import { useSelectedTags } from "./useSelectedTags";
|
||||
|
||||
const filterNetworks = (
|
||||
showcaseNetworks: Showcase[],
|
||||
selectedTags: string[],
|
||||
) => {
|
||||
if (selectedTags.length === 0) {
|
||||
return showcaseNetworks;
|
||||
}
|
||||
return showcaseNetworks.filter((showcaseNetwork) => {
|
||||
if (showcaseNetwork.tags.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return selectedTags.every((queryTag) =>
|
||||
showcaseNetwork.tags.find((searchTag) => searchTag.label === queryTag),
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export const useFilteredNetworks = (networks: Showcase[]) => {
|
||||
const selectedTags = useSelectedTags();
|
||||
return React.useMemo(
|
||||
() => filterNetworks(networks, selectedTags),
|
||||
[selectedTags],
|
||||
);
|
||||
};
|
16
src/hooks/useSelectedTags.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React from "react";
|
||||
|
||||
import { useLocation } from "@docusaurus/router";
|
||||
|
||||
import { readSearchTags } from "../pages/showcase/_components/TagSelect";
|
||||
|
||||
export const useSelectedTags = () => {
|
||||
const location = useLocation();
|
||||
const [selectedTags, setSelectedTags] = React.useState<string[]>([]);
|
||||
React.useEffect(() => {
|
||||
const tags = readSearchTags(location.search);
|
||||
setSelectedTags(tags);
|
||||
}, [location]);
|
||||
|
||||
return selectedTags;
|
||||
};
|
44
src/pages/credits/_components/Avatar.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import React from "react";
|
||||
|
||||
export interface avatarProps {
|
||||
imgUrl: string;
|
||||
name?: string;
|
||||
userName?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface avatarLayoutProps {
|
||||
list: list[];
|
||||
}
|
||||
|
||||
export const Avatar = ({
|
||||
imgUrl,
|
||||
name,
|
||||
description,
|
||||
}: avatarProps): JSX.Element => {
|
||||
return (
|
||||
<div className="card m-4 border-2 border-secondary">
|
||||
<div className="card__body">
|
||||
<div className="avatar">
|
||||
<img className="avatar__photo avatar__photo--sm" src={imgUrl} />
|
||||
<div className="avatar__intro">
|
||||
<div className="avatar__name">{name}</div>
|
||||
<small className="avatar__subtitle">{description}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const AvatarLayout = ({ list }: avatarLayoutProps): JSX.Element => {
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="flex flex-wrap justify-center bg-primary">
|
||||
{list.map(() => {
|
||||
return <Avatar />;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
165
src/pages/credits/index.tsx
Normal file
@ -0,0 +1,165 @@
|
||||
import React from "react";
|
||||
import Layout from "@theme/Layout";
|
||||
import Link from "@docusaurus/Link";
|
||||
|
||||
import { AvatarLayout } from "./_components/Avatar";
|
||||
|
||||
const Credits = (): JSX.Element => {
|
||||
const partnerLogos = [
|
||||
{
|
||||
name: "Vercel",
|
||||
url: "/2.0/vercel-logotype-dark.svg",
|
||||
},
|
||||
{
|
||||
name: "Cloudflare",
|
||||
url: "/2.0/CF_logo_horizontal_blktype.svg",
|
||||
},
|
||||
{
|
||||
name: "RAK Wireless",
|
||||
url: "/2.0/RAK-blue-main.svg",
|
||||
},
|
||||
{
|
||||
name: "Open Collective",
|
||||
url: "/2.0/opencollectivelogo.svg",
|
||||
},
|
||||
{
|
||||
name: "LILYGO",
|
||||
url: "/2.0/LILYGO.png",
|
||||
},
|
||||
{
|
||||
name: "Discord",
|
||||
url: "/2.0/discord.svg",
|
||||
},
|
||||
];
|
||||
return (
|
||||
<Layout
|
||||
title="Credits"
|
||||
description="Meshtastic is made possible by the following people & organizations."
|
||||
>
|
||||
<main className="relative mt-20">
|
||||
<div className="container mx-auto p-6 leading-normal space-y-4">
|
||||
<h1>Credits</h1>
|
||||
<p>
|
||||
Meshtastic is community driven. Thousands of hours have been donated
|
||||
by volunteers who want to develop this amazing project. Whether
|
||||
you've submitted a pull request or triaged a bug in our
|
||||
Discord/Forum. You've made Meshtastic possible. Thank you for your
|
||||
contributions.
|
||||
</p>
|
||||
<p>
|
||||
We would also like to recognize those who have donated financially
|
||||
to the project. As Meshtastic has grown, we've aquired some ongoing
|
||||
costs to keep the project running. Thank you for your generous
|
||||
donations.
|
||||
</p>
|
||||
</div>
|
||||
<div className="container mx-auto p-6 leading-normal space-y-4">
|
||||
<h2>Fiscal Sponsors</h2>
|
||||
<p>
|
||||
We have partnered with both the{" "}
|
||||
<a
|
||||
className="underline"
|
||||
href="https://opencollective.com"
|
||||
target="_blank"
|
||||
>
|
||||
Open Collective
|
||||
</a>{" "}
|
||||
and the{" "}
|
||||
<a
|
||||
className="underline"
|
||||
href="https://www.oscollective.org"
|
||||
target="_blank"
|
||||
>
|
||||
Open Source Collective
|
||||
</a>{" "}
|
||||
to help us with a fiscal management framework and banking needs.
|
||||
They help support over three thousand open source projects including
|
||||
the PHP Foundation, F-Droid, Sonarr, LinuxServer and DarkReader. We
|
||||
are in good hands and good company.
|
||||
</p>
|
||||
<p>
|
||||
As with everything we do here, Open Collective provides a fully
|
||||
transparent framework for our budget and expenses. You can see what
|
||||
we’re bringing in, who is spending money and where that money is
|
||||
going{" "}
|
||||
<a
|
||||
className="underline"
|
||||
href="https://opencollective.com/meshtastic"
|
||||
target="_blank"
|
||||
>
|
||||
here
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
<p>
|
||||
In addition to our partnership with Open Collective and Open Source
|
||||
Collective, we have also been approved into the{" "}
|
||||
<a
|
||||
className="underline"
|
||||
href="https://github.com/sponsors"
|
||||
target="_blank"
|
||||
>
|
||||
GitHub Sponsors
|
||||
</a>{" "}
|
||||
program where we can set fundraising goals with GitHub.
|
||||
</p>
|
||||
<p>
|
||||
All donations made through GitHub will be deposited to our account
|
||||
with the Open Source Collective and managed by the Open Collective.
|
||||
This means we have a single place to monitor and maintain
|
||||
transparency of our finances.
|
||||
</p>
|
||||
<p>If you are able, please contribute to this amazing project.</p>
|
||||
<div className="indexCtasBody">
|
||||
<Link
|
||||
className={"button button--outline button--lg cta--button"}
|
||||
to={"https://opencollective.com/meshtastic/donate"}
|
||||
>
|
||||
Sponsor Meshtastic
|
||||
</Link>
|
||||
</div>
|
||||
<h3>
|
||||
Open Collective Donations
|
||||
{/*Open Collective Donations*/}
|
||||
<AvatarLayout list={[]} />
|
||||
</h3>
|
||||
<h3>
|
||||
GitHub Sponsor Donations
|
||||
{/*GitHub Sponsor Donations*/}
|
||||
<AvatarLayout list={[]} />
|
||||
</h3>
|
||||
</div>
|
||||
<div className="container mx-auto p-6 leading-normal space-y-4">
|
||||
<h2>Partnerships</h2>
|
||||
<div className="mt-12 grid grid-cols-2 gap-0.5 md:grid-cols-3 lg:mt-0 lg:grid-cols-2">
|
||||
{partnerLogos.map((logo) => (
|
||||
<div
|
||||
key={logo.name}
|
||||
className="col-span-1 flex justify-center bg-gray-50 py-8 px-8"
|
||||
>
|
||||
<img className="max-h-12" src={logo.url} alt={logo.name} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="container mx-auto p-6 leading-normal space-y-4">
|
||||
<h2>Contributors</h2>
|
||||
<p>
|
||||
Literally thousands of hours have gone into creating, maintaining,
|
||||
and improving Meshtastic. Without our contributors none of this
|
||||
would be possible. Thank you for donating the time for each and
|
||||
every commit, issue, and pull request.
|
||||
</p>
|
||||
{/*GitHub Organization Contributors*/}
|
||||
<AvatarLayout list={[]} />
|
||||
</div>
|
||||
{/*Admin Bios*/}
|
||||
<div className="container mx-auto p-6 leading-normal space-y-4">
|
||||
<AvatarLayout list={[]} />
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Credits;
|
146
src/pages/downloads/_components/DownloadCard.tsx
Normal file
@ -0,0 +1,146 @@
|
||||
import React from "react";
|
||||
|
||||
export interface downloadCardProps {
|
||||
client: string;
|
||||
imgUrl: string;
|
||||
url: string;
|
||||
imgUrl2: string;
|
||||
url2: string;
|
||||
notes: string;
|
||||
buttonText: string;
|
||||
}
|
||||
|
||||
export const DownloadCard = ({
|
||||
client,
|
||||
imgUrl,
|
||||
url,
|
||||
imgUrl2,
|
||||
url2,
|
||||
notes,
|
||||
buttonText,
|
||||
}: downloadCardProps): JSX.Element => {
|
||||
return (
|
||||
<div className="card">
|
||||
<div
|
||||
className="card__header"
|
||||
style={{ display: "flex", justifyContent: "space-between" }}
|
||||
>
|
||||
<h3>{client}</h3>
|
||||
</div>
|
||||
<div
|
||||
className="card__body"
|
||||
style={{ display: "flex", justifyContent: "center" }}
|
||||
>
|
||||
{buttonText ? (
|
||||
<a href={url} className="button button--secondary button--block">
|
||||
{buttonText}
|
||||
</a>
|
||||
) : (
|
||||
<div>
|
||||
<a href={url}>
|
||||
<img alt="img1" style={{ height: "4rem" }} src={imgUrl} />
|
||||
</a>
|
||||
<a href={url2}>
|
||||
<img alt="img2" style={{ height: "4rem" }} src={imgUrl2} />
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="card__footer">{notes ? notes : null}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const PlaceholderCard = (): JSX.Element => {
|
||||
return (
|
||||
<div
|
||||
className="card"
|
||||
style={{
|
||||
width: "100%",
|
||||
animation: "pulse 2s infinite",
|
||||
transform: "scale(1)",
|
||||
display: "flex",
|
||||
gap: "1rem",
|
||||
padding: "1rem",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
marginBottom: "1rem",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "2rem",
|
||||
width: "8rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
marginTop: "1rem",
|
||||
height: "1rem",
|
||||
width: "8rem",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="card__body"
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "3rem",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
/>
|
||||
<a className="button disabled button--primary button--block"> </a>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
width: "8rem",
|
||||
height: "2rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
width: "11rem",
|
||||
height: "1rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
width: "9rem",
|
||||
height: "1rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
width: "13rem",
|
||||
height: "1rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
width: "11rem",
|
||||
height: "1rem",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
151
src/pages/downloads/_components/FirmwareCard.tsx
Normal file
@ -0,0 +1,151 @@
|
||||
import React from "react";
|
||||
|
||||
import { DeviceFirmwareResource } from "../../../utils/apiTypes";
|
||||
|
||||
export interface releaseCardProps {
|
||||
variant: string;
|
||||
description: string;
|
||||
release?: DeviceFirmwareResource[];
|
||||
}
|
||||
|
||||
export const FirmwareCard = ({
|
||||
variant,
|
||||
description,
|
||||
release,
|
||||
}: releaseCardProps): JSX.Element => {
|
||||
return (
|
||||
<div className="card m-4 border-2 border-secondary">
|
||||
<div
|
||||
className="card__header"
|
||||
style={{ display: "flex", justifyContent: "space-between" }}
|
||||
>
|
||||
<h3>{variant}</h3>
|
||||
{release?.length && (
|
||||
<a href={release[0].page_url}>{release[0].title}</a>
|
||||
)}
|
||||
</div>
|
||||
<div className="card__body">
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
<div className="card__footer mt-auto">
|
||||
<div className="margin-top--sm">
|
||||
<details>
|
||||
<summary>Older Versions</summary>
|
||||
{release.slice(1, 6).map((release) => {
|
||||
return (
|
||||
<div key={release.id}>
|
||||
<a href={release.zip_url}>{release.title}</a>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</details>
|
||||
</div>
|
||||
{release?.length ? (
|
||||
<>
|
||||
<a
|
||||
href={release[0].zip_url}
|
||||
className="button button--secondary button--block margin-top--sm"
|
||||
>
|
||||
Download {variant}
|
||||
</a>
|
||||
</>
|
||||
) : (
|
||||
<button disabled className="button button--secondary button--block">
|
||||
Loading...
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const PlaceholderFirmwareCard = (): JSX.Element => {
|
||||
return (
|
||||
<div
|
||||
className="card"
|
||||
style={{
|
||||
width: "100%",
|
||||
animation: "pulse 2s infinite",
|
||||
transform: "scale(1)",
|
||||
display: "flex",
|
||||
gap: "1rem",
|
||||
padding: "1rem",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
marginBottom: "1rem",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "2rem",
|
||||
width: "8rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
marginTop: "1rem",
|
||||
height: "1rem",
|
||||
width: "8rem",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="card__body"
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "3rem",
|
||||
}}
|
||||
/>
|
||||
<a className="button disabled button--primary button--block"> </a>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
width: "8rem",
|
||||
height: "2rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
width: "11rem",
|
||||
height: "1rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
width: "9rem",
|
||||
height: "1rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
width: "13rem",
|
||||
height: "1rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
width: "11rem",
|
||||
height: "1rem",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
18
src/pages/downloads/_components/HeaderText.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from "react";
|
||||
|
||||
export const HeaderText = ({ type, text, link }): JSX.Element => {
|
||||
const Header = type;
|
||||
|
||||
return (
|
||||
<Header className="anchor anchorWithHideOnScrollNavbar_node_modules-@docusaurus-theme-classic-lib-next-theme-Heading-styles-module">
|
||||
{text}
|
||||
{link && (
|
||||
<a
|
||||
className="hash-link"
|
||||
href={`#${link}`}
|
||||
title="Direct link to heading"
|
||||
/>
|
||||
)}
|
||||
</Header>
|
||||
);
|
||||
};
|
288
src/pages/downloads/index.tsx
Normal file
@ -0,0 +1,288 @@
|
||||
import React from "react";
|
||||
|
||||
import { FaAndroid, FaApple } from "react-icons/fa";
|
||||
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
|
||||
import {
|
||||
ArrowTopRightOnSquareIcon,
|
||||
ComputerDesktopIcon,
|
||||
GlobeAltIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import Layout from "@theme/Layout";
|
||||
|
||||
const Firmware = (): JSX.Element => {
|
||||
return (
|
||||
<Layout
|
||||
title="Завантаження"
|
||||
description="Клієнти для наших сервісів для різних платформ."
|
||||
>
|
||||
<div className="container mt-8 flex flex-col gap-3">
|
||||
<div className="flex w-full overflow-hidden rounded-xl">
|
||||
<div className="flex w-1/5 bg-gradient-to-r from-rose-500 to-primary">
|
||||
<span className="m-auto h-20 text-4xl font-black">#IRC</span>
|
||||
</div>
|
||||
<div className="flex w-full columns-3 flex-col bg-primary lg:flex-row">
|
||||
<div className="card m-4 border-2 border-secondary">
|
||||
<div className="card__header">
|
||||
<h3>Apple</h3>
|
||||
</div>
|
||||
<div className="card__body flex items-center">
|
||||
<div className="m-auto">
|
||||
<FaApple className="h-20 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__body">
|
||||
Available on MacOS & iOS. Requires MacOS Ventura or iOS 16+.
|
||||
</div>
|
||||
<div className="card__footer mt-auto">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="#"
|
||||
className="m-auto flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
App Store
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card m-4 border-2 border-secondary">
|
||||
<div className="card__header">
|
||||
<h3>Android</h3>
|
||||
</div>
|
||||
<div className="card__body flex items-center">
|
||||
<div className="m-auto">
|
||||
<FaAndroid className="h-20 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__body">Sideloading also available.</div>
|
||||
<div className="card__footer mt-auto">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="#"
|
||||
className="m-auto flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
F-Droid
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="#"
|
||||
className="mt-4 flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
Play Store
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card m-4 border-2 border-secondary">
|
||||
<div className="card__header">
|
||||
<h3>Web</h3>
|
||||
</div>
|
||||
<div className="card__body flex items-center">
|
||||
<div className="m-auto">
|
||||
<GlobeAltIcon className="h-20 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__body">
|
||||
<a href="https://sr.ht/~emersion/gamja/">gamja</a> веб клієнт
|
||||
для IRC.
|
||||
</div>
|
||||
<div className="card__footer mt-auto">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://irc.dead.guru"
|
||||
className="m-auto flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
irc.dead.guru
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* */}
|
||||
<div className="flex w-full overflow-hidden rounded-xl">
|
||||
<div className="flex w-1/5 bg-gradient-to-r from-green-500 to-primary">
|
||||
<span className="m-auto h-20 text-4xl font-black">#MATRIX</span>
|
||||
</div>
|
||||
<div className="flex w-full columns-3 flex-col bg-primary lg:flex-row">
|
||||
<div className="card m-4 border-2 border-secondary">
|
||||
<div className="card__header">
|
||||
<h3>Apple</h3>
|
||||
</div>
|
||||
<div className="card__body flex items-center">
|
||||
<div className="m-auto">
|
||||
<FaApple className="h-20 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__body">
|
||||
Available on MacOS & iOS. Requires MacOS Ventura or iOS 16+.
|
||||
</div>
|
||||
<div className="card__footer mt-auto">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="#"
|
||||
className="m-auto flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
App Store
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card m-4 border-2 border-secondary">
|
||||
<div className="card__header">
|
||||
<h3>Android</h3>
|
||||
</div>
|
||||
<div className="card__body flex items-center">
|
||||
<div className="m-auto">
|
||||
<FaAndroid className="h-20 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__body">Sideloading also available.</div>
|
||||
<div className="card__footer mt-auto">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="#"
|
||||
className="m-auto flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
F-Droid
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="#"
|
||||
className="mt-4 flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
Play Store
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card m-4 border-2 border-secondary">
|
||||
<div className="card__header">
|
||||
<h3>Web</h3>
|
||||
</div>
|
||||
<div className="card__body flex items-center">
|
||||
<div className="m-auto">
|
||||
<GlobeAltIcon className="h-20 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__body">
|
||||
fluffychat веб клієнт для matrix.
|
||||
</div>
|
||||
<div className="card__footer mt-auto">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://xmpp.dead.guru:5281/conversejs"
|
||||
className="m-auto flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
https://fluffychat.im/
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* */}
|
||||
<div className="flex w-full overflow-hidden rounded-xl">
|
||||
<div className="flex w-1/5 bg-gradient-to-r from-yellow-500 to-primary">
|
||||
<span className="m-auto h-20 text-4xl font-black">#XMPP</span>
|
||||
</div>
|
||||
<div className="flex w-full columns-3 flex-col bg-primary lg:flex-row">
|
||||
<div className="card m-4 border-2 border-secondary">
|
||||
<div className="card__header">
|
||||
<h3>Apple</h3>
|
||||
</div>
|
||||
<div className="card__body flex items-center">
|
||||
<div className="m-auto">
|
||||
<FaApple className="h-20 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__body">
|
||||
Available on MacOS & iOS. Requires MacOS Ventura or iOS 16+.
|
||||
</div>
|
||||
<div className="card__footer mt-auto">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="#"
|
||||
className="m-auto flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
App Store
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card m-4 border-2 border-secondary">
|
||||
<div className="card__header">
|
||||
<h3>Android</h3>
|
||||
</div>
|
||||
<div className="card__body flex items-center">
|
||||
<div className="m-auto">
|
||||
<FaAndroid className="h-20 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__body">Sideloading also available.</div>
|
||||
<div className="card__footer mt-auto">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="#"
|
||||
className="m-auto flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
F-Droid
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="#"
|
||||
className="mt-4 flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
Play Store
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card m-4 border-2 border-secondary">
|
||||
<div className="card__header">
|
||||
<h3>Web</h3>
|
||||
</div>
|
||||
<div className="card__body flex items-center">
|
||||
<div className="m-auto">
|
||||
<GlobeAltIcon className="h-20 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__body">
|
||||
<a href="https://conversejs.org/">Converse.js</a> веб клієнт для
|
||||
XMPP.
|
||||
</div>
|
||||
<div className="card__footer mt-auto">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://xmpp.dead.guru:5281/conversejs"
|
||||
className="m-auto flex rounded-lg border-4 border-transparent bg-accent p-1 font-semibold text-black shadow-md hover:text-black hover:brightness-110 active:border-green-200"
|
||||
>
|
||||
https://xmpp.dead.guru:5281/conversejs
|
||||
<ArrowTopRightOnSquareIcon className="m-auto ml-2 h-4" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Firmware;
|
7
src/pages/e/index.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
id: e
|
||||
title: Dead Channel Settings
|
||||
sidebar_label: e
|
||||
---
|
||||
|
||||
## TBD
|
300
src/pages/index.tsx
Normal file
@ -0,0 +1,300 @@
|
||||
import "react-responsive-carousel/lib/styles/carousel.min.css"; // requires a loader
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Carousel } from "react-responsive-carousel";
|
||||
|
||||
import Head from "@docusaurus/Head";
|
||||
import Link from "@docusaurus/Link";
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
||||
import Layout from "@theme/Layout";
|
||||
|
||||
import { SocialCard, SocialCardProps } from "../components/homepage/SocialCard";
|
||||
|
||||
const features = [
|
||||
{
|
||||
title: "Основа мережі — Спілкування",
|
||||
imageUrl: "img/homepage/messages.svg",
|
||||
description: (
|
||||
<>
|
||||
Мережу в першу чергу, створюють люди, а не технології. Спілкування
|
||||
дозволяє нам зберігати зв'язок з друзями та родиною, а також будувати
|
||||
новий, цікавий і вільний світ.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Захист",
|
||||
imageUrl: "img/homepage/encryption.svg",
|
||||
description: (
|
||||
<>
|
||||
Ми намагаємося захистити вашу приватність, використовуючи шифрування де
|
||||
це можливо та необхідно. Ви можете використовувати власні ключі
|
||||
шифрування, щоб забезпечити максимальний рівень захисту. Ми також
|
||||
відкриті для аудиту та вдосконалення наших методів шифрування та
|
||||
захисту.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Незалежність",
|
||||
imageUrl: "img/homepage/platforms.svg",
|
||||
description: (
|
||||
<>
|
||||
Свобода спілкування не повинна бути обмежена. Ми намагаємося
|
||||
підтримувати якомога більше платформ, щоб ви могли спілкуватися з
|
||||
друзями та родиною, незалежно від того, який пристрій ви використовуєте.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Open Source",
|
||||
imageUrl: "img/homepage/opensource.svg",
|
||||
description: (
|
||||
<>
|
||||
Мережа побудована на основі відкритих проектів, що дозволяє вам приймати
|
||||
участь в розвитку та вдосконаленні мережі.
|
||||
</>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const SocialCards: SocialCardProps[] = [
|
||||
{
|
||||
color: "bg-[#3875EA]",
|
||||
link: "https://irc.dead.guru",
|
||||
children: (
|
||||
<img alt="irc" className="m-auto h-10" src="/img/services/irc.svg" />
|
||||
),
|
||||
},
|
||||
{
|
||||
color: "bg-[#FFFFFF]",
|
||||
link: "https://matrix.to/#/#adhd_lab:hypogea.org",
|
||||
children: (
|
||||
<img
|
||||
alt="matrix"
|
||||
className="m-auto h-14"
|
||||
src="/img/services/Matrix_logo.svg"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
color: "bg-[#95c0d9]",
|
||||
link: "https://xmpp.dead.guru:5281/",
|
||||
children: (
|
||||
<img
|
||||
alt="xmpp"
|
||||
className="m-auto h-14"
|
||||
src="/img/services/XMPP_logo.svg"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
color: "bg-[#f05539]",
|
||||
link: "https://git.dead.guru/",
|
||||
children: (
|
||||
<img alt="git" className="m-auto h-14" src="/img/services/git_logo.svg" />
|
||||
),
|
||||
},
|
||||
{
|
||||
color: "bg-[#9e9b9a]",
|
||||
link: "https://mine.dead.guru",
|
||||
children: (
|
||||
<img
|
||||
alt="minecraft"
|
||||
className="m-auto h-16"
|
||||
src="/img/services/minecraft_logo.svg"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
color: "bg-[#39322b]",
|
||||
link: "https://bookhouse.hypogea.org/",
|
||||
children: (
|
||||
<img
|
||||
alt="Calibre"
|
||||
className="m-auto h-12"
|
||||
src="/img/services/Calibre_logo.png"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
color: "bg-[#6366f1]",
|
||||
link: "https://pi.dead.guru",
|
||||
children: (
|
||||
<img
|
||||
alt="reddit"
|
||||
className="m-auto h-20"
|
||||
src="/img/services/Pixelfed_logo.svg"
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
function Home() {
|
||||
const context = useDocusaurusContext();
|
||||
const { siteConfig } = context;
|
||||
return (
|
||||
<Layout>
|
||||
<Head>
|
||||
<meta property="og:title" content="Dead Network" />
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://meshtastic.org/design/web/social-preview-1200x630.png"
|
||||
/>
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Надаємо різноманітні сервіси-платформи, які дають змогу окремим особам і спільнотам спілкуватися, ділитися та розвиватися разом."
|
||||
/>
|
||||
<meta property="og:url" content="https://dead.guru/" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
</Head>
|
||||
<header style={{ textAlign: "center" }} className="hero hero--primary">
|
||||
<div className="container">
|
||||
<h1 className="hero__title">
|
||||
<img
|
||||
style={{ paddingTop: "2rem", paddingBottom: "2rem" }}
|
||||
alt="Dead Logo"
|
||||
className="header__logo"
|
||||
src={useBaseUrl("img/dead-banner.png")}
|
||||
/>
|
||||
</h1>
|
||||
<p className="hero__subtitle">{siteConfig.tagline}</p>
|
||||
<div className="indexCtas">
|
||||
<Link className="button button--lg" to="/docs/introduction">
|
||||
Дізнатися більше
|
||||
</Link>
|
||||
<Link className="button button--lg" to="/docs/getting-started">
|
||||
Розпочати
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<main className="flex flex-col gap-4">
|
||||
<Carousel autoPlay infiniteLoop showStatus={false} showThumbs={false}>
|
||||
{features.map((feature) => (
|
||||
<div key={feature.title} className="flex p-12">
|
||||
<div className="w-1/2">
|
||||
<img
|
||||
className="my-auto h-40"
|
||||
src={feature.imageUrl}
|
||||
alt={feature.title}
|
||||
/>
|
||||
</div>
|
||||
<div className="my-auto w-1/2">
|
||||
<h3 className="text-xl font-medium">{feature.title}</h3>
|
||||
<p>{feature.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</Carousel>
|
||||
|
||||
<div className="bg-primaryDark mx-auto flex w-full lg:w-auto flex-col gap-4 p-4 shadow-inner">
|
||||
<h3 className="text-xl font-bold">Приєднуйтесь до нас.</h3>
|
||||
<div className="flex w-full overflow-x-auto">
|
||||
{SocialCards.map((card) => (
|
||||
<SocialCard key={card.link} color={card.color} link={card.link}>
|
||||
{card.children}
|
||||
</SocialCard>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="container mx-auto flex w-auto flex-col">
|
||||
<h2 className="mb-2 text-xl font-medium">
|
||||
Доєднайтеся до "Мертвої" мережі в 3 кроки.
|
||||
</h2>
|
||||
<ul
|
||||
className="mx-auto"
|
||||
style={{
|
||||
position: "relative",
|
||||
display: "grid",
|
||||
gap: "1.5rem",
|
||||
gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
|
||||
paddingLeft: "0",
|
||||
}}
|
||||
>
|
||||
<div className="card">
|
||||
<div
|
||||
className="card__header"
|
||||
style={{ display: "flex", justifyContent: "space-between" }}
|
||||
>
|
||||
<h3>1. Оберіть платформу</h3>
|
||||
</div>
|
||||
<div
|
||||
className="card__body"
|
||||
style={{ display: "flex", justifyContent: "center" }}
|
||||
>
|
||||
<p>
|
||||
Для старту почніть з вибору платформи:
|
||||
<ul>
|
||||
<li>IRC</li>
|
||||
<li>XMPP</li>
|
||||
<li>Matrix</li>
|
||||
<li>
|
||||
Або взагалі проігноруйте сервіси повідомлень і почніть з{" "}
|
||||
<a href="">
|
||||
<strong>ігрових серверів</strong>
|
||||
</a>
|
||||
!
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card">
|
||||
<div
|
||||
className="card__header"
|
||||
style={{ display: "flex", justifyContent: "space-between" }}
|
||||
>
|
||||
<h3>2. Завантажте і зареєструйтесь!</h3>
|
||||
</div>
|
||||
<div
|
||||
className="card__body"
|
||||
style={{ display: "flex", justifyContent: "center" }}
|
||||
>
|
||||
<p>
|
||||
<a href="/downloads">
|
||||
<strong>Завантажте</strong>
|
||||
</a>{" "}
|
||||
додаток для обраної платформи, перегляньте наш{" "}
|
||||
<a href="">
|
||||
<strong>мануал по налаштуванню</strong>
|
||||
</a>{" "}
|
||||
і зареєструйтесь в сервісі мережі.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card">
|
||||
<div
|
||||
className="card__header"
|
||||
style={{ display: "flex", justifyContent: "space-between" }}
|
||||
>
|
||||
<h3>3. Приєднайтесь до чату</h3>
|
||||
</div>
|
||||
<div
|
||||
className="card__body"
|
||||
style={{ display: "flex", justifyContent: "center" }}
|
||||
>
|
||||
<p>
|
||||
В залежності від ваших інтересів і обраної платформи, ви
|
||||
можете приєднатися до:
|
||||
<ul>
|
||||
<li>Загальний чат</li>
|
||||
<li>ADHD Lab</li>
|
||||
<li>Ігрові чати</li>
|
||||
<li>HAM загальний чат</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export default Home;
|
110
src/pages/showcase/_components/Card.tsx
Normal file
@ -0,0 +1,110 @@
|
||||
import React from "react";
|
||||
|
||||
import { Showcase } from "../../../utils/apiTypes";
|
||||
import { mapUrl } from "../../../utils/map";
|
||||
import { CardTags } from "./CardTags";
|
||||
|
||||
export interface CardProps {
|
||||
network: Showcase;
|
||||
}
|
||||
|
||||
export const Card = React.memo(({ network }: CardProps) => (
|
||||
<div className="card">
|
||||
<div className="card__image">
|
||||
<div style={{ height: "140px" }}>
|
||||
<img src={mapUrl(network.nodes ?? [])} alt={network.title} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__body">
|
||||
<h4>{network.title}</h4>
|
||||
<small>{network.summary}</small>
|
||||
</div>
|
||||
<div className="card__footer">
|
||||
<a
|
||||
href={`?id=${network.id}`}
|
||||
className="button button--primary button--block"
|
||||
style={{ marginBottom: "0.5rem" }}
|
||||
>
|
||||
Read more
|
||||
</a>
|
||||
<CardTags tags={network.tags} />
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
export const PlaceholderCard = (): JSX.Element => (
|
||||
<div
|
||||
className="card"
|
||||
style={{
|
||||
animation: "pulse 2s infinite",
|
||||
transform: "scale(1)",
|
||||
}}
|
||||
>
|
||||
<div className="card__image">
|
||||
<div
|
||||
style={{
|
||||
height: "140px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="card__body">
|
||||
<div
|
||||
style={{
|
||||
width: "30%",
|
||||
height: "2rem",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
marginBottom: "1rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "1rem",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
marginBottom: "0.5rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "1rem",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="card__footer">
|
||||
<button
|
||||
className="button disabled button--primary button--block"
|
||||
style={{ marginBottom: "0.5rem" }}
|
||||
>
|
||||
|
||||
</button>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: "0.5rem",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: "4rem",
|
||||
height: "1.5rem",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: "4rem",
|
||||
height: "1.5rem",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
29
src/pages/showcase/_components/CardTags.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
|
||||
import { ShowcaseTag } from "../../../utils/apiTypes";
|
||||
|
||||
export interface CardTagsProps {
|
||||
tags: ShowcaseTag[];
|
||||
}
|
||||
|
||||
export const CardTags = ({ tags }: CardTagsProps) => {
|
||||
return (
|
||||
<div>
|
||||
{tags.map(({ color, label }) => {
|
||||
return (
|
||||
<span
|
||||
className="badge"
|
||||
key={label}
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
marginRight: "0.3rem",
|
||||
userSelect: "none",
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
90
src/pages/showcase/_components/Filters.tsx
Normal file
@ -0,0 +1,90 @@
|
||||
import React from "react";
|
||||
|
||||
import { FiHeart } from "react-icons/fi";
|
||||
import useSWR from "swr";
|
||||
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
||||
import { fetcher } from "../../../utils/swr";
|
||||
|
||||
import { ShowcaseTag } from "../../../utils/apiTypes";
|
||||
// import { TagList, Tags } from '../../../utils/showcase';
|
||||
import { PlaceholderTagSelect, TagSelect } from "./TagSelect";
|
||||
|
||||
export const Filters = (): JSX.Element => {
|
||||
const { siteConfig } = useDocusaurusContext();
|
||||
|
||||
const { data, error } = useSWR<ShowcaseTag[]>(
|
||||
`${siteConfig.customFields.API_URL}/showcase/tags`,
|
||||
fetcher,
|
||||
);
|
||||
|
||||
return (
|
||||
<section className="margin-top--l margin-bottom--lg container">
|
||||
{data && !error ? (
|
||||
<ul
|
||||
style={{
|
||||
padding: "0",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
{data.map((tag) => {
|
||||
const { label, color } = tag;
|
||||
const id = `showcase_checkbox_id_${tag};`;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={tag.id}
|
||||
style={{
|
||||
boxSizing: "border-box",
|
||||
position: "relative",
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
height: "2rem",
|
||||
marginTop: "0.5rem",
|
||||
marginRight: "0.5rem",
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
verticalAlign: "middle",
|
||||
userSelect: "none",
|
||||
}}
|
||||
>
|
||||
<TagSelect
|
||||
tag={tag}
|
||||
id={id}
|
||||
label={label}
|
||||
icon={
|
||||
tag.label === "Favorite" ? (
|
||||
<span
|
||||
style={{
|
||||
display: "flex",
|
||||
marginLeft: "0.5rem",
|
||||
color: "rgb(190 24 93)",
|
||||
}}
|
||||
>
|
||||
<FiHeart />
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: "50%",
|
||||
marginLeft: 8,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
) : (
|
||||
<PlaceholderTagSelect />
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
};
|
318
src/pages/showcase/_components/Network.tsx
Normal file
@ -0,0 +1,318 @@
|
||||
import React from "react";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
||||
import { Showcase } from "../../../utils/apiTypes";
|
||||
import { fetcher } from "../../../utils/swr";
|
||||
|
||||
interface NetworkProps {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export const Network = ({ id }: NetworkProps): JSX.Element => {
|
||||
const { siteConfig } = useDocusaurusContext();
|
||||
|
||||
const { data, error } = useSWR<Showcase>(
|
||||
`${siteConfig.customFields.API_URL}/showcase/${id}`,
|
||||
fetcher,
|
||||
);
|
||||
|
||||
const githubData = useSWR(
|
||||
`https://api.github.com/users/${data?.author?.githubUsername}`,
|
||||
fetcher,
|
||||
).data;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{data && !error ? (
|
||||
<div className="container">
|
||||
<h1>{data.title}</h1>
|
||||
<p>{data.summary}</p>
|
||||
{githubData && (
|
||||
<div className="avatar">
|
||||
<img
|
||||
src={githubData.avatar_url}
|
||||
alt={githubData.name}
|
||||
className="avatar__photo"
|
||||
/>
|
||||
<div className="avatar__intro">
|
||||
<div className="avatar__name">{githubData.name}</div>
|
||||
<div className="avatar__subtitle">{githubData.bio}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="markdown">{data.body}</div>
|
||||
|
||||
<div
|
||||
className="card"
|
||||
style={{
|
||||
marginLeft: "auto",
|
||||
marginRight: "auto",
|
||||
maxWidth: "900px",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="card__header"
|
||||
style={{
|
||||
margin: "8px",
|
||||
}}
|
||||
>
|
||||
<h2>Bill of Materials</h2>
|
||||
</div>
|
||||
<div className="card__body">
|
||||
{data.materials?.map((material) => (
|
||||
<div
|
||||
key={material.id}
|
||||
style={{
|
||||
borderTop: "2px solid gray",
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: "4rem",
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={material.image}
|
||||
height="auto"
|
||||
width="100%"
|
||||
style={{
|
||||
margin: "auto",
|
||||
padding: "4px",
|
||||
display: "block",
|
||||
maxWidth: "60px",
|
||||
maxHeight: "60px",
|
||||
width: "auto",
|
||||
height: "auto",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="avatar__intro">
|
||||
<div className="avatar__name">{material.name}</div>
|
||||
<small className="avatar__subtitle">
|
||||
{material.details}
|
||||
</small>
|
||||
</div>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href={material.url}
|
||||
className="button button--outline button--secondary"
|
||||
style={{
|
||||
marginTop: "auto",
|
||||
marginBottom: "auto",
|
||||
}}
|
||||
>
|
||||
View
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
{error && <div>{JSON.stringify(error)}</div>}
|
||||
{!data && <PlaceholderNetwork />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const PlaceholderNetwork = (): JSX.Element => {
|
||||
return (
|
||||
<div
|
||||
className="container"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: window.innerWidth > 768 ? "row" : "column",
|
||||
gap: "2rem",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: window.innerWidth > 768 ? "60%" : "100%",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="card"
|
||||
style={{
|
||||
width: "100%",
|
||||
animation: "pulse 2s infinite",
|
||||
transform: "scale(1)",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "2rem",
|
||||
padding: "2rem",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "4rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "12rem",
|
||||
}}
|
||||
/>
|
||||
<div style={{ display: "flex", gap: "1rem" }}>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "999px",
|
||||
backgroundColor: "gray",
|
||||
height: "4rem",
|
||||
width: "4rem",
|
||||
minWidth: "4rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "1rem",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "1rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "2rem",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: window.innerWidth > 768 ? "40%" : "100%",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="card"
|
||||
style={{
|
||||
width: "100%",
|
||||
animation: "pulse 2s infinite",
|
||||
transform: "scale(1)",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "2rem",
|
||||
padding: "2rem",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "12rem",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "2rem",
|
||||
}}
|
||||
/>
|
||||
<div style={{ display: "flex", gap: "0.5rem" }}>
|
||||
<div
|
||||
style={{
|
||||
width: "7rem",
|
||||
height: "1.8rem",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: "7rem",
|
||||
height: "1.8rem",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: "7rem",
|
||||
height: "1.8rem",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "column", gap: "1rem" }}
|
||||
>
|
||||
<div style={{ display: "flex", gap: "1rem" }}>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "2.5rem",
|
||||
width: "20%",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "2.5rem",
|
||||
width: "60%",
|
||||
}}
|
||||
/>
|
||||
<a
|
||||
className="button disabled button--primary button--block"
|
||||
style={{ width: "20%" }}
|
||||
>
|
||||
|
||||
</a>
|
||||
</div>
|
||||
<div style={{ display: "flex", gap: "1rem" }}>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "2.5rem",
|
||||
width: "20%",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
height: "2.5rem",
|
||||
width: "60%",
|
||||
}}
|
||||
/>
|
||||
<a
|
||||
className="button disabled button--primary button--block"
|
||||
style={{ width: "20%" }}
|
||||
>
|
||||
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
67
src/pages/showcase/_components/NetworkSection.tsx
Normal file
@ -0,0 +1,67 @@
|
||||
import React from "react";
|
||||
|
||||
import { Showcase } from "../../../utils/apiTypes";
|
||||
import { Card, PlaceholderCard } from "./Card";
|
||||
|
||||
interface NetworkSectionProps {
|
||||
title: string;
|
||||
icon?: JSX.Element;
|
||||
iconColor?: string;
|
||||
networks?: Showcase[];
|
||||
}
|
||||
|
||||
export const NetworkSection = ({
|
||||
title,
|
||||
icon,
|
||||
iconColor,
|
||||
networks,
|
||||
}: NetworkSectionProps): JSX.Element => {
|
||||
return (
|
||||
<div className="margin-top--lg container">
|
||||
<div
|
||||
className="margin-bottom--sm"
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<h2>{title}</h2>
|
||||
{icon && (
|
||||
<span
|
||||
style={{
|
||||
marginBottom: "0.5rem",
|
||||
marginLeft: "0.5rem",
|
||||
fontSize: "1.25rem",
|
||||
lineHeight: "1.75rem",
|
||||
color: iconColor,
|
||||
}}
|
||||
>
|
||||
{icon}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<ul
|
||||
style={{
|
||||
position: "relative",
|
||||
display: "grid",
|
||||
gap: "1.5rem",
|
||||
gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
|
||||
paddingLeft: "0",
|
||||
}}
|
||||
>
|
||||
{networks ? (
|
||||
<>
|
||||
{networks.map((network) => (
|
||||
<Card key={network.title} network={network} />
|
||||
))}
|
||||
{networks.length === 0 && <h2>No result</h2>}
|
||||
</>
|
||||
) : (
|
||||
<div>
|
||||
<PlaceholderCard />
|
||||
</div>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
52
src/pages/showcase/_components/Networks.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import React from "react";
|
||||
|
||||
import { FiHeart, FiSearch } from "react-icons/fi";
|
||||
import useSWR from "swr";
|
||||
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
||||
import { useSelectedTags } from "../../../hooks/useSelectedTags";
|
||||
|
||||
import { useFilteredNetworks } from "../../../hooks/useFilteredNetworks";
|
||||
import { Showcase } from "../../../utils/apiTypes";
|
||||
import { fetcher } from "../../../utils/swr";
|
||||
import { NetworkSection } from "./NetworkSection";
|
||||
|
||||
export const Networks = (): JSX.Element => {
|
||||
const { siteConfig } = useDocusaurusContext();
|
||||
|
||||
const { data, error } = useSWR<Showcase[]>(
|
||||
`${siteConfig.customFields.API_URL}/showcase`,
|
||||
fetcher,
|
||||
);
|
||||
|
||||
const selectedTags = useSelectedTags();
|
||||
const filteredNetworks = useFilteredNetworks(data ?? []);
|
||||
|
||||
return (
|
||||
<section className="margin-top--lg margin-bottom--xl">
|
||||
{!error ? (
|
||||
selectedTags.length === 0 ? (
|
||||
<>
|
||||
<NetworkSection
|
||||
title="Our favorites"
|
||||
icon={<FiHeart />}
|
||||
iconColor="rgb(190 24 93)"
|
||||
networks={data?.filter((network) =>
|
||||
network.tags.find((tag) => tag.label === "Favorite"),
|
||||
)}
|
||||
/>
|
||||
<NetworkSection title="All networks" networks={data} />
|
||||
</>
|
||||
) : (
|
||||
<NetworkSection
|
||||
title="Results"
|
||||
icon={<FiSearch />}
|
||||
networks={filteredNetworks}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<div>{JSON.stringify(error)}</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
};
|
111
src/pages/showcase/_components/TagSelect.tsx
Normal file
@ -0,0 +1,111 @@
|
||||
import "url-search-params-polyfill";
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { useHistory, useLocation } from "@docusaurus/router";
|
||||
import { ShowcaseTag } from "../../../utils/apiTypes";
|
||||
|
||||
import { toggleListItem } from "../../../utils/showcase";
|
||||
|
||||
interface Props extends React.ComponentProps<"input"> {
|
||||
icon: React.ReactElement<React.ComponentProps<"svg">>;
|
||||
label: React.ReactNode;
|
||||
tag: ShowcaseTag;
|
||||
}
|
||||
|
||||
export function readSearchTags(search: string): string[] {
|
||||
return new URLSearchParams(search).getAll("tags");
|
||||
}
|
||||
|
||||
function replaceSearchTags(search: string, newTags: string[]) {
|
||||
const searchParams = new URLSearchParams(search);
|
||||
searchParams.delete("tags");
|
||||
newTags.forEach((tag) => searchParams.append("tags", tag));
|
||||
return searchParams.toString();
|
||||
}
|
||||
|
||||
export const TagSelect = React.forwardRef<HTMLLabelElement, Props>(
|
||||
({ icon, label, tag }) => {
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
const [selected, setSelected] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
const tags = readSearchTags(location.search);
|
||||
setSelected(tags.includes(tag.label));
|
||||
}, [tag, location]);
|
||||
const toggleTag = React.useCallback(() => {
|
||||
const tags = readSearchTags(location.search);
|
||||
const newTags = toggleListItem(tags, tag.label);
|
||||
const newSearch = replaceSearchTags(location.search, newTags);
|
||||
history.push({ ...location, search: newSearch });
|
||||
}, [tag, location, history]);
|
||||
return (
|
||||
<button
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
className={`button button--sm button--outline button--secondary ${
|
||||
selected ? "button--active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
toggleTag();
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
{icon}
|
||||
</button>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export const PlaceholderTagSelect = (): JSX.Element => (
|
||||
<div
|
||||
style={{
|
||||
boxSizing: "border-box",
|
||||
position: "relative",
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
height: "2rem",
|
||||
marginTop: "0.5rem",
|
||||
marginRight: "0.5rem",
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
verticalAlign: "middle",
|
||||
userSelect: "none",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: "7rem",
|
||||
height: "1.8rem",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
animation: "pulse 2s infinite",
|
||||
transform: "scale(1)",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: "7rem",
|
||||
height: "1.8rem",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
animation: "pulse 2s infinite",
|
||||
transform: "scale(1)",
|
||||
marginLeft: 8,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: "7rem",
|
||||
height: "1.8rem",
|
||||
borderRadius: "0.4rem",
|
||||
backgroundColor: "gray",
|
||||
animation: "pulse 2s infinite",
|
||||
transform: "scale(1)",
|
||||
marginLeft: 8,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
35
src/pages/showcase/index.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import "url-search-params-polyfill";
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { useLocation } from "@docusaurus/router";
|
||||
import Layout from "@theme/Layout";
|
||||
|
||||
import { Filters } from "./_components/Filters";
|
||||
import { Network } from "./_components/Network";
|
||||
import { Networks } from "./_components/Networks";
|
||||
|
||||
const Showcase = (): JSX.Element => {
|
||||
const location = useLocation();
|
||||
const id = new URLSearchParams(location.search).get("id");
|
||||
|
||||
return (
|
||||
<Layout
|
||||
title="Showcase"
|
||||
description="Portfolio of projects from the Dead community"
|
||||
>
|
||||
<main className="margin-vert--lg">
|
||||
{id ? (
|
||||
<Network id={id} />
|
||||
) : (
|
||||
<>
|
||||
<Filters />
|
||||
<Networks />
|
||||
</>
|
||||
)}
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Showcase;
|
151
src/pages/tools/OEM.tsx
Normal file
@ -0,0 +1,151 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import { fromByteArray, toByteArray } from "base64-js";
|
||||
|
||||
import { Protobuf } from "@meshtastic/meshtasticjs";
|
||||
import Layout from "@theme/Layout";
|
||||
|
||||
const OEM = (): JSX.Element => {
|
||||
const [oemAesKey, setOemAesKey] = useState<Uint8Array>(new Uint8Array());
|
||||
const [oemFont, setOemFont] = useState<Protobuf.ScreenFonts>(
|
||||
Protobuf.ScreenFonts.FONT_MEDIUM,
|
||||
);
|
||||
const [oemIconBits, setOemIconBits] = useState<Uint8Array>(new Uint8Array());
|
||||
const [oemIconHeight, setOemIconHeight] = useState<number>(0);
|
||||
const [oemIconWidth, setOemIconWidth] = useState<number>(0);
|
||||
const [oemText, setOemText] = useState<string>("");
|
||||
const [oemBytes, setOemBytes] = useState<Uint8Array>(new Uint8Array());
|
||||
|
||||
useEffect(() => {
|
||||
setOemBytes(
|
||||
Protobuf.OEMStore.toBinary({
|
||||
oemAesKey,
|
||||
oemFont,
|
||||
oemIconBits,
|
||||
oemIconHeight,
|
||||
oemIconWidth,
|
||||
oemText,
|
||||
}),
|
||||
);
|
||||
}, [oemAesKey, oemFont, oemIconBits, oemIconHeight, oemIconWidth, oemText]);
|
||||
|
||||
const enumOptions = Protobuf.ScreenFonts
|
||||
? Object.entries(Protobuf.ScreenFonts).filter(
|
||||
(value) => typeof value[1] === "number",
|
||||
)
|
||||
: [];
|
||||
|
||||
const readFile = (file: File) => {
|
||||
return new Promise((resolve: (value: string) => void, reject) => {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (res) => {
|
||||
resolve(res.target.result as string);
|
||||
};
|
||||
reader.onerror = (err) => reject(err);
|
||||
|
||||
reader.readAsText(file);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout title="OEM Generator" description="OEM Bin Generator">
|
||||
<div className="container mt-8 flex flex-col gap-3">
|
||||
<span>AES Key</span>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = new Uint8Array(128 / 8);
|
||||
setOemAesKey(crypto.getRandomValues(key));
|
||||
}}
|
||||
className="cursor-pointer rounded-md bg-tertiary p-2 hover:brightness-90"
|
||||
>
|
||||
Generate 128bit
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = new Uint8Array(256 / 8);
|
||||
setOemAesKey(crypto.getRandomValues(key));
|
||||
}}
|
||||
className="mr-auto cursor-pointer rounded-md bg-tertiary p-2 hover:brightness-90"
|
||||
>
|
||||
Generate 256bit
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
name="oemAesKey"
|
||||
value={fromByteArray(oemAesKey)}
|
||||
onChange={(e) => {
|
||||
setOemAesKey(toByteArray(e.target.value));
|
||||
}}
|
||||
/>
|
||||
<span>Font</span>
|
||||
<select
|
||||
onChange={(e) => {
|
||||
setOemFont(parseInt(e.target.value));
|
||||
}}
|
||||
>
|
||||
{enumOptions.map(([name, value]) => (
|
||||
<option key={name} value={value}>
|
||||
{name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<span>Logo XBM</span>
|
||||
<input
|
||||
type="file"
|
||||
name="file"
|
||||
onChange={(e) => {
|
||||
readFile(e.target.files[0]).then((data) => {
|
||||
setOemIconBits(
|
||||
new Uint8Array(
|
||||
data.split(",").map((s) => parseInt(s.trim(), 16)),
|
||||
),
|
||||
);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<span>Logo Height</span>
|
||||
<input
|
||||
type="number"
|
||||
name="oemIconHeight"
|
||||
onChange={(e) => {
|
||||
setOemIconHeight(parseInt(e.target.value));
|
||||
}}
|
||||
/>
|
||||
<span>Logo Width</span>
|
||||
<input
|
||||
type="number"
|
||||
name="oemIconWidth"
|
||||
onChange={(e) => {
|
||||
setOemIconWidth(parseInt(e.target.value));
|
||||
}}
|
||||
/>
|
||||
<span>Boot Text</span>
|
||||
<input
|
||||
type="text"
|
||||
name="oemText"
|
||||
onChange={(e) => {
|
||||
setOemText(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<a
|
||||
className="cursor-pointer rounded-md bg-tertiary p-2 hover:brightness-90"
|
||||
download="OEM.bin"
|
||||
onClick={() => {
|
||||
const blob = new Blob([oemBytes], {
|
||||
type: "application/octet-stream",
|
||||
});
|
||||
window.open(URL.createObjectURL(blob));
|
||||
}}
|
||||
>
|
||||
Download
|
||||
</a>
|
||||
{oemBytes.toString()}
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default OEM;
|
2
src/theme/NotFound.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/// <reference types="react" />
|
||||
export default function NotFound(): JSX.Element;
|
33
src/theme/NotFound.js
Normal file
@ -0,0 +1,33 @@
|
||||
import React from "react";
|
||||
import Translate, { translate } from "@docusaurus/Translate";
|
||||
import { PageMetadata } from "@docusaurus/theme-common";
|
||||
import Layout from "@theme/Layout";
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<>
|
||||
<PageMetadata
|
||||
title={translate({
|
||||
id: "theme.NotFound.title",
|
||||
message: "Page Not Found",
|
||||
})}
|
||||
/>
|
||||
<Layout>
|
||||
<main className="container margin-vert--xl">
|
||||
<div className="row">
|
||||
<div className="col col--6 col--offset-3">
|
||||
<h1 className="hero__title">
|
||||
<Translate
|
||||
id="theme.NotFound.title"
|
||||
description="The title of the 404 page"
|
||||
>
|
||||
404 - Page Not Found
|
||||
</Translate>
|
||||
</h1>
|
||||
<img src="/design/chirpy.png" alt='Chirpy' />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
}
|
65
src/utils/apiTypes.ts
Normal file
@ -0,0 +1,65 @@
|
||||
export interface Showcase {
|
||||
id: string;
|
||||
title: string;
|
||||
summary: string;
|
||||
body: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
tags: ShowcaseTag[];
|
||||
nodes?: Node[];
|
||||
materials?: Material[];
|
||||
author?: Author;
|
||||
authorId?: string;
|
||||
}
|
||||
|
||||
export interface ShowcaseTag {
|
||||
id: string;
|
||||
label: string;
|
||||
description: string;
|
||||
color: string;
|
||||
|
||||
showcases?: Showcase[];
|
||||
}
|
||||
|
||||
export interface Node {
|
||||
id: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
|
||||
showcase?: Showcase;
|
||||
showcaseId?: string;
|
||||
}
|
||||
|
||||
export interface Material {
|
||||
id: string;
|
||||
name: string;
|
||||
details: string;
|
||||
image: string;
|
||||
url: string;
|
||||
|
||||
showcases?: Showcase[];
|
||||
}
|
||||
|
||||
export interface Author {
|
||||
id: string;
|
||||
githubUsername: string;
|
||||
bio: string;
|
||||
|
||||
showcase?: Showcase[];
|
||||
}
|
||||
|
||||
export interface DeviceFirmwareResource {
|
||||
id: string;
|
||||
title: string;
|
||||
page_url?: string;
|
||||
zip_url?: string;
|
||||
}
|
||||
|
||||
export interface FirmwareReleases {
|
||||
releases: {
|
||||
stable: DeviceFirmwareResource[];
|
||||
alpha: DeviceFirmwareResource[];
|
||||
};
|
||||
pullRequests: DeviceFirmwareResource[];
|
||||
}
|
1
src/utils/breakpoints.ts
Normal file
@ -0,0 +1 @@
|
||||
export const BREAKPOINTS = { sm: 640, md: 768, lg: 1024, xl: 1280 };
|
23
src/utils/calculateADC.ts
Normal file
@ -0,0 +1,23 @@
|
||||
export default function calculateADC() {
|
||||
//const variables
|
||||
const BAT_MILLIVOLTS_FULL = 4.2;
|
||||
const BAT_MILLIVOLTS_EMPTY = 3.27;
|
||||
const BAT_FULL_PERCENT = 1;
|
||||
//variable
|
||||
const batteryChargePercent =
|
||||
parseFloat(
|
||||
(<HTMLInputElement>document.getElementById("batteryChargePercent")).value,
|
||||
) / 100;
|
||||
const operativeAdcMultiplier = parseFloat(
|
||||
(<HTMLInputElement>document.getElementById("operativeAdcMultiplier")).value,
|
||||
);
|
||||
const result =
|
||||
(operativeAdcMultiplier *
|
||||
((BAT_FULL_PERCENT - 1) * BAT_MILLIVOLTS_EMPTY -
|
||||
BAT_FULL_PERCENT * BAT_MILLIVOLTS_FULL)) /
|
||||
((batteryChargePercent - 1) * BAT_MILLIVOLTS_EMPTY -
|
||||
batteryChargePercent * BAT_MILLIVOLTS_FULL);
|
||||
(<HTMLInputElement>(
|
||||
document.getElementById("newOperativeAdcMultiplier")
|
||||
)).value = result.toFixed(4);
|
||||
}
|
13
src/utils/map.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Node } from "./apiTypes";
|
||||
|
||||
export const mapUrl = (nodes: Node[]): string => {
|
||||
const width = 900;
|
||||
const height = 400;
|
||||
const access_token =
|
||||
"pk.eyJ1Ijoic2FjaGF3IiwiYSI6ImNrNW9meXozZjBsdW0zbHBjM2FnNnV6cmsifQ.3E4n8eFGD9ZOFo-XDVeZnQ";
|
||||
const nodeCoords = nodes.map(
|
||||
({ latitude, longitude }) => `pin-l+67ea94(${longitude},${latitude})`,
|
||||
);
|
||||
|
||||
return `https://api.mapbox.com/styles/v1/mapbox/satellite-v9/static/${nodeCoords}/auto/${width}x${height}@2x?access_token=${access_token}`;
|
||||
};
|
22
src/utils/showcase.ts
Normal file
@ -0,0 +1,22 @@
|
||||
export const sortBy = <T>(array: T[], getter: (item: T) => unknown): T[] => {
|
||||
const sortedArray = [...array];
|
||||
sortedArray.sort((a, b) =>
|
||||
getter(a) > getter(b) ? 1 : getter(b) > getter(a) ? -1 : 0,
|
||||
);
|
||||
return sortedArray;
|
||||
};
|
||||
|
||||
export const difference = <T>(...arrays: T[][]): T[] => {
|
||||
return arrays.reduce((a, b) => a.filter((c) => !b.includes(c)));
|
||||
};
|
||||
|
||||
export const toggleListItem = <T>(list: T[], item: T): T[] => {
|
||||
const itemIndex = list.indexOf(item);
|
||||
if (itemIndex === -1) {
|
||||
return list.concat(item);
|
||||
} else {
|
||||
const newList = [...list];
|
||||
newList.splice(itemIndex, 1);
|
||||
return newList;
|
||||
}
|
||||
};
|
1
src/utils/swr.ts
Normal file
@ -0,0 +1 @@
|
||||
export const fetcher = (url: string) => fetch(url).then((res) => res.json());
|
1
static/2.0/CF_logo_horizontal_blktype.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" viewBox="0 0 651.29 94.76"><path d="m143.05 93.42 1.07-3.71c1.27-4.41.8-8.48-1.34-11.48-2-2.76-5.26-4.38-9.25-4.57L58 72.7a1.47 1.47 0 0 1-1.35-2 2 2 0 0 1 1.75-1.34l76.26-1c9-.41 18.84-7.75 22.27-16.71l4.34-11.36a2.68 2.68 0 0 0 .18-1 3.31 3.31 0 0 0-.06-.54 49.67 49.67 0 0 0-95.49-5.14 22.35 22.35 0 0 0-35 23.42A31.73 31.73 0 0 0 .34 93.45a1.47 1.47 0 0 0 1.45 1.27h139.49a1.83 1.83 0 0 0 1.77-1.3Z" style="fill:#f78100"/><path d="M168.22 41.15q-1 0-2.1.06a.88.88 0 0 0-.32.07 1.17 1.17 0 0 0-.76.8l-3 10.26c-1.28 4.41-.81 8.48 1.34 11.48a11.65 11.65 0 0 0 9.24 4.57l16.11 1a1.44 1.44 0 0 1 1.14.62 1.5 1.5 0 0 1 .17 1.37 2 2 0 0 1-1.75 1.34l-16.73 1c-9.09.42-18.88 7.75-22.31 16.7l-1.21 3.16a.9.9 0 0 0 .79 1.22h57.63a1.55 1.55 0 0 0 1.54-1.17 41.34 41.34 0 0 0-39.76-52.48Z" style="fill:#fcad32"/><path d="M273.03 59.66h9.53v26.06h16.67v8.35h-26.2V59.66zM309.11 77v-.09c0-9.88 8-17.9 18.58-17.9s18.48 7.92 18.48 17.8v.1c0 9.88-8 17.89-18.58 17.89s-18.48-7.95-18.48-17.8m27.33 0v-.09c0-5-3.59-9.29-8.85-9.29s-8.7 4.22-8.7 9.19v.1c0 5 3.59 9.29 8.8 9.29s8.75-4.23 8.75-9.2m21.4 2V59.66h9.69v19.12c0 5 2.5 7.33 6.34 7.33s6.34-2.26 6.34-7.08V59.66h9.68v19.07c0 11.11-6.34 16-16.12 16s-15.93-5-15.93-15.73m46.65-19.34h13.27c12.29 0 19.42 7.08 19.42 17v.1c0 9.93-7.23 17.3-19.61 17.3h-13.08Zm13.42 26c5.7 0 9.49-3.15 9.49-8.71v-.09c0-5.51-3.79-8.71-9.49-8.71H414v17.47Zm33.13-26h27.52v8.36h-17.98v5.85h16.27v7.91h-16.27v12.29h-9.54V59.66zm40.8 0h9.53v26.06h16.67v8.35h-26.2V59.66zm51.16-.24h9.19l14.61 34.65h-10.22l-2.51-6.14h-13.28l-2.45 6.14h-10Zm8.35 21.08-3.83-9.78-3.92 9.78Zm27.73-20.84h16.27c5.27 0 8.9 1.38 11.21 3.74a10.64 10.64 0 0 1 3.05 8v.1a10.88 10.88 0 0 1-7.08 10.57l8.21 12h-11l-6.94-10.42h-4.18v10.42h-9.54Zm15.83 16.52c3.25 0 5.12-1.58 5.12-4.08V72c0-2.71-2-4.08-5.17-4.08h-6.24v8.26Zm28.46-16.52h27.68v8.11h-18.24v5.21h16.52v7.52h-16.52v5.46h18.48v8.11h-27.92V59.66zM252.15 81a8.44 8.44 0 0 1-7.88 5.16c-5.22 0-8.8-4.33-8.8-9.29v-.1c0-5 3.49-9.2 8.7-9.2a8.64 8.64 0 0 1 8.18 5.71h10C260.79 65.09 253.6 59 244.27 59c-10.62 0-18.58 8-18.58 17.9v.1c0 9.88 7.86 17.8 18.48 17.8 9.08 0 16.18-5.88 18.05-13.76Z"/></svg>
|
After Width: | Height: | Size: 2.1 KiB |
BIN
static/2.0/LILYGO.png
Normal file
After Width: | Height: | Size: 347 KiB |
1
static/2.0/RAK-blue-main.svg
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/2.0/android.jpg
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
static/2.0/background.png
Normal file
After Width: | Height: | Size: 988 KiB |
1
static/2.0/discord.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="292" height="80" fill="none" viewBox="0 0 292 80"><g clip-path="url(#a)"><g fill="#5865F2" clip-path="url(#b)"><path d="M61.796 16.494a59.415 59.415 0 0 0-15.05-4.73 44.128 44.128 0 0 0-1.928 4.003c-5.612-.844-11.172-.844-16.68 0a42.783 42.783 0 0 0-1.95-4.002 59.218 59.218 0 0 0-15.062 4.74C1.6 30.9-.981 44.936.31 58.772c6.317 4.717 12.44 7.583 18.458 9.458a45.906 45.906 0 0 0 3.953-6.51 38.872 38.872 0 0 1-6.225-3.03 30.957 30.957 0 0 0 1.526-1.208c12.004 5.615 25.046 5.615 36.906 0 .499.416 1.01.82 1.526 1.208a38.775 38.775 0 0 1-6.237 3.035 45.704 45.704 0 0 0 3.953 6.511c6.025-1.875 12.153-4.74 18.47-9.464 1.515-16.04-2.588-29.947-10.844-42.277Zm-37.44 33.767c-3.603 0-6.558-3.363-6.558-7.46 0-4.096 2.892-7.466 6.559-7.466 3.666 0 6.621 3.364 6.558 7.466.006 4.097-2.892 7.46-6.558 7.46Zm24.237 0c-3.603 0-6.558-3.363-6.558-7.46 0-4.096 2.892-7.466 6.558-7.466 3.667 0 6.622 3.364 6.558 7.466 0 4.097-2.891 7.46-6.558 7.46ZM98.03 26.17h15.663c3.776 0 6.966.604 9.583 1.806 2.61 1.201 4.567 2.877 5.864 5.022 1.296 2.145 1.95 4.6 1.95 7.367 0 2.707-.677 5.163-2.031 7.36-1.354 2.204-3.414 3.944-6.185 5.228-2.771 1.283-6.203 1.928-10.305 1.928h-14.54V26.17Zm14.378 21.414c2.542 0 4.499-.65 5.864-1.945 1.366-1.301 2.049-3.071 2.049-5.316 0-2.08-.609-3.739-1.825-4.98-1.216-1.243-3.058-1.87-5.52-1.87h-4.9v14.111h4.332Zm42.133 7.262c-2.169-.575-4.126-1.407-5.864-2.503v-6.81c1.314 1.038 3.075 1.893 5.284 2.567 2.209.668 4.344 1.002 6.409 1.002.964 0 1.693-.128 2.186-.386.494-.258.741-.569.741-.926 0-.41-.132-.75-.402-1.026-.27-.275-.792-.504-1.566-.697l-4.82-1.108c-2.76-.656-4.717-1.565-5.881-2.73-1.165-1.161-1.745-2.685-1.745-4.572 0-1.588.505-2.965 1.527-4.143 1.015-1.178 2.461-2.087 4.337-2.725 1.877-.645 4.068-.967 6.587-.967 2.249 0 4.309.246 6.186.738 1.876.492 3.425 1.12 4.659 1.887v6.44c-1.263-.767-2.709-1.37-4.361-1.828a19.138 19.138 0 0 0-5.084-.674c-2.519 0-3.775.44-3.775 1.313 0 .41.195.715.585.92.39.205 1.107.416 2.146.639l4.016.738c2.623.463 4.579 1.278 5.864 2.438 1.286 1.16 1.928 2.878 1.928 5.152 0 2.49-1.061 4.465-3.19 5.93-2.129 1.465-5.147 2.198-9.06 2.198a26.36 26.36 0 0 1-6.707-.867Zm28.437-.862c-2.3-1.149-4.039-2.708-5.198-4.677-1.159-1.969-1.744-4.184-1.744-6.645 0-2.462.602-4.665 1.807-6.605 1.205-1.94 2.972-3.464 5.302-4.571 2.329-1.108 5.112-1.659 8.354-1.659 4.016 0 7.35.862 10.001 2.585v7.507c-.935-.656-2.026-1.19-3.271-1.6-1.245-.41-2.576-.615-3.999-.615-2.49 0-4.435.463-5.841 1.395-1.406.931-2.111 2.144-2.111 3.65 0 1.477.682 2.685 2.048 3.634 1.366.944 3.345 1.418 5.944 1.418 1.337 0 2.657-.2 3.959-.592 1.297-.398 2.416-.885 3.351-1.459v7.261c-2.943 1.805-6.357 2.707-10.242 2.707-3.27-.011-6.059-.586-8.36-1.734Zm28.54 0c-2.318-1.148-4.085-2.72-5.302-4.718-1.216-1.998-1.83-4.225-1.83-6.686 0-2.462.608-4.66 1.83-6.587 1.222-1.928 2.978-3.44 5.285-4.536 2.3-1.096 5.049-1.641 8.233-1.641 3.185 0 5.933.545 8.234 1.64 2.301 1.097 4.057 2.597 5.262 4.513 1.205 1.917 1.807 4.114 1.807 6.605 0 2.461-.602 4.688-1.807 6.687-1.205 1.998-2.967 3.569-5.285 4.717-2.318 1.149-5.055 1.723-8.216 1.723-3.162 0-5.899-.568-8.211-1.717Zm12.204-7.279c.976-.996 1.469-2.314 1.469-3.955s-.488-2.948-1.469-3.915c-.975-.973-2.307-1.46-3.993-1.46-1.716 0-3.059.487-4.04 1.46-.975.973-1.463 2.274-1.463 3.915 0 1.64.488 2.96 1.463 3.956.976.996 2.324 1.5 4.04 1.5 1.686-.006 3.018-.504 3.993-1.5ZM259.17 31.34v8.86c-1.021-.685-2.341-1.025-3.976-1.025-2.141 0-3.793.662-4.941 1.986-1.153 1.325-1.727 3.388-1.727 6.177v7.548h-9.84V30.888h9.64v7.63c.533-2.79 1.4-4.846 2.593-6.176 1.188-1.325 2.725-1.987 4.596-1.987 1.417 0 2.634.328 3.655.985Zm32.694-5.99v29.537h-9.841v-5.374c-.832 2.022-2.094 3.563-3.792 4.618-1.699 1.049-3.799 1.576-6.289 1.576-2.226 0-4.165-.55-5.824-1.658-1.658-1.108-2.937-2.626-3.838-4.554-.895-1.928-1.349-4.108-1.349-6.546-.028-2.514.448-4.77 1.429-6.769.976-1.998 2.358-3.557 4.137-4.676 1.779-1.12 3.81-1.682 6.088-1.682 4.688 0 7.832 2.08 9.438 6.235V25.35h9.841Zm-11.309 21.191c1.004-.996 1.503-2.29 1.503-3.873 0-1.53-.488-2.778-1.463-3.733-.976-.956-2.313-1.436-3.994-1.436-1.658 0-2.983.486-3.976 1.46-.993.972-1.486 2.232-1.486 3.79 0 1.56.493 2.831 1.486 3.816.993.984 2.301 1.477 3.936 1.477 1.658-.006 2.989-.504 3.994-1.5ZM139.382 33.443c2.709 0 4.906-2.015 4.906-4.5 0-2.486-2.197-4.501-4.906-4.501-2.71 0-4.906 2.015-4.906 4.5 0 2.486 2.196 4.501 4.906 4.501Zm-4.91 3.101c3.006 1.324 6.736 1.383 9.811 0v18.471h-9.811V36.544Z"/></g></g><defs><clipPath id="a"><path fill="#fff" d="M0 11.765h292v56.47H0z"/></clipPath><clipPath id="b"><path fill="#fff" d="M0 11.765h292v56.47H0z"/></clipPath></defs></svg>
|
After Width: | Height: | Size: 4.5 KiB |
BIN
static/2.0/ios.png
Normal file
After Width: | Height: | Size: 1.2 MiB |
1
static/2.0/opencollectivelogo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="457" height="60" viewBox="0 0 457 60"><g fill="none" fill-rule="evenodd"><path fill="#7FADF2" d="M34.62 18.179C36.75 21.249 38 24.979 38 29s-1.25 7.75-3.38 10.821L29.697 34.9a12.16 12.16 0 0 0 1.517-5.9c0-2.14-.55-4.15-1.516-5.9l4.921-4.921Zm-4.8-4.799-4.92 4.922a12.16 12.16 0 0 0-5.9-1.516c-6.746 0-12.214 5.468-12.214 12.214S12.254 41.214 19 41.214c2.14 0 4.15-.55 5.9-1.516l4.921 4.921A18.912 18.912 0 0 1 19 48C8.507 48 0 39.493 0 29s8.507-19 19-19c4.021 0 7.75 1.25 10.821 3.38Z"/><path fill="#B8D3F4" d="M34.62 18.179C36.75 21.249 38 24.979 38 29s-1.25 7.75-3.38 10.821L29.697 34.9a12.16 12.16 0 0 0 1.517-5.9c0-2.14-.55-4.15-1.516-5.9l4.921-4.921Z"/><path fill="#515F71" d="M110.7 13.6c-3.7 0-7.2 1.4-9.8 3.6v-2.3c0-.6-.5-1-1-1h-3.4c-.6 0-1 .5-1 1v43.7c0 .5.4 1 1 1h3.5c.5 0 1-.4 1-1V40.3c2.6 2.2 6.1 3.6 9.8 3.6 8.4 0 15.2-6.8 15.2-15.2-.2-8.4-7-15.1-15.3-15.1Zm0 24.8c-5.4 0-9.7-4.4-9.7-9.7 0-5.4 4.4-9.7 9.7-9.7 5.4 0 9.7 4.4 9.7 9.7 0 5.4-4.4 9.7-9.7 9.7Zm65.9-24.8c-3.7 0-7.1 1.3-9.7 3.5v-1.3c0-1.1-.9-2-2-2h-1.5c-1.1 0-2 .9-2 2v26.3c0 .8.7 1.5 1.5 1.5h2.5c.8 0 1.5-.7 1.5-1.5V29.6c0-5.4 4.4-10.6 9.7-10.6 3.5 0 9.7 1.9 9.7 10.6v12.5c0 .8.7 1.5 1.5 1.5h2.5c.8 0 1.5-.7 1.5-1.5V29.5c0-13.2-10.4-15.9-15.2-15.9Zm-18.4 11.9c-1.5-7.1-8-12.3-15.6-11.9-7.6.4-13.8 6.4-14.3 14-.6 8.9 6.4 16.3 15.1 16.3 5.9 0 11-3.3 13.5-8.2.4-.7-.1-1.6-.9-1.8l-3-.6c-.5-.1-1 .1-1.3.6-1.7 2.7-4.8 4.6-8.2 4.6-3 0-5.7-1.4-7.5-3.5l17.2-7.2 5-2.3Zm-24.4 4.4c0-.4-.1-.8-.1-1.2 0-5.4 4.4-9.7 9.7-9.7 3 0 5.8 1.4 7.5 3.6l-17.1 7.3ZM77.3 13.4c-8.4 0-15.2 6.8-15.2 15.2 0 8.4 6.8 15.2 15.2 15.2 8.4 0 15.2-6.8 15.2-15.2 0-8.4-6.8-15.2-15.2-15.2Zm0 24.9c-5.4 0-9.7-4.4-9.7-9.7 0-5.4 4.4-9.7 9.7-9.7 5.4 0 9.7 4.4 9.7 9.7.1 5.3-4.3 9.7-9.7 9.7Zm181.4-25c-8.4 0-15.2 6.8-15.2 15.2 0 8.4 6.8 15.2 15.2 15.2 8.4 0 15.2-6.8 15.2-15.2 0-8.4-6.8-15.2-15.2-15.2Zm0 24.9c-5.4 0-9.7-4.4-9.7-9.7 0-5.4 4.4-9.7 9.7-9.7 5.4 0 9.7 4.4 9.7 9.7 0 5.3-4.3 9.7-9.7 9.7ZM390.6 4.3h-3.1c-.7 0-1.2.5-1.2 1.2v3.1c0 .7.5 1.2 1.2 1.2h3.1c.7 0 1.2-.5 1.2-1.2V5.5c0-.7-.6-1.2-1.2-1.2Zm63.9 29.4-3.6-.7c-.4-.1-.8.1-1 .5-1.7 2.8-4.8 4.7-8.3 4.7-3 0-5.7-1.4-7.5-3.5l17.2-7.2 5.2-2.2c-1.5-7.1-8-12.3-15.6-11.9-7.6.4-13.8 6.5-14.3 14.1-.6 8.9 6.4 16.3 15.1 16.3 6 0 11.2-3.5 13.6-8.5.2-.8-.2-1.5-.8-1.6Zm-22.7-5.3c0-5.4 4.4-9.7 9.7-9.7 3 0 5.8 1.4 7.5 3.6l-17.2 7.3v-1.2ZM332 25.2c-1.5-7.1-8-12.3-15.6-11.9-7.6.4-13.8 6.5-14.3 14.1-.6 8.9 6.4 16.3 15.1 16.3 6 0 11.2-3.5 13.7-8.6.3-.6-.1-1.3-.7-1.4l-3.6-.7c-.4-.1-.8.1-1 .5-1.7 2.8-4.8 4.7-8.3 4.7-3 0-5.7-1.4-7.5-3.5l17.2-7.2 5-2.3Zm-24.5 4.4c0-.4-.1-.8-.1-1.2 0-5.4 4.4-9.7 9.7-9.7 3 0 5.8 1.4 7.5 3.6l-17.1 7.3ZM283.2.7h-3.6c-.5 0-.9.4-.9.9v40.7c0 .5.4 1 1 1h3.5c.5 0 1-.4 1-1V1.6c0-.5-.5-.9-1-.9Zm12.3 0h-3.6c-.5 0-.9.4-.9.9v40.7c0 .5.4 1 1 1h3.5c.5 0 1-.4 1-1V1.6c-.1-.5-.5-.9-1-.9Zm95.1 12.7h-3.1c-.7 0-1.2.5-1.2 1.2v27.6c0 .7.5 1.2 1.2 1.2h3.1c.7 0 1.2-.5 1.2-1.2V14.5c0-.6-.6-1.1-1.2-1.1Zm-10.2 0h-3.9c-.4 0-.8-.4-.8-.8V1.5c0-.4-.4-.8-.8-.8H371c-.4 0-.8.4-.8.8v11.1c0 .4-.4.8-.8.8h-3.9c-.4 0-.8.4-.8.8V18c0 .4.4.8.8.8h3.9c.4 0 .8.4.8.8v22.7c0 .6.5 1 1 1h3.4c.6 0 1-.5 1-1V19.6c0-.4.4-.8.8-.8h3.9c.4 0 .8-.4.8-.8v-3.9c.1-.4-.2-.7-.7-.7Zm-21.6 22.1c-.4-.4-1.1-.4-1.5 0-1.8 1.7-4.1 2.7-6.8 2.7-5.7 0-10.3-5-9.7-10.8.5-4.5 4.2-8.1 8.7-8.6 2.8-.3 5.5.7 7.4 2.4.6.5 1.5.5 2.1-.1l1.7-1.7c.6-.6.6-1.6 0-2.2-2.9-2.7-6.9-4.2-11.2-3.9-7.7.5-13.9 6.9-14.2 14.7-.3 8.6 6.6 15.6 15.2 15.6 4.1 0 7.9-1.6 10.6-4.3.4-.4.4-1.1 0-1.5l-2.3-2.3Zm-119.7 0c-.4-.4-1.1-.4-1.5 0-1.8 1.7-4.1 2.7-6.8 2.7-5.7 0-10.3-5-9.7-10.8.5-4.5 4.2-8.1 8.7-8.6 2.8-.3 5.5.7 7.4 2.4.6.5 1.5.5 2.1-.1l1.7-1.7c.6-.6.6-1.6 0-2.2-2.9-2.7-6.9-4.2-11.2-3.9-7.7.5-13.9 6.9-14.2 14.7-.3 8.6 6.6 15.6 15.2 15.6 4.1 0 7.9-1.6 10.6-4.3.4-.4.4-1.1 0-1.5l-2.3-2.3ZM424 13.7h-4.9c-.1 0-.2.1-.2.2l-8 23.5c-.1.2-.4.2-.4 0l-8-23.5c0-.1-.1-.2-.2-.2h-4.9c-.2 0-.3.2-.2.3l9.9 29.1c0 .1.1.2.2.2h6.8c.1 0 .2-.1.2-.2l9.9-29.1c.1-.1 0-.3-.2-.3Z"/></g></svg>
|
After Width: | Height: | Size: 3.9 KiB |
1
static/2.0/typelogo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.5" viewBox="0 0 1115 116"><path d="m81.582 577.266 66.954-98.462" style="fill:none;stroke:#fff;stroke-width:14.11px" transform="translate(-75.985 -483.202) scale(1.02332)"/><path d="m81.582 577.266 66.954-98.462" style="fill:none;stroke:#fff;stroke-width:14.86px" transform="matrix(1.01019 0 0 1.0102 852.95 -475.627)"/><text x="640.988" y="399.072" style="fill:#fff;font-family:"ArialMT","Arial",sans-serif;font-size:12px" transform="matrix(12.6568 0 0 12.68749 -7898.028 -4950.898)">ESHT</text><path d="m187.032 410.85 63.864-93.658 64.011 93.51" style="fill:none;stroke:#fff;stroke-width:13.85px" transform="translate(-120.199 -314.73) scale(1.02696)"/><path d="m187.032 410.85 63.864-93.658 64.011 93.51" style="fill:none;stroke:#fff;stroke-width:13.85px" transform="translate(417.633 -313.199) scale(1.02696)"/><text style="fill:#fff;font-family:"ArialMT","Arial",sans-serif;font-size:252.715px" transform="matrix(.601 0 0 .60246 750.004 112.652)">ST</text><text style="fill:#fff;font-family:"ArialMT","Arial",sans-serif;font-size:252.715px" transform="matrix(.601 0 0 .60246 1008.532 112.998)">C</text></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
static/2.0/vercel-logotype-dark.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4438" height="1000" fill="none" viewBox="0 0 4438 1000"><path fill="#000" d="M2223.75 250c-172.5 0-296.88 112.5-296.88 281.25s139.85 281.25 312.51 281.25c104.21 0 196.09-41.25 252.96-110.781l-119.53-69.063c-31.56 34.532-79.53 54.688-133.43 54.688-74.85 0-138.44-39.063-162.04-101.563h437.82c3.43-17.5 5.47-35.625 5.47-54.687C2520.63 362.5 2396.41 250 2223.75 250Zm-147.66 226.562C2095.62 414.219 2149.06 375 2223.75 375c74.84 0 128.28 39.219 147.66 101.562h-295.32Zm-35.31-398.437-432.97 750-433.12-750h162.34l270.63 468.75 270.62-468.75h162.5ZM577.344 0l577.346 1000H0L577.344 0ZM3148.75 531.25C3148.75 625 3210 687.5 3305 687.5c64.38 0 112.66-29.219 137.5-76.875l120 69.219C3512.81 762.656 3419.69 812.5 3305 812.5c-172.66 0-296.87-112.5-296.87-281.25S3132.5 250 3305 250c114.69 0 207.66 49.844 257.5 132.656l-120 69.219C3417.66 404.219 3369.38 375 3305 375c-94.84 0-156.25 62.5-156.25 156.25ZM4437.5 78.125v718.75h-140.62V78.125h140.62ZM3906.25 250c-172.5 0-296.87 112.5-296.87 281.25s140 281.25 312.5 281.25c104.21 0 196.09-41.25 252.96-110.781l-119.53-69.063c-31.56 34.532-79.53 54.688-133.43 54.688-74.85 0-138.44-39.063-162.04-101.563h437.82c3.43-17.5 5.46-35.625 5.46-54.687C4203.12 362.5 4078.91 250 3906.25 250Zm-147.66 226.562C3778.13 414.219 3831.41 375 3906.25 375s128.28 39.219 147.66 101.562h-295.32Zm-797.34-210.937v151.406c-15.62-4.531-32.19-7.656-50-7.656-90.78 0-156.25 62.5-156.25 156.25v231.25h-140.62v-531.25H2755v143.75c0-79.375 92.34-143.75 206.25-143.75Z"/></svg>
|
After Width: | Height: | Size: 1.5 KiB |
BIN
static/2.0/webUI.png
Normal file
After Width: | Height: | Size: 410 KiB |
BIN
static/img/amazon-fire-button.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
static/img/dead-banner.png
Normal file
After Width: | Height: | Size: 15 KiB |
1
static/img/efficiency.svg
Normal file
After Width: | Height: | Size: 10 KiB |
1
static/img/homepage/Discord-Logo-White.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="71" height="55" fill="none" viewBox="0 0 71 55"><g clip-path="url(#a)"><path fill="#fff" d="M60.105 4.898A58.55 58.55 0 0 0 45.653.415a.22.22 0 0 0-.233.11 40.784 40.784 0 0 0-1.8 3.697c-5.456-.817-10.886-.817-16.23 0-.485-1.164-1.201-2.587-1.828-3.697a.228.228 0 0 0-.233-.11 58.386 58.386 0 0 0-14.451 4.483.207.207 0 0 0-.095.082C1.578 18.73-.944 32.144.293 45.39a.244.244 0 0 0 .093.167c6.073 4.46 11.955 7.167 17.729 8.962a.23.23 0 0 0 .249-.082 42.08 42.08 0 0 0 3.627-5.9.225.225 0 0 0-.123-.312 38.772 38.772 0 0 1-5.539-2.64.228.228 0 0 1-.022-.378 31.17 31.17 0 0 0 1.1-.862.22.22 0 0 1 .23-.03c11.619 5.304 24.198 5.304 35.68 0a.219.219 0 0 1 .233.027c.356.293.728.586 1.103.865a.228.228 0 0 1-.02.378 36.384 36.384 0 0 1-5.54 2.637.227.227 0 0 0-.121.315 47.249 47.249 0 0 0 3.624 5.897.225.225 0 0 0 .249.084c5.801-1.794 11.684-4.502 17.757-8.961a.228.228 0 0 0 .092-.164c1.48-15.315-2.48-28.618-10.497-40.412a.18.18 0 0 0-.093-.084Zm-36.38 32.427c-3.497 0-6.38-3.211-6.38-7.156 0-3.944 2.827-7.156 6.38-7.156 3.583 0 6.438 3.24 6.382 7.156 0 3.945-2.827 7.156-6.381 7.156Zm23.593 0c-3.498 0-6.38-3.211-6.38-7.156 0-3.944 2.826-7.156 6.38-7.156 3.582 0 6.437 3.24 6.38 7.156 0 3.945-2.798 7.156-6.38 7.156Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h71v55H0z"/></clipPath></defs></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
static/img/homepage/Discourse-Logo-White.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -1 104 106"><path d="M51.87 0C23.71 0 0 22.83 0 51v52.81l51.86-.05c28.16 0 51-23.71 51-51.87S80 0 51.87 0Z" style="fill:#231f20"/><path d="M52.37 19.74a31.62 31.62 0 0 0-27.79 46.67l-5.72 18.4 20.54-4.64a31.61 31.61 0 1 0 13-60.43Z" style="fill:#fff9ae"/><path d="M77.45 32.12a31.6 31.6 0 0 1-38.05 48l-20.54 4.7 20.91-2.47a31.6 31.6 0 0 0 37.68-50.23Z" style="fill:#00aeef"/><path d="M71.63 26.29A31.6 31.6 0 0 1 38.8 78l-19.94 6.82 20.54-4.65a31.6 31.6 0 0 0 32.23-53.88Z" style="fill:#00a94f"/><path d="M26.47 67.11a31.61 31.61 0 0 1 51-35 31.61 31.61 0 0 0-52.89 34.3l-5.72 18.4Z" style="fill:#f15d22"/><path d="M24.58 66.41a31.61 31.61 0 0 1 47.05-40.12 31.61 31.61 0 0 0-49 39.63l-3.76 18.9Z" style="fill:#e31b23"/></svg>
|
After Width: | Height: | Size: 778 B |
1
static/img/homepage/GitHub-Logo-White.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" fill="none" viewBox="0 0 1024 1024"><path fill="#1B1F23" fill-rule="evenodd" d="M512 0C229.12 0 0 229.12 0 512c0 226.56 146.56 417.92 350.08 485.76 25.6 4.48 35.2-10.88 35.2-24.32 0-12.16-.64-52.48-.64-95.36-128.64 23.68-161.92-31.36-172.16-60.16-5.76-14.72-30.72-60.16-52.48-72.32-17.92-9.6-43.52-33.28-.64-33.92 40.32-.64 69.12 37.12 78.72 52.48 46.08 77.44 119.68 55.68 149.12 42.24 4.48-33.28 17.92-55.68 32.64-68.48-113.92-12.8-232.96-56.96-232.96-252.8 0-55.68 19.84-101.76 52.48-137.6-5.12-12.8-23.04-65.28 5.12-135.68 0 0 42.88-13.44 140.8 52.48 40.96-11.52 84.48-17.28 128-17.28 43.52 0 87.04 5.76 128 17.28 97.92-66.56 140.8-52.48 140.8-52.48 28.16 70.4 10.24 122.88 5.12 135.68 32.64 35.84 52.48 81.28 52.48 137.6 0 196.48-119.68 240-233.6 252.8 18.56 16 34.56 46.72 34.56 94.72 0 68.48-.64 123.52-.64 140.8 0 13.44 9.6 29.44 35.2 24.32C877.44 929.92 1024 737.92 1024 512 1024 229.12 794.88 0 512 0Z" clip-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 1006 B |
1
static/img/homepage/Instagram_Glyph_Gradient.svg
Normal file
After Width: | Height: | Size: 45 KiB |
1
static/img/homepage/Reddit-Logo-White.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="85.45 80.45 170.9 170.9"><path d="M227.9 170.9c0-6.9-5.6-12.5-12.5-12.5-3.4 0-6.4 1.3-8.6 3.5-8.5-6.1-20.3-10.1-33.3-10.6l5.7-26.7 18.5 3.9c.2 4.7 4.1 8.5 8.9 8.5 4.9 0 8.9-4 8.9-8.9s-4-8.9-8.9-8.9c-3.5 0-6.5 2-7.9 5l-20.7-4.4c-.6-.1-1.2 0-1.7.3s-.8.8-1 1.4l-6.3 29.8c-13.3.4-25.2 4.3-33.8 10.6-2.2-2.1-5.3-3.5-8.6-3.5-6.9 0-12.5 5.6-12.5 12.5 0 5.1 3 9.4 7.4 11.4-.2 1.2-.3 2.5-.3 3.8 0 19.2 22.3 34.7 49.9 34.7s49.9-15.5 49.9-34.7c0-1.3-.1-2.5-.3-3.7 4.1-2 7.2-6.4 7.2-11.5zm-85.5 8.9c0-4.9 4-8.9 8.9-8.9s8.9 4 8.9 8.9-4 8.9-8.9 8.9-8.9-4-8.9-8.9zm49.7 23.5c-6.1 6.1-17.7 6.5-21.1 6.5-3.4 0-15.1-.5-21.1-6.5-.9-.9-.9-2.4 0-3.3.9-.9 2.4-.9 3.3 0 3.8 3.8 12 5.2 17.9 5.2s14-1.4 17.9-5.2c.9-.9 2.4-.9 3.3 0 .7 1 .7 2.4-.2 3.3zm-1.6-14.6c-4.9 0-8.9-4-8.9-8.9s4-8.9 8.9-8.9 8.9 4 8.9 8.9-4 8.9-8.9 8.9z" style="fill:#fff"/></svg>
|
After Width: | Height: | Size: 875 B |
1
static/img/homepage/Twitter-Logo-White.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="enable-background:new 0 0 400 400" viewBox="0 0 400 400"><path d="M400 200c0 110.5-89.5 200-200 200S0 310.5 0 200 89.5 0 200 0s200 89.5 200 200zM163.4 305.5c88.7 0 137.2-73.5 137.2-137.2 0-2.1 0-4.2-.1-6.2 9.4-6.8 17.6-15.3 24.1-25-8.6 3.8-17.9 6.4-27.7 7.6 10-6 17.6-15.4 21.2-26.7-9.3 5.5-19.6 9.5-30.6 11.7-8.8-9.4-21.3-15.2-35.2-15.2-26.6 0-48.2 21.6-48.2 48.2 0 3.8.4 7.5 1.3 11-40.1-2-75.6-21.2-99.4-50.4-4.1 7.1-6.5 15.4-6.5 24.2 0 16.7 8.5 31.5 21.5 40.1-7.9-.2-15.3-2.4-21.8-6v.6c0 23.4 16.6 42.8 38.7 47.3-4 1.1-8.3 1.7-12.7 1.7-3.1 0-6.1-.3-9.1-.9 6.1 19.2 23.9 33.1 45 33.5-16.5 12.9-37.3 20.6-59.9 20.6-3.9 0-7.7-.2-11.5-.7 21.1 13.8 46.5 21.8 73.7 21.8" style="fill:#fff"/></svg>
|
After Width: | Height: | Size: 761 B |
1
static/img/homepage/YouTube-Logo-White.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="800" viewBox="-35.2 -41.333 305.067 248"><path fill="#fff" d="M93.333 117.559V47.775l61.334 34.893zm136.43-91.742c-2.699-10.162-10.651-18.165-20.747-20.881C190.716 0 117.333 0 117.333 0S43.951 0 25.651 4.936C15.555 7.652 7.603 15.655 4.904 25.817 0 44.236 0 82.667 0 82.667s0 38.429 4.904 56.849c2.699 10.163 10.65 18.165 20.747 20.883 18.3 4.934 91.682 4.934 91.682 4.934s73.383 0 91.683-4.934c10.096-2.718 18.048-10.72 20.747-20.883 4.904-18.42 4.904-56.85 4.904-56.85s0-38.43-4.904-56.849"/></svg>
|
After Width: | Height: | Size: 561 B |
1
static/img/homepage/battery.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" viewBox="150 150 650 650"><g stroke-width=".948"><path fill="#4d4d4d" d="M247.5 596.333H657V353.667H247.5zM277.833 384h348.834v182H277.833z"/><path fill="#67ea94" d="M298.394 405.745h307.722v138.52H298.394z"/><path fill="#4d4d4d" d="M672.167 424.448H702.5v101.114h-30.333z"/></g></svg>
|
After Width: | Height: | Size: 352 B |
1
static/img/homepage/encryption.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" viewBox="150 150 650 650"><path fill="#4d4d4d" d="M604.283 369.655h-72.28V284.62a102.042 102.042 0 1 0-204.083 0v85.035h-72.28a12.755 12.755 0 0 0-12.755 12.755v297.622a12.755 12.755 0 0 0 12.755 12.755h348.643a12.755 12.755 0 0 0 12.755-12.755V382.41a12.755 12.755 0 0 0-12.755-12.755zm-112.671 0h-123.3v-85.832a61.65 61.65 0 1 1 123.3 0z"/><path fill="#eab167" stroke="#4d4d4d" stroke-width="8.5" d="M540.019 526.745c0 10.204 0 20.094 3.218 29.356-33.831 39.718-131.477 152.67-131.477 152.67l2.276 28.494s27.316 25.903 31.398 21.978c12.088-11.774 19.466-19.78 19.466-19.78l5.683-34.027 36.978-2.724 2.967-36.735 38.957-.746.384-39.317 41.359 1.648 7.064-14.788c12.167 5.259 23.234 7.378 37.442 7.378 53.768 0 97.332-41.915 97.332-93.564 0-51.649-43.596-93.408-97.364-93.408s-95.683 41.916-95.683 93.565zm148.156-18.21a30.495 30.495 0 1 1-30.495-30.495 30.463 30.463 0 0 1 30.495 30.494z"/></svg>
|
After Width: | Height: | Size: 964 B |
1
static/img/homepage/extendable.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" viewBox="150 150 650 650"><path fill="#67ea94" stroke="#4d4d4d" stroke-linecap="round" stroke-linejoin="round" stroke-width="15" d="M626.18 465.506h-26.524a1.918 1.918 0 0 1-1.918-1.918v-74.065a37.263 37.263 0 0 0-37.262-37.263H486.41a1.918 1.918 0 0 1-1.918-1.917V323.82c0-26.025-20.616-47.81-46.64-48.262a47.494 47.494 0 0 0-48.329 47.475v27.31a1.918 1.918 0 0 1-1.918 1.917H313.54a38.106 38.106 0 0 0-37.991 37.992v67.487a1.918 1.918 0 0 0 1.918 1.918h25.804c28.162 0 51.473 24.432 51.866 52.595.403 28.642-22.543 54.8-51.1 54.8h-26.57a1.918 1.918 0 0 0-1.918 1.919v67.487a38.106 38.106 0 0 0 37.991 37.99h67.487a1.918 1.918 0 0 0 1.918-1.917v-20.07c0-29.035 23.733-54.033 52.74-54.714 28.862-.671 54.656 19.475 54.656 48.213v26.571a1.918 1.918 0 0 0 1.918 1.918h68.216a37.263 37.263 0 0 0 37.262-37.263v-74.793a1.918 1.918 0 0 1 1.918-1.918h27.31c26.494 0 47.484-21.738 47.484-48.329s-22.246-46.64-48.27-46.64z"/></svg>
|
After Width: | Height: | Size: 990 B |
BIN
static/img/homepage/f_logo_RGB-White_1024.png
Normal file
After Width: | Height: | Size: 47 KiB |
1
static/img/homepage/messages.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" viewBox="150 150 650 650"><path fill="#eab167" stroke="#4d4d4d" stroke-linejoin="round" stroke-width="29.792" d="M585.204 337.464v148.4A52.285 52.285 0 0 1 533.068 538H379.313a7.448 7.448 0 0 0-4.777 1.73l-9.228 7.694v20.928a52.285 52.285 0 0 0 52.136 52.136h153.755a7.448 7.448 0 0 1 4.775 1.73l87.254 72.75v-74.48h37.24a52.285 52.285 0 0 0 52.136-52.136V389.6a52.285 52.285 0 0 0-52.136-52.136z"/><path fill="none" stroke="#4d4d4d" stroke-linejoin="round" stroke-width="29.792" d="M532.556 255.034H249.532a52.285 52.285 0 0 0-52.136 52.136v178.752a52.285 52.285 0 0 0 52.136 52.136h37.24v74.48l87.253-72.748a7.448 7.448 0 0 1 4.776-1.732h153.755a52.285 52.285 0 0 0 52.136-52.136V307.17a52.285 52.285 0 0 0-52.136-52.136z"/><g fill="#4d4d4d"><circle cx="301.668" cy="396.546" r="29.792" fill="#eab167"/><circle cx="391.044" cy="396.546" r="29.792" fill="#eab167"/><circle cx="480.42" cy="396.546" r="29.792" fill="#eab167"/></g></svg>
|
After Width: | Height: | Size: 1003 B |
1
static/img/homepage/opensource.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" viewBox="150 150 650 650" transform="matrix(1, 0, 0, 1, 0, 0)"><g stroke-width=".65" transform="matrix(-2403.8462 0 0 0 -624628.82 150)"><circle cx="-259.908" cy="348.214" r="72.8" fill="#eab167"/><path d="M-259.908 441.814c-45.123 0-135.2 27.872-135.2 83.2v41.6h270.4v-41.6c0-55.328-90.077-83.2-135.2-83.2z" fill="#eab167"/></g><g fill="#67ea94" transform="translate(-72.894 73.325)"><circle cx="809.715" cy="368.657" r="23.734" fill="#eab167"/><circle cx="682.328" cy="210.171" r="23.734" fill="#eab167"/><circle cx="682.328" cy="369.754" r="23.734" fill="#eab167"/></g><g fill="#4d4d4d" stroke-width=".65" transform="translate(174.183 59.196) scale(1.42001)"><circle cx="94.257" cy="296.297" r="46.8" fill="#eab167"/><path d="M147.557 369.097c-18.304-9.295-38.506-13-53.3-13-28.977 0-88.4 17.771-88.4 53.3v27.3h97.5v-10.445c0-12.35 5.2-24.733 14.3-35.055 7.26-8.242 17.426-15.892 29.9-22.1z" fill="#eab167"/><path d="M216.457 363.897c-33.846 0-101.4 20.904-101.4 62.4v31.2h202.8v-31.2c0-41.496-67.555-62.4-101.4-62.4z" fill="#eab167"/><circle cx="216.457" cy="285.897" r="57.2" fill="#eab167"/></g><path fill="#4d4d4d" d="M641.245 283.601a31.564 31.564 0 1 0-47.839 27.032v103.47a31.564 31.564 0 1 0 31.564 0V311.22a31.593 31.593 0 0 0 16.275-27.619zm-31.564-15.781A15.782 15.782 0 1 1 593.9 283.6a15.782 15.782 0 0 1 15.782-15.781zm-.493 189.382a15.782 15.782 0 1 1 15.782-15.782 15.782 15.782 0 0 1-15.782 15.782zm142.53-43.099v-100.91a45.422 45.422 0 0 0-45.373-45.373h-17.261v-26.667l-43.331 42.448 43.33 42.449v-26.667h17.262a13.81 13.81 0 0 1 13.81 13.81v100.91a31.564 31.564 0 1 0 31.563 0zm-15.782 43.1a15.782 15.782 0 1 1 15.782-15.783 15.782 15.782 0 0 1-15.782 15.782z"/></svg>
|
After Width: | Height: | Size: 1.7 KiB |
1
static/img/homepage/platforms.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" viewBox="150 150 650 650"><g fill="#eab167"><path stroke="#eab167" stroke-opacity=".894" stroke-width="2.126" d="M655.366 295.917h102.8v193.768h-102.8z" fill="#eab167000"/><rect width="376.029" height="274.791" x="225.888" y="362.06" stroke="#4d4d4d" stroke-linejoin="round" stroke-width="28.925" rx="29.052" fill="#eab167000"/><path stroke="#4d4d4d" stroke-linecap="round" stroke-miterlimit="10" stroke-width="28.925" d="M196.963 651.313h433.88" fill="#eab167000"/></g><path fill="#4d4d4d" stroke="#eab167" stroke-width=".417" d="M759.782 284.433H654.649a7.51 7.51 0 0 0-7.509 7.51v198.583a7.51 7.51 0 0 0 7.51 7.51h105.132a7.51 7.51 0 0 0 7.51-7.51V291.942a7.51 7.51 0 0 0-7.51-7.509zm-97.623 186.902V311.133h90.113v160.202z"/><path fill="#eab167" fill-rule="evenodd" d="m712.75 387.104-8.818 12.933-2.577-1.758 10.105-14.818a1.56 1.56 0 0 1 2.575-.003l10.128 14.796-2.573 1.762zm-19.815 12.949 10.788-15.82-2.667-1.818-10.788 15.82zM443.42 477.429l-47.027 68.965-13.741-9.37 53.884-79.021a8.315 8.315 0 0 1 13.732-.013l54.008 78.897-13.724 9.395zm-105.67 69.054 57.526-84.359-14.22-9.697-57.527 84.359z" clip-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
BIN
static/img/insufficient-space.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
1
static/img/logo-outline.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8,15A2,2 0 0,1 6,13A2,2 0 0,1 8,11A2,2 0 0,1 10,13A2,2 0 0,1 8,15M10.5,17L12,14L13.5,17H10.5M16,15A2,2 0 0,1 14,13A2,2 0 0,1 16,11A2,2 0 0,1 18,13A2,2 0 0,1 16,15M22,11A10,10 0 0,0 12,1A10,10 0 0,0 2,11C2,13.8 3.2,16.3 5,18.1V22H19V18.1C20.8,16.3 22,13.8 22,11M17,20H15V18H13V20H11V18H9V20H7V17.2C5.2,15.7 4,13.5 4,11A8,8 0 0,1 12,3A8,8 0 0,1 20,11C20,13.5 18.8,15.8 17,17.2V20Z" /></svg>
|
After Width: | Height: | Size: 458 B |
1
static/img/logo-scan-outline.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M2 0C.9 0 0 .9 0 2V6H2V2H6V0H2M18 0V2H22V6H24V2C24 .9 23.1 0 22 0H18M9.5 13C8.7 13 8 12.3 8 11.5S8.7 10 9.5 10 11 10.7 11 11.5 10.3 13 9.5 13M11 15L12 13L13 15H11M14.5 13C13.7 13 13 12.3 13 11.5S13.7 10 14.5 10 16 10.7 16 11.5 15.3 13 14.5 13M0 18V22C0 23.1 .9 24 2 24H6V22H2V18H0M22 18V22H18V24H22C23.1 24 24 23.1 24 22V18H22M12 3C7.6 3 4 6.6 4 11C4 13 4.8 14.9 6 16.3V21H18V16.3C19.2 14.9 20 13.1 20 11C20 6.6 16.4 3 12 3M16 15.4V19H14V17H13V19H11V17H10V19H8V15.4C6.8 14.3 6 12.7 6 11C6 7.7 8.7 5 12 5S18 7.7 18 11C18 12.8 17.2 14.3 16 15.4Z" /></svg>
|
After Width: | Height: | Size: 622 B |
1
static/img/logo-scan.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M2 0C.9 0 0 .9 0 2V6H2V2H6V0H2M18 0V2H22V6H24V2C24 .9 23.1 0 22 0H18M12 3C7.6 3 4 6.6 4 11C4 13.5 5.2 15.8 7 17.2V21H9V18H11V21H13V18H15V21H17V17.2C18.8 15.7 20 13.5 20 11C20 6.6 16.4 3 12 3M8 14C6.9 14 6 13.1 6 12S6.9 10 8 10 10 10.9 10 12 9.1 14 8 14M10.5 16L12 13L13.5 16H10.5M16 14C14.9 14 14 13.1 14 12S14.9 10 16 10 18 10.9 18 12 17.1 14 16 14M0 18V22C0 23.1 .9 24 2 24H6V22H2V18H0M22 18V22H18V24H22C23.1 24 24 23.1 24 22V18H22Z" /></svg>
|
After Width: | Height: | Size: 513 B |
1
static/img/logo-white.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,2A9,9 0 0,0 3,11C3,14.03 4.53,16.82 7,18.47V22H9V19H11V22H13V19H15V22H17V18.46C19.47,16.81 21,14 21,11A9,9 0 0,0 12,2M8,11A2,2 0 0,1 10,13A2,2 0 0,1 8,15A2,2 0 0,1 6,13A2,2 0 0,1 8,11M16,11A2,2 0 0,1 18,13A2,2 0 0,1 16,15A2,2 0 0,1 14,13A2,2 0 0,1 16,11M12,14L13.5,17H10.5L12,14Z" fill="#ffffff"/></svg>
|
After Width: | Height: | Size: 376 B |
1
static/img/logo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,2A9,9 0 0,0 3,11C3,14.03 4.53,16.82 7,18.47V22H9V19H11V22H13V19H15V22H17V18.46C19.47,16.81 21,14 21,11A9,9 0 0,0 12,2M8,11A2,2 0 0,1 10,13A2,2 0 0,1 8,15A2,2 0 0,1 6,13A2,2 0 0,1 8,11M16,11A2,2 0 0,1 18,13A2,2 0 0,1 16,15A2,2 0 0,1 14,13A2,2 0 0,1 16,11M12,14L13.5,17H10.5L12,14Z" /></svg>
|
After Width: | Height: | Size: 362 B |
1
static/img/readme/comment-alt.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><style>@media (prefers-color-scheme:dark){path{fill:#fff}}</style><path d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 7.1 5.8 12 12 12 2.4 0 4.9-.7 7.1-2.4L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64zm16 352c0 8.8-7.2 16-16 16H288l-12.8 9.6L208 428v-60H64c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16h384c8.8 0 16 7.2 16 16v288z"/></svg>
|
After Width: | Height: | Size: 428 B |
1
static/img/readme/discord.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="71" height="55" fill="#fff" viewBox="0 0 71 55"><g clip-path="url(#a)"><path d="M60.105 4.898A58.55 58.55 0 0 0 45.653.415a.22.22 0 0 0-.233.11 40.784 40.784 0 0 0-1.8 3.697c-5.456-.817-10.886-.817-16.23 0-.485-1.164-1.201-2.587-1.828-3.697a.228.228 0 0 0-.233-.11 58.386 58.386 0 0 0-14.451 4.483.207.207 0 0 0-.095.082C1.578 18.73-.944 32.144.293 45.39a.244.244 0 0 0 .093.167c6.073 4.46 11.955 7.167 17.729 8.962a.23.23 0 0 0 .249-.082 42.08 42.08 0 0 0 3.627-5.9.225.225 0 0 0-.123-.312 38.772 38.772 0 0 1-5.539-2.64.228.228 0 0 1-.022-.378 31.17 31.17 0 0 0 1.1-.862.22.22 0 0 1 .23-.03c11.619 5.304 24.198 5.304 35.68 0a.219.219 0 0 1 .233.027c.356.293.728.586 1.103.865a.228.228 0 0 1-.02.378 36.384 36.384 0 0 1-5.54 2.637.227.227 0 0 0-.121.315 47.249 47.249 0 0 0 3.624 5.897.225.225 0 0 0 .249.084c5.801-1.794 11.684-4.502 17.757-8.961a.228.228 0 0 0 .092-.164c1.48-15.315-2.48-28.618-10.497-40.412a.18.18 0 0 0-.093-.084Zm-36.38 32.427c-3.497 0-6.38-3.211-6.38-7.156 0-3.944 2.827-7.156 6.38-7.156 3.583 0 6.438 3.24 6.382 7.156 0 3.945-2.827 7.156-6.381 7.156Zm23.593 0c-3.498 0-6.38-3.211-6.38-7.156 0-3.944 2.826-7.156 6.38-7.156 3.582 0 6.437 3.24 6.38 7.156 0 3.945-2.798 7.156-6.38 7.156Z"/></g><defs><clipPath id="a"><path d="M0 0h71v55H0z"/></clipPath></defs></svg>
|
After Width: | Height: | Size: 1.3 KiB |