mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-03-17 21:31:43 +01:00
layout cleanup
This commit is contained in:
parent
0214b69bc7
commit
788dd9bcce
177
src/app.tsx
177
src/app.tsx
@ -4,7 +4,6 @@ import { Spinner } from "@chakra-ui/react";
|
||||
|
||||
import { ErrorBoundary } from "./components/error-boundary";
|
||||
import AppLayout from "./components/layout";
|
||||
import Layout from "./components/legacy-layout";
|
||||
import DrawerSubViewProvider from "./providers/drawer-sub-view-provider";
|
||||
import useSetColorMode from "./hooks/use-set-color-mode";
|
||||
import { RouteProviders } from "./providers/route";
|
||||
@ -78,7 +77,6 @@ import CacheRelayView from "./views/relays/cache";
|
||||
import RelaySetView from "./views/relays/relay-set";
|
||||
import AppRelays from "./views/relays/app";
|
||||
import MailboxesView from "./views/relays/mailboxes";
|
||||
import MediaServersView from "./views/settings/media-servers";
|
||||
import NIP05RelaysView from "./views/relays/nip05";
|
||||
import DatabaseView from "./views/relays/cache/database";
|
||||
import ContactListRelaysView from "./views/relays/contact-list";
|
||||
@ -99,6 +97,7 @@ import PerformanceSettings from "./views/settings/performance";
|
||||
import PrivacySettings from "./views/settings/privacy";
|
||||
import PostSettings from "./views/settings/post";
|
||||
import AccountSettings from "./views/settings/accounts";
|
||||
import MediaServersView from "./views/settings/media-servers";
|
||||
import ArticlesHomeView from "./views/articles";
|
||||
import ArticleView from "./views/articles/article";
|
||||
import WalletView from "./views/wallet";
|
||||
@ -107,6 +106,7 @@ import UserMediaPostsTab from "./views/user/media-posts";
|
||||
import NewView from "./views/new";
|
||||
import NewNoteView from "./views/new/note";
|
||||
import NewMediaPostView from "./views/new/media";
|
||||
import ConnectionStatus from "./components/bakery/connection-status";
|
||||
const TracksView = lazy(() => import("./views/tracks"));
|
||||
const UserTracksTab = lazy(() => import("./views/user/tracks"));
|
||||
const UserVideosTab = lazy(() => import("./views/user/videos"));
|
||||
@ -159,23 +159,17 @@ const RequireBakery = lazy(() => import("./components/router/require-bakery"));
|
||||
const BakerySetupView = lazy(() => import("./views/bakery/setup"));
|
||||
const BakeryAuthView = lazy(() => import("./views/bakery/connect/auth"));
|
||||
const RequireBakeryAuth = lazy(() => import("./components/router/require-bakery-auth"));
|
||||
const DisplaySettingsView = lazy(() => import("./views/bakery/settings/tabs/display-settings"));
|
||||
const NotificationSettingsView = lazy(() => import("./views/bakery/settings/tabs/notifications"));
|
||||
const BakeryGeneralSettingsView = lazy(() => import("./views/bakery/settings/tabs/general-settings"));
|
||||
const BakeryNetworkSettingsView = lazy(() => import("./views/bakery/settings/tabs/network"));
|
||||
const BakeryServiceLogsView = lazy(() => import("./views/bakery/settings/tabs/service-logs"));
|
||||
const NotificationSettingsView = lazy(() => import("./views/settings/bakery/notifications"));
|
||||
const BakeryGeneralSettingsView = lazy(() => import("./views/settings/bakery/general-settings"));
|
||||
const BakeryNetworkSettingsView = lazy(() => import("./views/settings/bakery/network"));
|
||||
const BakeryServiceLogsView = lazy(() => import("./views/settings/bakery/service-logs"));
|
||||
|
||||
const RootPage = () => {
|
||||
useSetColorMode();
|
||||
|
||||
return (
|
||||
<RouteProviders>
|
||||
<Layout>
|
||||
<ScrollRestoration />
|
||||
<Suspense fallback={<Spinner />}>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
</Layout>
|
||||
<AppLayout />
|
||||
</RouteProviders>
|
||||
);
|
||||
};
|
||||
@ -222,50 +216,6 @@ const router = createHashRouter([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "streams/moderation",
|
||||
element: (
|
||||
<RouteProviders>
|
||||
<StreamModerationView />
|
||||
</RouteProviders>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "streams/:naddr",
|
||||
element: (
|
||||
<RouteProviders>
|
||||
<StreamView />
|
||||
</RouteProviders>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "map",
|
||||
element: <MapView />,
|
||||
},
|
||||
{
|
||||
path: "launchpad",
|
||||
element: (
|
||||
<RouteProviders>
|
||||
<LaunchpadView />
|
||||
</RouteProviders>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "/discovery/relays",
|
||||
element: (
|
||||
<RouteProviders>
|
||||
<RelayDiscoveryView />
|
||||
</RouteProviders>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "/tools/publisher",
|
||||
element: (
|
||||
<RouteProviders>
|
||||
<EventPublisherView />
|
||||
</RouteProviders>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "/",
|
||||
element: <RootPage />,
|
||||
@ -283,6 +233,14 @@ const router = createHashRouter([
|
||||
{ path: "media", element: <NewMediaPostView /> },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "launchpad",
|
||||
element: <LaunchpadView />,
|
||||
},
|
||||
{
|
||||
path: "map",
|
||||
element: <MapView />,
|
||||
},
|
||||
{
|
||||
path: "/u/:pubkey",
|
||||
element: <UserView />,
|
||||
@ -334,6 +292,22 @@ const router = createHashRouter([
|
||||
{ path: "lightning", element: <LightningSettings /> },
|
||||
{ path: "performance", element: <PerformanceSettings /> },
|
||||
{ path: "media-servers", element: <MediaServersView /> },
|
||||
{
|
||||
path: "bakery",
|
||||
children: [
|
||||
{ path: "", element: <BakeryGeneralSettingsView /> },
|
||||
{ path: "notifications", element: <NotificationSettingsView /> },
|
||||
{
|
||||
path: "network",
|
||||
element: (
|
||||
<RequireBakeryAuth>
|
||||
<BakeryNetworkSettingsView />
|
||||
</RequireBakeryAuth>
|
||||
),
|
||||
},
|
||||
{ path: "logs", element: <BakeryServiceLogsView /> },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -420,6 +394,14 @@ const router = createHashRouter([
|
||||
{ path: ":pointer", element: <MediaPostView /> },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "streams/moderation",
|
||||
element: <StreamModerationView />,
|
||||
},
|
||||
{
|
||||
path: "streams/:naddr",
|
||||
element: <StreamView />,
|
||||
},
|
||||
{
|
||||
path: "files",
|
||||
children: [
|
||||
@ -466,7 +448,7 @@ const router = createHashRouter([
|
||||
},
|
||||
{ path: "search", element: <SearchView /> },
|
||||
{
|
||||
path: "dm",
|
||||
path: "messages",
|
||||
element: <DirectMessagesView />,
|
||||
children: [{ path: ":pubkey", element: <DirectMessageChatView /> }],
|
||||
},
|
||||
@ -483,8 +465,16 @@ const router = createHashRouter([
|
||||
{ path: "console", element: <EventConsoleView /> },
|
||||
{ path: "corrections", element: <CorrectionsFeedView /> },
|
||||
{ path: "nostrudel-users", element: <NoStrudelUsersView /> },
|
||||
{
|
||||
path: "publisher",
|
||||
element: <EventPublisherView />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/discovery/relays",
|
||||
element: <RelayDiscoveryView />,
|
||||
},
|
||||
{
|
||||
path: "lists",
|
||||
children: [
|
||||
@ -577,7 +567,7 @@ const router = createHashRouter([
|
||||
path: "auth",
|
||||
element: (
|
||||
<RequireBakery>
|
||||
{/* <ConnectionStatus /> */}
|
||||
<ConnectionStatus />
|
||||
<BakeryAuthView />
|
||||
</RequireBakery>
|
||||
),
|
||||
@ -588,28 +578,6 @@ const router = createHashRouter([
|
||||
path: "setup",
|
||||
element: <BakerySetupView />,
|
||||
},
|
||||
// {
|
||||
// path: "network",
|
||||
// element: (
|
||||
// <RequireBakery>
|
||||
// <RequireBakeryAuth>
|
||||
// <AppLayout />
|
||||
// </RequireBakeryAuth>
|
||||
// </RequireBakery>
|
||||
// ),
|
||||
// children: [
|
||||
// {
|
||||
// path: "",
|
||||
// element: <NetworkView />,
|
||||
// children: [
|
||||
// {
|
||||
// path: "",
|
||||
// element: <OverviewList />,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
path: "",
|
||||
element: (
|
||||
@ -622,57 +590,10 @@ const router = createHashRouter([
|
||||
</RequireBakery>
|
||||
),
|
||||
children: [
|
||||
// {
|
||||
// path: "messages",
|
||||
// element: <MessagesView />,
|
||||
// children: [
|
||||
// {
|
||||
// path: "p/:pubkey",
|
||||
// element: <DirectMessageConversationView />,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: "profile/:pubkey",
|
||||
// element: <UserProfileView />,
|
||||
// children: [
|
||||
// { path: "", element: <UserSummaryView /> },
|
||||
// { path: "summary", element: <UserSummaryView /> },
|
||||
// { path: "messages", element: <DirectMessageConversationView /> },
|
||||
// { path: "notes", element: <UserNotesView /> },
|
||||
// { path: "articles", element: <UserArticlesView /> },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
path: "search",
|
||||
element: <SearchView />,
|
||||
},
|
||||
{
|
||||
path: "settings",
|
||||
element: <SettingsView />,
|
||||
children: [
|
||||
{ path: "", element: <DisplaySettingsView /> },
|
||||
{ path: "display", element: <DisplaySettingsView /> },
|
||||
{ path: "notifications", element: <NotificationSettingsView /> },
|
||||
{
|
||||
path: "general",
|
||||
element: (
|
||||
<RequireBakeryAuth>
|
||||
<BakeryGeneralSettingsView />
|
||||
</RequireBakeryAuth>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "network",
|
||||
element: (
|
||||
<RequireBakeryAuth>
|
||||
<BakeryNetworkSettingsView />
|
||||
</RequireBakeryAuth>
|
||||
),
|
||||
},
|
||||
{ path: "logs", element: <BakeryServiceLogsView /> },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "",
|
||||
element: <HomeView />,
|
||||
|
@ -1,28 +1,20 @@
|
||||
import { Flex } from "@chakra-ui/react";
|
||||
import { Suspense } from "react";
|
||||
import { Flex, Spinner } from "@chakra-ui/react";
|
||||
import { Outlet, ScrollRestoration } from "react-router-dom";
|
||||
|
||||
import DesktopSideNav from "./side-nav";
|
||||
import ConnectionStatus from "../connection-status";
|
||||
import { ErrorBoundary } from "../../error-boundary";
|
||||
|
||||
export default function DesktopLayout() {
|
||||
return (
|
||||
<>
|
||||
<ScrollRestoration />
|
||||
<ConnectionStatus />
|
||||
<Flex
|
||||
direction={{
|
||||
base: "column",
|
||||
md: "row",
|
||||
}}
|
||||
overflow="hidden"
|
||||
h="full"
|
||||
>
|
||||
<DesktopSideNav />
|
||||
<DesktopSideNav />
|
||||
<Suspense fallback={<Spinner />}>
|
||||
<ErrorBoundary>
|
||||
<Outlet />
|
||||
</ErrorBoundary>
|
||||
</Flex>
|
||||
</Suspense>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,13 +1,28 @@
|
||||
import { Flex, IconButton, Menu, MenuButton, MenuDivider, MenuItem, MenuList } from "@chakra-ui/react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import { createContext, useState } from "react";
|
||||
import {
|
||||
Flex,
|
||||
FlexProps,
|
||||
IconButton,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuDivider,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
Spacer,
|
||||
} from "@chakra-ui/react";
|
||||
|
||||
import UserAvatar from "../../user/user-avatar";
|
||||
import useCurrentAccount from "../../../hooks/use-current-account";
|
||||
import accountService from "../../../services/account";
|
||||
import UserName from "../../user/user-name";
|
||||
import UserDnsIdentity from "../../user/user-dns-identity";
|
||||
import { DirectMessagesIcon, SettingsIcon, SearchIcon, RelayIcon } from "../../icons";
|
||||
import Home05 from "../../icons/home-05";
|
||||
import { ChevronLeftIcon, ChevronRightIcon, SettingsIcon } from "../../icons";
|
||||
import Plus from "../../icons/plus";
|
||||
import NavItem from "../nav-items/nav-item";
|
||||
import NavItems from "../nav-items";
|
||||
import useRootPadding from "../../../hooks/use-root-padding";
|
||||
|
||||
export const ExpandedContext = createContext(false);
|
||||
|
||||
function UserAccount() {
|
||||
const account = useCurrentAccount()!;
|
||||
@ -37,76 +52,49 @@ function UserAccount() {
|
||||
);
|
||||
}
|
||||
|
||||
export default function DesktopSideNav() {
|
||||
export default function DesktopSideNav({ ...props }: Omit<FlexProps, "children">) {
|
||||
const account = useCurrentAccount();
|
||||
const [expanded, setExpanded] = useState(true);
|
||||
|
||||
useRootPadding({ left: expanded ? "var(--chakra-sizes-64)" : "var(--chakra-sizes-16)" });
|
||||
|
||||
return (
|
||||
<Flex
|
||||
direction="column"
|
||||
gap="2"
|
||||
px="2"
|
||||
py="2"
|
||||
shrink={0}
|
||||
borderRightWidth={1}
|
||||
pt="calc(var(--chakra-space-2) + var(--safe-top))"
|
||||
pb="calc(var(--chakra-space-2) + var(--safe-bottom))"
|
||||
>
|
||||
{account && <UserAccount />}
|
||||
<IconButton
|
||||
as={RouterLink}
|
||||
aria-label="Search"
|
||||
title="Search"
|
||||
icon={<Home05 boxSize={5} />}
|
||||
w="12"
|
||||
h="12"
|
||||
fontSize="24"
|
||||
variant="outline"
|
||||
to="/"
|
||||
/>
|
||||
<IconButton
|
||||
as={RouterLink}
|
||||
aria-label="Search"
|
||||
title="Search"
|
||||
icon={<SearchIcon boxSize={5} />}
|
||||
w="12"
|
||||
h="12"
|
||||
fontSize="24"
|
||||
variant="outline"
|
||||
to="/search"
|
||||
/>
|
||||
<IconButton
|
||||
as={RouterLink}
|
||||
aria-label="Messages"
|
||||
title="Messages"
|
||||
icon={<DirectMessagesIcon boxSize={5} />}
|
||||
w="12"
|
||||
h="12"
|
||||
fontSize="24"
|
||||
variant="outline"
|
||||
to="/messages"
|
||||
/>
|
||||
<IconButton
|
||||
w="12"
|
||||
h="12"
|
||||
as={RouterLink}
|
||||
aria-label="Network"
|
||||
title="Network"
|
||||
icon={<RelayIcon boxSize={6} />}
|
||||
variant="outline"
|
||||
to="/network"
|
||||
/>
|
||||
<IconButton
|
||||
as={RouterLink}
|
||||
w="12"
|
||||
h="12"
|
||||
aria-label="Settings"
|
||||
title="Settings"
|
||||
mt="auto"
|
||||
variant="outline"
|
||||
icon={<SettingsIcon boxSize={5} />}
|
||||
to="/settings"
|
||||
/>
|
||||
{/* {explore.isOpen && <ExploreCommunitiesModal isOpen onClose={explore.onClose} />} */}
|
||||
</Flex>
|
||||
<ExpandedContext.Provider value={expanded}>
|
||||
<Flex
|
||||
direction="column"
|
||||
gap="2"
|
||||
px="2"
|
||||
py="2"
|
||||
shrink={0}
|
||||
borderRightWidth={1}
|
||||
pt="calc(var(--chakra-space-2) + var(--safe-top))"
|
||||
pb="calc(var(--chakra-space-2) + var(--safe-bottom))"
|
||||
w={expanded ? "64" : "16"}
|
||||
position="fixed"
|
||||
left="0"
|
||||
bottom="0"
|
||||
top="0"
|
||||
{...props}
|
||||
>
|
||||
<IconButton
|
||||
aria-label={expanded ? "Close" : "Open"}
|
||||
title={expanded ? "Close" : "Open"}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
icon={expanded ? <ChevronLeftIcon boxSize={5} /> : <ChevronRightIcon boxSize={5} />}
|
||||
position="absolute"
|
||||
bottom="4"
|
||||
right="-4"
|
||||
/>
|
||||
{account && <UserAccount />}
|
||||
<NavItem icon={Plus} label="Create new" colorScheme="primary" to="/new" variant="solid" />
|
||||
|
||||
<NavItems />
|
||||
|
||||
<Spacer />
|
||||
<NavItem label="Settings" icon={SettingsIcon} to="/settings" />
|
||||
</Flex>
|
||||
</ExpandedContext.Provider>
|
||||
);
|
||||
}
|
||||
|
@ -1,29 +1,75 @@
|
||||
import { Flex, IconButton } from "@chakra-ui/react";
|
||||
import { Avatar, Flex, IconButton, useDisclosure } from "@chakra-ui/react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
|
||||
import { DirectMessagesIcon, RelayIcon, SearchIcon } from "../../icons";
|
||||
import Home05 from "../../icons/home-05";
|
||||
import { DirectMessagesIcon, NotesIcon, NotificationsIcon, PlusCircleIcon, SearchIcon } from "../../icons";
|
||||
import useRootPadding from "../../../hooks/use-root-padding";
|
||||
import Rocket02 from "../../icons/rocket-02";
|
||||
import UserAvatar from "../../user/user-avatar";
|
||||
import useCurrentAccount from "../../../hooks/use-current-account";
|
||||
import NavDrawer from "./nav-drawer";
|
||||
|
||||
export default function MobileBottomNav() {
|
||||
useRootPadding({ bottom: "var(--chakra-sizes-14)" });
|
||||
const account = useCurrentAccount();
|
||||
const drawer = useDisclosure();
|
||||
|
||||
return (
|
||||
<Flex
|
||||
gap="2"
|
||||
p="2"
|
||||
borderTopWidth={1}
|
||||
hideFrom="md"
|
||||
bg="var(--chakra-colors-chakra-body-bg)"
|
||||
mb="var(--safe-bottom)"
|
||||
>
|
||||
<IconButton as={RouterLink} to="/" icon={<Home05 boxSize={5} />} aria-label="Search" flex={1} />
|
||||
<IconButton as={RouterLink} to="/search" icon={<SearchIcon boxSize={5} />} aria-label="Search" flex={1} />
|
||||
<IconButton
|
||||
as={RouterLink}
|
||||
to="/messages"
|
||||
icon={<DirectMessagesIcon boxSize={5} />}
|
||||
aria-label="Messages"
|
||||
flex={1}
|
||||
/>
|
||||
<IconButton as={RouterLink} to="/network" icon={<RelayIcon boxSize={6} />} aria-label="Network" flex={1} />
|
||||
</Flex>
|
||||
<>
|
||||
<Flex
|
||||
gap="2"
|
||||
p="2"
|
||||
borderTopWidth={1}
|
||||
hideFrom="md"
|
||||
bg="var(--chakra-colors-chakra-body-bg)"
|
||||
mb="var(--safe-bottom)"
|
||||
position="fixed"
|
||||
bottom="0"
|
||||
left="0"
|
||||
right="0"
|
||||
zIndex="modal"
|
||||
>
|
||||
{account ? (
|
||||
<UserAvatar pubkey={account.pubkey} size="sm" onClick={drawer.onOpen} noProxy />
|
||||
) : (
|
||||
<Avatar size="sm" src="/apple-touch-icon.png" onClick={drawer.onOpen} cursor="pointer" />
|
||||
)}
|
||||
<IconButton as={RouterLink} icon={<NotesIcon boxSize={6} />} aria-label="Home" flexGrow="1" size="md" to="/" />
|
||||
<IconButton
|
||||
as={RouterLink}
|
||||
icon={<SearchIcon boxSize={6} />}
|
||||
aria-label="Search"
|
||||
flexGrow="1"
|
||||
size="md"
|
||||
to="/search"
|
||||
/>
|
||||
<IconButton
|
||||
as={RouterLink}
|
||||
icon={<PlusCircleIcon boxSize={6} />}
|
||||
aria-label="Create new"
|
||||
title="Create new"
|
||||
variant="solid"
|
||||
colorScheme="primary"
|
||||
to="/new"
|
||||
/>
|
||||
<IconButton
|
||||
as={RouterLink}
|
||||
icon={<DirectMessagesIcon boxSize={6} />}
|
||||
aria-label="Messages"
|
||||
flexGrow="1"
|
||||
size="md"
|
||||
to="/messages"
|
||||
/>
|
||||
<IconButton
|
||||
as={RouterLink}
|
||||
icon={<NotificationsIcon boxSize={6} />}
|
||||
aria-label="Notifications"
|
||||
flexGrow="1"
|
||||
size="md"
|
||||
to="/notifications"
|
||||
/>
|
||||
<IconButton as={RouterLink} icon={<Rocket02 boxSize={6} />} aria-label="Launchpad" to="/launchpad" />
|
||||
</Flex>
|
||||
<NavDrawer isOpen={drawer.isOpen} onClose={drawer.onClose} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -2,23 +2,17 @@ import { BehaviorSubject } from "rxjs";
|
||||
import { Outlet, ScrollRestoration } from "react-router-dom";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import ConnectionStatus from "../connection-status";
|
||||
import MobileBottomNav from "./bottom-nav";
|
||||
import { ErrorBoundary } from "../../error-boundary";
|
||||
|
||||
export const showMobileNav = new BehaviorSubject(true);
|
||||
|
||||
export default function MobileLayout() {
|
||||
const showNav = useObservable(showMobileNav);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ScrollRestoration />
|
||||
<ConnectionStatus />
|
||||
<ErrorBoundary>
|
||||
<Outlet />
|
||||
</ErrorBoundary>
|
||||
{showNav && <MobileBottomNav />}
|
||||
<MobileBottomNav />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
51
src/components/layout/mobile/nav-drawer.tsx
Normal file
51
src/components/layout/mobile/nav-drawer.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
Drawer,
|
||||
DrawerBody,
|
||||
DrawerContent,
|
||||
DrawerOverlay,
|
||||
DrawerProps,
|
||||
Flex,
|
||||
Text,
|
||||
} from "@chakra-ui/react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
|
||||
import AccountSwitcher from "../../legacy-layout/account-switcher";
|
||||
import useCurrentAccount from "../../../hooks/use-current-account";
|
||||
import NavItems from "../nav-items";
|
||||
import TaskManagerButtons from "../../legacy-layout/task-manager-buttons";
|
||||
import { ExpandedContext } from "../desktop/side-nav";
|
||||
|
||||
export default function NavDrawer({ ...props }: Omit<DrawerProps, "children">) {
|
||||
const account = useCurrentAccount();
|
||||
|
||||
return (
|
||||
<Drawer placement="left" {...props}>
|
||||
<DrawerOverlay />
|
||||
<DrawerContent>
|
||||
<ExpandedContext.Provider value={true}>
|
||||
<DrawerBody display="flex" flexDirection="column" px="4" pt="4" overflowY="auto" overflowX="hidden" gap="2">
|
||||
{account ? (
|
||||
<AccountSwitcher />
|
||||
) : (
|
||||
<Flex gap="2" my="2" alignItems="center">
|
||||
<Avatar src="/apple-touch-icon.png" size="md" />
|
||||
<Text m={0}>Nostrudel</Text>
|
||||
</Flex>
|
||||
)}
|
||||
<NavItems />
|
||||
<Box h="2" />
|
||||
{!account && (
|
||||
<Button as={RouterLink} to="/signin" colorScheme="primary" flexShrink={0}>
|
||||
Sign in
|
||||
</Button>
|
||||
)}
|
||||
<TaskManagerButtons mt="auto" flexShrink={0} />
|
||||
</DrawerBody>
|
||||
</ExpandedContext.Provider>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
113
src/components/layout/nav-items/index.tsx
Normal file
113
src/components/layout/nav-items/index.tsx
Normal file
@ -0,0 +1,113 @@
|
||||
import { useMemo } from "react";
|
||||
import { ButtonProps } from "@chakra-ui/react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { nip19 } from "nostr-tools";
|
||||
|
||||
import {
|
||||
DirectMessagesIcon,
|
||||
NotificationsIcon,
|
||||
ProfileIcon,
|
||||
RelayIcon,
|
||||
SearchIcon,
|
||||
NotesIcon,
|
||||
LightningIcon,
|
||||
} from "../../icons";
|
||||
import useCurrentAccount from "../../../hooks/use-current-account";
|
||||
import PuzzlePiece01 from "../../icons/puzzle-piece-01";
|
||||
import Package from "../../icons/package";
|
||||
import Rocket02 from "../../icons/rocket-02";
|
||||
import { useBreakpointValue } from "../../../providers/global/breakpoint-provider";
|
||||
import useRecentIds from "../../../hooks/use-recent-ids";
|
||||
import { internalApps, internalTools } from "../../../views/other-stuff/apps";
|
||||
import { App } from "../../../views/other-stuff/component/app-card";
|
||||
import NavItem from "./nav-item";
|
||||
import { QuestionIcon } from "@chakra-ui/icons";
|
||||
|
||||
export default function NavItems() {
|
||||
const location = useLocation();
|
||||
const account = useCurrentAccount();
|
||||
|
||||
const showShortcuts = useBreakpointValue({ base: false, md: true });
|
||||
|
||||
const buttonProps: ButtonProps = {
|
||||
py: "2",
|
||||
justifyContent: "flex-start",
|
||||
variant: "link",
|
||||
};
|
||||
|
||||
let active = "";
|
||||
if (location.pathname.startsWith("/n/")) active = "notes";
|
||||
else if (location.pathname === "/") active = "notes";
|
||||
else if (location.pathname.startsWith("/notifications")) active = "notifications";
|
||||
else if (location.pathname.startsWith("/launchpad")) active = "launchpad";
|
||||
else if (location.pathname.startsWith("/discovery")) active = "discovery";
|
||||
else if (location.pathname.startsWith("/wallet")) active = "wallet";
|
||||
else if (location.pathname.startsWith("/dm")) active = "dm";
|
||||
else if (location.pathname.startsWith("/streams")) active = "streams";
|
||||
else if (location.pathname.startsWith("/relays")) active = "relays";
|
||||
else if (location.pathname.startsWith("/r/")) active = "relays";
|
||||
else if (location.pathname.startsWith("/lists")) active = "lists";
|
||||
else if (location.pathname.startsWith("/channels")) active = "channels";
|
||||
else if (location.pathname.startsWith("/goals")) active = "goals";
|
||||
else if (location.pathname.startsWith("/badges")) active = "badges";
|
||||
else if (location.pathname.startsWith("/emojis")) active = "emojis";
|
||||
else if (location.pathname.startsWith("/settings")) active = "settings";
|
||||
else if (location.pathname.startsWith("/tools")) active = "tools";
|
||||
else if (location.pathname.startsWith("/search")) active = "search";
|
||||
else if (location.pathname.startsWith("/tracks")) active = "tracks";
|
||||
else if (location.pathname.startsWith("/t/")) active = "search";
|
||||
else if (location.pathname.startsWith("/torrents")) active = "tools";
|
||||
else if (location.pathname.startsWith("/map")) active = "tools";
|
||||
else if (location.pathname.startsWith("/profile")) active = "profile";
|
||||
else if (location.pathname.startsWith("/support")) active = "support";
|
||||
else if (location.pathname.startsWith("/other-stuff")) active = "other-stuff";
|
||||
else if (
|
||||
account &&
|
||||
(location.pathname.startsWith("/u/" + nip19.npubEncode(account.pubkey)) ||
|
||||
location.pathname.startsWith("/u/" + account.pubkey))
|
||||
) {
|
||||
active = "profile";
|
||||
}
|
||||
|
||||
const { recent: recentApps } = useRecentIds("apps");
|
||||
const otherStuff = useMemo(() => {
|
||||
const internal = [...internalApps, ...internalTools];
|
||||
const apps = recentApps.map((id) => internal.find((app) => app.id === id)).filter(Boolean) as App[];
|
||||
if (apps.length > 3) {
|
||||
apps.length = 3;
|
||||
} else {
|
||||
if (apps.length < 3 && !apps.some((a) => a.id === "streams")) {
|
||||
apps.push(internal.find((app) => app.id === "streams")!);
|
||||
}
|
||||
if (apps.length < 3 && !apps.some((a) => a.id === "articles")) {
|
||||
apps.push(internal.find((app) => app.id === "articles")!);
|
||||
}
|
||||
if (apps.length < 3 && !apps.some((a) => a.id === "channels")) {
|
||||
apps.push(internal.find((app) => app.id === "channels")!);
|
||||
}
|
||||
}
|
||||
return apps;
|
||||
}, [recentApps]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<NavItem to="/launchpad" icon={Rocket02} label="Launchpad" />
|
||||
<NavItem to="/" icon={NotesIcon} colorScheme={location.pathname === "/" ? "primary" : "gray"} label="Notes" />
|
||||
<NavItem label="Discover" to="/discovery" icon={PuzzlePiece01} />
|
||||
{account && (
|
||||
<>
|
||||
<NavItem to="/notifications" icon={NotificationsIcon} label="Notifications" />
|
||||
<NavItem to="/messages" icon={DirectMessagesIcon} label="Messages" />
|
||||
</>
|
||||
)}
|
||||
<NavItem to="/search" icon={SearchIcon} label="Search" />
|
||||
{account?.pubkey && <NavItem to={"/u/" + nip19.npubEncode(account.pubkey)} icon={ProfileIcon} label="Profile" />}
|
||||
<NavItem to="/relays" icon={RelayIcon} label="Relays" />
|
||||
{otherStuff.map((app) => (
|
||||
<NavItem key={app.id} to={app.to} icon={app.icon || QuestionIcon} label={app.title} />
|
||||
))}
|
||||
<NavItem to="/other-stuff" icon={Package} label="More" />
|
||||
<NavItem to="/support" icon={LightningIcon} label="Support" />
|
||||
</>
|
||||
);
|
||||
}
|
52
src/components/layout/nav-items/nav-item.tsx
Normal file
52
src/components/layout/nav-items/nav-item.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import { useContext } from "react";
|
||||
import { Button, ComponentWithAs, IconButton, IconButtonProps, IconProps } from "@chakra-ui/react";
|
||||
import { To, Link as RouterLink, useLocation } from "react-router-dom";
|
||||
|
||||
import { ExpandedContext } from "../desktop/side-nav";
|
||||
|
||||
export default function NavItem({
|
||||
to,
|
||||
icon: Icon,
|
||||
label,
|
||||
colorScheme,
|
||||
variant,
|
||||
}: {
|
||||
to: string;
|
||||
icon: ComponentWithAs<"svg", IconProps>;
|
||||
label: string;
|
||||
colorScheme?: IconButtonProps["colorScheme"];
|
||||
variant?: IconButtonProps["variant"];
|
||||
}) {
|
||||
const expanded = useContext(ExpandedContext);
|
||||
const location = useLocation();
|
||||
|
||||
if (expanded)
|
||||
return (
|
||||
<Button
|
||||
as={RouterLink}
|
||||
aria-label={label}
|
||||
title={label}
|
||||
leftIcon={<Icon boxSize={5} />}
|
||||
variant={variant || "link"}
|
||||
py="2"
|
||||
justifyContent="flex-start"
|
||||
colorScheme={colorScheme || location.pathname.startsWith(to) ? "primary" : undefined}
|
||||
to={to}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
else
|
||||
return (
|
||||
<IconButton
|
||||
as={RouterLink}
|
||||
aria-label={label}
|
||||
title={label}
|
||||
icon={<Icon boxSize={5} />}
|
||||
fontSize="24"
|
||||
variant={variant || "ghost"}
|
||||
to={to}
|
||||
colorScheme={colorScheme || location.pathname.startsWith(to) ? "primary" : undefined}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,23 +1,23 @@
|
||||
import { Button, ButtonProps } from '@chakra-ui/react';
|
||||
import { useMatch, Link as RouterLink } from 'react-router-dom';
|
||||
import { Button, ButtonProps } from "@chakra-ui/react";
|
||||
import { useMatch, Link as RouterLink } from "react-router-dom";
|
||||
|
||||
export default function SimpleNavItem({
|
||||
children,
|
||||
to,
|
||||
...props
|
||||
}: Omit<ButtonProps, 'variant' | 'colorScheme'> & { to: string }) {
|
||||
const match = useMatch(to);
|
||||
children,
|
||||
to,
|
||||
...props
|
||||
}: Omit<ButtonProps, "variant" | "colorScheme"> & { to: string }) {
|
||||
const match = useMatch(to);
|
||||
|
||||
return (
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to={to}
|
||||
justifyContent="flex-start"
|
||||
{...props}
|
||||
variant="ghost"
|
||||
colorScheme={match ? 'brand' : undefined}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
return (
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to={to}
|
||||
justifyContent="flex-start"
|
||||
{...props}
|
||||
variant="outline"
|
||||
colorScheme={match ? "brand" : undefined}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ export default function SimpleView({
|
||||
as,
|
||||
flush,
|
||||
gap,
|
||||
maxW,
|
||||
...props
|
||||
}: FlexProps & { flush?: boolean; actions?: ReactNode }) {
|
||||
return (
|
||||
@ -24,6 +25,8 @@ export default function SimpleView({
|
||||
pb={flush ? 0 : "max(1rem, var(--safe-bottom))"}
|
||||
gap={gap || "2"}
|
||||
flexGrow={1}
|
||||
maxW={maxW}
|
||||
w={maxW ? "full" : "initial"}
|
||||
>
|
||||
{children}
|
||||
</Flex>
|
||||
|
@ -7,7 +7,7 @@ import { useObservable } from "applesauce-react/hooks";
|
||||
import Plus from "../icons/plus";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import AccountSwitcher from "./account-switcher";
|
||||
import NavItems from "./nav-items";
|
||||
import NavItems from "../layout/nav-items";
|
||||
import { PostModalContext } from "../../providers/route/post-modal-provider";
|
||||
import { offlineMode } from "../../services/offline-mode";
|
||||
import WifiOff from "../icons/wifi-off";
|
||||
|
@ -5,7 +5,7 @@ import { useLocation, Link as RouterLink } from "react-router-dom";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import { DirectMessagesIcon, NotesIcon, NotificationsIcon, PlusCircleIcon, SearchIcon } from "../icons";
|
||||
import UserAvatar from "../user/user-avatar";
|
||||
import MobileSideDrawer from "./mobile-side-drawer";
|
||||
import MobileSideDrawer from "../layout/mobile/nav-drawer";
|
||||
import Rocket02 from "../icons/rocket-02";
|
||||
|
||||
export default function MobileBottomNav(props: Omit<FlexProps, "children">) {
|
||||
|
@ -1,48 +0,0 @@
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
Drawer,
|
||||
DrawerBody,
|
||||
DrawerContent,
|
||||
DrawerOverlay,
|
||||
DrawerProps,
|
||||
Flex,
|
||||
Text,
|
||||
} from "@chakra-ui/react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
|
||||
import AccountSwitcher from "./account-switcher";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import NavItems from "./nav-items";
|
||||
import TaskManagerButtons from "./task-manager-buttons";
|
||||
|
||||
export default function MobileSideDrawer({ ...props }: Omit<DrawerProps, "children">) {
|
||||
const account = useCurrentAccount();
|
||||
|
||||
return (
|
||||
<Drawer placement="left" {...props}>
|
||||
<DrawerOverlay />
|
||||
<DrawerContent>
|
||||
<DrawerBody display="flex" flexDirection="column" px="4" pt="4" overflowY="auto" overflowX="hidden" gap="2">
|
||||
{account ? (
|
||||
<AccountSwitcher />
|
||||
) : (
|
||||
<Flex gap="2" my="2" alignItems="center">
|
||||
<Avatar src="/apple-touch-icon.png" size="md" />
|
||||
<Text m={0}>Nostrudel</Text>
|
||||
</Flex>
|
||||
)}
|
||||
<NavItems />
|
||||
<Box h="2" />
|
||||
{!account && (
|
||||
<Button as={RouterLink} to="/signin" colorScheme="primary" flexShrink={0}>
|
||||
Sign in
|
||||
</Button>
|
||||
)}
|
||||
<TaskManagerButtons mt="auto" flexShrink={0} />
|
||||
</DrawerBody>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
@ -1,238 +0,0 @@
|
||||
import { useMemo } from "react";
|
||||
import { Box, Button, ButtonProps, Text } from "@chakra-ui/react";
|
||||
import { Link as RouterLink, useLocation } from "react-router-dom";
|
||||
import { nip19 } from "nostr-tools";
|
||||
|
||||
import {
|
||||
DirectMessagesIcon,
|
||||
NotificationsIcon,
|
||||
ProfileIcon,
|
||||
RelayIcon,
|
||||
SearchIcon,
|
||||
SettingsIcon,
|
||||
LogoutIcon,
|
||||
NotesIcon,
|
||||
LightningIcon,
|
||||
} from "../icons";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import accountService from "../../services/account";
|
||||
import PuzzlePiece01 from "../icons/puzzle-piece-01";
|
||||
import Package from "../icons/package";
|
||||
import Rocket02 from "../icons/rocket-02";
|
||||
import { useBreakpointValue } from "../../providers/global/breakpoint-provider";
|
||||
import KeyboardShortcut from "../keyboard-shortcut";
|
||||
import useRecentIds from "../../hooks/use-recent-ids";
|
||||
import { internalApps, internalTools } from "../../views/other-stuff/apps";
|
||||
import { App, AppIcon } from "../../views/other-stuff/component/app-card";
|
||||
|
||||
export default function NavItems() {
|
||||
const location = useLocation();
|
||||
const account = useCurrentAccount();
|
||||
|
||||
const showShortcuts = useBreakpointValue({ base: false, md: true });
|
||||
|
||||
const buttonProps: ButtonProps = {
|
||||
py: "2",
|
||||
justifyContent: "flex-start",
|
||||
variant: "link",
|
||||
};
|
||||
|
||||
let active = "";
|
||||
if (location.pathname.startsWith("/n/")) active = "notes";
|
||||
else if (location.pathname === "/") active = "notes";
|
||||
else if (location.pathname.startsWith("/notifications")) active = "notifications";
|
||||
else if (location.pathname.startsWith("/launchpad")) active = "launchpad";
|
||||
else if (location.pathname.startsWith("/discovery")) active = "discovery";
|
||||
else if (location.pathname.startsWith("/wallet")) active = "wallet";
|
||||
else if (location.pathname.startsWith("/dm")) active = "dm";
|
||||
else if (location.pathname.startsWith("/streams")) active = "streams";
|
||||
else if (location.pathname.startsWith("/relays")) active = "relays";
|
||||
else if (location.pathname.startsWith("/r/")) active = "relays";
|
||||
else if (location.pathname.startsWith("/lists")) active = "lists";
|
||||
else if (location.pathname.startsWith("/channels")) active = "channels";
|
||||
else if (location.pathname.startsWith("/goals")) active = "goals";
|
||||
else if (location.pathname.startsWith("/badges")) active = "badges";
|
||||
else if (location.pathname.startsWith("/emojis")) active = "emojis";
|
||||
else if (location.pathname.startsWith("/settings")) active = "settings";
|
||||
else if (location.pathname.startsWith("/tools")) active = "tools";
|
||||
else if (location.pathname.startsWith("/search")) active = "search";
|
||||
else if (location.pathname.startsWith("/tracks")) active = "tracks";
|
||||
else if (location.pathname.startsWith("/t/")) active = "search";
|
||||
else if (location.pathname.startsWith("/torrents")) active = "tools";
|
||||
else if (location.pathname.startsWith("/map")) active = "tools";
|
||||
else if (location.pathname.startsWith("/profile")) active = "profile";
|
||||
else if (location.pathname.startsWith("/support")) active = "support";
|
||||
else if (location.pathname.startsWith("/other-stuff")) active = "other-stuff";
|
||||
else if (
|
||||
account &&
|
||||
(location.pathname.startsWith("/u/" + nip19.npubEncode(account.pubkey)) ||
|
||||
location.pathname.startsWith("/u/" + account.pubkey))
|
||||
) {
|
||||
active = "profile";
|
||||
}
|
||||
|
||||
const { recent: recentApps } = useRecentIds("apps");
|
||||
const otherStuff = useMemo(() => {
|
||||
const internal = [...internalApps, ...internalTools];
|
||||
const apps = recentApps.map((id) => internal.find((app) => app.id === id)).filter(Boolean) as App[];
|
||||
if (apps.length > 3) {
|
||||
apps.length = 3;
|
||||
} else {
|
||||
if (apps.length < 3 && !apps.some((a) => a.id === "streams")) {
|
||||
apps.push(internal.find((app) => app.id === "streams")!);
|
||||
}
|
||||
if (apps.length < 3 && !apps.some((a) => a.id === "articles")) {
|
||||
apps.push(internal.find((app) => app.id === "articles")!);
|
||||
}
|
||||
if (apps.length < 3 && !apps.some((a) => a.id === "channels")) {
|
||||
apps.push(internal.find((app) => app.id === "channels")!);
|
||||
}
|
||||
}
|
||||
return apps;
|
||||
}, [recentApps]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to="/launchpad"
|
||||
leftIcon={<Rocket02 boxSize={6} />}
|
||||
colorScheme={active === "launchpad" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Launchpad
|
||||
{showShortcuts && <KeyboardShortcut letter="l" requireMeta ml="auto" />}
|
||||
</Button>
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to="/"
|
||||
leftIcon={<NotesIcon boxSize={6} />}
|
||||
colorScheme={active === "notes" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Notes
|
||||
</Button>
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to="/discovery"
|
||||
leftIcon={<PuzzlePiece01 boxSize={6} />}
|
||||
colorScheme={active === "discovery" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Discover
|
||||
</Button>
|
||||
{account && (
|
||||
<>
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to="/notifications"
|
||||
leftIcon={<NotificationsIcon boxSize={6} />}
|
||||
colorScheme={active === "notifications" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Notifications
|
||||
{showShortcuts && <KeyboardShortcut letter="i" requireMeta ml="auto" />}
|
||||
</Button>
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to={"/dm"}
|
||||
leftIcon={<DirectMessagesIcon boxSize={6} />}
|
||||
colorScheme={active === "dm" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Messages
|
||||
{showShortcuts && <KeyboardShortcut letter="m" requireMeta ml="auto" />}
|
||||
</Button>
|
||||
{/* <Button
|
||||
as={RouterLink}
|
||||
to="/wallet"
|
||||
leftIcon={<Wallet02 boxSize={6} />}
|
||||
colorScheme={active === "wallet" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Wallet
|
||||
</Button> */}
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to="/search"
|
||||
leftIcon={<SearchIcon boxSize={6} />}
|
||||
colorScheme={active === "search" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Search
|
||||
{showShortcuts && <KeyboardShortcut letter="k" requireMeta ml="auto" />}
|
||||
</Button>
|
||||
{account?.pubkey && (
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to={"/u/" + nip19.npubEncode(account.pubkey)}
|
||||
leftIcon={<ProfileIcon boxSize={6} />}
|
||||
colorScheme={active === "profile" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Profile
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to="/relays"
|
||||
leftIcon={<RelayIcon boxSize={6} />}
|
||||
colorScheme={active === "relays" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Relays
|
||||
</Button>
|
||||
<Text position="relative" py="2" color="GrayText">
|
||||
Other Stuff
|
||||
</Text>
|
||||
{otherStuff.map((app) => (
|
||||
<Button
|
||||
key={app.id}
|
||||
as={RouterLink}
|
||||
to={app.to}
|
||||
leftIcon={<AppIcon size="6" app={app} />}
|
||||
colorScheme={typeof app.to === "string" && location.pathname.startsWith(app.to) ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
{app.title}
|
||||
</Button>
|
||||
))}
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to="/other-stuff"
|
||||
leftIcon={<Package boxSize={6} />}
|
||||
colorScheme={active === "other-stuff" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
More
|
||||
{showShortcuts && <KeyboardShortcut letter="o" requireMeta ml="auto" />}
|
||||
</Button>
|
||||
<Box h="4" />
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to="/settings"
|
||||
leftIcon={<SettingsIcon boxSize={6} />}
|
||||
colorScheme={active === "settings" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Settings
|
||||
</Button>
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to="/support"
|
||||
leftIcon={<LightningIcon boxSize={6} color="yellow.400" />}
|
||||
colorScheme={active === "support" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Support
|
||||
</Button>
|
||||
{account && (
|
||||
<Button onClick={() => accountService.logout()} leftIcon={<LogoutIcon boxSize={6} />} {...buttonProps}>
|
||||
Logout
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
import { Button, ButtonProps } from "@chakra-ui/react";
|
||||
import { useMatch, Link as RouterLink } from "react-router-dom";
|
||||
|
||||
export default function SimpleNavItem({
|
||||
children,
|
||||
to,
|
||||
...props
|
||||
}: Omit<ButtonProps, "variant" | "colorScheme"> & { to: string }) {
|
||||
const match = useMatch(to);
|
||||
|
||||
return (
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to={to}
|
||||
justifyContent="flex-start"
|
||||
{...props}
|
||||
variant="outline"
|
||||
colorScheme={match ? "primary" : undefined}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
import { ComponentWithAs, Flex, FlexProps } from "@chakra-ui/react";
|
||||
|
||||
/** @deprecated */
|
||||
const VerticalPageLayout: ComponentWithAs<"div", FlexProps> = ({ children, ...props }: FlexProps) => {
|
||||
return (
|
||||
<Flex direction="column" pt="2" pb="12" gap="2" px="2" {...props}>
|
||||
<Flex direction="column" pt="2" pb="12" gap="2" px="2" overflowX="hidden" {...props}>
|
||||
{children}
|
||||
</Flex>
|
||||
);
|
||||
|
20
src/hooks/use-root-padding.ts
Normal file
20
src/hooks/use-root-padding.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function useRootPadding(padding?: { left?: string; top?: string; right?: string; bottom?: string }) {
|
||||
useEffect(() => {
|
||||
const root = document.getElementById("root");
|
||||
if (!root) return;
|
||||
|
||||
if (padding?.top) root.style.paddingTop = padding.top;
|
||||
if (padding?.left) root.style.paddingLeft = padding.left;
|
||||
if (padding?.right) root.style.paddingRight = padding.right;
|
||||
if (padding?.bottom) root.style.paddingBottom = padding.bottom;
|
||||
|
||||
return () => {
|
||||
root.style.removeProperty("padding-top");
|
||||
root.style.removeProperty("padding-left");
|
||||
root.style.removeProperty("padding-right");
|
||||
root.style.removeProperty("padding-bottom");
|
||||
};
|
||||
}, [padding?.left, padding?.top, padding?.right, padding?.bottom]);
|
||||
}
|
@ -1,14 +1,16 @@
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#root {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body,
|
||||
#root {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
|
@ -1,46 +0,0 @@
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
FormLabel,
|
||||
Select,
|
||||
useColorMode,
|
||||
useColorModePreference,
|
||||
} from "@chakra-ui/react";
|
||||
import SimpleView from "../../../../components/layout/presets/simple-view";
|
||||
|
||||
export default function DisplaySettingsView() {
|
||||
const colorPreference = useColorModePreference();
|
||||
const { colorMode, setColorMode } = useColorMode();
|
||||
|
||||
return (
|
||||
<SimpleView title="Display Settings">
|
||||
<FormControl maxW="sm">
|
||||
<Flex justifyContent="space-between">
|
||||
<FormLabel htmlFor="colorMode" mb="0">
|
||||
Color Mode
|
||||
</FormLabel>
|
||||
{colorPreference && colorMode !== colorPreference && (
|
||||
<Button
|
||||
variant="link"
|
||||
colorScheme="brand"
|
||||
fontWeight="normal"
|
||||
fontSize="sm"
|
||||
ml="auto"
|
||||
onClick={() => setColorMode(colorPreference)}
|
||||
>
|
||||
Use system default
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
<Select id="colorMode" maxW="sm" value={colorMode} onChange={(e) => setColorMode(e.target.value)}>
|
||||
<option value="light">Light</option>
|
||||
<option value="dark">Dark</option>
|
||||
</Select>
|
||||
|
||||
<FormHelperText></FormHelperText>
|
||||
</FormControl>
|
||||
</SimpleView>
|
||||
);
|
||||
}
|
@ -54,7 +54,7 @@ function ConversationCard({ conversation }: { conversation: KnownConversation })
|
||||
{lastReceived && <MessagePreview message={lastReceived} pubkey={lastReceived.pubkey} />}
|
||||
</Flex>
|
||||
</CardBody>
|
||||
<LinkOverlay as={RouterLink} to={`/dm/${nip19.npubEncode(conversation.correspondent)}` + location.search} />
|
||||
<LinkOverlay as={RouterLink} to={`/messages/${nip19.npubEncode(conversation.correspondent)}` + location.search} />
|
||||
</LinkBox>
|
||||
);
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ function Conversation({ conversation }: { conversation: KnownConversation }) {
|
||||
<UserAvatar pubkey={conversation.correspondent} />
|
||||
<Flex direction="column" overflow="hidden">
|
||||
<Flex gap="2">
|
||||
<HoverLinkOverlay as={RouterLink} to={`/dm/${nip19.npubEncode(conversation.correspondent)}`}>
|
||||
<HoverLinkOverlay as={RouterLink} to={`/messages/${nip19.npubEncode(conversation.correspondent)}`}>
|
||||
<UserName pubkey={conversation.correspondent} />
|
||||
</HoverLinkOverlay>
|
||||
<UserDnsIdentity pubkey={conversation.correspondent} onlyIcon />
|
||||
|
@ -1,47 +1,18 @@
|
||||
import { Button, Container, Flex, IconButton } from "@chakra-ui/react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import { Container } from "@chakra-ui/react";
|
||||
|
||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import RequireCurrentAccount from "../../components/router/require-current-account";
|
||||
import AccountSwitcher from "../../components/legacy-layout/account-switcher";
|
||||
import { SettingsIcon } from "../../components/icons";
|
||||
import { ErrorBoundary } from "../../components/error-boundary";
|
||||
import FeedsCard from "./components/feeds-card";
|
||||
import SearchForm from "./components/search-form";
|
||||
import KeyboardShortcut from "../../components/keyboard-shortcut";
|
||||
import DMsCard from "./components/dms-card";
|
||||
import NotificationsCard from "./components/notifications-card";
|
||||
import ToolsCard from "./components/tools-card";
|
||||
import StreamsCard from "./components/streams-card";
|
||||
import Plus from "../../components/icons/plus";
|
||||
|
||||
function LaunchpadPage() {
|
||||
return (
|
||||
<VerticalPageLayout gap="4" direction="row" wrap="wrap">
|
||||
<Flex justifyContent="space-between" w="full">
|
||||
<Flex gap="2">
|
||||
<AccountSwitcher />
|
||||
<Button
|
||||
as={RouterLink}
|
||||
colorScheme="primary"
|
||||
size="lg"
|
||||
to="/new"
|
||||
variant="outline"
|
||||
leftIcon={<Plus boxSize={6} />}
|
||||
>
|
||||
New
|
||||
<KeyboardShortcut letter="n" ml="2" />
|
||||
</Button>
|
||||
</Flex>
|
||||
<IconButton
|
||||
as={RouterLink}
|
||||
icon={<SettingsIcon boxSize={6} />}
|
||||
aria-label="Settings"
|
||||
title="Settings"
|
||||
size="lg"
|
||||
to="/settings"
|
||||
/>
|
||||
</Flex>
|
||||
<SearchForm flex={1} />
|
||||
|
||||
<ErrorBoundary>
|
||||
|
@ -10,7 +10,7 @@ export type App = {
|
||||
description: string;
|
||||
id: string;
|
||||
isExternal?: boolean;
|
||||
to: To;
|
||||
to: string;
|
||||
};
|
||||
|
||||
export function AppIcon({ app, size }: { app: App; size: string }) {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Suspense } from "react";
|
||||
import { Outlet, useLocation } from "react-router-dom";
|
||||
import { Flex, Spinner } from "@chakra-ui/react";
|
||||
|
||||
@ -13,8 +14,7 @@ import useUserContactRelays from "../../hooks/use-user-contact-relays";
|
||||
import UserSquare from "../../components/icons/user-square";
|
||||
import Image01 from "../../components/icons/image-01";
|
||||
import Server05 from "../../components/icons/server-05";
|
||||
import { Suspense } from "react";
|
||||
import SimpleNavItem from "../../components/simple-nav-item";
|
||||
import SimpleNavItem from "../../components/layout/presets/simple-nav-item";
|
||||
|
||||
export default function RelaysView() {
|
||||
const account = useCurrentAccount();
|
||||
|
@ -38,6 +38,7 @@ export default function AccountSettings() {
|
||||
return (
|
||||
<SimpleView
|
||||
title="Account settings"
|
||||
maxW="6xl"
|
||||
actions={
|
||||
<Button
|
||||
colorScheme="primary"
|
||||
|
@ -38,7 +38,7 @@ function NodeGeneralSettingsPage() {
|
||||
return (
|
||||
<SimpleView title="Node Settings">
|
||||
<FormControl>
|
||||
<FormLabel>Node URL</FormLabel>
|
||||
<FormLabel>Bakery URL</FormLabel>
|
||||
<Flex gap="2">
|
||||
<Input readOnly value={personalNode!.url} maxW="xs" />
|
||||
<Button isDisabled>Change</Button>
|
@ -4,9 +4,9 @@ import { useForm } from "react-hook-form";
|
||||
import { safeRelayUrl } from "applesauce-core/helpers";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import useAsyncErrorHandler from "../../../../../hooks/use-async-error-handler";
|
||||
import { controlApi } from "../../../../../services/bakery";
|
||||
import { RelayFavicon } from "../../../../../components/relay-favicon";
|
||||
import useAsyncErrorHandler from "../../../../hooks/use-async-error-handler";
|
||||
import { controlApi } from "../../../../services/bakery";
|
||||
import { RelayFavicon } from "../../../../components/relay-favicon";
|
||||
|
||||
function BroadcastRelay({ relay }: { relay: string }) {
|
||||
const config = useObservable(controlApi?.config);
|
@ -1,7 +1,7 @@
|
||||
import { Alert, AlertIcon } from "@chakra-ui/react";
|
||||
|
||||
import useNetworkOverviewReport from "../../../../../hooks/reports/use-network-status-report";
|
||||
import PanelItemString from "../../../../../components/dashboard/panel-item-string";
|
||||
import useNetworkOverviewReport from "../../../../hooks/reports/use-network-status-report";
|
||||
import PanelItemString from "../../../../components/dashboard/panel-item-string";
|
||||
|
||||
export default function HyperInboundStatus() {
|
||||
const status = useNetworkOverviewReport();
|
@ -2,8 +2,8 @@ import { ReactNode } from "react";
|
||||
import { Alert, AlertIcon, FormControl, FormHelperText, Switch } from "@chakra-ui/react";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import useNetworkOverviewReport from "../../../../../hooks/reports/use-network-status-report";
|
||||
import { controlApi } from "../../../../../services/bakery";
|
||||
import useNetworkOverviewReport from "../../../../hooks/reports/use-network-status-report";
|
||||
import { controlApi } from "../../../../services/bakery";
|
||||
|
||||
export default function HyperOutboundStatus() {
|
||||
const config = useObservable(controlApi?.config);
|
@ -2,10 +2,10 @@ import { ReactNode } from "react";
|
||||
import { Alert, Button, Code, Flex, Heading, Link, Spinner, Switch } from "@chakra-ui/react";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import useNetworkOverviewReport from "../../../../../hooks/reports/use-network-status-report";
|
||||
import useNetworkOverviewReport from "../../../../hooks/reports/use-network-status-report";
|
||||
import HyperInboundStatus from "./hyper-inbound";
|
||||
import HyperOutboundStatus from "./hyper-outbound";
|
||||
import { controlApi } from "../../../../../services/bakery";
|
||||
import { controlApi } from "../../../../services/bakery";
|
||||
|
||||
export default function HyperNetworkStatus() {
|
||||
const config = useObservable(controlApi?.config);
|
@ -1,7 +1,7 @@
|
||||
import { Alert, AlertIcon, Spinner } from "@chakra-ui/react";
|
||||
|
||||
import useNetworkOverviewReport from "../../../../../hooks/reports/use-network-status-report";
|
||||
import PanelItemString from "../../../../../components/dashboard/panel-item-string";
|
||||
import useNetworkOverviewReport from "../../../../hooks/reports/use-network-status-report";
|
||||
import PanelItemString from "../../../../components/dashboard/panel-item-string";
|
||||
|
||||
export default function I2PInboundStatus() {
|
||||
const status = useNetworkOverviewReport();
|
@ -2,8 +2,8 @@ import { ReactNode } from "react";
|
||||
import { Alert, AlertIcon, FormControl, FormHelperText, Switch } from "@chakra-ui/react";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import { controlApi } from "../../../../../services/bakery";
|
||||
import useNetworkOverviewReport from "../../../../../hooks/reports/use-network-status-report";
|
||||
import { controlApi } from "../../../../services/bakery";
|
||||
import useNetworkOverviewReport from "../../../../hooks/reports/use-network-status-report";
|
||||
|
||||
export default function I2POutboundStatus() {
|
||||
const config = useObservable(controlApi?.config);
|
@ -4,8 +4,8 @@ import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import I2POutboundStatus from "./i2p-outbound";
|
||||
import I2PInboundStatus from "./i2p-inbound";
|
||||
import { controlApi } from "../../../../../services/bakery";
|
||||
import useNetworkOverviewReport from "../../../../../hooks/reports/use-network-status-report";
|
||||
import { controlApi } from "../../../../services/bakery";
|
||||
import useNetworkOverviewReport from "../../../../hooks/reports/use-network-status-report";
|
||||
|
||||
export default function I2PNetworkStatus() {
|
||||
const config = useObservable(controlApi?.config);
|
@ -4,7 +4,7 @@ import HyperNetworkStatus from "./hyper";
|
||||
import TorNetworkStatus from "./tor";
|
||||
import I2PNetworkStatus from "./i2p";
|
||||
import GossipSettings from "./gossip";
|
||||
import SimpleView from "../../../../../components/layout/presets/simple-view";
|
||||
import SimpleView from "../../../../components/layout/presets/simple-view";
|
||||
|
||||
export default function BakeryNetworkSettingsView() {
|
||||
return (
|
@ -1,7 +1,7 @@
|
||||
import { Alert, AlertIcon, Spinner } from "@chakra-ui/react";
|
||||
|
||||
import useNetworkOverviewReport from "../../../../../hooks/reports/use-network-status-report";
|
||||
import PanelItemString from "../../../../../components/dashboard/panel-item-string";
|
||||
import useNetworkOverviewReport from "../../../../hooks/reports/use-network-status-report";
|
||||
import PanelItemString from "../../../../components/dashboard/panel-item-string";
|
||||
|
||||
export default function TorInboundStatus() {
|
||||
const status = useNetworkOverviewReport();
|
@ -2,8 +2,8 @@ import { ReactNode } from "react";
|
||||
import { Alert, AlertIcon, FormControl, FormHelperText, Switch } from "@chakra-ui/react";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import { controlApi } from "../../../../../services/bakery";
|
||||
import useNetworkOverviewReport from "../../../../../hooks/reports/use-network-status-report";
|
||||
import { controlApi } from "../../../../services/bakery";
|
||||
import useNetworkOverviewReport from "../../../../hooks/reports/use-network-status-report";
|
||||
|
||||
export default function TorOutboundStatus() {
|
||||
const config = useObservable(controlApi?.config);
|
@ -4,8 +4,8 @@ import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import TorOutboundStatus from "./tor-outbound";
|
||||
import TorInboundStatus from "./tor-inbound";
|
||||
import { controlApi } from "../../../../../services/bakery";
|
||||
import useNetworkOverviewReport from "../../../../../hooks/reports/use-network-status-report";
|
||||
import { controlApi } from "../../../../services/bakery";
|
||||
import useNetworkOverviewReport from "../../../../hooks/reports/use-network-status-report";
|
||||
|
||||
export default function TorNetworkStatus() {
|
||||
const config = useObservable(controlApi?.config);
|
@ -6,9 +6,9 @@ import { useObservable } from "applesauce-react/hooks";
|
||||
import NtfyNotificationSettings from "./ntfy";
|
||||
import OtherSubscriptions from "./other";
|
||||
import WebPushNotificationSettings from "./web-push";
|
||||
import { controlApi } from "../../../../../services/bakery";
|
||||
import SimpleView from "../../../../../components/layout/presets/simple-view";
|
||||
import { CAP_IS_NATIVE, CAP_IS_WEB } from "../../../../../env";
|
||||
import { controlApi } from "../../../../services/bakery";
|
||||
import SimpleView from "../../../../components/layout/presets/simple-view";
|
||||
import { CAP_IS_NATIVE, CAP_IS_WEB } from "../../../../env";
|
||||
|
||||
function EmailForm() {
|
||||
const config = useObservable(controlApi?.config);
|
@ -4,12 +4,12 @@ import { nanoid } from "nanoid";
|
||||
import { kinds, NostrEvent } from "nostr-tools";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import useCurrentAccount from "../../../../../hooks/use-current-account";
|
||||
import bakery, { controlApi } from "../../../../../services/bakery";
|
||||
import localSettings from "../../../../../services/local-settings";
|
||||
import useNotificationChannelsReport from "../../../../../hooks/reports/use-notification-channels";
|
||||
import { CopyIconButton } from "../../../../../components/copy-icon-button";
|
||||
import { ExternalLinkIcon } from "../../../../../components/icons";
|
||||
import useCurrentAccount from "../../../../hooks/use-current-account";
|
||||
import bakery, { controlApi } from "../../../../services/bakery";
|
||||
import localSettings from "../../../../services/local-settings";
|
||||
import useNotificationChannelsReport from "../../../../hooks/reports/use-notification-channels";
|
||||
import { CopyIconButton } from "../../../../components/copy-icon-button";
|
||||
import { ExternalLinkIcon } from "../../../../components/icons";
|
||||
|
||||
export default function NtfyNotificationSettings() {
|
||||
const account = useCurrentAccount();
|
@ -2,8 +2,8 @@ import { ReactNode } from "react";
|
||||
import { Badge, Button, Flex, Heading, Text } from "@chakra-ui/react";
|
||||
import { NotificationChannel } from "@satellite-earth/core/types/control-api/notifications.js";
|
||||
|
||||
import { controlApi } from "../../../../../services/bakery";
|
||||
import useNotificationChannelsReport from "../../../../../hooks/reports/use-notification-channels";
|
||||
import { controlApi } from "../../../../services/bakery";
|
||||
import useNotificationChannelsReport from "../../../../hooks/reports/use-notification-channels";
|
||||
|
||||
function Channel({ channel }: { channel: NotificationChannel }) {
|
||||
let details: ReactNode = null;
|
@ -2,13 +2,13 @@ import { useEffect, useState } from "react";
|
||||
import { Alert, AlertIcon, Button, Code, Flex, Heading, Link, Text, useToast } from "@chakra-ui/react";
|
||||
import { useObservable } from "applesauce-react/hooks";
|
||||
|
||||
import { serviceWorkerRegistration } from "../../../../../services/worker";
|
||||
import { serviceWorkerRegistration } from "../../../../services/worker";
|
||||
import {
|
||||
disableNotifications,
|
||||
enableNotifications,
|
||||
pushSubscription,
|
||||
} from "../../../../../services/web-push-notifications";
|
||||
import { controlApi } from "../../../../../services/bakery";
|
||||
} from "../../../../services/web-push-notifications";
|
||||
import { controlApi } from "../../../../services/bakery";
|
||||
|
||||
function WebPushNotificationStatus() {
|
||||
const toast = useToast();
|
@ -15,10 +15,10 @@ import {
|
||||
} from "@chakra-ui/react";
|
||||
import Convert from "ansi-to-html";
|
||||
|
||||
import useLogsReport from "../../../../../hooks/reports/use-logs-report";
|
||||
import Timestamp from "../../../../../components/timestamp";
|
||||
import SimpleView from "../../../../../components/layout/presets/simple-view";
|
||||
import { controlApi } from "../../../../../services/bakery";
|
||||
import useLogsReport from "../../../../hooks/reports/use-logs-report";
|
||||
import Timestamp from "../../../../components/timestamp";
|
||||
import SimpleView from "../../../../components/layout/presets/simple-view";
|
||||
import { controlApi } from "../../../../services/bakery";
|
||||
import ServicesTree from "./service-tree";
|
||||
|
||||
const convert = new Convert();
|
@ -1,6 +1,6 @@
|
||||
import { Button, ButtonGroup, Flex, FlexProps, IconButton, useDisclosure } from "@chakra-ui/react";
|
||||
import useServicesReport from "../../../../../hooks/reports/use-services-report";
|
||||
import { ChevronDownIcon, ChevronRightIcon } from "../../../../../components/icons";
|
||||
import useServicesReport from "../../../../hooks/reports/use-services-report";
|
||||
import { ChevronDownIcon, ChevronRightIcon } from "../../../../components/icons";
|
||||
|
||||
type Service = {
|
||||
id: string;
|
@ -1,8 +1,7 @@
|
||||
import { Divider, Flex, Heading, Link } from "@chakra-ui/react";
|
||||
import { Divider, Flex, Link, Spinner, Text } from "@chakra-ui/react";
|
||||
import { Outlet, useMatch } from "react-router-dom";
|
||||
|
||||
import { useBreakpointValue } from "../../providers/global/breakpoint-provider";
|
||||
import SimpleNavItem from "../../components/simple-nav-item";
|
||||
import { ErrorBoundary } from "../../components/error-boundary";
|
||||
import {
|
||||
AppearanceIcon,
|
||||
@ -18,6 +17,12 @@ import Image01 from "../../components/icons/image-01";
|
||||
import UserAvatar from "../../components/user/user-avatar";
|
||||
import VersionButton from "../../components/version-button";
|
||||
import SimpleHeader from "../../components/layout/presets/simple-header";
|
||||
import bakery from "../../services/bakery";
|
||||
import SimpleNavItem from "../../components/layout/presets/simple-nav-item";
|
||||
import Bell01 from "../../components/icons/bell-01";
|
||||
import Share07 from "../../components/icons/share-07";
|
||||
import Database01 from "../../components/icons/database-01";
|
||||
import { Suspense } from "react";
|
||||
|
||||
export default function SettingsView() {
|
||||
const account = useCurrentAccount();
|
||||
@ -62,6 +67,28 @@ export default function SettingsView() {
|
||||
Database Tools
|
||||
</SimpleNavItem>
|
||||
|
||||
{bakery && (
|
||||
<Flex direction="column" gap="2">
|
||||
<Flex alignItems="center" gap="2">
|
||||
<Divider />
|
||||
<Text fontWeight="bold" fontSize="md">
|
||||
Bakery
|
||||
</Text>
|
||||
<Divider />
|
||||
</Flex>
|
||||
<SimpleNavItem to="/settings/bakery">Bakery</SimpleNavItem>
|
||||
<SimpleNavItem to="/settings/bakery/notifications" leftIcon={<Bell01 boxSize={5} />}>
|
||||
Notifications
|
||||
</SimpleNavItem>
|
||||
<SimpleNavItem to="/settings/bakery/network" leftIcon={<Share07 boxSize={5} />}>
|
||||
Network
|
||||
</SimpleNavItem>
|
||||
<SimpleNavItem to="/settings/bakery/logs" leftIcon={<Database01 />}>
|
||||
Service Logs
|
||||
</SimpleNavItem>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
<Divider />
|
||||
|
||||
<Flex alignItems="center">
|
||||
@ -73,17 +100,21 @@ export default function SettingsView() {
|
||||
</Flex>
|
||||
</Flex>
|
||||
{!isMobile && (
|
||||
<ErrorBoundary>
|
||||
<Outlet />
|
||||
</ErrorBoundary>
|
||||
<Suspense fallback={<Spinner />}>
|
||||
<ErrorBoundary>
|
||||
<Outlet />
|
||||
</ErrorBoundary>
|
||||
</Suspense>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<Outlet />
|
||||
</ErrorBoundary>
|
||||
<Suspense fallback={<Spinner />}>
|
||||
<ErrorBoundary>
|
||||
<Outlet />
|
||||
</ErrorBoundary>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
@ -105,7 +105,12 @@ function MediaServersPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<SimpleView gap="2" title="Media Servers" actions={event && <DebugEventButton event={event} size="sm" ml="auto" />}>
|
||||
<SimpleView
|
||||
gap="2"
|
||||
title="Media Servers"
|
||||
actions={event && <DebugEventButton event={event} size="sm" ml="auto" />}
|
||||
maxW="4xl"
|
||||
>
|
||||
<Text fontStyle="italic" mt="-2">
|
||||
<Link href="https://github.com/hzrd149/blossom" target="_blank" color="blue.500">
|
||||
Blossom
|
||||
|
@ -61,6 +61,8 @@ function StreamsPage() {
|
||||
const liveStreams = streams.filter((stream) => getStreamStatus(stream) === "live");
|
||||
const endedStreams = streams.filter((stream) => getStreamStatus(stream) === "ended");
|
||||
|
||||
const columns = { base: 1, md: 2, lg: 3, xl: 4, "2xl": 5 };
|
||||
|
||||
return (
|
||||
<VerticalPageLayout>
|
||||
<Flex gap="2" wrap="wrap" alignItems="center">
|
||||
@ -75,7 +77,7 @@ function StreamsPage() {
|
||||
<Heading size="lg" mt="2">
|
||||
Favorites
|
||||
</Heading>
|
||||
<SimpleGrid columns={{ base: 1, md: 2, lg: 3, xl: 4 }} spacing="2">
|
||||
<SimpleGrid columns={columns} spacing="2">
|
||||
{favorites.map((stream) => (
|
||||
<StreamCard key={getEventUID(stream)} stream={stream} />
|
||||
))}
|
||||
@ -85,7 +87,7 @@ function StreamsPage() {
|
||||
<Heading size="lg" mt="2">
|
||||
Live
|
||||
</Heading>
|
||||
<SimpleGrid columns={{ base: 1, md: 2, lg: 3, xl: 4 }} spacing="2">
|
||||
<SimpleGrid columns={columns} spacing="2">
|
||||
{liveStreams.map((stream) => (
|
||||
<StreamCard key={getEventUID(stream)} stream={stream} />
|
||||
))}
|
||||
@ -95,7 +97,7 @@ function StreamsPage() {
|
||||
<Heading size="lg" mt="4">
|
||||
Ended
|
||||
</Heading>
|
||||
<SimpleGrid columns={{ base: 1, md: 2, lg: 3, xl: 4 }} spacing="2">
|
||||
<SimpleGrid columns={columns} spacing="2">
|
||||
{endedStreams.map((stream) => (
|
||||
<StreamCard key={getEventUID(stream)} stream={stream} />
|
||||
))}
|
||||
|
@ -154,7 +154,7 @@ export default function UserAboutTab() {
|
||||
size="sm"
|
||||
icon={<ChatIcon />}
|
||||
aria-label="Message"
|
||||
to={`/dm/${npub ?? pubkey}`}
|
||||
to={`/messages/${npub ?? pubkey}`}
|
||||
/>
|
||||
<UserFollowButton pubkey={pubkey} size="sm" showLists />
|
||||
<UserProfileMenu pubkey={pubkey} aria-label="More Options" size="sm" />
|
||||
|
@ -52,7 +52,11 @@ export const UserProfileMenu = ({
|
||||
{isMuted ? "Unmute User" : "Mute User"}
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem icon={<DirectMessagesIcon fontSize="1.5em" />} as={RouterLink} to={`/dm/${nip19.npubEncode(pubkey)}`}>
|
||||
<MenuItem
|
||||
icon={<DirectMessagesIcon fontSize="1.5em" />}
|
||||
as={RouterLink}
|
||||
to={`/messages/${nip19.npubEncode(pubkey)}`}
|
||||
>
|
||||
Direct messages
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
|
Loading…
x
Reference in New Issue
Block a user