diff --git a/package-lock.json b/package-lock.json index 9fb4642..ef7fb43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.7", "license": "MIT", "dependencies": { - "@codex-storage/marketplace-ui-components": "0.0.42", + "@codex-storage/marketplace-ui-components": "^0.0.43", "@codex-storage/sdk-js": "^0.0.15", "@sentry/browser": "^8.32.0", "@sentry/react": "^8.31.0", @@ -424,9 +424,9 @@ "peer": true }, "node_modules/@codex-storage/marketplace-ui-components": { - "version": "0.0.42", - "resolved": "https://registry.npmjs.org/@codex-storage/marketplace-ui-components/-/marketplace-ui-components-0.0.42.tgz", - "integrity": "sha512-JRs7v5rsxNnH3T30UV+DHuJNr25kJ1a1EAqgthA/0okDrcr9IlOVEvl7XrsNBGRDDbJC5MDJkWo9VD2Jh3gAgQ==", + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/@codex-storage/marketplace-ui-components/-/marketplace-ui-components-0.0.43.tgz", + "integrity": "sha512-rNhLfbJXu/1ZKh8hTnD2PkUcj/6M0/jHEfHJ86vIgFX4AFPq4+XGMstylx33VZAUYiDCEAc8iyJV/hMXjTNOsA==", "dependencies": { "lucide-react": "^0.453.0" }, diff --git a/package.json b/package.json index 8204889..8c90b35 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "React" ], "dependencies": { - "@codex-storage/marketplace-ui-components": "0.0.42", + "@codex-storage/marketplace-ui-components": "^0.0.43", "@codex-storage/sdk-js": "^0.0.15", "@sentry/browser": "^8.32.0", "@sentry/react": "^8.31.0", diff --git a/src/assets/icons/bridge.svg b/src/assets/icons/bridge.svg new file mode 100644 index 0000000..32808a5 --- /dev/null +++ b/src/assets/icons/bridge.svg @@ -0,0 +1,11 @@ + + + diff --git a/src/assets/icons/buy-sell.svg b/src/assets/icons/buy-sell.svg new file mode 100644 index 0000000..6c2efb2 --- /dev/null +++ b/src/assets/icons/buy-sell.svg @@ -0,0 +1,11 @@ + + + diff --git a/src/assets/icons/codextoken.svg b/src/assets/icons/codextoken.svg new file mode 100644 index 0000000..fb56963 --- /dev/null +++ b/src/assets/icons/codextoken.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + diff --git a/src/assets/icons/contacts.svg b/src/assets/icons/contacts.svg new file mode 100644 index 0000000..fcbbde8 --- /dev/null +++ b/src/assets/icons/contacts.svg @@ -0,0 +1,10 @@ + + + diff --git a/src/assets/icons/ethereum.svg b/src/assets/icons/ethereum.svg new file mode 100644 index 0000000..edef96b --- /dev/null +++ b/src/assets/icons/ethereum.svg @@ -0,0 +1,10 @@ + + + diff --git a/src/assets/icons/import.svg b/src/assets/icons/import.svg new file mode 100644 index 0000000..79ddb5a --- /dev/null +++ b/src/assets/icons/import.svg @@ -0,0 +1,11 @@ + + + diff --git a/src/assets/icons/receive.svg b/src/assets/icons/receive.svg new file mode 100644 index 0000000..f62ef22 --- /dev/null +++ b/src/assets/icons/receive.svg @@ -0,0 +1,11 @@ + + + diff --git a/src/assets/icons/send.svg b/src/assets/icons/send.svg new file mode 100644 index 0000000..67e06d0 --- /dev/null +++ b/src/assets/icons/send.svg @@ -0,0 +1,11 @@ + + + diff --git a/src/assets/icons/swap.svg b/src/assets/icons/swap.svg new file mode 100644 index 0000000..fe59f13 --- /dev/null +++ b/src/assets/icons/swap.svg @@ -0,0 +1,11 @@ + + + diff --git a/src/assets/icons/tokens.svg b/src/assets/icons/tokens.svg new file mode 100644 index 0000000..bc20137 --- /dev/null +++ b/src/assets/icons/tokens.svg @@ -0,0 +1,10 @@ + + + diff --git a/src/components/AppBar/AppBar.tsx b/src/components/AppBar/AppBar.tsx index b9a1540..e38fac5 100644 --- a/src/components/AppBar/AppBar.tsx +++ b/src/components/AppBar/AppBar.tsx @@ -74,9 +74,12 @@ export function AppBar({ onIconClick }: Props) { const networkIconColor = online ? "#3EE089" : "var(--codex-input-color-error)"; - const nodesIconColor = codex.enabled - ? "#3EE089" - : "var(--codex-input-color-error)"; + const nodesIconColor = + codex.enabled === false + ? "var(--codex-input-color-error)" + : persistence.enabled + ? "#3EE089" + : "var(--codex-input-color-warning)"; return ( <> diff --git a/src/components/AppBar/appBar.css b/src/components/AppBar/appBar.css index 084a830..9a6d877 100644 --- a/src/components/AppBar/appBar.css +++ b/src/components/AppBar/appBar.css @@ -26,7 +26,7 @@ border-right-color: var(--codex-input-color-error); } - &.app-bar--no-persistence { + &.app-bar--no-persistence:not(.app-bar--offline) { border-right-color: rgb(var(--codex-color-warning)); } diff --git a/src/components/ConnectedAccount/WalletCard.css b/src/components/ConnectedAccount/WalletCard.css index 4971622..f0fa1d8 100644 --- a/src/components/ConnectedAccount/WalletCard.css +++ b/src/components/ConnectedAccount/WalletCard.css @@ -30,6 +30,11 @@ } header { + display: flex; + justify-content: space-between; + margin-bottom: 16px; + align-items: center; + button { background-color: #161616; border: 1px solid #96969633; diff --git a/src/components/Files/FileDetails.css b/src/components/Files/FileDetails.css index 790551b..4f78919 100644 --- a/src/components/Files/FileDetails.css +++ b/src/components/Files/FileDetails.css @@ -15,6 +15,8 @@ line-height: 24px; letter-spacing: -0.011em; text-align: left; + gap: 16px; + margin-bottom: 8px; span { flex-grow: 1; diff --git a/src/components/Files/FolderButton.css b/src/components/Files/FolderButton.css index 755b618..5ec2643 100644 --- a/src/components/Files/FolderButton.css +++ b/src/components/Files/FolderButton.css @@ -1,12 +1,9 @@ .folder-button { > div { position: absolute; - right: 300px; + transform: translate(310px, -200px); opacity: 0; - transition: - transform 0.25s, - left 0.25s, - opacity 0.15s; + transition: opacity 0.15s; background-color: var(--codex-background); padding: 0.5rem; border-radius: var(--codex-border-radius); diff --git a/src/components/HealthChecks/HealthChecks.tsx b/src/components/HealthChecks/HealthChecks.tsx index 7efb698..abc16dd 100644 --- a/src/components/HealthChecks/HealthChecks.tsx +++ b/src/components/HealthChecks/HealthChecks.tsx @@ -37,14 +37,10 @@ export function HealthChecks({ online, onStepValid }: Props) { useEffect( () => { - if (codex.isSuccess) { - persistence.refetch(); - portForwarding.refetch().then(({ data }) => { - onStepValid(data?.reachable || false); - }); - } else { - onStepValid(false); - } + persistence.refetch(); + portForwarding.refetch(); + + onStepValid(codex.isSuccess); }, // We really do not want to add persistence and portForwarding as // dependencies because it will cause a re-render every time. @@ -163,18 +159,6 @@ export function HealthChecks({ online, onStepValid }: Props) { Internet connection -
  • - - {portForwarding.isFetching ? ( - - ) : portForwarding.enabled ? ( - - ) : ( - - )} - - Port forwarding -
  • {codex.isFetching ? ( @@ -187,6 +171,18 @@ export function HealthChecks({ online, onStepValid }: Props) { Codex connection
  • +
  • + + {portForwarding.isFetching ? ( + + ) : portForwarding.enabled ? ( + + ) : ( + + )} + + Port forwarding +
  • {persistence.isFetching ? ( diff --git a/src/components/OnBoarding/OnBoardingLayout.css b/src/components/OnBoarding/OnBoardingLayout.css index 6a1c2cc..c58252a 100644 --- a/src/components/OnBoarding/OnBoardingLayout.css +++ b/src/components/OnBoarding/OnBoardingLayout.css @@ -212,6 +212,11 @@ cursor: not-allowed; } } + + .disclaimer dialog { + padding: 16px; + max-width: 700px; + } } @keyframes rotate { diff --git a/src/components/WalletLogin/WalletLogin.css b/src/components/WalletLogin/WalletLogin.css index 4ac3e13..2aeb48f 100644 --- a/src/components/WalletLogin/WalletLogin.css +++ b/src/components/WalletLogin/WalletLogin.css @@ -4,11 +4,8 @@ align-items: center; gap: 16px; background-color: #252525; - - & { - filter: grayscale(30); - transition: filter 0.5s; - } + filter: grayscale(30); + transition: filter 0.5s; &:hover { filter: none; diff --git a/src/main.tsx b/src/main.tsx index d54cd72..b277f10 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -16,18 +16,19 @@ import { CodexSdk } from "./sdk/codex"; import { ErrorPlaceholder } from "./components/ErrorPlaceholder/ErrorPlaceholder.tsx"; import { DebugErrorsDataLoad } from "./components/DebugErrors/debug-errors.domain.ts"; -if (import.meta.env.PROD && !import.meta.env.CI) { +if (true || (import.meta.env.PROD && !import.meta.env.CI)) { Sentry.init({ release: "codex-storage-marketplace-ui@" + import.meta.env.PACKAGE_VERSION, dsn: "https://22d77c59a27b8d5efc07132188b505b9@o4507855852011520.ingest.de.sentry.io/4507866758512720", integrations: [ Sentry.browserTracingIntegration(), Sentry.replayIntegration(), - Sentry.feedbackIntegration({ - // Additional SDK configuration goes in here, for example: - colorScheme: "dark", - triggerLabel: "", - }), + // Sentry.feedbackIntegration({ + // // Additional SDK configuration goes in here, for example: + // colorScheme: "dark", + // triggerLabel: "", + // autoInject: false, + // }), ], // Tracing tracesSampleRate: 1.0, // Capture 100% of the transactions diff --git a/src/routes/dashboard/disclaimer.css b/src/routes/dashboard/disclaimer.css index be0e3ac..ad2febf 100644 --- a/src/routes/dashboard/disclaimer.css +++ b/src/routes/dashboard/disclaimer.css @@ -1,6 +1,7 @@ .disclaimer { max-width: 600px; margin: auto; + padding: 32px; } .disclaimer-title { diff --git a/src/routes/dashboard/help.tsx b/src/routes/dashboard/help.tsx index a312b0d..ea78221 100644 --- a/src/routes/dashboard/help.tsx +++ b/src/routes/dashboard/help.tsx @@ -1,98 +1,114 @@ import { createFileRoute } from "@tanstack/react-router"; import "./help.css"; import { HelpCircle } from "lucide-react"; +import { useEffect } from "react"; +import * as Sentry from "@sentry/react"; export const Route = createFileRoute("/dashboard/help")({ - component: () => ( -
    -
    -

    You might be wondering...

    + component: () => { + useEffect(() => { + const feedback = Sentry.feedbackIntegration({ + // Additional SDK configuration goes in here, for example: + colorScheme: "dark", + triggerLabel: "", + }); + const widget = feedback.createWidget(); + return () => { + return widget.removeFromDom(); + }; + }, []); -
    - -
    -

    What's Codex?

    -

    - Codex is a decentralised data storage platform that provides - exceptionally strong censorship resistance and durability - guarantees. It serves as the storage layer of the Logos tech - stack. -

    + return ( +
    +
    +

    You might be wondering...

    + +
    + +
    +

    What's Codex?

    +

    + Codex is a decentralised data storage platform that provides + exceptionally strong censorship resistance and durability + guarantees. It serves as the storage layer of the Logos tech + stack. +

    +
    -
    -
    - -
    -

    - What is the purpose of this web application? -

    -

    - This application allows you to interact with the Codex Marketplace - network in a user-friendly manner. -

    +
    + +
    +

    + What is the purpose of this web application? +

    +

    + This application allows you to interact with the Codex + Marketplace network in a user-friendly manner. +

    +
    -
    -
    - -
    -

    Can Codex handle big files ?

    -

    - Codex can handle very large files, which is its main purpose. - However, for this UI, the files used should not be too large. -

    +
    + +
    +

    Can Codex handle big files ?

    +

    + Codex can handle very large files, which is its main purpose. + However, for this UI, the files used should not be too large. +

    +
    -
    -
    - -
    -

    Is it production ready ?

    -

    - Not at all! This is a very early alpha version. You should expect - to encounter bugs, but don't worry—feel free to reach out to us if - you need assistance. -

    +
    + +
    +

    Is it production ready ?

    +

    + Not at all! This is a very early alpha version. You should + expect to encounter bugs, but don't worry—feel free to reach out + to us if you need assistance. +

    +
    -
    -
    - -
    -

    - How can I reach you if I am stuck ? -

    -

    - Please create a new issue on our GitHub repository  - - https://github.com/codex-storage/codex-marketplace-ui - - . -

    +
    + +
    +

    + How can I reach you if I am stuck ? +

    +

    + Please create a new issue on our GitHub repository  + + https://github.com/codex-storage/codex-marketplace-ui + + . +

    +
    -
    -
    - -
    -

    How can I build and run Codex ?

    -

    - For instructions, please visit{" "} - - https://docs.codex.storage - - . -

    +
    + +
    +

    How can I build and run Codex ?

    +

    + For instructions, please visit{" "} + + https://docs.codex.storage + + . +

    +
    -
    - ), + ); + }, }); diff --git a/src/routes/dashboard/index.css b/src/routes/dashboard/index.css index 60aa6c6..ddac5ec 100644 --- a/src/routes/dashboard/index.css +++ b/src/routes/dashboard/index.css @@ -26,7 +26,7 @@ } } - header { + > header { display: flex; justify-content: space-between; margin-bottom: 16px; diff --git a/src/routes/dashboard/index.tsx b/src/routes/dashboard/index.tsx index fe7fd24..51ac37e 100644 --- a/src/routes/dashboard/index.tsx +++ b/src/routes/dashboard/index.tsx @@ -47,7 +47,8 @@ function Dashboard() { className="card--main" title="Connected Account" buttonLabel="Add Wallet" - buttonIcon={() => }> + buttonIcon={() => } + buttonAction={() => navigate({ to: "/dashboard/availabilities" })}> diff --git a/src/routes/dashboard/logs.tsx b/src/routes/dashboard/logs.tsx index ec5e5f6..8b5ee93 100644 --- a/src/routes/dashboard/logs.tsx +++ b/src/routes/dashboard/logs.tsx @@ -4,12 +4,28 @@ import { RequireAssitance } from "../../components/RequireAssitance/RequireAssit import { LogLevel } from "../../components/LogLevel/LogLevel"; import { useDebug } from "../../hooks/useDebug"; import LogsIcon from "../../assets/icons/logs.svg?react"; +import * as Sentry from "@sentry/react"; +import { useEffect } from "react"; const throwOnError = false; +// Sentry.showReportDialog({}); + const Logs = () => { const { data } = useDebug(throwOnError); + useEffect(() => { + const feedback = Sentry.feedbackIntegration({ + // Additional SDK configuration goes in here, for example: + colorScheme: "dark", + triggerLabel: "", + }); + const widget = feedback.createWidget(); + return () => { + return widget.removeFromDom(); + }; + }, []); + const { table, ...rest } = data ?? {}; return ( diff --git a/src/routes/dashboard/settings.css b/src/routes/dashboard/settings.css index c75ccc5..c4379c2 100644 --- a/src/routes/dashboard/settings.css +++ b/src/routes/dashboard/settings.css @@ -31,6 +31,7 @@ .background-img { top: 200px; right: -400px; + height: 1000px; } .refresh { diff --git a/src/routes/dashboard/wallet.css b/src/routes/dashboard/wallet.css index 258fa5e..d6fda3f 100644 --- a/src/routes/dashboard/wallet.css +++ b/src/routes/dashboard/wallet.css @@ -1,4 +1,63 @@ .wallet-page { + display: flex; + gap: 16px; + + .card { + filter: grayscale(30); + transition: filter 0.5s; + + &:hover { + filter: none; + } + } + + .buttons { + display: flex; + justify-content: space-between; + margin-top: 16px; + margin-bottom: 16px; + border-top: 1px solid #96969633; + border-bottom: 1px solid #96969633; + padding-top: 16px; + padding-bottom: 16px; + + div { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8px; + + small { + font-family: Inter; + font-size: 12px; + font-weight: 500; + line-height: 16px; + text-align: left; + color: #969696; + } + } + + span { + height: 36px; + width: 1px; + background-color: #ffffff33; + margin: auto 0; + } + } + + .button-icon { + background-color: #2f2f2f; + height: 60px; + width: 60px; + color: #96969666; + border: 0.75px solid #96969633; + + svg { + mix-blend-mode: unset; + } + } + .card { flex: 1; } @@ -7,4 +66,66 @@ max-height: 145px; margin-top: 8px; } + + .card:nth-child(2) { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + gap: 8px; + + div { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8px; + color: #969696; + font-size: 20px; + } + } + + .tabs { + > div { + cursor: not-allowed; + } + } + + ul { + list-style-type: none; + margin-top: 16px; + + li { + display: flex; + gap: 48px; + border-bottom: 1px solid #96969633; + margin-bottom: 16px; + padding-bottom: 16px; + + div { + display: flex; + flex-direction: column; + justify-content: center; + + small { + font-family: Inter; + font-size: 14px; + font-weight: 400; + line-height: 20px; + letter-spacing: -0.006em; + text-align: left; + color: #ffffffb2; + } + + p { + font-family: Inter; + font-size: 32px; + font-weight: 500; + line-height: 40px; + letter-spacing: -0.005em; + text-align: left; + } + } + } + } } diff --git a/src/routes/dashboard/wallet.tsx b/src/routes/dashboard/wallet.tsx index fae7d43..247d9bb 100644 --- a/src/routes/dashboard/wallet.tsx +++ b/src/routes/dashboard/wallet.tsx @@ -6,40 +6,115 @@ import PlusIcon from "../../assets/icons/plus.svg?react"; import RequestDurationIcon from "../../assets/icons/request-duration.svg?react"; import { RequireAssitance } from "../../components/RequireAssitance/RequireAssitance"; import "./wallet.css"; +import BuySellIcon from "../../assets/icons/buy-sell.svg?react"; +import SendIcon from "../../assets/icons/send.svg?react"; +import SwapIcon from "../../assets/icons/swap.svg?react"; +import BridgeIcon from "../../assets/icons/bridge.svg?react"; +import ReceiveIcon from "../../assets/icons/receive.svg?react"; +import ImportIcon from "../../assets/icons/import.svg?react"; +import RefreshIcon from "../../assets/icons/refresh.svg?react"; +import TokensIcon from "../../assets/icons/tokens.svg?react"; +import FavoriteIcon from "../../assets/icons/favorite.svg?react"; +import ContactsIcon from "../../assets/icons/contacts.svg?react"; +import CodexTokenIcon from "../../assets/icons/codextoken.svg?react"; +import EthereumIcon from "../../assets/icons/ethereum.svg?react"; +import { + ButtonIcon, + TabProps, + Tabs, +} from "@codex-storage/marketplace-ui-components"; + +const Wallet = () => { + const tabs: TabProps[] = [ + { + label: "Tokens", + Icon: TokensIcon, + }, + { + label: "NFTs", + Icon: FavoriteIcon, + }, + { + label: "Contacts", + Icon: ContactsIcon, + }, + ]; + + return ( +
    + } + title="Connected Account" + buttonLabel="Add Wallet" + buttonIcon={() => }> + <> + + +
    +
    + + Buy / Sell +
    +
    + + Send +
    +
    + + Swap +
    +
    + + Bridge +
    + +
    + + Receive +
    +
    + + Import +
    +
    + + Refresh +
    +
    + {}}> +
      +
    • + +
      + Codex +

      123,223 CDX

      +
      +
    • +
    • + +
      + Ethereum +

      2.32 ETH

      +
      +
    • +
    + +
    + } + title="Activity"> +
    +
    + +
    +
    You currently have no activity.
    + +
    +
    +
    + ); +}; export const Route = createFileRoute("/dashboard/wallet")({ - component: () => { - return ( -
    - } - title="Connected Account" - buttonLabel="Add Wallet" - buttonIcon={() => }> - - - } - title="Activity"> -
    -
    - -
    -
    - You currently have no activity. -
    - -
    -
    -
    - ); - }, + component: Wallet, }); diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 7f65845..2b843a7 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,5 +1,5 @@ import { createFileRoute, useNavigate } from "@tanstack/react-router"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { Modal } from "@codex-storage/marketplace-ui-components"; import { ArrowRight } from "lucide-react"; import { OnBoardingLayout } from "../components/OnBoarding/OnBoardingLayout"; @@ -26,6 +26,19 @@ function Index() { const onNextStep = () => navigate({ to: "/onboarding-name" }); + useEffect(() => { + const onKeyPress = (event: Event) => { + const e = event as KeyboardEvent; + if (e.key === "ArrowRight") { + navigate({ to: "/onboarding-name" }); + } + }; + + document.addEventListener("keydown", onKeyPress); + + return () => document.removeEventListener("keydown", onKeyPress); + }, [navigate]); + return ( <> @@ -56,7 +69,10 @@ function Index() { Let’s get started - +

    Disclaimer

    diff --git a/src/routes/onboarding-checks.tsx b/src/routes/onboarding-checks.tsx index bf9ea25..ac51a1c 100644 --- a/src/routes/onboarding-checks.tsx +++ b/src/routes/onboarding-checks.tsx @@ -1,5 +1,5 @@ import { createFileRoute, useNavigate } from "@tanstack/react-router"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { attributes } from "../utils/attributes"; import ArrowRightCircle from "../assets/icons/arrow-circle.svg?react"; import { OnBoardingLayout } from "../components/OnBoarding/OnBoardingLayout"; @@ -14,6 +14,21 @@ const OnBoardingChecks = () => { const [isStepValid, setIsStepValid] = useState(false); const navigate = useNavigate({ from: "/onboarding-checks" }); + useEffect(() => { + const onKeyPress = (event: Event) => { + const e = event as KeyboardEvent; + if (e.key === "ArrowRight" && isStepValid) { + navigate({ to: "/dashboard" }); + } else if (e.key === "ArrowLeft") { + navigate({ to: "/onboarding-name" }); + } + }; + + document.addEventListener("keydown", onKeyPress); + + return () => document.removeEventListener("keydown", onKeyPress); + }, [navigate, isStepValid]); + const onNextStep = () => { if (isStepValid) { navigate({ to: "/dashboard" }); diff --git a/src/routes/onboarding-name.tsx b/src/routes/onboarding-name.tsx index 983c3df..09faacf 100644 --- a/src/routes/onboarding-name.tsx +++ b/src/routes/onboarding-name.tsx @@ -1,5 +1,5 @@ import { createFileRoute, useNavigate } from "@tanstack/react-router"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { OnBoardingLayout } from "../components/OnBoarding/OnBoardingLayout"; import { attributes } from "../utils/attributes"; import ArrowRightCircle from "../assets/icons/arrow-circle.svg?react"; @@ -21,6 +21,21 @@ const OnBoardingName = () => { } }; + useEffect(() => { + const onKeyPress = (event: Event) => { + const e = event as KeyboardEvent; + if (e.key === "ArrowRight") { + navigate({ to: "/onboarding-checks" }); + } else if (e.key === "ArrowLeft") { + navigate({ to: "/" }); + } + }; + + document.addEventListener("keydown", onKeyPress); + + return () => document.removeEventListener("keydown", onKeyPress); + }, [navigate]); + return ( <>