feat: larger UI
This commit is contained in:
parent
623bb8f0b5
commit
d5904d4ee0
@ -28,7 +28,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||||||
|
|
||||||
let args: ProgramArgs = ProgramArgs::parse();
|
let args: ProgramArgs = ProgramArgs::parse();
|
||||||
|
|
||||||
let mut report: HashMap<String, HashSet<Uuid>> = HashMap::new();
|
let mut report: HashMap<String, HashSet<String>> = HashMap::new();
|
||||||
|
|
||||||
let mut binding = NostrCursor::new(args.archive);
|
let mut binding = NostrCursor::new(args.archive);
|
||||||
let mut cursor = Box::pin(binding.walk());
|
let mut cursor = Box::pin(binding.walk());
|
||||||
@ -44,7 +44,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||||||
warn!("Invalid base58 id {}", g);
|
warn!("Invalid base58 id {}", g);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let uuid = if let Ok(u) = Uuid::from_slice_le(base58.as_slice()) {
|
let _uuid = if let Ok(u) = Uuid::from_slice_le(base58.as_slice()) {
|
||||||
u
|
u
|
||||||
} else {
|
} else {
|
||||||
warn!("Invalid uuid {}", g);
|
warn!("Invalid uuid {}", g);
|
||||||
@ -52,9 +52,9 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||||||
};
|
};
|
||||||
info!("Got link: {} => {}", g, e.pubkey);
|
info!("Got link: {} => {}", g, e.pubkey);
|
||||||
if let Some(ur) = report.get_mut(&e.pubkey) {
|
if let Some(ur) = report.get_mut(&e.pubkey) {
|
||||||
ur.insert(uuid);
|
ur.insert(g.to_string());
|
||||||
} else {
|
} else {
|
||||||
report.insert(e.pubkey.clone(), HashSet::from([uuid]));
|
report.insert(e.pubkey.clone(), HashSet::from([g.to_string()]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import Upload from "./views/upload";
|
|||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-4 w-[700px] mx-auto mt-4">
|
<div className="flex flex-col gap-4 mx-auto mt-4 max-w-[1920px] px-10">
|
||||||
<Header />
|
<Header />
|
||||||
<Upload />
|
<Upload />
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,7 +5,7 @@ export default function Button({
|
|||||||
className,
|
className,
|
||||||
onClick,
|
onClick,
|
||||||
...props
|
...props
|
||||||
}: { onClick?: (e: React.MouseEvent) => Promise<void> } & Omit<
|
}: { onClick?: (e: React.MouseEvent) => Promise<void> | void } & Omit<
|
||||||
HTMLProps<HTMLButtonElement>,
|
HTMLProps<HTMLButtonElement>,
|
||||||
"type" | "onClick"
|
"type" | "onClick"
|
||||||
>) {
|
>) {
|
||||||
|
@ -18,7 +18,7 @@ export default function FileList({
|
|||||||
onPage,
|
onPage,
|
||||||
onDelete,
|
onDelete,
|
||||||
}: {
|
}: {
|
||||||
files: Array<File | NostrEvent>;
|
files: Array<File | NostrEvent | FileInfo>;
|
||||||
pages?: number;
|
pages?: number;
|
||||||
page?: number;
|
page?: number;
|
||||||
onPage?: (n: number) => void;
|
onPage?: (n: number) => void;
|
||||||
@ -30,9 +30,9 @@ export default function FileList({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderInner(f: FileInfo) {
|
function renderInner(f: FileInfo) {
|
||||||
if (f.type?.startsWith("image/")) {
|
if (f.type?.startsWith("image/") || !f.type) {
|
||||||
return (
|
return (
|
||||||
<img src={f.url} className="w-full h-full object-cover object-center" />
|
<img src={f.url} className="w-full h-full object-contain object-center" loading="lazy" />
|
||||||
);
|
);
|
||||||
} else if (f.type?.startsWith("video/")) {
|
} else if (f.type?.startsWith("video/")) {
|
||||||
return (
|
return (
|
||||||
@ -43,7 +43,10 @@ export default function FileList({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInfo(f: File | NostrEvent): FileInfo {
|
function getInfo(f: File | NostrEvent | FileInfo): FileInfo {
|
||||||
|
if ("url" in f) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
if ("created_at" in f) {
|
if ("created_at" in f) {
|
||||||
return {
|
return {
|
||||||
id: f.tags.find((a) => a[0] === "x")![1],
|
id: f.tags.find((a) => a[0] === "x")![1],
|
||||||
@ -88,7 +91,7 @@ export default function FileList({
|
|||||||
|
|
||||||
function showGrid() {
|
function showGrid() {
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-4 gap-2">
|
<div className="grid gap-2 grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10">
|
||||||
{files.map((a) => {
|
{files.map((a) => {
|
||||||
const info = getInfo(a);
|
const info = getInfo(a);
|
||||||
|
|
||||||
@ -110,12 +113,12 @@ export default function FileList({
|
|||||||
<a href={info.url} className="underline" target="_blank">
|
<a href={info.url} className="underline" target="_blank">
|
||||||
Link
|
Link
|
||||||
</a>
|
</a>
|
||||||
<a href="#" onClick={e => {
|
{onDelete && <a href="#" onClick={e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
onDelete?.(info.id)
|
onDelete?.(info.id)
|
||||||
}} className="underline">
|
}} className="underline">
|
||||||
Delete
|
Delete
|
||||||
</a>
|
</a>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{renderInner(info)}
|
{renderInner(info)}
|
||||||
@ -166,12 +169,12 @@ export default function FileList({
|
|||||||
<a href={info.url} className="underline" target="_blank">
|
<a href={info.url} className="underline" target="_blank">
|
||||||
Link
|
Link
|
||||||
</a>
|
</a>
|
||||||
<a href="#" onClick={e => {
|
{onDelete && <a href="#" onClick={e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
onDelete?.(info.id)
|
onDelete?.(info.id)
|
||||||
}} className="underline">
|
}} className="underline">
|
||||||
Delete
|
Delete
|
||||||
</a>
|
</a>}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -8,10 +8,12 @@ import usePublisher from "../hooks/publisher";
|
|||||||
import { Nip96, Nip96FileList } from "../upload/nip96";
|
import { Nip96, Nip96FileList } from "../upload/nip96";
|
||||||
import { AdminSelf, Route96 } from "../upload/admin";
|
import { AdminSelf, Route96 } from "../upload/admin";
|
||||||
import { FormatBytes } from "../const";
|
import { FormatBytes } from "../const";
|
||||||
|
import Report from "../report.json";
|
||||||
|
|
||||||
export default function Upload() {
|
export default function Upload() {
|
||||||
const [type, setType] = useState<"blossom" | "nip96">("blossom");
|
const [type, setType] = useState<"blossom" | "nip96">("blossom");
|
||||||
const [noCompress, setNoCompress] = useState(false);
|
const [noCompress, setNoCompress] = useState(false);
|
||||||
|
const [showLegacy, setShowLegacy] = useState(false);
|
||||||
const [toUpload, setToUpload] = useState<File>();
|
const [toUpload, setToUpload] = useState<File>();
|
||||||
const [self, setSelf] = useState<AdminSelf>();
|
const [self, setSelf] = useState<AdminSelf>();
|
||||||
const [error, setError] = useState<string>();
|
const [error, setError] = useState<string>();
|
||||||
@ -24,6 +26,8 @@ export default function Upload() {
|
|||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
const pub = usePublisher();
|
const pub = usePublisher();
|
||||||
|
|
||||||
|
const myLegacyFiles = login ? (Report as Record<string, Array<string>>)[login.pubkey] : [];
|
||||||
|
|
||||||
const url = import.meta.env.VITE_API_URL || `${location.protocol}//${location.host}`;
|
const url = import.meta.env.VITE_API_URL || `${location.protocol}//${location.host}`;
|
||||||
async function doUpload() {
|
async function doUpload() {
|
||||||
if (!pub) return;
|
if (!pub) return;
|
||||||
@ -58,7 +62,7 @@ export default function Upload() {
|
|||||||
setError(undefined);
|
setError(undefined);
|
||||||
const uploader = new Nip96(url, pub);
|
const uploader = new Nip96(url, pub);
|
||||||
await uploader.loadInfo();
|
await uploader.loadInfo();
|
||||||
const result = await uploader.listFiles(n, 12);
|
const result = await uploader.listFiles(n, 50);
|
||||||
setListedFiles(result);
|
setListedFiles(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
@ -76,7 +80,7 @@ export default function Upload() {
|
|||||||
try {
|
try {
|
||||||
setError(undefined);
|
setError(undefined);
|
||||||
const uploader = new Route96(url, pub);
|
const uploader = new Route96(url, pub);
|
||||||
const result = await uploader.listFiles(n, 12);
|
const result = await uploader.listFiles(n, 50);
|
||||||
setAdminListedFiles(result);
|
setAdminListedFiles(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
@ -176,11 +180,30 @@ export default function Upload() {
|
|||||||
List Uploads
|
List Uploads
|
||||||
</Button>}
|
</Button>}
|
||||||
|
|
||||||
|
|
||||||
{self && <div className="flex justify-between font-medium">
|
{self && <div className="flex justify-between font-medium">
|
||||||
<div>Uploads: {self.file_count.toLocaleString()}</div>
|
<div>Uploads: {self.file_count.toLocaleString()}</div>
|
||||||
<div>Total Size: {FormatBytes(self.total_size)}</div>
|
<div>Total Size: {FormatBytes(self.total_size)}</div>
|
||||||
</div>}
|
</div>}
|
||||||
|
|
||||||
|
{login && myLegacyFiles.length > 0 && (
|
||||||
|
<div className="flex flex-col gap-4 font-bold">
|
||||||
|
You have {myLegacyFiles.length.toLocaleString()} files which can be migrated from void.cat
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button>
|
||||||
|
Migrate Files
|
||||||
|
</Button>
|
||||||
|
<Button onClick={() => setShowLegacy(true)}>
|
||||||
|
Show Files
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{showLegacy && (
|
||||||
|
<FileList
|
||||||
|
files={myLegacyFiles.map(f => ({ id: f, url: `https://void.cat/d/${f}` }))}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{listedFiles && (
|
{listedFiles && (
|
||||||
<FileList
|
<FileList
|
||||||
files={listedFiles.files}
|
files={listedFiles.files}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user