diff --git a/package-lock.json b/package-lock.json index 826d6e9..f37fce9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.13", "license": "MIT", "dependencies": { - "@codex-storage/marketplace-ui-components": "^0.0.46", + "@codex-storage/marketplace-ui-components": "^0.0.47", "@codex-storage/sdk-js": "^0.0.16", "@sentry/browser": "^8.32.0", "@sentry/react": "^8.31.0", @@ -27,7 +27,7 @@ "@preact/preset-vite": "^2.9.1", "@svgr/plugin-svgo": "^8.1.0", "@tanstack/router-plugin": "^1.58.4", - "@types/node": "^22.7.5", + "@types/node": "^22.9.1", "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^8.7.0", @@ -42,7 +42,7 @@ "prettier": "^3.3.3", "react": "^18.3.1", "react-dom": "^18.3.1", - "typescript": "5.5.4", + "typescript": "^5.5.4", "vite": "^5.4.7", "vite-plugin-svgr": "^4.3.0", "vitest": "^2.1.4" @@ -395,9 +395,9 @@ } }, "node_modules/@codex-storage/marketplace-ui-components": { - "version": "0.0.46", - "resolved": "https://registry.npmjs.org/@codex-storage/marketplace-ui-components/-/marketplace-ui-components-0.0.46.tgz", - "integrity": "sha512-HEkuKOFjigOOkgY/If68WLXYN89+jJ1bCTwL8dNBt2N5QdFF/KmoKQ67X0SlOFAgxz6DdK4cskd07iLTiT5YUA==", + "version": "0.0.47", + "resolved": "https://registry.npmjs.org/@codex-storage/marketplace-ui-components/-/marketplace-ui-components-0.0.47.tgz", + "integrity": "sha512-dcnZsYEFB1IoEx9sSC3Z1gaReLf6SAFmFNvfnBs3U81mAFnOd/nGi7IUY/ipPyN9U+J8nrGlAOsWnzNiPlEOpA==", "engines": { "node": ">=18" }, diff --git a/package.json b/package.json index da305f9..3b9b81d 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "preview": "vite preview --host 127.0.0.1 --port 5173", "format": "prettier --write ./src", "test": "npx playwright test", - "test:unit": "vitest run" + "test:unit": "vitest run", + "knip": "knip" }, "keywords": [ "Codex", @@ -25,7 +26,7 @@ "React" ], "dependencies": { - "@codex-storage/marketplace-ui-components": "^0.0.46", + "@codex-storage/marketplace-ui-components": "^0.0.47", "@codex-storage/sdk-js": "^0.0.16", "@sentry/browser": "^8.32.0", "@sentry/react": "^8.31.0", @@ -43,7 +44,7 @@ "@preact/preset-vite": "^2.9.1", "@svgr/plugin-svgo": "^8.1.0", "@tanstack/router-plugin": "^1.58.4", - "@types/node": "^22.7.5", + "@types/node": "^22.9.1", "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^8.7.0", @@ -58,7 +59,7 @@ "prettier": "^3.3.3", "react": "^18.3.1", "react-dom": "^18.3.1", - "typescript": "5.5.4", + "typescript": "^5.5.4", "vite": "^5.4.7", "vite-plugin-svgr": "^4.3.0", "vitest": "^2.1.4" diff --git a/src/assets/icons/success-circle.svg b/src/assets/icons/success-circle.svg index 14218d4..b4e5e4a 100644 --- a/src/assets/icons/success-circle.svg +++ b/src/assets/icons/success-circle.svg @@ -1,7 +1,5 @@ diff --git a/src/components/AppBar/AppBar.tsx b/src/components/AppBar/AppBar.tsx index ec5a17f..322fba1 100644 --- a/src/components/AppBar/AppBar.tsx +++ b/src/components/AppBar/AppBar.tsx @@ -19,9 +19,12 @@ import HelpIcon from "../../assets/icons/help.svg?react"; import DisclaimerIcon from "../../assets/icons/disclaimer.svg?react"; import { WalletConnect } from "../WalletLogin/WalletLogin"; import { useNavigate } from "react-router-dom"; +import Logo from "../../assets/icons/logo.svg?react"; +import { useIsMobile } from "../../hooks/useMobile"; type Props = { onIconClick: () => void; + onExpanded: (val: boolean) => void; }; const icons: Record = { @@ -50,12 +53,13 @@ const descriptions: Record = { disclaimer: "Important information.", }; -export function AppBar({ onIconClick }: Props) { +export function AppBar({ onIconClick, onExpanded }: Props) { const online = useNetwork(); const queryClient = useQueryClient(); const codex = useCodexConnection(); const persistence = usePersistence(codex.enabled); const navigate = useNavigate(); + const isMobile = useIsMobile(); useEffect(() => { queryClient.invalidateQueries({ @@ -80,6 +84,12 @@ export function AppBar({ onIconClick }: Props) { ? "#3EE089" : "var(--codex-input-color-warning)"; + const icon = isMobile ? ( + onExpanded(true)}> + ) : ( + icons[title] + ); + return ( <>
- {icons[title]} + {icon}

