diff --git a/package-lock.json b/package-lock.json
index beeb0ee..d0400e9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -39,6 +39,8 @@
"regenerator-runtime": "^0.13.11",
"rehype-highlight": "^7.0.0",
"rehype-raw": "^7.0.0",
+ "remark": "^15.0.1",
+ "remark-stringify": "^11.0.0",
"shepherd.js": "^13.0.3",
"styled-components": "^6.1.12",
"ts-debounce": "^4.0.0",
@@ -19427,6 +19429,22 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/remark": {
+ "version": "15.0.1",
+ "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz",
+ "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "remark-parse": "^11.0.0",
+ "remark-stringify": "^11.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/remark-parse": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
@@ -19458,6 +19476,21 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/remark-stringify": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz",
+ "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
diff --git a/package.json b/package.json
index a556a24..34162c6 100644
--- a/package.json
+++ b/package.json
@@ -47,6 +47,8 @@
"regenerator-runtime": "^0.13.11",
"rehype-highlight": "^7.0.0",
"rehype-raw": "^7.0.0",
+ "remark": "^15.0.1",
+ "remark-stringify": "^11.0.0",
"shepherd.js": "^13.0.3",
"styled-components": "^6.1.12",
"ts-debounce": "^4.0.0",
diff --git a/src/editors/editorsContainer/AgreementData.tsx b/src/editors/editorsContainer/AgreementData.tsx
index 74d6059..e5a9c6d 100644
--- a/src/editors/editorsContainer/AgreementData.tsx
+++ b/src/editors/editorsContainer/AgreementData.tsx
@@ -1,7 +1,7 @@
+import { FaMagic } from "react-icons/fa";
import JSONEditor from "../JSONEditor";
import useAppStore from "../../store/store";
import useUndoRedo from "../../components/useUndoRedo";
-
import { FaUndo, FaRedo } from "react-icons/fa";
function AgreementData() {
@@ -9,16 +9,27 @@ function AgreementData() {
const editorAgreementData = useAppStore((state) => state.editorAgreementData);
const setEditorAgreementData = useAppStore((state) => state.setEditorAgreementData);
const setData = useAppStore((state) => state.setData);
+
const { value, setValue, undo, redo } = useUndoRedo(
editorAgreementData,
setEditorAgreementData,
- setData // Sync to main state and rebuild
+ setData
);
const handleChange = (value: string | undefined) => {
if (value !== undefined) {
- setValue(value); // Update editor state and sync
- setData(value);
+ setValue(value);
+ setData(value);
+ }
+ };
+
+ const handleFormat = () => {
+ try {
+ const formatted = JSON.stringify(JSON.parse(value), null, 2);
+ setValue(formatted);
+ setEditorAgreementData(formatted);
+ } catch {
+ alert("Invalid JSON format!");
}
};
@@ -27,16 +38,19 @@ function AgreementData() {
-
- JSON data (an instance of the Concerto model) used to preview output from the template.
-
+ JSON data (instance of the Concerto model) for preview output.
);
}
-export default AgreementData;
\ No newline at end of file
+export default AgreementData;
diff --git a/src/editors/editorsContainer/TemplateMarkdown.tsx b/src/editors/editorsContainer/TemplateMarkdown.tsx
index 28e91af..3e87a83 100644
--- a/src/editors/editorsContainer/TemplateMarkdown.tsx
+++ b/src/editors/editorsContainer/TemplateMarkdown.tsx
@@ -1,7 +1,11 @@
+import { FaMagic } from "react-icons/fa";
import MarkdownEditor from "../MarkdownEditor";
import useAppStore from "../../store/store";
import useUndoRedo from "../../components/useUndoRedo";
import { FaUndo, FaRedo } from "react-icons/fa";
+import { remark } from "remark";
+import remarkParse from "remark-parse";
+import remarkStringify from "remark-stringify";
function TemplateMarkdown() {
const textColor = useAppStore((state) => state.textColor);
@@ -9,16 +13,27 @@ function TemplateMarkdown() {
const editorValue = useAppStore((state) => state.editorValue);
const setEditorValue = useAppStore((state) => state.setEditorValue);
const setTemplateMarkdown = useAppStore((state) => state.setTemplateMarkdown);
+
const { value, setValue, undo, redo } = useUndoRedo(
editorValue,
setEditorValue,
- setTemplateMarkdown // Sync to main state and rebuild
+ setTemplateMarkdown
);
const handleChange = (value: string | undefined) => {
if (value !== undefined) {
- setValue(value); // Update editor state and sync
- setTemplateMarkdown(value);
+ setValue(value);
+ setTemplateMarkdown(value);
+ }
+ };
+
+ const handleFormat = async () => {
+ try {
+ const formatted = await remark().use(remarkParse).use(remarkStringify).process(value);
+ setValue(String(formatted));
+ setEditorValue(String(formatted));
+ } catch {
+ alert("Error formatting Markdown!");
}
};
@@ -27,16 +42,19 @@ function TemplateMarkdown() {
-
- A natural language template with embedded variables, conditional sections, and TypeScript code.
-
+ A natural language template with embedded logic.
);
}
-export default TemplateMarkdown;
\ No newline at end of file
+export default TemplateMarkdown;
diff --git a/src/editors/editorsContainer/TemplateModel.tsx b/src/editors/editorsContainer/TemplateModel.tsx
index ca4f0fc..aa3b1df 100644
--- a/src/editors/editorsContainer/TemplateModel.tsx
+++ b/src/editors/editorsContainer/TemplateModel.tsx
@@ -1,7 +1,7 @@
+import { FaMagic } from "react-icons/fa";
import ConcertoEditor from "../ConcertoEditor";
import useAppStore from "../../store/store";
import useUndoRedo from "../../components/useUndoRedo";
-
import { FaUndo, FaRedo } from "react-icons/fa";
function TemplateModel() {
@@ -9,34 +9,72 @@ function TemplateModel() {
const editorModelCto = useAppStore((state) => state.editorModelCto);
const setEditorModelCto = useAppStore((state) => state.setEditorModelCto);
const setModelCto = useAppStore((state) => state.setModelCto);
+
const { value, setValue, undo, redo } = useUndoRedo(
editorModelCto,
setEditorModelCto,
- setModelCto // Sync to main state and rebuild
+ setModelCto
);
-
+
const handleChange = (value: string | undefined) => {
if (value !== undefined) {
- setValue(value); // Update editor state and sync
- setModelCto(value);
+ setValue(value);
+ setModelCto(value);
+ }
+ };
+
+ const handleFormat = () => {
+ try {
+ const lines = value.split("\n").map(line => line.trim()).filter(line => line.length > 0);
+ let indentLevel = 0;
+ const formattedLines: string[] = [];
+
+ lines.forEach(line => {
+ const isClosingBrace = line.startsWith("}");
+ if (isClosingBrace) indentLevel = Math.max(0, indentLevel - 1);
+
+ const indent = " ".repeat(indentLevel);
+ if (line.startsWith("concept") && !line.endsWith("{")) {
+ formattedLines.push(`${indent}${line} {`);
+ indentLevel++;
+ } else if (isClosingBrace) {
+ formattedLines.push(`${indent}}`);
+ } else if (line.startsWith("o")) {
+ line.split(/(?=o\s)/).map(field => field.trim()).forEach(field => formattedLines.push(`${indent}${field}`));
+ } else if (line.includes("{")) {
+ formattedLines.push(`${indent}${line}`);
+ indentLevel++;
+ } else {
+ formattedLines.push(`${indent}${line}`);
+ }
+ });
+
+ const formatted = formattedLines.join("\n");
+ setValue(formatted);
+ setEditorModelCto(formatted);
+ } catch {
+ alert("Error formatting Concerto model!");
}
};
return (
-
+
-
- Defines the data model for the template and its logic.
-
+
Defines the data model for the template.
);
}
-export default TemplateModel;
\ No newline at end of file
+export default TemplateModel;