@alpaca-headless/alpaca-headless-nextjs 0.0.4 → 1.0.13
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/cjs/components/Image.js +36 -0
- package/dist/cjs/components/Link.js +22 -0
- package/dist/cjs/components/Picture.js +119 -0
- package/dist/cjs/components/PictureEditor.js +43 -0
- package/dist/cjs/components/Placeholder.js +40 -4
- package/dist/cjs/components/RichText.js +44 -0
- package/dist/cjs/components/RichTextEditor.js +82 -0
- package/dist/cjs/components/Slot.js +8 -0
- package/dist/cjs/components/Text.js +24 -4
- package/dist/cjs/components/TextEditor.js +68 -0
- package/dist/cjs/components/Translate.js +14 -0
- package/dist/cjs/components/index.js +5 -0
- package/dist/cjs/editor/AiTerminal.js +150 -0
- package/dist/cjs/editor/ComponentInfo.js +14 -0
- package/dist/cjs/editor/ComponentPalette.js +78 -0
- package/dist/cjs/editor/ComponentTree.js +200 -0
- package/dist/cjs/editor/ContentTree.js +120 -0
- package/dist/cjs/editor/Debug.js +16 -0
- package/dist/cjs/editor/DictionaryEditor.js +35 -0
- package/dist/cjs/editor/EditFrame.js +61 -0
- package/dist/cjs/editor/EditHistory.js +30 -0
- package/dist/cjs/editor/Editor.js +27 -0
- package/dist/cjs/editor/EditorClient.js +457 -0
- package/dist/cjs/editor/EditorClientHost.js +37 -0
- package/dist/cjs/editor/FieldList.js +59 -0
- package/dist/cjs/editor/GraphQL.js +90 -0
- package/dist/cjs/editor/LanguageSelector.js +21 -0
- package/dist/cjs/editor/MediaSelector.js +61 -0
- package/dist/cjs/editor/PageInfo.js +12 -0
- package/dist/cjs/editor/PlaceholderDropZone.js +54 -0
- package/dist/cjs/editor/PlaceholderDropZoneHost.js +37 -0
- package/dist/cjs/editor/Terminal.js +51 -0
- package/dist/cjs/editor/TranslateEditor.js +25 -0
- package/dist/cjs/editor/VersionSelector.js +21 -0
- package/dist/cjs/editor/componentTreeHelper.js +18 -0
- package/dist/cjs/editor/contentService.js +38 -0
- package/dist/cjs/editor/editContext.js +35 -0
- package/dist/cjs/editor/editService.js +150 -0
- package/dist/cjs/editor/fieldTypes/RichTextEditor.js +19 -0
- package/dist/cjs/editor/fieldTypes/SingleLineText.js +17 -0
- package/dist/cjs/editor/index.js +18 -0
- package/dist/cjs/graphQLTypes.js +2 -0
- package/dist/cjs/index.js +15 -0
- package/dist/cjs/loadRouteData.js +98 -40
- package/dist/cjs/mediaProtection.js +56 -0
- package/dist/editor.css +120 -0
- package/dist/esm/components/Image.js +32 -0
- package/dist/esm/components/Link.js +18 -0
- package/dist/esm/components/Picture.js +115 -0
- package/dist/esm/components/PictureEditor.js +39 -0
- package/dist/esm/components/Placeholder.js +38 -5
- package/dist/esm/components/RichText.js +37 -0
- package/dist/esm/components/RichTextEditor.js +55 -0
- package/dist/esm/components/Slot.js +5 -0
- package/dist/esm/components/Text.js +24 -4
- package/dist/esm/components/TextEditor.js +41 -0
- package/dist/esm/components/Translate.js +10 -0
- package/dist/esm/components/index.js +5 -0
- package/dist/esm/editor/AiTerminal.js +146 -0
- package/dist/esm/editor/ComponentInfo.js +10 -0
- package/dist/esm/editor/ComponentPalette.js +71 -0
- package/dist/esm/editor/ComponentTree.js +196 -0
- package/dist/esm/editor/ContentTree.js +117 -0
- package/dist/esm/editor/Debug.js +9 -0
- package/dist/esm/editor/DictionaryEditor.js +31 -0
- package/dist/esm/editor/EditFrame.js +57 -0
- package/dist/esm/editor/EditHistory.js +26 -0
- package/dist/esm/editor/Editor.js +23 -0
- package/dist/esm/editor/EditorClient.js +450 -0
- package/dist/esm/editor/EditorClientHost.js +7 -0
- package/dist/esm/editor/FieldList.js +55 -0
- package/dist/esm/editor/GraphQL.js +83 -0
- package/dist/esm/editor/LanguageSelector.js +17 -0
- package/dist/esm/editor/MediaSelector.js +54 -0
- package/dist/esm/editor/PageInfo.js +8 -0
- package/dist/esm/editor/PlaceholderDropZone.js +50 -0
- package/dist/esm/editor/PlaceholderDropZoneHost.js +7 -0
- package/dist/esm/editor/Terminal.js +47 -0
- package/dist/esm/editor/TranslateEditor.js +21 -0
- package/dist/esm/editor/VersionSelector.js +17 -0
- package/dist/esm/editor/componentTreeHelper.js +14 -0
- package/dist/esm/editor/contentService.js +31 -0
- package/dist/esm/editor/editContext.js +5 -0
- package/dist/esm/editor/editService.js +139 -0
- package/dist/esm/editor/fieldTypes/RichTextEditor.js +15 -0
- package/dist/esm/editor/fieldTypes/SingleLineText.js +13 -0
- package/dist/esm/editor/index.js +2 -0
- package/dist/esm/graphQLTypes.js +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/loadRouteData.js +97 -39
- package/dist/esm/mediaProtection.js +49 -0
- package/package.json +16 -4
- package/types/alpacaContext.d.ts +11 -0
- package/types/components/Image.d.ts +10 -0
- package/types/components/Link.d.ts +6 -0
- package/types/components/Picture.d.ts +20 -0
- package/types/components/PictureEditor.d.ts +3 -0
- package/types/components/RichText.d.ts +7 -0
- package/types/components/RichTextEditor.d.ts +296 -0
- package/types/components/Slot.d.ts +4 -0
- package/types/components/Text.d.ts +3 -2
- package/types/components/TextEditor.d.ts +296 -0
- package/types/components/Translate.d.ts +3 -0
- package/types/components/index.d.ts +5 -0
- package/types/editor/AiTerminal.d.ts +4 -0
- package/types/editor/ComponentInfo.d.ts +4 -0
- package/types/editor/ComponentPalette.d.ts +7 -0
- package/types/editor/ComponentTree.d.ts +5 -0
- package/types/editor/ContentTree.d.ts +13 -0
- package/types/editor/Debug.d.ts +6 -0
- package/types/editor/DictionaryEditor.d.ts +3 -0
- package/types/editor/EditFrame.d.ts +6 -0
- package/types/editor/EditHistory.d.ts +4 -0
- package/types/editor/Editor.d.ts +6 -0
- package/types/editor/EditorClient.d.ts +9 -0
- package/types/editor/EditorClientHost.d.ts +8 -0
- package/types/editor/FieldList.d.ts +4 -0
- package/types/editor/GraphQL.d.ts +5 -0
- package/types/editor/LanguageSelector.d.ts +5 -0
- package/types/editor/MediaSelector.d.ts +5 -0
- package/types/editor/PageInfo.d.ts +4 -0
- package/types/editor/PlaceholderDropZone.d.ts +6 -0
- package/types/editor/PlaceholderDropZoneHost.d.ts +6 -0
- package/types/editor/Terminal.d.ts +4 -0
- package/types/editor/TranslateEditor.d.ts +3 -0
- package/types/editor/VersionSelector.d.ts +5 -0
- package/types/editor/componentTreeHelper.d.ts +2 -0
- package/types/editor/contentService.d.ts +14 -0
- package/types/editor/editContext.d.ts +81 -0
- package/types/editor/editService.d.ts +12 -0
- package/types/editor/fieldTypes/RichTextEditor.d.ts +4 -0
- package/types/editor/fieldTypes/SingleLineText.d.ts +4 -0
- package/types/editor/index.d.ts +2 -0
- package/types/fieldTypes.d.ts +63 -1
- package/types/graphQLTypes.d.ts +24 -0
- package/types/index.d.ts +2 -0
- package/types/layoutData.d.ts +56 -1
- package/types/loadRouteData.d.ts +30 -1
- package/types/mediaProtection.d.ts +2 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
export function PageInfo({ page }) {
|
|
4
|
+
var _a;
|
|
5
|
+
if (!(page === null || page === void 0 ? void 0 : page.fields))
|
|
6
|
+
return;
|
|
7
|
+
return (_jsxs("div", { className: "p-1", children: [_jsx("h2", { className: "text-xl font-bold my-2", children: page.path }), _jsxs("div", { className: "text-xs", children: ["ID: ", page.id] }), _jsxs("div", { className: "text-xs", children: ["Language: ", page.language] }), _jsxs("div", { className: "text-xs", children: ["Version: ", page.version] }), page.translations && (_jsxs("div", { className: "text-xs", children: ["Languages: ", (_a = page.translations) === null || _a === void 0 ? void 0 : _a.join(", ")] }))] }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { ProgressBar } from "primereact/progressbar";
|
|
5
|
+
import { useEditContext } from "..";
|
|
6
|
+
export function PlaceholderDropZone({ placeholder, index, parentName, }) {
|
|
7
|
+
const [isInserting, setIsInserting] = useState(false);
|
|
8
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
9
|
+
const editContext = useEditContext();
|
|
10
|
+
if (!editContext)
|
|
11
|
+
return;
|
|
12
|
+
const { selection, refreshCompletedFlag, dragObject, selectedForInsertion } = editContext;
|
|
13
|
+
function isAnyPlaceholderSelected() {
|
|
14
|
+
return selection.find((x) => x.indexOf("_") > 0) != undefined;
|
|
15
|
+
}
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
setIsInserting(false);
|
|
18
|
+
}, [refreshCompletedFlag]);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
var _a;
|
|
21
|
+
const isSelectedForInsertion = editContext.selectedForInsertion.length > 0 &&
|
|
22
|
+
placeholder.key.indexOf(editContext.selectedForInsertion) >= 0;
|
|
23
|
+
const dragObjectAllowed = (editContext.dragObject ? true : false) &&
|
|
24
|
+
((_a = placeholder.insertOptions) === null || _a === void 0 ? void 0 : _a.find((x) => { var _a; return x.id == ((_a = editContext.dragObject) === null || _a === void 0 ? void 0 : _a.templateId); })) != undefined;
|
|
25
|
+
const selected = (isSelectedForInsertion ||
|
|
26
|
+
(!isAnyPlaceholderSelected() && editContext.dragObject != undefined)) &&
|
|
27
|
+
(!editContext.dragObject ? true : false || dragObjectAllowed);
|
|
28
|
+
setIsSelected(selected);
|
|
29
|
+
}, [selection, dragObject, selectedForInsertion, editContext]);
|
|
30
|
+
function dragOver(ev) {
|
|
31
|
+
var _a;
|
|
32
|
+
ev.dataTransfer.dropEffect =
|
|
33
|
+
((_a = editContext === null || editContext === void 0 ? void 0 : editContext.dragObject) === null || _a === void 0 ? void 0 : _a.type) == "template" ? "copy" : "move";
|
|
34
|
+
ev.preventDefault();
|
|
35
|
+
}
|
|
36
|
+
function drop(ev) {
|
|
37
|
+
ev.preventDefault();
|
|
38
|
+
setIsInserting(true);
|
|
39
|
+
editContext.droppedInPlaceholder(placeholder.key, index);
|
|
40
|
+
}
|
|
41
|
+
if (isInserting)
|
|
42
|
+
return (_jsx("div", { className: " bg-gray-200 p-10", children: _jsx(ProgressBar, { mode: "indeterminate", style: { height: "6px" } }) }));
|
|
43
|
+
return (_jsx("div", { onClick: (ev) => {
|
|
44
|
+
// editContext.setSelectedForInsertion(placeholder.key + "_" + index);
|
|
45
|
+
editContext.openComponentPalette();
|
|
46
|
+
ev.stopPropagation();
|
|
47
|
+
}, onDragOver: dragOver, onDrop: drop,
|
|
48
|
+
// ref={setNodeRef}
|
|
49
|
+
className: `ape-placeholder ${isSelected ? "" : "ape-hidden"}`, children: _jsx("div", { className: "p-6 max-w-sm mx-auto bg-white rounded-xl shadow-md flex items-center space-x-4", children: _jsxs("div", { children: [_jsxs("div", { className: "text-xl font-medium text-black", children: ["Placeholder ", parentName, " / ", placeholder.name, " ", index] }), _jsx("p", { className: "text-gray-500", children: "You can add your components here." })] }) }) }));
|
|
50
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import dynamic from "next/dynamic";
|
|
4
|
+
const PlaceholderDropZone = dynamic(() => import("./PlaceholderDropZone").then((dnd) => dnd.PlaceholderDropZone), { ssr: false });
|
|
5
|
+
export function PlaceholderDropZoneHost({ placeholder, index, parentName, }) {
|
|
6
|
+
return (_jsx(PlaceholderDropZone, { placeholder: placeholder, index: index, parentName: parentName }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { InputTextarea } from "primereact/inputtextarea";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
export function Terminal({ commandHandler, onReset, }) {
|
|
6
|
+
const [value, setValue] = useState("");
|
|
7
|
+
const [response, setResponse] = useState();
|
|
8
|
+
const [messages, setMessages] = useState([]);
|
|
9
|
+
const bottomRef = useRef(null);
|
|
10
|
+
const messageRef = useRef(messages);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
messageRef.current = messages;
|
|
13
|
+
}, [messages]);
|
|
14
|
+
const callback = (text, finished) => {
|
|
15
|
+
if (!finished)
|
|
16
|
+
setResponse(text);
|
|
17
|
+
else {
|
|
18
|
+
setResponse(undefined);
|
|
19
|
+
setMessages([...messageRef.current, { type: "response", text }]);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const handleKeyPress = (e) => {
|
|
23
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
24
|
+
e.preventDefault(); // Prevent newline insertion
|
|
25
|
+
setMessages([...messages, { type: "command", text: value }]);
|
|
26
|
+
setValue("");
|
|
27
|
+
setResponse("...");
|
|
28
|
+
commandHandler(value, callback);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
var _a;
|
|
33
|
+
// 👇️ scroll to bottom every time messages change
|
|
34
|
+
(_a = bottomRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
|
|
35
|
+
}, [messages, response]);
|
|
36
|
+
const getClasses = (m) => {
|
|
37
|
+
if (m.type === "response")
|
|
38
|
+
return "text-blue-500";
|
|
39
|
+
return "";
|
|
40
|
+
};
|
|
41
|
+
return (_jsxs("div", { className: "flex flex-col h-full", children: [_jsx("div", { className: "p-4 border-b border-gray-200", children: _jsx("button", { onClick: () => {
|
|
42
|
+
setMessages([]);
|
|
43
|
+
onReset();
|
|
44
|
+
}, children: _jsx("i", { className: "pi pi-trash" }) }) }), _jsxs("div", { className: "overflow-y-auto h-full overflow-x-hidden p-2", children: [messages.map((m, i) => (_jsx("div", { className: getClasses(m), children: m.text }, i))), response != null && (_jsxs("div", { className: "flex", children: [_jsxs("div", { className: "text-xs", children: [" ", _jsx("i", { className: "pi pi-spin pi-spinner" })] }), _jsx("div", { dangerouslySetInnerHTML: {
|
|
45
|
+
__html: response.replaceAll("\\n", "<br>"),
|
|
46
|
+
} })] })), _jsx("div", { ref: bottomRef })] }), _jsx(InputTextarea, { value: value, className: "border-0 border-t-2 rounded-none", onKeyDown: handleKeyPress, onChange: (e) => setValue(e.target.value), rows: 5, cols: 30 })] }));
|
|
47
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import { useEditContext } from "..";
|
|
5
|
+
export function TranslateEditor({ text }) {
|
|
6
|
+
const context = useEditContext();
|
|
7
|
+
if (!context || !context.dictionary)
|
|
8
|
+
return text;
|
|
9
|
+
const dictionary = context.dictionary;
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (Object.keys(dictionary).indexOf(text) < 0 &&
|
|
12
|
+
context.unresolvedDictionaryKeys.indexOf(text) < 0) {
|
|
13
|
+
console.log("Pushing...");
|
|
14
|
+
context.setUnresolvedDictionaryKeys([
|
|
15
|
+
...context.unresolvedDictionaryKeys,
|
|
16
|
+
text,
|
|
17
|
+
]);
|
|
18
|
+
}
|
|
19
|
+
}, []);
|
|
20
|
+
return (dictionary[text] || _jsx("span", { className: "p-1 ring-2 ring-red-500", children: text }));
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Dropdown } from "primereact/dropdown";
|
|
4
|
+
export function VersionSelector({ page, onVersionSelected, }) {
|
|
5
|
+
if (page == null)
|
|
6
|
+
return;
|
|
7
|
+
const selectedVersionTemplate = (option, props) => {
|
|
8
|
+
if (option) {
|
|
9
|
+
return _jsx("div", { children: option.version });
|
|
10
|
+
}
|
|
11
|
+
return _jsx("span", { children: props.placeholder });
|
|
12
|
+
};
|
|
13
|
+
const versionOptionTemplate = (option) => {
|
|
14
|
+
return (_jsxs("div", { children: [option.version, " ", _jsxs("div", { className: "text-xs", children: ["(", option.updated.toString(), " by ", option.updatedBy, ")"] })] }));
|
|
15
|
+
};
|
|
16
|
+
return (_jsx(_Fragment, { children: _jsx(Dropdown, { value: page.version, onChange: (e) => onVersionSelected(e.value), options: page.versions, optionValue: "version", optionLabel: "version", placeholder: "Select a version", valueTemplate: selectedVersionTemplate, itemTemplate: versionOptionTemplate }) }));
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function findComponent(id, placeholders) {
|
|
2
|
+
for (const p of placeholders) {
|
|
3
|
+
for (const c of p.components) {
|
|
4
|
+
if (c.id == id) {
|
|
5
|
+
return c;
|
|
6
|
+
}
|
|
7
|
+
const match = findComponent(id, c.placeholders);
|
|
8
|
+
if (match) {
|
|
9
|
+
return match;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import Cookies from "universal-cookie";
|
|
11
|
+
export function getChildren(itemId, sessionId, templateIds = []) {
|
|
12
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
13
|
+
let url = "/alpaca/headless/editor/children?itemId=" +
|
|
14
|
+
itemId +
|
|
15
|
+
"&sessionId=" +
|
|
16
|
+
sessionId;
|
|
17
|
+
url = templateIds.reduce((u, t) => u + "&templateIds=" + t, url);
|
|
18
|
+
const response = yield fetch(url, {
|
|
19
|
+
method: "GET",
|
|
20
|
+
credentials: "include",
|
|
21
|
+
headers: {
|
|
22
|
+
"Content-Type": "application/json",
|
|
23
|
+
Cookie: new Cookies().getAll(),
|
|
24
|
+
},
|
|
25
|
+
next: {
|
|
26
|
+
revalidate: 0,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
return yield response.json();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import Cookies from "universal-cookie";
|
|
11
|
+
export let currentOperation = undefined;
|
|
12
|
+
export function setCurrentOperation(operation) {
|
|
13
|
+
currentOperation = operation;
|
|
14
|
+
}
|
|
15
|
+
export function executeEditOperation(editOperation, sessionId) {
|
|
16
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
const response = yield fetch("/alpaca/headless/editor/edit?sessionId=" + sessionId, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
body: JSON.stringify(editOperation),
|
|
20
|
+
credentials: "include",
|
|
21
|
+
headers: {
|
|
22
|
+
"Content-Type": "application/json",
|
|
23
|
+
Cookie: new Cookies().getAll(),
|
|
24
|
+
},
|
|
25
|
+
next: {
|
|
26
|
+
revalidate: 0,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
if (response.status === 500 || response.redirected) {
|
|
30
|
+
return {
|
|
31
|
+
type: "error",
|
|
32
|
+
summary: "Error",
|
|
33
|
+
details: "An error occured while saving changes.",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (response.status === 401) {
|
|
37
|
+
return {
|
|
38
|
+
type: "unauthenticated",
|
|
39
|
+
summary: "Unauthorized",
|
|
40
|
+
details: "Not logged in anymore?",
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return yield response.json();
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export function executeUndo(sessionId) {
|
|
47
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
const response = yield fetch("/alpaca/headless/editor/undo?sessionId=" + sessionId, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
body: "",
|
|
51
|
+
credentials: "include",
|
|
52
|
+
headers: {
|
|
53
|
+
"Content-Type": "application/json",
|
|
54
|
+
Cookie: new Cookies().getAll(),
|
|
55
|
+
},
|
|
56
|
+
next: {
|
|
57
|
+
revalidate: 0,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
if (response.status === 500 || response.redirected) {
|
|
61
|
+
return {
|
|
62
|
+
type: "error",
|
|
63
|
+
summary: "Error",
|
|
64
|
+
details: "An error occured while saving changes.",
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (response.status === 401) {
|
|
68
|
+
return {
|
|
69
|
+
type: "error",
|
|
70
|
+
summary: "Unauthorized",
|
|
71
|
+
details: "Not logged in anymore?",
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { type: "success" };
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export function executeRedo(sessionId) {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
const response = yield fetch("/alpaca/headless/editor/redo?sessionId=" + sessionId, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
body: "",
|
|
82
|
+
credentials: "include",
|
|
83
|
+
headers: {
|
|
84
|
+
"Content-Type": "application/json",
|
|
85
|
+
Cookie: new Cookies().getAll(),
|
|
86
|
+
},
|
|
87
|
+
next: {
|
|
88
|
+
revalidate: 0,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
if (response.status === 500 || response.redirected) {
|
|
92
|
+
return {
|
|
93
|
+
type: "error",
|
|
94
|
+
summary: "Error",
|
|
95
|
+
details: "An error occured while saving changes.",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (response.status === 401) {
|
|
99
|
+
return {
|
|
100
|
+
type: "error",
|
|
101
|
+
summary: "Unauthorized",
|
|
102
|
+
details: "Not logged in anymore?",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return { type: "success" };
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
export function commitChanges(sessionId) {
|
|
109
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
110
|
+
const response = yield fetch("/alpaca/headless/editor/commit?sessionId=" + sessionId, {
|
|
111
|
+
method: "POST",
|
|
112
|
+
body: "",
|
|
113
|
+
credentials: "include",
|
|
114
|
+
headers: {
|
|
115
|
+
"Content-Type": "application/json",
|
|
116
|
+
Cookie: new Cookies().getAll(),
|
|
117
|
+
},
|
|
118
|
+
next: {
|
|
119
|
+
revalidate: 0,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
if (response.ok)
|
|
123
|
+
return { type: "success" };
|
|
124
|
+
else {
|
|
125
|
+
if (response.status === 401) {
|
|
126
|
+
return {
|
|
127
|
+
type: "error",
|
|
128
|
+
summary: "Unauthorized",
|
|
129
|
+
details: "Not logged in anymore?",
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
type: "error",
|
|
134
|
+
summary: "Error",
|
|
135
|
+
details: "An error occured while saving changes.",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEditContext } from "../..";
|
|
4
|
+
import { Editor } from "primereact/editor";
|
|
5
|
+
export function RichTextEditor({ field }) {
|
|
6
|
+
const editContext = useEditContext();
|
|
7
|
+
if (!editContext)
|
|
8
|
+
return;
|
|
9
|
+
return (_jsx(Editor, { value: field.value, style: { width: "100%" }, onTextChange: (e) => {
|
|
10
|
+
var _a;
|
|
11
|
+
// console.log("Text change: " + field.itemId);
|
|
12
|
+
editContext.editField(field, (_a = e.htmlValue) !== null && _a !== void 0 ? _a : "", true);
|
|
13
|
+
field.value = e.htmlValue;
|
|
14
|
+
} }, field.itemId + field.id + field.language + field.version));
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEditContext } from "../..";
|
|
4
|
+
import { InputText } from "primereact/inputtext";
|
|
5
|
+
export function SingleLineText({ field }) {
|
|
6
|
+
const editContext = useEditContext();
|
|
7
|
+
if (!editContext)
|
|
8
|
+
return;
|
|
9
|
+
return (_jsx(InputText, { value: field.value, style: { width: "100%" }, onChange: (e) => {
|
|
10
|
+
editContext.editField(field, e.target.value, false);
|
|
11
|
+
field.value = e.target.value;
|
|
12
|
+
} }, field.itemId + field.id + field.language + field.version));
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/esm/index.js
CHANGED
|
@@ -9,57 +9,115 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { useAlpacaContext } from "./alpacaContext";
|
|
11
11
|
import { cookies } from "next/headers";
|
|
12
|
+
import { cache } from "react";
|
|
13
|
+
const fetchRouteData = cache((path, host, mode, itemId, language, session, version) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
+
const request = {
|
|
15
|
+
Path: path,
|
|
16
|
+
Host: host,
|
|
17
|
+
Mode: mode,
|
|
18
|
+
ItemId: itemId,
|
|
19
|
+
Language: language,
|
|
20
|
+
SessionId: session,
|
|
21
|
+
Version: version,
|
|
22
|
+
};
|
|
23
|
+
const url = process.env.LAYOUT_SERVICE_URL +
|
|
24
|
+
"/alpaca/headless/layout?session=" +
|
|
25
|
+
session;
|
|
26
|
+
console.log(`Fetching page layout from ${url}. Host:${request.Host} Path: ${request.Path}`);
|
|
27
|
+
const response = yield fetch(url, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
body: JSON.stringify(request),
|
|
30
|
+
credentials: "include",
|
|
31
|
+
headers: {
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
Cookie: cookies().toString(),
|
|
34
|
+
"x-api-key": getApiKey(),
|
|
35
|
+
},
|
|
36
|
+
next: {
|
|
37
|
+
tags: ["pages"],
|
|
38
|
+
revalidate: mode === "preview" || mode == "edit" ? 0 : 30,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
console.log("STATUS: " + response.status + " mode: " + mode);
|
|
42
|
+
if (response.status === 404) {
|
|
43
|
+
return {
|
|
44
|
+
type: "notfound",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (response.status === 301) {
|
|
48
|
+
return {
|
|
49
|
+
type: "redirect",
|
|
50
|
+
location: response.url,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
const message = yield response.text();
|
|
55
|
+
return {
|
|
56
|
+
type: "error",
|
|
57
|
+
errorCode: response.status,
|
|
58
|
+
message: message,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const data = yield response.json();
|
|
62
|
+
//console.log(JSON.stringify(data, null, 2));
|
|
63
|
+
const context = useAlpacaContext();
|
|
64
|
+
context.pageContext = {
|
|
65
|
+
itemId: data.page.id,
|
|
66
|
+
language: data.page.language,
|
|
67
|
+
site: data.site,
|
|
68
|
+
pageEditing: data.page.editing,
|
|
69
|
+
pageState: "",
|
|
70
|
+
database: data.page.database,
|
|
71
|
+
};
|
|
72
|
+
context.fields = data.page.fields;
|
|
73
|
+
context.edit = data.edit;
|
|
74
|
+
const dictionary = yield loadDictionary(context.pageContext.site.name, context.pageContext.language, mode);
|
|
75
|
+
context.dictionary = dictionary;
|
|
76
|
+
context.translate = (text) => {
|
|
77
|
+
return context.dictionary[text] || text;
|
|
78
|
+
};
|
|
79
|
+
return Object.assign(Object.assign({}, data.page), { type: "page" });
|
|
80
|
+
}));
|
|
12
81
|
export function loadRouteData(params, searchParams, host) {
|
|
13
82
|
var _a, _b;
|
|
14
83
|
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
84
|
+
const result = yield fetchRouteData((_b = (_a = params.path) === null || _a === void 0 ? void 0 : _a.join("/")) !== null && _b !== void 0 ? _b : "/", host, searchParams["mode"] || "normal", searchParams["itemid"], searchParams["language"], searchParams["session"], searchParams["version"]);
|
|
85
|
+
return result;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function loadDictionary(siteName, language, mode) {
|
|
89
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
90
|
+
const url = process.env.LAYOUT_SERVICE_URL +
|
|
91
|
+
"/alpaca/headless/dictionary?siteName=" +
|
|
92
|
+
siteName +
|
|
93
|
+
"&language=" +
|
|
94
|
+
language;
|
|
95
|
+
console.log(`Fetching dictionary from ${url}.`);
|
|
24
96
|
const response = yield fetch(url, {
|
|
25
|
-
method: "
|
|
26
|
-
body: JSON.stringify(request),
|
|
97
|
+
method: "GET",
|
|
27
98
|
credentials: "include",
|
|
28
99
|
headers: {
|
|
29
100
|
"Content-Type": "application/json",
|
|
30
101
|
Cookie: cookies().toString(),
|
|
102
|
+
"x-api-key": getApiKey(),
|
|
103
|
+
},
|
|
104
|
+
next: {
|
|
105
|
+
tags: ["dictionary"],
|
|
106
|
+
revalidate: mode === "preview" || mode == "edit" ? 15 : 600,
|
|
31
107
|
},
|
|
32
|
-
next: { tags: ["pages"], revalidate: 10 },
|
|
33
108
|
});
|
|
34
|
-
if (response.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
if (response.status === 301) {
|
|
40
|
-
return {
|
|
41
|
-
type: "redirect",
|
|
42
|
-
location: response.url,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
if (response.status !== 200) {
|
|
46
|
-
const message = yield response.text();
|
|
47
|
-
return {
|
|
48
|
-
type: "error",
|
|
49
|
-
errorCode: response.status,
|
|
50
|
-
message: message,
|
|
51
|
-
};
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
console.log("Could not load dictionary: Response code: " + response.status);
|
|
111
|
+
return {};
|
|
52
112
|
}
|
|
53
113
|
const data = yield response.json();
|
|
54
114
|
console.log(data);
|
|
55
|
-
|
|
56
|
-
context.pageContext = {
|
|
57
|
-
itemId: data.page.id,
|
|
58
|
-
language: data.page.language,
|
|
59
|
-
site: data.site,
|
|
60
|
-
pageEditing: true,
|
|
61
|
-
pageState: "",
|
|
62
|
-
};
|
|
63
|
-
return Object.assign(Object.assign({}, data.page), { type: "page" });
|
|
115
|
+
return data;
|
|
64
116
|
});
|
|
65
117
|
}
|
|
118
|
+
function getApiKey() {
|
|
119
|
+
const apiKey = process.env.ALPACA_HEADLESS_API_KEY || process.env.API_KEY;
|
|
120
|
+
if (!apiKey)
|
|
121
|
+
console.log("ERROR: Could not find API key environment variable: ALPACA_HEADLESS_API_KEY");
|
|
122
|
+
return apiKey;
|
|
123
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import crypto from "crypto";
|
|
2
|
+
import "url";
|
|
3
|
+
const protectedParams = [
|
|
4
|
+
"w",
|
|
5
|
+
"h",
|
|
6
|
+
"mw",
|
|
7
|
+
"mh",
|
|
8
|
+
"sc",
|
|
9
|
+
"as",
|
|
10
|
+
"bc",
|
|
11
|
+
"db",
|
|
12
|
+
"iar",
|
|
13
|
+
"la",
|
|
14
|
+
"thn",
|
|
15
|
+
"vs",
|
|
16
|
+
"sc_content",
|
|
17
|
+
"sc_lang",
|
|
18
|
+
"sc_site",
|
|
19
|
+
"gray",
|
|
20
|
+
"rev",
|
|
21
|
+
"devicepixelratio",
|
|
22
|
+
"encodequality",
|
|
23
|
+
"rx",
|
|
24
|
+
"ry",
|
|
25
|
+
"rw",
|
|
26
|
+
"rh",
|
|
27
|
+
"crop",
|
|
28
|
+
];
|
|
29
|
+
export function hashImageUrl(url) {
|
|
30
|
+
if (!process.env.MEDIA_REQUESTPROTECTION_SHAREDSECRET)
|
|
31
|
+
return url;
|
|
32
|
+
if (!url)
|
|
33
|
+
return url;
|
|
34
|
+
const baseURL = 'http://temp-base-url.com'; // This will serve as a placeholder.
|
|
35
|
+
const uri = new URL(url.toLowerCase(), baseURL);
|
|
36
|
+
uri.searchParams.delete("hash");
|
|
37
|
+
const searchParams = protectedParams
|
|
38
|
+
.map((x) => ({ name: x, val: uri.searchParams.get(x) }))
|
|
39
|
+
.filter((x) => x.val)
|
|
40
|
+
.map((x) => x.name + "=" + x.val)
|
|
41
|
+
.join("&");
|
|
42
|
+
const stringToProtect = uri.pathname.substring(1) + "?" + searchParams;
|
|
43
|
+
const hash = crypto
|
|
44
|
+
.createHash("md5")
|
|
45
|
+
.update(stringToProtect + process.env.MEDIA_REQUESTPROTECTION_SHAREDSECRET, "utf16le")
|
|
46
|
+
.digest("hex");
|
|
47
|
+
uri.searchParams.set("hash", hash);
|
|
48
|
+
return url.startsWith('http') ? uri.toString() : uri.pathname + uri.search;
|
|
49
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alpaca-headless/alpaca-headless-nextjs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"description": "Alpaca Headless NextJs Integration",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
"dist",
|
|
10
10
|
"types",
|
|
11
11
|
"/*.js",
|
|
12
|
+
"/*.css",
|
|
12
13
|
"/*.d.ts"
|
|
13
14
|
],
|
|
14
15
|
"scripts": {
|
|
15
|
-
"build": "npm run build:cjs && npm run build:esm",
|
|
16
|
+
"build": "npm run build:cjs && npm run build:esm && npm run copy-files",
|
|
16
17
|
"build:cjs": "node tools/cleanup cjs && tsc -p config/tsconfig.cjs.json --noEmit false",
|
|
17
18
|
"build:esm": "node tools/cleanup esm && tsc -p config/tsconfig.esm.json --noEmit false",
|
|
19
|
+
"copy-files": "copyfiles -u 1 -E -V \"src/editor.css\" dist/",
|
|
18
20
|
"clean": "node tools/cleanup",
|
|
19
21
|
"package": "npm run build && npm pack"
|
|
20
22
|
},
|
|
@@ -22,11 +24,21 @@
|
|
|
22
24
|
"license": "MIT",
|
|
23
25
|
"dependencies": {
|
|
24
26
|
"autoprefixer": "10.4.14",
|
|
25
|
-
"
|
|
27
|
+
"copyfiles": "^2.4.1",
|
|
28
|
+
"crypto": "^1.0.1",
|
|
29
|
+
"cryptography": "^1.2.3",
|
|
30
|
+
"graphql-formatter": "^1.0.3",
|
|
31
|
+
"next": "13.5.1",
|
|
26
32
|
"node-cleanup": "^2.1.2",
|
|
33
|
+
"prettier": "^3.0.3",
|
|
34
|
+
"primereact": "^9.6.2",
|
|
35
|
+
"quill": "^1.3.7",
|
|
27
36
|
"react": "18.2.0",
|
|
28
37
|
"react-dom": "18.2.0",
|
|
29
|
-
"
|
|
38
|
+
"react-json-pretty": "^2.2.0",
|
|
39
|
+
"react-uuid": "^2.0.0",
|
|
40
|
+
"server-only": "^0.0.1",
|
|
41
|
+
"universal-cookie": "^6.1.1"
|
|
30
42
|
},
|
|
31
43
|
"devDependencies": {
|
|
32
44
|
"@types/node": "20.4.1",
|