rebuild tools view

This commit is contained in:
hzrd149
2023-11-27 17:19:23 -06:00
parent 5b0ab0a1a8
commit c8ee526adf
7 changed files with 203 additions and 172 deletions

View File

@@ -0,0 +1,5 @@
---
"nostrudel": minor
---
Rebuild tools view

View File

@@ -1,11 +1,4 @@
import {
MouseEventHandler,
MutableRefObject,
forwardRef,
useCallback,
useMemo,
useRef,
} from "react";
import { MouseEventHandler, MutableRefObject, forwardRef, useCallback, useMemo, useRef } from "react";
import { Image, ImageProps, Link, LinkProps } from "@chakra-ui/react";
import appSettings from "../../services/settings/app-settings";

View File

@@ -22,56 +22,57 @@ export default function LightningSettings() {
return (
<AccordionItem>
{({ isExpanded }) => (<>
<h2>
<AccordionButton fontSize="xl">
<LightningIcon mr="2" />
<Box as="span" flex="1" textAlign="left">
Lightning
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel>
<Flex direction="column" gap="4">
{isExpanded && <Button />}
<FormControl>
<Flex alignItems="center">
<FormLabel htmlFor="autoPayWithWebLN" mb="0">
Auto pay with WebLN
</FormLabel>
<Switch id="autoPayWithWebLN" {...register("autoPayWithWebLN")} />
{({ isExpanded }) => (
<>
<h2>
<AccordionButton fontSize="xl">
<LightningIcon mr="2" />
<Box as="span" flex="1" textAlign="left">
Lightning
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel>
<Flex direction="column" gap="4">
{isExpanded && <Button />}
<FormControl>
<Flex alignItems="center">
<FormLabel htmlFor="autoPayWithWebLN" mb="0">
Auto pay with WebLN
</FormLabel>
<Switch id="autoPayWithWebLN" {...register("autoPayWithWebLN")} />
</Flex>
<FormHelperText>
<span>Enabled: Attempt to automatically pay with WebLN if its available</span>
</FormHelperText>
</FormControl>
<FormControl>
<FormLabel htmlFor="customZapAmounts" mb="0">
Zap Amounts
</FormLabel>
<Input
id="customZapAmounts"
autoComplete="off"
{...register("customZapAmounts", {
validate: (v) => {
if (!/^[\d,]*$/.test(v)) return "Must be a list of comma separated numbers";
return true;
},
})}
/>
{formState.errors.customZapAmounts && (
<FormErrorMessage>{formState.errors.customZapAmounts.message}</FormErrorMessage>
)}
<FormHelperText>
<span>Comma separated list of custom zap amounts</span>
</FormHelperText>
</FormControl>
</Flex>
<FormHelperText>
<span>Enabled: Attempt to automatically pay with WebLN if its available</span>
</FormHelperText>
</FormControl>
<FormControl>
<FormLabel htmlFor="customZapAmounts" mb="0">
Zap Amounts
</FormLabel>
<Input
id="customZapAmounts"
autoComplete="off"
{...register("customZapAmounts", {
validate: (v) => {
if (!/^[\d,]*$/.test(v)) return "Must be a list of comma separated numbers";
return true;
},
})}
/>
{formState.errors.customZapAmounts && (
<FormErrorMessage>{formState.errors.customZapAmounts.message}</FormErrorMessage>
)}
<FormHelperText>
<span>Comma separated list of custom zap amounts</span>
</FormHelperText>
</FormControl>
</Flex>
</AccordionPanel>
</>
</AccordionPanel>
</>
)}
</AccordionItem>
);

View File

@@ -1,4 +1,4 @@
import { Flex } from "@chakra-ui/react";
import { Button, Flex } from "@chakra-ui/react";
import { memo, useRef } from "react";
import { Kind } from "nostr-tools";
@@ -12,6 +12,8 @@ import IntersectionObserverProvider, { useRegisterIntersectionEntity } from "../
import useSubject from "../../hooks/use-subject";
import EmbeddedDM from "../../components/embed-event/event-types/embedded-dm";
import { NostrEvent } from "../../types/nostr-event";
import { ChevronLeftIcon } from "../../components/icons";
import { useNavigate } from "react-router-dom";
const DirectMessage = memo(({ dm }: { dm: NostrEvent }) => {
const ref = useRef<HTMLDivElement | null>(null);
@@ -25,6 +27,7 @@ const DirectMessage = memo(({ dm }: { dm: NostrEvent }) => {
});
export function DMFeedPage() {
const navigate = useNavigate();
const { listId, filter } = usePeopleListContext();
const readRelays = useReadRelayUrls();
@@ -48,6 +51,9 @@ export function DMFeedPage() {
return (
<VerticalPageLayout>
<Flex gap="2">
<Button leftIcon={<ChevronLeftIcon />} onClick={() => navigate(-1)}>
Back
</Button>
<PeopleListSelection />
</Flex>
<IntersectionObserverProvider callback={callback}>

View File

@@ -1,105 +1,114 @@
import { Button, Divider, Flex, Heading, Image, Link } from "@chakra-ui/react";
import {
Button,
Card,
CardHeader,
ComponentWithAs,
Flex,
Heading,
IconProps,
Image,
Link,
LinkBox,
} from "@chakra-ui/react";
import { Link as RouterLink } from "react-router-dom";
import { ExternalLinkIcon, LiveStreamIcon, MapIcon, ToolsIcon } from "../../components/icons";
import VerticalPageLayout from "../../components/vertical-page-layout";
import { ConnectedRelays } from "../../components/connected-relays";
import { DirectMessagesIcon, ExternalLinkIcon, LiveStreamIcon, MapIcon, MuteIcon } from "../../components/icons";
import VerticalPageLayout from "../../components/vertical-page-layout";
import ShieldOff from "../../components/icons/shield-off";
import HoverLinkOverlay from "../../components/hover-link-overlay";
import Users01 from "../../components/icons/users-01";
import PackageSearch from "../../components/icons/package-search";
function InternalLink({
to,
icon: Icon,
children,
}: {
to?: string;
icon: ComponentWithAs<"svg", IconProps>;
children: string;
}) {
return (
<Card as={LinkBox} alignItems="center" p="4" gap="4" minW="40">
<Icon boxSize={10} />
<CardHeader p="0">
<Heading size="md">
<HoverLinkOverlay as={RouterLink} to={to}>
{children}
</HoverLinkOverlay>
</Heading>
</CardHeader>
</Card>
);
}
function ExternalLink({ href, image, children }: { href?: string; image: string; children: string }) {
return (
<Card as={LinkBox} alignItems="center" p="4" gap="4" minW="40">
<Image src={image} h="10" />
<CardHeader p="0">
<Heading size="md">
<HoverLinkOverlay as={Link} href={href} isExternal>
{children}
</HoverLinkOverlay>
</Heading>
</CardHeader>
</Card>
);
}
export default function ToolsHomeView() {
return (
<VerticalPageLayout>
<Heading>
<ToolsIcon /> Tools
</Heading>
<Divider />
<Heading>Tools</Heading>
<Flex wrap="wrap" gap="4">
<Button as={RouterLink} to="/tools/content-discovery">
Content Discovery DVM
</Button>
<Button as={RouterLink} to="/tools/network">
Contact network
</Button>
<Button as={RouterLink} to="/tools/network-mute-graph">
Contacts Mute Graph
</Button>
<Button as={RouterLink} to="/tools/network-dm-graph">
Contacts DM Graph
</Button>
<Button as={RouterLink} to="/tools/dm-feed">
<InternalLink to="/tools/content-discovery" icon={PackageSearch}>
Discovery DVM
</InternalLink>
<InternalLink to="/tools/network" icon={Users01}>
User Network
</InternalLink>
<InternalLink to="/tools/network-mute-graph" icon={MuteIcon}>
Mute Graph
</InternalLink>
<InternalLink to="/tools/network-dm-graph" icon={DirectMessagesIcon}>
DM Graph
</InternalLink>
<InternalLink to="/tools/dm-feed" icon={ShieldOff}>
DM Feed
</Button>
<Button as={RouterLink} to="/map" leftIcon={<MapIcon />}>
</InternalLink>
<InternalLink to="/map" icon={MapIcon}>
Map
</Button>
<Button as={RouterLink} to="/tools/stream-moderation" leftIcon={<LiveStreamIcon />}>
</InternalLink>
<InternalLink to="/tools/stream-moderation" icon={LiveStreamIcon}>
Stream Moderation
</Button>
<ConnectedRelays />
</InternalLink>
</Flex>
<Heading size="lg" mt="4">
Third party tools
</Heading>
<Divider />
<Flex wrap="wrap" gap="4">
<Button
as={Link}
href="https://w3.do/"
isExternal
target="_blank"
leftIcon={<Image src="https://w3.do/favicon.ico" h="1.5em" />}
>
<ExternalLink href="https://w3.do/" image="https://w3.do/favicon.ico">
URL Shortener
</Button>
<Button
as={Link}
href="https://nak.nostr.com/"
isExternal
target="_blank"
leftIcon={<Image src="https://nak.nostr.com/favicon.ico" h="1.5em" />}
>
</ExternalLink>
<ExternalLink href="https://nak.nostr.com/" image="https://nak.nostr.com/favicon.ico">
nostr army knife
</Button>
<Button
as={Link}
href="https://nostr-delete.vercel.app/"
isExternal
target="_blank"
leftIcon={<ExternalLinkIcon />}
>
</ExternalLink>
<ExternalLink href="https://nostr-delete.vercel.app/" image="https://nostr-delete.vercel.app/favicon.png">
Nostr Event Deletion
</Button>
<Button
as={Link}
href="https://nostrdebug.com/"
isExternal
target="_blank"
leftIcon={<Image src="https://nostrdebug.com/favicon.ico" h="1.5em" />}
>
</ExternalLink>
<ExternalLink href="https://nostrdebug.com/" image="https://nostrdebug.com/favicon.ico">
Nostr Debug
</Button>
<Button
as={Link}
href="https://metadata.nostr.com/"
isExternal
target="_blank"
leftIcon={<Image src="https://metadata.nostr.com/img/git.png" h="1.5em" />}
>
</ExternalLink>
<ExternalLink href="https://metadata.nostr.com/" image="https://metadata.nostr.com/img/git.png">
Nostr Profile Manager
</Button>
<Button
as={Link}
</ExternalLink>
<ExternalLink
href="https://www.nostrapps.com/"
isExternal
target="_blank"
leftIcon={
<Image
src="https://uploads-ssl.webflow.com/641d0d46d5c124ac928a6027/64b1dd06d59d8f1e530d2926_32x32.png"
h="1.5em"
/>
}
image="https://uploads-ssl.webflow.com/641d0d46d5c124ac928a6027/64b1dd06d59d8f1e530d2926_32x32.png"
>
Nostr Apps
</Button>
</ExternalLink>
</Flex>
</VerticalPageLayout>
);

View File

@@ -1,5 +1,5 @@
import { useEffect, useMemo, useState } from "react";
import { Box, Flex, Input, Text } from "@chakra-ui/react";
import { Box, Button, Flex, Input, Text } from "@chakra-ui/react";
import AutoSizer from "react-virtualized-auto-sizer";
import ForceGraph, { LinkObject, NodeObject } from "react-force-graph-3d";
import { Kind } from "nostr-tools";
@@ -28,10 +28,13 @@ import RelaySelectionProvider, { useRelaySelectionContext } from "../../provider
import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
import { useDebounce } from "react-use";
import useSubject from "../../hooks/use-subject";
import { ChevronLeftIcon } from "../../components/icons";
import { useNavigate } from "react-router-dom";
type NodeType = { id: string; image?: string; name?: string };
function NetworkDMGraphPage() {
const navigate = useNavigate();
const account = useCurrentAccount()!;
const { relays } = useRelaySelectionContext();
@@ -110,6 +113,9 @@ function NetworkDMGraphPage() {
return (
<Flex direction="column" gap="2" h="full" pt="2">
<Flex gap="2" alignItems="center">
<Button leftIcon={<ChevronLeftIcon />} onClick={() => navigate(-1)}>
Back
</Button>
<Input
type="datetime-local"
maxW="sm"

View File

@@ -1,5 +1,5 @@
import { useMemo, useRef } from "react";
import { Box } from "@chakra-ui/react";
import { Box, Button, Flex, Text } from "@chakra-ui/react";
import AutoSizer from "react-virtualized-auto-sizer";
import ForceGraph, { LinkObject, NodeObject } from "react-force-graph-3d";
import {
@@ -22,6 +22,8 @@ import { useReadRelayUrls } from "../../hooks/use-client-relays";
import replaceableEventLoaderService from "../../services/replaceable-event-requester";
import useSubjects from "../../hooks/use-subjects";
import { useUserMetadata } from "../../hooks/use-user-metadata";
import { useNavigate } from "react-router-dom";
import { ChevronLeftIcon } from "../../components/icons";
export function useUsersMuteLists(pubkeys: string[], additionalRelays: string[] = []) {
const readRelays = useReadRelayUrls(additionalRelays);
@@ -34,6 +36,7 @@ export function useUsersMuteLists(pubkeys: string[], additionalRelays: string[]
type NodeType = { id: string; image?: string; name?: string };
function NetworkGraphPage() {
const navigate = useNavigate();
const account = useCurrentAccount()!;
const selfMetadata = useUserMetadata(account.pubkey);
@@ -82,44 +85,52 @@ function NetworkGraphPage() {
}, [contacts, usersMuteLists, usersMetadata, selfMetadata]);
return (
<Box overflow="hidden" flex={1}>
<AutoSizer>
{({ height, width }) => (
<ForceGraph<NodeType>
graphData={graphData}
enableNodeDrag={false}
width={width}
height={height}
linkDirectionalArrowLength={3.5}
linkDirectionalArrowRelPos={1}
linkCurvature={0.25}
nodeThreeObject={(node: NodeType) => {
if (!node.image) {
return new Mesh(new SphereGeometry(5, 12, 6), new MeshBasicMaterial({ color: 0xaa0f0f }));
}
<Flex direction="column" gap="2" h="full" pt="2">
<Flex gap="2" alignItems="center">
<Button leftIcon={<ChevronLeftIcon />} onClick={() => navigate(-1)}>
Back
</Button>
<Text>Showing how many of your contacts are muting each other</Text>
</Flex>
<Box overflow="hidden" flex={1}>
<AutoSizer>
{({ height, width }) => (
<ForceGraph<NodeType>
graphData={graphData}
enableNodeDrag={false}
width={width}
height={height}
linkDirectionalArrowLength={3.5}
linkDirectionalArrowRelPos={1}
linkCurvature={0.25}
nodeThreeObject={(node: NodeType) => {
if (!node.image) {
return new Mesh(new SphereGeometry(5, 12, 6), new MeshBasicMaterial({ color: 0xaa0f0f }));
}
const group = new Group();
const group = new Group();
const imgTexture = new TextureLoader().load(node.image);
imgTexture.colorSpace = SRGBColorSpace;
const material = new SpriteMaterial({ map: imgTexture });
const sprite = new Sprite(material);
sprite.scale.set(10, 10, 10);
const imgTexture = new TextureLoader().load(node.image);
imgTexture.colorSpace = SRGBColorSpace;
const material = new SpriteMaterial({ map: imgTexture });
const sprite = new Sprite(material);
sprite.scale.set(10, 10, 10);
group.children.push(sprite);
group.children.push(sprite);
// if (node.name) {
// const text = new SpriteText(node.name, 8, "ffffff");
// text.position.set(0, 0, 16);
// group.children.push(text);
// }
// if (node.name) {
// const text = new SpriteText(node.name, 8, "ffffff");
// text.position.set(0, 0, 16);
// group.children.push(text);
// }
return sprite;
}}
/>
)}
</AutoSizer>
</Box>
return sprite;
}}
/>
)}
</AutoSizer>
</Box>
</Flex>
);
}