mirror of
https://github.com/smolgrrr/TAO.git
synced 2024-09-20 09:21:25 +00:00
various tings alright
This commit is contained in:
parent
23da7698c8
commit
80a2b3fc29
@ -15,8 +15,10 @@
|
|||||||
"nostr-tools": "latest",
|
"nostr-tools": "latest",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"react-pull-to-refresh": "^2.0.1",
|
||||||
"react-router-dom": "^6.15.0",
|
"react-router-dom": "^6.15.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
|
"react-swipe": "^6.0.4",
|
||||||
"react-swipeable-views": "^0.14.0",
|
"react-swipeable-views": "^0.14.0",
|
||||||
"web-vitals": "^2.1.4",
|
"web-vitals": "^2.1.4",
|
||||||
"workbox-background-sync": "^6.6.0",
|
"workbox-background-sync": "^6.6.0",
|
||||||
|
@ -2,7 +2,7 @@ import { PropsWithChildren } from 'react';
|
|||||||
|
|
||||||
export default function CardContainer({ children }: PropsWithChildren) {
|
export default function CardContainer({ children }: PropsWithChildren) {
|
||||||
return (
|
return (
|
||||||
<div className="card bg-gradient-to-r from-black to-neutral-900 shadow-lg shadow-black">
|
<div className="card bg-gradient-to-r from-black to-neutral-950 shadow-lg shadow-black">
|
||||||
<div className="card-body p-4">{children}</div>
|
<div className="card-body p-4">{children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -4,11 +4,13 @@ import { useState } from 'react';
|
|||||||
import { Event, generatePrivateKey, getPublicKey, finishEvent, relayInit } from 'nostr-tools';
|
import { Event, generatePrivateKey, getPublicKey, finishEvent, relayInit } from 'nostr-tools';
|
||||||
import { minePow } from '../../utils/mine';
|
import { minePow } from '../../utils/mine';
|
||||||
import { publish } from '../../utils/relays';
|
import { publish } from '../../utils/relays';
|
||||||
|
import NostrImg from '../../utils/ImgUpload';
|
||||||
|
|
||||||
const difficulty = 20
|
const difficulty = 20
|
||||||
|
|
||||||
const NewThreadCard: React.FC = () => {
|
const NewThreadCard: React.FC = () => {
|
||||||
const [comment, setComment] = useState("");
|
const [comment, setComment] = useState("");
|
||||||
|
const [file, setFile] = useState("");
|
||||||
|
|
||||||
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -18,36 +20,37 @@ const NewThreadCard: React.FC = () => {
|
|||||||
const event = minePow({
|
const event = minePow({
|
||||||
kind: 1,
|
kind: 1,
|
||||||
tags: [],
|
tags: [],
|
||||||
content: comment,
|
content: comment + " " + file,
|
||||||
created_at: Math.floor(Date.now() / 1000),
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
pubkey: getPublicKey(sk),
|
pubkey: getPublicKey(sk),
|
||||||
}, difficulty);
|
}, difficulty);
|
||||||
|
|
||||||
const signedEvent = finishEvent(event, sk);
|
const signedEvent = finishEvent(event, sk);
|
||||||
await publish(signedEvent);
|
await publish(signedEvent);
|
||||||
console.log(signedEvent.id);
|
|
||||||
|
|
||||||
|
setComment("")
|
||||||
|
setFile("")
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setComment(comment + " " + error);
|
setComment(comment + " " + error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// async function attachFile(file_input: File | null) {
|
async function attachFile(file_input: File | null) {
|
||||||
// try {
|
try {
|
||||||
// if (file_input) {
|
if (file_input) {
|
||||||
// const rx = await NostrImg(file_input);
|
const rx = await NostrImg(file_input);
|
||||||
// if (rx.url) {
|
if (rx.url) {
|
||||||
// setComment(comment + " " + rx.url);
|
setFile(rx.url);
|
||||||
// } else if (rx?.error) {
|
} else if (rx?.error) {
|
||||||
// setComment(comment + " " + rx.error);
|
setFile(rx.error);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// } catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
// if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
// setComment(comment + " " + error?.message);
|
setFile(error?.message);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -73,10 +76,34 @@ const NewThreadCard: React.FC = () => {
|
|||||||
onChange={(e) => setComment(e.target.value)}
|
onChange={(e) => setComment(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
{file !== "" && (
|
||||||
|
<div className="file m-0.5">
|
||||||
|
<img
|
||||||
|
src={file}
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<ArrowUpTrayIcon className="h-6 w-6 text-white" />
|
<ArrowUpTrayIcon
|
||||||
<input type="file" className="hidden" />
|
className="h-6 w-6 text-white cursor-pointer"
|
||||||
|
onClick={() => document.getElementById('file_input')?.click()}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
name="file_input"
|
||||||
|
id="file_input"
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
onChange={(e) => {
|
||||||
|
const file_input = e.target.files?.[0];
|
||||||
|
if (file_input) {
|
||||||
|
attachFile(file_input);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="flex items-center"><CpuChipIcon className="h-6 w-6 text-white" />: {difficulty}</span>
|
<span className="flex items-center"><CpuChipIcon className="h-6 w-6 text-white" />: {difficulty}</span>
|
||||||
<button type="submit" className="px-4 py-2 bg-gradient-to-r from-cyan-900 to-blue-500 rounded text-white font-semibold">
|
<button type="submit" className="px-4 py-2 bg-gradient-to-r from-cyan-900 to-blue-500 rounded text-white font-semibold">
|
||||||
|
@ -94,14 +94,14 @@ const PostCard = ({ event, metadata, replyCount }: { event: Event, metadata: Eve
|
|||||||
<div className="mr-2 flex flex-col break-words">
|
<div className="mr-2 flex flex-col break-words">
|
||||||
{comment}
|
{comment}
|
||||||
</div>
|
</div>
|
||||||
{/* {file !== "" && (
|
{file !== "" && (
|
||||||
<div className="file">
|
<div className="file">
|
||||||
<img
|
<img
|
||||||
src={file}
|
src={file}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)} */}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</CardContainer>
|
</CardContainer>
|
||||||
|
@ -1,56 +1,55 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import {generatePrivateKey, getPublicKey} from 'nostr-tools';
|
||||||
|
// import {powEvent} from './system';
|
||||||
|
// import {publish} from './relays';
|
||||||
|
|
||||||
const Settings = () => {
|
const Settings = () => {
|
||||||
// State variables to hold the settings
|
const [filterDifficulty, setFilterDifficulty] = useState(localStorage.getItem('filterDifficulty') || 20);
|
||||||
const [isDarkMode, setIsDarkMode] = useState(false);
|
const [difficulty, setDifficulty] = useState(localStorage.getItem('difficulty') || 20);
|
||||||
const [username, setUsername] = useState('');
|
|
||||||
|
|
||||||
// Mimic fetching existing settings from an API or local storage
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
useEffect(() => {
|
e.preventDefault();
|
||||||
// Simulate fetching existing settings
|
localStorage.setItem('filterDifficulty', String(filterDifficulty));
|
||||||
const existingSettings = {
|
localStorage.setItem('difficulty', String(difficulty));
|
||||||
isDarkMode: false, // replace with actual value
|
|
||||||
username: '' // replace with actual value
|
|
||||||
};
|
|
||||||
setIsDarkMode(existingSettings.isDarkMode);
|
|
||||||
setUsername(existingSettings.username);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Function to save changes (simulate API call or local storage update)
|
|
||||||
const saveChanges = () => {
|
|
||||||
// Replace this with an actual API call or local storage update
|
|
||||||
console.log('Dark Mode:', isDarkMode);
|
|
||||||
console.log('Username:', username);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="settings-page">
|
<div className="settings-page bg-black text-white min-h-screen p-8">
|
||||||
<h1>Settings</h1>
|
<h1 className="text-lg font-semibold mb-4">Settings</h1>
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
<div className="setting-item">
|
<div className="flex flex-wrap -mx-2 mb-4">
|
||||||
<label>
|
<div className="w-full md:w-1/3 px-2 mb-4 md:mb-0">
|
||||||
Dark Mode
|
<label className="block mb-2" htmlFor="filterDifficulty">
|
||||||
<input
|
Filter Difficulty:
|
||||||
type="checkbox"
|
|
||||||
checked={isDarkMode}
|
|
||||||
onChange={(e) => setIsDarkMode(e.target.checked)}
|
|
||||||
/>
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="setting-item">
|
|
||||||
<label>
|
|
||||||
Username
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
id="filterDifficulty"
|
||||||
value={username}
|
type="number"
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
value={filterDifficulty}
|
||||||
|
onChange={e => setFilterDifficulty(e.target.value)}
|
||||||
|
className="w-full px-3 py-2 border rounded-md text-black"
|
||||||
/>
|
/>
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button onClick={saveChanges}>Save Changes</button>
|
<div className="w-full md:w-1/3 px-2 mb-4 md:mb-0">
|
||||||
|
<label className="block mb-2" htmlFor="difficulty">
|
||||||
|
Post Difficulty:
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="difficulty"
|
||||||
|
type="number"
|
||||||
|
value={difficulty}
|
||||||
|
onChange={e => setDifficulty(e.target.value)}
|
||||||
|
className="w-full px-3 py-2 border rounded-md text-black"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<button className="bg-gradient-to-r from-blue-900 to-cyan-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
|
||||||
|
Save Settings
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import { ArrowUpTrayIcon, CpuChipIcon } from '@heroicons/react/24/outline';
|
|||||||
import { generatePrivateKey, getPublicKey, finishEvent, relayInit } from 'nostr-tools';
|
import { generatePrivateKey, getPublicKey, finishEvent, relayInit } from 'nostr-tools';
|
||||||
import { minePow } from '../../utils/mine';
|
import { minePow } from '../../utils/mine';
|
||||||
import { publish } from '../../utils/relays';
|
import { publish } from '../../utils/relays';
|
||||||
|
import ThreadPost from './ThreadPost';
|
||||||
|
|
||||||
|
|
||||||
const difficulty = 20
|
const difficulty = 20
|
||||||
@ -20,6 +21,7 @@ const Thread = () => {
|
|||||||
let decodeResult = nip19.decode(id as string);
|
let decodeResult = nip19.decode(id as string);
|
||||||
const [comment, setComment] = useState("");
|
const [comment, setComment] = useState("");
|
||||||
const [showForm, setShowForm] = useState(false);
|
const [showForm, setShowForm] = useState(false);
|
||||||
|
const [postType, setPostType] = useState("");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -80,7 +82,7 @@ const Thread = () => {
|
|||||||
|
|
||||||
if (!uniqEvents[0]) {
|
if (!uniqEvents[0]) {
|
||||||
return (
|
return (
|
||||||
<main className="bg-black text-white min-h-screen">
|
<>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
|
||||||
<div className="border border-blue-300 shadow rounded-md p-4 max-w-sm w-full mx-auto">
|
<div className="border border-blue-300 shadow rounded-md p-4 max-w-sm w-full mx-auto">
|
||||||
<div className="animate-pulse flex space-x-4">
|
<div className="animate-pulse flex space-x-4">
|
||||||
@ -98,7 +100,7 @@ const Thread = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
@ -107,44 +109,24 @@ const Thread = () => {
|
|||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
|
||||||
<PostCard event={uniqEvents[0]} metadata={getMetadataEvent(uniqEvents[0])} replyCount={countReplies(uniqEvents[0])} />
|
<PostCard event={uniqEvents[0]} metadata={getMetadataEvent(uniqEvents[0])} replyCount={countReplies(uniqEvents[0])} />
|
||||||
<div className="col-span-full flex justify-center space-x-36 ">
|
<div className="col-span-full flex justify-center space-x-36 ">
|
||||||
<DocumentTextIcon className="h-5 w-5 text-gray-200" onClick={() => setShowForm(prevShowForm => !prevShowForm)} />
|
<DocumentTextIcon
|
||||||
<FolderPlusIcon className="h-5 w-5 text-gray-200" onClick={() => setShowForm(prevShowForm => !prevShowForm)} />
|
className="h-5 w-5 text-gray-200"
|
||||||
</div>
|
onClick={() => {
|
||||||
<div>
|
setShowForm(prevShowForm => !prevShowForm);
|
||||||
{showForm && (
|
setPostType('r');
|
||||||
<form
|
}}
|
||||||
name="post"
|
/>
|
||||||
method="post"
|
|
||||||
encType="multipart/form-data"
|
<FolderPlusIcon
|
||||||
className=""
|
className="h-5 w-5 text-gray-200"
|
||||||
onSubmit={handleSubmit}
|
onClick={() => {
|
||||||
>
|
setShowForm(prevShowForm => !prevShowForm);
|
||||||
<input type="hidden" name="MAX_FILE_SIZE" defaultValue={4194304} />
|
setPostType('q');
|
||||||
<div id="togglePostFormLink" className="text-lg font-semibold">
|
}}
|
||||||
Reply to note
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<textarea
|
|
||||||
name="com"
|
|
||||||
wrap="soft"
|
|
||||||
className="w-full p-2 rounded bg-gradient-to-r from-blue-900 to-cyan-500 text-white border-none placeholder-blue-300"
|
|
||||||
placeholder='Shitpost here...'
|
|
||||||
value={comment}
|
|
||||||
onChange={(e) => setComment(e.target.value)}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center">
|
<div>
|
||||||
<div className="flex items-center">
|
<ThreadPost state={showForm} type={postType} />
|
||||||
<ArrowUpTrayIcon className="h-6 w-6 text-white" />
|
|
||||||
<input type="file" className="hidden" />
|
|
||||||
</div>
|
|
||||||
<span className="flex items-center"><CpuChipIcon className="h-6 w-6 text-white" />: {difficulty}</span>
|
|
||||||
<button type="submit" className="px-4 py-2 bg-gradient-to-r from-cyan-900 to-blue-500 rounded text-white font-semibold">
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div id="postFormError" className="text-red-500" />
|
|
||||||
</form>)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-full h-0.5 bg-neutral-900"></div> {/* This is the white line separator */}
|
<div className="col-span-full h-0.5 bg-neutral-900"></div> {/* This is the white line separator */}
|
||||||
{uniqEvents
|
{uniqEvents
|
||||||
|
133
client/src/components/Thread/ThreadPost.tsx
Normal file
133
client/src/components/Thread/ThreadPost.tsx
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { useState } from "react";
|
||||||
|
import { ArrowUpTrayIcon, CpuChipIcon } from '@heroicons/react/24/outline';
|
||||||
|
import { generatePrivateKey, getPublicKey, finishEvent, relayInit } from 'nostr-tools';
|
||||||
|
import { minePow } from '../../utils/mine';
|
||||||
|
import { publish } from '../../utils/relays';
|
||||||
|
import NostrImg from '../../utils/ImgUpload';
|
||||||
|
import { nip19 } from 'nostr-tools';
|
||||||
|
|
||||||
|
|
||||||
|
const difficulty = 5
|
||||||
|
|
||||||
|
const ThreadPost = ({ state, type }: { state: Boolean, type: String }) => {
|
||||||
|
const { id} = useParams();
|
||||||
|
const [comment, setComment] = useState("");
|
||||||
|
const [file, setFile] = useState("");
|
||||||
|
const [tags, setTags] = useState([['']]);
|
||||||
|
|
||||||
|
let decodeResult = nip19.decode(id as string);
|
||||||
|
|
||||||
|
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
let sk = generatePrivateKey();
|
||||||
|
let id = decodeResult.data as string
|
||||||
|
|
||||||
|
if (type === 'r') {
|
||||||
|
tags.push(["e", id as string])
|
||||||
|
} else if (type === 'q') {
|
||||||
|
tags.push(["q", id as string])
|
||||||
|
setComment(comment + ' nostr:' + id)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const event = minePow({
|
||||||
|
kind: 1,
|
||||||
|
tags,
|
||||||
|
content: comment + " " + file,
|
||||||
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
|
pubkey: getPublicKey(sk),
|
||||||
|
}, difficulty);
|
||||||
|
|
||||||
|
const signedEvent = finishEvent(event, sk);
|
||||||
|
await publish(signedEvent);
|
||||||
|
console.log(signedEvent.id);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
setComment(comment + " " + error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function attachFile(file_input: File | null) {
|
||||||
|
try {
|
||||||
|
if (file_input) {
|
||||||
|
const rx = await NostrImg(file_input);
|
||||||
|
if (rx.url) {
|
||||||
|
setFile(rx.url);
|
||||||
|
} else if (rx?.error) {
|
||||||
|
setFile(rx.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
setFile(error?.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{state && (
|
||||||
|
<form
|
||||||
|
name="post"
|
||||||
|
method="post"
|
||||||
|
encType="multipart/form-data"
|
||||||
|
className=""
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
>
|
||||||
|
<input type="hidden" name="MAX_FILE_SIZE" defaultValue={4194304} />
|
||||||
|
<div id="togglePostFormLink" className="text-lg font-semibold">
|
||||||
|
{type === 'r' ? <span>Reply To Post</span> : <span>Quote Post</span>}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<textarea
|
||||||
|
name="com"
|
||||||
|
wrap="soft"
|
||||||
|
className="w-full p-2 rounded bg-gradient-to-r from-blue-900 to-cyan-500 text-white border-none placeholder-blue-300"
|
||||||
|
placeholder='Shitpost here...'
|
||||||
|
value={comment}
|
||||||
|
onChange={(e) => setComment(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{file !== "" && (
|
||||||
|
<div className="file m-0.5">
|
||||||
|
<img
|
||||||
|
src={file}
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<ArrowUpTrayIcon
|
||||||
|
className="h-6 w-6 text-white cursor-pointer"
|
||||||
|
onClick={() => document.getElementById('file_input')?.click()}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
name="file_input"
|
||||||
|
id="file_input"
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
onChange={(e) => {
|
||||||
|
const file_input = e.target.files?.[0];
|
||||||
|
if (file_input) {
|
||||||
|
attachFile(file_input);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className="flex items-center"><CpuChipIcon className="h-6 w-6 text-white" />: {difficulty}</span>
|
||||||
|
<button type="submit" className="px-4 py-2 bg-gradient-to-r from-cyan-900 to-blue-500 rounded text-white font-semibold">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="postFormError" className="text-red-500" />
|
||||||
|
</form>)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ThreadPost;
|
@ -9,6 +9,7 @@ body {
|
|||||||
sans-serif;
|
sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
background-color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
|
@ -9,23 +9,23 @@ export interface UploadResult {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export default async function NostrImg(file: File ): Promise<UploadResult> {
|
export default async function NostrImg(file: File ): Promise<UploadResult> {
|
||||||
const buf = await file.arrayBuffer();
|
const fd = new FormData();
|
||||||
|
fd.append("image", file);
|
||||||
|
|
||||||
const req = await fetch("https://void.cat/upload", {
|
const req = await fetch("https://nostrimg.com/api/upload", {
|
||||||
body: buf,
|
body: fd,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/octet-stream",
|
accept: "application/json",
|
||||||
"V-Content-Type": file.type, // Extracting the mime type
|
|
||||||
"V-Filename": file.name, // Extracting the filename
|
|
||||||
"V-Description": "Upload from https://tao-green.vercel.app/",
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (req.ok) {
|
if (req.ok) {
|
||||||
let rsp: VoidUploadResponse = await req.json();
|
const data: UploadResponse = await req.json();
|
||||||
const fileExtension = file.name.split('.').pop(); // Extracting the file extension
|
if (typeof data?.imageUrl === "string" && data.success) {
|
||||||
const resultUrl = `https://void.cat/d/${rsp.file?.id}.${fileExtension}`;
|
return {
|
||||||
return {url: resultUrl};
|
url: new URL(data.imageUrl).toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
error: "Upload failed",
|
error: "Upload failed",
|
||||||
@ -43,6 +43,22 @@ export type VoidUploadResponse = {
|
|||||||
errorMessage?: string,
|
errorMessage?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface UploadResponse {
|
||||||
|
fileID?: string;
|
||||||
|
fileName?: string;
|
||||||
|
imageUrl?: string;
|
||||||
|
lightningDestination?: string;
|
||||||
|
lightningPaymentLink?: string;
|
||||||
|
message?: string;
|
||||||
|
route?: string;
|
||||||
|
status: number;
|
||||||
|
success: boolean;
|
||||||
|
url?: string;
|
||||||
|
data?: {
|
||||||
|
url?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export type VoidFile = {
|
export type VoidFile = {
|
||||||
id: string,
|
id: string,
|
||||||
meta?: VoidFileMeta
|
meta?: VoidFileMeta
|
||||||
|
Loading…
Reference in New Issue
Block a user