@agent-native/core 0.77.10 → 0.77.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +6 -0
  3. package/corpus/core/package.json +3 -3
  4. package/corpus/core/src/collab/awareness.ts +12 -9
  5. package/corpus/core/src/collab/client.ts +4 -2
  6. package/corpus/templates/clips/chrome-extension/package.json +1 -1
  7. package/corpus/templates/content/actions/list-trashed-content-databases.ts +36 -2
  8. package/corpus/templates/content/actions/move-document.ts +79 -33
  9. package/corpus/templates/content/actions/restore-content-database.ts +40 -3
  10. package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +84 -2
  11. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +177 -49
  12. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +393 -219
  13. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +632 -467
  14. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +114 -14
  15. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +56 -15
  16. package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +6 -5
  17. package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +12 -4
  18. package/corpus/templates/content/app/global.css +9 -0
  19. package/corpus/templates/content/app/hooks/use-create-page.ts +36 -7
  20. package/corpus/templates/content/app/i18n-data.ts +140 -10
  21. package/corpus/templates/content/changelog/2026-06-25-comment-cards-now-track-their-highlighted-text-while-scrolli.md +6 -0
  22. package/corpus/templates/content/changelog/2026-06-25-comments-now-scroll-with-the-document-and-stay-below-the-pag.md +6 -0
  23. package/corpus/templates/content/changelog/2026-06-25-creating-a-database-from-the-slash-menu-no-longer-leaves-sta.md +6 -0
  24. package/corpus/templates/content/changelog/2026-06-25-sidebar-hover-controls-no-longer-leave-a-lingering-fade-when.md +6 -0
  25. package/corpus/templates/content/changelog/2026-06-25-sidebar-page-actions-are-now-easier-to-see-when-hovering-ina.md +6 -0
  26. package/corpus/templates/content/changelog/2026-06-25-text-selections-in-the-editor-no-longer-show-white-gaps-when.md +6 -0
  27. package/corpus/templates/content/changelog/2026-06-25-the-editor-toolbar-now-has-a-one-click-page-link-copy-button.md +6 -0
  28. package/corpus/templates/content/changelog/2026-06-25-the-editor-toolbar-now-shows-page-breadcrumbs-and-the-latest.md +6 -0
  29. package/corpus/templates/content/changelog/2026-06-25-the-page-command-now-leaves-a-notion-style-page-reference-an.md +6 -0
  30. package/corpus/templates/content/shared/nfm.ts +16 -0
  31. package/dist/collab/awareness.d.ts +1 -1
  32. package/dist/collab/awareness.d.ts.map +1 -1
  33. package/dist/collab/awareness.js +12 -8
  34. package/dist/collab/awareness.js.map +1 -1
  35. package/dist/collab/client.d.ts.map +1 -1
  36. package/dist/collab/client.js +4 -3
  37. package/dist/collab/client.js.map +1 -1
  38. package/dist/collab/routes.d.ts +1 -1
  39. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  40. package/dist/notifications/routes.d.ts +2 -2
  41. package/dist/observability/routes.d.ts +7 -7
  42. package/dist/progress/routes.d.ts +1 -1
  43. package/dist/resources/handlers.d.ts +3 -3
  44. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  45. package/dist/server/transcribe-voice.d.ts +1 -1
  46. package/package.json +3 -3
@@ -27,6 +27,7 @@ import {
27
27
  IconFolderOpen,
28
28
  IconPlus,
29
29
  IconHistory,
30
+ IconLink,
30
31
  IconRefresh,
31
32
  IconShare3,
32
33
  } from "@tabler/icons-react";
@@ -152,10 +153,105 @@ function NotionIcon({ className }: { className?: string }) {
152
153
  );
153
154
  }
154
155
 
