From 2408d724058dd0c76a5ae9c4a8596fd69578bd86 Mon Sep 17 00:00:00 2001 From: Kiet <31864905+Kitenite@users.noreply.github.com> Date: Wed, 24 Jul 2024 15:14:29 -0400 Subject: [PATCH] Refactor code writing modules (#81) * Refactor code writing modules --- app/bun.lockb | Bin 311214 -> 341797 bytes app/common/constants.ts | 19 +- app/common/helpers/template.ts | 2 +- app/common/models.ts | 44 ---- app/common/models/element/index.ts | 25 +++ app/common/models/element/templateNode.ts | 17 ++ app/common/models/index.ts | 14 ++ app/common/models/tunnel.ts | 4 + app/electron/main/code/babel.ts | 80 ++++++++ app/electron/main/code/files.ts | 114 ----------- app/electron/main/code/index.ts | 193 +++++++++++------- app/electron/main/events/index.ts | 73 +++++++ app/electron/main/index.ts | 2 +- app/electron/main/ipcEvents.ts | 51 ----- app/electron/main/tunnel/index.ts | 2 +- .../preload/webview/elements/index.ts | 2 +- app/src/lib/editor/engine/code/index.ts | 68 +++--- app/src/lib/editor/engine/index.ts | 2 +- app/src/lib/editor/engine/state.ts | 2 +- app/src/lib/editor/eventHandler.ts | 2 +- app/src/routes/project/PublishModal/index.tsx | 60 ++++-- app/src/routes/project/SharePopover/index.tsx | 2 +- app/src/routes/project/TopBar/index.tsx | 4 +- demos/next/components/ui/card.tsx | 2 +- plugins/babel/README.md | 6 +- 25 files changed, 448 insertions(+), 342 deletions(-) delete mode 100644 app/common/models.ts create mode 100644 app/common/models/element/index.ts create mode 100644 app/common/models/element/templateNode.ts create mode 100644 app/common/models/index.ts create mode 100644 app/common/models/tunnel.ts create mode 100644 app/electron/main/code/babel.ts create mode 100644 app/electron/main/events/index.ts delete mode 100644 app/electron/main/ipcEvents.ts diff --git a/app/bun.lockb b/app/bun.lockb index 8d3f6ba174dd62c54ef17b20a1b9b88d7e78676e..629e70255851d505a321ae4957028455c0111ad1 100755 GIT binary patch delta 78029 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 delta 59054 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 { + if (t.isJSXAttribute(attribute) && attribute.name.name === 'className') { + classNameAttr = attribute; + + if (t.isStringLiteral(attribute.value)) { + attribute.value.value = twMerge(attribute.value.value, className); + } + // Handle className that is an expression (e.g., cn("class1", className)) + else if ( + t.isJSXExpressionContainer(attribute.value) && + t.isCallExpression(attribute.value.expression) + ) { + attribute.value.expression.arguments.push(t.stringLiteral(className)); + } + } + }); + + if (!classNameAttr) { + const newClassNameAttr = t.jsxAttribute( + t.jsxIdentifier('className'), + t.stringLiteral(className), + ); + path.node.attributes.push(newClassNameAttr); + } + processed = true; + }, + }); +} diff --git a/app/electron/main/code/files.ts b/app/electron/main/code/files.ts index b457c1001..697af6990 100644 --- a/app/electron/main/code/files.ts +++ b/app/electron/main/code/files.ts @@ -1,8 +1,5 @@ -import { shell } from 'electron'; import { promises as fs } from 'fs'; import * as path from 'path'; -import { compareTemplateNodes } from '/common/helpers/template'; -import { CodeResult, TemplateNode } from '/common/models'; export async function readFile(filePath: string): Promise { try { @@ -24,114 +21,3 @@ export async function writeFile(filePath: string, content: string): Promise { - try { - const filePath = templateNode.path; - - const startTag = templateNode.startTag; - const startRow = startTag.start.line; - const startColumn = startTag.start.column; - - const endTag = templateNode.endTag || startTag; - const endRow = endTag.end.line; - const endColumn = endTag.end.column; - - const fileContent = await readFile(filePath); - const lines = fileContent.split('\n'); - - const selectedText = lines - .slice(startRow - 1, endRow) - .map((line, index, array) => { - if (index === 0 && array.length === 1) { - // Only one line - return line.substring(startColumn - 1, endColumn); - } else if (index === 0) { - // First line of multiple - return line.substring(startColumn - 1); - } else if (index === array.length - 1) { - // Last line - return line.substring(0, endColumn); - } - // Full lines in between - return line; - }) - .join('\n'); - - return selectedText; - } catch (error: any) { - console.error('Error reading range from file:', error); - throw error; - } -} - -export async function writeCodeResults(codeResults: CodeResult[]): Promise { - // Write from bottom to prevent line offset - const sortedCodeResults = codeResults - .sort((a, b) => compareTemplateNodes(a.param.templateNode, b.param.templateNode)) - .toReversed(); - const files = new Map(); - - for (const result of sortedCodeResults) { - let fileContent = files.get(result.param.templateNode.path); - if (!fileContent) { - fileContent = await readFile(result.param.templateNode.path); - } - - const newFileContent = await writeBlock( - result.param.templateNode, - result.generated, - fileContent, - ); - files.set(result.param.templateNode.path, newFileContent); - } - - for (const [filePath, content] of files) { - await writeFile(filePath, content); - } -} - -export async function writeBlock( - templateNode: TemplateNode, - newBlock: string, - fileContent: string, -): Promise { - try { - const startTag = templateNode.startTag; - const startRow = startTag.start.line; - const startColumn = startTag.start.column; - - const endTag = templateNode.endTag || startTag; - const endRow = endTag.end.line; - const endColumn = endTag.end.column; - - const lines = fileContent.split('\n'); - const before = lines.slice(0, startRow - 1).join('\n'); - const after = lines.slice(endRow).join('\n'); - - const firstLine = lines[startRow - 1].substring(0, startColumn - 1); - const lastLine = lines[endRow - 1].substring(endColumn); - - const newFileContent = [before, firstLine + newBlock + lastLine, after].join('\n'); - return newFileContent; - } catch (error: any) { - console.error('Error replacing range in file:', error); - throw error; - } -} - -export function openInVsCode(templateNode: TemplateNode) { - const filePath = templateNode.path; - const startTag = templateNode.startTag; - const endTag = templateNode.endTag || startTag; - let command = `vscode://file/${filePath}`; - - if (startTag && endTag) { - const startRow = startTag.start.line; - const startColumn = startTag.start.column; - const endRow = endTag.end.line; - const endColumn = endTag.end.column - 1; - command += `:${startRow}:${startColumn}:${endRow}:${endColumn}`; - } - shell.openExternal(command); -} diff --git a/app/electron/main/code/index.ts b/app/electron/main/code/index.ts index 6551b16a1..127a0b5e5 100644 --- a/app/electron/main/code/index.ts +++ b/app/electron/main/code/index.ts @@ -1,80 +1,131 @@ -import generate from '@babel/generator'; -import { parse } from '@babel/parser'; -import traverse from '@babel/traverse'; -import t from '@babel/types'; -import { twMerge } from 'tailwind-merge'; -import { readBlock } from './files'; -import { CodeResult, WriteStyleParams } from '/common/models'; - -export async function writeStyle(params: WriteStyleParams[]): Promise { - const codeResults: CodeResult[] = []; - const generateOptions = { retainLines: true, compact: false }; - - for (const param of params) { - const code = await readBlock(param.templateNode); - const ast = parseJsx(code); - const original = removeSemiColonIfApplicable( - generate(ast, generateOptions, code).code, - code, - ); - - addClassToAst(ast, param.tailwind); - - const generated = removeSemiColonIfApplicable( - generate(ast, generateOptions, code).code, - code, - ); - codeResults.push({ original, generated, param }); +import { shell } from 'electron'; +import { TemplateNode } from '../../../common/models/element/templateNode'; +import { readFile, writeFile } from './files'; +import { compareTemplateNodes } from '/common/helpers/template'; +import { StyleCodeDiff } from '/common/models'; + +export async function readCodeBlocks(templateNodes: TemplateNode[]): Promise { + const blocks: string[] = []; + for (const templateNode of templateNodes) { + const block = await readCodeBlock(templateNode); + blocks.push(block); } - return codeResults; + return blocks; } -function removeSemiColonIfApplicable(code: string, original: string) { - if (!original.endsWith(';') && code.endsWith(';')) { - return code.slice(0, -1); +export async function readCodeBlock(templateNode: TemplateNode): Promise { + try { + const filePath = templateNode.path; + + const startTag = templateNode.startTag; + const startRow = startTag.start.line; + const startColumn = startTag.start.column; + + const endTag = templateNode.endTag || startTag; + const endRow = endTag.end.line; + const endColumn = endTag.end.column; + + const fileContent = await readFile(filePath); + const lines = fileContent.split('\n'); + + const selectedText = lines + .slice(startRow - 1, endRow) + .map((line: string, index: number, array: string[]) => { + if (index === 0 && array.length === 1) { + // Only one line + return line.substring(startColumn - 1, endColumn); + } else if (index === 0) { + // First line of multiple + return line.substring(startColumn - 1); + } else if (index === array.length - 1) { + // Last line + return line.substring(0, endColumn); + } + // Full lines in between + return line; + }) + .join('\n'); + + return selectedText; + } catch (error: any) { + console.error('Error reading range from file:', error); + throw error; } - return code; } -function parseJsx(code: string) { - return parse(code, { - plugins: ['typescript', 'jsx'], - }); -} +export async function writeCode(styleCodeDiffs: StyleCodeDiff[]): Promise { + try { + // Write from bottom to prevent line offset + const sortedCodeDiffs = styleCodeDiffs + .sort((a, b) => compareTemplateNodes(a.param.templateNode, b.param.templateNode)) + .toReversed(); + const files = new Map(); -function addClassToAst(ast: t.File, className: string) { - let processed = false; - traverse(ast, { - JSXOpeningElement(path) { - if (processed) { - return; - } - let classNameAttr = null; - path.node.attributes.forEach((attribute) => { - if (t.isJSXAttribute(attribute) && attribute.name.name === 'className') { - classNameAttr = attribute; - - if (t.isStringLiteral(attribute.value)) { - attribute.value.value = twMerge(attribute.value.value, className); - } - // Handle className that is an expression (e.g., cn("class1", className)) - else if ( - t.isJSXExpressionContainer(attribute.value) && - t.isCallExpression(attribute.value.expression) - ) { - attribute.value.expression.arguments.push(t.stringLiteral(className)); - } - } - }); - - if (!classNameAttr) { - const newClassNameAttr = t.jsxAttribute( - t.jsxIdentifier('className'), - t.stringLiteral(className), - ); - path.node.attributes.push(newClassNameAttr); + for (const result of sortedCodeDiffs) { + let fileContent = files.get(result.param.templateNode.path); + if (!fileContent) { + fileContent = await readFile(result.param.templateNode.path); } - processed = true; - }, - }); + + const updatedFileContent = await getUpdatedFileContent( + result.param.templateNode, + result.generated, + fileContent, + ); + files.set(result.param.templateNode.path, updatedFileContent); + } + + for (const [filePath, content] of files) { + await writeFile(filePath, content); + } + } catch (error: any) { + console.error('Error writing range to file:', error); + return false; + } + return true; +} + +export async function getUpdatedFileContent( + templateNode: TemplateNode, + newBlock: string, + fileContent: string, +): Promise { + try { + const startTag = templateNode.startTag; + const startRow = startTag.start.line; + const startColumn = startTag.start.column; + + const endTag = templateNode.endTag || startTag; + const endRow = endTag.end.line; + const endColumn = endTag.end.column; + + const lines = fileContent.split('\n'); + const before = lines.slice(0, startRow - 1).join('\n'); + const after = lines.slice(endRow).join('\n'); + + const firstLine = lines[startRow - 1].substring(0, startColumn - 1); + const lastLine = lines[endRow - 1].substring(endColumn); + + const newFileContent = [before, firstLine + newBlock + lastLine, after].join('\n'); + return newFileContent; + } catch (error: any) { + console.error('Error replacing range in file:', error); + throw error; + } +} + +export function openInVsCode(templateNode: TemplateNode) { + const filePath = templateNode.path; + const startTag = templateNode.startTag; + const endTag = templateNode.endTag || startTag; + let command = `vscode://file/${filePath}`; + + if (startTag && endTag) { + const startRow = startTag.start.line; + const startColumn = startTag.start.column; + const endRow = endTag.end.line; + const endColumn = endTag.end.column - 1; + command += `:${startRow}:${startColumn}:${endRow}:${endColumn}`; + } + shell.openExternal(command); } diff --git a/app/electron/main/events/index.ts b/app/electron/main/events/index.ts new file mode 100644 index 000000000..30096c5cb --- /dev/null +++ b/app/electron/main/events/index.ts @@ -0,0 +1,73 @@ +import { ipcMain } from 'electron'; +import { TemplateNode } from '../../../common/models/element/templateNode'; +import Analytics from '../analytics'; +import { openInVsCode, readCodeBlock, readCodeBlocks, writeCode } from '../code/'; +import { getStyleCodeDiffs } from '../code/babel'; +import { TunnelService } from '../tunnel'; +import { MainChannels } from '/common/constants'; +import { StyleChangeParam, StyleCodeDiff } from '/common/models'; + +function listenForTunnelMessages() { + const tunnelService = new TunnelService(); + + ipcMain.handle(MainChannels.OPEN_TUNNEL, (e: Electron.IpcMainInvokeEvent, args) => { + const port = args as number; + return tunnelService.open(port); + }); + + ipcMain.handle(MainChannels.CLOSE_TUNNEL, (e: Electron.IpcMainInvokeEvent) => { + return tunnelService.close(); + }); +} + +function listenForAnalyticsMessages() { + let analytics: Analytics | null = null; + + ipcMain.on(MainChannels.ANLYTICS_PREF_SET, (e: Electron.IpcMainInvokeEvent, args) => { + const analyticsPref = args as boolean; + if (analyticsPref) { + analytics = new Analytics(); + analytics.track('analytics-allowed'); + } + }); + + ipcMain.on(MainChannels.SEND_ANALYTICS, (e: Electron.IpcMainInvokeEvent, args) => { + if (analytics) { + const { event, data } = args as { event: string; data: object }; + analytics.track(event, data); + } + }); +} + +function listenForCodeMessages() { + ipcMain.handle(MainChannels.VIEW_SOURCE_CODE, (e: Electron.IpcMainInvokeEvent, args) => { + const templateNode = args as TemplateNode; + openInVsCode(templateNode); + }); + + ipcMain.handle(MainChannels.GET_CODE_BLOCK, (e: Electron.IpcMainInvokeEvent, args) => { + const templateNode = args as TemplateNode; + return readCodeBlock(templateNode); + }); + + ipcMain.handle(MainChannels.GET_CODE_BLOCKS, (e: Electron.IpcMainInvokeEvent, args) => { + const templateNodes = args as TemplateNode[]; + return readCodeBlocks(templateNodes); + }); + + ipcMain.handle(MainChannels.WRITE_CODE_BLOCKS, (e: Electron.IpcMainInvokeEvent, args) => { + const codeResults = args as StyleCodeDiff[]; + return writeCode(codeResults); + }); + + ipcMain.handle(MainChannels.GET_STYLE_CODE_DIFFS, (e: Electron.IpcMainInvokeEvent, args) => { + const styleParams = args as StyleChangeParam[]; + return getStyleCodeDiffs(styleParams); + }); +} + +export function listenForIpcMessages() { + listenForTunnelMessages(); + listenForAnalyticsMessages(); + listenForCodeMessages(); +} diff --git a/app/electron/main/index.ts b/app/electron/main/index.ts index e5f73aa39..1c33ed49c 100644 --- a/app/electron/main/index.ts +++ b/app/electron/main/index.ts @@ -3,7 +3,7 @@ import { createRequire } from 'node:module'; import os from 'node:os'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { listenForIpcMessages } from './ipcEvents'; +import { listenForIpcMessages } from './events'; import AutoUpdateManager from './update'; import { APP_NAME } from '/common/constants'; diff --git a/app/electron/main/ipcEvents.ts b/app/electron/main/ipcEvents.ts deleted file mode 100644 index 37327ff26..000000000 --- a/app/electron/main/ipcEvents.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { ipcMain } from 'electron'; -import Analytics from './analytics'; -import { writeStyle } from './code'; -import { openInVsCode, writeCodeResults } from './code/files'; -import { TunnelService } from './tunnel'; -import { MainChannels } from '/common/constants'; -import { CodeResult, TemplateNode, WriteStyleParams } from '/common/models'; - -export function listenForIpcMessages() { - let analytics: Analytics | null = null; - const tunnelService = new TunnelService(); - - ipcMain.handle(MainChannels.OPEN_CODE_BLOCK, (e: Electron.IpcMainInvokeEvent, args) => { - const templateNode = args as TemplateNode; - openInVsCode(templateNode); - }); - - ipcMain.handle(MainChannels.WRITE_CODE_BLOCK, (e: Electron.IpcMainInvokeEvent, args) => { - const codeResults = args as CodeResult[]; - return writeCodeResults(codeResults); - }); - - ipcMain.handle(MainChannels.GET_STYLE_CODE, (e: Electron.IpcMainInvokeEvent, args) => { - const writeStylePrams = args as WriteStyleParams[]; - return writeStyle(writeStylePrams); - }); - - ipcMain.handle(MainChannels.OPEN_TUNNEL, (e: Electron.IpcMainInvokeEvent, args) => { - const port = args as number; - return tunnelService.open(port); - }); - - ipcMain.handle(MainChannels.CLOSE_TUNNEL, (e: Electron.IpcMainInvokeEvent) => { - return tunnelService.close(); - }); - - ipcMain.on(MainChannels.ANLYTICS_PREF_SET, (e: Electron.IpcMainInvokeEvent, args) => { - const analyticsPref = args as boolean; - if (analyticsPref) { - analytics = new Analytics(); - analytics.track('analytics-allowed'); - } - }); - - ipcMain.on(MainChannels.SEND_ANALYTICS, (e: Electron.IpcMainInvokeEvent, args) => { - if (analytics) { - const { event, data } = args as { event: string; data: object }; - analytics.track(event, data); - } - }); -} diff --git a/app/electron/main/tunnel/index.ts b/app/electron/main/tunnel/index.ts index 9ee7960d8..eab4f298a 100644 --- a/app/electron/main/tunnel/index.ts +++ b/app/electron/main/tunnel/index.ts @@ -1,5 +1,5 @@ import localtunnel from 'localtunnel'; -import { TunnelResult } from '/common/models'; +import { TunnelResult } from '/common/models/tunnel'; export class TunnelService { tunnel: localtunnel.Tunnel | null = null; diff --git a/app/electron/preload/webview/elements/index.ts b/app/electron/preload/webview/elements/index.ts index f6af9c056..206cbd67e 100644 --- a/app/electron/preload/webview/elements/index.ts +++ b/app/electron/preload/webview/elements/index.ts @@ -1,6 +1,6 @@ import { EditorAttributes } from '/common/constants'; import { getUniqueSelector } from '/common/helpers'; -import { ElementMetadata } from '/common/models'; +import { ElementMetadata } from '/common/models/element'; export const getElementsMetadataFromSelector = ( selector: string, diff --git a/app/src/lib/editor/engine/code/index.ts b/app/src/lib/editor/engine/code/index.ts index 91cb53968..55fb94d4a 100644 --- a/app/src/lib/editor/engine/code/index.ts +++ b/app/src/lib/editor/engine/code/index.ts @@ -4,28 +4,48 @@ import { WebviewManager } from '../webviews'; import { EditorAttributes, MainChannels } from '/common/constants'; import { querySelectorCommand } from '/common/helpers'; import { decodeTemplateNode } from '/common/helpers/template'; -import { CodeResult, TemplateNode, WriteStyleParams } from '/common/models'; +import { StyleChangeParam, StyleCodeDiff } from '/common/models'; +import { TemplateNode } from '/common/models/element/templateNode'; export class CodeManager { constructor(private webviewManager: WebviewManager) {} - viewInEditor(templateNode: TemplateNode) { - window.api.invoke(MainChannels.OPEN_CODE_BLOCK, templateNode); + viewSource(templateNode: TemplateNode) { + window.api.invoke(MainChannels.VIEW_SOURCE_CODE, templateNode); } - async getStylesheet(webview: Electron.WebviewTag) { + async generateCodeDiffs(): Promise { + const webview = [...this.webviewManager.getAll().values()][0]; + const stylesheet = await this.getStylesheet(webview); + + if (!stylesheet) { + console.log('No stylesheet found in the webview.'); + return []; + } + + const tailwindResults = await this.getTailwindClasses(stylesheet); + const writeParams = await this.getStyleChangeParams(tailwindResults, webview); + const styleCodeDiffs = (await this.getStyleCodeDiff(writeParams)) as StyleCodeDiff[]; + return styleCodeDiffs; + } + + private getStyleCodeDiff(styleParams: StyleChangeParam[]): Promise { + return window.api.invoke(MainChannels.GET_STYLE_CODE_DIFFS, styleParams); + } + + private async getStylesheet(webview: Electron.WebviewTag) { return await webview.executeJavaScript( `document.getElementById('${EditorAttributes.ONLOOK_STYLESHEET_ID}')?.textContent`, ); } - async getDataOnlookId(selector: string, webview: Electron.WebviewTag) { + private async getDataOnlookId(selector: string, webview: Electron.WebviewTag) { return await webview.executeJavaScript( `${querySelectorCommand(selector)}?.getAttribute('${EditorAttributes.DATA_ONLOOK_ID}')`, ); } - async getTailwindClasses(stylesheet: string) { + private async getTailwindClasses(stylesheet: string) { const tailwindResult = CssToTailwindTranslator(stylesheet); if (tailwindResult.code !== 'OK') { throw new Error('Failed to translate CSS to Tailwind CSS.'); @@ -33,8 +53,11 @@ export class CodeManager { return tailwindResult.data; } - async getWriteStyleParams(tailwindResults: ResultCode[], webview: Electron.WebviewTag) { - const writeParams: Map = new Map(); + private async getStyleChangeParams( + tailwindResults: ResultCode[], + webview: Electron.WebviewTag, + ): Promise { + const changeParams: Map = new Map(); for (const twRes of tailwindResults) { const { resultVal, selectorName } = twRes; const dataOnlookId = await this.getDataOnlookId(selectorName, webview); @@ -42,37 +65,26 @@ export class CodeManager { continue; } - let writeParam = writeParams.get(dataOnlookId); + let writeParam = changeParams.get(dataOnlookId); if (!writeParam) { + const templateNode = decodeTemplateNode(dataOnlookId); + const codeBlock = (await window.api.invoke( + MainChannels.GET_CODE_BLOCK, + templateNode, + )) as string; writeParam = { selector: selectorName, templateNode: decodeTemplateNode(dataOnlookId), tailwind: resultVal, + codeBlock, }; } else { writeParam.tailwind = twMerge(writeParam.tailwind, resultVal); } - writeParams.set(dataOnlookId, writeParam); + changeParams.set(dataOnlookId, writeParam); } - return Array.from(writeParams.values()); - } - - async generateCodeDiffs(): Promise { - // TODO: Handle multiple webviews - const webview = [...this.webviewManager.getAll().values()][0]; - const stylesheet = await this.getStylesheet(webview); - - if (!stylesheet) { - console.log('No stylesheet found in the webview.'); - return []; - } - - const tailwindResults = await this.getTailwindClasses(stylesheet); - const writeParams = await this.getWriteStyleParams(tailwindResults, webview); - const result = await window.api.invoke(MainChannels.GET_STYLE_CODE, writeParams); - - return (result || []) as CodeResult[]; + return Array.from(changeParams.values()); } } diff --git a/app/src/lib/editor/engine/index.ts b/app/src/lib/editor/engine/index.ts index 0eae7fed4..1f0af8d0f 100644 --- a/app/src/lib/editor/engine/index.ts +++ b/app/src/lib/editor/engine/index.ts @@ -7,7 +7,7 @@ import { EditorElementState } from './state'; import { WebviewManager } from './webviews'; import { Action, ActionTarget } from '/common/actions'; import { WebviewChannels } from '/common/constants'; -import { ElementMetadata } from '/common/models'; +import { ElementMetadata } from '/common/models/element'; export enum EditorMode { Design = 'Design', diff --git a/app/src/lib/editor/engine/state.ts b/app/src/lib/editor/engine/state.ts index c8bc2689d..92eb10a21 100644 --- a/app/src/lib/editor/engine/state.ts +++ b/app/src/lib/editor/engine/state.ts @@ -1,5 +1,5 @@ import { makeAutoObservable } from 'mobx'; -import { ElementMetadata } from '/common/models'; +import { ElementMetadata } from '/common/models/element'; export class EditorElementState { private hoveredElement: ElementMetadata | undefined; diff --git a/app/src/lib/editor/eventHandler.ts b/app/src/lib/editor/eventHandler.ts index b6c2a1b27..a8fb3354d 100644 --- a/app/src/lib/editor/eventHandler.ts +++ b/app/src/lib/editor/eventHandler.ts @@ -1,4 +1,4 @@ -import { ElementMetadata } from 'common/models'; +import { ElementMetadata } from 'common/models/element'; import { EditorEngine } from './engine'; import { WebviewChannels } from '/common/constants'; diff --git a/app/src/routes/project/PublishModal/index.tsx b/app/src/routes/project/PublishModal/index.tsx index a24c7893c..85ec759d1 100644 --- a/app/src/routes/project/PublishModal/index.tsx +++ b/app/src/routes/project/PublishModal/index.tsx @@ -15,49 +15,63 @@ import { useState } from 'react'; import ReactDiffViewer from 'react-diff-viewer-continued'; import { useEditorEngine } from '..'; import { MainChannels, WebviewChannels } from '/common/constants'; -import { CodeResult, TemplateNode } from '/common/models'; +import { StyleCodeDiff } from '/common/models'; +import { TemplateNode } from '/common/models/element/templateNode'; const PublishModal = observer(() => { const editorEngine = useEditorEngine(); - const [codeResult, setCodeResult] = useState([]); - const [loading, setLoading] = useState(false); - const [open, setOpen] = useState(false); const { toast } = useToast(); - async function onOpenChange(open: boolean) { + const [open, setOpen] = useState(false); + const [loading, setLoading] = useState(false); + const [codeDiffs, setCodeDiffs] = useState([]); + + async function handleOpenChange(open: boolean) { setOpen(open); if (open) { const res = await editorEngine.code.generateCodeDiffs(); - setCodeResult(res); + setCodeDiffs(res); } } - function openCodeBlock(templateNode: TemplateNode) { - editorEngine.code.viewInEditor(templateNode); + function viewSource(templateNode: TemplateNode) { + editorEngine.code.viewSource(templateNode); } function handleWriteSucceeded() { setLoading(false); setOpen(false); - setCodeResult([]); + setCodeDiffs([]); editorEngine.webviews.getAll().forEach((webview) => { webview.send(WebviewChannels.CLEAR_STYLE_SHEET); }); toast({ title: 'Write successful!', - description: `${codeResult.length} change(s) written to codebase`, + description: `${codeDiffs.length} change(s) written to codebase`, + }); + } + + function handleWriteFailed() { + setLoading(false); + toast({ + title: 'Write failed!', + description: 'Failed to write changes to codebase', }); } async function writeCodeBlock() { setLoading(true); - const res = await window.api.invoke(MainChannels.WRITE_CODE_BLOCK, codeResult); - handleWriteSucceeded(); + const res = await window.api.invoke(MainChannels.WRITE_CODE_BLOCKS, codeDiffs); + if (res) { + handleWriteSucceeded(); + } else { + handleWriteFailed(); + } } return ( - + @@ -110,7 +131,11 @@ const PublishModal = observer(() => { ))} - ); }); + export default PublishModal; diff --git a/app/src/routes/project/SharePopover/index.tsx b/app/src/routes/project/SharePopover/index.tsx index 5018621b4..a9d92a988 100644 --- a/app/src/routes/project/SharePopover/index.tsx +++ b/app/src/routes/project/SharePopover/index.tsx @@ -5,7 +5,7 @@ import { GlobeIcon } from '@radix-ui/react-icons'; import { useEffect, useState } from 'react'; import { useEditorEngine } from '..'; import { MainChannels } from '/common/constants'; -import { TunnelResult } from '/common/models'; +import { TunnelResult } from '/common/models/tunnel'; export default function SharePopover() { const editorEngine = useEditorEngine(); diff --git a/app/src/routes/project/TopBar/index.tsx b/app/src/routes/project/TopBar/index.tsx index 24e40e8b7..565c272b3 100644 --- a/app/src/routes/project/TopBar/index.tsx +++ b/app/src/routes/project/TopBar/index.tsx @@ -7,7 +7,7 @@ import PublishModal from '../PublishModal'; import SharePopover from '../SharePopover'; import ModeToggle from './ModeToggle'; import { decodeTemplateNode } from '/common/helpers/template'; -import { TemplateNode } from '/common/models'; +import { TemplateNode } from '/common/models/element/templateNode'; const EditorTopBar = observer(() => { const editorEngine = useEditorEngine(); @@ -27,7 +27,7 @@ const EditorTopBar = observer(() => { function openCodeBlock() { if (selectedNode) { - editorEngine.code.viewInEditor(selectedNode); + editorEngine.code.viewSource(selectedNode); } } diff --git a/demos/next/components/ui/card.tsx b/demos/next/components/ui/card.tsx index afa13ecfa..a0e3a3faa 100644 --- a/demos/next/components/ui/card.tsx +++ b/demos/next/components/ui/card.tsx @@ -76,4 +76,4 @@ const CardFooter = React.forwardRef< )) CardFooter.displayName = "CardFooter" -export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } +export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } diff --git a/plugins/babel/README.md b/plugins/babel/README.md index d3d51e040..d7089a036 100644 --- a/plugins/babel/README.md +++ b/plugins/babel/README.md @@ -1,4 +1,4 @@ -# Onlook svelte preprocessor +# Onlook React Babel preprocessor ## Usage @@ -32,7 +32,7 @@ npm install -D babel-loader @babel/core @babel/preset-env webpack @onlook/babel- module: { rules: [ { - test: /\.(?:js|mjs|cjs)$/, + test: /\.(?:js|mjs|cjs|ts|tsx|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', @@ -56,6 +56,8 @@ If it doesn't exists, create a `.babelrc` file and add the onlook plugin. } ``` +4. Run the project normally + ## Using with Create react app To use with Create React App, access to webpack configuration is required to add the preprocessor. This requires either [ejecting the app](https://create-react-app.dev/docs/available-scripts/#npm-run-eject) or using `react-app-rewired`.