add nanoid by Vito0912

This commit is contained in:
fuscodev
2025-06-27 20:27:54 +02:00
parent f689291a99
commit 1baff07e4e
5 changed files with 59 additions and 13 deletions
@@ -16,32 +16,36 @@ const generateSlug = (text: string) =>
export default function HeadingView({ node }: NodeViewProps) {
const { t } = useTranslation();
const [slug, setSlug] = useState("");
const [combinedId, setCombinedId] = useState("");
const [url, setUrl] = useState("");
const [showAnchorButton, setShowAnchorButton] = useState(false);
const tag: ElementType = `h${node.attrs.level}` as ElementType;
const uid = node.attrs.uid;
useEffect(() => {
const text = node.textContent || "";
const generatedSlug = generateSlug(text);
setSlug(generatedSlug);
const baseUrl = window.location.href.split("#")[0];
setUrl(`${baseUrl}#${generatedSlug}`);
}, [node.content]);
if (uid) {
const text = node.textContent || "";
const textSlug = generateSlug(text);
const combined = textSlug ? `${textSlug}-${uid}` : uid;
setCombinedId(combined);
const baseUrl = window.location.href.split("#")[0];
setUrl(`${baseUrl}#${combined}`);
}
}, [uid, node.content]);
return (
<NodeViewWrapper
as={tag}
id={slug}
id={combinedId}
className={classes.anchorScrollMargin}
onMouseEnter={() => setShowAnchorButton(true)}
onMouseLeave={() => setShowAnchorButton(false)}
>
<Flex gap="sm" justify="flex-start" align="center">
<NodeViewContent as="span" />
{showAnchorButton && node.textContent && (
{showAnchorButton && uid && combinedId && node.textContent && (
<CopyButton value={url} timeout={2000}>
{({ copied, copy }) => (
<Tooltip
@@ -9,11 +9,39 @@ export function useAnchorScroll(offset = 95, maxRetries = 10, retryDelay = 500)
let retries = maxRetries;
const tryScroll = () => {
const el = document.getElementById(lastHash.current);
let el = document.getElementById(lastHash.current);
if (!el) {
const hash = lastHash.current;
if (hash.includes('-')) {
const parts = hash.split('-');
const possibleUid = parts[parts.length - 1];
const elements = document.querySelectorAll('[id]');
for (const element of elements) {
if (element.id.endsWith(`-${possibleUid}`)) {
el = element as HTMLElement;
break;
}
}
}
if (!el) {
const elements = document.querySelectorAll('[id]');
for (const element of elements) {
if (element.id.endsWith(`-${hash}`) || element.id === hash) {
el = element as HTMLElement;
break;
}
}
}
}
if (el) {
const y = el.getBoundingClientRect().top + window.scrollY - offset;
window.scrollTo({ top: y, behavior: "smooth" });
window.history.replaceState(null, "", `#${lastHash.current}`);
window.history.replaceState(null, "", `#${el.id}`);
} else if (retries > 0) {
retries--;
setTimeout(tryScroll, retryDelay);
@@ -13,7 +13,7 @@ import { Color } from "@tiptap/extension-color";
import Table from "@tiptap/extension-table";
import TableHeader from "@tiptap/extension-table-header";
import SlashCommand from "@/features/editor/extensions/slash-command";
import { Collaboration } from "@tiptap/extension-collaboration";
import { Collaboration, isChangeOrigin } from "@tiptap/extension-collaboration";
import { CollaborationCursor } from "@tiptap/extension-collaboration-cursor";
import { HocuspocusProvider } from "@hocuspocus/provider";
import {
@@ -76,6 +76,8 @@ import { CharacterCount } from "@tiptap/extension-character-count";
import Heading from "@tiptap/extension-heading";
import HeadingView from "../components/heading/heading-view";
import { countWords } from "alfaaz";
import UniqueID from '@tiptap/extension-unique-id';
import { generateSlugId } from "../utils/nanoid";
const lowlight = createLowlight(common);
lowlight.register("mermaid", plaintext);
@@ -225,6 +227,12 @@ export const mainExtensions = [
CharacterCount.configure({
wordCounter: (text) => countWords(text),
}),
UniqueID.configure({
types: ['heading'],
attributeName: 'uid',
generateID: () => generateSlugId(),
filterTransaction: (transaction) => !isChangeOrigin(transaction),
}),
] as any;
type CollabExtensions = (provider: HocuspocusProvider, user: IUser) => any[];
@@ -0,0 +1,5 @@
import { customAlphabet } from "nanoid";
const slugIdAlphabet =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
export const generateSlugId = customAlphabet(slugIdAlphabet, 10);
+1
View File
@@ -54,6 +54,7 @@
"@tiptap/extension-text-style": "^2.10.3",
"@tiptap/extension-typography": "^2.10.3",
"@tiptap/extension-underline": "^2.10.3",
"@tiptap/extension-unique-id": "^2.23.0",
"@tiptap/extension-youtube": "^2.10.3",
"@tiptap/html": "^2.10.3",
"@tiptap/pm": "^2.10.3",