mirror of
https://github.com/smolgrrr/TAO.git
synced 2024-09-20 01:11:25 +00:00
penis
This commit is contained in:
parent
1f00204ab6
commit
610256fbfa
@ -5,7 +5,6 @@ import Settings from './components/Settings';
|
||||
import SwipeableViews from 'react-swipeable-views';
|
||||
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
|
||||
import Thread from './components/Thread/Thread';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
function App() {
|
||||
const [index, setIndex] = React.useState(1);
|
||||
|
@ -8,6 +8,7 @@ import { uniqBy } from '../utils/utils';
|
||||
|
||||
const Home = () => {
|
||||
const [events, setEvents] = useState<Event[]>([]);
|
||||
const [filterDifficulty, setFilterDifficulty] = useState(localStorage.getItem('filterDifficulty') || '12');
|
||||
|
||||
const onEvent = (event: Event) => {
|
||||
setEvents((prevEvents) => [...prevEvents, event]);
|
||||
@ -16,15 +17,27 @@ const Home = () => {
|
||||
useEffect(() => {
|
||||
subGlobalFeed(onEvent);
|
||||
// If you eventually need a cleanup function, put it here
|
||||
|
||||
const handleDifficultyChange = (event: any) => {
|
||||
const customEvent = event as CustomEvent;
|
||||
const { difficulty, filterDifficulty } = customEvent.detail;
|
||||
setFilterDifficulty(filterDifficulty);
|
||||
};
|
||||
|
||||
window.addEventListener('difficultyChanged', handleDifficultyChange);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('difficultyChanged', handleDifficultyChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const uniqEvents = events.length > 0 ? uniqBy(events, "id") : [];
|
||||
|
||||
const filteredAndSortedEvents = uniqEvents
|
||||
.filter(event =>
|
||||
getPow(event.id) > 5 &&
|
||||
getPow(event.id) > Math.ceil(Number(filterDifficulty)/4) &&
|
||||
event.kind === 1 &&
|
||||
!event.tags.some(tag => tag[0] === 'p')
|
||||
!event.tags.some(tag => tag[0] === 'e')
|
||||
)
|
||||
.sort((a, b) => (b.created_at as any) - (a.created_at as any));
|
||||
|
||||
|
@ -17,11 +17,11 @@ const ContentPreview = ({ key, comment }: { key: string, comment: string }) => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// const findUrl = comment.match(/\bhttps?:\/\/\S+/gi);
|
||||
// if (findUrl && findUrl.length > 0) {
|
||||
// setUrl(findUrl[0])
|
||||
// setFinalComment(finalComment.replace(findUrl[0], '').trim())
|
||||
// }
|
||||
const findUrl = comment.match(/\bhttps?:\/\/\S+/gi);
|
||||
if (findUrl && findUrl.length > 0) {
|
||||
setUrl(findUrl[0])
|
||||
setFinalComment(finalComment.replace(findUrl[0], '').trim())
|
||||
}
|
||||
|
||||
const match = comment.match(/\bnostr:([a-z0-9]+)/i);
|
||||
const nostrQuoteID = match && match[1];
|
||||
|
@ -2,59 +2,73 @@ import CardContainer from './CardContainer';
|
||||
import { ArrowUpTrayIcon, CpuChipIcon } from '@heroicons/react/24/outline';
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { generatePrivateKey, getPublicKey, finishEvent } from 'nostr-tools';
|
||||
import { minePow } from '../../utils/mine';
|
||||
import { publish } from '../../utils/relays';
|
||||
import NostrImg from '../../utils/ImgUpload';
|
||||
|
||||
const difficulty = 20
|
||||
|
||||
const NewThreadCard: React.FC = () => {
|
||||
const [comment, setComment] = useState("");
|
||||
const [file, setFile] = useState("");
|
||||
const [sk, setSk] = useState(generatePrivateKey());
|
||||
const [sk, setSk] = useState(generatePrivateKey());
|
||||
const [difficulty, setDifficulty] = useState(localStorage.getItem('difficulty') || '21');
|
||||
|
||||
|
||||
const [messageFromWorker, setMessageFromWorker] = useState(null);
|
||||
// Initialize the worker outside of any effects
|
||||
const [doingWorkProp, setDoingWorkProp] = useState(false);
|
||||
// Initialize the worker outside of any effects
|
||||
const worker = useMemo(() => new Worker(new URL('../../powWorker', import.meta.url)), []);
|
||||
|
||||
useEffect(() => {
|
||||
worker.onmessage = (event) => {
|
||||
setMessageFromWorker(event.data);
|
||||
};
|
||||
|
||||
const handleDifficultyChange = (event: Event) => {
|
||||
const customEvent = event as CustomEvent;
|
||||
const { difficulty, filterDifficulty } = customEvent.detail;
|
||||
setDifficulty(difficulty);
|
||||
};
|
||||
|
||||
window.addEventListener('difficultyChanged', handleDifficultyChange);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('difficultyChanged', handleDifficultyChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
worker.postMessage({
|
||||
unsigned: {
|
||||
kind: 1,
|
||||
tags: [],
|
||||
content: comment + " " + file,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
pubkey: getPublicKey(sk),
|
||||
},
|
||||
difficulty
|
||||
unsigned: {
|
||||
kind: 1,
|
||||
tags: [],
|
||||
content: comment + " " + file,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
pubkey: getPublicKey(sk),
|
||||
},
|
||||
difficulty
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setDoingWorkProp(false)
|
||||
if (messageFromWorker) {
|
||||
try {
|
||||
const signedEvent = finishEvent(messageFromWorker, sk);
|
||||
publish(signedEvent);
|
||||
try {
|
||||
const signedEvent = finishEvent(messageFromWorker, sk);
|
||||
publish(signedEvent);
|
||||
|
||||
setComment("");
|
||||
setFile("");
|
||||
setSk(generatePrivateKey())
|
||||
setComment("");
|
||||
setFile("");
|
||||
setSk(generatePrivateKey());
|
||||
setMessageFromWorker(null);
|
||||
|
||||
return () => {
|
||||
worker.terminate();
|
||||
};
|
||||
} catch (error) {
|
||||
setComment(error + ' ' + comment);
|
||||
}
|
||||
return () => {
|
||||
worker.terminate();
|
||||
};
|
||||
} catch (error) {
|
||||
setComment(error + ' ' + comment);
|
||||
}
|
||||
}
|
||||
}, [messageFromWorker]);
|
||||
}, [messageFromWorker]);
|
||||
|
||||
async function attachFile(file_input: File | null) {
|
||||
try {
|
||||
@ -76,13 +90,15 @@ const NewThreadCard: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<CardContainer>
|
||||
{/* <p>Message from worker: {messageFromWorker}</p> */}
|
||||
<form
|
||||
name="post"
|
||||
method="post"
|
||||
encType="multipart/form-data"
|
||||
className=""
|
||||
onSubmit={handleSubmit}
|
||||
onSubmit={(event) => {
|
||||
handleSubmit(event);
|
||||
setDoingWorkProp(true);
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="MAX_FILE_SIZE" defaultValue={4194304} />
|
||||
<div id="togglePostFormLink" className="text-lg font-semibold">
|
||||
@ -99,14 +115,14 @@ const NewThreadCard: React.FC = () => {
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{file !== "" && (
|
||||
<div className="file m-0.5">
|
||||
{file !== "" && (
|
||||
<div className="file m-0.5">
|
||||
<img
|
||||
src={file}
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex items-center">
|
||||
@ -132,6 +148,12 @@ const NewThreadCard: React.FC = () => {
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
{doingWorkProp ? (
|
||||
<div className='flex animate-pulse text-sm text-gray-300'>
|
||||
<CpuChipIcon className="h-4 w-4 ml-auto" />
|
||||
<span>Working...</span>
|
||||
</div>
|
||||
) : null}
|
||||
<div id="postFormError" className="text-red-500" />
|
||||
</form>
|
||||
</CardContainer>
|
||||
|
@ -10,6 +10,13 @@ const Settings = () => {
|
||||
e.preventDefault();
|
||||
localStorage.setItem('filterDifficulty', String(filterDifficulty));
|
||||
localStorage.setItem('difficulty', String(difficulty));
|
||||
|
||||
const eventData = {
|
||||
difficulty: String(difficulty),
|
||||
filterDifficulty: String(filterDifficulty),
|
||||
};
|
||||
const event = new CustomEvent('settingsChanged', { detail: eventData });
|
||||
window.dispatchEvent(event);
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -1,53 +1,94 @@
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useState } from "react";
|
||||
import { useState, useMemo, useEffect } from "react";
|
||||
import { ArrowUpTrayIcon, CpuChipIcon } from '@heroicons/react/24/outline';
|
||||
import { generatePrivateKey, getPublicKey, finishEvent } 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 = 25
|
||||
|
||||
const ThreadPost = ({ state, type }: { state: Boolean, type: String }) => {
|
||||
const { id} = useParams();
|
||||
const { id } = useParams();
|
||||
const [comment, setComment] = useState("");
|
||||
const [file, setFile] = useState("");
|
||||
const [difficulty, setDifficulty] = useState(localStorage.getItem('difficulty') || '21');
|
||||
|
||||
let decodeResult = nip19.decode(id as string);
|
||||
|
||||
const [sk, setSk] = useState(generatePrivateKey());
|
||||
|
||||
const [messageFromWorker, setMessageFromWorker] = useState(null);
|
||||
const [doingWorkProp, setDoingWorkProp] = useState(false);
|
||||
// Initialize the worker outside of any effects
|
||||
const worker = useMemo(() => new Worker(new URL('../../powWorker', import.meta.url)), []);
|
||||
|
||||
useEffect(() => {
|
||||
worker.onmessage = (event) => {
|
||||
setMessageFromWorker(event.data);
|
||||
};
|
||||
|
||||
const handleDifficultyChange = (event: Event) => {
|
||||
const customEvent = event as CustomEvent;
|
||||
setDifficulty(customEvent.detail);
|
||||
};
|
||||
|
||||
window.addEventListener('difficultyChanged', handleDifficultyChange);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('difficultyChanged', handleDifficultyChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
let sk = generatePrivateKey();
|
||||
let id = decodeResult.data as string
|
||||
|
||||
let tags = [];
|
||||
let modifiedComment = comment + " " + file;
|
||||
if (type === 'r') {
|
||||
tags.push(["e", id as string])
|
||||
} else if (type === 'q') {
|
||||
tags.push(["q", id as string])
|
||||
setComment(comment + ' nostr:' + id)
|
||||
modifiedComment += ' nostr:' + nip19.noteEncode(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);
|
||||
worker.postMessage({
|
||||
unsigned: {
|
||||
kind: 1,
|
||||
tags,
|
||||
content: modifiedComment,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
pubkey: getPublicKey(sk),
|
||||
}, difficulty
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
setComment(comment + " " + error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setDoingWorkProp(false)
|
||||
if (messageFromWorker) {
|
||||
try {
|
||||
const signedEvent = finishEvent(messageFromWorker, sk);
|
||||
publish(signedEvent);
|
||||
|
||||
setComment("");
|
||||
setFile("");
|
||||
setSk(generatePrivateKey())
|
||||
setMessageFromWorker(null);
|
||||
|
||||
return () => {
|
||||
worker.terminate();
|
||||
};
|
||||
} catch (error) {
|
||||
setComment(error + ' ' + comment);
|
||||
}
|
||||
}
|
||||
}, [messageFromWorker]);
|
||||
|
||||
async function attachFile(file_input: File | null) {
|
||||
try {
|
||||
if (file_input) {
|
||||
@ -74,7 +115,10 @@ const ThreadPost = ({ state, type }: { state: Boolean, type: String }) => {
|
||||
method="post"
|
||||
encType="multipart/form-data"
|
||||
className=""
|
||||
onSubmit={handleSubmit}
|
||||
onSubmit={(event) => {
|
||||
handleSubmit(event);
|
||||
setDoingWorkProp(true);
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="MAX_FILE_SIZE" defaultValue={4194304} />
|
||||
<div id="togglePostFormLink" className="text-lg font-semibold">
|
||||
@ -124,6 +168,12 @@ const ThreadPost = ({ state, type }: { state: Boolean, type: String }) => {
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
{doingWorkProp ? (
|
||||
<div className='flex animate-pulse text-sm text-gray-300'>
|
||||
<CpuChipIcon className="h-4 w-4 ml-auto" />
|
||||
<span>Working...</span>
|
||||
</div>
|
||||
) : null}
|
||||
<div id="postFormError" className="text-red-500" />
|
||||
</form>)}
|
||||
</>
|
||||
|
32
client/src/utils/postNote.ts
Normal file
32
client/src/utils/postNote.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import {
|
||||
type Event as NostrEvent,
|
||||
generatePrivateKey,
|
||||
getEventHash,
|
||||
getPublicKey,
|
||||
signEvent,
|
||||
} from "nostr-tools";
|
||||
|
||||
export const handleThreadSubmit = async (comment: string, tags: []) => {
|
||||
if (!comment) {
|
||||
alert("no message provided");
|
||||
return;
|
||||
}
|
||||
|
||||
const newEvent: NostrEvent = {
|
||||
id: 'null',
|
||||
content: comment,
|
||||
kind: 1,
|
||||
tags,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
pubkey: 'null',
|
||||
sig: 'null',
|
||||
};
|
||||
|
||||
let sk = generatePrivateKey();
|
||||
|
||||
newEvent.pubkey = getPublicKey(sk);
|
||||
newEvent.id = getEventHash(newEvent);
|
||||
newEvent.sig = signEvent(newEvent, sk);
|
||||
|
||||
return newEvent
|
||||
};
|
Loading…
Reference in New Issue
Block a user