{title}

diff --git a/src/components/AppBar/appBar.css b/src/components/AppBar/appBar.css index 460bb94..9c6d110 100644 --- a/src/components/AppBar/appBar.css +++ b/src/components/AppBar/appBar.css @@ -86,4 +86,10 @@ cursor: pointer; } } + + @media (max-width: 800px) { + aside { + display: none; + } + } } diff --git a/src/components/Availability/AvailabilityForm.css b/src/components/Availability/AvailabilityForm.css index 262e8c1..72fb2ed 100644 --- a/src/components/Availability/AvailabilityForm.css +++ b/src/components/Availability/AvailabilityForm.css @@ -20,6 +20,12 @@ .row { margin-bottom: 16px; + + @media screen and (max-width: 800px) { + & { + flex-direction: column; + } + } } .group { diff --git a/src/components/Availability/AvailabilityForm.tsx b/src/components/Availability/AvailabilityForm.tsx index 6f4c847..315dcf1 100644 --- a/src/components/Availability/AvailabilityForm.tsx +++ b/src/components/Availability/AvailabilityForm.tsx @@ -185,40 +185,38 @@ export function AvailabilityForm({
-
-
-
- - - - -
+
+
+ + + + +
-
- - - - -
+
+ + + +
diff --git a/src/components/Availability/AvailabilitySuccess.tsx b/src/components/Availability/AvailabilitySuccess.tsx index 9f515cf..9bc22c0 100644 --- a/src/components/Availability/AvailabilitySuccess.tsx +++ b/src/components/Availability/AvailabilitySuccess.tsx @@ -14,7 +14,7 @@ export function AvailabilitySuccess({ dispatch }: AvailabilityComponentProps) { return ( } + Icon={} title="Success" message="The new sale will appear in your sale list. You can safely close this dialog."> ); diff --git a/src/components/Availability/Sunburst.css b/src/components/Availability/Sunburst.css index 80d6ecd..84ce893 100644 --- a/src/components/Availability/Sunburst.css +++ b/src/components/Availability/Sunburst.css @@ -1,5 +1,3 @@ .sunburst { - height: 350px; - width: 350px; margin: auto; } diff --git a/src/components/Availability/Sunburst.tsx b/src/components/Availability/Sunburst.tsx index 1dfc447..c0950c5 100644 --- a/src/components/Availability/Sunburst.tsx +++ b/src/components/Availability/Sunburst.tsx @@ -4,7 +4,6 @@ import { Strings } from "../../utils/strings"; import { PrettyBytes } from "../../utils/bytes"; import { useEffect, useRef, useState } from "react"; import { CallbackDataParams, ECBasicOption } from "echarts/types/dist/shared"; -// Import the echarts core module, which provides the necessary interfaces for using echarts. import * as echarts from "echarts/core"; // Import bar charts, all suffixed with Chart @@ -19,7 +18,6 @@ type Props = { }; import { TooltipComponent } from "echarts/components"; - import { SVGRenderer } from "echarts/renderers"; echarts.use([SunburstChart, TooltipComponent, SVGRenderer]); @@ -97,80 +95,80 @@ export function Sunburst({ availabilities, space }: Props) { }; }); - const option: ECBasicOption = { - series: { - type: "sunburst", - data: [ - ...data, - { - name: "Space remaining", - value: - space.quotaMaxBytes - - space.quotaReservedBytes - - space.quotaUsedBytes, - children: [], - itemStyle: { - color: "#2F2F2F", - borderColor: "transparent", - }, - tooltip: { - backgroundColor: "#333", - textStyle: { - color: "#fff", - }, - formatter: (params: CallbackDataParams) => { - return ( - params.marker + - " Space remaining " + - PrettyBytes( - space.quotaMaxBytes - - space.quotaReservedBytes - - space.quotaUsedBytes - ) - ); - }, - }, - }, - ], - radius: [60, "90%"], - itemStyle: { - borderWidth: 1, - }, - label: { - show: false, - }, - levels: [ - {}, - { - r0: "35%", - r: "70%", - label: { - align: "right", - }, - }, - { - r0: "75%", - r: "85%", - itemStyle: {}, - label: { - position: "outside", - textShadowBlur: 5, - textShadowColor: "#333", - }, - downplay: { - label: { - opacity: 1, - }, - }, - }, - ], - }, - tooltip: { - // type: "item", - }, - }; - if (chart.current) { + const option: ECBasicOption = { + series: { + type: "sunburst", + data: [ + ...data, + { + name: "Space remaining", + value: + space.quotaMaxBytes - + space.quotaReservedBytes - + space.quotaUsedBytes, + children: [], + itemStyle: { + color: "#2F2F2F", + borderColor: "transparent", + }, + tooltip: { + backgroundColor: "#333", + textStyle: { + color: "#fff", + }, + formatter: (params: CallbackDataParams) => { + return ( + params.marker + + " Space remaining " + + PrettyBytes( + space.quotaMaxBytes - + space.quotaReservedBytes - + space.quotaUsedBytes + ) + ); + }, + }, + }, + ], + radius: [60, "90%"], + itemStyle: { + borderWidth: 1, + }, + label: { + show: false, + }, + levels: [ + {}, + { + r0: "35%", + r: "70%", + label: { + align: "right", + }, + }, + { + r0: "75%", + r: "85%", + itemStyle: {}, + label: { + position: "outside", + textShadowBlur: 5, + textShadowColor: "#333", + }, + downplay: { + label: { + opacity: 1, + }, + }, + }, + ], + }, + tooltip: { + // type: "item", + }, + }; + chart.current.setOption(option); // chart.current.off("click"); // chart.current.on("click", function (params) { @@ -190,5 +188,16 @@ export function Sunburst({ availabilities, space }: Props) { // }); } - return
; + const size = window.innerWidth > 500 ? 350 : 300; + + return ( +
+ ); } diff --git a/src/components/ConnectedAccount/ConnectedAccount.css b/src/components/ConnectedAccount/ConnectedAccount.css index 55f6c46..299f46d 100644 --- a/src/components/ConnectedAccount/ConnectedAccount.css +++ b/src/components/ConnectedAccount/ConnectedAccount.css @@ -2,7 +2,7 @@ border-radius: 8px; display: flex; flex-direction: column; - min-width: 550px; + /* min-width: 550px; */ main { flex: 1; diff --git a/src/components/CustomStateCellRender/CustomStateCellRender.tsx b/src/components/CustomStateCellRender/CustomStateCellRender.tsx index 9b3b33b..990552c 100644 --- a/src/components/CustomStateCellRender/CustomStateCellRender.tsx +++ b/src/components/CustomStateCellRender/CustomStateCellRender.tsx @@ -13,7 +13,7 @@ export const CustomStateCellRender = ({ state, message }: Props) => { pending: PurchaseStateIcon, submitted: PurchaseStateIcon, started: PurchaseStateIcon, - finished: SuccessCircleIcon, + finished: () => , cancelled: ErrorCircleIcon, errored: ErrorCircleIcon, }; diff --git a/src/components/Files/FileActions.css b/src/components/Files/FileActions.css index 242ffac..5a8d6b7 100644 --- a/src/components/Files/FileActions.css +++ b/src/components/Files/FileActions.css @@ -16,4 +16,10 @@ border: 1px solid #96969633; } } + + @media (max-width: 800px) { + .folder-button { + display: none; + } + } } diff --git a/src/components/Files/Files.css b/src/components/Files/Files.css index 68a5aa9..6c6e059 100644 --- a/src/components/Files/Files.css +++ b/src/components/Files/Files.css @@ -26,4 +26,15 @@ table thead tr th { background-color: #14141499; } + + @media (max-width: 800px) { + table th:nth-child(2), + table td:nth-child(2), + table th:nth-child(3), + table td:nth-child(3), + section, + .filters { + display: none; + } + } } diff --git a/src/components/Files/FolderButton.tsx b/src/components/Files/FolderButton.tsx index 551b0db..8b60849 100644 --- a/src/components/Files/FolderButton.tsx +++ b/src/components/Files/FolderButton.tsx @@ -42,7 +42,7 @@ export function FolderButton({ folders, onFolderToggle }: Props) { {folders.map(([folder, isActive]) => (
onFolderToggle(folder)}> {folder} - {isActive && } + {isActive && }
))}
diff --git a/src/components/HealthChecks/HealthChecks.tsx b/src/components/HealthChecks/HealthChecks.tsx index 555f79c..b10049d 100644 --- a/src/components/HealthChecks/HealthChecks.tsx +++ b/src/components/HealthChecks/HealthChecks.tsx @@ -116,7 +116,7 @@ export function HealthChecks({ online, onStepValid }: Props) { {isAddressInvalid ? ( ) : ( - + )}
@@ -129,7 +129,7 @@ export function HealthChecks({ online, onStepValid }: Props) { value={port} isInvalid={isPortInvalid} placeholder="8080"> - +
diff --git a/src/components/Menu/Menu.tsx b/src/components/Menu/Menu.tsx index 9e9e790..0f5f423 100644 --- a/src/components/Menu/Menu.tsx +++ b/src/components/Menu/Menu.tsx @@ -1,6 +1,6 @@ import { attributes } from "../../utils/attributes"; import "./menu.css"; -import { ComponentType, useState } from "react"; +import { ComponentType, useEffect } from "react"; import { classnames } from "../../utils/classnames"; import HomeIcon from "../../assets/icons/home.svg?react"; import ExpandIcon from "../../assets/icons/expand.svg?react"; @@ -19,11 +19,17 @@ import SettingsIcon from "../../assets/icons/settings.svg?react"; import HelpIcon from "../../assets/icons/help.svg?react"; import DisclaimerIcon from "../../assets/icons/disclaimer.svg?react"; import { NavLink } from "react-router-dom"; +import { useIsMobile } from "../../hooks/useMobile"; export type MenuItemComponentProps = { onClick: () => void; }; +export type Props = { + isExpanded: boolean; + onExpanded: (val: boolean) => void; +}; + export type MenuItem = | { type: "separator"; @@ -36,16 +42,28 @@ export type MenuItem = Component: ComponentType; }; -export function Menu() { - const [isExpanded, setIsExpanded] = useState(true); +export function Menu({ isExpanded, onExpanded }: Props) { + const isMobile = useIsMobile(); const onLogoClick = () => { if (isExpanded === false) { - setIsExpanded(true); + onExpanded(true); } }; - const onExpandMenu = () => setIsExpanded(!isExpanded); + useEffect(() => { + if (isMobile) { + onExpanded(false); + } + }, [isMobile, onExpanded]); + + const onExpandMenu = () => onExpanded(!isExpanded); + + const onClose = () => { + if (isMobile) { + onExpanded(false); + } + }; return ( <> @@ -64,35 +82,38 @@ export function Menu() {
- + Dashboard - + Wallet - + Files + data-title="Coming soon" + end> Nodes @@ -102,7 +123,8 @@ export function Menu() { Analytics @@ -112,45 +134,45 @@ export function Menu() { Devices
- + Purchases - + Host
- + Peers - + Log
- + Settings - + Help - + diff --git a/src/components/Menu/menu.css b/src/components/Menu/menu.css index 459116b..9466962 100644 --- a/src/components/Menu/menu.css +++ b/src/components/Menu/menu.css @@ -6,33 +6,25 @@ transition: left 0.25s; position: sticky; z-index: 10; - view-transition-name: main-menu; height: 100%; top: 0; transition: width 0.5s, font-size 0.5s, - left 0.05s; - min-width: 0; + left 0.5s; width: 272px; min-width: 80px; - @media (max-width: 1199px) { + @media (max-width: 800px) { & { - width: 80px; - .items { - a { - width: 26px; - gap: 0; - display: flex; - justify-content: center; + left: -300px; + position: fixed; + z-index: 12; + } - span + span { - font-size: 0; - display: none; - } - } - } + &[aria-expanded] { + left: 0px; + font-size: 12px; } } @@ -63,9 +55,11 @@ display: flex; justify-content: center; - span + span { - font-size: 0; - display: none; + @media (min-width: 801px) { + span + span { + font-size: 0; + display: none; + } } } } @@ -154,17 +148,17 @@ top: 115px; } - &:has(.active:nth-child(4))::before { + /* &:has(.active:nth-child(4))::before { top: 158px; - } - + } */ + /* &:has(.active:nth-child(5))::before { top: 201px; } &:has(.active:nth-child(6))::before { top: 244px; - } + } */ &:has(.active:nth-child(8))::before { top: 339px; @@ -227,7 +221,7 @@ margin-left: 6px; &:hover:not([aria-disabled="true"]), - &.active { + &.active:not([aria-disabled="true"]) { background-color: var(--codex-highlight-color); color: #c7c7c7; } @@ -244,10 +238,15 @@ span + span { display: inline-block; overflow: hidden; - min-width: 0; } - &.active span:first-child { + @media (min-width: 801px) { + span + span { + min-width: 0; + } + } + + &.active:not([aria-disabled="true"]) span:first-child { color: var(--codex-color-primary); } } diff --git a/src/components/Peers/PeersCard.tsx b/src/components/Peers/PeersCard.tsx index cd6f2d7..fc73f37 100644 --- a/src/components/Peers/PeersCard.tsx +++ b/src/components/Peers/PeersCard.tsx @@ -12,14 +12,14 @@ export function PeersCard() { const nodes = data?.table.nodes ?? []; const actives = PeerUtils.countActives(nodes); - const degrees = PeerUtils.calculareDegrees(nodes); + const percent = PeerUtils.calcularePercent(nodes); const good = PeerUtils.isGoodQuality(actives); return (
- +