feat: internal page links and mentions (#604)

* Work on mentions

* fix: properly parse page slug

* fix editor suggestion bugs

* mentions must start with whitespace

* add icon to page mention render

* feat: backlinks - WIP

* UI - WIP

* permissions check
* use FTS for page suggestion

* cleanup

* WIP

* page title fallback

* feat: handle internal link paste

* link styling

* WIP

* Switch back to LIKE operator for search suggestion

* WIP
* scope to workspaceId
* still create link for pages not found

* select necessary columns

* cleanups
This commit is contained in:
Philip Okugbe
2025-02-14 15:36:44 +00:00
committed by GitHub
parent 0ef6b1978a
commit e209aaa272
46 changed files with 1679 additions and 101 deletions

View File

@ -0,0 +1,2 @@
export const INTERNAL_LINK_REGEX =
/^(https?:\/\/)?([^\/]+)?(\/s\/([^\/]+)\/)?p\/([a-zA-Z0-9-]+)\/?$/;

View File

@ -1,3 +1,7 @@
import { validate as isValidUUID } from "uuid";
import { ActionIcon } from "@mantine/core";
import { IconFileDescription } from "@tabler/icons-react";
import { ReactNode } from "react";
import { TFunction } from "i18next";
export function formatMemberCount(memberCount: number, t: TFunction): string {
@ -8,12 +12,15 @@ export function formatMemberCount(memberCount: number, t: TFunction): string {
}
}
export function extractPageSlugId(input: string): string {
if (!input) {
export function extractPageSlugId(slug: string): string {
if (!slug) {
return undefined;
}
const parts = input.split("-");
return parts.length > 1 ? parts[parts.length - 1] : input;
if (isValidUUID(slug)) {
return slug;
}
const parts = slug.split("-");
return parts.length > 1 ? parts[parts.length - 1] : slug;
}
export const computeSpaceSlug = (name: string) => {
@ -76,3 +83,13 @@ export function decodeBase64ToSvgString(base64Data: string): string {
export function capitalizeFirstChar(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
export function getPageIcon(icon: string, size = 18): string | ReactNode {
return (
icon || (
<ActionIcon variant="transparent" color="gray" size={size}>
<IconFileDescription size={size} />
</ActionIcon>
)
);
}