This commit is contained in:
smolgrrr 2023-10-30 15:58:33 +11:00
parent 1f00204ab6
commit 610256fbfa
7 changed files with 185 additions and 62 deletions

View File

@ -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);

View File

@ -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));

View File

@ -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];

View File

@ -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>

View File

@ -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 (

View File

@ -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 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>)}
</>

View 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
};