Remove "open in drawer" for notes

This commit is contained in:
hzrd149 2025-01-16 15:59:11 -06:00
parent 7ad01e97c8
commit 0b6e8e9947
12 changed files with 15 additions and 396 deletions

View File

@ -0,0 +1,5 @@
---
"nostrudel": minor
---
Remove "open in drawer" for notes

View File

@ -6,7 +6,6 @@ import GlobalStyles from "./styles";
import { ErrorBoundary } from "./components/error-boundary";
import AppLayout from "./components/layout";
import DrawerSubViewProvider from "./providers/drawer-sub-view-provider";
import { RouteProviders } from "./providers/route";
import useSetColorMode from "./hooks/use-set-color-mode";
@ -138,11 +137,9 @@ export const App = () => (
<ErrorBoundary>
<GlobalStyles />
<TaskManagerProvider parentRouter={router}>
<DrawerSubViewProvider parentRouter={router}>
<Suspense fallback={<Spinner />}>
<RouterProvider router={router} />
</Suspense>
</DrawerSubViewProvider>
<Suspense fallback={<Spinner />}>
<RouterProvider router={router} />
</Suspense>
</TaskManagerProvider>
</ErrorBoundary>
);

View File

@ -1,7 +1,6 @@
import { MouseEventHandler, useCallback } from "react";
import { Card, CardProps, Flex, LinkBox, Spacer } from "@chakra-ui/react";
import { Link as RouterLink, useNavigate } from "react-router";
import { useObservable } from "applesauce-react/hooks";
import { NostrEvent } from "../../../types/nostr-event";
import UserAvatarLink from "../../user/user-avatar-link";
@ -11,16 +10,13 @@ import { TrustProvider } from "../../../providers/local/trust-provider";
import { NoteLink } from "../../note/note-link";
import Timestamp from "../../timestamp";
import { CompactNoteContent } from "../../compact-note-content";
import { useNavigateInDrawer } from "../../../providers/drawer-sub-view-provider";
import HoverLinkOverlay from "../../hover-link-overlay";
import { getSharableEventAddress } from "../../../services/relay-hints";
import localSettings from "../../../services/local-settings";
import useAppSettings from "../../../hooks/use-user-app-settings";
export default function EmbeddedNote({ event, ...props }: Omit<CardProps, "children"> & { event: NostrEvent }) {
const { showSignatureVerification } = useAppSettings();
const enableDrawer = useObservable(localSettings.enableNoteThreadDrawer);
const navigate = enableDrawer ? useNavigateInDrawer() : useNavigate();
const navigate = useNavigate();
const to = `/n/${getSharableEventAddress(event)}`;
const handleClick = useCallback<MouseEventHandler>(

View File

@ -1,5 +1,6 @@
import { Card, CardProps, Flex, LinkBox, Spacer, Text } from "@chakra-ui/react";
import { Link as RouterLink } from "react-router";
import { Link as RouterLink, useNavigate } from "react-router";
import { nip19 } from "nostr-tools";
import { NostrEvent } from "../../../types/nostr-event";
import UserAvatarLink from "../../user/user-avatar-link";
@ -12,16 +13,14 @@ import HoverLinkOverlay from "../../hover-link-overlay";
import { getThreadReferences } from "../../../helpers/nostr/event";
import useSingleEvent from "../../../hooks/use-single-event";
import { getTorrentTitle } from "../../../helpers/nostr/torrents";
import { useNavigateInDrawer } from "../../../providers/drawer-sub-view-provider";
import { MouseEventHandler, useCallback } from "react";
import { nip19 } from "nostr-tools";
import useAppSettings from "../../../hooks/use-user-app-settings";
export default function EmbeddedTorrentComment({
comment,
...props
}: Omit<CardProps, "children"> & { comment: NostrEvent }) {
const navigate = useNavigateInDrawer();
const navigate = useNavigate();
const { showSignatureVerification } = useAppSettings();
const refs = getThreadReferences(comment);
const torrent = useSingleEvent(refs.root?.e?.id, refs.root?.e?.relays);

View File

@ -24,14 +24,12 @@ import Timestamp from "../../timestamp";
import Magnet from "../../icons/magnet";
import { getTorrentMagnetLink, getTorrentSize, getTorrentTitle } from "../../../helpers/nostr/torrents";
import { formatBytes } from "../../../helpers/number";
import { useNavigateInDrawer } from "../../../providers/drawer-sub-view-provider";
import HoverLinkOverlay from "../../hover-link-overlay";
import { getSharableEventAddress } from "../../../services/relay-hints";
import localSettings from "../../../services/local-settings";
export default function EmbeddedTorrent({ torrent, ...props }: Omit<CardProps, "children"> & { torrent: NostrEvent }) {
const enableDrawer = useObservable(localSettings.enableNoteThreadDrawer);
const navigate = enableDrawer ? useNavigateInDrawer() : useNavigate();
const navigate = useNavigate();
const link = `/torrents/${getSharableEventAddress(torrent)}`;
const handleClick = useCallback<MouseEventHandler>(

View File

@ -1,91 +0,0 @@
import {
Box,
Button,
Center,
Drawer,
DrawerBody,
DrawerContent,
DrawerHeader,
DrawerOverlay,
Flex,
ModalProps,
Spacer,
Text,
} from "@chakra-ui/react";
import { Link as RouterLink } from "react-router";
import { IconButton } from "@chakra-ui/react";
import { useObservable } from "applesauce-react/hooks";
import { UserAvatar } from "../../user/user-avatar";
import useCurrentAccount from "../../../hooks/use-current-account";
import UserName from "../../user/user-name";
import UserDnsIdentity from "../../user/user-dns-identity";
import { DirectMessagesIcon, RelayIcon, SearchIcon, SettingsIcon } from "../../icons";
import { bakery$ } from "../../../services/bakery";
export default function DrawerNav({ isOpen, onClose, ...props }: Omit<ModalProps, "children">) {
const account = useCurrentAccount();
const bakery = useObservable(bakery$);
return (
<Drawer placement="left" onClose={onClose} isOpen={isOpen} {...props}>
<DrawerOverlay />
<DrawerContent>
<DrawerHeader borderBottomWidth="1px" display="flex" gap="2" p="4">
{account ? (
<>
<UserAvatar pubkey={account.pubkey} />
<Box flex={1}>
<UserName pubkey={account.pubkey} isTruncated />
<Text fontSize="sm" fontWeight="normal" isTruncated>
<UserDnsIdentity pubkey={account.pubkey} />
</Text>
</Box>
<IconButton
as={RouterLink}
w="10"
h="10"
aria-label="Settings"
title="Settings"
variant="outline"
icon={<SettingsIcon boxSize={5} />}
to="/settings"
/>
{/* <ColorModeButton variant="ghost" /> */}
</>
) : (
<Button as={RouterLink} to="/login">
Login
</Button>
)}
</DrawerHeader>
<DrawerBody p="0" display="flex" flexDirection="column">
<Flex as={RouterLink} to="/search" alignItems="center" p="2" gap="2" tabIndex={0} cursor="pointer">
<Center w="10" h="10">
<SearchIcon boxSize={5} />
</Center>
<Text fontWeight="bold">Search</Text>
</Flex>
<Flex as={RouterLink} to="/messages" alignItems="center" p="2" gap="2" tabIndex={0} cursor="pointer">
<Center w="10" h="10">
<DirectMessagesIcon boxSize={5} />
</Center>
<Text fontWeight="bold">Messages</Text>
</Flex>
<Flex as={RouterLink} to="/network" alignItems="center" p="2" gap="2" tabIndex={0} cursor="pointer">
<Center w="10" h="10">
<RelayIcon boxSize={6} />
</Center>
<Text fontWeight="bold">My Network</Text>
</Flex>
<Spacer />
{bakery && (
<Button variant="link" p="4" w="full" as={RouterLink} to="/dashboard">
Bakery
</Button>
)}
</DrawerBody>
</DrawerContent>
</Drawer>
);
}

View File

@ -1,32 +0,0 @@
import { MouseEventHandler, useCallback } from "react";
import { IconButton, IconButtonProps } from "@chakra-ui/react";
import { To } from "react-router";
import { DrawerIcon } from "../icons";
import { useNavigateInDrawer } from "../../providers/drawer-sub-view-provider";
export default function OpenInDrawerButton({
to,
onClick,
...props
}: Omit<IconButtonProps, "aria-label"> & { to: To }) {
const navigate = useNavigateInDrawer();
const handleClick = useCallback<MouseEventHandler<HTMLButtonElement>>(
(e) => {
navigate(to);
if (onClick) onClick(e);
},
[navigate, onClick],
);
return (
<IconButton
icon={<DrawerIcon />}
aria-label="Open in drawer"
title="Open in drawer"
onClick={handleClick}
{...props}
/>
);
}

View File

@ -34,7 +34,6 @@ import NoteReactions from "./components/note-reactions";
import ReplyForm from "../../../views/thread/components/reply-form";
import { getThreadReferences } from "../../../helpers/nostr/event";
import Timestamp from "../../timestamp";
import OpenInDrawerButton from "../open-in-drawer-button";
import { useBreakpointValue } from "../../../providers/global/breakpoint-provider";
import HoverLinkOverlay from "../../hover-link-overlay";
import NoteCommunityMetadata from "./note-community-metadata";
@ -100,9 +99,6 @@ export function TimelineNote({
<NotePublishedUsing event={event} />
<Flex grow={1} />
{showSignatureVerification && <EventVerificationIcon event={event} />}
{!hideDrawerButton && (
<OpenInDrawerButton to={`/n/${getSharableEventAddress(event)}`} size="sm" variant="ghost" />
)}
</Flex>
<NoteCommunityMetadata event={event} />
{showReplyLine && <ReplyContext event={event} />}

View File

@ -1,222 +0,0 @@
import {
PropsWithChildren,
Suspense,
createContext,
lazy,
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import {
ButtonGroup,
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerHeader,
DrawerOverlay,
DrawerProps,
Heading,
IconButton,
Spinner,
} from "@chakra-ui/react";
import { Location, RouteObject, RouterProvider, To, createMemoryRouter, useNavigate } from "react-router";
import { ErrorBoundary } from "../components/error-boundary";
import ThreadView from "../views/thread";
import { ChevronLeftIcon, ChevronRightIcon, ExternalLinkIcon } from "../components/icons";
import { logger } from "../helpers/debug";
import { RouteProviders } from "./route";
import useRouterMarker from "../hooks/use-router-marker";
const TorrentDetailsView = lazy(() => import("../views/torrents/torrent"));
type Router = ReturnType<typeof createMemoryRouter>;
const IsInDrawerContext = createContext(false);
const DrawerSubViewContext = createContext<{ openDrawer: (route: To) => void; closeDrawer: () => void }>({
openDrawer() {},
closeDrawer() {},
});
function DrawerSubView({
router,
openInParent,
...props
}: Omit<DrawerProps, "children"> & { router: Router; openInParent: (to: To) => void }) {
const [title, setTitle] = useState("");
return (
<Drawer size="xl" {...props}>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader p="2">
<ButtonGroup size="sm">
<IconButton icon={<ChevronLeftIcon />} aria-label="Back" onClick={() => router.navigate(-1)} />
<IconButton icon={<ChevronRightIcon />} aria-label="Forward" onClick={() => router.navigate(+1)} />
<IconButton
icon={<ExternalLinkIcon />}
aria-label="Open"
onClick={() => openInParent(router.state.location)}
/>
</ButtonGroup>
{title}
</DrawerHeader>
<DrawerBody px="2" pb="2" pt="0">
<ErrorBoundary>
<IsInDrawerContext.Provider value={true}>
<Suspense
fallback={
<Heading size="md" mx="auto" my="4">
<Spinner /> Loading page
</Heading>
}
>
<RouterProvider router={router} />
</Suspense>
</IsInDrawerContext.Provider>
</ErrorBoundary>
</DrawerBody>
</DrawerContent>
</Drawer>
);
}
const routes: RouteObject[] = [
{
path: "/n/:id",
element: (
<RouteProviders>
<ThreadView />
</RouteProviders>
),
},
{
path: "/torrents/:id",
element: (
<RouteProviders>
<TorrentDetailsView />
</RouteProviders>
),
},
];
export function useDrawerSubView() {
return useContext(DrawerSubViewContext);
}
export function useNavigateInDrawer() {
const navigate = useNavigate();
const isInDrawer = useContext(IsInDrawerContext);
const { openDrawer } = useDrawerSubView();
return isInDrawer ? navigate : openDrawer;
}
const log = logger.extend("DrawerRouter");
export default function DrawerSubViewProvider({
children,
parentRouter,
}: PropsWithChildren & { parentRouter: Router }) {
const [router, setRouter] = useState<Router | null>(null);
const openInParent = useCallback((to: To) => parentRouter.navigate(to), [parentRouter]);
const direction = useRef<"up" | "down">();
const marker = useRouterMarker(parentRouter);
useEffect(() => {
return parentRouter.subscribe((event) => {
const location = event.location as Location<{ subRouterPath?: To | null } | null>;
const subRoute = location.state?.subRouterPath;
if (subRoute) {
if (router) {
if (router.state.location.pathname !== subRoute && direction.current !== "up") {
log("Updating router from parent state");
direction.current = "down";
router.navigate(subRoute);
direction.current = undefined;
}
} else {
log("Create Router");
const newRouter = createMemoryRouter(routes, { initialEntries: [subRoute] });
newRouter.subscribe((e) => {
if (
e.errors &&
e.errors["__shim-error-route__"].status === 404 &&
e.errors["__shim-error-route__"].internal
) {
openInParent(e.location);
} else if (direction.current !== "down") {
log("Updating parent state from Router");
direction.current = "up";
parentRouter.navigate(parentRouter.state.location, {
preventScrollReset: true,
state: { ...parentRouter.state.location.state, subRouterPath: e.location.pathname },
});
}
direction.current = undefined;
});
// use the parent routers createHref method so that users can open links in new tabs
newRouter.createHref = parentRouter.createHref;
setRouter(newRouter);
}
} else if (router) {
log("Destroy Router");
setRouter(null);
}
});
}, [parentRouter, router, setRouter]);
const openDrawer = useCallback(
(to: To) => {
marker.set();
parentRouter.navigate(parentRouter.state.location, {
preventScrollReset: true,
state: { ...parentRouter.state.location.state, subRouterPath: to },
});
},
[parentRouter],
);
const closeDrawer = useCallback(() => {
const i = marker.index.current;
if (i !== null && i > 0) {
log(`Navigating back ${i} entries to the point the drawer was opened`);
parentRouter.navigate(-i);
} else {
log(`Failed to navigate back, clearing state`);
parentRouter.navigate(parentRouter.state.location, {
preventScrollReset: true,
state: { ...parentRouter.state.location.state, subRouterPath: undefined },
});
}
// reset marker
marker.reset();
}, [parentRouter]);
const context = useMemo(
() => ({
openDrawer,
closeDrawer,
}),
[openDrawer, closeDrawer],
);
return (
<DrawerSubViewContext.Provider value={context}>
{children}
{router && <DrawerSubView router={router} isOpen onClose={closeDrawer} openInParent={openInParent} />}
</DrawerSubViewContext.Provider>
);
}

View File

@ -14,14 +14,6 @@ import { nanoid } from "nanoid";
const idbMaxEvents = new NumberLocalStorageEntry("nostr-idb-max-events", 10_000);
const wasmPersistForDays = new NullableNumberLocalStorageEntry("wasm-relay-oldest-event", 365);
// note behavior
const enableNoteThreadDrawer = new LocalStorageEntry(
"enable-note-thread-drawer",
false,
(raw) => raw === "true",
(v) => String(v),
);
const hideZapBubbles = new BooleanLocalStorageEntry("hide-zap-bubbles", false);
// webrtc relay
@ -72,7 +64,6 @@ const bakeryURL = new LocalStorageEntry<string>("bakery-url", "");
const localSettings = {
idbMaxEvents,
wasmPersistForDays,
enableNoteThreadDrawer,
hideZapBubbles,
webRtcLocalIdentity,
webRtcSignalingRelays,

View File

@ -1,4 +1,5 @@
import { MouseEventHandler, useCallback, useMemo } from "react";
import { AvatarGroup, Box, Button, ButtonGroup, Flex, LinkBox, Text, useDisclosure } from "@chakra-ui/react";
import { kinds, NostrEvent } from "nostr-tools";
import { useObservable } from "applesauce-react/hooks";
import { Link as RouterLink, useNavigate } from "react-router";
@ -12,7 +13,6 @@ import { useNotifications } from "../../providers/global/notifications-provider"
import { TORRENT_COMMENT_KIND } from "../../helpers/nostr/torrents";
import { groupByRoot } from "../../helpers/notification";
import { ChevronLeftIcon } from "../../components/icons";
import { AvatarGroup, Box, Button, ButtonGroup, Flex, LinkBox, Text, useDisclosure } from "@chakra-ui/react";
import UserAvatarLink from "../../components/user/user-avatar-link";
import useSingleEvent from "../../hooks/use-single-event";
import UserLink from "../../components/user/user-link";
@ -21,7 +21,6 @@ import Timestamp from "../../components/timestamp";
import HoverLinkOverlay from "../../components/hover-link-overlay";
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
import { useNavigateInDrawer } from "../../providers/drawer-sub-view-provider";
import useEventIntersectionRef from "../../hooks/use-event-intersection-ref";
import useShareableEventAddress from "../../hooks/use-shareable-event-address";
import localSettings from "../../services/local-settings";
@ -30,8 +29,7 @@ import GitBranch01 from "../../components/icons/git-branch-01";
const THREAD_KINDS = [kinds.ShortTextNote, TORRENT_COMMENT_KIND];
function ReplyEntry({ event }: { event: NostrEvent }) {
const enableDrawer = useObservable(localSettings.enableNoteThreadDrawer);
const navigate = enableDrawer ? useNavigateInDrawer() : useNavigate();
const navigate = useNavigate();
const address = useShareableEventAddress(event);
const onClick = useCallback<MouseEventHandler>(
(e) => {

View File

@ -21,7 +21,6 @@ export default function DisplaySettings() {
const { register, submit, formState } = useSettingsForm();
const hideZapBubbles = useObservable(localSettings.hideZapBubbles);
const enableNoteDrawer = useObservable(localSettings.enableNoteThreadDrawer);
return (
<SimpleView
@ -165,21 +164,6 @@ export default function DisplaySettings() {
<span>Enabled: shows a warning for notes with NIP-36 Content Warning</span>
</FormHelperText>
</FormControl>
<FormControl>
<Flex alignItems="center">
<FormLabel htmlFor="enableNoteDrawer" mb="0">
Open embedded notes in side drawer
</FormLabel>
<Switch
id="enableNoteDrawer"
isChecked={enableNoteDrawer}
onChange={() => localSettings.enableNoteThreadDrawer.next(!localSettings.enableNoteThreadDrawer.value)}
/>
</Flex>
<FormHelperText>
<span>Enabled: Clicking on an embedded note will open it in a side drawer</span>
</FormHelperText>
</FormControl>
<FormControl>
<FormLabel htmlFor="muted-words" mb="0">
Muted words