feat: public page sharing (#1012)

* Share - WIP

* - public attachment links
- WIP

* WIP

* WIP

* Share - WIP

* WIP

* WIP

* include userRole in space object

* WIP

* Server render shared page meta tags

* disable user select

* Close Navbar on outside click on mobile

* update shared page spaceId

* WIP

* fix

* close sidebar on click

* close sidebar

* defaults

* update copy

* Store share key in lowercase

* refactor page breadcrumbs

* Change copy

* add link ref

* open link button

* add meta og:title

* add twitter tags

* WIP

* make shares/info endpoint public

* fix

* * add /p/ segment to share urls
* minore fixes

* change mobile breadcrumb icon
This commit is contained in:
Philip Okugbe
2025-04-22 20:37:32 +01:00
committed by GitHub
parent 3e8824435d
commit 6c422011ac
66 changed files with 3331 additions and 512 deletions
+60
View File
@@ -0,0 +1,60 @@
import { IPage } from "@/features/page/types/page.types.ts";
import { sortPositionKeys } from "@/features/page/tree/utils";
export type SharedPageTreeNode = {
id: string;
slugId: string;
name: string;
icon?: string;
position: string;
spaceId: string;
parentPageId: string;
hasChildren: boolean;
children: SharedPageTreeNode[];
label: string,
value: string,
};
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.
pages.forEach((page) => {
pageMap[page.id] = {
id: page.slugId,
slugId: page.slugId,
name: page.title,
icon: page.icon,
position: page.position,
// Initially assume a page has no children.
hasChildren: false,
spaceId: page.spaceId,
parentPageId: page.parentPageId,
label: page.title || 'untitled',
value: page.id,
children: [],
};
});
// Build the tree structure.
const tree: SharedPageTreeNode[] = [];
pages.forEach((page) => {
if (page.parentPageId) {
// If the page has a parent, add it as a child of the parent node.
const parentNode = pageMap[page.parentPageId];
if (parentNode) {
parentNode.children.push(pageMap[page.id]);
parentNode.hasChildren = true;
} else {
// Parent not found treat this page as a top-level node.
tree.push(pageMap[page.id]);
}
} else {
// No parentPageId indicates a top-level page.
tree.push(pageMap[page.id]);
}
});
// Return the sorted tree.
return sortPositionKeys(tree);
}