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() {

Data

+
-

- 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() {

TemplateMark

+
-

- 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 (
-
+

Concerto Model

+
- - 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;