feat: enhance public sharing (#1057)

* fix tree nodes sort

* remove comment mark in shares

* remove clickoutside hook for now

* feat: search in shared pages

* fix user-select

* use Link

* render page icons
This commit is contained in:
Philip Okugbe
2025-04-23 14:32:35 +01:00
committed by GitHub
parent de5f90309c
commit c26a851d52
17 changed files with 420 additions and 61 deletions
@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React from "react";
import {
ActionIcon,
Affix,
@@ -30,7 +30,12 @@ import {
import { IconList } from "@tabler/icons-react";
import { useToggleToc } from "@/features/share/hooks/use-toggle-toc.ts";
import classes from "./share.module.css";
import { useClickOutside } from "@mantine/hooks";
import {
SearchControl,
SearchMobileControl,
} from "@/features/search/components/search-control.tsx";
import { ShareSearchSpotlight } from "@/features/search/share-search-spotlight";
import { shareSearchSpotlight } from "@/features/search/constants";
const MemoizedSharedTree = React.memo(SharedTree);
@@ -54,21 +59,9 @@ export default function ShareShell({
const { data } = useGetSharedPageTreeQuery(shareId);
const readOnlyEditor = useAtomValue(readOnlyEditorAtom);
const [navbarOutside, setNavbarOutside] = useState<HTMLElement | null>(null);
useClickOutside(
() => {
if (mobileOpened) {
toggleMobile();
}
},
null,
[navbarOutside],
);
return (
<AppShell
header={{ height: 48 }}
header={{ height: 50 }}
{...(data?.pageTree?.length > 1 && {
navbar: {
width: 300,
@@ -91,7 +84,7 @@ export default function ShareShell({
>
<AppShell.Header>
<Group wrap="nowrap" justify="space-between" py="sm" px="xl">
<Group>
<Group wrap="nowrap">
{data?.pageTree?.length > 1 && (
<>
<Tooltip label={t("Sidebar toggle")}>
@@ -116,8 +109,21 @@ export default function ShareShell({
</>
)}
</Group>
{shareId && (
<Group visibleFrom="sm">
<SearchControl onClick={shareSearchSpotlight.open} />
</Group>
)}
<Group>
<>
{shareId && (
<Group hiddenFrom="sm">
<SearchMobileControl onSearch={shareSearchSpotlight.open} />
</Group>
)}
<Tooltip label={t("Table of contents")} withArrow>
<ActionIcon
variant="default"
@@ -149,11 +155,7 @@ export default function ShareShell({
</AppShell.Header>
{data?.pageTree?.length > 1 && (
<AppShell.Navbar
p="md"
className={classes.navbar}
ref={setNavbarOutside}
>
<AppShell.Navbar p="md" className={classes.navbar}>
<MemoizedSharedTree sharedPageTree={data} />
</AppShell.Navbar>
)}
@@ -186,6 +188,8 @@ export default function ShareShell({
</div>
</ScrollArea>
</AppShell.Aside>
<ShareSearchSpotlight shareId={shareId} />
</AppShell>
);
}
@@ -15,6 +15,7 @@ import clsx from "clsx";
import {
IconChevronDown,
IconChevronRight,
IconFileDescription,
IconPointFilled,
} from "@tabler/icons-react";
import { ActionIcon, Box } from "@mantine/core";
@@ -23,6 +24,7 @@ import { OpenMap } from "react-arborist/dist/main/state/open-slice";
import classes from "@/features/page/tree/styles/tree.module.css";
import styles from "./share.module.css";
import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
import EmojiPicker from "@/components/ui/emoji-picker.tsx";
interface SharedTree {
sharedPageTree: ISharedPageTree;
@@ -141,6 +143,20 @@ function Node({ node, style, tree }: NodeRendererProps<any>) {
}}
>
<PageArrow node={node} />
<div style={{ marginRight: "4px" }}>
<EmojiPicker
onEmojiSelect={() => {}}
icon={
node.data.icon ? (
node.data.icon
) : (
<IconFileDescription size="18" />
)
}
readOnly={true}
removeEmojiAction={() => {}}
/>
</div>
<span className={classes.text}>{node.data.name || t("untitled")}</span>
</Box>
</>
+14 -6
View File
@@ -11,11 +11,13 @@ export type SharedPageTreeNode = {
parentPageId: string;
hasChildren: boolean;
children: SharedPageTreeNode[];
label: string,
value: string,
label: string;
value: string;
};
export function buildSharedPageTree(pages: Partial<IPage[]>): SharedPageTreeNode[] {
export function buildSharedPageTree(
pages: Partial<IPage[]>,
): SharedPageTreeNode[] {
const pageMap: Record<string, SharedPageTreeNode> = {};
// Initialize each page as a tree node and store it in a map.
@@ -30,7 +32,7 @@ export function buildSharedPageTree(pages: Partial<IPage[]>): SharedPageTreeNode
hasChildren: false,
spaceId: page.spaceId,
parentPageId: page.parentPageId,
label: page.title || 'untitled',
label: page.title || "untitled",
value: page.id,
children: [],
};
@@ -55,6 +57,12 @@ export function buildSharedPageTree(pages: Partial<IPage[]>): SharedPageTreeNode
}
});
// Return the sorted tree.
return sortPositionKeys(tree);
function sortTree(nodes: SharedPageTreeNode[]): SharedPageTreeNode[] {
return sortPositionKeys(nodes).map((node: SharedPageTreeNode) => ({
...node,
children: sortTree(node.children),
}));
}
return sortTree(tree);
}