mirror of
https://github.com/logos-storage/logos-storage-marketplace-ui.git
synced 2026-02-22 22:33:07 +00:00
Implements feedbacks on purchases table
This commit is contained in:
parent
1c2dc2c2f3
commit
8e3a4d91d9
@ -3,6 +3,10 @@
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.fileCell-cid {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.fileCell-subtitle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@ -32,23 +32,29 @@ export function FileCell({ requestId, purchaseCid }: Props) {
|
||||
});
|
||||
}, [requestId]);
|
||||
|
||||
let name = metadata.name;
|
||||
let name = metadata.name.slice(0, 10);
|
||||
|
||||
if (name.length > 10) {
|
||||
const [filename, ext] = metadata.name.split(".");
|
||||
name = filename.slice(0, 10) + "..." + ext;
|
||||
if (metadata.name.length > 10) {
|
||||
// const [filename, ext] = metadata.name.split(".");
|
||||
// name = filename.slice(0, 10) + "..." + ext;
|
||||
name += "...";
|
||||
}
|
||||
|
||||
const cidTruncated = cid.slice(0, 5) + ".".repeat(5) + cid.slice(-5);
|
||||
// const cidTruncated = cid.slice(0, 5) + ".".repeat(5) + cid.slice(-5);
|
||||
const cidTruncated = cid.slice(0, 10) + "...";
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="fileCell">
|
||||
<WebFileIcon type={metadata.mimetype} />
|
||||
<div>
|
||||
<span className="fileCell-title">{name}</span>
|
||||
<span className="fileCell-title">
|
||||
<Tooltip message={metadata.name}>{name}</Tooltip>
|
||||
</span>
|
||||
<span className="fileCell-subtitle">
|
||||
<Tooltip message={cid}>{cidTruncated}</Tooltip>
|
||||
<Tooltip message={cid}>
|
||||
<span className="fileCell-cid">{cidTruncated}</span>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,11 +1,3 @@
|
||||
.fileDetails {
|
||||
position: fixed;
|
||||
transition: transform 0.25s;
|
||||
background-color: var(--codex-background-secondary);
|
||||
z-index: 2;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.fileDetails-header {
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-bottom: 1px solid var(--codex-border-color);
|
||||
@ -17,10 +9,6 @@
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.files-backdrop {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.fileDetails-body {
|
||||
padding: 0;
|
||||
}
|
||||
@ -43,36 +31,3 @@
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1000px) {
|
||||
.fileDetails {
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
transform: translatex(300px);
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.fileDetails[aria-expanded] {
|
||||
transform: translatex(0);
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 999px) {
|
||||
.fileDetails {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
transform: translatey(1000px);
|
||||
left: 0;
|
||||
padding-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.fileDetails[aria-expanded] {
|
||||
transform: translatey(0);
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import { ButtonIcon, Button } from "@codex-storage/marketplace-ui-components";
|
||||
import {
|
||||
ButtonIcon,
|
||||
Button,
|
||||
Sheets,
|
||||
} from "@codex-storage/marketplace-ui-components";
|
||||
import { CodexDataContent } from "@codex-storage/sdk-js";
|
||||
import { X, DownloadIcon } from "lucide-react";
|
||||
import { attributes } from "../../utils/attributes";
|
||||
import { PrettyBytes } from "../../utils/bytes";
|
||||
import { ICON_SIZE } from "../../utils/constants";
|
||||
import { Dates } from "../../utils/dates";
|
||||
import { CidCopyButton } from "./CidCopyButton";
|
||||
import "./FileDetails.css";
|
||||
import { FileMetadata } from "../../utils/file-storage";
|
||||
import { DownloadIcon, X } from "lucide-react";
|
||||
|
||||
type Props = {
|
||||
details: (CodexDataContent & FileMetadata) | undefined;
|
||||
@ -16,7 +19,6 @@ type Props = {
|
||||
};
|
||||
|
||||
export function FileDetails({ onClose, details, expanded }: Props) {
|
||||
const attr = attributes({ "aria-expanded": expanded });
|
||||
const url = import.meta.env.VITE_CODEX_API_URL + "/api/codex/v1/data/";
|
||||
|
||||
const Icon = () => <X size={ICON_SIZE} onClick={onClose} />;
|
||||
@ -24,13 +26,8 @@ export function FileDetails({ onClose, details, expanded }: Props) {
|
||||
const onDownload = () => window.open(url + details?.cid, "_target");
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="files-backdrop backdrop"
|
||||
onClick={onClose}
|
||||
{...attr}></div>
|
||||
|
||||
<div className="fileDetails" {...attr}>
|
||||
<Sheets open={expanded} onClose={onClose}>
|
||||
<>
|
||||
{details && (
|
||||
<>
|
||||
<div className="fileDetails-header">
|
||||
@ -86,7 +83,7 @@ export function FileDetails({ onClose, details, expanded }: Props) {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
</>
|
||||
</Sheets>
|
||||
);
|
||||
}
|
||||
|
||||
@ -69,42 +69,3 @@
|
||||
.files-header {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.files-headerTabs {
|
||||
display: flex;
|
||||
margin-top: 1rem;
|
||||
gap: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.files-headerTabs::after {
|
||||
width: 100%;
|
||||
background-color: var(--codex-background-light);
|
||||
content: " ";
|
||||
position: absolute;
|
||||
height: 2px;
|
||||
top: 11px;
|
||||
top: 31px;
|
||||
}
|
||||
|
||||
.files-headerTab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
padding-bottom: 1rem;
|
||||
cursor: pointer;
|
||||
transition: 0.35s opacity;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.files-headerTab:not(.files-headerTab--active) {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.files-headerTab:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.files-headerTab--active {
|
||||
border-bottom: 2px solid var(--codex-color-contrast);
|
||||
}
|
||||
|
||||
@ -8,9 +8,9 @@ import {
|
||||
ButtonIcon,
|
||||
EmptyPlaceholder,
|
||||
WebFileIcon,
|
||||
Tabs,
|
||||
} from "@codex-storage/marketplace-ui-components";
|
||||
import { FileDetails } from "./FileDetails.tsx";
|
||||
import { classnames } from "../../utils/classnames.ts";
|
||||
import { FavoriteStorage } from "../../utils/favorite-storage.tsx";
|
||||
import { useData } from "../../hooks/useData.tsx";
|
||||
|
||||
@ -33,7 +33,7 @@ export function Files() {
|
||||
const cid = useRef<string | null>("");
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [favorites, setFavorites] = useState<string[]>([]);
|
||||
const [selected, setSelected] = useState<"all" | "favorites">("all");
|
||||
const [index, setIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
FavoriteStorage.list().then((cids) => setFavorites(cids));
|
||||
@ -47,8 +47,7 @@ export function Files() {
|
||||
}, SIDE_DURATION);
|
||||
};
|
||||
|
||||
const onSelected = () =>
|
||||
setSelected(selected === "all" ? "favorites" : "all");
|
||||
const onTabChange = (i: number) => setIndex(i);
|
||||
|
||||
const onDetails = (id: string) => {
|
||||
cid.current = id;
|
||||
@ -67,7 +66,7 @@ export function Files() {
|
||||
|
||||
const items = [];
|
||||
|
||||
if (selected === "favorites") {
|
||||
if (index === 1) {
|
||||
items.push(...files.filter((f) => favorites.includes(f.cid)));
|
||||
} else {
|
||||
items.push(...files);
|
||||
@ -81,27 +80,19 @@ export function Files() {
|
||||
<div className="files">
|
||||
<div className="files-header">
|
||||
<div className="files-title">Files</div>
|
||||
<div className="files-headerTabs">
|
||||
<div
|
||||
className={classnames(
|
||||
["files-headerTab"],
|
||||
["files-headerTab--active", selected === "all"]
|
||||
)}
|
||||
onClick={onSelected}>
|
||||
<FilesIcon size={"1rem"}></FilesIcon>
|
||||
<span>All files</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={classnames(
|
||||
["files-headerTab"],
|
||||
["files-headerTab--active", selected === "favorites"]
|
||||
)}
|
||||
onClick={onSelected}>
|
||||
<Star size={"1rem"}></Star>
|
||||
<span>Favorites</span>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs
|
||||
onTabChange={onTabChange}
|
||||
tabIndex={index}
|
||||
tabs={[
|
||||
{
|
||||
label: "All files",
|
||||
Icon: () => <FilesIcon size={"1rem"}></FilesIcon>,
|
||||
},
|
||||
{
|
||||
label: "Favorites",
|
||||
Icon: () => <Star size={"1rem"}></Star>,
|
||||
},
|
||||
]}></Tabs>
|
||||
</div>
|
||||
|
||||
<div className="files-fileBody">
|
||||
|
||||
7
src/components/TruncateCell/TruncateCell.css
Normal file
7
src/components/TruncateCell/TruncateCell.css
Normal file
@ -0,0 +1,7 @@
|
||||
.truncateCell {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.truncateCell .tooltip:hover:after {
|
||||
left: -33%;
|
||||
}
|
||||
20
src/components/TruncateCell/TruncateCell.tsx
Normal file
20
src/components/TruncateCell/TruncateCell.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { Tooltip } from "@codex-storage/marketplace-ui-components";
|
||||
import "./TruncateCell.css";
|
||||
|
||||
type Props = {
|
||||
value: string;
|
||||
};
|
||||
|
||||
export function TruncateCell({ value }: Props) {
|
||||
if (value.length <= 10) {
|
||||
return <span>{value}</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="truncateCell">
|
||||
<Tooltip message={value}>
|
||||
<span>{value.slice(0, 10) + "..."}</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -4,6 +4,7 @@ import { CodexSdk } from "../../sdk/codex";
|
||||
import { Plus } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
BreakCell,
|
||||
Button,
|
||||
Cell,
|
||||
Spinner,
|
||||
@ -17,6 +18,7 @@ import { CustomStateCellRender } from "../../components/CustomStateCellRender/Cu
|
||||
import prettyMilliseconds from "pretty-ms";
|
||||
import { ErrorBoundary } from "../../components/ErrorBoundary/ErrorBoundary";
|
||||
import { Promises } from "../../utils/promises";
|
||||
import { TruncateCell } from "../../components/TruncateCell/TruncateCell";
|
||||
|
||||
const Purchases = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
@ -40,7 +42,8 @@ const Purchases = () => {
|
||||
}
|
||||
|
||||
const headers = [
|
||||
"cid",
|
||||
"file",
|
||||
"request id",
|
||||
"duration",
|
||||
"slots",
|
||||
"reward",
|
||||
@ -58,10 +61,11 @@ const Purchases = () => {
|
||||
|
||||
return [
|
||||
<FileCell requestId={r.id} purchaseCid={r.content.cid} index={index} />,
|
||||
<Cell value={prettyMilliseconds(duration)} />,
|
||||
<Cell value={ask.slots + " hosts"} />,
|
||||
<Cell value={ask.reward + " tokens"} />,
|
||||
<Cell value={"Every " + prettyMilliseconds(pf)} />,
|
||||
<TruncateCell value={r.id} />,
|
||||
<Cell value={prettyMilliseconds(duration, { verbose: true })} />,
|
||||
<Cell value={ask.slots.toString()} />,
|
||||
<Cell value={ask.reward + " CDX"} />,
|
||||
<Cell value={prettyMilliseconds(pf, { verbose: true })} />,
|
||||
<CustomStateCellRender state={p.state} message={p.error} />,
|
||||
];
|
||||
}) || [];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user