@alpaca-editor/core 1.0.3992 → 1.0.3995
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.
- package/dist/components/ui/copy-button.d.ts +10 -0
- package/dist/components/ui/copy-button.js +33 -0
- package/dist/components/ui/copy-button.js.map +1 -0
- package/dist/components/ui/sonner.d.ts +3 -0
- package/dist/components/ui/sonner.js +14 -0
- package/dist/components/ui/sonner.js.map +1 -0
- package/dist/config/config.js +4 -16
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +6 -3
- package/dist/editor/ComponentInfo.js +2 -2
- package/dist/editor/ComponentInfo.js.map +1 -1
- package/dist/editor/ContentTree.d.ts +2 -1
- package/dist/editor/ContentTree.js +4 -8
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/FieldListField.js +3 -10
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/ItemInfo.js +3 -3
- package/dist/editor/ItemInfo.js.map +1 -1
- package/dist/editor/ai/Agents.d.ts +6 -0
- package/dist/editor/ai/Agents.js +48 -0
- package/dist/editor/ai/Agents.js.map +1 -0
- package/dist/editor/ai/AiTerminal.js +4 -2
- package/dist/editor/ai/AiTerminal.js.map +1 -1
- package/dist/editor/client/EditorClient.js +48 -91
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +3 -2
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/commands/itemCommands.js +5 -24
- package/dist/editor/commands/itemCommands.js.map +1 -1
- package/dist/editor/component-designer/ComponentEditor.js +3 -5
- package/dist/editor/component-designer/ComponentEditor.js.map +1 -1
- package/dist/editor/field-types/InternalLinkFieldEditor.js +20 -25
- package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
- package/dist/editor/field-types/RichTextEditor.d.ts +4 -3
- package/dist/editor/field-types/RichTextEditor.js +16 -3
- package/dist/editor/field-types/RichTextEditor.js.map +1 -1
- package/dist/editor/field-types/RichTextEditorComponent.d.ts +6 -5
- package/dist/editor/field-types/RichTextEditorComponent.js +59 -60
- package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
- package/dist/editor/field-types/TreeListEditor.js +7 -5
- package/dist/editor/field-types/TreeListEditor.js.map +1 -1
- package/dist/editor/field-types/richtext/components/EditorDropdown.d.ts +11 -0
- package/dist/editor/field-types/richtext/components/EditorDropdown.js +83 -0
- package/dist/editor/field-types/richtext/components/EditorDropdown.js.map +1 -0
- package/dist/editor/field-types/richtext/components/ReactSlate.d.ts +5 -0
- package/dist/editor/field-types/richtext/components/ReactSlate.js +562 -0
- package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -0
- package/dist/editor/field-types/richtext/components/ToolbarButton.d.ts +3 -0
- package/dist/editor/field-types/richtext/components/ToolbarButton.js +13 -0
- package/dist/editor/field-types/richtext/components/ToolbarButton.js.map +1 -0
- package/dist/editor/field-types/richtext/config/pluginFactory.d.ts +17 -0
- package/dist/editor/field-types/richtext/config/pluginFactory.js +14 -0
- package/dist/editor/field-types/richtext/config/pluginFactory.js.map +1 -0
- package/dist/editor/field-types/richtext/hooks/useProfileCache.d.ts +68 -0
- package/dist/editor/field-types/richtext/hooks/useProfileCache.js +208 -0
- package/dist/editor/field-types/richtext/hooks/useProfileCache.js.map +1 -0
- package/dist/editor/field-types/richtext/hooks/useRichTextProfile.d.ts +25 -0
- package/dist/editor/field-types/richtext/hooks/useRichTextProfile.js +64 -0
- package/dist/editor/field-types/richtext/hooks/useRichTextProfile.js.map +1 -0
- package/dist/editor/field-types/richtext/index.d.ts +5 -0
- package/dist/editor/field-types/richtext/index.js +6 -0
- package/dist/editor/field-types/richtext/index.js.map +1 -0
- package/dist/editor/field-types/richtext/types.d.ts +139 -0
- package/dist/editor/field-types/richtext/types.js +107 -0
- package/dist/editor/field-types/richtext/types.js.map +1 -0
- package/dist/editor/field-types/richtext/utils/conversion.d.ts +5 -0
- package/dist/editor/field-types/richtext/utils/conversion.js +539 -0
- package/dist/editor/field-types/richtext/utils/conversion.js.map +1 -0
- package/dist/editor/field-types/richtext/utils/plugins.d.ts +97 -0
- package/dist/editor/field-types/richtext/utils/plugins.js +272 -0
- package/dist/editor/field-types/richtext/utils/plugins.js.map +1 -0
- package/dist/editor/field-types/richtext/utils/profileMapper.d.ts +38 -0
- package/dist/editor/field-types/richtext/utils/profileMapper.js +366 -0
- package/dist/editor/field-types/richtext/utils/profileMapper.js.map +1 -0
- package/dist/editor/field-types/richtext/utils/profileServiceCache.d.ts +37 -0
- package/dist/editor/field-types/richtext/utils/profileServiceCache.js +117 -0
- package/dist/editor/field-types/richtext/utils/profileServiceCache.js.map +1 -0
- package/dist/editor/media-selector/AiImageSearch.js +2 -5
- package/dist/editor/media-selector/AiImageSearch.js.map +1 -1
- package/dist/editor/media-selector/MediaFolderBrowser.js +2 -5
- package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
- package/dist/editor/media-selector/TreeSelector.js +2 -5
- package/dist/editor/media-selector/TreeSelector.js.map +1 -1
- package/dist/editor/menubar/FavoritesControls.d.ts +8 -0
- package/dist/editor/menubar/FavoritesControls.js +124 -0
- package/dist/editor/menubar/FavoritesControls.js.map +1 -0
- package/dist/editor/menubar/ItemLanguageVersion.js +2 -1
- package/dist/editor/menubar/ItemLanguageVersion.js.map +1 -1
- package/dist/editor/menubar/PageSelector.js +3 -6
- package/dist/editor/menubar/PageSelector.js.map +1 -1
- package/dist/editor/reviews/reviewCommands.js +3 -8
- package/dist/editor/reviews/reviewCommands.js.map +1 -1
- package/dist/editor/services/contentService.d.ts +8 -0
- package/dist/editor/services/contentService.js +3 -0
- package/dist/editor/services/contentService.js.map +1 -1
- package/dist/editor/services/favouritesService.d.ts +33 -0
- package/dist/editor/services/favouritesService.js +22 -0
- package/dist/editor/services/favouritesService.js.map +1 -0
- package/dist/editor/sidebar/ComponentTree.js +7 -1
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/Debug.js +2 -2
- package/dist/editor/sidebar/Debug.js.map +1 -1
- package/dist/editor/sidebar/SEOInfo.js +4 -15
- package/dist/editor/sidebar/SEOInfo.js.map +1 -1
- package/dist/editor/ui/ItemSearch.js +2 -5
- package/dist/editor/ui/ItemSearch.js.map +1 -1
- package/dist/editor/ui/PerfectTree.d.ts +4 -2
- package/dist/editor/ui/PerfectTree.js +16 -7
- package/dist/editor/ui/PerfectTree.js.map +1 -1
- package/dist/editor/ui/Section.js +1 -1
- package/dist/editor/utils/itemutils.js +3 -1
- package/dist/editor/utils/itemutils.js.map +1 -1
- package/dist/editor/utils/keyboardNavigation.d.ts +32 -0
- package/dist/editor/utils/keyboardNavigation.js +156 -0
- package/dist/editor/utils/keyboardNavigation.js.map +1 -0
- package/dist/editor/views/ItemEditor.js +10 -3
- package/dist/editor/views/ItemEditor.js.map +1 -1
- package/dist/page-wizard/PageWizard.d.ts +2 -2
- package/dist/page-wizard/steps/ContentStep.js +7 -7
- package/dist/page-wizard/steps/ContentStep.js.map +1 -1
- package/dist/page-wizard/steps/schema.js +4 -2
- package/dist/page-wizard/steps/schema.js.map +1 -1
- package/dist/page-wizard/steps/usePageCreator.js +1 -1
- package/dist/page-wizard/steps/usePageCreator.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/splash-screen/NewPage.js +7 -10
- package/dist/splash-screen/NewPage.js.map +1 -1
- package/dist/styles.css +34 -5
- package/package.json +6 -1
- package/src/components/ui/copy-button.tsx +75 -0
- package/src/components/ui/sonner.tsx +25 -0
- package/src/config/config.tsx +5 -19
- package/src/config/types.ts +6 -3
- package/src/editor/ComponentInfo.tsx +5 -4
- package/src/editor/ContentTree.tsx +5 -6
- package/src/editor/FieldListField.tsx +4 -25
- package/src/editor/ItemInfo.tsx +5 -5
- package/src/editor/ai/Agents.tsx +125 -0
- package/src/editor/ai/AiTerminal.tsx +4 -0
- package/src/editor/client/EditorClient.tsx +58 -119
- package/src/editor/client/editContext.ts +3 -2
- package/src/editor/commands/itemCommands.tsx +10 -25
- package/src/editor/component-designer/ComponentEditor.tsx +8 -10
- package/src/editor/field-types/InternalLinkFieldEditor.tsx +73 -69
- package/src/editor/field-types/RichTextEditor.tsx +40 -3
- package/src/editor/field-types/RichTextEditorComponent.tsx +74 -77
- package/src/editor/field-types/TreeListEditor.tsx +7 -7
- package/src/editor/field-types/richtext/components/EditorDropdown.css +81 -0
- package/src/editor/field-types/richtext/components/EditorDropdown.tsx +165 -0
- package/src/editor/field-types/richtext/components/ReactSlate.css +161 -0
- package/src/editor/field-types/richtext/components/ReactSlate.tsx +801 -0
- package/src/editor/field-types/richtext/components/ToolbarButton.tsx +23 -0
- package/src/editor/field-types/richtext/config/pluginFactory.tsx +22 -0
- package/src/editor/field-types/richtext/hooks/useProfileCache.ts +270 -0
- package/src/editor/field-types/richtext/hooks/useRichTextProfile.ts +94 -0
- package/src/editor/field-types/richtext/index.ts +5 -0
- package/src/editor/field-types/richtext/types.ts +269 -0
- package/src/editor/field-types/richtext/utils/conversion.ts +589 -0
- package/src/editor/field-types/richtext/utils/plugins.ts +346 -0
- package/src/editor/field-types/richtext/utils/profileMapper.ts +424 -0
- package/src/editor/field-types/richtext/utils/profileServiceCache.ts +154 -0
- package/src/editor/media-selector/AiImageSearch.tsx +2 -5
- package/src/editor/media-selector/MediaFolderBrowser.tsx +2 -5
- package/src/editor/media-selector/TreeSelector.tsx +2 -5
- package/src/editor/menubar/FavoritesControls.tsx +250 -0
- package/src/editor/menubar/ItemLanguageVersion.tsx +3 -1
- package/src/editor/menubar/PageSelector.tsx +76 -75
- package/src/editor/reviews/reviewCommands.tsx +3 -8
- package/src/editor/services/contentService.ts +12 -0
- package/src/editor/services/favouritesService.ts +60 -0
- package/src/editor/sidebar/ComponentTree.tsx +12 -1
- package/src/editor/sidebar/Debug.tsx +4 -3
- package/src/editor/sidebar/SEOInfo.tsx +6 -16
- package/src/editor/ui/ItemSearch.tsx +2 -5
- package/src/editor/ui/PerfectTree.tsx +19 -6
- package/src/editor/ui/Section.tsx +1 -1
- package/src/editor/utils/{itemutils.ts → itemutils.tsx} +12 -12
- package/src/editor/utils/keyboardNavigation.ts +234 -0
- package/src/editor/views/ItemEditor.tsx +22 -1
- package/src/page-wizard/PageWizard.tsx +2 -2
- package/src/page-wizard/steps/ContentStep.tsx +7 -9
- package/src/page-wizard/steps/schema.ts +10 -7
- package/src/page-wizard/steps/usePageCreator.ts +1 -0
- package/src/revision.ts +2 -2
- package/src/splash-screen/NewPage.tsx +28 -24
- package/dist/editor/ui/CopyToClipboardButton.d.ts +0 -3
- package/dist/editor/ui/CopyToClipboardButton.js +0 -16
- package/dist/editor/ui/CopyToClipboardButton.js.map +0 -1
- package/src/editor/ui/CopyToClipboardButton.tsx +0 -24
|
@@ -81,6 +81,8 @@ export interface TreeProps<T = any> {
|
|
|
81
81
|
enableKeyboardSearch?: boolean;
|
|
82
82
|
/** Time in ms before search is cleared (default: 1500) */
|
|
83
83
|
searchClearDelay?: number;
|
|
84
|
+
/** Whether to disable automatic selection when expanding nodes (even during search) */
|
|
85
|
+
disableAutoSelectOnExpand?: boolean;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
/**
|
|
@@ -580,6 +582,7 @@ export const PerfectTree = <T,>({
|
|
|
580
582
|
scrollToSelected = false,
|
|
581
583
|
enableKeyboardSearch = false,
|
|
582
584
|
searchClearDelay = 1500,
|
|
585
|
+
disableAutoSelectOnExpand = false,
|
|
583
586
|
}: TreeProps<T>) => {
|
|
584
587
|
const [searchTerm, setSearchTerm] = useState("");
|
|
585
588
|
const [isFocused, setIsFocused] = useState(false);
|
|
@@ -590,18 +593,21 @@ export const PerfectTree = <T,>({
|
|
|
590
593
|
(node: TreeNode<T>) => {
|
|
591
594
|
const isCurrentlyExpanded = expandedKeys.includes(node.key);
|
|
592
595
|
|
|
593
|
-
// If the node is being expanded (not collapsed)
|
|
596
|
+
// If the node is being expanded (not collapsed) and there's an active search filter
|
|
594
597
|
if (!isCurrentlyExpanded) {
|
|
598
|
+
// Only select the node for quick navigation if there's an active search filter
|
|
599
|
+
// and auto-selection is not disabled
|
|
600
|
+
if (searchTerm && onSelect && !disableAutoSelectOnExpand) {
|
|
601
|
+
onSelect(node.key, {} as React.MouseEvent);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Clear the search filter
|
|
595
605
|
setSearchTerm("");
|
|
596
606
|
// Clear any pending search timeout
|
|
597
607
|
if (searchTimeoutRef.current) {
|
|
598
608
|
clearTimeout(searchTimeoutRef.current);
|
|
599
609
|
searchTimeoutRef.current = null;
|
|
600
610
|
}
|
|
601
|
-
// Select the node being expanded for quick navigation
|
|
602
|
-
if (onSelect) {
|
|
603
|
-
onSelect(node.key, {} as React.MouseEvent);
|
|
604
|
-
}
|
|
605
611
|
}
|
|
606
612
|
|
|
607
613
|
if (onToggleExpand) {
|
|
@@ -613,7 +619,14 @@ export const PerfectTree = <T,>({
|
|
|
613
619
|
onLazyLoad(node);
|
|
614
620
|
}
|
|
615
621
|
},
|
|
616
|
-
[
|
|
622
|
+
[
|
|
623
|
+
onToggleExpand,
|
|
624
|
+
onLazyLoad,
|
|
625
|
+
expandedKeys,
|
|
626
|
+
onSelect,
|
|
627
|
+
searchTerm,
|
|
628
|
+
disableAutoSelectOnExpand,
|
|
629
|
+
],
|
|
617
630
|
);
|
|
618
631
|
|
|
619
632
|
const handleSelect = useCallback(
|
|
@@ -18,7 +18,7 @@ export function Section({
|
|
|
18
18
|
open
|
|
19
19
|
? "border-blue-500 bg-gray-600"
|
|
20
20
|
: "border-gray-400 bg-gray-400 hover:border-gray-300 hover:bg-gray-500",
|
|
21
|
-
"flex cursor-pointer items-center justify-between border-l-[
|
|
21
|
+
"flex cursor-pointer items-center justify-between border-l-[7px] px-3 py-2 text-xs text-white transition-all duration-200 ease-in-out",
|
|
22
22
|
)}
|
|
23
23
|
onClick={() => setOpen(!open)}
|
|
24
24
|
>
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { getCreateAndSwitchToNewVersionCommand } from "../commands/createVersionCommand";
|
|
2
2
|
import { Language } from "../pageModel";
|
|
3
3
|
import { EditContextType } from "../client/editContext";
|
|
4
|
+
import { TriangleAlert } from "lucide-react";
|
|
4
5
|
|
|
5
6
|
export const confirmCreateVersion = (
|
|
6
7
|
editContext: EditContextType,
|
|
7
|
-
language: Language
|
|
8
|
+
language: Language,
|
|
8
9
|
) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
editContext.confirm({
|
|
11
|
+
message:
|
|
12
|
+
"This page has no version in language " +
|
|
13
|
+
language.name +
|
|
14
|
+
" (" +
|
|
15
|
+
language.languageCode +
|
|
16
|
+
"). Do you want to create a new version?",
|
|
17
|
+
header: "Create Language Version?",
|
|
18
|
+
icon: <TriangleAlert strokeWidth={1} className="h-4 w-4" />,
|
|
18
19
|
acceptLabel: "Yes, create version",
|
|
19
20
|
rejectLabel: "No",
|
|
20
21
|
accept: async () => {
|
|
@@ -23,7 +24,6 @@ export const confirmCreateVersion = (
|
|
|
23
24
|
language: language.languageCode,
|
|
24
25
|
}),
|
|
25
26
|
});
|
|
26
|
-
},
|
|
27
27
|
},
|
|
28
|
-
);
|
|
28
|
+
});
|
|
29
29
|
};
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { EditContextType } from "../client/editContext";
|
|
2
|
+
import { EditorConfiguration } from "../../config/types";
|
|
3
|
+
import { ItemDescriptor, FullItem } from "../pageModel";
|
|
4
|
+
import { HistoryEntry } from "../../types";
|
|
5
|
+
import { useDebouncedCallback } from "use-debounce";
|
|
6
|
+
import { useCallback } from "react";
|
|
7
|
+
|
|
8
|
+
export interface KeyboardNavigationDependencies {
|
|
9
|
+
editContextRef: React.MutableRefObject<EditContextType | undefined>;
|
|
10
|
+
operations: any;
|
|
11
|
+
pageViewContext: any;
|
|
12
|
+
configuration: EditorConfiguration;
|
|
13
|
+
contentEditorItem: FullItem | undefined;
|
|
14
|
+
browseHistory: HistoryEntry[];
|
|
15
|
+
loadItem: (
|
|
16
|
+
itemToLoad: ItemDescriptor | string,
|
|
17
|
+
options?: { addToBrowseHistory?: boolean; skipViewChange?: boolean },
|
|
18
|
+
) => Promise<FullItem | undefined>;
|
|
19
|
+
showInfoToast: (props: { summary?: string; details?: string }) => void;
|
|
20
|
+
showErrorToast: (props: { summary?: string; details?: string }) => void;
|
|
21
|
+
executeCommand: (params: {
|
|
22
|
+
command: any;
|
|
23
|
+
data?: any;
|
|
24
|
+
event?: React.SyntheticEvent;
|
|
25
|
+
}) => Promise<any>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function useKeyboardNavigation(deps: KeyboardNavigationDependencies) {
|
|
29
|
+
const {
|
|
30
|
+
editContextRef,
|
|
31
|
+
operations,
|
|
32
|
+
pageViewContext,
|
|
33
|
+
configuration,
|
|
34
|
+
contentEditorItem,
|
|
35
|
+
browseHistory,
|
|
36
|
+
loadItem,
|
|
37
|
+
showInfoToast,
|
|
38
|
+
executeCommand,
|
|
39
|
+
} = deps;
|
|
40
|
+
|
|
41
|
+
const handleKeyDownDebounced = useDebouncedCallback(
|
|
42
|
+
async (event: KeyboardEvent) => {
|
|
43
|
+
if (!event.key) return;
|
|
44
|
+
|
|
45
|
+
if (event.ctrlKey && event.key === "z") {
|
|
46
|
+
await operations.undo();
|
|
47
|
+
}
|
|
48
|
+
if (event.ctrlKey && event.key === "y") {
|
|
49
|
+
await operations.redo();
|
|
50
|
+
}
|
|
51
|
+
if (event.ctrlKey && event.key === "F11") {
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
pageViewContext.setFullscreen(false);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// History Navigation (Alt + Arrow keys, Alt + Shift + Arrow keys for favorites only)
|
|
57
|
+
if (
|
|
58
|
+
event.altKey &&
|
|
59
|
+
(event.key === "ArrowLeft" || event.key === "ArrowRight")
|
|
60
|
+
) {
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
const currentItem = contentEditorItem;
|
|
63
|
+
if (!currentItem) return;
|
|
64
|
+
|
|
65
|
+
let historyToNavigate = browseHistory;
|
|
66
|
+
|
|
67
|
+
// If Shift is also pressed, filter history to only include favorites
|
|
68
|
+
if (event.shiftKey) {
|
|
69
|
+
if (editContextRef.current?.favorites) {
|
|
70
|
+
const favoriteIds = new Set(
|
|
71
|
+
editContextRef.current.favorites.map(
|
|
72
|
+
(fav: any) => `${fav.itemId}:${fav.language}`,
|
|
73
|
+
),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
historyToNavigate = browseHistory.filter((historyItem) =>
|
|
77
|
+
favoriteIds.has(`${historyItem.id}:${historyItem.language}`),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (historyToNavigate.length === 0) {
|
|
81
|
+
showInfoToast({
|
|
82
|
+
summary: "Navigation",
|
|
83
|
+
details: "No favorite items found in browse history",
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
showInfoToast({
|
|
89
|
+
summary: "Navigation",
|
|
90
|
+
details: "Favorites not loaded yet",
|
|
91
|
+
});
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const currentIndex = historyToNavigate.findIndex(
|
|
97
|
+
(x) => x.id === currentItem.id && x.language === currentItem.language,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
if (
|
|
101
|
+
event.key === "ArrowLeft" &&
|
|
102
|
+
currentIndex < historyToNavigate.length - 1
|
|
103
|
+
) {
|
|
104
|
+
// Go forward in history
|
|
105
|
+
const historyItem = historyToNavigate[currentIndex + 1];
|
|
106
|
+
if (historyItem) {
|
|
107
|
+
loadItem(
|
|
108
|
+
{
|
|
109
|
+
id: historyItem.id,
|
|
110
|
+
language: historyItem.language,
|
|
111
|
+
version: historyItem.version || 0,
|
|
112
|
+
},
|
|
113
|
+
{ addToBrowseHistory: false },
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
} else if (event.key === "ArrowRight" && currentIndex > 0) {
|
|
117
|
+
// Go back in history
|
|
118
|
+
const historyItem = historyToNavigate[currentIndex - 1];
|
|
119
|
+
if (historyItem) {
|
|
120
|
+
loadItem(
|
|
121
|
+
{
|
|
122
|
+
id: historyItem.id,
|
|
123
|
+
language: historyItem.language,
|
|
124
|
+
version: historyItem.version || 0,
|
|
125
|
+
},
|
|
126
|
+
{ addToBrowseHistory: false },
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Quick access to favorites (Ctrl + 1-9)
|
|
134
|
+
if (event.altKey && /^[1-9]$/.test(event.key)) {
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
const index = parseInt(event.key) - 1;
|
|
137
|
+
|
|
138
|
+
// Use favorites from editContext
|
|
139
|
+
if (editContextRef.current?.favorites) {
|
|
140
|
+
const favorites = editContextRef.current.favorites;
|
|
141
|
+
if (favorites[index]) {
|
|
142
|
+
const favorite = favorites[index];
|
|
143
|
+
loadItem({
|
|
144
|
+
id: favorite.itemId,
|
|
145
|
+
language: favorite.language,
|
|
146
|
+
version: 0,
|
|
147
|
+
});
|
|
148
|
+
} else {
|
|
149
|
+
showInfoToast({
|
|
150
|
+
summary: "Favorites",
|
|
151
|
+
details: `No favorite item at position ${event.key}`,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
showInfoToast({
|
|
156
|
+
summary: "Favorites",
|
|
157
|
+
details: "Favorites not loaded yet",
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Command execution
|
|
164
|
+
const command = configuration.commands.allItemCommands.find(
|
|
165
|
+
(x) => x.keyBinding === event.key,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
if (command) {
|
|
169
|
+
event.preventDefault();
|
|
170
|
+
const contentEditorItem = editContextRef.current?.contentEditorItem;
|
|
171
|
+
if (!contentEditorItem) return;
|
|
172
|
+
|
|
173
|
+
const items =
|
|
174
|
+
editContextRef.current?.selection?.map((x) => ({
|
|
175
|
+
id: x,
|
|
176
|
+
language: contentEditorItem.language,
|
|
177
|
+
version: 0,
|
|
178
|
+
})) || [];
|
|
179
|
+
|
|
180
|
+
if (!items.length) items.push(contentEditorItem.descriptor);
|
|
181
|
+
|
|
182
|
+
if (items.length > 0) {
|
|
183
|
+
const fullItems =
|
|
184
|
+
await editContextRef.current?.itemsRepository.getItems(items);
|
|
185
|
+
executeCommand({
|
|
186
|
+
command,
|
|
187
|
+
data: {
|
|
188
|
+
items: fullItems,
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
50,
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
const handleKeyDown = useCallback(
|
|
198
|
+
async (event: KeyboardEvent) => {
|
|
199
|
+
if (event.key === "Insert") {
|
|
200
|
+
event.preventDefault();
|
|
201
|
+
event.stopPropagation();
|
|
202
|
+
editContextRef.current?.setInsertMode((x) => !x);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (event.ctrlKey && event.key === "s") {
|
|
206
|
+
event.preventDefault();
|
|
207
|
+
event.stopPropagation();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const target = event.target as HTMLElement;
|
|
212
|
+
const isTyping =
|
|
213
|
+
target instanceof HTMLInputElement ||
|
|
214
|
+
target instanceof HTMLTextAreaElement ||
|
|
215
|
+
target.isContentEditable;
|
|
216
|
+
|
|
217
|
+
if (
|
|
218
|
+
(event.ctrlKey && event.key === "z") ||
|
|
219
|
+
(event.ctrlKey && event.key === "y")
|
|
220
|
+
) {
|
|
221
|
+
if (!isTyping) {
|
|
222
|
+
event.preventDefault();
|
|
223
|
+
event.stopPropagation();
|
|
224
|
+
handleKeyDownDebounced(event);
|
|
225
|
+
}
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
handleKeyDownDebounced(event);
|
|
229
|
+
},
|
|
230
|
+
[handleKeyDownDebounced, editContextRef],
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
return { handleKeyDown };
|
|
234
|
+
}
|
|
@@ -5,6 +5,7 @@ import { ItemInfo } from "../ItemInfo";
|
|
|
5
5
|
import { useEditContext } from "../client/editContext";
|
|
6
6
|
import { PageViewContext } from "../page-viewer/pageViewContext";
|
|
7
7
|
import { FullItem } from "../pageModel";
|
|
8
|
+
import { LanguageSelector } from "../menubar/LanguageSelector";
|
|
8
9
|
|
|
9
10
|
export function ItemEditor({
|
|
10
11
|
item,
|
|
@@ -43,7 +44,7 @@ export function ItemEditor({
|
|
|
43
44
|
)}
|
|
44
45
|
|
|
45
46
|
{editContext.itemVersions.length === 0 && (
|
|
46
|
-
<div className="flex
|
|
47
|
+
<div className="flex flex-col items-center gap-4 p-4">
|
|
47
48
|
<Button
|
|
48
49
|
onClick={async () => {
|
|
49
50
|
await editContext.operations.createVersion(item.descriptor);
|
|
@@ -51,6 +52,26 @@ export function ItemEditor({
|
|
|
51
52
|
>
|
|
52
53
|
Create First Version ({item.language})
|
|
53
54
|
</Button>
|
|
55
|
+
|
|
56
|
+
{/* Show LanguageSelector if other languages are available */}
|
|
57
|
+
{editContext.itemLanguages.length > 1 && (
|
|
58
|
+
<div className="flex flex-col items-center gap-2">
|
|
59
|
+
<div className="text-sm text-gray-600">
|
|
60
|
+
Or select a different language:
|
|
61
|
+
</div>
|
|
62
|
+
<LanguageSelector
|
|
63
|
+
selectedLanguage={item.language}
|
|
64
|
+
onLanguageSelected={(language) => {
|
|
65
|
+
editContext.loadItem({
|
|
66
|
+
id: item.descriptor.id,
|
|
67
|
+
language: language.languageCode,
|
|
68
|
+
version: 0,
|
|
69
|
+
});
|
|
70
|
+
}}
|
|
71
|
+
showAllLanguagesSwitch={false}
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
)}
|
|
54
75
|
</div>
|
|
55
76
|
)}
|
|
56
77
|
</div>
|
|
@@ -36,8 +36,8 @@ export type SchemaField = {
|
|
|
36
36
|
export type WizardSchemaComponent = {
|
|
37
37
|
type: string;
|
|
38
38
|
fields: WizardSchemaField[];
|
|
39
|
-
|
|
40
|
-
allowedChildrenComponentTypes
|
|
39
|
+
validParentPlaceholders?: string[];
|
|
40
|
+
allowedChildrenComponentTypes?: string[];
|
|
41
41
|
allowedOnRoot: boolean;
|
|
42
42
|
};
|
|
43
43
|
|
|
@@ -472,7 +472,6 @@ export function ContentStep({
|
|
|
472
472
|
return;
|
|
473
473
|
}
|
|
474
474
|
}
|
|
475
|
-
console.log("Wiping components 2");
|
|
476
475
|
editContextRef.current?.itemsRepository.clear();
|
|
477
476
|
modifiedFieldsContext?.clear();
|
|
478
477
|
setInternalState((prev: any) => ({
|
|
@@ -488,10 +487,9 @@ export function ContentStep({
|
|
|
488
487
|
|
|
489
488
|
pageLoadedRef.current = false;
|
|
490
489
|
|
|
491
|
-
console.log("Wiping components 3");
|
|
492
490
|
editContextRef.current?.requestRefresh("immediate");
|
|
493
491
|
await waitForPageLoaded();
|
|
494
|
-
console.log("
|
|
492
|
+
console.log("Page loaded after wipe");
|
|
495
493
|
}
|
|
496
494
|
|
|
497
495
|
// Parse schema if it's a string
|
|
@@ -509,11 +507,11 @@ export function ContentStep({
|
|
|
509
507
|
const localAbortController = new AbortController();
|
|
510
508
|
setAbortController(localAbortController);
|
|
511
509
|
|
|
512
|
-
// Get the existing page model
|
|
513
|
-
const existingPageModel = await convertToAiPageModel(
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
);
|
|
510
|
+
// Get the existing page model; TODO make optional
|
|
511
|
+
const existingPageModel = undefined; // await convertToAiPageModel(
|
|
512
|
+
//editContextRef.current?.page!,
|
|
513
|
+
//editContextRef.current!,
|
|
514
|
+
//);
|
|
517
515
|
|
|
518
516
|
console.log("Existing page model: ", existingPageModel);
|
|
519
517
|
|
|
@@ -525,7 +523,7 @@ export function ContentStep({
|
|
|
525
523
|
Generate a descriptive name for each component including the topic.
|
|
526
524
|
Only use component types that are in the page schema.
|
|
527
525
|
Keep existing components with their ids. Leave id field empty for new components.
|
|
528
|
-
Existing page model: ${JSON.stringify(existingPageModel)}
|
|
526
|
+
${existingPageModel && `Existing page model: ${JSON.stringify(existingPageModel)}`}
|
|
529
527
|
Fill empty fields of existing components before you insert new components.
|
|
530
528
|
Component types: ${JSON.stringify(
|
|
531
529
|
filteredSchema,
|
|
@@ -15,7 +15,7 @@ type WizardSchemaComponentAccumulator = {
|
|
|
15
15
|
|
|
16
16
|
export function convertPageSchemaToWizardComponents(
|
|
17
17
|
pageSchema: PageSchema,
|
|
18
|
-
whitelist: string[]
|
|
18
|
+
whitelist: string[],
|
|
19
19
|
): WizardSchemaComponent[] {
|
|
20
20
|
const componentMap = new Map<string, WizardSchemaComponentAccumulator>();
|
|
21
21
|
|
|
@@ -31,7 +31,7 @@ export function convertPageSchemaToWizardComponents(
|
|
|
31
31
|
component: SchemaComponent,
|
|
32
32
|
parentPlaceholder: string,
|
|
33
33
|
isRoot: boolean,
|
|
34
|
-
parentAccumulator?: WizardSchemaComponentAccumulator
|
|
34
|
+
parentAccumulator?: WizardSchemaComponentAccumulator,
|
|
35
35
|
): void {
|
|
36
36
|
const isAllowed = whitelist.includes(component.type);
|
|
37
37
|
let currentAccumulator: WizardSchemaComponentAccumulator | undefined =
|
|
@@ -86,13 +86,16 @@ export function convertPageSchemaToWizardComponents(
|
|
|
86
86
|
const wizardComponent: WizardSchemaComponent = {
|
|
87
87
|
type: acc.type,
|
|
88
88
|
fields: acc.fields,
|
|
89
|
-
allowedChildrenComponentTypes:
|
|
89
|
+
allowedChildrenComponentTypes:
|
|
90
|
+
acc.validChildComponentTypes.size > 0
|
|
91
|
+
? Array.from(acc.validChildComponentTypes)
|
|
92
|
+
: undefined,
|
|
90
93
|
allowedOnRoot: acc.allowedOnRoot,
|
|
91
94
|
};
|
|
92
95
|
// Only include validParentPlaceholders if there is more than one.
|
|
93
96
|
if (acc.validParentPlaceholders.size > 1) {
|
|
94
|
-
wizardComponent.
|
|
95
|
-
acc.validParentPlaceholders
|
|
97
|
+
wizardComponent.validParentPlaceholders = Array.from(
|
|
98
|
+
acc.validParentPlaceholders,
|
|
96
99
|
);
|
|
97
100
|
}
|
|
98
101
|
wizardComponents.push(wizardComponent);
|
|
@@ -114,7 +117,7 @@ export function convertPageSchemaToWizardComponents(
|
|
|
114
117
|
export function getPlaceholder(
|
|
115
118
|
schema: PageSchema,
|
|
116
119
|
parentComponentType: string,
|
|
117
|
-
childComponentType: string
|
|
120
|
+
childComponentType: string,
|
|
118
121
|
): string | undefined {
|
|
119
122
|
// Check for the special case where we want to place at the root level.
|
|
120
123
|
if (parentComponentType.toLowerCase() === "root") {
|
|
@@ -145,7 +148,7 @@ export function getPlaceholder(
|
|
|
145
148
|
for (const placeholder of component.placeholders) {
|
|
146
149
|
if (
|
|
147
150
|
placeholder.components.some(
|
|
148
|
-
(child) => child.type === childComponentType
|
|
151
|
+
(child) => child.type === childComponentType,
|
|
149
152
|
)
|
|
150
153
|
) {
|
|
151
154
|
return placeholder.name;
|
package/src/revision.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = "1.0.
|
|
2
|
-
export const buildDate = "2025-07-10
|
|
1
|
+
export const version = "1.0.3995";
|
|
2
|
+
export const buildDate = "2025-07-12 10:36:17";
|
|
@@ -24,6 +24,7 @@ import { CardConnector } from "../components/ui/CardConnector";
|
|
|
24
24
|
import { Logo } from "../editor/ui/Icons";
|
|
25
25
|
import { ActionButton } from "../components/ActionButton";
|
|
26
26
|
import { FilePenLine, Palette } from "lucide-react";
|
|
27
|
+
import { toast } from "sonner";
|
|
27
28
|
|
|
28
29
|
export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
|
|
29
30
|
const [selectedItem, setSelectedItem] = useState<ItemDescriptor | null>(null);
|
|
@@ -126,11 +127,7 @@ export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
|
|
|
126
127
|
editContext?.switchView("page-editor");
|
|
127
128
|
if (result.data) editContext?.loadItem(result.data);
|
|
128
129
|
} else {
|
|
129
|
-
|
|
130
|
-
severity: "error",
|
|
131
|
-
summary: "Error",
|
|
132
|
-
detail: "Failed to create item",
|
|
133
|
-
});
|
|
130
|
+
toast.error("Failed to create item");
|
|
134
131
|
}
|
|
135
132
|
};
|
|
136
133
|
|
|
@@ -167,26 +164,33 @@ export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
|
|
|
167
164
|
Open Existing
|
|
168
165
|
</ActionButton>
|
|
169
166
|
</div>
|
|
170
|
-
</div>
|
|
171
|
-
<div className="flex flex-1 flex-col md:flex-row">
|
|
172
|
-
|
|
173
|
-
|
|
167
|
+
</div>
|
|
168
|
+
<div className="flex flex-1 flex-col md:flex-row">
|
|
169
|
+
{" "}
|
|
170
|
+
<div
|
|
171
|
+
className={`tour-pick-location w-full md:w-1/2 ${
|
|
172
|
+
selectedItem ? "h-full md:h-full" : ""
|
|
173
|
+
}`}
|
|
174
|
+
>
|
|
175
|
+
<Card
|
|
174
176
|
icon={<i className="pi pi-map-marker text-sm"></i>}
|
|
175
177
|
title="Pick Location"
|
|
176
178
|
description="Select where to create your new page"
|
|
177
179
|
noPadding
|
|
178
|
-
className={selectedItem ?
|
|
180
|
+
className={selectedItem ? "h-full" : "h-auto"}
|
|
179
181
|
>
|
|
180
|
-
<div
|
|
181
|
-
selectedItem ?
|
|
182
|
-
|
|
183
|
-
<div className={`relative ${
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
182
|
+
<div
|
|
183
|
+
className={`px-4 pb-4 md:px-6 ${selectedItem ? "h-full" : ""}`}
|
|
184
|
+
>
|
|
185
|
+
<div className={`relative ${selectedItem ? "h-full" : ""}`}>
|
|
186
|
+
{" "}
|
|
187
|
+
<div
|
|
188
|
+
className={`overflow-auto ${
|
|
189
|
+
selectedItem
|
|
190
|
+
? "absolute inset-0"
|
|
191
|
+
: "min-h-[300px] md:min-h-[400px]"
|
|
192
|
+
}`}
|
|
193
|
+
>
|
|
190
194
|
<ScrollingContentTree
|
|
191
195
|
selectedItemId={selectedItem?.id || selectedItemId}
|
|
192
196
|
onSelectionChange={(selection) => {
|
|
@@ -199,13 +203,11 @@ export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
|
|
|
199
203
|
</div>
|
|
200
204
|
</Card>
|
|
201
205
|
</div>
|
|
202
|
-
|
|
203
206
|
{/* Card Connector - only visible when location is selected */}
|
|
204
207
|
{selectedItem && <CardConnector />}
|
|
205
|
-
|
|
206
208
|
{/* Second card - only visible when location is selected */}
|
|
207
209
|
{selectedItem && (
|
|
208
|
-
<div className="flex w-full flex-col
|
|
210
|
+
<div className="flex h-auto w-full flex-col md:w-1/2">
|
|
209
211
|
<Card
|
|
210
212
|
icon={<Palette className="h-4 w-4" />}
|
|
211
213
|
title="Choose Template or Wizard"
|
|
@@ -228,7 +230,9 @@ export function NewPage({ selectedItemId }: { selectedItemId?: string }) {
|
|
|
228
230
|
? "bg-theme-secondary-light border-theme-secondary"
|
|
229
231
|
: "bg-white",
|
|
230
232
|
)}
|
|
231
|
-
>
|
|
233
|
+
>
|
|
234
|
+
{" "}
|
|
235
|
+
{
|
|
232
236
|
<img
|
|
233
237
|
src={getAbsoluteIconUrl(option.icon)}
|
|
234
238
|
alt={option.name}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { Copy } from "lucide-react";
|
|
4
|
-
import { useEditContext } from "../client/editContext";
|
|
5
|
-
export function CopyToClipboardButton({ text }) {
|
|
6
|
-
const editContext = useEditContext();
|
|
7
|
-
const handleCopyToClipboard = (text) => {
|
|
8
|
-
navigator.clipboard.writeText(text);
|
|
9
|
-
editContext.showToast({
|
|
10
|
-
summary: "Copied to clipboard",
|
|
11
|
-
severity: "success",
|
|
12
|
-
});
|
|
13
|
-
};
|
|
14
|
-
return (_jsx("span", { className: "cursor-pointer", onClick: () => handleCopyToClipboard(text), children: _jsx(Copy, { size: 14, strokeWidth: 1 }) }));
|
|
15
|
-
}
|
|
16
|
-
//# sourceMappingURL=CopyToClipboardButton.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CopyToClipboardButton.js","sourceRoot":"","sources":["../../../src/editor/ui/CopyToClipboardButton.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,UAAU,qBAAqB,CAAC,EAAE,IAAI,EAAoB;IAC9D,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,qBAAqB,GAAG,CAAC,IAAY,EAAE,EAAE;QAC7C,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACpC,WAAY,CAAC,SAAS,CAAC;YACrB,OAAO,EAAE,qBAAqB;YAC9B,QAAQ,EAAE,SAAS;SACpB,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO,CACL,eACE,SAAS,EAAC,gBAAgB,EAC1B,OAAO,EAAE,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,YAE1C,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,GAAI,GAC7B,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { Copy } from "lucide-react";
|
|
4
|
-
import { useEditContext } from "../client/editContext";
|
|
5
|
-
|
|
6
|
-
export function CopyToClipboardButton({ text }: { text: string }) {
|
|
7
|
-
const editContext = useEditContext();
|
|
8
|
-
const handleCopyToClipboard = (text: string) => {
|
|
9
|
-
navigator.clipboard.writeText(text);
|
|
10
|
-
editContext!.showToast({
|
|
11
|
-
summary: "Copied to clipboard",
|
|
12
|
-
severity: "success",
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<span
|
|
18
|
-
className="cursor-pointer"
|
|
19
|
-
onClick={() => handleCopyToClipboard(text)}
|
|
20
|
-
>
|
|
21
|
-
<Copy size={14} strokeWidth={1} />
|
|
22
|
-
</span>
|
|
23
|
-
);
|
|
24
|
-
}
|