some cleanup

This commit is contained in:
hzrd149 2023-02-24 08:38:53 -06:00
parent be77fad706
commit 759edb33ad
11 changed files with 76 additions and 68 deletions

View File

@ -1,13 +1,13 @@
import { Menu, MenuButton, MenuList, IconButton, MenuListProps, MenuButtonProps } from "@chakra-ui/react";
import { Menu, MenuButton, MenuList, IconButton, MenuListProps, IconButtonProps } from "@chakra-ui/react";
import { MoreIcon } from "./icons";
export type MenuIconButtonProps = MenuButtonProps & {
export type MenuIconButtonProps = IconButtonProps & {
children: MenuListProps["children"];
};
export const MenuIconButton = ({ children, ...props }: MenuIconButtonProps) => (
<Menu isLazy>
<MenuButton as={IconButton} icon={<MoreIcon />} aria-label="view raw" title="view raw" size="xs" {...props} />
<MenuButton as={IconButton} icon={<MoreIcon />} {...props} />
<MenuList>{children}</MenuList>
</Menu>
);

View File

@ -69,28 +69,30 @@ export const Note = React.memo(({ event, maxHeight }: NoteProps) => {
</CardBody>
<CardFooter padding="2" display="flex" gap="2">
<IconButton
variant="link"
icon={<ReplyIcon />}
title="Reply"
aria-label="Reply"
onClick={reply}
size="xs"
size="sm"
isDisabled={account.readonly}
/>
<IconButton
variant="link"
icon={<ShareIcon />}
onClick={share}
aria-label="Share Note"
title="Share Note"
size="xs"
size="sm"
isDisabled={account.readonly}
/>
<ButtonGroup size="xs" isAttached>
<NoteZapButton note={event} size="xs" />
<NoteLikeButton note={event} size="xs" />
<ButtonGroup size="sm" variant="link">
<NoteZapButton note={event} size="sm" />
<NoteLikeButton note={event} size="sm" />
</ButtonGroup>
<Box flexGrow={1} />
<NoteRelays event={event} size="xs" />
<NoteMenu event={event} />
<NoteRelays event={event} size="sm" variant="link" />
<NoteMenu event={event} size="sm" variant="link" aria-label="More Options" />
</CardFooter>
</Card>
);

View File

@ -12,13 +12,13 @@ import { useCopyToClipboard } from "react-use";
import { Bech32Prefix, normalizeToBech32 } from "../../helpers/nip-19";
import { NostrEvent } from "../../types/nostr-event";
import { MenuIconButton } from "../menu-icon-button";
import { MenuIconButton, MenuIconButtonProps } from "../menu-icon-button";
import { ClipboardIcon, CodeIcon, LikeIcon } from "../icons";
import { getReferences } from "../../helpers/nostr-event";
import NoteReactionsModal from "./note-reactions-modal";
export const NoteMenu = ({ event }: { event: NostrEvent }) => {
export const NoteMenu = ({ event, ...props }: { event: NostrEvent } & Omit<MenuIconButtonProps, "children">) => {
const infoModal = useDisclosure();
const reactionsModal = useDisclosure();
const [_clipboardState, copyToClipboard] = useCopyToClipboard();
@ -26,7 +26,7 @@ export const NoteMenu = ({ event }: { event: NostrEvent }) => {
return (
<>
<MenuIconButton>
<MenuIconButton {...props}>
<MenuItem onClick={reactionsModal.onOpen} icon={<LikeIcon />}>
Reactions
</MenuItem>

View File

@ -51,7 +51,7 @@ export const NoteRelays = memo(({ event, ...props }: NoteRelaysProps) => {
return (
<Popover isLazy>
<PopoverTrigger>
<IconButton title="Note Relays" icon={<RelayIcon />} size={props.size ?? "sm"} aria-label="Note Relays" />
<IconButton title="Note Relays" icon={<RelayIcon />} aria-label="Note Relays" {...props} />
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />

View File

@ -1,7 +0,0 @@
import { useCurrentAccount } from "./use-current-account";
/** @deprecated */
export function useReadonlyMode() {
const account = useCurrentAccount();
return account.readonly;
}

View File

@ -85,7 +85,7 @@ class ClientRelayService {
await results.onComplete;
// pass new event to the user relay service
userRelaysService.handleEvent(event);
userRelaysService.receiveEvent(event);
}
getWriteUrls() {

View File

@ -35,30 +35,28 @@ async function fetchIdentity(address: string) {
const { name, domain } = parseAddress(address);
if (!name || !domain) throw new Error("invalid address");
try {
const json = await fetch(`https://${domain}/.well-known/nostr.json?name=${name}`)
.then((res) => res.json() as Promise<IdentityJson>)
.then((json) => {
// convert all keys in names, and relays to lower case
if (json.names) {
for (const [name, pubkey] of Object.entries(json.names)) {
delete json.names[name];
json.names[name.toLowerCase()] = pubkey;
}
const json = await fetch(`https://${domain}/.well-known/nostr.json?name=${name}`)
.then((res) => res.json() as Promise<IdentityJson>)
.then((json) => {
// convert all keys in names, and relays to lower case
if (json.names) {
for (const [name, pubkey] of Object.entries(json.names)) {
delete json.names[name];
json.names[name.toLowerCase()] = pubkey;
}
if (json.relays) {
for (const [name, pubkey] of Object.entries(json.relays)) {
delete json.relays[name];
json.relays[name.toLowerCase()] = pubkey;
}
}
if (json.relays) {
for (const [name, pubkey] of Object.entries(json.relays)) {
delete json.relays[name];
json.relays[name.toLowerCase()] = pubkey;
}
return json;
});
}
return json;
});
await addToCache(domain, json);
await addToCache(domain, json);
return getIdentityFromJson(name, domain, json);
} catch (e) {}
return getIdentityFromJson(name, domain, json);
}
async function addToCache(domain: string, json: IdentityJson) {

View File

@ -5,9 +5,12 @@ import { Kind0ParsedContent, parseKind0Event } from "../helpers/user-metadata";
import { SuperMap } from "../classes/super-map";
import Subject from "../classes/subject";
class UserMetadataService extends CachedPubkeyEventRequester {
class UserMetadataService {
requester: CachedPubkeyEventRequester;
constructor() {
super(0, "user-metadata");
this.requester = new CachedPubkeyEventRequester(0, "user-metadata");
this.requester.readCache = this.readCache;
this.requester.writeCache = this.writeCache;
}
readCache(pubkey: string) {
@ -20,13 +23,18 @@ class UserMetadataService extends CachedPubkeyEventRequester {
private parsedSubjects = new SuperMap<string, Subject<Kind0ParsedContent>>(() => new Subject<Kind0ParsedContent>());
requestMetadata(pubkey: string, relays: string[], alwaysRequest = false) {
const sub = this.parsedSubjects.get(pubkey);
const requestSub = this.requestEvent(pubkey, relays, alwaysRequest);
const requestSub = this.requester.requestEvent(pubkey, relays, alwaysRequest);
sub.connectWithHandler(requestSub, (event, next) => next(parseKind0Event(event)));
return sub;
}
receiveEvent(event: NostrEvent) {
this.requester.handleEvent(event);
}
update() {
this.requester.update();
}
}
const userMetadataService = new UserMetadataService();
@ -35,9 +43,4 @@ setInterval(() => {
userMetadataService.update();
}, 1000 * 2);
if (import.meta.env.DEV) {
// @ts-ignore
window.userMetadataService = userMetadataService;
}
export default userMetadataService;

View File

@ -20,9 +20,12 @@ function parseRelaysEvent(event: NostrEvent): UserRelays {
};
}
class UserRelaysService extends CachedPubkeyEventRequester {
class UserRelaysService {
requester: CachedPubkeyEventRequester;
constructor() {
super(10002, "user-relays");
this.requester = new CachedPubkeyEventRequester(10002, "user-relays");
this.requester.readCache = this.readCache;
this.requester.writeCache = this.writeCache;
}
readCache(pubkey: string) {
@ -32,16 +35,21 @@ class UserRelaysService extends CachedPubkeyEventRequester {
return db.put("userRelays", event);
}
private parsedSubjects = new SuperMap<string, Subject<UserRelays>>(() => new Subject<UserRelays>());
private subjects = new SuperMap<string, Subject<UserRelays>>(() => new Subject<UserRelays>());
requestRelays(pubkey: string, relays: string[], alwaysRequest = false) {
const sub = this.parsedSubjects.get(pubkey);
const requestSub = this.requestEvent(pubkey, relays, alwaysRequest);
const sub = this.subjects.get(pubkey);
const requestSub = this.requester.requestEvent(pubkey, relays, alwaysRequest);
sub.connectWithHandler(requestSub, (event, next) => next(parseRelaysEvent(event)));
return sub;
}
receiveEvent(event: NostrEvent) {
this.requester.handleEvent(event);
}
update() {
this.requester.update();
}
}
const userRelaysService = new UserRelaysService();

View File

@ -118,10 +118,14 @@ const MetadataForm = ({ defaultValues, onSubmit }: MetadataFormProps) => {
minLength: 5,
validate: async (address) => {
if (!address) return true;
if (!address.includes("@")) return "invalid address";
const id = await dnsIdentityService.getIdentity(address);
if (!id) return "cant find NIP-05 ID";
if (id.pubkey !== account.pubkey) return "Pubkey dose not match";
if (!address.includes("@")) return "Invalid address";
try {
const id = await dnsIdentityService.getIdentity(address);
if (!id) return "Cant find NIP-05 ID";
if (id.pubkey !== account.pubkey) return "Pubkey dose not match";
} catch (e) {
return "Failed to fetch ID";
}
return true;
},
})}
@ -224,7 +228,7 @@ export const ProfileEditView = () => {
const event = await signingService.requestSignature(draft, account);
const results = nostrPostAction(writeRelays, event);
userMetadataService.handleEvent(event);
userMetadataService.receiveEvent(event);
await results.onComplete;
} catch (e) {

View File

@ -35,8 +35,8 @@ export default function Header({ pubkey }: { pubkey: string }) {
<UserDnsIdentityIcon pubkey={pubkey} />
</Flex>
<Flex gap="2">
<UserTipButton pubkey={pubkey} size="xs" />
<UserProfileMenu pubkey={pubkey} />
<UserTipButton pubkey={pubkey} size="sm" variant="link" />
<UserProfileMenu pubkey={pubkey} aria-label="More Options" size="sm" variant="link" />
</Flex>
</Flex>
{!metadata ? <SkeletonText /> : <Text>{metadata?.about}</Text>}