23
.dockerignore
Normal file
@ -0,0 +1,23 @@
|
||||
target/
|
||||
wit/
|
||||
**/target/
|
||||
**/wit/
|
||||
**/*.wasm
|
||||
.vscode
|
||||
.app-signing
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
*.zip
|
||||
/home
|
||||
packages/**/pkg/*.wasm
|
||||
packages/**/wit
|
||||
*/**/node_modules
|
||||
.env
|
||||
kinode/src/bootstrapped_processes.rs
|
||||
kinode/packages/**/wasi_snapshot_preview1.wasm
|
||||
|
||||
LICENSE
|
||||
pull_request_template.md
|
||||
README.md
|
||||
Dockerfile
|
32
Dockerfile
Normal file
@ -0,0 +1,32 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM rust AS builder
|
||||
|
||||
COPY . /tmp/source
|
||||
|
||||
WORKDIR /tmp/source
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install clang -y
|
||||
|
||||
RUN cargo install wasm-tools && \
|
||||
rustup install nightly && \
|
||||
rustup target add wasm32-wasi && \
|
||||
rustup target add wasm32-wasi --toolchain nightly && \
|
||||
cargo install cargo-wasi
|
||||
|
||||
RUN cargo +nightly build -p kinode --release
|
||||
|
||||
FROM debian:12-slim
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install openssl -y
|
||||
|
||||
COPY --from=builder /tmp/source/target/release/kinode /bin/kinode
|
||||
|
||||
ENV LD_LIBRARY_PATH=/lib
|
||||
ENV RUST_BACKTRACE=full
|
||||
ENTRYPOINT [ "/bin/kinode" ]
|
||||
CMD [ "/kinode-home" ]
|
||||
|
||||
EXPOSE 8080
|
||||
EXPOSE 9000
|
22
README.md
@ -134,3 +134,25 @@ Download and install an app:
|
||||
m our@main:app_store:sys '{"Download": {"package": {"package_name": "<pkg>", "publisher_node": "<node>"}, "install_from": "<node>"}}'
|
||||
m our@main:app_store:sys '{"Install": {"package_name": "<pkg>", "publisher_node": "<node>"}}'
|
||||
```
|
||||
|
||||
## Running as a Docker container
|
||||
|
||||
This image expects a volume mounted at `/kinode-home`. This volume may be empty or may contain another Kinode's data. It will be used as the home directory of your Kinode.
|
||||
|
||||
The image includes EXPOSE directives for TCP port `8080` and TCP port `9000`. Port `8080` is used for serving the Kinode web dashboard over HTTP, and it may be mapped to a different port on the host. Port `9000` is optional and is only required for a direct node.
|
||||
|
||||
If you are running a direct node, you must map port `9000` to the same port on the host and on your router. Otherwise, your Kinode will not be able to connect to the rest of the network as connection info is written to the chain, and this information is based on the view from inside the Docker container.
|
||||
|
||||
To build a local Docker image, run the following command in this project root.
|
||||
```
|
||||
docker build -t 0xlynett/kinode .
|
||||
```
|
||||
|
||||
For example:
|
||||
```
|
||||
docker volume create kinode-volume
|
||||
|
||||
docker run -d -p 8080:8080 -it --name my-kinode \
|
||||
--mount type=volume,source=kinode-volume,destination=/kinode-home \
|
||||
0xlynett/kinode
|
||||
```
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
kinode/packages/app_store/pkg/ui/assets/fonts/Futura-Heavy.ttf
Normal file
94
kinode/packages/app_store/pkg/ui/assets/index-przgvy-e.js
Normal file
4
kinode/packages/app_store/pkg/ui/assets/kinode.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="779" height="514" viewBox="0 0 779 514" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M753.092 5.91932C756.557 5.09976 755.962 -0.00012207 752.401 -0.00012207H426.001C424.755 -0.00012207 423.639 0.77027 423.197 1.93535L236.968 492.6C235.729 495.865 240.123 498.255 242.191 495.441L569.357 50.1132C569.778 49.5392 570.391 49.1339 571.084 48.97L753.092 5.91932Z" fill="#FFF5D9"/>
|
||||
<path d="M11.9665 40.2288C9.10949 38.777 10.2135 34.4583 13.4167 34.5557L404.273 46.4367C406.334 46.4993 407.719 48.5749 406.986 50.5023L347.438 206.981C346.804 208.647 344.865 209.396 343.275 208.588L11.9665 40.2288Z" fill="#FFF5D9"/>
|
||||
</svg>
|
After Width: | Height: | Size: 644 B |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
Before Width: | Height: | Size: 1.5 KiB |
@ -15,8 +15,8 @@
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
|
||||
<link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet'>
|
||||
<script type="module" crossorigin src="/main:app_store:sys/assets/index-YeOEFbyC.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/main:app_store:sys/assets/index-JESB3UJK.css">
|
||||
<script type="module" crossorigin src="/main:app_store:sys/assets/index-przgvy-e.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/main:app_store:sys/assets/index-avBSgupm.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
1
kinode/packages/app_store/ui/buidl.sh
Executable file
@ -0,0 +1 @@
|
||||
npm run build:copy && cd ~/kinode && cargo +nightly build -p kinode && cd kinode/packages/app_store/ui
|
1148
kinode/packages/app_store/ui/package-lock.json
generated
@ -16,6 +16,7 @@
|
||||
"dependencies": {
|
||||
"@ethersproject/hash": "^5.7.0",
|
||||
"@kinode/client-api": "^0.1.0",
|
||||
"@metamask/jazzicon": "^2.0.0",
|
||||
"@szhsin/react-menu": "^4.1.0",
|
||||
"@web3-react/coinbase-wallet": "^8.2.3",
|
||||
"@web3-react/core": "^8.2.2",
|
||||
@ -27,12 +28,14 @@
|
||||
"@web3-react/walletconnect": "^8.2.3",
|
||||
"@web3-react/walletconnect-connector": "^6.2.13",
|
||||
"@web3-react/walletconnect-v2": "^8.5.1",
|
||||
"classnames": "^2.5.1",
|
||||
"ethers": "^5.7.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-router-dom": "^6.21.3",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"unocss": "^0.59.0-beta.1",
|
||||
"zustand": "^4.4.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
4
kinode/packages/app_store/ui/public/assets/kinode.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="779" height="514" viewBox="0 0 779 514" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M753.092 5.91932C756.557 5.09976 755.962 -0.00012207 752.401 -0.00012207H426.001C424.755 -0.00012207 423.639 0.77027 423.197 1.93535L236.968 492.6C235.729 495.865 240.123 498.255 242.191 495.441L569.357 50.1132C569.778 49.5392 570.391 49.1339 571.084 48.97L753.092 5.91932Z" fill="#FFF5D9"/>
|
||||
<path d="M11.9665 40.2288C9.10949 38.777 10.2135 34.4583 13.4167 34.5557L404.273 46.4367C406.334 46.4993 407.719 48.5749 406.986 50.5023L347.438 206.981C346.804 208.647 344.865 209.396 343.275 208.588L11.9665 40.2288Z" fill="#FFF5D9"/>
|
||||
</svg>
|
After Width: | Height: | Size: 644 B |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
Before Width: | Height: | Size: 1.5 KiB |
@ -1,381 +0,0 @@
|
||||
#root {
|
||||
max-width: 700px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem 0;
|
||||
text-align: center;
|
||||
width: 75%;
|
||||
max-height: calc(100vh - 64px);
|
||||
min-height: calc(100vh - 64px);
|
||||
}
|
||||
|
||||
/* General */
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.row.center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.row.between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.row.around {
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.col.center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: var(--input-background);
|
||||
border-radius: 0.75em;
|
||||
border: 1px solid var(--orange-medium);
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
button.action-btn {
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
button.small {
|
||||
padding: 0.25em 0.5em;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Specific */
|
||||
|
||||
.searchbar {
|
||||
height: 2.25em;
|
||||
padding: .5em 1em;
|
||||
border-radius: 16px;
|
||||
flex: 1;
|
||||
background-color: var(--input-background);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.searchbar>input {
|
||||
border: none;
|
||||
height: 1.5em;
|
||||
margin-left: 0.5em;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
button.connect-wallet {
|
||||
margin: 1em auto 0;
|
||||
}
|
||||
|
||||
.my-pkg-btn {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.my-pkg-btn.selected {
|
||||
background-color: var(--bg-gray-medium);
|
||||
}
|
||||
|
||||
.app-header {
|
||||
cursor: pointer;
|
||||
width: calc(100% - 10.3em);
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.app-header:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.app-header.large:hover {
|
||||
text-decoration: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.app-header.small>img {
|
||||
height: 3em;
|
||||
margin-right: 1em;
|
||||
border-radius: 0.375em;
|
||||
}
|
||||
|
||||
.app-header>img {
|
||||
height: 3em;
|
||||
margin-right: 1em;
|
||||
border-radius: 0.375em;
|
||||
}
|
||||
|
||||
.app-header.large>img {
|
||||
height: 5em;
|
||||
margin-right: 1em;
|
||||
border-radius: 0.5em;
|
||||
}
|
||||
|
||||
.app-header.large .app-name {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.app-entry {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.app-actions {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown>ul {
|
||||
background-color: var(--orange-medium);
|
||||
padding: 0.5em 1em;
|
||||
border-radius: 0.5em;
|
||||
align-items: flex-start;
|
||||
text-align: left;
|
||||
border: 1px solid var(--orange-medium);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.dropdown .dropdown-header {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.dropdown .dropdown-list {
|
||||
position: absolute;
|
||||
top: 1em;
|
||||
right: -0.5em;
|
||||
}
|
||||
|
||||
.page-selector {
|
||||
margin: 0.25em 0.5em;
|
||||
}
|
||||
|
||||
.page-selector.selected {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
margin-right: 1em;
|
||||
justify-content: center;
|
||||
width: 2.5em;
|
||||
}
|
||||
|
||||
.app-details {
|
||||
margin-top: 0.5em;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.app-details .title {
|
||||
width: 8em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.app-details .value {
|
||||
margin-bottom: 0.5em;
|
||||
text-align: left;
|
||||
max-width: calc(100% - 8em);
|
||||
}
|
||||
|
||||
.app-details .value.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.app-details .value.permission {
|
||||
background-color: var(--bg-gray-medium);
|
||||
border-radius: 2em;
|
||||
padding: 0.25em 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.app-screenshots {
|
||||
margin-top: 0.5em;
|
||||
overflow-x: scroll;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.app-screenshots>img {
|
||||
margin-right: 1em;
|
||||
max-height: 10em;
|
||||
max-width: 100%;
|
||||
border-radius: 0.5em;
|
||||
border: 1px solid var(--bg-gray-medium);
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
cursor: pointer;
|
||||
color: var(--bg-gray-solid);
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.f-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#loading h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#loader {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
#loader div {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin: 6px;
|
||||
border: 6px solid #fff;
|
||||
border-radius: 50%;
|
||||
animation: loader 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
|
||||
border-color: #fff transparent transparent transparent;
|
||||
}
|
||||
|
||||
#loader div:nth-child(1) {
|
||||
animation-delay: -0.45s;
|
||||
}
|
||||
|
||||
#loader div:nth-child(2) {
|
||||
animation-delay: -0.3s;
|
||||
}
|
||||
|
||||
#loader div:nth-child(3) {
|
||||
animation-delay: -0.15s;
|
||||
}
|
||||
|
||||
@keyframes loader {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.action-entry {
|
||||
margin-bottom: 0.25em;
|
||||
color: inherit;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
.action-entry:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.action-entry:first-child {
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
.my-apps-list {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
max-height: calc(100vh - 10em);
|
||||
border-radius: 0.5em;
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.title {
|
||||
width: calc(100% - 6em);
|
||||
}
|
||||
|
||||
.title>div {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 3;
|
||||
min-height: 10em;
|
||||
min-width: 20em;
|
||||
}
|
||||
|
||||
.modal-backdrop .close {
|
||||
position: absolute;
|
||||
top: 0.5em;
|
||||
right: 0.5em;
|
||||
font-size: 18px;
|
||||
font-weight: 200;
|
||||
cursor: pointer;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.modal {
|
||||
position: relative;
|
||||
background-color: var(--dark-background);
|
||||
color: black;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
line-height: 24px;
|
||||
max-width: 500px;
|
||||
min-width: 300px;
|
||||
color: var(--text-light);
|
||||
}
|
||||
|
||||
.modal .modal-title {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.modal .modal-content {
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
form.new {
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
form.metadata {
|
||||
gap: 0.5em;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
form.metadata input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
form.metadata .row {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
form.metadata .col.label {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
align-items: center;
|
||||
margin: 1em 0;
|
||||
}
|
@ -12,7 +12,6 @@ import { MY_APPS_PATH } from "./constants/path";
|
||||
import { ChainId, PACKAGE_STORE_ADDRESSES } from "./constants/chain";
|
||||
import PublishPage from "./pages/PublishPage";
|
||||
import { hooks as metaMaskHooks, metaMask } from './utils/metamask'
|
||||
import "./App.css";
|
||||
|
||||
const connectors: [MetaMask, Web3ReactHooks][] = [
|
||||
[metaMask, metaMaskHooks],
|
||||
@ -43,9 +42,8 @@ const RPC_URL = import.meta.env.VITE_SEPOLIA_RPC_URL;
|
||||
const BASE_URL = import.meta.env.BASE_URL;
|
||||
if (window.our) window.our.process = BASE_URL?.replace("/", "");
|
||||
|
||||
const PROXY_TARGET = `${
|
||||
import.meta.env.VITE_NODE_URL || "http://localhost:8080"
|
||||
}${BASE_URL}`;
|
||||
const PROXY_TARGET = `${import.meta.env.VITE_NODE_URL || "http://localhost:8080"
|
||||
}${BASE_URL}`;
|
||||
|
||||
// This env also has BASE_URL which should match the process + package name
|
||||
const WEBSOCKET_URL = import.meta.env.DEV // eslint-disable-line
|
||||
@ -96,7 +94,7 @@ function App() {
|
||||
|
||||
if (!nodeConnected) {
|
||||
return (
|
||||
<div className="node-not-connected">
|
||||
<div className="flex flex-col c">
|
||||
<h2 style={{ color: "red" }}>Node not connected</h2>
|
||||
<h4>
|
||||
You need to start a node at {PROXY_TARGET} before you can use this UI
|
||||
@ -109,16 +107,18 @@ function App() {
|
||||
const props = { provider, packageAbi };
|
||||
|
||||
return (
|
||||
<Web3ReactProvider connectors={connectors}>
|
||||
<Router basename={BASE_URL}>
|
||||
<Routes>
|
||||
<Route path="/" element={<StorePage {...props} />} />
|
||||
<Route path={MY_APPS_PATH} element={<MyAppsPage {...props} />} />
|
||||
<Route path="/app-details/:id" element={<AppPage {...props} />} />
|
||||
<Route path="/publish" element={<PublishPage {...props} />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
</Web3ReactProvider>
|
||||
<div className="flex flex-col c h-screen w-screen">
|
||||
<Web3ReactProvider connectors={connectors}>
|
||||
<Router basename={BASE_URL}>
|
||||
<Routes>
|
||||
<Route path="/" element={<StorePage {...props} />} />
|
||||
<Route path={MY_APPS_PATH} element={<MyAppsPage {...props} />} />
|
||||
<Route path="/app-details/:id" element={<AppPage {...props} />} />
|
||||
<Route path="/publish" element={<PublishPage {...props} />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
</Web3ReactProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
<svg width="580" height="72" viewBox="0 0 580 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_6_641)">
|
||||
<path d="M0.824922 1.07031L0.794922 70.0703H14.7949L14.8049 1.07031H0.824922Z" fill="#FFF5D9"/>
|
||||
<path d="M16.5947 36.8803L41.2547 1.07031H58.2447L33.1647 36.8803L61.2447 70.0703H42.9947L16.5947 36.8803Z" fill="#FFF5D9"/>
|
||||
<path d="M119.885 1.07031H105.765V70.0703H119.885V1.07031Z" fill="#FFF5D9"/>
|
||||
<path d="M173.185 1.07031V70.0703H186.775V26.8303L224.045 70.0703H234.825V1.07031H221.325V45.6803L183.445 1.07031H173.185Z" fill="#FFF5D9"/>
|
||||
<path d="M342.465 8.86C333.025 0.15 321.645 0 318.535 0C315.475 0 303.575 0.22 294.005 9.52C283.845 19.4 283.805 32.24 283.795 35.66C283.785 39.3 283.895 49.03 290.805 57.99C300.855 71.02 316.695 71.31 318.535 71.32C321.375 71.32 334.185 71 343.965 60.66C353.065 51.04 353.265 39.4 353.275 35.66C353.275 32.49 353.305 18.86 342.455 8.86H342.465ZM318.435 58.01C307.095 58.01 297.895 47.95 297.895 35.54C297.895 23.13 307.085 13.07 318.435 13.07C329.785 13.07 338.975 23.13 338.975 35.54C338.975 47.95 329.785 58.01 318.435 58.01Z" fill="#FFF5D9"/>
|
||||
<path d="M450.495 12.0802C444.975 5.46023 437.135 0.990234 427.955 0.990234C417.555 0.990234 405.295 1.07023 402.295 1.07023V69.9802C405.285 69.9802 417.555 70.0602 427.955 70.0602C445.525 70.0602 458.445 53.4102 459.065 36.8602C459.395 28.0102 456.185 18.9002 450.495 12.0802ZM440.085 49.9502C436.895 53.8702 432.705 56.6902 427.665 57.5602C424.025 58.1902 420.095 57.8302 416.405 57.8302C416.405 50.4002 416.405 42.9802 416.405 35.5502V13.2202C423.795 13.2202 430.525 12.7002 436.605 17.6002C440.275 20.5602 442.925 24.7102 444.165 29.2402C444.525 30.5402 444.765 31.8802 444.875 33.2302C445.395 39.3702 443.995 45.1402 440.085 49.9502Z" fill="#FFF5D9"/>
|
||||
<path d="M508.135 0.990234V70.0602H552.715V57.9302H522.035V40.4202H547.125V28.0702H521.995V13.3202H552.715V0.990234H508.135Z" fill="#FFF5D9"/>
|
||||
<path d="M574.835 66.0398H572.745L571.015 63.0698H569.845V66.0398H567.805V57.5498H571.765C572.845 57.5498 573.865 57.9298 574.425 58.9398C575.205 60.3698 574.665 62.3798 573.105 63.0298C573.725 64.1198 574.225 64.9498 574.845 66.0398H574.835ZM570.375 61.0798H570.845C571.335 61.0798 572.365 61.0798 572.365 60.2898C572.365 59.5598 571.335 59.5598 570.845 59.5598H570.375V61.0798Z" fill="#FFF5D9"/>
|
||||
<path d="M570.964 69.0002C574.913 69.0002 578.114 65.799 578.114 61.8502C578.114 57.9014 574.913 54.7002 570.964 54.7002C567.016 54.7002 563.814 57.9014 563.814 61.8502C563.814 65.799 567.016 69.0002 570.964 69.0002Z" stroke="#FFF5D9" stroke-width="2.2" stroke-miterlimit="10"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_6_641">
|
||||
<rect width="578.41" height="71.32" fill="white" transform="translate(0.794922)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.7 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
Before Width: | Height: | Size: 4.0 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
Before Width: | Height: | Size: 1.5 KiB |
@ -4,6 +4,7 @@ import useAppsStore from "../store/apps-store";
|
||||
import Modal from "./Modal";
|
||||
import { getAppName } from "../utils/app";
|
||||
import Loader from "./Loader";
|
||||
import classNames from "classnames";
|
||||
|
||||
interface ActionButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
app: AppInfo;
|
||||
@ -136,22 +137,22 @@ export default function ActionButton({ app, ...props }: ActionButtonProps) {
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
className={`small action-btn ${props.className || ""}`}
|
||||
className={classNames("text-sm min-w-[100px] px-2 py-1 self-start", props.className)}
|
||||
onClick={onClick}
|
||||
>
|
||||
{installed && updatable
|
||||
? "Update"
|
||||
: installed
|
||||
? "Installed"
|
||||
: downloaded
|
||||
? "Install"
|
||||
: "Download"}
|
||||
? "Installed"
|
||||
: downloaded
|
||||
? "Install"
|
||||
: "Download"}
|
||||
</button>
|
||||
<Modal show={showModal} hide={() => setShowModal(false)}>
|
||||
{loading ? (
|
||||
<Loader msg={loading} />
|
||||
) : clean ? (
|
||||
<form className="col" style={{alignItems: "center", gap: "1em"}} onSubmit={download}>
|
||||
<form className="flex flex-col items-center gap-2" onSubmit={download}>
|
||||
<h4>Download '{appName}'</h4>
|
||||
<h5 style={{ margin: 0 }}>Select Mirror</h5>
|
||||
<select value={mirror} onChange={(e) => setMirror(e.target.value)}>
|
||||
@ -167,7 +168,7 @@ export default function ActionButton({ app, ...props }: ActionButtonProps) {
|
||||
value={customMirror}
|
||||
onChange={(e) => setCustomMirror(e.target.value)}
|
||||
placeholder="Mirror, i.e. 'template.os'"
|
||||
style={{ padding: "0.5em", maxWidth: 240, width: "100%" }}
|
||||
className="p-1 max-w-[240px] w-full"
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
@ -179,10 +180,10 @@ export default function ActionButton({ app, ...props }: ActionButtonProps) {
|
||||
) : downloaded ? (
|
||||
<>
|
||||
<h4>Approve App Permissions</h4>
|
||||
<h5 style={{ margin: 0 }}>
|
||||
<h5 className="m-0">
|
||||
{getAppName(app)} needs the following permissions:
|
||||
</h5>
|
||||
<ul className="col" style={{ alignItems: "flex-start" }}>
|
||||
<ul className="flex flex-col items-start">
|
||||
{caps.map((cap) => (
|
||||
<li key={cap}>{cap}</li>
|
||||
))}
|
||||
@ -194,12 +195,12 @@ export default function ActionButton({ app, ...props }: ActionButtonProps) {
|
||||
) : (
|
||||
<>
|
||||
<h4>Approve App Permissions</h4>
|
||||
<h5 style={{ margin: 0 }}>
|
||||
<h5 className="m-0">
|
||||
{getAppName(app)} needs the following permissions:
|
||||
</h5>
|
||||
{/* <h5>Send Messages:</h5> */}
|
||||
<br />
|
||||
<ul className="col" style={{ alignItems: "flex-start" }}>
|
||||
<ul className="flex flex-col items-start">
|
||||
{caps.map((cap) => (
|
||||
<li key={cap}>{cap}</li>
|
||||
))}
|
||||
|
@ -12,10 +12,10 @@ interface AppEntryProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
|
||||
export default function AppEntry({ app, ...props }: AppEntryProps) {
|
||||
return (
|
||||
<div {...props} key={appId(app)} className="app-entry row between">
|
||||
<div {...props} key={appId(app)} className="flex justify-between w-full rounded hover:bg-white/10 card">
|
||||
<AppHeader app={app} size="small" />
|
||||
<div className="app-actions row">
|
||||
{!app.state?.caps_approved && <ActionButton app={app} style={{ marginRight: "1em" }} />}
|
||||
<div className="flex mr-1 items-start">
|
||||
{!app.state?.caps_approved && <ActionButton app={app} className="mr-2" />}
|
||||
<MoreActions app={app} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,6 +2,7 @@ import React from "react";
|
||||
import { AppInfo } from "../types/Apps";
|
||||
import { appId } from "../utils/app";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import classNames from "classnames";
|
||||
|
||||
interface AppHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
app: AppInfo;
|
||||
@ -18,7 +19,7 @@ export default function AppHeader({
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={`app-header row ${size} ${props.className || ""}`}
|
||||
className={classNames('flex w-full justify-content-start', size, props.className, { 'cursor-pointer': size !== 'large' })}
|
||||
onClick={() => navigate(`/app-details/${appId(app)}`)}
|
||||
>
|
||||
<img
|
||||
@ -27,11 +28,18 @@ export default function AppHeader({
|
||||
"https://png.pngtree.com/png-vector/20190215/ourmid/pngtree-vector-question-mark-icon-png-image_515448.jpg"
|
||||
}
|
||||
alt="app icon"
|
||||
className={classNames('mr-2', { 'h-32 rounded-md': size === 'large', 'h-12 rounded': size !== 'large' })}
|
||||
/>
|
||||
<div className="col title">
|
||||
<div className="app-name ellipsis">{app.metadata?.name || appId(app)}</div>
|
||||
<div className="flex flex-col w-full">
|
||||
<div
|
||||
className={classNames("whitespace-nowrap overflow-hidden text-ellipsis", { 'text-3xl': size === 'large', })}
|
||||
>
|
||||
{app.metadata?.name || appId(app)}
|
||||
</div>
|
||||
{app.metadata?.description && size !== "large" && (
|
||||
<div className="ellipsis">{app.metadata?.description?.slice(0, 100)}</div>
|
||||
<div className="whitespace-nowrap overflow-hidden text-ellipsis">
|
||||
{app.metadata?.description?.slice(0, 100)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from "react";
|
||||
import { FaCheck } from "react-icons/fa6";
|
||||
|
||||
export default function Checkbox({
|
||||
readOnly = false,
|
||||
@ -10,7 +11,7 @@ export default function Checkbox({
|
||||
setChecked?: (checked: boolean) => void;
|
||||
}) {
|
||||
return (
|
||||
<div style={{ position: "relative" }}>
|
||||
<div className="relative">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="checked"
|
||||
@ -21,9 +22,10 @@ export default function Checkbox({
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
{checked && (
|
||||
<span onClick={() => setChecked && setChecked(false)} className="checkmark">
|
||||
✓
|
||||
</span>
|
||||
<FaCheck
|
||||
className="absolute left-1 top-1 cursor-pointer"
|
||||
onClick={() => setChecked && setChecked(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -1,15 +1,21 @@
|
||||
import React from 'react';
|
||||
import { FaEllipsisH } from 'react-icons/fa';
|
||||
import { Menu, MenuButton } from '@szhsin/react-menu';
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface DropdownProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
}
|
||||
|
||||
export default function Dropdown({ ...props }: DropdownProps) {
|
||||
return (
|
||||
<Menu {...props} className={"dropdown " + props.className} menuButton={<MenuButton className="small">
|
||||
<FaEllipsisH style={{ marginBottom: '-0.125em' }} />
|
||||
</MenuButton>}>
|
||||
<Menu
|
||||
{...props}
|
||||
unmountOnClose={true}
|
||||
className={classNames("relative", props.className)}
|
||||
menuButton={<MenuButton className="small">
|
||||
<FaEllipsisH className='-mb-1' />
|
||||
</MenuButton>}
|
||||
>
|
||||
{props.children}
|
||||
</Menu>
|
||||
)
|
||||
|
27
kinode/packages/app_store/ui/src/components/Jazzicon.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import jazzicon from '@metamask/jazzicon';
|
||||
|
||||
interface JazziconProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
address: string;
|
||||
diameter?: number;
|
||||
}
|
||||
|
||||
const Jazzicon: React.FC<JazziconProps> = ({ address, diameter = 40, ...props }) => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (address && ref.current) {
|
||||
const seed = parseInt(address.slice(2, 10), 16); // Derive a seed from Ethereum address
|
||||
const icon = jazzicon(diameter, seed);
|
||||
|
||||
// Clear the current icon
|
||||
ref.current.innerHTML = '';
|
||||
// Append the new icon
|
||||
ref.current.appendChild(icon);
|
||||
}
|
||||
}, [address, diameter]);
|
||||
|
||||
return <div {...props} ref={ref} />;
|
||||
};
|
||||
|
||||
export default Jazzicon;
|
@ -1,5 +1,6 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { AppInfo } from "../types/Apps";
|
||||
import { FaX } from "react-icons/fa6";
|
||||
|
||||
interface Props {
|
||||
app?: AppInfo;
|
||||
@ -111,9 +112,9 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<form className="col card metadata" style={{ gap: "0.5em" }}>
|
||||
<form className="flex flex-col card mt-2 gap-2">
|
||||
<h4>Fill out metadata</h4>
|
||||
<div className="col label">
|
||||
<div className="flex flex-col w-3/4">
|
||||
<label className="metadata-label">Name</label>
|
||||
<input
|
||||
type="text"
|
||||
@ -122,7 +123,7 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
onChange={(e) => handleFieldChange("name", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col label">
|
||||
<div className="flex flex-col w-3/4">
|
||||
<label className="metadata-label">Description</label>
|
||||
<input
|
||||
type="text"
|
||||
@ -131,7 +132,7 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
onChange={(e) => handleFieldChange("description", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col label">
|
||||
<div className="flex flex-col w-3/4">
|
||||
<label className="metadata-label">Image URL</label>
|
||||
<input
|
||||
type="text"
|
||||
@ -140,7 +141,7 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
onChange={(e) => handleFieldChange("image", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col label">
|
||||
<div className="flex flex-col w-3/4">
|
||||
<label className="metadata-label">External URL</label>
|
||||
<input
|
||||
type="text"
|
||||
@ -149,7 +150,7 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
onChange={(e) => handleFieldChange("external_url", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col label">
|
||||
<div className="flex flex-col w-3/4">
|
||||
<label className="metadata-label">Animation URL</label>
|
||||
<input
|
||||
type="text"
|
||||
@ -158,7 +159,7 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
onChange={(e) => handleFieldChange("animation_url", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col label">
|
||||
<div className="flex flex-col w-3/4">
|
||||
<label className="metadata-label">Package Name</label>
|
||||
<input
|
||||
type="text"
|
||||
@ -167,7 +168,7 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
onChange={(e) => handleFieldChange("package_name", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col label">
|
||||
<div className="flex flex-col w-3/4">
|
||||
<label className="metadata-label">Current Version</label>
|
||||
<input
|
||||
type="text"
|
||||
@ -176,7 +177,7 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
onChange={(e) => handleFieldChange("current_version", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col label">
|
||||
<div className="flex flex-col w-3/4">
|
||||
<label className="metadata-label">Publisher</label>
|
||||
<input
|
||||
type="text"
|
||||
@ -185,7 +186,7 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
onChange={(e) => handleFieldChange("publisher", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col label">
|
||||
<div className="flex flex-col w-3/4">
|
||||
<label className="metadata-label">Mirrors (separated by commas)</label>
|
||||
<input
|
||||
type="text"
|
||||
@ -200,25 +201,16 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="col label"
|
||||
style={{
|
||||
gap: "0.5em",
|
||||
}}
|
||||
className="flex flex-col w-3/4 gap-2"
|
||||
>
|
||||
<div
|
||||
className="row"
|
||||
style={{
|
||||
gap: "0.5em",
|
||||
marginTop: 0,
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
}}
|
||||
className="flex gap-2 mt-0 justify-between w-full"
|
||||
>
|
||||
<h5 style={{ margin: 0 }}>Code Hashes</h5>
|
||||
<h5 className="m-0">Code Hashes</h5>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCodeHashes([...codeHashes, ["", ""]])}
|
||||
className="small"
|
||||
className="clear"
|
||||
>
|
||||
Add code hash
|
||||
</button>
|
||||
@ -227,8 +219,7 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
{codeHashes.map(([version, hash], ind, arr) => (
|
||||
<div
|
||||
key={ind + "_code_hash"}
|
||||
className="row"
|
||||
style={{ gap: "0.5em", marginTop: 0, width: "100%" }}
|
||||
className="flex gap-2 mt-0 w-full"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
@ -241,7 +232,7 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
return newHashes;
|
||||
})
|
||||
}
|
||||
style={{ flex: 1 }}
|
||||
className="flex-1"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
@ -254,7 +245,7 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
return newHashes;
|
||||
})
|
||||
}
|
||||
style={{ flex: 5 }}
|
||||
className="flex-5"
|
||||
/>
|
||||
{arr.length > 1 && (
|
||||
<button
|
||||
@ -262,24 +253,19 @@ const MetadataForm = ({ app, packageName, publisherId, goBack }: Props) => {
|
||||
onClick={() =>
|
||||
setCodeHashes((prev) => prev.filter((_, i) => i !== ind))
|
||||
}
|
||||
style={{
|
||||
fontSize: "2em",
|
||||
height: 32,
|
||||
lineHeight: "1em",
|
||||
padding: "0 0.2em",
|
||||
}}
|
||||
className="icon"
|
||||
>
|
||||
×
|
||||
<FaX />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="row" style={{ gap: "0.5em", margin: "1em 0" }}>
|
||||
<button type="button" onClick={handleSubmit}>
|
||||
<div className="flex gap-2 my-4">
|
||||
<button type="button" onClick={handleSubmit} className="alt">
|
||||
Download JSON
|
||||
</button>
|
||||
<button type="button" onClick={handleClearForm}>
|
||||
<button type="button" onClick={handleClearForm} className="clear">
|
||||
Clear Form
|
||||
</button>
|
||||
<button type="button" onClick={goBack}>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import classNames from 'classnames'
|
||||
import React, { MouseEvent } from 'react'
|
||||
import { FaPlus } from 'react-icons/fa'
|
||||
import { FaX } from 'react-icons/fa6'
|
||||
|
||||
export interface ModalProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
show: boolean
|
||||
@ -25,13 +26,30 @@ const Modal: React.FC<ModalProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`modal-backdrop ${show ? 'show' : ''}`} onClick={hide}>
|
||||
<div {...props} className={`col modal ${props.className || ''}`} onClick={dontHide}>
|
||||
{Boolean(title) && <h4 className='modal-title'>{title}</h4>}
|
||||
<div
|
||||
className={classNames(`bg-black/25 fixed top-0 bottom-0 left-0 right-0 flex flex-col c z-30 min-h-[10em] min-w-[30em]`,
|
||||
{ show }
|
||||
)}
|
||||
onClick={hide}
|
||||
>
|
||||
<div
|
||||
{...props}
|
||||
className={`flex flex-col relative bg-black/90 rounded-lg py-6 px-12 ${props.className || ''}`}
|
||||
onClick={dontHide}
|
||||
>
|
||||
{Boolean(title) && <h4 className='mt-0 mb-2'>{title}</h4>}
|
||||
{!hideClose && (
|
||||
<FaPlus className='close' onClick={hide} />
|
||||
<button
|
||||
className='icon absolute top-1 right-1'
|
||||
onClick={hide}
|
||||
>
|
||||
<FaX />
|
||||
</button>
|
||||
)}
|
||||
<div className='col modal-content' onClick={dontHide}>
|
||||
<div
|
||||
className='flex flex-col items-center w-full'
|
||||
onClick={dontHide}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { MenuItem } from "@szhsin/react-menu";
|
||||
|
||||
import Dropdown from "./Dropdown";
|
||||
import { AppInfo } from "../types/Apps";
|
||||
@ -9,74 +8,75 @@ import useAppsStore from "../store/apps-store";
|
||||
|
||||
interface MoreActionsProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
app: AppInfo;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function MoreActions({ app }: MoreActionsProps) {
|
||||
export default function MoreActions({ app, className }: MoreActionsProps) {
|
||||
const { uninstallApp, setMirroring, setAutoUpdate } = useAppsStore();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const downloaded = Boolean(app.state);
|
||||
|
||||
if (!downloaded) {
|
||||
if (!app.metadata) return <div style={{ width: 38 }} />;
|
||||
if (!app.metadata) return <></>;
|
||||
|
||||
return (
|
||||
<Dropdown>
|
||||
{app.metadata?.description && (
|
||||
<MenuItem
|
||||
className="action-entry"
|
||||
onClick={() => navigate(`/app-details/${appId(app)}`)}
|
||||
>
|
||||
View Details
|
||||
</MenuItem>
|
||||
)}
|
||||
{app.metadata?.external_url && (
|
||||
<MenuItem>
|
||||
<Dropdown className={className}>
|
||||
<div className="flex flex-col bg-black/50 p-2 rounded-lg">
|
||||
{app.metadata?.description && (
|
||||
<button
|
||||
className="my-1 whitespace-nowrap clear"
|
||||
onClick={() => navigate(`/app-details/${appId(app)}`)}
|
||||
>
|
||||
View Details
|
||||
</button>
|
||||
)}
|
||||
{app.metadata?.external_url && (
|
||||
<a
|
||||
style={{
|
||||
color: "inherit",
|
||||
whiteSpace: "nowrap",
|
||||
cursor: "pointer",
|
||||
marginTop: "0.25em",
|
||||
}}
|
||||
target="_blank"
|
||||
href={app.metadata?.external_url}
|
||||
className="mb-1 whitespace-nowrap button clear"
|
||||
>
|
||||
View Site
|
||||
</a>
|
||||
</MenuItem>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown>
|
||||
<MenuItem
|
||||
className="action-entry"
|
||||
onClick={() => navigate(`/app-details/${appId(app)}`)}
|
||||
>
|
||||
View Details
|
||||
</MenuItem>
|
||||
{app.installed && (
|
||||
<>
|
||||
<MenuItem className="action-entry" onClick={() => uninstallApp(app)}>
|
||||
Uninstall
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
className="action-entry"
|
||||
onClick={() => setMirroring(app, !app.state?.mirroring)}
|
||||
>
|
||||
{app.state?.mirroring ? "Stop" : "Start"} Mirroring
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
className="action-entry"
|
||||
onClick={() => setAutoUpdate(app, !app.state?.auto_update)}
|
||||
>
|
||||
{app.state?.auto_update ? "Disable" : "Enable"} Auto Update
|
||||
</MenuItem>
|
||||
</>
|
||||
)}
|
||||
<Dropdown className={className}>
|
||||
<div className="flex flex-col bg-black/50 p-2 rounded-lg">
|
||||
<button
|
||||
className="my-1 whitespace-nowrap clear"
|
||||
onClick={() => navigate(`/app-details/${appId(app)}`)}
|
||||
>
|
||||
View Details
|
||||
</button>
|
||||
{app.installed && (
|
||||
<>
|
||||
<button
|
||||
className="mb-1 whitespace-nowrap clear"
|
||||
onClick={() => uninstallApp(app)}
|
||||
>
|
||||
Uninstall
|
||||
</button>
|
||||
<button
|
||||
className="mb-1 whitespace-nowrap clear"
|
||||
onClick={() => setMirroring(app, !app.state?.mirroring)}
|
||||
>
|
||||
{app.state?.mirroring ? "Stop" : "Start"} Mirroring
|
||||
</button>
|
||||
<button
|
||||
className="mb-1 whitespace-nowrap clear"
|
||||
onClick={() => setAutoUpdate(app, !app.state?.auto_update)}
|
||||
>
|
||||
{app.state?.auto_update ? "Disable" : "Enable"} Auto Update
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
@ -3,12 +3,13 @@ import { useLocation, useNavigate } from "react-router-dom";
|
||||
import {
|
||||
FaArrowLeft,
|
||||
FaDownload,
|
||||
FaRegTimesCircle,
|
||||
FaSearch,
|
||||
FaMagnifyingGlass,
|
||||
FaUpload,
|
||||
} from "react-icons/fa";
|
||||
FaX,
|
||||
} from "react-icons/fa6";
|
||||
|
||||
import { MY_APPS_PATH } from "../constants/path";
|
||||
import classNames from "classnames";
|
||||
|
||||
interface SearchHeaderProps {
|
||||
value?: string;
|
||||
@ -32,9 +33,9 @@ export default function SearchHeader({
|
||||
const isMyAppsPage = location.pathname === MY_APPS_PATH;
|
||||
|
||||
return (
|
||||
<div className="search-header row between">
|
||||
<div className="flex justify-between">
|
||||
{location.pathname !== '/' ? (
|
||||
<button className="back-btn col center" onClick={() => {
|
||||
<button className="flex flex-col c mr-1 icon" onClick={() => {
|
||||
if (onBack) {
|
||||
onBack()
|
||||
} else {
|
||||
@ -45,40 +46,44 @@ export default function SearchHeader({
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
className="back-btn col center"
|
||||
className="flex flex-col c mr-1 alt"
|
||||
onClick={() => navigate("/publish")}
|
||||
>
|
||||
<FaUpload />
|
||||
</button>
|
||||
)}
|
||||
{!hideSearch && (
|
||||
<div className="searchbar row">
|
||||
<FaSearch
|
||||
className="search-icon"
|
||||
<div className="flex mx-2 flex-1 rounded-md">
|
||||
<button
|
||||
className="icon"
|
||||
type="button"
|
||||
onClick={() => inputRef.current?.focus()}
|
||||
/>
|
||||
>
|
||||
<FaMagnifyingGlass />
|
||||
</button>
|
||||
<input
|
||||
type="text"
|
||||
ref={inputRef}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
value={value}
|
||||
placeholder="Search for apps..."
|
||||
className="w-full ml-2"
|
||||
/>
|
||||
{value.length > 0 && (
|
||||
<FaRegTimesCircle
|
||||
className="search-icon"
|
||||
style={{ margin: "0 -0.25em 0 0.25em" }}
|
||||
onClick={() => onChange("")}
|
||||
/>
|
||||
)}
|
||||
{value.length > 0 && <button
|
||||
className="icon ml-2"
|
||||
onClick={() => onChange("")}
|
||||
>
|
||||
<FaX />
|
||||
</button>}
|
||||
</div>
|
||||
)}
|
||||
<div className="row">
|
||||
<div className="flex">
|
||||
<button
|
||||
className={`my-pkg-btn row ${isMyAppsPage ? "selected" : ""}`}
|
||||
className={classNames("flex ml-1 alt")}
|
||||
onClick={() => (isMyAppsPage ? navigate(-1) : navigate(MY_APPS_PATH))}
|
||||
>
|
||||
<FaDownload style={{ marginRight: "0.5em" }} />
|
||||
My Packages
|
||||
<FaDownload className="mr-1" />
|
||||
My Apps
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
39
kinode/packages/app_store/ui/src/components/Tooltip.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { React, useState } from "react"
|
||||
import classNames from 'classnames'
|
||||
import { FaQuestion, FaX } from 'react-icons/fa6'
|
||||
|
||||
interface TooltipProps {
|
||||
text: string
|
||||
button?: React.ReactNode
|
||||
className?: string
|
||||
position?: "top" | "bottom" | "left" | "right"
|
||||
}
|
||||
|
||||
export const Tooltip: React.FC<TooltipProps> = ({ text, button, className, position }) => {
|
||||
const [showTooltip, setShowTooltip] = useState(false)
|
||||
return <div className={classNames("flex place-items-center place-content-center text-sm relative cursor-pointer shrink", className)}>
|
||||
<div onClick={() => setShowTooltip(!showTooltip)}>
|
||||
{button || <button
|
||||
className="icon ml-4"
|
||||
type='button'
|
||||
>
|
||||
<FaQuestion />
|
||||
</button>}
|
||||
</div>
|
||||
<div className={classNames('absolute rounded bg-black p-2 min-w-[200px] z-10',
|
||||
{
|
||||
"hidden": !showTooltip,
|
||||
"top-8": position === "top" || !position,
|
||||
"bottom-8": position === "bottom",
|
||||
"right-8": position === "left",
|
||||
"left-8": position === "right",
|
||||
})}>
|
||||
{text}
|
||||
</div>
|
||||
<button className={classNames("absolute bg-black icon right-0 top-0", {
|
||||
"hidden": !showTooltip,
|
||||
})} onClick={() => setShowTooltip(false)}>
|
||||
<FaX />
|
||||
</button>
|
||||
</div>
|
||||
}
|
@ -2,45 +2,23 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--text-light: #FFF5D9;
|
||||
--text-dark: #22211F;
|
||||
--text-orange: #FF7533;
|
||||
--orange-light: #F36822;
|
||||
--orange-medium: #F35422;
|
||||
--orange-burnt: #E25F35;
|
||||
@font-face {
|
||||
font-family: 'Futura';
|
||||
src: url('./fonts/Futura-Heavy.ttf');
|
||||
}
|
||||
|
||||
--medium-gray: #7E7E7E;
|
||||
--gray-button: rgba(253, 245, 220, 0.25);
|
||||
--dark-background: rgb(130, 59, 28);
|
||||
--input-background: rgba(243, 84, 34, 0.25);
|
||||
/* orange-medium */
|
||||
@font-face {
|
||||
font-family: 'OpenSans';
|
||||
src: url('./fonts/OpenSans-CondBold.ttf');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Barlow';
|
||||
src: url('./fonts/BarlowCondensed-Black.ttf');
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
color: var(--text-light);
|
||||
font-weight: 400;
|
||||
background: url('./assets/background.jpg') no-repeat center center fixed;
|
||||
background-size: cover;
|
||||
background-color: var(--dark-background);
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
body,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
a,
|
||||
button,
|
||||
input {
|
||||
font-family: 'Barlow Condensed', sans-serif;
|
||||
font-family: 'Barlow', 'ui-sans-serif', 'system-ui', '-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Roboto', '"Helvetica Neue"', 'Arial', '"Noto Sans"', 'sans-serif', '"Apple Color Emoji"', '"Segoe UI Emoji"', '"Segoe UI Symbol"', '"Noto Color Emoji"';
|
||||
}
|
||||
|
||||
h1,
|
||||
@ -49,174 +27,107 @@ h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.5em;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
letter-spacing: -0.01em;
|
||||
@apply leading-6 m-0 font-[OpenSans]
|
||||
}
|
||||
|
||||
h1.display {
|
||||
letter-spacing: 0.25em;
|
||||
text-transform: uppercase;
|
||||
@apply font-[Futura] text-3xl font-normal;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 64px;
|
||||
@apply text-3xl;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 48px;
|
||||
@apply text-2xl;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 36px;
|
||||
@apply text-xl;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 20px;
|
||||
@apply text-lg;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="password"],
|
||||
input[type="checkbox"] {
|
||||
padding: 1em;
|
||||
border: 1px solid var(--orange-medium);
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
font-size: 1em;
|
||||
background-color: var(--input-background);
|
||||
color: var(--text-light);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="password"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
padding: 0.25em 0.8em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked {
|
||||
background-color: var(--orange-medium);
|
||||
}
|
||||
|
||||
.checkmark {
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
font-size: 24px;
|
||||
top: -5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: var(--text-light);
|
||||
}
|
||||
|
||||
::-webkit-input-placeholder::placeholder {
|
||||
color: var(--text-light);
|
||||
}
|
||||
|
||||
::-moz-placeholder::placeholder {
|
||||
color: var(--text-light);
|
||||
}
|
||||
|
||||
::-ms-input-placeholder {
|
||||
color: var(--text-light);
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 20px;
|
||||
@apply text-sm;
|
||||
}
|
||||
|
||||
button,
|
||||
[type='button'],
|
||||
[type='reset'],
|
||||
[type='submit'] {
|
||||
padding: 0.75em 1em;
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: var(--orange-medium);
|
||||
/* border-image: linear-gradient(to right, var(--orange-medium), var(--orange-light)); */
|
||||
border-radius: 8px;
|
||||
background: var(--orange-medium);
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
font-size: 1.125em;
|
||||
transition: all 0.1s;
|
||||
box-shadow: 0 1px 2px var(--orange-light);
|
||||
color: var(--text-light);
|
||||
button[type="submit"],
|
||||
.button {
|
||||
@apply flex m-0 py-2 px-6 rounded border-orange bg-orange border-2 cursor-pointer place-items-center place-content-center text-center rounded-lg heading transition ease-in-out duration-100 hover:bg-black text-white font-[OpenSans];
|
||||
}
|
||||
|
||||
button.alt {
|
||||
background-color: var(--text-light);
|
||||
color: var(--text-dark);
|
||||
border-color: var(--text-light);
|
||||
box-shadow: 0 1px 2px var(--text-light);
|
||||
.clear {
|
||||
@apply bg-transparent border-transparent font-bold font-[Barlow] hover:bg-white/25;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
opacity: 0.9;
|
||||
box-shadow: none;
|
||||
.alt {
|
||||
@apply bg-white text-black border-white hover:text-white;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
background-color: var(--medium-gray);
|
||||
border: 1px solid var(--medium-gray);
|
||||
box-shadow: 0 1px 2px var(--medium-gray);
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
.thin {
|
||||
@apply px-0 border-none;
|
||||
}
|
||||
|
||||
ul,
|
||||
li {
|
||||
.icon {
|
||||
@apply flex items-center place-content-center bg-transparent w-11 p-3 text-[14px] rounded-full border-white/25;
|
||||
}
|
||||
|
||||
.icon.alt {
|
||||
@apply border-black/25 hover:border-white/25
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-[url('./background.jpg')] bg-cover bg-no-repeat bg-center bg-fixed text-white;
|
||||
}
|
||||
|
||||
input {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
select,
|
||||
textarea,
|
||||
input[type="text"],
|
||||
input[type="password"],
|
||||
input[type="checkbox"] {
|
||||
@apply px-4 py-2 rounded-lg bg-orange bg-opacity-25 text-white border border-orange border-2;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
@apply w-2 h-2 cursor-pointer p-2;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked {
|
||||
@apply bg-orange;
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 0.25em 0.5em;
|
||||
font-size: 0.9rem;
|
||||
border: 1px solid var(--orange-medium);
|
||||
background-color: var(--input-background);
|
||||
color: var(--text-light);
|
||||
border-radius: 8px;
|
||||
|
||||
/* Use a custom chevron image */
|
||||
background-image: url('./assets/select-chevron.svg');
|
||||
/* arrow image */
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="%23ffffff" d="M7.41 8.58L12 13.17l4.59-4.59L18 10l-6 6-6-6z"/></svg>');
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 8px center;
|
||||
/* Adjust the horizontal position to control padding */
|
||||
background-size: 16px;
|
||||
/* Adjust size of the chevron */
|
||||
padding-right: 2em;
|
||||
/* Adjust the padding to make room for the chevron */
|
||||
background-position: right 1.25rem center;
|
||||
@apply appearance-none pr-16;
|
||||
}
|
||||
|
||||
-webkit-appearance: none;
|
||||
/* Removes default styling on WebKit browsers like Safari */
|
||||
-moz-appearance: none;
|
||||
/* Removes default styling on Firefox */
|
||||
appearance: none;
|
||||
/* Standard property, currently not fully supported */
|
||||
button:hover {
|
||||
@apply opacity-90 shadow-none;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
@apply opacity-70 cursor-not-allowed bg-gray border-gray;
|
||||
}
|
||||
|
||||
.obox,
|
||||
.card {
|
||||
@apply rounded-lg p-4 bg-orange/25;
|
||||
}
|
||||
|
||||
.c {
|
||||
@apply place-items-center place-content-center;
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import '@unocss/reset/tailwind.css'
|
||||
import 'uno.css'
|
||||
import './index.css'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
|
@ -9,7 +9,7 @@ import SearchHeader from "../components/SearchHeader";
|
||||
import { PageProps } from "../types/Page";
|
||||
import { appId } from "../utils/app";
|
||||
|
||||
interface AppPageProps extends PageProps {}
|
||||
interface AppPageProps extends PageProps { }
|
||||
|
||||
export default function AppPage(props: AppPageProps) {
|
||||
// eslint-disable-line
|
||||
@ -48,64 +48,64 @@ export default function AppPage(props: AppPageProps) {
|
||||
(versions[(versions.length || 1) - 1] || ["", ""])[1];
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%" }}>
|
||||
<div className="flex flex-col w-full max-w-[900px]">
|
||||
<SearchHeader value="" onChange={() => null} hideSearch />
|
||||
<div className="card" style={{ marginTop: "1em" }}>
|
||||
<div className="card mt1">
|
||||
{app ? (
|
||||
<>
|
||||
<div className="row between">
|
||||
<div className="flex justify-between">
|
||||
<AppHeader app={app} size="large" />
|
||||
<ActionButton app={app} style={{ marginRight: "0.5em" }} />
|
||||
<ActionButton app={app} className="mr-1" />
|
||||
</div>
|
||||
<div className="col" style={{ marginTop: "1em" }}>
|
||||
<div className="app-details row">
|
||||
<div className="title">Description</div>
|
||||
<div className="value">
|
||||
<div className="flex flex-col mt-2">
|
||||
<div className="flex mt-1 items-start">
|
||||
<div className="w-1/4">Description</div>
|
||||
<div className="mb-1 w-3/4">
|
||||
{(app.metadata?.description || "No description given").slice(
|
||||
0,
|
||||
2000
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="app-details row">
|
||||
<div className="title">Publisher</div>
|
||||
<div className="value underline">{app.publisher}</div>
|
||||
<div className="flex mt-1 items-start">
|
||||
<div className="w-1/4">Publisher</div>
|
||||
<div className="mb-1 w-3/4">{app.publisher}</div>
|
||||
</div>
|
||||
<div className="app-details row">
|
||||
<div className="title">Version</div>
|
||||
<div className="value">{version}</div>
|
||||
<div className="flex mt-1 items-start">
|
||||
<div className="w-1/4">Version</div>
|
||||
<div className="mb-1 w-3/4">{version}</div>
|
||||
</div>
|
||||
<div className="app-details row">
|
||||
<div className="title">Mirrors</div>
|
||||
<div className="col">
|
||||
<div className="flex mt-1 items-start">
|
||||
<div className="w-1/4">Mirrors</div>
|
||||
<div className="w-3/4 flex flex-col">
|
||||
{(app.metadata?.properties?.mirrors || []).map(
|
||||
(mirror, index) => (
|
||||
<div key={index + mirror} className="value underline">
|
||||
<div key={index + mirror} className="mb-1">
|
||||
{mirror}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="app-details row">
|
||||
<div className="title">Permissions</div>
|
||||
<div className="col">
|
||||
{/* <div className="flex mt-1 items-start">
|
||||
<div className="w-1/4">Permissions</div>
|
||||
<div className="w-3/4 flex flex-col">
|
||||
{app.permissions?.map((permission, index) => (
|
||||
<div key={index + permission} className="value permission">{permission}</div>
|
||||
<div key={index + permission} className="mb-1">{permission}</div>
|
||||
))}
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="app-details row">
|
||||
<div className="title">Hash</div>
|
||||
<div className="value" style={{ wordBreak: "break-all" }}>
|
||||
<div className="flex mt-1 items-start">
|
||||
<div className="w-1/4">Hash</div>
|
||||
<div className="w-3/4 break-all">
|
||||
{hash}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="app-screenshots row">
|
||||
<div className="app-screenshots flex mt-2 overflow-x-auto max-w-full">
|
||||
{(app.metadata?.properties?.screenshots || []).map(
|
||||
(screenshot, index) => (
|
||||
<img key={index + screenshot} src={screenshot} />
|
||||
<img key={index + screenshot} src={screenshot} className="mr-2 max-h-20 max-w-full rounded border border-black" />
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
|
@ -9,7 +9,7 @@ import { PageProps } from "../types/Page";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { appId } from "../utils/app";
|
||||
|
||||
interface MyAppsPageProps extends PageProps {}
|
||||
interface MyAppsPageProps extends PageProps { }
|
||||
|
||||
export default function MyAppsPage(props: MyAppsPageProps) { // eslint-disable-line
|
||||
const { myApps, getMyApps } = useAppsStore()
|
||||
@ -53,27 +53,25 @@ export default function MyAppsPage(props: MyAppsPageProps) { // eslint-disable-l
|
||||
}, [myApps]);
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%", height: '100%' }}>
|
||||
<div className="flex flex-col w-full max-w-[900px]">
|
||||
<SearchHeader value={searchQuery} onChange={searchMyApps} />
|
||||
<div className="row between page-title">
|
||||
<h4 style={{ marginBottom: "0.5em" }}>My Packages</h4>
|
||||
<button className="row" onClick={() => navigate('/publish')}>
|
||||
<FaUpload style={{ marginRight: "0.5em" }} />
|
||||
<div className="flex justify-between items-center mt-2">
|
||||
<h4 className="mb-2">My Packages</h4>
|
||||
<button onClick={() => navigate('/publish')}>
|
||||
<FaUpload className="mr-2" />
|
||||
Publish Package
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="my-apps-list">
|
||||
<div className="new card col" style={{ gap: "1em" }}>
|
||||
<h4>Downloaded</h4>
|
||||
{(displayedApps.downloaded || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
<h4>Installed</h4>
|
||||
{(displayedApps.installed || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
<h4>Local</h4>
|
||||
{(displayedApps.local || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
<h4>System</h4>
|
||||
{(displayedApps.system || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
</div>
|
||||
<div className="flex flex-col card gap-2 mt-2">
|
||||
<h4>Downloaded</h4>
|
||||
{(displayedApps.downloaded || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
<h4>Installed</h4>
|
||||
{(displayedApps.installed || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
<h4>Local</h4>
|
||||
{(displayedApps.local || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
<h4>System</h4>
|
||||
{(displayedApps.system || []).map((app) => <AppEntry key={appId(app)} app={app} />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -14,10 +14,12 @@ import useAppsStore from "../store/apps-store";
|
||||
import MetadataForm from "../components/MetadataForm";
|
||||
import { AppInfo } from "../types/Apps";
|
||||
import Checkbox from "../components/Checkbox";
|
||||
import Jazzicon from "../components/Jazzicon";
|
||||
import { Tooltip } from "../components/Tooltip";
|
||||
|
||||
const { useIsActivating } = hooks;
|
||||
|
||||
interface PublishPageProps extends PageProps {}
|
||||
interface PublishPageProps extends PageProps { }
|
||||
|
||||
export default function PublishPage({
|
||||
provider,
|
||||
@ -53,7 +55,7 @@ export default function PublishPage({
|
||||
}, [state])
|
||||
|
||||
const connectWallet = useCallback(async () => {
|
||||
await metaMask.activate().catch(() => {});
|
||||
await metaMask.activate().catch(() => { });
|
||||
|
||||
try {
|
||||
setChain(SEPOLIA_OPT_HEX);
|
||||
@ -104,21 +106,21 @@ export default function PublishPage({
|
||||
|
||||
const tx = await (isUpdate
|
||||
? packageAbi.updateMetadata(
|
||||
BigNumber.from(
|
||||
utils.solidityKeccak256(
|
||||
["string", "bytes"],
|
||||
[packageName, publisherIdDnsWireFormat]
|
||||
)
|
||||
),
|
||||
metadataUrl,
|
||||
metadata
|
||||
)
|
||||
BigNumber.from(
|
||||
utils.solidityKeccak256(
|
||||
["string", "bytes"],
|
||||
[packageName, publisherIdDnsWireFormat]
|
||||
)
|
||||
),
|
||||
metadataUrl,
|
||||
metadata
|
||||
)
|
||||
: packageAbi.registerApp(
|
||||
packageName,
|
||||
publisherIdDnsWireFormat,
|
||||
metadataUrl,
|
||||
metadata
|
||||
));
|
||||
packageName,
|
||||
publisherIdDnsWireFormat,
|
||||
metadataUrl,
|
||||
metadata
|
||||
));
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
|
||||
@ -170,42 +172,39 @@ export default function PublishPage({
|
||||
}, [listedApps, packageName, publisherId, isUpdate, setIsUpdate]);
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%" }}>
|
||||
<div className="max-w-[900px] w-full">
|
||||
<SearchHeader hideSearch onBack={showMetadataForm ? () => setShowMetadataForm(false) : undefined} />
|
||||
<div className="row between page-title">
|
||||
<div className="flex justify-between items-center my-2">
|
||||
<h4>Publish Package</h4>
|
||||
{Boolean(account) && (
|
||||
<div style={{ textAlign: "right", lineHeight: 1.5 }}>
|
||||
{" "}
|
||||
Connected as{" "}
|
||||
{account?.slice(0, 6) + "..." + account?.slice(account.length - 6)}
|
||||
</div>
|
||||
)}
|
||||
{Boolean(account) && <div className="card flex items-center">
|
||||
<span>Publishing as:</span>
|
||||
<Jazzicon address={account!} className="mx-2" />
|
||||
<span className="font-mono">{account?.slice(0, 4)}...{account?.slice(-4)}</span>
|
||||
</div>}
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
<div className="col center">
|
||||
<div className="flex flex-col items-center">
|
||||
<Loader msg={loading} />
|
||||
</div>
|
||||
) : publishSuccess ? (
|
||||
<div className="col center">
|
||||
<h4 style={{ marginBottom: "0.5em" }}>Package Published!</h4>
|
||||
<div style={{ marginBottom: "0.5em" }}>
|
||||
<div className="flex flex-col items-center">
|
||||
<h4 className="mb-2">Package Published!</h4>
|
||||
<div className="mb-2">
|
||||
<strong>Package Name:</strong> {publishSuccess.packageName}
|
||||
</div>
|
||||
<div style={{ marginBottom: "0.5em" }}>
|
||||
<div className="mb-2">
|
||||
<strong>Publisher ID:</strong> {publishSuccess.publisherId}
|
||||
</div>
|
||||
<button
|
||||
className={`my-pkg-btn row`}
|
||||
style={{ marginTop: "1em" }}
|
||||
className={`flex ml-2 mt-2`}
|
||||
onClick={() => setPublishSuccess(undefined)}
|
||||
>
|
||||
Publish Another Package
|
||||
</button>
|
||||
</div>
|
||||
) : showMetadataForm ? (
|
||||
<MetadataForm {...{packageName, publisherId, app: state?.app}} goBack={() => setShowMetadataForm(false)} />
|
||||
<MetadataForm {...{ packageName, publisherId, app: state?.app }} goBack={() => setShowMetadataForm(false)} />
|
||||
) : !account || !isActive ? (
|
||||
<>
|
||||
<h4 style={{}}>Please connect your wallet to publish a package</h4>
|
||||
@ -217,28 +216,23 @@ export default function PublishPage({
|
||||
<Loader msg="Approve connection in your wallet" />
|
||||
) : (
|
||||
<form
|
||||
className="new card col"
|
||||
style={{ flex: 1, overflowY: "scroll" }}
|
||||
className="flex flex-col flex-1 overflow-y-auto"
|
||||
onSubmit={publishPackage}
|
||||
>
|
||||
<div
|
||||
className="row between"
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
padding: "0.5em",
|
||||
margin: "0 0 0 -0.5em",
|
||||
}}
|
||||
className="flex cursor-pointer p-2 -mb-2"
|
||||
onClick={() => setIsUpdate(!isUpdate)}
|
||||
>
|
||||
<Checkbox checked={isUpdate} readOnly />
|
||||
<label htmlFor="update" style={{ cursor: "pointer", marginLeft: 8 }}>
|
||||
<Checkbox
|
||||
checked={isUpdate} readOnly
|
||||
/>
|
||||
<label htmlFor="update" className="cursor-pointer ml-4">
|
||||
Update existing package
|
||||
</label>
|
||||
</div>
|
||||
<div className="col f-width">
|
||||
<div className="flex flex-col mb-2">
|
||||
<label htmlFor="package-name">Package Name</label>
|
||||
<input
|
||||
style={{ minWidth: "80%" }}
|
||||
id="package-name"
|
||||
type="text"
|
||||
required
|
||||
@ -248,10 +242,9 @@ export default function PublishPage({
|
||||
onBlur={checkIfUpdate}
|
||||
/>
|
||||
</div>
|
||||
<div className="col f-width">
|
||||
<div className="flex flex-col mb-2">
|
||||
<label htmlFor="publisher-id">Publisher ID</label>
|
||||
<input
|
||||
style={{ minWidth: "80%" }}
|
||||
id="publisher-id"
|
||||
type="text"
|
||||
required
|
||||
@ -260,12 +253,11 @@ export default function PublishPage({
|
||||
onBlur={checkIfUpdate}
|
||||
/>
|
||||
</div>
|
||||
<div className="col f-width">
|
||||
<div className="flex flex-col mb-2">
|
||||
<label htmlFor="metadata-url">
|
||||
Metadata URL
|
||||
</label>
|
||||
<input
|
||||
style={{ minWidth: "80%" }}
|
||||
id="metadata-url"
|
||||
type="text"
|
||||
required
|
||||
@ -274,19 +266,20 @@ export default function PublishPage({
|
||||
onBlur={calculateMetadataHash}
|
||||
placeholder="https://github/my-org/my-repo/metadata.json"
|
||||
/>
|
||||
<div style={{ textAlign: "left", margin: "0.5em 0 0" }}>
|
||||
Metadata is a JSON file that describes your package.
|
||||
<br /> You can{" "}
|
||||
<a onClick={() => setShowMetadataForm(true)} style={{ cursor: "pointer", textDecoration: "underline" }}>
|
||||
fill out a template here
|
||||
</a>
|
||||
.
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
Metadata is a JSON file that describes your package.
|
||||
<br /> You can{" "}
|
||||
<a onClick={() => setShowMetadataForm(true)}
|
||||
className="underline cursor-pointer"
|
||||
>
|
||||
fill out a template here
|
||||
</a>
|
||||
.
|
||||
</div>
|
||||
</div>
|
||||
<div className="col f-width">
|
||||
<div className="flex flex-col mb-2">
|
||||
<label htmlFor="metadata-hash">Metadata Hash</label>
|
||||
<input
|
||||
style={{ minWidth: "80%" }}
|
||||
readOnly
|
||||
id="metadata-hash"
|
||||
type="text"
|
||||
@ -295,7 +288,7 @@ export default function PublishPage({
|
||||
placeholder="Calculated automatically from metadata URL"
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" className="primary">
|
||||
<button type="submit">
|
||||
Publish
|
||||
</button>
|
||||
</form>
|
||||
|
@ -7,6 +7,7 @@ import AppEntry from "../components/AppEntry";
|
||||
import SearchHeader from "../components/SearchHeader";
|
||||
import { PageProps } from "../types/Page";
|
||||
import { appId } from "../utils/app";
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface StorePageProps extends PageProps { }
|
||||
|
||||
@ -108,7 +109,7 @@ export default function StorePage(props: StorePageProps) {
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%" }}>
|
||||
<div className="max-w-[900px] w-full">
|
||||
{/* <div style={{ position: "absolute", top: 4, left: 8 }}>
|
||||
ID: <strong>{window.our?.node}</strong>
|
||||
</div> */}
|
||||
@ -134,7 +135,7 @@ export default function StorePage(props: StorePageProps) {
|
||||
</div>
|
||||
))}
|
||||
</div> */}
|
||||
<div className="row between page-title">
|
||||
<div className="flex justify-between items-center my-2 mx-0">
|
||||
<h4>New</h4>
|
||||
|
||||
<select
|
||||
@ -150,7 +151,7 @@ export default function StorePage(props: StorePageProps) {
|
||||
<option>Recently updated</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="new card col" style={{ flex: 1, overflowY: "auto", gap: "1em" }}>
|
||||
<div className="flex flex-col flex-1 overflow-y-auto gap-2">
|
||||
{displayedApps.map((app) => (
|
||||
<AppEntry
|
||||
key={appId(app) + (app.state?.our_version || "")}
|
||||
@ -158,14 +159,14 @@ export default function StorePage(props: StorePageProps) {
|
||||
/>
|
||||
))}
|
||||
{pages.length > 1 && (
|
||||
<div className="row" style={{ alignSelf: "center" }}>
|
||||
<div className="flex self-center">
|
||||
{page !== pages[0] && (
|
||||
<FaChevronLeft onClick={() => setPage(page - 1)} />
|
||||
)}
|
||||
{pages.map((p) => (
|
||||
<div
|
||||
key={`page-${p}`}
|
||||
className={`page-selector ${p === page ? "selected" : ""}`}
|
||||
className={classNames('my-1 mx-2', { "font-bold": p === page })}
|
||||
onClick={() => setPage(p)}
|
||||
>
|
||||
{p}
|
||||
|
@ -1,5 +1,10 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import UnoCSS from 'unocss/vite'
|
||||
import { transformerDirectives } from 'unocss'
|
||||
import presetIcons from '@unocss/preset-icons'
|
||||
import presetUno from '@unocss/preset-uno'
|
||||
import presetWind from '@unocss/preset-wind'
|
||||
|
||||
/*
|
||||
If you are developing a UI outside of a Kinode project,
|
||||
@ -22,7 +27,39 @@ const PROXY_URL = (process.env.VITE_NODE_URL || 'http://127.0.0.1:8080').replace
|
||||
console.log('process.env.VITE_NODE_URL', process.env.VITE_NODE_URL, PROXY_URL);
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
plugins: [
|
||||
UnoCSS({
|
||||
presets: [presetUno(), presetWind(), presetIcons()],
|
||||
shortcuts: [
|
||||
{
|
||||
'flex-center': 'flex justify-center items-center',
|
||||
'flex-col-center': 'flex flex-col justify-center items-center',
|
||||
},
|
||||
],
|
||||
rules: [
|
||||
],
|
||||
theme: {
|
||||
colors: {
|
||||
'white': '#FFF5D9',
|
||||
'black': '#22211F',
|
||||
'orange': '#F35422',
|
||||
'transparent': 'transparent',
|
||||
'gray': '#7E7E7E',
|
||||
},
|
||||
font: {
|
||||
'sans': ['Barlow', 'ui-sans-serif', 'system-ui', '-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Roboto', '"Helvetica Neue"', 'Arial', '"Noto Sans"', 'sans-serif', '"Apple Color Emoji"', '"Segoe UI Emoji"', '"Segoe UI Symbol"', '"Noto Color Emoji"'],
|
||||
'serif': ['ui-serif', 'Georgia', 'Cambria', '"Times New Roman"', 'Times', 'serif'],
|
||||
'mono': ['ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', '"Liberation Mono"', '"Courier New"', 'monospace'],
|
||||
'heading': ['OpenSans', 'ui-sans-serif', 'system-ui', '-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Roboto', '"Helvetica Neue"', 'Arial', '"Noto Sans"', 'sans-serif', '"Apple Color Emoji"', '"Segoe UI Emoji"', '"Segoe UI Symbol"', '"Noto Color Emoji"'],
|
||||
'display': ['Futura', 'ui-sans-serif', 'system-ui', '-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Roboto', '"Helvetica Neue"', 'Arial', '"Noto Sans"', 'sans-serif', '"Apple Color Emoji"', '"Segoe UI Emoji"', '"Segoe UI Symbol"', '"Noto Color Emoji"'],
|
||||
},
|
||||
},
|
||||
transformers: [
|
||||
transformerDirectives()
|
||||
],
|
||||
}),
|
||||
react(),
|
||||
],
|
||||
base: BASE_URL,
|
||||
build: {
|
||||
rollupOptions: {
|
||||
|
3
kinode/src/register-ui/.gitignore
vendored
@ -19,5 +19,4 @@
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
src/abis/types/*
|
||||
src/abis/types/*
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.6c087b1c.css",
|
||||
"main.js": "/static/js/main.48b36a2c.js",
|
||||
"main.css": "/static/css/main.eb8419e6.css",
|
||||
"main.js": "/static/js/main.94cc3f8a.js",
|
||||
"static/media/OpenSans-CondBold.ttf": "/static/media/OpenSans-CondBold.6293057f8484b6c0da03.ttf",
|
||||
"static/media/BarlowCondensed-Black.ttf": "/static/media/BarlowCondensed-Black.3ba02bbdeb04e17f34bf.ttf",
|
||||
"static/media/Futura-Heavy.ttf": "/static/media/Futura-Heavy.af72c25a6945b0f48abb.ttf",
|
||||
@ -11,7 +11,7 @@
|
||||
"static/media/kinode.svg": "/static/media/kinode.6b178bc9164b31d90099844a82d04497.svg"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.6c087b1c.css",
|
||||
"static/js/main.48b36a2c.js"
|
||||
"static/css/main.eb8419e6.css",
|
||||
"static/js/main.94cc3f8a.js"
|
||||
]
|
||||
}
|
@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><title>Welcome - Kinode</title><meta charset="utf-8"/><meta http-equiv="pragma" content="no-cache"/><meta http-equiv="cache-control" content="no-cache"/><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet"><link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzc5IiBoZWlnaHQ9IjUxNCIgdmlld0JveD0iMCAwIDc3OSA1MTQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgICA8c3R5bGU+CiAgICAgICAgQG1lZGlhIChwcmVmZXJzLWNvbG9yLXNjaGVtZTogZGFyaykgewogICAgICAgICAgICBzdmcgeyBmaWxsOiB3aGl0ZTsgfQogICAgICAgIH0KICAgICAgICBAbWVkaWEgKHByZWZlcnMtY29sb3Itc2NoZW1lOiBsaWdodCkgewogICAgICAgICAgICBzdmcgeyBmaWxsOiBibGFjazsgfQogICAgICAgIH0KICAgIDwvc3R5bGU+CiAgICA8cGF0aCBkPSJNNzUzLjA5MiA1LjkxOTMyQzc1Ni41NTcgNS4wOTk3NiA3NTUuOTYyIC0wLjAwMDEyMjA3IDc1Mi40MDEgLTAuMDAwMTIyMDdINDI2LjAwMUM0MjQuNzU1IC0wLjAwMDEyMjA3IDQyMy42MzkgMC43NzAyNyA0MjMuMTk3IDEuOTM1MzVMMjM2Ljk2OCA0OTIuNkMyMzUuNzI5IDQ5NS44NjUgMjQwLjEyMyA0OTguMjU1IDI0Mi4xOTEgNDk1LjQ0MUw1NjkuMzU3IDUwLjExMzJDNTY5Ljc3OCA0OS41MzkyIDU3MC4zOTEgNDkuMTMzOSA1NzEuMDg0IDQ4Ljk3TDc1My4wOTIgNS45MTkzMloiLz4KICAgIDxwYXRoIGQ9Ik0xMS45NjY1IDQwLjIyODhDOS4xMDk0OSAzOC43NzcgMTAuMjEzNSAzNC40NTgzIDEzLjQxNjcgMzQuNTU1N0w0MDQuMjczIDQ2LjQzNjdDNDA2LjMzNCA0Ni40OTkzIDQwNy43MTkgNDguNTc0OSA0MDYuOTg2IDUwLjUwMjNMMzQ3LjQzOCAyMDYuOTgxQzM0Ni44MDQgMjA4LjY0NyAzNDQuODY1IDIwOS4zOTYgMzQzLjI3NSAyMDguNTg4TDExLjk2NjUgNDAuMjI4OFoiLz4KPC9zdmc+Cg=="><meta httpequiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1.00001,viewport-fit=cover"/><script defer="defer" src="/static/js/main.48b36a2c.js"></script><link href="/static/css/main.6c087b1c.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><title>Welcome - Kinode</title><meta charset="utf-8"/><meta http-equiv="pragma" content="no-cache"/><meta http-equiv="cache-control" content="no-cache"/><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet"><link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzc5IiBoZWlnaHQ9IjUxNCIgdmlld0JveD0iMCAwIDc3OSA1MTQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgICA8c3R5bGU+CiAgICAgICAgQG1lZGlhIChwcmVmZXJzLWNvbG9yLXNjaGVtZTogZGFyaykgewogICAgICAgICAgICBzdmcgeyBmaWxsOiB3aGl0ZTsgfQogICAgICAgIH0KICAgICAgICBAbWVkaWEgKHByZWZlcnMtY29sb3Itc2NoZW1lOiBsaWdodCkgewogICAgICAgICAgICBzdmcgeyBmaWxsOiBibGFjazsgfQogICAgICAgIH0KICAgIDwvc3R5bGU+CiAgICA8cGF0aCBkPSJNNzUzLjA5MiA1LjkxOTMyQzc1Ni41NTcgNS4wOTk3NiA3NTUuOTYyIC0wLjAwMDEyMjA3IDc1Mi40MDEgLTAuMDAwMTIyMDdINDI2LjAwMUM0MjQuNzU1IC0wLjAwMDEyMjA3IDQyMy42MzkgMC43NzAyNyA0MjMuMTk3IDEuOTM1MzVMMjM2Ljk2OCA0OTIuNkMyMzUuNzI5IDQ5NS44NjUgMjQwLjEyMyA0OTguMjU1IDI0Mi4xOTEgNDk1LjQ0MUw1NjkuMzU3IDUwLjExMzJDNTY5Ljc3OCA0OS41MzkyIDU3MC4zOTEgNDkuMTMzOSA1NzEuMDg0IDQ4Ljk3TDc1My4wOTIgNS45MTkzMloiLz4KICAgIDxwYXRoIGQ9Ik0xMS45NjY1IDQwLjIyODhDOS4xMDk0OSAzOC43NzcgMTAuMjEzNSAzNC40NTgzIDEzLjQxNjcgMzQuNTU1N0w0MDQuMjczIDQ2LjQzNjdDNDA2LjMzNCA0Ni40OTkzIDQwNy43MTkgNDguNTc0OSA0MDYuOTg2IDUwLjUwMjNMMzQ3LjQzOCAyMDYuOTgxQzM0Ni44MDQgMjA4LjY0NyAzNDQuODY1IDIwOS4zOTYgMzQzLjI3NSAyMDguNTg4TDExLjk2NjUgNDAuMjI4OFoiLz4KPC9zdmc+Cg=="><meta httpequiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1.00001,viewport-fit=cover"/><script defer="defer" src="/static/js/main.94cc3f8a.js"></script><link href="/static/css/main.eb8419e6.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
|
2
kinode/src/register-ui/build/static/js/main.94cc3f8a.js
Normal file
@ -0,0 +1,143 @@
|
||||
/*!
|
||||
Copyright (c) 2018 Jed Watson.
|
||||
Licensed under the MIT License (MIT), see
|
||||
http://jedwatson.github.io/classnames
|
||||
*/
|
||||
|
||||
/*!
|
||||
Copyright (c) 2015 Jed Watson.
|
||||
Based on code that is Copyright 2013-2015, Facebook, Inc.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Adapted from jQuery UI core
|
||||
*
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright 2014 jQuery Foundation and other contributors
|
||||
* Released under the MIT license.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://api.jqueryui.com/category/ui-core/
|
||||
*/
|
||||
|
||||
/*!
|
||||
* The buffer module from node.js, for the browser.
|
||||
*
|
||||
* @author Feross Aboukhadijeh <https://feross.org>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-jsx-runtime.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* scheduler.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* use-sync-external-store-shim.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* use-sync-external-store-shim/with-selector.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @remix-run/router v1.15.3
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router DOM v6.22.3
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router v6.22.3
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* [js-sha3]{@link https://github.com/emn178/js-sha3}
|
||||
*
|
||||
* @version 0.5.7
|
||||
* @author Chen, Yi-Cyuan [emn178@gmail.com]
|
||||
* @copyright Chen, Yi-Cyuan 2015-2016
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* [js-sha3]{@link https://github.com/emn178/js-sha3}
|
||||
*
|
||||
* @version 0.8.0
|
||||
* @author Chen, Yi-Cyuan [emn178@gmail.com]
|
||||
* @copyright Chen, Yi-Cyuan 2015-2018
|
||||
* @license MIT
|
||||
*/
|
9
kinode/src/register-ui/package-lock.json
generated
@ -34,6 +34,7 @@
|
||||
"jazzicon": "^1.5.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-modal": "^3.16.1",
|
||||
"react-router-dom": "^6.16.0",
|
||||
"react-scripts": "5.0.1",
|
||||
@ -18660,6 +18661,14 @@
|
||||
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz",
|
||||
"integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==",
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
|
@ -84,7 +84,7 @@ function ChainInfo({
|
||||
</button>
|
||||
<button
|
||||
onClick={changeToNodeChain}
|
||||
className="clear max-w-1/3"
|
||||
className="clear max-w-1/3 z-10"
|
||||
>
|
||||
{generateNetworkIcon(networkName)}
|
||||
<div className='ml-2'>
|
||||
|
@ -79,7 +79,7 @@ function KinodeHeader({
|
||||
nodeChainId === OPTIMISM_OPT_HEX) && (
|
||||
<Tooltip
|
||||
position="left"
|
||||
className="!absolute top-8 right-8"
|
||||
className="!absolute top-8 right-8 z-10"
|
||||
button={nodeChainId === SEPOLIA_OPT_HEX ? (
|
||||
<img
|
||||
alt="sepolia"
|
||||
@ -105,7 +105,7 @@ function KinodeHeader({
|
||||
</div>
|
||||
{!hideConnect && (
|
||||
<div
|
||||
className="flex c max-w-[50vw] mb-8 absolute top-2 left-2"
|
||||
className="flex c w-[99vw] mb-8 absolute top-2 left-2"
|
||||
>
|
||||
{isActive && account ? (
|
||||
<ChainInfo
|
||||
|
@ -702,54 +702,38 @@ button:hover {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bottom-2 {
|
||||
bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.bottom-8 {
|
||||
bottom: 2rem;
|
||||
}
|
||||
|
||||
.left-8 {
|
||||
left: 2rem;
|
||||
}
|
||||
|
||||
.right-1 {
|
||||
right: 0.25rem;
|
||||
}
|
||||
|
||||
.right-8 {
|
||||
right: 2rem;
|
||||
}
|
||||
|
||||
.top-1 {
|
||||
top: 0.25rem;
|
||||
}
|
||||
|
||||
.top-8 {
|
||||
top: 2rem;
|
||||
}
|
||||
|
||||
.right-0 {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.top-0 {
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.left-0 {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.left-2 {
|
||||
left: 0.5rem;
|
||||
}
|
||||
|
||||
.left-8 {
|
||||
left: 2rem;
|
||||
}
|
||||
|
||||
.right-0 {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.right-8 {
|
||||
right: 2rem;
|
||||
}
|
||||
|
||||
.top-0 {
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.top-2 {
|
||||
top: 0.5rem;
|
||||
}
|
||||
|
||||
.top-8 {
|
||||
top: 2rem;
|
||||
}
|
||||
|
||||
.z-10 {
|
||||
z-index: 10;
|
||||
}
|
||||
@ -774,11 +758,6 @@ button:hover {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.my-10 {
|
||||
margin-top: 2.5rem;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.mb-1 {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
@ -815,6 +794,10 @@ button:hover {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.mt-10 {
|
||||
margin-top: 2.5rem;
|
||||
}
|
||||
|
||||
.mt-2 {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
@ -827,10 +810,6 @@ button:hover {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.mt-10 {
|
||||
margin-top: 2.5rem;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
@ -843,20 +822,20 @@ button:hover {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.h-16 {
|
||||
height: 4rem;
|
||||
.h-32 {
|
||||
height: 8rem;
|
||||
}
|
||||
|
||||
.h-screen {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.h-32 {
|
||||
height: 8rem;
|
||||
.w-32 {
|
||||
width: 8rem;
|
||||
}
|
||||
|
||||
.w-16 {
|
||||
width: 4rem;
|
||||
.w-\[95vw\] {
|
||||
width: 95vw;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
@ -867,8 +846,8 @@ button:hover {
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
.w-32 {
|
||||
width: 8rem;
|
||||
.w-\[99vw\] {
|
||||
width: 99vw;
|
||||
}
|
||||
|
||||
.min-w-\[200px\] {
|
||||
@ -883,8 +862,8 @@ button:hover {
|
||||
max-width: 460px;
|
||||
}
|
||||
|
||||
.max-w-\[50vw\] {
|
||||
max-width: 50vw;
|
||||
.max-w-\[450vw\] {
|
||||
max-width: 450vw;
|
||||
}
|
||||
|
||||
.shrink {
|
||||
@ -957,15 +936,11 @@ button:hover {
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.text-6xl {
|
||||
font-size: 3.75rem;
|
||||
.text-5xl {
|
||||
font-size: 3rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.text-\[8px\] {
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
@ -976,16 +951,6 @@ button:hover {
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.text-3xl {
|
||||
font-size: 1.875rem;
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
|
||||
.text-5xl {
|
||||
font-size: 3rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.text-xs {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
|
@ -5,6 +5,7 @@ import { utils, providers } from "ethers";
|
||||
import { downloadKeyfile } from "../utils/download-keyfile";
|
||||
import { ReactComponent as NameLogo } from "../assets/kinode.svg"
|
||||
import { Tooltip } from "../components/Tooltip";
|
||||
import { KinodeTitle } from "../components/KinodeTitle";
|
||||
|
||||
type SetPasswordProps = {
|
||||
direct: boolean;
|
||||
@ -113,11 +114,7 @@ function SetPassword({
|
||||
return (
|
||||
<>
|
||||
<KinodeHeader
|
||||
header={<h1
|
||||
className="flex place-content-center place-items-center mb-4"
|
||||
>
|
||||
Set Password
|
||||
</h1>}
|
||||
header={<KinodeTitle prefix="Set Password" showLogo />}
|
||||
openConnect={() => { }}
|
||||
closeConnect={closeConnect}
|
||||
nodeChainId={nodeChainId}
|
||||
@ -128,7 +125,7 @@ function SetPassword({
|
||||
<form id="signup-form" className="flex flex-col w-full max-w-[450px] gap-4" onSubmit={handleSubmit}>
|
||||
<div className="flex flex-col w-full place-items-center place-content-center">
|
||||
<div className="flex w-full place-items-center mb-2">
|
||||
<label className="flex leading-6 place-items-center mt-2 cursor-pointer mb-2" style={{fontSize: 20}} htmlFor="password">New Password</label>
|
||||
<label className="flex leading-6 place-items-center mt-2 cursor-pointer mb-2" style={{ fontSize: 20 }} htmlFor="password">New Password</label>
|
||||
<Tooltip text={`This password will be used to log in if you restart your node or switch browsers.`} />
|
||||
</div>
|
||||
<div className="flex w-full place-items-center">
|
||||
@ -148,7 +145,7 @@ function SetPassword({
|
||||
</div>
|
||||
<div className="flex flex-col w-full place-items-center place-content-center">
|
||||
<div className="flex w-full place-items-center">
|
||||
<label className="flex leading-6 place-items-center mt-2 cursor-pointer mb-4" style={{fontSize: 20}} htmlFor="confirm-password">Confirm Password</label>
|
||||
<label className="flex leading-6 place-items-center mt-2 cursor-pointer mb-4" style={{ fontSize: 20 }} htmlFor="confirm-password">Confirm Password</label>
|
||||
</div>
|
||||
<div className="flex w-full place-items-center">
|
||||
<input
|
||||
|