mirror of
https://github.com/smolgrrr/TAO.git
synced 2024-09-20 01:11:25 +00:00
add deterministic icon and start context relay stuff
This commit is contained in:
parent
d754c20158
commit
e968c13939
@ -3,7 +3,9 @@ import './App.css';
|
|||||||
import Home from './components/Home';
|
import Home from './components/Home';
|
||||||
import Settings from './components/Settings';
|
import Settings from './components/Settings';
|
||||||
import SwipeableViews from 'react-swipeable-views';
|
import SwipeableViews from 'react-swipeable-views';
|
||||||
|
import { NostrProvider } from './utils/relays';
|
||||||
|
|
||||||
|
const relayUrls = ['wss://relay.damus.io'];
|
||||||
function App() {
|
function App() {
|
||||||
const [index, setIndex] = React.useState(1);
|
const [index, setIndex] = React.useState(1);
|
||||||
|
|
||||||
@ -13,7 +15,7 @@ function App() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<NostrProvider relayUrls={relayUrls} debug={true}>
|
||||||
<SwipeableViews index={index} onChangeIndex={handleChangeIndex}>
|
<SwipeableViews index={index} onChangeIndex={handleChangeIndex}>
|
||||||
<div>
|
<div>
|
||||||
<Settings />
|
<Settings />
|
||||||
@ -22,7 +24,7 @@ function App() {
|
|||||||
<Home />
|
<Home />
|
||||||
</div>
|
</div>
|
||||||
</SwipeableViews>
|
</SwipeableViews>
|
||||||
</div>
|
</NostrProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,19 @@ function getRandomElement(array: string[]): string {
|
|||||||
const index = Math.floor(Math.random() * array.length);
|
const index = Math.floor(Math.random() * array.length);
|
||||||
return array[index];
|
return array[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getColorFromHash = (id: string, colors: string[]): string => {
|
||||||
|
// Create a simple hash from the event.id
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < id.length; i++) {
|
||||||
|
hash = (hash << 5) - hash + id.charCodeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the hash to pick a color from the colors array
|
||||||
|
const index = Math.abs(hash) % colors.length;
|
||||||
|
return colors[index];
|
||||||
|
};
|
||||||
|
|
||||||
const timeAgo = (unixTime: number) => {
|
const timeAgo = (unixTime: number) => {
|
||||||
const seconds = Math.floor((new Date().getTime() / 1000) - unixTime);
|
const seconds = Math.floor((new Date().getTime() / 1000) - unixTime);
|
||||||
|
|
||||||
@ -52,6 +65,7 @@ const PostCard = ({ event}: { event: Event }) => {
|
|||||||
// limit: 200,
|
// limit: 200,
|
||||||
// },
|
// },
|
||||||
// ]);
|
// ]);
|
||||||
|
const colorCombo = getColorFromHash(event.id, colorCombos);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -59,7 +73,7 @@ const PostCard = ({ event}: { event: Event }) => {
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className={`h-5 w-5 bg-gradient-to-r ${getRandomElement(colorCombos)} rounded-full`} />
|
<div className={`h-5 w-5 bg-gradient-to-r ${colorCombo} rounded-full`} />
|
||||||
<div className="ml-2 text-md font-semibold">Anonymous</div>
|
<div className="ml-2 text-md font-semibold">Anonymous</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center ml-auto">
|
<div className="flex items-center ml-auto">
|
||||||
|
152
client/src/utils/relays.tsx
Normal file
152
client/src/utils/relays.tsx
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
import {
|
||||||
|
createContext,
|
||||||
|
ReactNode,
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react"
|
||||||
|
import { Relay, Filter, Event, relayInit, Sub } from "nostr-tools"
|
||||||
|
import { uniqBy } from "./utils"
|
||||||
|
|
||||||
|
type OnConnectFunc = (relay: Relay) => void
|
||||||
|
type OnDisconnectFunc = (relay: Relay) => void
|
||||||
|
type OnEventFunc = (event: Event) => void
|
||||||
|
type OnDoneFunc = () => void
|
||||||
|
type OnSubscribeFunc = (sub: Sub, relay: Relay) => void
|
||||||
|
|
||||||
|
interface NostrContextType {
|
||||||
|
isLoading: boolean
|
||||||
|
debug?: boolean
|
||||||
|
connectedRelays: Relay[]
|
||||||
|
onConnect: (_onConnectCallback?: OnConnectFunc) => void
|
||||||
|
onDisconnect: (_onDisconnectCallback?: OnDisconnectFunc) => void
|
||||||
|
publish: (event: Event) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const NostrContext = createContext<NostrContextType>({
|
||||||
|
isLoading: true,
|
||||||
|
connectedRelays: [],
|
||||||
|
onConnect: () => null,
|
||||||
|
onDisconnect: () => null,
|
||||||
|
publish: () => null,
|
||||||
|
})
|
||||||
|
|
||||||
|
const log = (
|
||||||
|
isOn: boolean | undefined,
|
||||||
|
type: "info" | "error" | "warn",
|
||||||
|
...args: unknown[]
|
||||||
|
) => {
|
||||||
|
if (!isOn) return
|
||||||
|
console[type](...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NostrProvider({
|
||||||
|
children,
|
||||||
|
relayUrls,
|
||||||
|
debug,
|
||||||
|
}: {
|
||||||
|
children: ReactNode
|
||||||
|
relayUrls: string[]
|
||||||
|
debug?: boolean
|
||||||
|
}) {
|
||||||
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
|
const [connectedRelays, setConnectedRelays] = useState<Relay[]>([])
|
||||||
|
const [relays, setRelays] = useState<Relay[]>([])
|
||||||
|
const relayUrlsRef = useRef<string[]>([])
|
||||||
|
|
||||||
|
let onConnectCallback: null | OnConnectFunc = null
|
||||||
|
let onDisconnectCallback: null | OnDisconnectFunc = null
|
||||||
|
|
||||||
|
const disconnectToRelays = useCallback(
|
||||||
|
(relayUrls: string[]) => {
|
||||||
|
relayUrls.forEach(async (relayUrl) => {
|
||||||
|
await relays.find((relay) => relay.url === relayUrl)?.close()
|
||||||
|
setRelays((prev) => prev.filter((r) => r.url !== relayUrl))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[relays],
|
||||||
|
)
|
||||||
|
|
||||||
|
const connectToRelays = useCallback(
|
||||||
|
(relayUrls: string[]) => {
|
||||||
|
relayUrls.forEach(async (relayUrl) => {
|
||||||
|
const relay = relayInit(relayUrl)
|
||||||
|
|
||||||
|
if (connectedRelays.findIndex((r) => r.url === relayUrl) >= 0) {
|
||||||
|
// already connected, skip
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setRelays((prev) => uniqBy([...prev, relay], "url"))
|
||||||
|
relay.connect()
|
||||||
|
|
||||||
|
relay.on("connect", () => {
|
||||||
|
log(debug, "info", `✅ nostr (${relayUrl}): Connected!`)
|
||||||
|
setIsLoading(false)
|
||||||
|
onConnectCallback?.(relay)
|
||||||
|
setConnectedRelays((prev) => uniqBy([...prev, relay], "url"))
|
||||||
|
})
|
||||||
|
|
||||||
|
relay.on("disconnect", () => {
|
||||||
|
log(debug, "warn", `🚪 nostr (${relayUrl}): Connection closed.`)
|
||||||
|
onDisconnectCallback?.(relay)
|
||||||
|
setConnectedRelays((prev) => prev.filter((r) => r.url !== relayUrl))
|
||||||
|
})
|
||||||
|
|
||||||
|
relay.on("error", () => {
|
||||||
|
log(debug, "error", `❌ nostr (${relayUrl}): Connection error!`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[connectedRelays, debug, onConnectCallback, onDisconnectCallback],
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (relayUrlsRef.current === relayUrls) {
|
||||||
|
// relayUrls isn't updated, skip
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const relayUrlsToDisconnect = relayUrlsRef.current.filter(
|
||||||
|
(relayUrl) => !relayUrls.includes(relayUrl),
|
||||||
|
)
|
||||||
|
|
||||||
|
disconnectToRelays(relayUrlsToDisconnect)
|
||||||
|
connectToRelays(relayUrls)
|
||||||
|
|
||||||
|
relayUrlsRef.current = relayUrls
|
||||||
|
}, [relayUrls, connectToRelays, disconnectToRelays])
|
||||||
|
|
||||||
|
const publish = (event: Event) => {
|
||||||
|
return connectedRelays.map((relay) => {
|
||||||
|
log(debug, "info", `⬆️ nostr (${relay.url}): Sending event:`, event)
|
||||||
|
|
||||||
|
return relay.publish(event)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const value: NostrContextType = {
|
||||||
|
debug,
|
||||||
|
isLoading,
|
||||||
|
connectedRelays,
|
||||||
|
publish,
|
||||||
|
onConnect: (_onConnectCallback?: OnConnectFunc) => {
|
||||||
|
if (_onConnectCallback) {
|
||||||
|
onConnectCallback = _onConnectCallback
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDisconnect: (_onDisconnectCallback?: OnDisconnectFunc) => {
|
||||||
|
if (_onDisconnectCallback) {
|
||||||
|
onDisconnectCallback = _onDisconnectCallback
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return <NostrContext.Provider value={value}>{children}</NostrContext.Provider>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useNostr() {
|
||||||
|
return useContext(NostrContext)
|
||||||
|
}
|
21
client/src/utils/utils.ts
Normal file
21
client/src/utils/utils.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export const uniqBy = <T>(arr: T[], key: keyof T): T[] => {
|
||||||
|
return Object.values(
|
||||||
|
arr.reduce(
|
||||||
|
(map, item) => ({
|
||||||
|
...map,
|
||||||
|
[`${item[key]}`]: item,
|
||||||
|
}),
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const uniqValues = (value: string, index: number, self: string[]) => {
|
||||||
|
return self.indexOf(value) === index
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dateToUnix = (_date?: Date) => {
|
||||||
|
const date = _date || new Date()
|
||||||
|
|
||||||
|
return Math.floor(date.getTime() / 1000)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user