From 5d6257be938b16d1a9e4136d2c47ebd0ffaae38c Mon Sep 17 00:00:00 2001 From: Kiet <31864905+Kitenite@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:41:01 -0400 Subject: [PATCH] Move element write-to-code infrastructure (#233) --- app/common/models/code.ts | 5 +- app/common/models/element/domAction.ts | 25 +++ app/common/models/element/insert.ts | 13 -- app/electron/main/code/diff/index.ts | 2 +- app/electron/main/code/diff/insert.ts | 4 +- app/electron/preload/webview/api.ts | 4 +- .../preload/webview/elements/insert.ts | 12 +- .../preload/webview/elements/move/drag.ts | 149 ++++++++++++++ .../preload/webview/elements/move/helpers.ts | 16 ++ .../preload/webview/elements/move/index.ts | 188 ++++-------------- app/src/lib/editor/engine/code/index.ts | 41 +++- app/src/lib/editor/engine/insert/index.ts | 4 +- .../project/TopBar/PublishModal/index.tsx | 45 +++-- 13 files changed, 305 insertions(+), 203 deletions(-) create mode 100644 app/common/models/element/domAction.ts delete mode 100644 app/common/models/element/insert.ts create mode 100644 app/electron/preload/webview/elements/move/drag.ts diff --git a/app/common/models/code.ts b/app/common/models/code.ts index 2dd34fe9e..3ef54085f 100644 --- a/app/common/models/code.ts +++ b/app/common/models/code.ts @@ -1,11 +1,12 @@ -import { InsertedElement } from './element/insert'; +import { InsertedElement, MovedElement } from './element/domAction'; import { TemplateNode } from './element/templateNode'; export interface CodeDiffRequest { selector: string; templateNode: TemplateNode; codeBlock: string; - elements: InsertedElement[]; + insertedElements: InsertedElement[]; + movedElements: MovedElement[]; attributes: Record; } diff --git a/app/common/models/element/domAction.ts b/app/common/models/element/domAction.ts new file mode 100644 index 000000000..eeb2459b5 --- /dev/null +++ b/app/common/models/element/domAction.ts @@ -0,0 +1,25 @@ +import { InsertPos } from '..'; +import { ActionElementLocation } from '/common/actions'; + +export interface DomActionElement { + timestamp: number; + selector: string; + location: ActionElementLocation; +} + +export interface ActionMoveLocation extends ActionElementLocation { + position: InsertPos.INDEX; + targetSelector: string; + index: number; +} + +export interface MovedElement extends DomActionElement { + location: ActionMoveLocation; +} + +export interface InsertedElement extends DomActionElement { + tagName: string; + selector: string; + children: InsertedElement[]; + attributes: Record; +} diff --git a/app/common/models/element/insert.ts b/app/common/models/element/insert.ts deleted file mode 100644 index be97b44ba..000000000 --- a/app/common/models/element/insert.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ActionElementLocation } from '/common/actions'; - -export interface InsertedChild { - tagName: string; - selector: string; - children: InsertedChild[]; - attributes: Record; - timestamp: number; -} - -export interface InsertedElement extends InsertedChild { - location: ActionElementLocation; -} diff --git a/app/electron/main/code/diff/index.ts b/app/electron/main/code/diff/index.ts index 67414292c..8bfdc1733 100644 --- a/app/electron/main/code/diff/index.ts +++ b/app/electron/main/code/diff/index.ts @@ -23,7 +23,7 @@ export function getCodeDiffs(requests: CodeDiffRequest[]): CodeDiff[] { addClassToAst(ast, request.attributes.className); } - for (const element of request.elements) { + for (const element of request.insertedElements) { insertElementToAst(ast, element); } diff --git a/app/electron/main/code/diff/insert.ts b/app/electron/main/code/diff/insert.ts index 539f56520..fb6456d88 100644 --- a/app/electron/main/code/diff/insert.ts +++ b/app/electron/main/code/diff/insert.ts @@ -1,7 +1,7 @@ import traverse from '@babel/traverse'; import t from '@babel/types'; import { InsertPos } from '/common/models'; -import { InsertedChild, InsertedElement } from '/common/models/element/insert'; +import { InsertedElement } from '/common/models/element/domAction'; export function insertElementToAst(ast: t.File, element: InsertedElement) { let processed = false; @@ -47,7 +47,7 @@ function handleIndexPosition(path: any, element: InsertedElement, newElement: t. } } -function createJSXElement(insertedChild: InsertedChild): t.JSXElement { +function createJSXElement(insertedChild: InsertedElement): t.JSXElement { const attributes = Object.entries(insertedChild.attributes || {}).map(([key, value]) => t.jsxAttribute( t.jsxIdentifier(key), diff --git a/app/electron/preload/webview/api.ts b/app/electron/preload/webview/api.ts index 3e236a576..c686e1b38 100644 --- a/app/electron/preload/webview/api.ts +++ b/app/electron/preload/webview/api.ts @@ -1,7 +1,8 @@ import { contextBridge } from 'electron'; import { getElementAtLoc, getElementWithSelector } from './elements'; import { getInsertedElements, getInsertLocation } from './elements/insert'; -import { drag, endDrag, startDrag } from './elements/move'; +import { getMovedElements } from './elements/move'; +import { drag, endDrag, startDrag } from './elements/move/drag'; export function setApi() { contextBridge.exposeInMainWorld('api', { @@ -12,5 +13,6 @@ export function setApi() { startDrag: startDrag, drag: drag, endDrag: endDrag, + getMovedElements: getMovedElements, }); } diff --git a/app/electron/preload/webview/elements/insert.ts b/app/electron/preload/webview/elements/insert.ts index 854467980..50b86c8ef 100644 --- a/app/electron/preload/webview/elements/insert.ts +++ b/app/electron/preload/webview/elements/insert.ts @@ -5,7 +5,7 @@ import { EditorAttributes, INLINE_ONLY_CONTAINERS } from '/common/constants'; import { getUniqueSelector } from '/common/helpers'; import { InsertPos } from '/common/models'; import { DomElement } from '/common/models/element'; -import { InsertedChild, InsertedElement } from '/common/models/element/insert'; +import { InsertedElement } from '/common/models/element/domAction'; export function getInsertLocation(x: number, y: number): ActionElementLocation | undefined { const targetEl = findNearestBlockLevelContainer(x, y); @@ -132,19 +132,13 @@ export function getInsertedElements(): InsertedElement[] { } function getInsertedElement(el: HTMLElement): InsertedElement { - return { - ...getInsertedChild(el as HTMLElement), - location: getInsertedLocation(el), - }; -} - -function getInsertedChild(el: HTMLElement): InsertedChild { return { tagName: el.tagName.toLowerCase(), selector: getUniqueSelector(el), - children: Array.from(el.children).map((child) => getInsertedChild(child as HTMLElement)), + children: Array.from(el.children).map((child) => getInsertedElement(child as HTMLElement)), timestamp: parseInt(el.getAttribute(EditorAttributes.DATA_ONLOOK_TIMESTAMP) || '0'), attributes: {}, + location: getInsertedLocation(el), }; } diff --git a/app/electron/preload/webview/elements/move/drag.ts b/app/electron/preload/webview/elements/move/drag.ts new file mode 100644 index 000000000..9cb1e8694 --- /dev/null +++ b/app/electron/preload/webview/elements/move/drag.ts @@ -0,0 +1,149 @@ +import { getDisplayDirection, moveElToIndex, publishMoveEvent } from './helpers'; +import { createStub, getCurrentStubIndex, moveStub, removeStub } from './stub'; +import { EditorAttributes } from '/common/constants'; +import { getOnlookUniqueSelector, getUniqueSelector } from '/common/helpers'; + +export function startDrag(selector: string): number { + const el = document.querySelector(selector) as HTMLElement | null; + if (!el) { + console.error(`Start drag element not found: ${selector}`); + return -1; + } + const originalIndex = Array.from(el.parentElement!.children).indexOf(el); + prepareElementForDragging(el, originalIndex); + createStub(el); + return originalIndex; +} + +export function drag(dx: number, dy: number, x: number, y: number) { + const el = getDragElement(); + if (!el) { + console.error('Dragging element not found'); + return; + } + el.style.position = 'fixed'; + el.style.transform = `translate(${dx}px, ${dy}px)`; + moveStub(el, x, y); +} + +export function endDrag( + newUniqueId: string, +): { newSelector: string; newIndex: number } | undefined { + const el = getDragElement(); + if (!el) { + console.error('End drag element not found'); + return; + } + + const parent = el.parentElement; + if (!parent) { + console.error('End drag parent not found'); + return; + } + + const stubIndex = getCurrentStubIndex(parent); + const elIndex = Array.from(parent.children).indexOf(el); + + if (stubIndex !== -1 && stubIndex !== elIndex) { + moveElToIndex(el, stubIndex); + } + removeStub(); + + const newIndex = Array.from(parent.children).indexOf(el); + + cleanUpElementAfterDragging(el, newIndex, newUniqueId); + + if (stubIndex !== -1 && stubIndex !== elIndex) { + publishMoveEvent(el); + } + const newSelector = getOnlookUniqueSelector(el) || getUniqueSelector(el); + return { newSelector, newIndex }; +} + +function prepareElementForDragging(el: HTMLElement, originalIndex: number) { + const saved = el.getAttribute(EditorAttributes.DATA_ONLOOK_SAVED_STYLE); + if (saved) { + return; + } + + const style = { + position: el.style.position, + transform: el.style.transform, + }; + + el.setAttribute(EditorAttributes.DATA_ONLOOK_SAVED_STYLE, JSON.stringify(style)); + el.setAttribute(EditorAttributes.DATA_ONLOOK_DRAGGING, 'true'); + + if (el.getAttribute(EditorAttributes.DATA_ONLOOK_ORIGINAL_INDEX) === null) { + el.setAttribute(EditorAttributes.DATA_ONLOOK_ORIGINAL_INDEX, originalIndex.toString()); + } + + if (el.getAttribute(EditorAttributes.DATA_ONLOOK_DRAG_DIRECTION) !== null) { + const parent = el.parentElement; + if (parent) { + const displayDirection = getDisplayDirection(parent); + el.setAttribute(EditorAttributes.DATA_ONLOOK_DRAG_DIRECTION, displayDirection); + } + } +} + +function getDragElement(): HTMLElement | undefined { + const el = document.querySelector( + `[${EditorAttributes.DATA_ONLOOK_DRAGGING}]`, + ) as HTMLElement | null; + if (!el) { + return; + } + return el; +} + +function cleanUpElementAfterDragging(el: HTMLElement, newIndex: number, newUniqueId: string) { + restoreElementStyle(el); + removeDragAttributes(el); + saveElementIndex(el, newIndex); + assignUniqueId(el, newUniqueId); + saveTimestamp(el); +} + +function removeDragAttributes(el: HTMLElement) { + el.removeAttribute(EditorAttributes.DATA_ONLOOK_SAVED_STYLE); + el.removeAttribute(EditorAttributes.DATA_ONLOOK_DRAGGING); + el.removeAttribute(EditorAttributes.DATA_ONLOOK_DRAG_DIRECTION); +} + +function restoreElementStyle(el: HTMLElement) { + try { + const saved = el.getAttribute(EditorAttributes.DATA_ONLOOK_SAVED_STYLE); + if (saved) { + const style = JSON.parse(saved); + for (const key in style) { + el.style[key as any] = style[key]; + } + } + } catch (e) { + console.error('Error restoring style', e); + } +} + +function saveElementIndex(el: HTMLElement, newIndex: number) { + const originalIndex = parseInt( + el.getAttribute(EditorAttributes.DATA_ONLOOK_ORIGINAL_INDEX) || '-1', + 10, + ); + if (originalIndex !== newIndex) { + el.setAttribute(EditorAttributes.DATA_ONLOOK_NEW_INDEX, newIndex.toString()); + } else { + el.removeAttribute(EditorAttributes.DATA_ONLOOK_ORIGINAL_INDEX); + el.removeAttribute(EditorAttributes.DATA_ONLOOK_NEW_INDEX); + } +} + +function assignUniqueId(el: HTMLElement, newUniqueId: string) { + if (el.getAttribute(EditorAttributes.DATA_ONLOOK_UNIQUE_ID) === null) { + el.setAttribute(EditorAttributes.DATA_ONLOOK_UNIQUE_ID, newUniqueId); + } +} + +function saveTimestamp(el: HTMLElement) { + el.setAttribute(EditorAttributes.DATA_ONLOOK_TIMESTAMP, Date.now().toString()); +} diff --git a/app/electron/preload/webview/elements/move/helpers.ts b/app/electron/preload/webview/elements/move/helpers.ts index 76d45a785..fa07ddb26 100644 --- a/app/electron/preload/webview/elements/move/helpers.ts +++ b/app/electron/preload/webview/elements/move/helpers.ts @@ -57,3 +57,19 @@ export function findInsertionIndex( export function publishMoveEvent(el: HTMLElement) { ipcRenderer.sendToHost(WebviewChannels.ELEMENT_MOVED, getDomElement(el, true)); } + +export function moveElToIndex(el: HTMLElement, newIndex: number): HTMLElement | undefined { + const parent = el.parentElement; + if (!parent) { + return; + } + parent.removeChild(el); + if (newIndex >= parent.children.length) { + parent.appendChild(el); + return el; + } + + const referenceNode = parent.children[newIndex]; + parent.insertBefore(el, referenceNode); + return el; +} diff --git a/app/electron/preload/webview/elements/move/index.ts b/app/electron/preload/webview/elements/move/index.ts index 8430e00b9..397380b20 100644 --- a/app/electron/preload/webview/elements/move/index.ts +++ b/app/electron/preload/webview/elements/move/index.ts @@ -1,66 +1,10 @@ import { getDomElement } from '../helpers'; -import { getDisplayDirection, publishMoveEvent } from './helpers'; -import { createStub, getCurrentStubIndex, moveStub, removeStub } from './stub'; +import { moveElToIndex } from './helpers'; import { EditorAttributes } from '/common/constants'; -import { getOnlookUniqueSelector, getUniqueSelector } from '/common/helpers'; +import { getUniqueSelector } from '/common/helpers'; +import { InsertPos } from '/common/models'; import { DomElement } from '/common/models/element'; - -export function startDrag(selector: string): number { - const el = document.querySelector(selector) as HTMLElement | null; - if (!el) { - console.error(`Start drag element not found: ${selector}`); - return -1; - } - const originalIndex = Array.from(el.parentElement!.children).indexOf(el); - prepareElementForDragging(el, originalIndex); - createStub(el); - return originalIndex; -} - -export function drag(dx: number, dy: number, x: number, y: number) { - const el = getDragElement(); - if (!el) { - console.error('Dragging element not found'); - return; - } - el.style.position = 'fixed'; - el.style.transform = `translate(${dx}px, ${dy}px)`; - moveStub(el, x, y); -} - -export function endDrag( - newUniqueId: string, -): { newSelector: string; newIndex: number } | undefined { - const el = getDragElement(); - if (!el) { - console.error('End drag element not found'); - return; - } - - const parent = el.parentElement; - if (!parent) { - console.error('End drag parent not found'); - return; - } - - const stubIndex = getCurrentStubIndex(parent); - const elIndex = Array.from(parent.children).indexOf(el); - - if (stubIndex !== -1 && stubIndex !== elIndex) { - moveElToIndex(el, stubIndex); - } - removeStub(); - - const newIndex = Array.from(parent.children).indexOf(el); - - cleanUpElementAfterDragging(el, newIndex, newUniqueId); - - if (stubIndex !== -1 && stubIndex !== elIndex) { - publishMoveEvent(el); - } - const newSelector = getOnlookUniqueSelector(el) || getUniqueSelector(el); - return { newSelector, newIndex }; -} +import { ActionMoveLocation, MovedElement } from '/common/models/element/domAction'; export function moveElement(selector: string, newIndex: number): DomElement | undefined { const el = document.querySelector(selector) as HTMLElement | null; @@ -77,101 +21,41 @@ export function moveElement(selector: string, newIndex: number): DomElement | un return domEl; } -function moveElToIndex(el: HTMLElement, newIndex: number): HTMLElement | undefined { - const parent = el.parentElement; - if (!parent) { - return; - } - parent.removeChild(el); - if (newIndex >= parent.children.length) { - parent.appendChild(el); - return el; - } - - const referenceNode = parent.children[newIndex]; - parent.insertBefore(el, referenceNode); - return el; -} - -function prepareElementForDragging(el: HTMLElement, originalIndex: number) { - const saved = el.getAttribute(EditorAttributes.DATA_ONLOOK_SAVED_STYLE); - if (saved) { - return; - } - - const style = { - position: el.style.position, - transform: el.style.transform, +export function getMovedElements(): MovedElement[] { + const movedEls = Array.from( + document.querySelectorAll(`[${EditorAttributes.DATA_ONLOOK_ORIGINAL_INDEX}]`), + ) + .filter((el) => { + const parent = el.parentElement; + const isParentInserted = + parent && parent.hasAttribute(EditorAttributes.DATA_ONLOOK_INSERTED); + const isElementInserted = el.hasAttribute(EditorAttributes.DATA_ONLOOK_INSERTED); + return !isParentInserted && !isElementInserted; + }) + .map((el) => getMovedElement(el as HTMLElement)) + .sort((a, b) => a.timestamp - b.timestamp); + return movedEls; +} + +function getMovedElement(el: HTMLElement): MovedElement { + return { + selector: getUniqueSelector(el), + timestamp: parseInt(el.getAttribute(EditorAttributes.DATA_ONLOOK_TIMESTAMP) || '0'), + location: getMovedLocation(el), }; - - el.setAttribute(EditorAttributes.DATA_ONLOOK_SAVED_STYLE, JSON.stringify(style)); - el.setAttribute(EditorAttributes.DATA_ONLOOK_DRAGGING, 'true'); - - if (el.getAttribute(EditorAttributes.DATA_ONLOOK_ORIGINAL_INDEX) === null) { - el.setAttribute(EditorAttributes.DATA_ONLOOK_ORIGINAL_INDEX, originalIndex.toString()); - } - - if (el.getAttribute(EditorAttributes.DATA_ONLOOK_DRAG_DIRECTION) !== null) { - const parent = el.parentElement; - if (parent) { - const displayDirection = getDisplayDirection(parent); - el.setAttribute(EditorAttributes.DATA_ONLOOK_DRAG_DIRECTION, displayDirection); - } - } -} - -function getDragElement(): HTMLElement | undefined { - const el = document.querySelector( - `[${EditorAttributes.DATA_ONLOOK_DRAGGING}]`, - ) as HTMLElement | null; - if (!el) { - return; - } - return el; -} - -function cleanUpElementAfterDragging(el: HTMLElement, newIndex: number, newUniqueId: string) { - restoreElementStyle(el); - removeDragAttributes(el); - saveElementIndex(el, newIndex); - assignUniqueId(el, newUniqueId); -} - -function removeDragAttributes(el: HTMLElement) { - el.removeAttribute(EditorAttributes.DATA_ONLOOK_SAVED_STYLE); - el.removeAttribute(EditorAttributes.DATA_ONLOOK_DRAGGING); - el.removeAttribute(EditorAttributes.DATA_ONLOOK_DRAG_DIRECTION); } -function restoreElementStyle(el: HTMLElement) { - try { - const saved = el.getAttribute(EditorAttributes.DATA_ONLOOK_SAVED_STYLE); - if (saved) { - const style = JSON.parse(saved); - for (const key in style) { - el.style[key as any] = style[key]; - } - } - } catch (e) { - console.error('Error restoring style', e); - } -} - -function saveElementIndex(el: HTMLElement, newIndex: number) { - const originalIndex = parseInt( - el.getAttribute(EditorAttributes.DATA_ONLOOK_ORIGINAL_INDEX) || '-1', - 10, - ); - if (originalIndex !== newIndex) { - el.setAttribute(EditorAttributes.DATA_ONLOOK_NEW_INDEX, newIndex.toString()); - } else { - el.removeAttribute(EditorAttributes.DATA_ONLOOK_ORIGINAL_INDEX); - el.removeAttribute(EditorAttributes.DATA_ONLOOK_NEW_INDEX); +function getMovedLocation(el: HTMLElement): ActionMoveLocation { + const parent = el.parentElement; + if (!parent) { + throw new Error('Inserted element has no parent'); } -} + const index: number | undefined = Array.from(parent.children).indexOf(el); + const position = InsertPos.INDEX; -function assignUniqueId(el: HTMLElement, newUniqueId: string) { - if (el.getAttribute(EditorAttributes.DATA_ONLOOK_UNIQUE_ID) === null) { - el.setAttribute(EditorAttributes.DATA_ONLOOK_UNIQUE_ID, newUniqueId); - } + return { + targetSelector: getUniqueSelector(parent), + position, + index, + }; } diff --git a/app/src/lib/editor/engine/code/index.ts b/app/src/lib/editor/engine/code/index.ts index 4cfcd3047..f2d800ad6 100644 --- a/app/src/lib/editor/engine/code/index.ts +++ b/app/src/lib/editor/engine/code/index.ts @@ -6,7 +6,7 @@ import { AstManager } from '../ast'; import { WebviewManager } from '../webview'; import { EditorAttributes, MainChannels } from '/common/constants'; import { CodeDiff, CodeDiffRequest } from '/common/models/code'; -import { InsertedElement } from '/common/models/element/insert'; +import { InsertedElement, MovedElement } from '/common/models/element/domAction'; import { TemplateNode } from '/common/models/element/templateNode'; export class CodeManager { @@ -34,7 +34,13 @@ export class CodeManager { const tailwindResults = await this.getTailwindClasses(webview); const insertedEls = await this.getInsertedElements(webview); - const codeDiffRequest = await this.getCodeDiffRequests(tailwindResults, insertedEls); + const movedEls = await this.getMovedElements(webview); + + const codeDiffRequest = await this.getCodeDiffRequests( + tailwindResults, + insertedEls, + movedEls, + ); const codeDiffs = await this.getCodeDiff(codeDiffRequest); return codeDiffs; } @@ -56,14 +62,19 @@ export class CodeManager { return webview.executeJavaScript(`window.api?.getInsertedElements()`); } + private async getMovedElements(webview: Electron.WebviewTag): Promise { + return webview.executeJavaScript(`window.api?.getMovedElements()`); + } + private async getCodeDiffRequests( tailwindResults: ResultCode[], insertedEls: InsertedElement[], + movedEls: MovedElement[], ): Promise { const templateToRequest = new Map(); await this.processTailwindChanges(tailwindResults, templateToRequest); await this.processInsertedElements(insertedEls, tailwindResults, templateToRequest); - + await this.processMovedElements(movedEls, templateToRequest); return Array.from(templateToRequest.values()); } @@ -112,7 +123,26 @@ export class CodeManager { insertedEl, tailwindResults, ); - request.elements.push(insertedElWithTailwind); + request.insertedElements.push(insertedElWithTailwind); + } + } + + private async processMovedElements( + movedEls: MovedElement[], + templateToCodeChange: Map, + ): Promise { + for (const movedEl of movedEls) { + const templateNode = await this.getTemplateNodeForSelector(movedEl.selector); + if (!templateNode) { + continue; + } + + const request = await this.getOrCreateCodeDiffRequest( + templateNode, + movedEl.location.targetSelector, + templateToCodeChange, + ); + request.movedElements.push(movedEl); } } @@ -138,7 +168,8 @@ export class CodeManager { selector, templateNode, codeBlock, - elements: [], + insertedElements: [], + movedElements: [], attributes: {}, }; templateToCodeChange.set(templateNode, diffRequest); diff --git a/app/src/lib/editor/engine/insert/index.ts b/app/src/lib/editor/engine/insert/index.ts index ab507190c..83c0df9a3 100644 --- a/app/src/lib/editor/engine/insert/index.ts +++ b/app/src/lib/editor/engine/insert/index.ts @@ -106,10 +106,12 @@ export class InsertManager { }, ]; + const id = nanoid(); const actionElement: ActionElement = { tagName: 'div', attributes: { - [EditorAttributes.DATA_ONLOOK_UNIQUE_ID]: nanoid(), + id, + [EditorAttributes.DATA_ONLOOK_UNIQUE_ID]: id, [EditorAttributes.DATA_ONLOOK_INSERTED]: 'true', [EditorAttributes.DATA_ONLOOK_TIMESTAMP]: Date.now().toString(), }, diff --git a/app/src/routes/project/TopBar/PublishModal/index.tsx b/app/src/routes/project/TopBar/PublishModal/index.tsx index 7d9d8824d..7288d884e 100644 --- a/app/src/routes/project/TopBar/PublishModal/index.tsx +++ b/app/src/routes/project/TopBar/PublishModal/index.tsx @@ -23,14 +23,17 @@ const PublishModal = observer(() => { const editorEngine = useEditorEngine(); const { toast } = useToast(); - const [open, setOpen] = useState(false); - const [loading, setLoading] = useState(false); + const [isOpen, setIsOpen] = useState(false); + const [isLoadingCodeDiff, setIsLoadingCodeDiff] = useState(false); + const [isWriting, setIsWriting] = useState(false); const [codeDiffs, setCodeDiffs] = useState([]); async function handleOpenChange(open: boolean) { - setOpen(open); + setIsOpen(open); if (open) { + setIsLoadingCodeDiff(true); const res = await editorEngine.code.generateCodeDiffs(); + setIsLoadingCodeDiff(false); setCodeDiffs(res); } } @@ -40,8 +43,8 @@ const PublishModal = observer(() => { } function handleWriteSucceeded() { - setLoading(false); - setOpen(false); + setIsWriting(false); + setIsOpen(false); setCodeDiffs([]); editorEngine.webviews.getAll().forEach((webview) => { webview.send(WebviewChannels.CLEAN_AFTER_WRITE_TO_CODE); @@ -54,7 +57,7 @@ const PublishModal = observer(() => { } function handleWriteFailed() { - setLoading(false); + setIsWriting(false); toast({ title: 'Write failed!', description: 'Failed to write changes to codebase', @@ -62,7 +65,7 @@ const PublishModal = observer(() => { } async function writeCodeBlock() { - setLoading(true); + setIsWriting(true); const res = await window.api.invoke(MainChannels.WRITE_CODE_BLOCKS, codeDiffs); if (res) { handleWriteSucceeded(); @@ -81,8 +84,17 @@ const PublishModal = observer(() => { } } + function renderDescription() { + return codeDiffs.length === 0 ? ( + + No code changes detected. Make some changes in the editor to see differences. + + ) : ( + Review and apply the changes to your codebase + ); + } return ( - +