mirror of
https://github.com/logos-storage/logos-storage-marketplace-ui.git
synced 2026-01-04 06:23:08 +00:00
Update files
This commit is contained in:
parent
9e6aa37981
commit
301a6720e8
8
package-lock.json
generated
8
package-lock.json
generated
@ -9,7 +9,7 @@
|
||||
"version": "0.0.7",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codex-storage/marketplace-ui-components": "^0.0.33",
|
||||
"@codex-storage/marketplace-ui-components": "^0.0.34",
|
||||
"@codex-storage/sdk-js": "^0.0.15",
|
||||
"@sentry/browser": "^8.32.0",
|
||||
"@sentry/react": "^8.31.0",
|
||||
@ -379,9 +379,9 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@codex-storage/marketplace-ui-components": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/@codex-storage/marketplace-ui-components/-/marketplace-ui-components-0.0.33.tgz",
|
||||
"integrity": "sha512-Au/k1FNygejrcHNLdgghgxm8VuERb2bQsI0JjGaIdk4LGgTS0EuMCd0Y6fo6VuZeyuVPN/kFSWMVPBO5xdFEEw==",
|
||||
"version": "0.0.34",
|
||||
"resolved": "https://registry.npmjs.org/@codex-storage/marketplace-ui-components/-/marketplace-ui-components-0.0.34.tgz",
|
||||
"integrity": "sha512-WRSgQU/OiERKBqpUIq95tgz1jKizM8fd28hottD4Ra8Z0gHkFZThxoVGad2pq96ha7U/Q/U+VEW+f+t4Z251rg==",
|
||||
"dependencies": {
|
||||
"lucide-react": "^0.453.0"
|
||||
},
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
"React"
|
||||
],
|
||||
"dependencies": {
|
||||
"@codex-storage/marketplace-ui-components": "^0.0.33",
|
||||
"@codex-storage/marketplace-ui-components": "^0.0.34",
|
||||
"@codex-storage/sdk-js": "^0.0.15",
|
||||
"@sentry/browser": "^8.32.0",
|
||||
"@sentry/react": "^8.31.0",
|
||||
|
||||
15
src/components/CloseIcon/CloseIcon.tsx
Normal file
15
src/components/CloseIcon/CloseIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function CloseIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="10"
|
||||
height="10"
|
||||
viewBox="0 0 10 10"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5.00005 3.93955L8.71255 0.227051L9.77305 1.28755L6.06055 5.00005L9.77305 8.71255L8.71255 9.77305L5.00005 6.06055L1.28755 9.77305L0.227051 8.71255L3.93955 5.00005L0.227051 1.28755L1.28755 0.227051L5.00005 3.93955Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -9,13 +9,13 @@ export function WalletLines() {
|
||||
opacity="0.5"
|
||||
d="M16.8017 44.5368H0.231579C0.103681 44.5368 0 44.6405 0 44.7684C0 44.8963 0.103681 45 0.231579 45H679C681.209 45 683 43.2091 683 41V5C683 2.79086 681.209 1 679 1H644.034C643.689 1 643.345 1.04472 643.011 1.13303L560.776 22.8885C560.443 22.9768 560.099 23.0215 559.753 23.0215H532.049C531.504 23.0215 530.964 22.91 530.463 22.6937L480.993 1.32786C480.493 1.11157 479.953 1 479.408 1H428.397C427.753 1 427.117 1.15593 426.546 1.45451L386.125 22.567C385.553 22.8656 384.945 23.0215 384.3 23.0215H317.645C317.177 23.0215 316.73 23.1039 316.289 23.2648L274.515 38.5387C274.075 38.6996 273.61 38.782 273.141 38.782H244.777C244.302 38.782 243.831 38.6975 243.386 38.5324L202.234 23.2711C201.789 23.1061 201.318 23.0215 200.843 23.0215H164.28C163.623 23.0215 162.977 22.8599 162.397 22.5508L122.879 1.47072C122.299 1.16166 121.653 1 120.996 1H73.6247C72.7112 1 71.8252 1.31267 71.1141 1.88603L19.3123 43.6508C18.6011 44.2242 17.7152 44.5368 16.8017 44.5368Z"
|
||||
fill="url(#paint0_linear_401_31774)"
|
||||
fill-opacity="0.06"
|
||||
fillOpacity="0.06"
|
||||
/>
|
||||
<path
|
||||
opacity="0.6"
|
||||
d="M0 45H15.3667C17.2079 45 18.9928 44.3649 20.4201 43.2019L70.0062 2.79813C71.4336 1.63509 73.2184 1 75.0596 1H119.977C121.302 1 122.607 1.32923 123.773 1.9581L161.502 22.2977C162.669 22.9266 163.973 23.2558 165.299 23.2558H200.111C201.07 23.2558 202.021 23.4282 202.919 23.7647L242.701 38.675C243.599 39.0115 244.55 39.1839 245.509 39.1839H272.419C273.365 39.1839 274.304 39.016 275.192 38.688L315.613 23.7517C316.5 23.4237 317.424 23.2558 318.37 23.2558C336.899 23.2558 374.308 23.2558 383.286 23.2558C384.587 23.2558 385.856 22.9382 387.007 22.3306L425.663 1.92521C426.814 1.31759 428.096 1 429.398 1H478.564C479.666 1 480.755 1.22743 481.765 1.66803L529.692 22.5878C530.701 23.0284 531.791 23.2558 532.892 23.2558H559.222C559.92 23.2558 560.615 23.1645 561.289 22.9843L642.499 1.27147C643.173 1.09126 643.867 1 644.565 1L683 1"
|
||||
stroke="#3EE089"
|
||||
stroke-width="2"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
@ -25,8 +25,8 @@ export function WalletLines() {
|
||||
x2="341.5"
|
||||
y2="45"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#CFD1D3" />
|
||||
<stop offset="1" stop-color="#E4E5E7" stop-opacity="0" />
|
||||
<stop stopColor="#CFD1D3" />
|
||||
<stop offset="1" stopColor="#E4E5E7" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
15
src/components/Files/AllFilesIcon.tsx
Normal file
15
src/components/Files/AllFilesIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function AllFilesIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="14"
|
||||
height="16"
|
||||
viewBox="0 0 14 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3.25 3.5V1.25C3.25 1.05109 3.32902 0.860322 3.46967 0.71967C3.61032 0.579018 3.80109 0.5 4 0.5H13C13.1989 0.5 13.3897 0.579018 13.5303 0.71967C13.671 0.860322 13.75 1.05109 13.75 1.25V11.75C13.75 11.9489 13.671 12.1397 13.5303 12.2803C13.3897 12.421 13.1989 12.5 13 12.5H10.75V14.75C10.75 15.164 10.4125 15.5 9.99475 15.5H1.00525C0.906345 15.5006 0.808298 15.4816 0.716742 15.4442C0.625186 15.4068 0.541925 15.3517 0.471744 15.282C0.401563 15.2123 0.345845 15.1294 0.307791 15.0381C0.269737 14.9468 0.250097 14.8489 0.25 14.75L0.25225 4.25C0.25225 3.836 0.58975 3.5 1.0075 3.5H3.25ZM4.75 3.5H10.75V11H12.25V2H4.75V3.5ZM3.25 7.25V8.75H7.75V7.25H3.25ZM3.25 10.25V11.75H7.75V10.25H3.25Z"
|
||||
fill="#6FCB94"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
15
src/components/Files/ArchiveIcon.tsx
Normal file
15
src/components/Files/ArchiveIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function ArchiveIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.4 3.8001C13.5591 3.8001 13.7117 3.86331 13.8243 3.97583C13.9368 4.08836 14 4.24097 14 4.4001V12.8001C14 12.9592 13.9368 13.1118 13.8243 13.2244C13.7117 13.3369 13.5591 13.4001 13.4 13.4001H2.6C2.44087 13.4001 2.28826 13.3369 2.17574 13.2244C2.06321 13.1118 2 12.9592 2 12.8001V3.2001C2 3.04097 2.06321 2.88836 2.17574 2.77583C2.28826 2.66331 2.44087 2.6001 2.6 2.6001H7.0484L8.2484 3.8001H10.4V5.0001H11.6V3.8001H13.4ZM11.6 8.6001H10.4V9.8001H9.2V11.6001H11.6V8.6001ZM10.4 7.4001H9.2V8.6001H10.4V7.4001ZM11.6 6.2001H10.4V7.4001H11.6V6.2001ZM10.4 5.0001H9.2V6.2001H10.4V5.0001Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { useRef, useState } from "react";
|
||||
import { COPY_DURATION, ICON_SIZE } from "../../utils/constants";
|
||||
import { Copy } from "lucide-react";
|
||||
import { COPY_DURATION } from "../../utils/constants";
|
||||
import { Button } from "@codex-storage/marketplace-ui-components";
|
||||
import { CoypIcon } from "./CopyIcon";
|
||||
|
||||
type CopyButtonProps = {
|
||||
cid: string;
|
||||
@ -27,13 +27,11 @@ export function CidCopyButton({ cid }: CopyButtonProps) {
|
||||
|
||||
const label = copied ? "Copied !" : "Copy CID";
|
||||
|
||||
const Icon = () => <Copy size={ICON_SIZE} />;
|
||||
|
||||
return (
|
||||
<Button
|
||||
label={label}
|
||||
variant="outline"
|
||||
onClick={onCopy}
|
||||
Icon={Icon}></Button>
|
||||
Icon={CoypIcon}></Button>
|
||||
);
|
||||
}
|
||||
|
||||
15
src/components/Files/CopyIcon.tsx
Normal file
15
src/components/Files/CopyIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function CoypIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="14"
|
||||
height="16"
|
||||
viewBox="0 0 14 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3 3.5V1.25C3 1.05109 3.07902 0.860322 3.21967 0.71967C3.36032 0.579018 3.55109 0.5 3.75 0.5H12.75C12.9489 0.5 13.1397 0.579018 13.2803 0.71967C13.421 0.860322 13.5 1.05109 13.5 1.25V11.75C13.5 11.9489 13.421 12.1397 13.2803 12.2803C13.1397 12.421 12.9489 12.5 12.75 12.5H10.5V14.75C10.5 15.164 10.1625 15.5 9.74475 15.5H0.75525C0.656345 15.5006 0.558298 15.4816 0.466742 15.4442C0.375186 15.4068 0.291925 15.3517 0.221744 15.282C0.151563 15.2123 0.0958447 15.1294 0.0577907 15.0381C0.0197367 14.9468 9.70307e-05 14.8489 0 14.75L0.00225002 4.25C0.00225002 3.836 0.33975 3.5 0.7575 3.5H3ZM1.50225 5L1.5 14H9V5H1.50225ZM4.5 3.5H10.5V11H12V2H4.5V3.5Z"
|
||||
fill="#99A0AE"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
15
src/components/Files/DocumentIcon.tsx
Normal file
15
src/components/Files/DocumentIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function DocumentIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13.4001 6.2V13.3958C13.4007 13.4746 13.3857 13.5527 13.356 13.6257C13.3264 13.6987 13.2827 13.7652 13.2273 13.8213C13.172 13.8774 13.1062 13.9221 13.0336 13.9527C12.961 13.9834 12.8831 13.9995 12.8043 14H3.1959C3.03799 14 2.88653 13.9373 2.77482 13.8257C2.6631 13.7141 2.60026 13.5627 2.6001 13.4048V2.5952C2.6001 2.273 2.8683 2 3.1989 2H9.2001V5.6C9.2001 5.75913 9.26331 5.91174 9.37583 6.02426C9.48836 6.13679 9.64097 6.2 9.8001 6.2H13.4001ZM13.4001 5H10.4001V2.0018L13.4001 5ZM5.6001 5V6.2H7.4001V5H5.6001ZM5.6001 7.4V8.6H10.4001V7.4H5.6001ZM5.6001 9.8V11H10.4001V9.8H5.6001Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
15
src/components/Files/DownloadIcon.tsx
Normal file
15
src/components/Files/DownloadIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function DownloadIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="14"
|
||||
viewBox="0 0 16 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M2 12.25H14V7H15.5V13C15.5 13.1989 15.421 13.3897 15.2803 13.5303C15.1397 13.671 14.9489 13.75 14.75 13.75H1.25C1.05109 13.75 0.860322 13.671 0.71967 13.5303C0.579018 13.3897 0.5 13.1989 0.5 13V7H2V12.25ZM9.5 4.75H13.25L8 10L2.75 4.75H6.5V0.25H9.5V4.75Z"
|
||||
fill="#969696"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
15
src/components/Files/FavoriteIcon.tsx
Normal file
15
src/components/Files/FavoriteIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function FavoriteIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="15"
|
||||
viewBox="0 0 16 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M8.00018 11.75L3.59168 14.4425L4.79018 9.4175L0.867676 6.0575L6.01643 5.645L8.00018 0.875L9.98393 5.645L15.1334 6.0575L11.2102 9.4175L12.4087 14.4425L8.00018 11.75Z"
|
||||
fill="#969696"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
19
src/components/Files/FileActions.css
Normal file
19
src/components/Files/FileActions.css
Normal file
@ -0,0 +1,19 @@
|
||||
.file-actions {
|
||||
> div {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border: 1px solid var(--codex-border-color);
|
||||
border-radius: var(--codex-border-radius);
|
||||
padding: 0.5rem;
|
||||
background-color: #14141499;
|
||||
gap: 8px;
|
||||
padding: 10px;
|
||||
|
||||
.button-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background-color: #2f2f2f;
|
||||
border: 1px solid #96969633;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,10 @@
|
||||
import { ButtonIcon, Cell } from "@codex-storage/marketplace-ui-components";
|
||||
import { Download, ReceiptText } from "lucide-react";
|
||||
import { ICON_SIZE } from "../../utils/constants";
|
||||
import { FolderButton } from "./FolderButton";
|
||||
import { CodexDataContent } from "@codex-storage/sdk-js";
|
||||
import { CodexSdk } from "../../sdk/codex";
|
||||
import "./FileActions.css";
|
||||
import { DownloadIcon } from "./DownloadIcon";
|
||||
import { InfoFileIcon } from "./InfoFileIcon";
|
||||
|
||||
type Props = {
|
||||
content: CodexDataContent;
|
||||
@ -21,15 +22,12 @@ export function FileActions({
|
||||
const url = CodexSdk.url() + "/api/codex/v1/data/";
|
||||
|
||||
return (
|
||||
<Cell>
|
||||
<div className="files-fileActions">
|
||||
<Cell className="file-actions">
|
||||
<div>
|
||||
<ButtonIcon
|
||||
variant="small"
|
||||
animation="bounce"
|
||||
onClick={() => window.open(url + content.cid, "_blank")}
|
||||
Icon={(props) => (
|
||||
<Download size={ICON_SIZE} {...props} />
|
||||
)}></ButtonIcon>
|
||||
Icon={DownloadIcon}></ButtonIcon>
|
||||
|
||||
<FolderButton
|
||||
folders={folders.map(([folder, files]) => [
|
||||
@ -42,7 +40,7 @@ export function FileActions({
|
||||
<ButtonIcon
|
||||
variant="small"
|
||||
onClick={() => onDetails(content.cid)}
|
||||
Icon={() => <ReceiptText size={ICON_SIZE} />}></ButtonIcon>
|
||||
Icon={InfoFileIcon}></ButtonIcon>
|
||||
</div>
|
||||
</Cell>
|
||||
);
|
||||
|
||||
22
src/components/Files/FileCell.css
Normal file
22
src/components/Files/FileCell.css
Normal file
@ -0,0 +1,22 @@
|
||||
.file-cell {
|
||||
small {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
|
||||
> div {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.button-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background-color: #14141499;
|
||||
border: 1px solid #96969633;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ import {
|
||||
import { CodexDataContent } from "@codex-storage/sdk-js";
|
||||
import { Copy } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import "./FileCell.css";
|
||||
|
||||
type Props = {
|
||||
content: CodexDataContent;
|
||||
@ -22,23 +23,23 @@ export function FileCell({ content }: Props) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Cell>
|
||||
<div className="files-cell-file">
|
||||
<Cell className="file-cell">
|
||||
<div>
|
||||
<WebFileIcon type={content.manifest.mimetype || ""} />
|
||||
|
||||
<div>
|
||||
<b>{content.manifest.filename}</b>
|
||||
<div className="files-fileMeta">
|
||||
<small className="files-fileMeta-cid">{content.cid}</small>
|
||||
<ButtonIcon
|
||||
variant="small"
|
||||
onClick={() => onCopy(content.cid)}
|
||||
animation="buzz"
|
||||
Icon={(props) => (
|
||||
<Copy size={"1rem"} {...props} />
|
||||
)}></ButtonIcon>
|
||||
</div>
|
||||
<p>
|
||||
<b>{content.manifest.filename}</b>
|
||||
</p>
|
||||
<p>
|
||||
<small>{content.cid}</small>
|
||||
</p>
|
||||
</div>
|
||||
<ButtonIcon
|
||||
variant="small"
|
||||
onClick={() => onCopy(content.cid)}
|
||||
animation="buzz"
|
||||
Icon={(props) => <Copy size={"1rem"} {...props} />}></ButtonIcon>
|
||||
</div>
|
||||
|
||||
<Toast message={toast.message} time={toast.time} variant={"success"} />
|
||||
|
||||
@ -1,16 +1,118 @@
|
||||
.fileDetails-header {
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-bottom: 1px solid var(--codex-border-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.file-details {
|
||||
background-color: #232323;
|
||||
border-left: 1px solid #96969633;
|
||||
border-top-left-radius: 16px;
|
||||
border-bottom-left-radius: 16px;
|
||||
padding: 16px;
|
||||
height: 100%;
|
||||
|
||||
.fileDetails-headerTitle {
|
||||
flex-grow: 1;
|
||||
}
|
||||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: Inter;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
letter-spacing: -0.011em;
|
||||
text-align: left;
|
||||
|
||||
.fileDetails-body {
|
||||
padding: 0;
|
||||
span {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.button-icon {
|
||||
background-color: #2f2f2f;
|
||||
border: 1px solid #96969633;
|
||||
}
|
||||
}
|
||||
|
||||
.preview {
|
||||
background-color: #14141499;
|
||||
border: 1px solid #69696933;
|
||||
height: 200px;
|
||||
margin: auto;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
figure {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
|
||||
font-family: Inter;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
letter-spacing: -0.011em;
|
||||
text-align: left;
|
||||
color: #ffffff33;
|
||||
|
||||
p {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
li {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
display: grid;
|
||||
padding: 8px 0;
|
||||
align-items: center;
|
||||
|
||||
p:first-child {
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
line-height: 20px;
|
||||
letter-spacing: -0.006em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
p:nth-child(2) {
|
||||
grid-column: span 2 / span 2;
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
letter-spacing: -0.006em;
|
||||
text-align: left;
|
||||
color: #ffffffcc;
|
||||
}
|
||||
|
||||
&:last-child p:nth-child(2) {
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
letter-spacing: -0.006em;
|
||||
text-align: left;
|
||||
|
||||
color: #6beca1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
padding: 16px 0;
|
||||
border-bottom: 1px solid #96969633;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fileDetails-grid {
|
||||
|
||||
@ -2,18 +2,20 @@ import {
|
||||
ButtonIcon,
|
||||
Button,
|
||||
Sheets,
|
||||
WebFileIcon,
|
||||
} from "@codex-storage/marketplace-ui-components";
|
||||
import { CodexDataContent } from "@codex-storage/sdk-js";
|
||||
import { PrettyBytes } from "../../utils/bytes";
|
||||
import { ICON_SIZE } from "../../utils/constants";
|
||||
import { Dates } from "../../utils/dates";
|
||||
import { CidCopyButton } from "./CidCopyButton";
|
||||
import "./FileDetails.css";
|
||||
import { DownloadIcon, X } from "lucide-react";
|
||||
import { CodexSdk } from "../../sdk/codex";
|
||||
import { Files } from "../../utils/files";
|
||||
import { useEffect, useState } from "react";
|
||||
import { WebStorage } from "../../utils/web-storage";
|
||||
import { FileDetailsIcon } from "./FileDetailsIcon";
|
||||
import { CloseIcon } from "../CloseIcon/CloseIcon";
|
||||
import { DownloadIcon } from "./DownloadIcon";
|
||||
|
||||
type Props = {
|
||||
details: CodexDataContent | null;
|
||||
@ -37,84 +39,85 @@ export function FileDetails({ onClose, details }: Props) {
|
||||
|
||||
const url = CodexSdk.url() + "/api/codex/v1/data/";
|
||||
|
||||
const Icon = () => <X size={ICON_SIZE} onClick={onClose} />;
|
||||
|
||||
const onDownload = () => window.open(url + details?.cid, "_target");
|
||||
|
||||
return (
|
||||
<Sheets open={!!details} onClose={onClose}>
|
||||
<>
|
||||
{details && (
|
||||
<>
|
||||
<div className="fileDetails-header">
|
||||
<b className="fileDetails-headerTitle">File details</b>
|
||||
<ButtonIcon variant="small" Icon={Icon}></ButtonIcon>
|
||||
<div className="file-details">
|
||||
<header>
|
||||
<FileDetailsIcon></FileDetailsIcon>
|
||||
<span>File details</span>
|
||||
<ButtonIcon
|
||||
onClick={onClose}
|
||||
variant="small"
|
||||
Icon={CloseIcon}></ButtonIcon>
|
||||
</header>
|
||||
|
||||
<div className="preview">
|
||||
{Files.isImage(details.manifest.mimetype) ? (
|
||||
<img src={url + details.cid} />
|
||||
) : (
|
||||
<figure>
|
||||
<WebFileIcon
|
||||
type={details.manifest.mimetype || ""}
|
||||
size={32}
|
||||
/>
|
||||
<p>File Preview not available.</p>
|
||||
</figure>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{Files.isImage(details.manifest.mimetype) && (
|
||||
<div className="fileDetails-imageContainer">
|
||||
<img className="fileDetails-image" src={url + details.cid} />
|
||||
</div>
|
||||
)}
|
||||
<ul>
|
||||
<li>
|
||||
<p>CID:</p>
|
||||
<p>{details.cid}</p>
|
||||
</li>
|
||||
|
||||
<div className="fileDetails-body">
|
||||
<div className="fileDetails-grid">
|
||||
<p className="text-secondary">CID:</p>
|
||||
<p className="fileDetails-gridColumn">{details.cid}</p>
|
||||
</div>
|
||||
<li>
|
||||
<p>File name:</p>
|
||||
<p>{details.manifest.filename}</p>
|
||||
</li>
|
||||
|
||||
<div className="fileDetails-grid">
|
||||
<p className="text-secondary">File name:</p>
|
||||
<p className="fileDetails-gridColumn">
|
||||
{details.manifest.filename}
|
||||
<li>
|
||||
<p>Date:</p>
|
||||
<p>{Dates.format(details.manifest.uploadedAt).toString()}</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>Mimetype:</p>
|
||||
<p>{details.manifest.mimetype}</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>Size:</p>
|
||||
<p>{PrettyBytes(details.manifest.datasetSize)}</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>Protected:</p>
|
||||
<p>{details.manifest.protected ? "Yes" : "No"}</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p>Used:</p>
|
||||
<p>
|
||||
<b>{purchases} </b> purchase(s)
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div className="fileDetails-grid">
|
||||
<p className="text-secondary">Date:</p>
|
||||
<p className="fileDetails-gridColumn">
|
||||
{Dates.format(details.manifest.uploadedAt).toString()}
|
||||
</p>
|
||||
</div>
|
||||
<div className="buttons">
|
||||
<CidCopyButton cid={details.cid} />
|
||||
|
||||
<div className="fileDetails-grid">
|
||||
<p className="text-secondary">Mimetype:</p>
|
||||
<p className="fileDetails-gridColumn">
|
||||
{details.manifest.mimetype}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="fileDetails-grid">
|
||||
<p className="text-secondary">Size:</p>
|
||||
<p className="fileDetails-gridColumn">
|
||||
{PrettyBytes(details.manifest.datasetSize)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="fileDetails-grid">
|
||||
<p className="text-secondary">Protected:</p>
|
||||
<p className="fileDetails-gridColumn">
|
||||
{details.manifest.protected ? "Yes" : "No"}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="fileDetails-grid">
|
||||
<p className="text-secondary">Used:</p>
|
||||
<p className="fileDetails-gridColumn">
|
||||
{purchases + " purchase(s)"}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="fileDetails-actions">
|
||||
<CidCopyButton cid={details.cid} />
|
||||
|
||||
<Button
|
||||
Icon={() => <DownloadIcon size={ICON_SIZE} />}
|
||||
label="Download"
|
||||
onClick={onDownload}></Button>
|
||||
</div>
|
||||
<Button
|
||||
Icon={DownloadIcon}
|
||||
label="Download"
|
||||
variant="outline"
|
||||
onClick={onDownload}></Button>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</Sheets>
|
||||
|
||||
15
src/components/Files/FileDetailsIcon.tsx
Normal file
15
src/components/Files/FileDetailsIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function FileDetailsIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M6.29993 0.00270002V0H16.1981C16.6949 0 17.0999 0.4095 17.0999 0.8928V17.1072C17.0997 17.3441 17.0054 17.5712 16.8378 17.7386C16.6703 17.906 16.4431 18 16.2062 18H1.79362C1.67543 17.9992 1.55856 17.9751 1.44969 17.9291C1.34081 17.8831 1.24206 17.8161 1.15907 17.7319C1.07608 17.6478 1.01048 17.5481 0.966016 17.4386C0.921552 17.3291 0.899094 17.2119 0.899925 17.0937V5.4L6.29993 0.00270002ZM3.44692 5.4H6.29993V2.547L3.44692 5.4ZM8.09993 1.8V6.3C8.09993 6.53869 8.0051 6.76761 7.83632 6.9364C7.66754 7.10518 7.43862 7.2 7.19993 7.2H2.69992V16.2H15.2999V1.8H8.09993Z"
|
||||
fill="#969696"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
35
src/components/Files/FileFilters.css
Normal file
35
src/components/Files/FileFilters.css
Normal file
@ -0,0 +1,35 @@
|
||||
.filter {
|
||||
padding: 4px 8px;
|
||||
gap: 8px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #96969633;
|
||||
background-color: #2f2f2f;
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
text-align: left;
|
||||
color: #969696;
|
||||
text-transform: capitalize;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: box-shadow 0.35s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 0 3px var(--codex-border-color);
|
||||
}
|
||||
|
||||
svg {
|
||||
color: #969696;
|
||||
}
|
||||
|
||||
&.filter--active {
|
||||
border-color: var(--codex-color-primary);
|
||||
color: var(--codex-color-primary);
|
||||
|
||||
svg {
|
||||
color: var(--codex-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,11 @@
|
||||
import { CodexDataContent } from "@codex-storage/sdk-js";
|
||||
import { Files } from "../../utils/files";
|
||||
import { classnames } from "../../utils/classnames";
|
||||
import { Check } from "lucide-react";
|
||||
import "./FileFilters.css";
|
||||
import { ArchiveIcon } from "./ArchiveIcon";
|
||||
import { ImageIcon } from "./ImageIcon";
|
||||
import { VideoIcon } from "./VideoIcon";
|
||||
import { DocumentIcon } from "./DocumentIcon";
|
||||
|
||||
type Props = {
|
||||
files: CodexDataContent[];
|
||||
@ -9,28 +13,73 @@ type Props = {
|
||||
selected: string[];
|
||||
};
|
||||
|
||||
function getIcon(type: string) {
|
||||
switch (type) {
|
||||
case "image": {
|
||||
return <ImageIcon></ImageIcon>;
|
||||
}
|
||||
|
||||
case "archive": {
|
||||
return <ArchiveIcon></ArchiveIcon>;
|
||||
}
|
||||
|
||||
case "video": {
|
||||
return <VideoIcon></VideoIcon>;
|
||||
}
|
||||
|
||||
default: {
|
||||
return <DocumentIcon></DocumentIcon>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getType(mimetype: string) {
|
||||
if (Files.isArchive(mimetype)) {
|
||||
return "archive";
|
||||
}
|
||||
|
||||
if (Files.isImage(mimetype)) {
|
||||
return "image";
|
||||
}
|
||||
|
||||
if (Files.isVideo(mimetype)) {
|
||||
return "video";
|
||||
}
|
||||
|
||||
return "document";
|
||||
}
|
||||
|
||||
export function FilterFilters({ selected, files, onFilterToggle }: Props) {
|
||||
const filters = Array.from(
|
||||
new Set(
|
||||
files
|
||||
.filter((f) => f.manifest.mimetype !== "")
|
||||
.map((file) =>
|
||||
Files.isArchive(file.manifest.mimetype)
|
||||
? "archive"
|
||||
: Files.type(file.manifest.mimetype)
|
||||
)
|
||||
.map((file) => getType(file.manifest.mimetype || ""))
|
||||
)
|
||||
);
|
||||
|
||||
return filters.map((type) => (
|
||||
<span
|
||||
key={type}
|
||||
className={classnames(
|
||||
["files-filter"],
|
||||
["files-filter--active", !!filters.find((f) => selected.includes(f))]
|
||||
)}
|
||||
onClick={() => onFilterToggle(type)}>
|
||||
<span>{type}</span> <Check size={"1rem"}></Check>
|
||||
</span>
|
||||
));
|
||||
const html = filters.map((type) => {
|
||||
const count = files.reduce(
|
||||
(acc, file) =>
|
||||
getType(file.manifest.mimetype || "") === type ? acc + 1 : acc,
|
||||
0
|
||||
);
|
||||
|
||||
return (
|
||||
<span
|
||||
key={type}
|
||||
className={classnames(
|
||||
["filter"],
|
||||
["filter--active", selected.includes(type)]
|
||||
)}
|
||||
onClick={() => onFilterToggle(type)}>
|
||||
{getIcon(type)}
|
||||
<span>
|
||||
{type + "s"} ({count})
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
});
|
||||
|
||||
return <div className="filters">{html}</div>;
|
||||
}
|
||||
|
||||
@ -1,8 +1,29 @@
|
||||
.files {
|
||||
border-radius: var(--codex-border-radius);
|
||||
border: 1px solid var(--codex-border-color);
|
||||
background-color: var(--codex-background-secondary);
|
||||
padding: 1rem 1.5rem;
|
||||
main > section {
|
||||
display: inline-flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
gap: 16px;
|
||||
|
||||
.tabs {
|
||||
flex-basis: 75%;
|
||||
}
|
||||
}
|
||||
|
||||
.filters {
|
||||
margin-top: 16px;
|
||||
gap: 16px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 105px;
|
||||
}
|
||||
|
||||
table thead tr th {
|
||||
background-color: #14141499;
|
||||
}
|
||||
}
|
||||
|
||||
.files-cell-file {
|
||||
@ -90,10 +111,6 @@
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.files-fileBody {
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
|
||||
.files-folders {
|
||||
width: 200px;
|
||||
min-width: 0px;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { FilesIcon, Folder, Plus, X } from "lucide-react";
|
||||
import { Plus } from "lucide-react";
|
||||
import { ChangeEvent, useEffect, useState } from "react";
|
||||
import { PrettyBytes } from "../../utils/bytes";
|
||||
import { Dates } from "../../utils/dates";
|
||||
@ -22,6 +22,9 @@ import { Files as F } from "../../utils/files.ts";
|
||||
import { FilterFilters } from "./FileFilters.tsx";
|
||||
import { FileCell } from "./FileCell.tsx";
|
||||
import { FileActions } from "./FileActions.tsx";
|
||||
import { FilesIconOutline } from "../FilesIcon/FilesIcon.tsx";
|
||||
import { AllFilesIcon } from "./AllFilesIcon.tsx";
|
||||
import { FavoriteIcon } from "./FavoriteIcon.tsx";
|
||||
|
||||
type SortFn = (a: CodexDataContent, b: CodexDataContent) => number;
|
||||
|
||||
@ -82,17 +85,17 @@ export function Files() {
|
||||
setFolders([...folders, [folder, []]]);
|
||||
};
|
||||
|
||||
const onFolderDelete = (val: string) => {
|
||||
WebStorage.folders.delete(val);
|
||||
// const onFolderDelete = (val: string) => {
|
||||
// WebStorage.folders.delete(val);
|
||||
|
||||
const currentIndex = folders.findIndex(([name]) => name === val);
|
||||
// const currentIndex = folders.findIndex(([name]) => name === val);
|
||||
|
||||
if (currentIndex + 1 == index) {
|
||||
setIndex(index - 1);
|
||||
}
|
||||
// if (currentIndex + 1 == index) {
|
||||
// setIndex(index - 1);
|
||||
// }
|
||||
|
||||
setFolders(folders.filter(([name]) => name !== val));
|
||||
};
|
||||
// setFolders(folders.filter(([name]) => name !== val));
|
||||
// };
|
||||
|
||||
const onFolderToggle = (cid: string, folder: string) => {
|
||||
const current = folders.find(([name]) => name === folder);
|
||||
@ -124,22 +127,22 @@ export function Files() {
|
||||
}
|
||||
};
|
||||
|
||||
const tabs: TabProps[] = folders.map(([folder]) => ({
|
||||
const tabs: TabProps[] = folders.map(([folder], index) => ({
|
||||
label: folder,
|
||||
Icon: () => <Folder size={"1rem"}></Folder>,
|
||||
IconAfter:
|
||||
folder === "Favorites"
|
||||
? undefined
|
||||
: () => (
|
||||
<X
|
||||
size={"1rem"}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
Icon: () => (index === 0 ? <FavoriteIcon></FavoriteIcon> : null),
|
||||
// IconAfter:
|
||||
// folder === "Favorites"
|
||||
// ? undefined
|
||||
// : () => (
|
||||
// <X
|
||||
// size={"1rem"}
|
||||
// onClick={(e) => {
|
||||
// e.preventDefault();
|
||||
// e.stopPropagation();
|
||||
|
||||
onFolderDelete(folder);
|
||||
}}></X>
|
||||
),
|
||||
// onFolderDelete(folder);
|
||||
// }}></X>
|
||||
// ),
|
||||
}));
|
||||
|
||||
const onSortByFilename = (state: TabSortState) => {
|
||||
@ -200,8 +203,8 @@ export function Files() {
|
||||
: setSelectedFilters([...selectedFilters, filter]);
|
||||
|
||||
tabs.unshift({
|
||||
label: "All files",
|
||||
Icon: () => <FilesIcon size={"1rem"}></FilesIcon>,
|
||||
label: "All",
|
||||
Icon: () => <AllFilesIcon></AllFilesIcon>,
|
||||
});
|
||||
|
||||
const items =
|
||||
@ -241,13 +244,17 @@ export function Files() {
|
||||
)) || [];
|
||||
|
||||
return (
|
||||
<div className="files">
|
||||
<div className="files-header">
|
||||
<div className="files-headerLeft">
|
||||
<div className="files-title">Files</div>
|
||||
<div className="card files">
|
||||
<header>
|
||||
<div>
|
||||
<FilesIconOutline></FilesIconOutline>
|
||||
<h5>Files</h5>
|
||||
</div>
|
||||
<div className="files-headerRight">
|
||||
<div>
|
||||
</header>
|
||||
<main>
|
||||
<section>
|
||||
<Tabs onTabChange={onTabChange} tabIndex={index} tabs={tabs}></Tabs>
|
||||
<div className="row gap">
|
||||
<Input
|
||||
id="folder"
|
||||
inputClassName={classnames(["files-folders"])}
|
||||
@ -256,33 +263,35 @@ export function Files() {
|
||||
required={true}
|
||||
pattern="[A-Za-z0-9_\-]*"
|
||||
maxLength={9}
|
||||
helper={error || "Enter the folder name"}
|
||||
size={"medium" as any}
|
||||
placeholder="Folder name"
|
||||
onChange={onFolderChange}></Input>
|
||||
|
||||
<Button
|
||||
label="Folder"
|
||||
Icon={Plus}
|
||||
variant="outline"
|
||||
disabled={!!error || !folder}
|
||||
onClick={onFolderCreate}></Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<Button
|
||||
label="Folder"
|
||||
Icon={Plus}
|
||||
disabled={!!error || !folder}
|
||||
onClick={onFolderCreate}></Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Tabs onTabChange={onTabChange} tabIndex={index} tabs={tabs}></Tabs>
|
||||
|
||||
<div className="files-filters">
|
||||
<FilterFilters
|
||||
files={files}
|
||||
onFilterToggle={onToggleFilter}
|
||||
selected={selectedFilters}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="files-fileBody">
|
||||
<Table headers={headers} rows={rows.slice(0, 4)} defaultSortIndex={2} />
|
||||
</div>
|
||||
<div>
|
||||
<Table
|
||||
headers={headers}
|
||||
rows={rows.slice(0, 4)}
|
||||
defaultSortIndex={2}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<FileDetails onClose={onClose} details={details} />
|
||||
<FileDetails onClose={onClose} details={details} />
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
15
src/components/Files/FolderAdd.tsx
Normal file
15
src/components/Files/FolderAdd.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function FolderAdd() {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="14"
|
||||
viewBox="0 0 16 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M8.3105 1.75H14.75C14.9489 1.75 15.1397 1.82902 15.2803 1.96967C15.421 2.11032 15.5 2.30109 15.5 2.5V13C15.5 13.1989 15.421 13.3897 15.2803 13.5303C15.1397 13.671 14.9489 13.75 14.75 13.75H1.25C1.05109 13.75 0.860322 13.671 0.71967 13.5303C0.579018 13.3897 0.5 13.1989 0.5 13V1C0.5 0.801088 0.579018 0.610322 0.71967 0.46967C0.860322 0.329018 1.05109 0.25 1.25 0.25H6.8105L8.3105 1.75ZM2 1.75V12.25H14V3.25H7.6895L6.1895 1.75H2ZM7.25 7V4.75H8.75V7H11V8.5H8.75V10.75H7.25V8.5H5V7H7.25Z"
|
||||
fill="#969696"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,38 +1,41 @@
|
||||
.folderButton {
|
||||
position: relative;
|
||||
}
|
||||
.folder-button {
|
||||
> div {
|
||||
position: absolute;
|
||||
transform: translate(-110px, -75px);
|
||||
opacity: 0;
|
||||
transition:
|
||||
transform 0.25s,
|
||||
opacity 0.15s;
|
||||
background-color: var(--codex-background);
|
||||
padding: 0.5rem;
|
||||
border-radius: var(--codex-border-radius);
|
||||
width: 150px;
|
||||
right: -40px;
|
||||
border: 1px solid var(--codex-border-color);
|
||||
z-index: -1;
|
||||
|
||||
.folderButton-options {
|
||||
position: absolute;
|
||||
transform: translateY(200px);
|
||||
opacity: 0;
|
||||
transition:
|
||||
transform 0.25s,
|
||||
opacity 0.15s;
|
||||
background-color: var(--codex-background);
|
||||
padding: 0.5rem;
|
||||
border-radius: var(--codex-border-radius);
|
||||
width: 150px;
|
||||
right: -40px;
|
||||
border: 1px solid var(--codex-border-color);
|
||||
}
|
||||
&[aria-expanded] {
|
||||
z-index: 12;
|
||||
transform: translate(-110px, -200px);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.folderButton-options[aria-expanded] {
|
||||
z-index: 12;
|
||||
transform: translateY(0px);
|
||||
opacity: 1;
|
||||
}
|
||||
> div {
|
||||
padding: 0.75rem;
|
||||
transition: background-color 0.35s;
|
||||
cursor: pointer;
|
||||
border-radius: var(--codex-border-radius);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.folderButton-option {
|
||||
padding: 0.75rem;
|
||||
transition: background-color 0.35s;
|
||||
cursor: pointer;
|
||||
border-radius: var(--codex-border-radius);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--codex-background-light);
|
||||
}
|
||||
}
|
||||
|
||||
.folderButton-option:hover {
|
||||
background-color: var(--codex-background-light);
|
||||
svg {
|
||||
color: var(--codex-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { Backdrop, ButtonIcon } from "@codex-storage/marketplace-ui-components";
|
||||
import { CheckCircle, Folder } from "lucide-react";
|
||||
import { CheckCircle } from "lucide-react";
|
||||
import "./FolderButton.css";
|
||||
import { useState } from "react";
|
||||
import { attributes } from "../../utils/attributes";
|
||||
import { FolderAdd } from "./FolderAdd";
|
||||
import { classnames } from "../../utils/classnames";
|
||||
|
||||
type Props = {
|
||||
folders: [string, boolean][];
|
||||
@ -24,35 +26,28 @@ export function FolderButton({ folders, onFolderToggle }: Props) {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="folderButton">
|
||||
<Backdrop open={open} onClose={onClose}></Backdrop>
|
||||
<>
|
||||
<div
|
||||
className={classnames(
|
||||
["folder-button"],
|
||||
["folder-button--active", doesFolderContainFile]
|
||||
)}>
|
||||
<ButtonIcon
|
||||
variant="small"
|
||||
className={classnames([""])}
|
||||
onClick={onOpen}
|
||||
Icon={FolderAdd}></ButtonIcon>
|
||||
|
||||
<ButtonIcon
|
||||
variant="small"
|
||||
onClick={onOpen}
|
||||
Icon={() => (
|
||||
<Folder
|
||||
fill={doesFolderContainFile ? "var(--codex-color-primary)" : ""}
|
||||
/>
|
||||
)}></ButtonIcon>
|
||||
|
||||
<div className="folderButton-options" {...attr}>
|
||||
{folders.map(([folder, isActive]) => (
|
||||
<div
|
||||
key={folder}
|
||||
className="folderButton-option"
|
||||
onClick={() => onFolderToggle(folder)}>
|
||||
<div>{folder}</div>
|
||||
<div>
|
||||
{isActive && (
|
||||
<span className="text--primary">
|
||||
<CheckCircle size={"1rem"}></CheckCircle>
|
||||
</span>
|
||||
)}
|
||||
<div {...attr}>
|
||||
{folders.map(([folder, isActive]) => (
|
||||
<div key={folder} onClick={() => onFolderToggle(folder)}>
|
||||
<span>{folder}</span>
|
||||
{isActive && <CheckCircle size={"1rem"}></CheckCircle>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Backdrop open={open} onClose={onClose}></Backdrop>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
15
src/components/Files/ImageIcon.tsx
Normal file
15
src/components/Files/ImageIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function ImageIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12.8 3.8001H3.2V12.2001L8.7752 6.6237C8.88772 6.51122 9.0403 6.44803 9.1994 6.44803C9.3585 6.44803 9.51108 6.51122 9.6236 6.6237L12.8 9.8061V3.8001ZM2 3.1959C2.0011 3.03832 2.06414 2.88751 2.17551 2.77603C2.28688 2.66455 2.43763 2.60135 2.5952 2.6001H13.4048C13.7336 2.6001 14 2.8671 14 3.1959V12.8043C13.9989 12.9619 13.9359 13.1127 13.8245 13.2242C13.7131 13.3356 13.5624 13.3988 13.4048 13.4001H2.5952C2.43729 13.3999 2.2859 13.3371 2.17429 13.2254C2.06269 13.1137 2 12.9622 2 12.8043V3.1959ZM5.6 7.4001C5.28174 7.4001 4.97652 7.27367 4.75147 7.04863C4.52643 6.82358 4.4 6.51836 4.4 6.2001C4.4 5.88184 4.52643 5.57661 4.75147 5.35157C4.97652 5.12653 5.28174 5.0001 5.6 5.0001C5.91826 5.0001 6.22348 5.12653 6.44853 5.35157C6.67357 5.57661 6.8 5.88184 6.8 6.2001C6.8 6.51836 6.67357 6.82358 6.44853 7.04863C6.22348 7.27367 5.91826 7.4001 5.6 7.4001Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
15
src/components/Files/InfoFileIcon.tsx
Normal file
15
src/components/Files/InfoFileIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function InfoFileIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="14"
|
||||
height="16"
|
||||
viewBox="0 0 14 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M9.25 2H1.75V14H12.25V5H9.25V2ZM0.25 1.244C0.25 0.833 0.58525 0.5 0.99925 0.5H10L13.75 4.25V14.7448C13.7507 14.8432 13.732 14.9409 13.6949 15.0322C13.6579 15.1234 13.6032 15.2065 13.534 15.2766C13.4649 15.3468 13.3826 15.4026 13.2919 15.4409C13.2011 15.4792 13.1037 15.4993 13.0052 15.5H0.99475C0.797784 15.4986 0.609263 15.4198 0.469913 15.2806C0.330563 15.1414 0.251571 14.953 0.25 14.756V1.244ZM6.25 7.25H7.75V11.75H6.25V7.25ZM6.25 4.25H7.75V5.75H6.25V4.25Z"
|
||||
fill="#969696"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
15
src/components/Files/VideoIcon.tsx
Normal file
15
src/components/Files/VideoIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export function VideoIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12.5 4.5H8.2071L7.2071 3.5H3.5C3.22386 3.5 3 3.72386 3 4V12C3 12.2761 3.22386 12.5 3.5 12.5H12.5C12.7761 12.5 13 12.2761 13 12V5C13 4.72386 12.7761 4.5 12.5 4.5ZM9.5004 8.3335C9.5923 8.39475 9.61715 8.51895 9.55585 8.61085C9.5412 8.6328 9.52235 8.65165 9.5004 8.6663L7.06095 10.2926C6.96905 10.3539 6.84485 10.3291 6.7836 10.2372C6.7617 10.2043 6.75 10.1657 6.75 10.1262V6.87359C6.75 6.76313 6.83955 6.67358 6.95 6.67358C6.9895 6.67358 7.0281 6.68527 7.06095 6.70717L9.5004 8.3335Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
34
src/components/FilesIcon/FilesIcon.tsx
Normal file
34
src/components/FilesIcon/FilesIcon.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
type Props = {
|
||||
width?: number;
|
||||
};
|
||||
|
||||
export function FilesIcon({ width = 16 }: Props) {
|
||||
return (
|
||||
<svg
|
||||
width={width}
|
||||
viewBox="0 0 16 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3.5 3.25V1C3.5 0.801088 3.57902 0.610322 3.71967 0.46967C3.86032 0.329018 4.05109 0.25 4.25 0.25H9.0605L10.5605 1.75H14.75C14.9489 1.75 15.1397 1.82902 15.2803 1.96967C15.421 2.11032 15.5 2.30109 15.5 2.5V10C15.5 10.1989 15.421 10.3897 15.2803 10.5303C15.1397 10.671 14.9489 10.75 14.75 10.75H12.5V13C12.5 13.1989 12.421 13.3897 12.2803 13.5303C12.1397 13.671 11.9489 13.75 11.75 13.75H1.25C1.05109 13.75 0.860322 13.671 0.71967 13.5303C0.579018 13.3897 0.5 13.1989 0.5 13V4C0.5 3.80109 0.579018 3.61032 0.71967 3.46967C0.860322 3.32902 1.05109 3.25 1.25 3.25H3.5ZM3.5 4.75H2V12.25H11V10.75H3.5V4.75Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function FilesIconOutline() {
|
||||
return (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3.6 4.4999V1.7999C3.6 1.56121 3.69482 1.33229 3.8636 1.16351C4.03239 0.994723 4.2613 0.899902 4.5 0.899902H10.2726L12.0726 2.6999H17.1C17.3387 2.6999 17.5676 2.79472 17.7364 2.96351C17.9052 3.13229 18 3.36121 18 3.5999V12.5999C18 12.8386 17.9052 13.0675 17.7364 13.2363C17.5676 13.4051 17.3387 13.4999 17.1 13.4999H14.4V16.1999C14.4 16.4386 14.3052 16.6675 14.1364 16.8363C13.9676 17.0051 13.7387 17.0999 13.5 17.0999H0.9C0.661305 17.0999 0.432387 17.0051 0.263604 16.8363C0.0948211 16.6675 0 16.4386 0 16.1999V5.3999C0 5.16121 0.0948211 4.93229 0.263604 4.76351C0.432387 4.59472 0.661305 4.4999 0.9 4.4999H3.6ZM3.6 6.2999H1.8V15.2999H12.6V13.4999H3.6V6.2999ZM5.4 2.6999V11.6999H16.2V4.4999H11.3274L9.5274 2.6999H5.4Z"
|
||||
fill="#969696"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
export function FilesIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="14"
|
||||
viewBox="0 0 16 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3.5 3.25V1C3.5 0.801088 3.57902 0.610322 3.71967 0.46967C3.86032 0.329018 4.05109 0.25 4.25 0.25H9.0605L10.5605 1.75H14.75C14.9489 1.75 15.1397 1.82902 15.2803 1.96967C15.421 2.11032 15.5 2.30109 15.5 2.5V10C15.5 10.1989 15.421 10.3897 15.2803 10.5303C15.1397 10.671 14.9489 10.75 14.75 10.75H12.5V13C12.5 13.1989 12.421 13.3897 12.2803 13.5303C12.1397 13.671 11.9489 13.75 11.75 13.75H1.25C1.05109 13.75 0.860322 13.671 0.71967 13.5303C0.579018 13.3897 0.5 13.1989 0.5 13V4C0.5 3.80109 0.579018 3.61032 0.71967 3.46967C0.860322 3.32902 1.05109 3.25 1.25 3.25H3.5ZM3.5 4.75H2V12.25H11V10.75H3.5V4.75Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -8,7 +8,7 @@ import { classnames } from "../../utils/classnames";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { HomeIcon } from "./HomeIcon";
|
||||
import { WalletIcon } from "./WalletIcon";
|
||||
import { FilesIcon } from "./FilesIcon";
|
||||
import { FilesIcon } from "../FilesIcon/FilesIcon";
|
||||
import { NodesIcon } from "./NodesIcon";
|
||||
import { AnalyticsIcon } from "./AnalyticsIcon";
|
||||
import { DeviceIcon } from "./DeviceIcon";
|
||||
|
||||
17
src/routes/dashboard/files.css
Normal file
17
src/routes/dashboard/files.css
Normal file
@ -0,0 +1,17 @@
|
||||
.files-page {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
|
||||
.files {
|
||||
margin-bottom: 16px;
|
||||
flex: 1 1 67%;
|
||||
}
|
||||
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,30 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { Files } from "../../components/Files/Files";
|
||||
import "./files.css";
|
||||
import { ErrorBoundary } from "@sentry/react";
|
||||
import { ErrorPlaceholder } from "../../components/ErrorPlaceholder/ErrorPlaceholder";
|
||||
import { ManifestFetchCard } from "../../components/ManifestFetch/ManifestFetchCard";
|
||||
import { UploadCard } from "../../components/UploadCard/UploadCard";
|
||||
import { Download } from "../../components/Download/Download";
|
||||
|
||||
export const Route = createFileRoute("/dashboard/files")({
|
||||
component: () => <div>Hello /dashboard/files!</div>,
|
||||
component: () => (
|
||||
<div className="files-page">
|
||||
<Files></Files>
|
||||
|
||||
<div className="column">
|
||||
<ErrorBoundary
|
||||
fallback={({ error }) => (
|
||||
<ErrorPlaceholder
|
||||
error={error}
|
||||
subtitle="Cannot retrieve the data."
|
||||
/>
|
||||
)}>
|
||||
<UploadCard />
|
||||
</ErrorBoundary>
|
||||
<Download></Download>
|
||||
<ManifestFetchCard />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
@ -13,6 +13,9 @@ export const Files = {
|
||||
isImage(type: string | null) {
|
||||
return type && type.startsWith("image");
|
||||
},
|
||||
isVideo(type: string | null) {
|
||||
return type && type.startsWith("video");
|
||||
},
|
||||
type(mimetype: string | null) {
|
||||
const [type] = mimetype?.split("/") || []
|
||||
return type
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user