156
+ function formatEditedLabel(updatedAt?: string | null) {
157
+ if (!updatedAt) return null;
158
+ const timestamp = new Date(updatedAt).getTime();
159
+ if (!Number.isFinite(timestamp)) return null;
160
+
161
+ const diffMs = Math.max(0, Date.now() - timestamp);
162
+ const minute = 60_000;
163
+ const hour = 60 * minute;
164
+ const day = 24 * hour;
165
+
166
+ if (diffMs < minute) return "Edited just now";
167
+ if (diffMs < hour) {
168
+ const minutes = Math.max(1, Math.round(diffMs / minute));
169
+ return `Edited ${minutes}m ago`;
170
+ }
171
+ if (diffMs < day) {
172
+ const hours = Math.max(1, Math.round(diffMs / hour));
173
+ return `Edited ${hours}h ago`;
174
+ }
175
+ if (diffMs < 7 * day) {
176
+ const days = Math.max(1, Math.round(diffMs / day));
177
+ return `Edited ${days}d ago`;
178
+ }
179
+
180
+ return `Edited ${new Date(updatedAt).toLocaleDateString("en-US", {
181
+ month: "short",
182
+ day: "numeric",
183
+ })}`;
184
+ }
185
+
186
+ function ToolbarBreadcrumb({
187
+ items,
188
+ currentDocumentId,
189
+ ariaLabel,
190
+ untitledLabel,
191
+ onOpen,
192
+ }: {
193
+ items: { id?: string; title: string; icon?: string | null }[];
194
+ currentDocumentId: string;
195
+ ariaLabel: string;
196
+ untitledLabel: string;
197
+ onOpen: (id: string) => void;
198
+ }) {
199
+ return (
200
+ <nav
201
+ aria-label={ariaLabel}
202
+ className="flex min-w-0 flex-1 items-center gap-1 text-sm text-foreground"
203
+ >
204
+ {items.map((item, index) => {
205
+ const isLast = index === items.length - 1;
206
+ const label = item.title.trim() || untitledLabel;
207
+ const content = (
208
+ <>
209
+ {item.icon ? (
210
+ <span className="shrink-0 text-sm leading-none">{item.icon}</span>
211
+ ) : null}
212
+ <span className="truncate">{label}</span>
213
+ </>
214
+ );
215
+
216
+ return (
217
+ <div
218
+ key={`${item.id ?? label}-${index}`}
219
+ className="flex min-w-0 items-center gap-1"
220
+ >
221
+ {item.id && item.id !== currentDocumentId ? (
222
+ <button
223
+ type="button"
224
+ className="flex min-w-0 max-w-48 items-center gap-1 rounded px-1.5 py-1 text-left text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
225
+ onClick={() => onOpen(item.id!)}
226
+ >
227
+ {content}
228
+ </button>
229
+ ) : (
230
+ <span
231
+ className={cn(
232
+ "flex min-w-0 max-w-56 items-center gap-1 truncate px-1.5 py-1",
233
+ isLast ? "text-foreground" : "text-muted-foreground",
234
+ )}
235
+ >
236
+ {content}
237
+ </span>
238
+ )}
239
+ {!isLast ? (
240
+ <span className="shrink-0 text-muted-foreground/70">/</span>
241
+ ) : null}
242
+ </div>
243
+ );
244
+ })}
245
+ </nav>
246
+ );
247
+ }
248
+
155
249
  interface DocumentToolbarProps {
156
250
  documentId: string;
157
251
  documentTitle?: string;
158
252
  documentContent?: string;
253
+ breadcrumbItems?: { id?: string; title: string; icon?: string | null }[];
254
+ documentUpdatedAt?: string | null;
159
255
  activeUsers?: CollabUser[];
160
256
  agentPresent?: boolean;
161
257
  agentActive?: boolean;
@@ -169,6 +265,8 @@ export function DocumentToolbar({
169
265
  documentId,
170
266
  documentTitle,
171
267
  documentContent,
268
+ breadcrumbItems = [],
269
+ documentUpdatedAt,
172
270
  activeUsers,
173
271
  agentPresent,
174
272
  agentActive,
@@ -238,7 +336,13 @@ export function DocumentToolbar({
238
336
  typeof window === "undefined"
239
337
  ? `/p/${documentId}`
240
338
  : `${window.location.origin}${appPath(`/p/${documentId}`)}`;
339
+ const pageUrl =
340
+ typeof window === "undefined"
341
+ ? `/page/${documentId}`
342
+ : `${window.location.origin}${appPath(`/page/${documentId}`)}`;
343
+ const copyPageUrl = isLocalFileDocument ? pageUrl : shareUrl;
241
344
  const effectiveHideFromSearch = pendingHideFromSearch ?? hideFromSearch;
345
+ const editedLabel = formatEditedLabel(documentUpdatedAt);
242
346
 
243
347
  const { data: searchResults, isLoading: searchLoading } =
244
348
  useSearchNotionPages(debouncedQuery, open && isConnected && !isLinked);
@@ -320,6 +424,25 @@ export function DocumentToolbar({
320
424
  toast.success(t("editor.toolbar.copiedAbsolutePath"));
321
425
  }, [source, t]);
322
426
 
427
+ const handleCopyPageLink = useCallback(async () => {
428
+ if (!navigator.clipboard?.writeText) {
429
+ toast.error(t("editor.toolbar.couldNotCopyLink"), {
430
+ description: t("editor.toolbar.clipboardAccessUnavailable"),
431
+ });
432
+ return;
433
+ }
434
+
435
+ try {
436
+ await navigator.clipboard.writeText(copyPageUrl);
437
+ toast.success(t("editor.toolbar.copiedPageLink"));
438
+ } catch (error) {
439
+ toast.error(t("editor.toolbar.couldNotCopyLink"), {
440
+ description:
441
+ error instanceof Error ? error.message : t("empty.genericError"),
442
+ });
443
+ }
444
+ }, [copyPageUrl, t]);
445
+
323
446
  const handleRevealLocalPath = useCallback(async () => {
324
447
  try {
325
448
  const result = await revealLinkedLocalSourceFile(source);
@@ -528,515 +651,557 @@ export function DocumentToolbar({
528
651
 
529
652
  return (
530
653
  <>
531
- <div className="absolute top-2 end-2 z-10 flex items-center gap-0.5 rounded-xl border border-border/70 bg-background/95 p-1 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-background/85 sm:top-3 sm:end-4 sm:gap-1">
532
- {/* Presence — shared PresenceBar (agent + collaborator avatars) */}
533
- <PresenceBar
534
- activeUsers={activeUsers ?? []}
535
- agentPresent={agentPresent}
536
- agentActive={agentActive}
537
- currentUserEmail={currentUserEmail}
538
- className="me-1"
654
+ <div className="relative z-10 flex h-12 shrink-0 items-center gap-3 bg-background px-4">
655
+ <ToolbarBreadcrumb
656
+ items={
657
+ breadcrumbItems.length
658
+ ? breadcrumbItems
659
+ : [{ id: documentId, title: documentTitle || "Untitled" }]
660
+ }
661
+ currentDocumentId={documentId}
662
+ ariaLabel={t("editor.toolbar.pageBreadcrumb")}
663
+ untitledLabel={t("sidebar.untitled")}
664
+ onOpen={(id) => navigate(`/page/${id}`, { flushSync: true })}
539
665
  />
540
- {isLocalFileDocument ? (
541
- <Button
542
- size="sm"
543
- variant="outline"
544
- className="h-9 gap-1.5 rounded-lg px-3"
545
- disabled={shareLocalFile.isPending}
546
- onClick={() => void handleShareLocalFile()}
547
- >
548
- {shareLocalFile.isPending ? (
549
- <IconLoader2 className="h-4 w-4 animate-spin" />
550
- ) : (
551
- <IconShare3 className="h-4 w-4" />
552
- )}
553
- <span className="hidden sm:inline">
554
- {t("editor.toolbar.share")}
666
+
667
+ <div className="ml-auto flex min-w-0 items-center gap-0.5 sm:gap-1">
668
+ {editedLabel ? (
669
+ <span className="hidden shrink-0 px-2 text-sm text-muted-foreground lg:inline">
670
+ {editedLabel}
555
671
  </span>
556
- </Button>
557
- ) : (
558
- <>
559
- <ShareButton
560
- resourceType="document"
561
- resourceId={documentId}
562
- resourceTitle={documentTitle}
563
- shareUrl={shareUrl}
564
- defaultOpen={openShareOnLoad}
565
- onOpenChange={handleDbShareOpenChange}
566
- visibilityCopy={{
567
- org: {
568
- description: effectiveHideFromSearch
569
- ? t("editor.toolbar.orgLinkCanView")
570
- : t("editor.toolbar.orgCanFindAndView"),
571
- },
572
- }}
573
- hideInSearchControl={{
574
- checked: effectiveHideFromSearch,
575
- pending: setDocumentDiscoverability.isPending,
576
- label: t("editor.toolbar.hideInSearch"),
577
- description: t("editor.toolbar.hideInSearchDescription"),
578
- onCheckedChange: handleHideFromSearchChange,
579
- }}
580
- variant="compact"
581
- />
672
+ ) : null}
582
673
 
583
- <VersionHistoryPanel
584
- documentId={documentId}
585
- open={historyOpen}
586
- onOpenChange={setHistoryOpen}
587
- canRestore={canEdit}
588
- activeUsers={activeUsers}
589
- />
590
- </>
591
- )}
674
+ {/* Presence — shared PresenceBar (agent + collaborator avatars) */}
675
+ <PresenceBar
676
+ activeUsers={activeUsers ?? []}
677
+ agentPresent={agentPresent}
678
+ agentActive={agentActive}
679
+ currentUserEmail={currentUserEmail}
680
+ className="mr-1"
681
+ />
682
+ {isLocalFileDocument ? (
683
+ <Button
684
+ size="sm"
685
+ variant="outline"
686
+ className="h-9 gap-1.5 rounded-lg px-3"
687
+ disabled={shareLocalFile.isPending}
688
+ onClick={() => void handleShareLocalFile()}
689
+ >
690
+ {shareLocalFile.isPending ? (
691
+ <IconLoader2 className="h-4 w-4 animate-spin" />
692
+ ) : (
693
+ <IconShare3 className="h-4 w-4" />
694
+ )}
695
+ <span className="hidden sm:inline">
696
+ {t("editor.toolbar.share")}
697
+ </span>
698
+ </Button>
699
+ ) : (
700
+ <>
701
+ <ShareButton
702
+ resourceType="document"
703
+ resourceId={documentId}
704
+ resourceTitle={documentTitle}
705
+ shareUrl={shareUrl}
706
+ defaultOpen={openShareOnLoad}
707
+ onOpenChange={handleDbShareOpenChange}
708
+ visibilityCopy={{
709
+ org: {
710
+ description: effectiveHideFromSearch
711
+ ? t("editor.toolbar.orgLinkCanView")
712
+ : t("editor.toolbar.orgCanFindAndView"),
713
+ },
714
+ }}
715
+ hideInSearchControl={{
716
+ checked: effectiveHideFromSearch,
717
+ pending: setDocumentDiscoverability.isPending,
718
+ label: t("editor.toolbar.hideInSearch"),
719
+ description: t("editor.toolbar.hideInSearchDescription"),
720
+ onCheckedChange: handleHideFromSearchChange,
721
+ }}
722
+ variant="compact"
723
+ />
724
+
725
+ <VersionHistoryPanel
726
+ documentId={documentId}
727
+ open={historyOpen}
728
+ onOpenChange={setHistoryOpen}
729
+ canRestore={canEdit}
730
+ activeUsers={activeUsers}
731
+ />
732
+ </>
733
+ )}
592
734
 
593
- <DropdownMenu modal={false}>
594
735
  <Tooltip>
595
736
  <TooltipTrigger asChild>
596
- <DropdownMenuTrigger asChild>
597
- <button
598
- className="flex h-9 w-9 items-center justify-center rounded-lg text-muted-foreground hover:text-foreground hover:bg-accent"
599
- aria-label={t("editor.toolbar.morePageActions")}
600
- >
601
- <IconDotsVertical size={16} />
602
- </button>
603
- </DropdownMenuTrigger>
737
+ <button
738
+ type="button"
739
+ className="flex h-9 w-9 items-center justify-center rounded-lg text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
740
+ aria-label={t("editor.toolbar.copyPageLink")}
741
+ onClick={() => void handleCopyPageLink()}
742
+ >
743
+ <IconLink size={16} />
744
+ </button>
604
745
  </TooltipTrigger>
605
- <TooltipContent>
606
- {t("editor.toolbar.morePageActions")}
607
- </TooltipContent>
746
+ <TooltipContent>{t("editor.toolbar.copyPageLink")}</TooltipContent>
608
747
  </Tooltip>
609
- <DropdownMenuContent align="end" className="w-60">
610
- {isLocalFileDocument ? (
611
- <DropdownMenuGroup>
612
- <DropdownMenuLabel className="text-xs text-muted-foreground">
613
- {t("editor.toolbar.localFile")}
614
- </DropdownMenuLabel>
615
- <DropdownMenuItem disabled className="min-w-0">
616
- <IconFileText className="me-2 h-4 w-4 shrink-0" />
617
- <span className="truncate">{source?.path}</span>
618
- </DropdownMenuItem>
619
- <DropdownMenuItem
620
- disabled={revealLocalSource.isPending}
621
- onSelect={() => void handleRevealLocalPath()}
622
- >
623
- <IconFolderOpen className="me-2 h-4 w-4" />
624
- {t("editor.toolbar.revealInFinder")}
625
- </DropdownMenuItem>
626
- <DropdownMenuItem onSelect={handleCopyLocalRelativePath}>
627
- <IconCopy className="me-2 h-4 w-4" />
628
- {t("editor.toolbar.copyRelativePath")}
629
- </DropdownMenuItem>
630
- <DropdownMenuItem
631
- onSelect={() => void handleCopyLocalAbsolutePath()}
632
- >
633
- <IconCopy className="me-2 h-4 w-4" />
634
- {t("editor.toolbar.copyAbsolutePath")}
635
- </DropdownMenuItem>
636
- </DropdownMenuGroup>
637
- ) : (
638
- <>
748
+
749
+ <DropdownMenu modal={false}>
750
+ <Tooltip>
751
+ <TooltipTrigger asChild>
752
+ <DropdownMenuTrigger asChild>
753
+ <button
754
+ className="flex h-9 w-9 items-center justify-center rounded-lg text-muted-foreground hover:text-foreground hover:bg-accent"
755
+ aria-label={t("editor.toolbar.morePageActions")}
756
+ >
757
+ <IconDotsVertical size={16} />
758
+ </button>
759
+ </DropdownMenuTrigger>
760
+ </TooltipTrigger>
761
+ <TooltipContent>
762
+ {t("editor.toolbar.morePageActions")}
763
+ </TooltipContent>
764
+ </Tooltip>
765
+ <DropdownMenuContent align="end" className="w-60">
766
+ {isLocalFileDocument ? (
639
767
  <DropdownMenuGroup>
640
- <DropdownMenuItem onSelect={() => setHistoryOpen(true)}>
641
- <IconHistory className="me-2 h-4 w-4" />
642
- {t("editor.toolbar.versionHistory")}
768
+ <DropdownMenuLabel className="text-xs text-muted-foreground">
769
+ {t("editor.toolbar.localFile")}
770
+ </DropdownMenuLabel>
771
+ <DropdownMenuItem disabled className="min-w-0">
772
+ <IconFileText className="me-2 h-4 w-4 shrink-0" />
773
+ <span className="truncate">{source?.path}</span>
774
+ </DropdownMenuItem>
775
+ <DropdownMenuItem
776
+ disabled={revealLocalSource.isPending}
777
+ onSelect={() => void handleRevealLocalPath()}
778
+ >
779
+ <IconFolderOpen className="me-2 h-4 w-4" />
780
+ {t("editor.toolbar.revealInFinder")}
781
+ </DropdownMenuItem>
782
+ <DropdownMenuItem onSelect={handleCopyLocalRelativePath}>
783
+ <IconCopy className="me-2 h-4 w-4" />
784
+ {t("editor.toolbar.copyRelativePath")}
785
+ </DropdownMenuItem>
786
+ <DropdownMenuItem
787
+ onSelect={() => void handleCopyLocalAbsolutePath()}
788
+ >
789
+ <IconCopy className="me-2 h-4 w-4" />
790
+ {t("editor.toolbar.copyAbsolutePath")}
643
791
  </DropdownMenuItem>
644
792
  </DropdownMenuGroup>
645
- <DropdownMenuSeparator />
646
- <DropdownMenuSub>
647
- <DropdownMenuSubTrigger disabled={exportDocument.isPending}>
648
- {exportDocument.isPending ? (
649
- <IconLoader2 className="me-2 h-4 w-4 animate-spin" />
650
- ) : (
651
- <IconDownload className="me-2 h-4 w-4" />
652
- )}
653
- {t("editor.toolbar.export")}
654
- </DropdownMenuSubTrigger>
655
- <DropdownMenuSubContent className="w-44">
656
- <DropdownMenuItem
657
- disabled={exportDocument.isPending}
658
- onSelect={() => void handleExport("pdf")}
659
- >
660
- <IconFileTypePdf className="me-2 h-4 w-4" />
661
- PDF
793
+ ) : (
794
+ <>
795
+ <DropdownMenuGroup>
796
+ <DropdownMenuItem onSelect={() => setHistoryOpen(true)}>
797
+ <IconHistory className="me-2 h-4 w-4" />
798
+ {t("editor.toolbar.versionHistory")}
662
799
  </DropdownMenuItem>
663
- <DropdownMenuItem
664
- disabled={exportDocument.isPending}
665
- onSelect={() => void handleExport("markdown")}
666
- >
667
- <IconMarkdown className="me-2 h-4 w-4" />
668
- Markdown
669
- </DropdownMenuItem>
670
- <DropdownMenuItem
671
- disabled={exportDocument.isPending}
672
- onSelect={() => void handleExport("html")}
673
- >
674
- <IconFileTypeHtml className="me-2 h-4 w-4" />
675
- HTML
676
- </DropdownMenuItem>
677
- </DropdownMenuSubContent>
678
- </DropdownMenuSub>
679
- </>
680
- )}
681
- <DropdownMenuSeparator />
682
- <DropdownMenuGroup>
683
- {canEdit && !isLocalFileDocument ? (
684
- <Popover open={open} onOpenChange={setOpen}>
685
- <PopoverTrigger asChild>
686
- <button
687
- type="button"
688
- className={cn(
689
- "flex w-full items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground",
690
- isLinked ? "text-foreground" : "text-muted-foreground",
800
+ </DropdownMenuGroup>
801
+ <DropdownMenuSeparator />
802
+ <DropdownMenuSub>
803
+ <DropdownMenuSubTrigger disabled={exportDocument.isPending}>
804
+ {exportDocument.isPending ? (
805
+ <IconLoader2 className="me-2 h-4 w-4 animate-spin" />
806
+ ) : (
807
+ <IconDownload className="me-2 h-4 w-4" />
691
808
  )}
692
- >
693
- <span className="me-2 flex h-4 w-4 shrink-0 items-center justify-center">
694
- {hasConflict ? (
695
- <span className="relative">
696
- <NotionIcon className="h-4 w-4" />
697
- <IconAlertTriangle
698
- size={8}
699
- className="absolute -end-1 -top-1 text-amber-500"
700
- />
701
- </span>
702
- ) : isLinked && autoSync ? (
703
- <span className="relative">
704
- <NotionIcon className="h-4 w-4" />
705
- <span className="absolute -end-0.5 -top-0.5 h-2 w-2 rounded-full bg-emerald-500" />
706
- </span>
707
- ) : (
708
- <NotionIcon className="h-4 w-4" />
809
+ {t("editor.toolbar.export")}
810
+ </DropdownMenuSubTrigger>
811
+ <DropdownMenuSubContent className="w-44">
812
+ <DropdownMenuItem
813
+ disabled={exportDocument.isPending}
814
+ onSelect={() => void handleExport("pdf")}
815
+ >
816
+ <IconFileTypePdf className="me-2 h-4 w-4" />
817
+ PDF
818
+ </DropdownMenuItem>
819
+ <DropdownMenuItem
820
+ disabled={exportDocument.isPending}
821
+ onSelect={() => void handleExport("markdown")}
822
+ >
823
+ <IconMarkdown className="me-2 h-4 w-4" />
824
+ Markdown
825
+ </DropdownMenuItem>
826
+ <DropdownMenuItem
827
+ disabled={exportDocument.isPending}
828
+ onSelect={() => void handleExport("html")}
829
+ >
830
+ <IconFileTypeHtml className="me-2 h-4 w-4" />
831
+ HTML
832
+ </DropdownMenuItem>
833
+ </DropdownMenuSubContent>
834
+ </DropdownMenuSub>
835
+ </>
836
+ )}
837
+ <DropdownMenuSeparator />
838
+ <DropdownMenuGroup>
839
+ {canEdit && !isLocalFileDocument ? (
840
+ <Popover open={open} onOpenChange={setOpen}>
841
+ <PopoverTrigger asChild>
842
+ <button
843
+ type="button"
844
+ className={cn(
845
+ "flex w-full items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground",
846
+ isLinked
847
+ ? "text-foreground"
848
+ : "text-muted-foreground",
709
849
  )}
710
- </span>
711
- <span className="min-w-0 flex-1 truncate text-start">
712
- {isLinked
713
- ? t("editor.toolbar.notionSync")
714
- : isConnected
715
- ? t("editor.toolbar.linkToNotion")
716
- : t("editor.toolbar.connectNotion")}
717
- </span>
718
- </button>
719
- </PopoverTrigger>
850
+ >
851
+ <span className="me-2 flex h-4 w-4 shrink-0 items-center justify-center">
852
+ {hasConflict ? (
853
+ <span className="relative">
854
+ <NotionIcon className="h-4 w-4" />
855
+ <IconAlertTriangle
856
+ size={8}
857
+ className="absolute -end-1 -top-1 text-amber-500"
858
+ />
859
+ </span>
860
+ ) : isLinked && autoSync ? (
861
+ <span className="relative">
862
+ <NotionIcon className="h-4 w-4" />
863
+ <span className="absolute -end-0.5 -top-0.5 h-2 w-2 rounded-full bg-emerald-500" />
864
+ </span>
865
+ ) : (
866
+ <NotionIcon className="h-4 w-4" />
867
+ )}
868
+ </span>
869
+ <span className="min-w-0 flex-1 truncate text-start">
870
+ {isLinked
871
+ ? t("editor.toolbar.notionSync")
872
+ : isConnected
873
+ ? t("editor.toolbar.linkToNotion")
874
+ : t("editor.toolbar.connectNotion")}
875
+ </span>
876
+ </button>
877
+ </PopoverTrigger>
720
878
 
721
- <PopoverContent
722
- side="left"
723
- align="start"
724
- sideOffset={8}
725
- className="w-80 p-0"
726
- onOpenAutoFocus={(e) => e.preventDefault()}
727
- >
728
- {!isConnected ? (
729
- /* ─── Not connected ─── */
730
- <div className="p-4">
731
- <div className="flex items-center gap-2 mb-2">
732
- <NotionIcon className="h-4 w-4 shrink-0 text-muted-foreground" />
733
- <p className="text-sm font-medium">
734
- {t("editor.toolbar.connectNotion")}
879
+ <PopoverContent
880
+ side="left"
881
+ align="start"
882
+ sideOffset={8}
883
+ className="w-80 p-0"
884
+ onOpenAutoFocus={(e) => e.preventDefault()}
885
+ >
886
+ {!isConnected ? (
887
+ /* ─── Not connected ─── */
888
+ <div className="p-4">
889
+ <div className="flex items-center gap-2 mb-2">
890
+ <NotionIcon className="h-4 w-4 shrink-0 text-muted-foreground" />
891
+ <p className="text-sm font-medium">
892
+ {t("editor.toolbar.connectNotion")}
893
+ </p>
894
+ </div>
895
+ <p className="text-xs text-muted-foreground mb-3">
896
+ {t("editor.toolbar.setUpNotionToSync")}
735
897
  </p>
898
+ <Button
899
+ size="sm"
900
+ className="w-full"
901
+ onClick={handleSetup}
902
+ >
903
+ {t("editor.toolbar.setUpNotion")}
904
+ </Button>
736
905
  </div>
737
- <p className="text-xs text-muted-foreground mb-3">
738
- {t("editor.toolbar.setUpNotionToSync")}
739
- </p>
740
- <Button
741
- size="sm"
742
- className="w-full"
743
- onClick={handleSetup}
744
- >
745
- {t("editor.toolbar.setUpNotion")}
746
- </Button>
747
- </div>
748
- ) : isLinked ? (
749
- /* ─── Linked — show sync actions ─── */
750
- <div>
751
- <div className="px-4 py-3 border-b border-border">
752
- <div className="flex items-center gap-2">
753
- <NotionIcon className="h-3.5 w-3.5 shrink-0" />
754
- <span className="text-xs font-medium truncate">
755
- {t("editor.toolbar.linkedToNotion")}
756
- </span>
757
- {autoSync && (
758
- <span className="inline-flex items-center gap-1 rounded-full bg-emerald-500/15 px-1.5 py-0.5 text-[10px] font-medium text-emerald-700 dark:text-emerald-300">
759
- <IconRefresh size={9} />
760
- {t("editor.toolbar.auto")}
906
+ ) : isLinked ? (
907
+ /* ─── Linked — show sync actions ─── */
908
+ <div>
909
+ <div className="px-4 py-3 border-b border-border">
910
+ <div className="flex items-center gap-2">
911
+ <NotionIcon className="h-3.5 w-3.5 shrink-0" />
912
+ <span className="text-xs font-medium truncate">
913
+ {t("editor.toolbar.linkedToNotion")}
761
914
  </span>
915
+ {autoSync && (
916
+ <span className="inline-flex items-center gap-1 rounded-full bg-emerald-500/15 px-1.5 py-0.5 text-[10px] font-medium text-emerald-700 dark:text-emerald-300">
917
+ <IconRefresh size={9} />
918
+ {t("editor.toolbar.auto")}
919
+ </span>
920
+ )}
921
+ </div>
922
+ {syncStatus?.lastSyncedAt && (
923
+ <p className="mt-1 text-[10px] text-muted-foreground">
924
+ {t("editor.toolbar.lastSynced")}{" "}
925
+ {new Date(
926
+ syncStatus.lastSyncedAt,
927
+ ).toLocaleString()}
928
+ </p>
762
929
  )}
930
+ {syncStatus?.lastError && (
931
+ <p className="mt-1 text-[10px] text-destructive">
932
+ {syncStatus.lastError}
933
+ </p>
934
+ )}
935
+ {syncStatus?.warnings?.length ? (
936
+ <div className="mt-1.5 space-y-1">
937
+ {syncStatus.warnings
938
+ .slice(0, 3)
939
+ .map((warning, index) => (
940
+ <p
941
+ key={`${warning}-${index}`}
942
+ className="text-[10px] text-muted-foreground"
943
+ >
944
+ {warning}
945
+ </p>
946
+ ))}
947
+ </div>
948
+ ) : null}
763
949
  </div>
764
- {syncStatus?.lastSyncedAt && (
765
- <p className="mt-1 text-[10px] text-muted-foreground">
766
- {t("editor.toolbar.lastSynced")}{" "}
767
- {new Date(
768
- syncStatus.lastSyncedAt,
769
- ).toLocaleString()}
770
- </p>
771
- )}
772
- {syncStatus?.lastError && (
773
- <p className="mt-1 text-[10px] text-destructive">
774
- {syncStatus.lastError}
775
- </p>
776
- )}
777
- {syncStatus?.warnings?.length ? (
778
- <div className="mt-1.5 space-y-1">
779
- {syncStatus.warnings
780
- .slice(0, 3)
781
- .map((warning, index) => (
782
- <p
783
- key={`${warning}-${index}`}
784
- className="text-[10px] text-muted-foreground"
785
- >
786
- {warning}
787
- </p>
788
- ))}
789
- </div>
790
- ) : null}
791
- </div>
792
950
 
793
- {/* Conflict is shown via NotionConflictBanner above the title */}
951
+ {/* Conflict is shown via NotionConflictBanner above the title */}
794
952
 
795
- <div className="p-1.5">
796
- <button
797
- onClick={() => setAutoSync(!autoSync)}
798
- className="w-full flex items-center gap-2 px-3 py-1.5 text-xs hover:bg-accent rounded-md"
799
- >
800
- <IconRefresh
801
- size={12}
802
- className={
803
- autoSync
804
- ? "text-emerald-500"
805
- : "text-muted-foreground"
806
- }
807
- />
808
- <span
809
- className={
810
- autoSync
811
- ? "text-foreground font-medium"
812
- : "text-muted-foreground"
813
- }
814
- >
815
- {t("editor.toolbar.autoSync")}
816
- </span>
817
- <span
818
- className={cn(
819
- "ml-auto h-4 w-7 rounded-full relative",
820
- autoSync
821
- ? "bg-emerald-500"
822
- : "bg-muted-foreground/30",
823
- )}
953
+ <div className="p-1.5">
954
+ <button
955
+ onClick={() => setAutoSync(!autoSync)}
956
+ className="w-full flex items-center gap-2 px-3 py-1.5 text-xs hover:bg-accent rounded-md"
824
957
  >
958
+ <IconRefresh
959
+ size={12}
960
+ className={
961
+ autoSync
962
+ ? "text-emerald-500"
963
+ : "text-muted-foreground"
964
+ }
965
+ />
966
+ <span
967
+ className={
968
+ autoSync
969
+ ? "text-foreground font-medium"
970
+ : "text-muted-foreground"
971
+ }
972
+ >
973
+ {t("editor.toolbar.autoSync")}
974
+ </span>
825
975
  <span
826
976
  className={cn(
827
- "absolute top-0.5 h-3 w-3 rounded-full bg-white",
828
- autoSync ? "right-0.5" : "left-0.5",
977
+ "ml-auto h-4 w-7 rounded-full relative",
978
+ autoSync
979
+ ? "bg-emerald-500"
980
+ : "bg-muted-foreground/30",
829
981
  )}
830
- />
831
- </span>
832
- </button>
833
- <button
834
- onClick={handlePull}
835
- disabled={isWorking}
836
- className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground hover:text-foreground hover:bg-accent rounded-md disabled:opacity-40"
837
- >
838
- {pullDocument.isPending ? (
839
- <IconLoader2 size={12} className="animate-spin" />
840
- ) : (
841
- <IconArrowBarDown size={12} />
842
- )}
843
- {t("editor.toolbar.pullFromNotion")}
844
- </button>
845
- <button
846
- onClick={handlePush}
847
- disabled={isWorking}
848
- className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground hover:text-foreground hover:bg-accent rounded-md disabled:opacity-40"
849
- >
850
- {pushDocument.isPending ? (
851
- <IconLoader2 size={12} className="animate-spin" />
852
- ) : (
853
- <IconArrowBarUp size={12} />
854
- )}
855
- {t("editor.toolbar.pushToNotion")}
856
- </button>
857
- {syncStatus?.pageUrl && (
858
- <a
859
- href={syncStatus.pageUrl}
860
- target="_blank"
861
- rel="noopener noreferrer"
862
- className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground hover:text-foreground hover:bg-accent rounded-md"
982
+ >
983
+ <span
984
+ className={cn(
985
+ "absolute top-0.5 h-3 w-3 rounded-full bg-white",
986
+ autoSync ? "right-0.5" : "left-0.5",
987
+ )}
988
+ />
989
+ </span>
990
+ </button>
991
+ <button
992
+ onClick={handlePull}
993
+ disabled={isWorking}
994
+ className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground hover:text-foreground hover:bg-accent rounded-md disabled:opacity-40"
863
995
  >
864
- <IconExternalLink size={12} />
865
- {t("editor.toolbar.openInNotion")}
866
- </a>
867
- )}
868
- <button
869
- onClick={handleUnlink}
870
- disabled={isWorking}
871
- className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-destructive hover:bg-destructive/10 rounded-md disabled:opacity-40"
872
- >
873
- <IconLinkOff size={12} />
874
- {t("editor.toolbar.unlink")}
875
- </button>
876
- </div>
877
- </div>
878
- ) : (
879
- /* ─── Not linked — show search ─── */
880
- <div>
881
- <div className="p-3 pb-2">
882
- <div className="flex items-center gap-2 mb-2">
883
- <NotionIcon className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
884
- <span className="text-xs font-medium">
885
- {t("editor.toolbar.linkToNotionPage")}
886
- </span>
887
- </div>
888
- <div className="relative">
889
- <IconSearch
890
- size={13}
891
- className="absolute left-2.5 top-1/2 -translate-y-1/2 text-muted-foreground"
892
- />
893
- <input
894
- ref={searchInputRef}
895
- type="text"
896
- value={searchQuery}
897
- onChange={(e) => setSearchQuery(e.target.value)}
898
- placeholder={t(
899
- "editor.toolbar.searchNotionPages",
996
+ {pullDocument.isPending ? (
997
+ <IconLoader2
998
+ size={12}
999
+ className="animate-spin"
1000
+ />
1001
+ ) : (
1002
+ <IconArrowBarDown size={12} />
900
1003
  )}
901
- className="w-full rounded-md border border-input bg-background pl-8 pr-3 py-1.5 text-xs outline-none focus:ring-1 focus:ring-ring placeholder:text-muted-foreground"
902
- />
903
- </div>
904
- </div>
905
-
906
- <div className="max-h-64 overflow-y-auto border-t border-border">
907
- {/* Create new page option */}
908
- <div className="p-1.5 border-b border-border">
1004
+ {t("editor.toolbar.pullFromNotion")}
1005
+ </button>
909
1006
  <button
910
- onClick={() => handleCreateAndLink()}
1007
+ onClick={handlePush}
911
1008
  disabled={isWorking}
912
- className="w-full flex items-center gap-2.5 px-2.5 py-2 text-left rounded-md hover:bg-accent disabled:opacity-40"
1009
+ className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground hover:text-foreground hover:bg-accent rounded-md disabled:opacity-40"
913
1010
  >
914
- <span className="flex h-5 w-5 shrink-0 items-center justify-center">
915
- {createAndLink.isPending ? (
916
- <IconLoader2
917
- size={14}
918
- className="animate-spin text-muted-foreground"
919
- />
920
- ) : (
921
- <IconPlus
922
- size={14}
923
- className="text-muted-foreground"
924
- />
925
- )}
926
- </span>
1011
+ {pushDocument.isPending ? (
1012
+ <IconLoader2
1013
+ size={12}
1014
+ className="animate-spin"
1015
+ />
1016
+ ) : (
1017
+ <IconArrowBarUp size={12} />
1018
+ )}
1019
+ {t("editor.toolbar.pushToNotion")}
1020
+ </button>
1021
+ {syncStatus?.pageUrl && (
1022
+ <a
1023
+ href={syncStatus.pageUrl}
1024
+ target="_blank"
1025
+ rel="noopener noreferrer"
1026
+ className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground hover:text-foreground hover:bg-accent rounded-md"
1027
+ >
1028
+ <IconExternalLink size={12} />
1029
+ {t("editor.toolbar.openInNotion")}
1030
+ </a>
1031
+ )}
1032
+ <button
1033
+ onClick={handleUnlink}
1034
+ disabled={isWorking}
1035
+ className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-destructive hover:bg-destructive/10 rounded-md disabled:opacity-40"
1036
+ >
1037
+ <IconLinkOff size={12} />
1038
+ {t("editor.toolbar.unlink")}
1039
+ </button>
1040
+ </div>
1041
+ </div>
1042
+ ) : (
1043
+ /* ─── Not linked — show search ─── */
1044
+ <div>
1045
+ <div className="p-3 pb-2">
1046
+ <div className="flex items-center gap-2 mb-2">
1047
+ <NotionIcon className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
927
1048
  <span className="text-xs font-medium">
928
- {t("editor.toolbar.createNewPageInNotion")}
1049
+ {t("editor.toolbar.linkToNotionPage")}
929
1050
  </span>
930
- </button>
1051
+ </div>
1052
+ <div className="relative">
1053
+ <IconSearch
1054
+ size={13}
1055
+ className="absolute left-2.5 top-1/2 -translate-y-1/2 text-muted-foreground"
1056
+ />
1057
+ <input
1058
+ ref={searchInputRef}
1059
+ type="text"
1060
+ value={searchQuery}
1061
+ onChange={(e) => setSearchQuery(e.target.value)}
1062
+ placeholder={t(
1063
+ "editor.toolbar.searchNotionPages",
1064
+ )}
1065
+ className="w-full rounded-md border border-input bg-background pl-8 pr-3 py-1.5 text-xs outline-none focus:ring-1 focus:ring-ring placeholder:text-muted-foreground"
1066
+ />
1067
+ </div>
931
1068
  </div>
932
1069
 
933
- {searchLoading ? (
934
- <div className="flex items-center justify-center py-6">
935
- <IconLoader2
936
- size={16}
937
- className="animate-spin text-muted-foreground"
938
- />
1070
+ <div className="max-h-64 overflow-y-auto border-t border-border">
1071
+ {/* Create new page option */}
1072
+ <div className="p-1.5 border-b border-border">
1073
+ <button
1074
+ onClick={() => handleCreateAndLink()}
1075
+ disabled={isWorking}
1076
+ className="w-full flex items-center gap-2.5 px-2.5 py-2 text-left rounded-md hover:bg-accent disabled:opacity-40"
1077
+ >
1078
+ <span className="flex h-5 w-5 shrink-0 items-center justify-center">
1079
+ {createAndLink.isPending ? (
1080
+ <IconLoader2
1081
+ size={14}
1082
+ className="animate-spin text-muted-foreground"
1083
+ />
1084
+ ) : (
1085
+ <IconPlus
1086
+ size={14}
1087
+ className="text-muted-foreground"
1088
+ />
1089
+ )}
1090
+ </span>
1091
+ <span className="text-xs font-medium">
1092
+ {t("editor.toolbar.createNewPageInNotion")}
1093
+ </span>
1094
+ </button>
939
1095
  </div>
940
- ) : searchResults?.results.length ? (
941
- <div className="p-1.5">
942
- {searchResults.results.map((page) => (
943
- <div
944
- key={page.id}
945
- className="flex items-center gap-1 rounded-md hover:bg-accent"
946
- >
947
- <button
948
- onClick={() => handleLink(page.id)}
949
- disabled={isWorking}
950
- className="min-w-0 flex-1 flex items-center gap-2.5 px-2.5 py-2 text-left rounded-md disabled:opacity-40"
1096
+
1097
+ {searchLoading ? (
1098
+ <div className="flex items-center justify-center py-6">
1099
+ <IconLoader2
1100
+ size={16}
1101
+ className="animate-spin text-muted-foreground"
1102
+ />
1103
+ </div>
1104
+ ) : searchResults?.results.length ? (
1105
+ <div className="p-1.5">
1106
+ {searchResults.results.map((page) => (
1107
+ <div
1108
+ key={page.id}
1109
+ className="flex items-center gap-1 rounded-md hover:bg-accent"
951
1110
  >
952
- <span className="flex h-5 w-5 shrink-0 items-center justify-center text-sm">
953
- {linkingPageId === page.id ? (
954
- <IconLoader2
955
- size={14}
956
- className="animate-spin text-muted-foreground"
957
- />
958
- ) : (
959
- page.icon || (
960
- <IconFileText
961
- size={14}
962
- className="text-muted-foreground"
963
- />
964
- )
965
- )}
966
- </span>
967
- <div className="min-w-0 flex-1">
968
- <p className="text-xs font-medium truncate">
969
- {page.title}
970
- </p>
971
- {linkingPageId === page.id ? (
972
- <p className="text-[10px] text-muted-foreground">
973
- {t(
974
- "editor.toolbar.importingFromNotion",
975
- )}
976
- </p>
977
- ) : page.lastEditedTime ? (
978
- <p className="text-[10px] text-muted-foreground">
979
- {t("editor.toolbar.edited")}{" "}
980
- {new Date(
981
- page.lastEditedTime,
982
- ).toLocaleDateString()}
983
- </p>
984
- ) : null}
985
- </div>
986
- </button>
987
- <Tooltip>
988
- <TooltipTrigger asChild>
989
- <button
990
- onClick={() =>
991
- handleCreateAndLink(page.id)
992
- }
993
- disabled={isWorking}
994
- className="mr-1 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-foreground disabled:opacity-40"
995
- aria-label={t(
996
- "editor.toolbar.createNewPageInside",
997
- { title: page.title },
998
- )}
999
- >
1000
- {creatingParentPageId === page.id ? (
1111
+ <button
1112
+ onClick={() => handleLink(page.id)}
1113
+ disabled={isWorking}
1114
+ className="min-w-0 flex-1 flex items-center gap-2.5 px-2.5 py-2 text-left rounded-md disabled:opacity-40"
1115
+ >
1116
+ <span className="flex h-5 w-5 shrink-0 items-center justify-center text-sm">
1117
+ {linkingPageId === page.id ? (
1001
1118
  <IconLoader2
1002
- size={13}
1003
- className="animate-spin"
1119
+ size={14}
1120
+ className="animate-spin text-muted-foreground"
1004
1121
  />
1005
1122
  ) : (
1006
- <IconPlus size={13} />
1123
+ page.icon || (
1124
+ <IconFileText
1125
+ size={14}
1126
+ className="text-muted-foreground"
1127
+ />
1128
+ )
1007
1129
  )}
1008
- </button>
1009
- </TooltipTrigger>
1010
- <TooltipContent>
1011
- {t(
1012
- "editor.toolbar.createNewPageInsideThisPage",
1013
- )}
1014
- </TooltipContent>
1015
- </Tooltip>
1016
- </div>
1017
- ))}
1018
- </div>
1019
- ) : debouncedQuery || searchResults ? (
1020
- <div className="py-6 text-center text-xs text-muted-foreground">
1021
- {t("editor.toolbar.noPagesFound")}
1022
- </div>
1023
- ) : null}
1130
+ </span>
1131
+ <div className="min-w-0 flex-1">
1132
+ <p className="text-xs font-medium truncate">
1133
+ {page.title}
1134
+ </p>
1135
+ {linkingPageId === page.id ? (
1136
+ <p className="text-[10px] text-muted-foreground">
1137
+ {t(
1138
+ "editor.toolbar.importingFromNotion",
1139
+ )}
1140
+ </p>
1141
+ ) : page.lastEditedTime ? (
1142
+ <p className="text-[10px] text-muted-foreground">
1143
+ {t("editor.toolbar.edited")}{" "}
1144
+ {new Date(
1145
+ page.lastEditedTime,
1146
+ ).toLocaleDateString()}
1147
+ </p>
1148
+ ) : null}
1149
+ </div>
1150
+ </button>
1151
+ <Tooltip>
1152
+ <TooltipTrigger asChild>
1153
+ <button
1154
+ onClick={() =>
1155
+ handleCreateAndLink(page.id)
1156
+ }
1157
+ disabled={isWorking}
1158
+ className="mr-1 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-foreground disabled:opacity-40"
1159
+ aria-label={t(
1160
+ "editor.toolbar.createNewPageInside",
1161
+ { title: page.title },
1162
+ )}
1163
+ >
1164
+ {creatingParentPageId === page.id ? (
1165
+ <IconLoader2
1166
+ size={13}
1167
+ className="animate-spin"
1168
+ />
1169
+ ) : (
1170
+ <IconPlus size={13} />
1171
+ )}
1172
+ </button>
1173
+ </TooltipTrigger>
1174
+ <TooltipContent>
1175
+ {t(
1176
+ "editor.toolbar.createNewPageInsideThisPage",
1177
+ )}
1178
+ </TooltipContent>
1179
+ </Tooltip>
1180
+ </div>
1181
+ ))}
1182
+ </div>
1183
+ ) : debouncedQuery || searchResults ? (
1184
+ <div className="py-6 text-center text-xs text-muted-foreground">
1185
+ {t("editor.toolbar.noPagesFound")}
1186
+ </div>
1187
+ ) : null}
1188
+ </div>
1024
1189
  </div>
1025
- </div>
1026
- )}
1027
- </PopoverContent>
1028
- </Popover>
1029
- ) : null}
1030
- <div className="group relative">
1031
- <NotificationsBell className="!h-8 !w-full !justify-start !rounded-sm !px-2 !py-1.5 !text-sm hover:!bg-accent hover:!text-accent-foreground focus-visible:!ring-0" />
1032
- <span className="pointer-events-none absolute start-8 top-1/2 -translate-y-1/2 text-sm text-muted-foreground group-hover:text-accent-foreground">
1033
- {t("editor.toolbar.notifications")}
1034
- </span>
1035
- </div>
1036
- </DropdownMenuGroup>
1037
- </DropdownMenuContent>
1038
- </DropdownMenu>
1039
- <AgentToggleButton />
1190
+ )}
1191
+ </PopoverContent>
1192
+ </Popover>
1193
+ ) : null}
1194
+ <div className="group relative">
1195
+ <NotificationsBell className="!h-8 !w-full !justify-start !rounded-sm !px-2 !py-1.5 !text-sm hover:!bg-accent hover:!text-accent-foreground focus-visible:!ring-0" />
1196
+ <span className="pointer-events-none absolute start-8 top-1/2 -translate-y-1/2 text-sm text-muted-foreground group-hover:text-accent-foreground">
1197
+ {t("editor.toolbar.notifications")}
1198
+ </span>
1199
+ </div>
1200
+ </DropdownMenuGroup>
1201
+ </DropdownMenuContent>
1202
+ </DropdownMenu>
1203
+ <AgentToggleButton />
1204
+ </div>
1040
1205
  </div>
1041
1206
  </>
1042
1207
  );