import { useState } from "react"; import { Loader, Popover } from "@mantine/core"; import { IconChevronDown, IconCornerDownLeft, IconFile, IconInfoCircle, } from "@tabler/icons-react"; import { Link } from "react-router-dom"; import { Trans, useTranslation } from "react-i18next"; import { useReferencesQuery } from "@/features/transclusion/queries/transclusion-query"; import type { ReferencingPage } from "@/features/transclusion/types/transclusion.types"; import { buildPageUrl } from "@/features/page/page.utils"; import classes from "./sync-block-references-dropdown.module.css"; type Props = { sourcePageId: string | null; transclusionId: string | null; /** The page currently being viewed - used to mark the "THIS PAGE" badge. */ currentPageId: string; /** * Source: trigger reads "Editing original". * Reference: trigger reads "Synced to N other pages". */ mode: "source" | "reference"; /** Notified whenever the dropdown opens/closes (for keep-chrome-visible). */ onOpenChange?: (open: boolean) => void; }; export default function SyncBlockReferencesDropdown({ sourcePageId, transclusionId, currentPageId, mode, onOpenChange, }: Props) { const { t } = useTranslation(); const [opened, setOpened] = useState(false); const handleOpenChange = (next: boolean) => { setOpened(next); onOpenChange?.(next); }; // Fetch eagerly so the "Synced to N other pages" count is correct even // before the dropdown is opened. The cache is keyed on (sourcePageId, // transclusionId), so two views (source + reference) share one fetch. const enabled = !!sourcePageId && !!transclusionId; const { data, isLoading } = useReferencesQuery( sourcePageId, transclusionId, enabled, ); const allPages: Array<{ page: ReferencingPage; isOriginal: boolean }> = []; if (data?.source) { allPages.push({ page: data.source, isOriginal: true }); } for (const ref of data?.references ?? []) { allPages.push({ page: ref, isOriginal: false }); } const otherCount = allPages.filter((p) => p.page.id !== currentPageId).length; const label = mode === "source" ? t("Editing original") : t("Synced to {{count}} other page", { count: otherCount, defaultValue_one: "Synced to {{count}} other page", defaultValue_other: "Synced to {{count}} other pages", }); return ( {mode === "reference" && data?.source && (
handleOpenChange(false)} /> ), }} />
)} {isLoading ? (
) : allPages.length === 0 ? (
{t("No pages")}
) : (
{t("Synced to")}
    {allPages.map(({ page, isOriginal }) => { const isCurrent = page.id === currentPageId; const href = page.spaceSlug ? buildPageUrl(page.spaceSlug, page.slugId, page.title) : `/p/${page.id}`; const title = page.title?.length ? page.title : t("Untitled"); return (
  • handleOpenChange(false)} > {page.icon ? ( {page.icon} ) : ( )} {title} {isCurrent ? ( {t("THIS PAGE")} ) : isOriginal ? ( {t("ORIGINAL")} ) : null}
  • ); })}
)}
); }