Return to natural page scrolling

This commit is contained in:
hzrd149 2023-07-13 22:16:34 -05:00
parent f78605696c
commit 0074c9e735
22 changed files with 70 additions and 66 deletions

View File

@ -0,0 +1,5 @@
---
"nostrudel": minor
---
Remove scroll-boxes and return to natural page scrolling

View File

@ -2,7 +2,7 @@ import React, { Suspense } from "react";
import { createHashRouter, Outlet, RouterProvider, ScrollRestoration } from "react-router-dom";
import { Spinner } from "@chakra-ui/react";
import { ErrorBoundary } from "./components/error-boundary";
import { Page } from "./components/page";
import Layout from "./components/layout";
import HomeView from "./views/home";
import SettingsView from "./views/settings";
@ -43,12 +43,12 @@ const RootPage = () => {
useSetColorMode();
return (
<Page>
<Layout>
<ScrollRestoration />
<Suspense fallback={<Spinner />}>
<Outlet />
</Suspense>
</Page>
</Layout>
);
};

View File

@ -13,7 +13,7 @@ export default function NoteDebugModal({ event, ...props }: { event: NostrEvent
<ModalOverlay />
<ModalContent>
<ModalCloseButton />
<ModalBody overflow="auto" p="4">
<ModalBody p="4">
<Flex gap="2" direction="column">
<RawValue heading="Event Id" value={event.id} />
<RawValue heading="Encoded id (NIP-19)" value={hexToBech32(event.id, Bech32Prefix.Note) ?? "failed"} />

View File

@ -21,7 +21,7 @@ export default function UserDebugModal({ pubkey, ...props }: { pubkey: string }
<ModalOverlay />
<ModalContent>
<ModalCloseButton />
<ModalBody overflow="auto" p="4">
<ModalBody p="4">
<Flex gap="2" direction="column">
<RawValue heading="Hex pubkey" value={pubkey} />
{npub && <RawValue heading="npub" value={npub} />}

View File

@ -54,7 +54,7 @@ const videoExt = [".mp4", ".mkv", ".webm", ".mov"];
export function renderVideoUrl(match: URL) {
if (!videoExt.some((ext) => match.pathname.endsWith(ext))) return null;
return <video src={match.toString()} controls style={{ maxWidth: "30rem", maxHeight: "20rem" }} />;
return <video src={match.toString()} controls style={{ maxWidth: "30rem", maxHeight: "20rem", width: "100%" }} />;
}
export function renderGenericUrl(match: URL) {

View File

@ -1,5 +1,5 @@
import { SettingsIcon } from "@chakra-ui/icons";
import { Avatar, Button, Flex, Heading, IconButton, LinkOverlay, Text, VStack } from "@chakra-ui/react";
import { Avatar, Button, Flex, FlexProps, Heading, IconButton, LinkOverlay, Text, VStack } from "@chakra-ui/react";
import { Link as RouterLink, useNavigate } from "react-router-dom";
import { useCurrentAccount } from "../../hooks/use-current-account";
import accountService from "../../services/account";
@ -20,13 +20,13 @@ import AccountSwitcher from "./account-switcher";
import { useContext } from "react";
import { PostModalContext } from "../../providers/post-modal-provider";
export default function DesktopSideNav() {
export default function DesktopSideNav(props: Omit<FlexProps, "children">) {
const navigate = useNavigate();
const account = useCurrentAccount();
const { openModal } = useContext(PostModalContext);
return (
<VStack width="15rem" pt="2" alignItems="stretch" flexShrink={0}>
<Flex {...props} gap="2" direction="column" width="15rem" pt="2" alignItems="stretch" flexShrink={0}>
<Flex gap="2" alignItems="center" position="relative">
<LinkOverlay as={RouterLink} to="/" />
<Avatar src="/apple-touch-icon.png" size="sm" />
@ -81,6 +81,6 @@ export default function DesktopSideNav() {
onClick={() => openModal()}
/>
</Flex>
</VStack>
</Flex>
);
}

View File

@ -0,0 +1,34 @@
import React from "react";
import { Container, Flex } from "@chakra-ui/react";
import { ErrorBoundary } from "../error-boundary";
import { useIsMobile } from "../../hooks/use-is-mobile";
import { ReloadPrompt } from "../reload-prompt";
import DesktopSideNav from "./desktop-side-nav";
import MobileBottomNav from "./mobile-bottom-nav";
export default function Layout({ children }: { children: React.ReactNode }) {
const isMobile = useIsMobile();
return (
<>
<ReloadPrompt mb="2" />
<Container size="lg" display="flex" padding="0" gap="4" alignItems="flex-start">
{!isMobile && <DesktopSideNav position="sticky" top="0" />}
<Flex flexGrow={1} direction="column" w="full" overflowX="hidden" pb={isMobile ? "14" : 0}>
<ErrorBoundary>{children}</ErrorBoundary>
</Flex>
{isMobile && (
<MobileBottomNav
position="fixed"
bottom="0"
left="0"
right="0"
backgroundColor="var(--chakra-colors-chakra-body-bg)"
zIndex={10}
/>
)}
</Container>
</>
);
}

View File

@ -1,4 +1,4 @@
import { Avatar, Flex, IconButton, useDisclosure } from "@chakra-ui/react";
import { Avatar, Flex, FlexProps, IconButton, useDisclosure } from "@chakra-ui/react";
import { useContext, useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { useCurrentAccount } from "../../hooks/use-current-account";
@ -7,7 +7,7 @@ import { ChatIcon, FeedIcon, HomeIcon, NotificationIcon, PlusCircleIcon, SearchI
import { UserAvatar } from "../user-avatar";
import MobileSideDrawer from "./mobile-side-drawer";
export default function MobileBottomNav() {
export default function MobileBottomNav(props: Omit<FlexProps, "children">) {
const { isOpen, onOpen, onClose } = useDisclosure();
const { openModal } = useContext(PostModalContext);
const navigate = useNavigate();
@ -18,7 +18,7 @@ export default function MobileBottomNav() {
return (
<>
<Flex flexShrink={0} gap="2" padding="2" alignItems="center">
<Flex {...props} gap="2" padding="2" alignItems="center">
{account ? (
<UserAvatar pubkey={account.pubkey} size="sm" onClick={onOpen} noProxy />
) : (

View File

@ -1,36 +0,0 @@
import React from "react";
import { Container, Flex } from "@chakra-ui/react";
import { ErrorBoundary } from "../error-boundary";
import { useIsMobile } from "../../hooks/use-is-mobile";
import { ReloadPrompt } from "../reload-prompt";
import { PostModalProvider } from "../../providers/post-modal-provider";
import DesktopSideNav from "./desktop-side-nav";
import MobileBottomNav from "./mobile-bottom-nav";
export const Page = ({ children }: { children: React.ReactNode }) => {
const isMobile = useIsMobile();
return (
<PostModalProvider>
<Container
size="lg"
display="flex"
flexDirection="column"
height="100%"
overflow="hidden"
position="relative"
padding="0"
>
<ReloadPrompt />
<Flex gap="4" grow={1} overflow="hidden">
{!isMobile && <DesktopSideNav />}
<Flex flexGrow={1} direction="column" overflow="hidden">
<ErrorBoundary>{children}</ErrorBoundary>
</Flex>
</Flex>
{isMobile && <MobileBottomNav />}
</Container>
</PostModalProvider>
);
};

View File

@ -1,10 +1,10 @@
import { useRegisterSW } from "virtual:pwa-register/react";
import { Alert, AlertIcon, AlertTitle, Button, CloseButton, useToast } from "@chakra-ui/react";
import { Alert, AlertIcon, AlertProps, AlertTitle, Button, CloseButton, useToast } from "@chakra-ui/react";
// check for updates every hour
const intervalMS = 60 * 60 * 1000;
export const ReloadPrompt = () => {
export const ReloadPrompt = (props: Omit<AlertProps, "children" | "status">) => {
const toast = useToast();
const {
needRefresh: [needRefresh, setNeedRefresh],
@ -30,7 +30,7 @@ export const ReloadPrompt = () => {
};
return needRefresh ? (
<Alert status="success" flexShrink={0}>
<Alert status="success" {...props}>
<AlertIcon />
<AlertTitle>New update ready!</AlertTitle>
<Button size="sm" ml="auto" onClick={() => updateServiceWorker(true)}>

View File

@ -5,6 +5,7 @@ import createTheme from "../theme";
import useAppSettings from "../hooks/use-app-settings";
import { InvoiceModalProvider } from "./invoice-modal";
import NotificationTimelineProvider from "./notification-timeline";
import PostModalProvider from "./post-modal-provider";
export const Providers = ({ children }: { children: React.ReactNode }) => {
const { primaryColor } = useAppSettings();
@ -14,7 +15,9 @@ export const Providers = ({ children }: { children: React.ReactNode }) => {
<ChakraProvider theme={theme} colorModeManager={localStorageManager}>
<SigningProvider>
<InvoiceModalProvider>
<NotificationTimelineProvider>{children}</NotificationTimelineProvider>
<NotificationTimelineProvider>
<PostModalProvider>{children}</PostModalProvider>
</NotificationTimelineProvider>
</InvoiceModalProvider>
</SigningProvider>
</ChakraProvider>

View File

@ -1,5 +1,5 @@
import React, { PropsWithChildren, useCallback, useMemo, useState } from "react";
import { useDisclosure } from "@chakra-ui/react";
import React, { useCallback, useMemo, useState } from "react";
import { ErrorBoundary } from "../components/error-boundary";
import { PostModal } from "../components/post-modal";
import { DraftNostrEvent } from "../types/nostr-event";
@ -12,7 +12,7 @@ export const PostModalContext = React.createContext<PostModalContextType>({
openModal: () => {},
});
export const PostModalProvider = ({ children }: { children: React.ReactNode }) => {
export default function PostModalProvider({ children }: PropsWithChildren) {
const { isOpen, onOpen, onClose } = useDisclosure();
const [draft, setDraft] = useState<Partial<DraftNostrEvent> | undefined>(undefined);
const openModal = useCallback(
@ -32,4 +32,4 @@ export const PostModalProvider = ({ children }: { children: React.ReactNode }) =
</ErrorBoundary>
</PostModalContext.Provider>
);
};
}

View File

@ -4,5 +4,4 @@ body,
margin: 0;
height: 100%;
width: 100%;
overflow: hidden;
}

View File

@ -61,7 +61,7 @@ const NoteView = () => {
}
return (
<Flex direction="column" gap="4" overflow="auto" flex={1} pb="4" pt="4" pl="1" pr="1">
<Flex direction="column" gap="4" flex={1} pb="4" pt="4" pl="1" pr="1">
{pageContent}
</Flex>
);

View File

@ -68,7 +68,7 @@ const MetadataForm = ({ defaultValues, onSubmit }: MetadataFormProps) => {
}, [defaultValues]);
return (
<Flex direction="column" pb="4" overflow="auto" px={isMobile ? "2" : 0}>
<Flex direction="column" pb="4" px={isMobile ? "2" : 0}>
<form onSubmit={handleSubmit(onSubmit)}>
<Flex direction="column" gap="2" pt="4">
<Flex gap="2">

View File

@ -74,7 +74,7 @@ function RelaysPage() {
const hasPending = pendingAdd.length > 0 || pendingRemove.length > 0;
return (
<Flex direction="column" pt="2" pb="2" overflow="auto">
<Flex direction="column" pt="2" pb="2">
<TableContainer mb="4" overflowY="initial">
<Table variant="simple" size="sm">
<Thead>

View File

@ -28,7 +28,7 @@ export default function SettingsView() {
});
return (
<Flex direction="column" pt="2" pb="2" overflow="auto">
<Flex direction="column" pt="2" pb="2">
<form onSubmit={saveSettings}>
<FormProvider {...form}>
<Accordion defaultIndex={[0]} allowMultiple>

View File

@ -93,7 +93,7 @@ export default function StreamCard({ stream, ...props }: CardProps & { stream: P
<ModalContent>
<ModalHeader>Raw event</ModalHeader>
<ModalCloseButton />
<ModalBody overflow="auto" p="4">
<ModalBody p="4">
<Flex gap="2" direction="column">
<RawValue heading="Event Id" value={stream.event.id} />
<RawValue heading="naddr" value={naddr} />

View File

@ -101,13 +101,12 @@ const UserView = () => {
return (
<>
<AdditionalRelayProvider relays={unique([...userTopRelays, ...pointerRelays])}>
<Flex direction="column" alignItems="stretch" gap="2" overflow="hidden" h="full">
<Flex direction="column" alignItems="stretch" gap="2">
<Header pubkey={pubkey} showRelaySelectionModal={relayModal.onOpen} />
<Tabs
display="flex"
flexDirection="column"
flexGrow="1"
overflow="hidden"
isLazy
index={activeTab}
onChange={(v) => navigate(tabs[v].path)}
@ -119,9 +118,9 @@ const UserView = () => {
))}
</TabList>
<TabPanels overflow="hidden" h="full">
<TabPanels>
{tabs.map(({ label }) => (
<TabPanel key={label} p={0} h="full" overflow="hidden">
<TabPanel key={label} p={0}>
<Suspense fallback={<Spinner />}>
<Outlet context={{ pubkey, setRelayCount }} />
</Suspense>