mirror of
https://github.com/smolgrrr/TAO.git
synced 2024-09-20 09:21:25 +00:00
rm boards
This commit is contained in:
parent
eef394a388
commit
91311e6346
@ -6,8 +6,6 @@ import Thread from "./components/Thread";
|
|||||||
import Header from "./components/Header/Header";
|
import Header from "./components/Header/Header";
|
||||||
import AddToHomeScreenPrompt from "./components/Modals/CheckMobile/CheckMobile";
|
import AddToHomeScreenPrompt from "./components/Modals/CheckMobile/CheckMobile";
|
||||||
import Notifications from "./components/Notifications";
|
import Notifications from "./components/Notifications";
|
||||||
import Board from "./components/Board";
|
|
||||||
import Boards from "./components/Boards";
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
@ -18,8 +16,6 @@ function App() {
|
|||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
<Route path="/thread/:id" element={<Thread />} />
|
<Route path="/thread/:id" element={<Thread />} />
|
||||||
<Route path="/notifications" element={<Notifications />} />
|
<Route path="/notifications" element={<Notifications />} />
|
||||||
<Route path="/board/:id" element={<Board />} />
|
|
||||||
<Route path="/boards" element={<Boards />} />
|
|
||||||
</Routes>
|
</Routes>
|
||||||
<AddToHomeScreenPrompt/>
|
<AddToHomeScreenPrompt/>
|
||||||
</Router>
|
</Router>
|
||||||
|
@ -1,130 +0,0 @@
|
|||||||
import { useEffect, useState, useCallback } from "react";
|
|
||||||
import PostCard from "./Modals/NoteCard";
|
|
||||||
import { uniqBy } from "../utils/otherUtils"; // Assume getPow is a correct import now
|
|
||||||
import { subBoardFeed, subProfile} from "../utils/subscriptions";
|
|
||||||
import { verifyPow } from "../utils/mine";
|
|
||||||
import { Event, nip19 } from "nostr-tools";
|
|
||||||
import NewNoteCard from "./Forms/PostFormCard";
|
|
||||||
import RepostCard from "./Modals/RepostCard";
|
|
||||||
import OptionsBar from "./Modals/OptionsBar";
|
|
||||||
import { useParams } from "react-router-dom";
|
|
||||||
|
|
||||||
const DEFAULT_DIFFICULTY = 20;
|
|
||||||
|
|
||||||
const useUniqEvents = (pubkey: string) => {
|
|
||||||
const [events, setEvents] = useState<Event[]>([]);
|
|
||||||
const age = Number(localStorage.getItem("age")) || 24;
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const onEvent = (event: Event) => setEvents((prevEvents) => [...prevEvents, event]);
|
|
||||||
console.log(events)
|
|
||||||
const unsubscribe = subBoardFeed(pubkey, onEvent, age);
|
|
||||||
|
|
||||||
return unsubscribe;
|
|
||||||
}, [pubkey]);
|
|
||||||
|
|
||||||
const uniqEvents = uniqBy(events, "id");
|
|
||||||
|
|
||||||
const noteEvents = uniqEvents.filter(event => event.kind === 1 || event.kind === 6);
|
|
||||||
const metadataEvents = uniqEvents.filter(event => event.kind === 0);
|
|
||||||
const pinnedEvents = uniqEvents.filter(event => event.pubkey === pubkey && !event.tags.some((tag) => tag[0] === "e"));
|
|
||||||
|
|
||||||
return { pinnedEvents, noteEvents, metadataEvents };
|
|
||||||
};
|
|
||||||
|
|
||||||
const Board = () => {
|
|
||||||
const { id } = useParams();
|
|
||||||
const filterDifficulty = localStorage.getItem("filterDifficulty") || DEFAULT_DIFFICULTY;
|
|
||||||
const [sortByTime, setSortByTime] = useState<boolean>(localStorage.getItem('sortBy') !== 'false');
|
|
||||||
const [setAnon, setSetAnon] = useState<boolean>(localStorage.getItem('anonMode') !== 'false');
|
|
||||||
|
|
||||||
let decodeResult = nip19.decode(id as string);
|
|
||||||
let pubkey = decodeResult.data as string;
|
|
||||||
const {pinnedEvents, noteEvents, metadataEvents } = useUniqEvents(pubkey);
|
|
||||||
|
|
||||||
const [delayedSort, setDelayedSort] = useState(false)
|
|
||||||
|
|
||||||
const postEvents: Event[] = noteEvents
|
|
||||||
.filter((event) =>
|
|
||||||
verifyPow(event) >= Number(filterDifficulty) &&
|
|
||||||
event.kind !== 0 &&
|
|
||||||
(event.kind !== 1 || !event.tags.some((tag) => tag[0] === "e"))
|
|
||||||
)
|
|
||||||
|
|
||||||
// Delayed filtering
|
|
||||||
useEffect(() => {
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
setDelayedSort(true);
|
|
||||||
}, 3000);
|
|
||||||
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
let sortedEvents = [...postEvents]
|
|
||||||
.sort((a, b) =>
|
|
||||||
sortByTime ? b.created_at - a.created_at : verifyPow(b) - verifyPow(a)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (delayedSort) {
|
|
||||||
sortedEvents = sortedEvents.filter(
|
|
||||||
!setAnon ? (e) => !metadataEvents.some((metadataEvent) => metadataEvent.pubkey === e.pubkey) : () => true
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
sortedEvents = sortedEvents.filter((e) => setAnon || e.tags.some((tag) => tag[0] === "client" && tag[1] === 'getwired.app'));
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggleSort = useCallback(() => {
|
|
||||||
setSortByTime(prev => {
|
|
||||||
const newValue = !prev;
|
|
||||||
localStorage.setItem('sortBy', String(newValue));
|
|
||||||
return newValue;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const toggleAnon = useCallback(() => {
|
|
||||||
setSetAnon(prev => {
|
|
||||||
const newValue = !prev;
|
|
||||||
localStorage.setItem('anonMode', String(newValue));
|
|
||||||
return newValue;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const countReplies = (event: Event) => {
|
|
||||||
return noteEvents.filter((e) => e.tags.some((tag) => tag[0] === "e" && tag[1] === event.id)).length;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Render the component
|
|
||||||
return (
|
|
||||||
<main className="text-white mb-20">
|
|
||||||
<div className="w-full px-4 sm:px-0 sm:max-w-xl mx-auto my-2">
|
|
||||||
<NewNoteCard board={id}/>
|
|
||||||
</div>
|
|
||||||
<OptionsBar sortByTime={sortByTime} setAnon={setAnon} toggleSort={toggleSort} toggleAnon={toggleAnon} />
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-4 p-4">
|
|
||||||
{pinnedEvents.map((event) => (
|
|
||||||
<div className="rounded-lg border border-red-900">
|
|
||||||
<PostCard
|
|
||||||
event={event}
|
|
||||||
metadata={metadataEvents.find((e) => e.pubkey === event.pubkey && e.kind === 0) || null}
|
|
||||||
replyCount={countReplies(event)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
{sortedEvents.map((event) => (
|
|
||||||
event.kind === 1 ?
|
|
||||||
<PostCard
|
|
||||||
event={event}
|
|
||||||
metadata={metadataEvents.find((e) => e.pubkey === event.pubkey && e.kind === 0) || null}
|
|
||||||
replyCount={countReplies(event)}
|
|
||||||
/>
|
|
||||||
:
|
|
||||||
<RepostCard
|
|
||||||
event={event}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Board;
|
|
@ -1,85 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
|
|
||||||
export const DefaultBoards = [
|
|
||||||
['Bitcoin', 'npub19nrn4l0s39kpwww7pgk9jddj8lzekqxmtrll8r2a57chtq3zx6sq00vetn', 'btc'],
|
|
||||||
['Technology', 'npub1mltf3r3tskdxfjlq6ltt2n73xs29wcza3sjfw75ggxz3p8fpcg4qe44h9v', 'g'],
|
|
||||||
['Television & Film', 'npub1cpeuaea3cymx42fmmx2ur82t5qnckqv85qy5q2nhzhxwzael5v4sksfe29', 'tv'],
|
|
||||||
['Vidya', 'npub19t2dt6deqaleq59fdaq576tnqdzwkyzwptxfa2tck0v66w29xagqe7yqll', 'v'],
|
|
||||||
['Politically Incorrect', 'npub19znf32s8s7qpkpfrck0suyym3m3wtrwpnldj76u0qwjtms3dcftsqs6r87', 'pol']
|
|
||||||
];
|
|
||||||
|
|
||||||
const Boards = () => {
|
|
||||||
const [addedBoards, setAddedBoards] = useState<string[][]>(JSON.parse(localStorage.getItem('addedBoards') as string) || []);
|
|
||||||
const [boardName, setBoardName] = useState('');
|
|
||||||
const [boardPubkey, setboardPubkey] = useState('')
|
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const newBoards = [...addedBoards, [boardName, boardPubkey]];
|
|
||||||
setAddedBoards(newBoards);
|
|
||||||
localStorage.setItem('addedBoards', JSON.stringify(newBoards));
|
|
||||||
};
|
|
||||||
|
|
||||||
const clearBoards = () => {
|
|
||||||
localStorage.setItem('addedBoards', JSON.stringify([]));
|
|
||||||
setAddedBoards([]);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="settings-page bg-black text-white p-8 flex flex-col h-full">
|
|
||||||
<h1 className="text-lg font-semibold mb-4">Boards</h1>
|
|
||||||
<div className="">
|
|
||||||
{/* Map over DefaultBoards and addedBoards and display them */}
|
|
||||||
<ul className='py-4'>
|
|
||||||
{DefaultBoards.map((board, index) => (
|
|
||||||
<li key={index}><a href={`/board/${board[1]}`} className='hover:underline'>/{board[0]}/</a></li>
|
|
||||||
))}
|
|
||||||
{addedBoards.map((board: string[], index: number) => (
|
|
||||||
<li key={index}><a href={`/board/${board[1]}`} className='hover:underline'>/{board[0]}/</a></li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<div className="flex flex-wrap -mx-2 my-4">
|
|
||||||
<div className="w-full md:w-1/3 px-2 mb-4 md:mb-0">
|
|
||||||
<label className="block text-xs mb-2" htmlFor="difficulty">
|
|
||||||
<span style={{ display: 'inline-flex', alignItems: 'center' }}>
|
|
||||||
Add Board
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
<div className="flex">
|
|
||||||
<input
|
|
||||||
id="BoardName"
|
|
||||||
type="string"
|
|
||||||
placeholder={'Board Name'}
|
|
||||||
onChange={e => setBoardName(e.target.value)}
|
|
||||||
className="w-full px-3 py-2 border rounded-md bg-black"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
id="BoardPubkey"
|
|
||||||
type="string"
|
|
||||||
placeholder={'Board Pubkey'}
|
|
||||||
onChange={e => setboardPubkey(e.target.value)}
|
|
||||||
className="w-full px-3 py-2 border rounded-md bg-black"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="bg-black border text-white font-bold py-2 px-4 rounded">
|
|
||||||
Add Board
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={clearBoards}
|
|
||||||
className="bg-black border text-white font-bold py-2 px-4 rounded mx-4">
|
|
||||||
Clear
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Boards;
|
|
@ -16,13 +16,11 @@ import "./Form.css";
|
|||||||
interface FormProps {
|
interface FormProps {
|
||||||
refEvent?: NostrEvent;
|
refEvent?: NostrEvent;
|
||||||
tagType?: 'Reply' | 'Quote' | '';
|
tagType?: 'Reply' | 'Quote' | '';
|
||||||
board?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NewNoteCard = ({
|
const NewNoteCard = ({
|
||||||
refEvent,
|
refEvent,
|
||||||
tagType,
|
tagType
|
||||||
board
|
|
||||||
}: FormProps) => {
|
}: FormProps) => {
|
||||||
const ref = useRef<HTMLDivElement | null>(null);
|
const ref = useRef<HTMLDivElement | null>(null);
|
||||||
const [comment, setComment] = useState("");
|
const [comment, setComment] = useState("");
|
||||||
@ -62,10 +60,6 @@ const NewNoteCard = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (board) {
|
|
||||||
unsigned.tags.push(['d', nip19.decode(board).data as string]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDifficultyChange = (event: Event) => {
|
const handleDifficultyChange = (event: Event) => {
|
||||||
const customEvent = event as CustomEvent;
|
const customEvent = event as CustomEvent;
|
||||||
const { difficulty } = customEvent.detail;
|
const { difficulty } = customEvent.detail;
|
||||||
|
@ -3,7 +3,6 @@ import {
|
|||||||
BellIcon,
|
BellIcon,
|
||||||
ArchiveBoxIcon
|
ArchiveBoxIcon
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
import { DefaultBoards } from "../Boards";
|
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
return (
|
return (
|
||||||
@ -17,11 +16,6 @@ export default function Header() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div className="hidden md:block">
|
|
||||||
{DefaultBoards.map((board) => (
|
|
||||||
<a href={`/board/${board[1]}`} className='hover:underline text-neutral-600 text-xs pr-4'>/{board[2]}/</a>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
href="/boards"
|
href="/boards"
|
||||||
@ -49,11 +43,6 @@ export default function Header() {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="block md:hidden flex justify-center ">
|
|
||||||
{DefaultBoards.map((board) => (
|
|
||||||
<a href={`/board/${board[1]}`} className='hover:underline text-neutral-600 text-xs pr-4'>/{board[2]}/</a>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ type TestResponse = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Settings = () => {
|
const Settings = () => {
|
||||||
const [filterDifficulty, setFilterDifficulty] = useState(localStorage.getItem('filterDifficulty') || 20);
|
const [filterDifficulty, setFilterDifficulty] = useState(localStorage.getItem('filterDifficulty') || 21);
|
||||||
const [difficulty, setDifficulty] = useState(localStorage.getItem('difficulty') || 21);
|
const [difficulty, setDifficulty] = useState(localStorage.getItem('difficulty') || 21);
|
||||||
const [age, setAge] = useState(localStorage.getItem('age') || 24);
|
const [age, setAge] = useState(localStorage.getItem('age') || 24);
|
||||||
const [showAdvancedSettings, setShowAdvancedSettings] = useState(false);
|
const [showAdvancedSettings, setShowAdvancedSettings] = useState(false);
|
||||||
|
@ -262,98 +262,6 @@ export const subNotifications = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** subscribe to global feed */
|
|
||||||
export const subBoardFeed = (
|
|
||||||
board: string,
|
|
||||||
onEvent: SubCallback,
|
|
||||||
age: number
|
|
||||||
) => {
|
|
||||||
console.info('subscribe to board feed');
|
|
||||||
unsubAll();
|
|
||||||
const now = Math.floor(Date.now() * 0.001);
|
|
||||||
const pubkeys = new Set<string>();
|
|
||||||
const notes = new Set<string>();
|
|
||||||
const prefix = Math.floor(16 / 4); // 4 bits in each '0' character
|
|
||||||
sub({ // get past events
|
|
||||||
cb: (evt, relay) => {
|
|
||||||
pubkeys.add(evt.pubkey);
|
|
||||||
notes.add(evt.id);
|
|
||||||
onEvent(evt, relay);
|
|
||||||
},
|
|
||||||
filter: {
|
|
||||||
...(prefix && { ids: ['0'.repeat(prefix)] }),
|
|
||||||
"#d": [board],
|
|
||||||
kinds: [1, 6],
|
|
||||||
since: Math.floor((Date.now() * 0.001) - (age * 60 * 60)),
|
|
||||||
limit: 500,
|
|
||||||
},
|
|
||||||
unsub: true
|
|
||||||
});
|
|
||||||
sub({
|
|
||||||
cb: (evt, relay) => {
|
|
||||||
onEvent(evt, relay);
|
|
||||||
},
|
|
||||||
filter: {
|
|
||||||
authors: [board],
|
|
||||||
kinds: [1, 7],
|
|
||||||
limit: 25,
|
|
||||||
},
|
|
||||||
unsub: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
// get profile info
|
|
||||||
sub({
|
|
||||||
cb: onEvent,
|
|
||||||
filter: {
|
|
||||||
authors: Array.from(pubkeys),
|
|
||||||
kinds: [0],
|
|
||||||
limit: pubkeys.size,
|
|
||||||
},
|
|
||||||
unsub: true,
|
|
||||||
});
|
|
||||||
pubkeys.clear();
|
|
||||||
|
|
||||||
sub({
|
|
||||||
cb: onEvent,
|
|
||||||
filter: {
|
|
||||||
'#e': Array.from(notes),
|
|
||||||
kinds: [1],
|
|
||||||
},
|
|
||||||
unsub: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
notes.clear();
|
|
||||||
}, 2000);
|
|
||||||
|
|
||||||
// subscribe to future notes, reactions and profile updates
|
|
||||||
sub({
|
|
||||||
cb: (evt, relay) => {
|
|
||||||
onEvent(evt, relay);
|
|
||||||
if (
|
|
||||||
evt.kind !== 1
|
|
||||||
|| pubkeys.has(evt.pubkey)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
subOnce({ // get profile data
|
|
||||||
relay,
|
|
||||||
cb: onEvent,
|
|
||||||
filter: {
|
|
||||||
authors: [evt.pubkey],
|
|
||||||
kinds: [0],
|
|
||||||
limit: 1,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
filter: {
|
|
||||||
...(prefix && { ids: ['0'.repeat(prefix)] }),
|
|
||||||
kinds: [1],
|
|
||||||
since: now,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const subProfile = (
|
export const subProfile = (
|
||||||
pubkey: string,
|
pubkey: string,
|
||||||
onEvent: SubCallback,
|
onEvent: SubCallback,
|
||||||
|
Loading…
Reference in New Issue
Block a user