Skip to content

Commit

Permalink
Resolve merge conflicts and expand layout section when flex or grid i…
Browse files Browse the repository at this point in the history
…s selected
  • Loading branch information
Alexandre Antunes Mendes committed Nov 15, 2024
2 parents 08883f2 + 0efefa7 commit 9ce03d3
Show file tree
Hide file tree
Showing 36 changed files with 909 additions and 249 deletions.
13 changes: 8 additions & 5 deletions apps/studio/electron/main/code/diff/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ export function addClassToNode(node: t.JSXElement, className: string): void {
classNameAttr.value.expression.arguments.push(t.stringLiteral(className));
}
} else {
const newClassNameAttr = t.jsxAttribute(
t.jsxIdentifier('className'),
t.stringLiteral(className),
);
openingElement.attributes.push(newClassNameAttr);
insertAttribute(openingElement, 'className', className);
}
}

Expand All @@ -33,5 +29,12 @@ export function replaceNodeClasses(node: t.JSXElement, className: string): void

if (classNameAttr) {
classNameAttr.value = t.stringLiteral(className);
} else {
insertAttribute(openingElement, 'className', className);
}
}

function insertAttribute(element: t.JSXOpeningElement, attribute: string, className: string): void {
const newClassNameAttr = t.jsxAttribute(t.jsxIdentifier(attribute), t.stringLiteral(className));
element.attributes.push(newClassNameAttr);
}
8 changes: 4 additions & 4 deletions apps/studio/electron/main/code/diff/transform.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import traverse, { type NodePath } from '@babel/traverse';
import type * as t from '@babel/types';
import { type CodeAction, CodeActionType } from '@onlook/models/actions';
import type { CodeDiffRequest } from '@onlook/models/code';
import type { TemplateNode } from '@onlook/models/element';
import { getTemplateNode } from '../templateNode';
import { groupElementsInNode, ungroupElementsInNode } from './group';
import { addKeyToElement, createHashedTemplateToCodeDiff, hashTemplateNode } from './helpers';
Expand All @@ -9,9 +12,6 @@ import { removeElementFromNode } from './remove';
import { addClassToNode, replaceNodeClasses } from './style';
import { updateNodeTextContent } from './text';
import { assertNever } from '/common/helpers';
import { type CodeAction, CodeActionType } from '@onlook/models/actions';
import type { CodeDiffRequest } from '@onlook/models/code';
import type { TemplateNode } from '@onlook/models/element';

export function transformAst(
ast: t.File,
Expand All @@ -26,7 +26,7 @@ export function transformAst(
const codeDiffRequest = hashedTemplateToCodeDiff.get(hashedKey);

if (codeDiffRequest) {
if (codeDiffRequest.attributes && codeDiffRequest.attributes.className) {
if (codeDiffRequest.attributes && codeDiffRequest.attributes.className !== null) {
if (codeDiffRequest.overrideClasses) {
replaceNodeClasses(path.node, codeDiffRequest.attributes.className);
} else {
Expand Down
6 changes: 3 additions & 3 deletions apps/studio/electron/main/events/code.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import type { CodeDiff, CodeDiffRequest } from '@onlook/models/code';
import { MainChannels } from '@onlook/models/constants';
import type { TemplateNode } from '@onlook/models/element';
import { ipcMain } from 'electron';
import { openInIde, pickDirectory, readCodeBlock, readCodeBlocks, writeCode } from '../code/';
import { getTemplateNodeClass } from '../code/classes';
Expand All @@ -6,9 +9,6 @@ import { extractComponentsFromDirectory } from '../code/components';
import { getCodeDiffs } from '../code/diff';
import { readFile } from '../code/files';
import { getTemplateNodeChild } from '../code/templateNode';
import { MainChannels } from '@onlook/models/constants';
import type { CodeDiff, CodeDiffRequest } from '@onlook/models/code';
import type { TemplateNode } from '@onlook/models/element';

export function listenForCodeMessages() {
ipcMain.handle(MainChannels.VIEW_SOURCE_CODE, (e: Electron.IpcMainInvokeEvent, args) => {
Expand Down
5 changes: 5 additions & 0 deletions apps/studio/electron/main/events/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { MainChannels } from '@onlook/models/constants';
import { WindowCommand } from '@onlook/models/projects';
import { BrowserWindow, ipcMain, shell } from 'electron';
import { mainWindow } from '..';
import { checkSystemRequirements } from '../requirements';
import { imageStorage } from '../storage/images';
import { updater } from '../update';
import { listenForAnalyticsMessages } from './analytics';
Expand All @@ -26,6 +27,10 @@ function listenForGeneralMessages() {
return mainWindow?.reload();
});

ipcMain.handle(MainChannels.CHECK_REQUIREMENTS, () => {
return checkSystemRequirements();
});

ipcMain.handle(
MainChannels.OPEN_IN_EXPLORER,
(e: Electron.IpcMainInvokeEvent, args: string) => {
Expand Down
31 changes: 31 additions & 0 deletions apps/studio/electron/main/requirements/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { RequirementsResponse } from '@onlook/models/requirements';
import { execSync } from 'child_process';

export function checkSystemRequirements(): RequirementsResponse {
return {
git: checkGitInstallation(),
node: checkNodeInstallation(),
};
}

// Note: Test by passing empty PATH
// execSync('git --version', { stdio: 'ignore', env: { ...process.env, PATH: '' }});

function checkGitInstallation(): boolean {
try {
execSync('git --version', { stdio: 'ignore' });
return true;
} catch (error) {
console.error('Git check failed:', error);
return false;
}
}

function checkNodeInstallation(): boolean {
try {
execSync('node --version', { stdio: 'ignore' });
return true;
} catch (error) {
return false;
}
}
2 changes: 1 addition & 1 deletion apps/studio/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"productName": "Onlook",
"name": "@onlook/studio",
"version": "0.0.55",
"version": "0.0.57",
"homepage": "https://onlook.dev",
"main": "dist-electron/main/index.js",
"description": "The first-ever devtool for designers",
Expand Down
4 changes: 4 additions & 0 deletions apps/studio/src/components/Context/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AuthManager } from '@/lib/auth';
import { EditorEngine } from '@/lib/editor/engine';
import { ProjectsManager } from '@/lib/projects';
import { RequirementsManager } from '@/lib/requirements';
import { RouteManager } from '@/lib/routes';
import { UpdateManager } from '@/lib/update';
import { createContext, useContext } from 'react';
Expand All @@ -10,15 +11,18 @@ const routeManager = new RouteManager();
const projectsManager = new ProjectsManager();
const editorEngine = new EditorEngine(projectsManager);
const updateManager = new UpdateManager();
const requirementsManager = new RequirementsManager();

const AuthContext = createContext(authManager);
const RouteContext = createContext(routeManager);
const ProjectsContext = createContext(projectsManager);
const EditorEngineContext = createContext(editorEngine);
const UpdateContext = createContext(updateManager);
const RequirementsContext = createContext(requirementsManager);

export const useAuthManager = () => useContext(AuthContext);
export const useRouteManager = () => useContext(RouteContext);
export const useProjectsManager = () => useContext(ProjectsContext);
export const useEditorEngine = () => useContext(EditorEngineContext);
export const useUpdateManager = () => useContext(UpdateContext);
export const useRequirementsManager = () => useContext(RequirementsContext);
19 changes: 19 additions & 0 deletions apps/studio/src/components/ui/dunes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import dunesDark from '@/assets/dunes-login-dark.png';
import dunesLight from '@/assets/dunes-login-light.png';

export function Dunes() {
return (
<div className="hidden w-full lg:block md:block m-6">
<img
className="w-full h-full object-cover rounded-xl hidden dark:flex"
src={dunesDark}
alt="Onlook dunes dark"
/>
<img
className="w-full h-full object-cover rounded-xl flex dark:hidden"
src={dunesLight}
alt="Onlook dunes light"
/>
</div>
);
}
5 changes: 1 addition & 4 deletions apps/studio/src/lib/editor/engine/chat/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,5 @@ function getTemplateNodeString(templateNode: TemplateNode) {
}

function getUserInstructionString(instructions: string) {
return `<instruction>
Please edit the selected code or the entire file following these instructions: \t${instructions}
If you make a change, rewrite the entire file.
</instruction>`;
return `<instruction>Please edit the selected code or the entire file following these instructions: ${instructions}\nIf you make a change, rewrite the entire file.</instruction>`;
}
6 changes: 5 additions & 1 deletion apps/studio/src/lib/editor/engine/code/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { MainChannels, WebviewChannels } from '@onlook/models/constants';
import type { TemplateNode } from '@onlook/models/element';
import { makeAutoObservable } from 'mobx';
import type { EditorEngine } from '..';
import { StyleMode } from '../style';
import { getGroupElement, getUngroupElement } from './group';
import { getOrCreateCodeDiffRequest, getTailwindClassChangeFromStyle } from './helpers';
import { getInsertedElement } from './insert';
Expand Down Expand Up @@ -270,7 +271,10 @@ export class CodeManager {
templateToCodeChange: Map<TemplateNode, CodeDiffRequest>,
): Promise<void> {
for (const change of styleChanges) {
const templateNode = this.editorEngine.ast.getAnyTemplateNode(change.selector);
const templateNode =
this.editorEngine.style.mode === StyleMode.Instance
? this.editorEngine.ast.getInstance(change.selector)
: this.editorEngine.ast.getRoot(change.selector);
if (!templateNode) {
continue;
}
Expand Down
48 changes: 31 additions & 17 deletions apps/studio/src/lib/editor/engine/style/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { makeAutoObservable, reaction } from 'mobx';
import type { EditorEngine } from '..';
import type { Change, StyleActionTarget, UpdateStyleAction } from '@onlook/models/actions';
import type { DomElement } from '@onlook/models/element';
import { makeAutoObservable, reaction } from 'mobx';
import type { EditorEngine } from '..';

export interface SelectedStyle {
styles: Record<string, string>;
parentRect: DOMRect;
rect: DOMRect;
}

export enum StyleMode {
Instance = 'instance',
Root = 'root',
}

export class StyleManager {
selectedStyle: SelectedStyle | null = null;
selectorToStyle: Map<string, SelectedStyle> = new Map();
private selectedElementsDisposer: () => void;
prevSelectedSignature: string = '';
mode: StyleMode = StyleMode.Root;

constructor(private editorEngine: EditorEngine) {
makeAutoObservable(this);
Expand All @@ -35,21 +42,19 @@ export class StyleManager {
selected = selected.filter((el) => selectors.includes(el.selector));
}

const targets: Array<StyleActionTarget> = this.editorEngine.elements.selected.map(
(selectedEl) => {
const change: Change<string> = {
updated: value,
original: selectedEl.styles[style],
};
const target: StyleActionTarget = {
webviewId: selectedEl.webviewId,
selector: selectedEl.selector,
change: change,
uuid: selectedEl.uuid,
};
return target;
},
);
const targets: Array<StyleActionTarget> = selected.map((selectedEl) => {
const change: Change<string> = {
updated: value,
original: selectedEl.styles[style],
};
const target: StyleActionTarget = {
webviewId: selectedEl.webviewId,
selector: selectedEl.selector,
change: change,
uuid: selectedEl.uuid,
};
return target;
});
return {
type: 'update-style',
targets: targets,
Expand All @@ -75,6 +80,15 @@ export class StyleManager {
}

private onSelectedElementsChanged(selectedElements: DomElement[]) {
const newSelected = selectedElements
.map((el) => el.selector)
.toSorted()
.join();
if (newSelected !== this.prevSelectedSignature) {
this.mode = StyleMode.Root;
}
this.prevSelectedSignature = newSelected;

if (selectedElements.length === 0) {
this.selectorToStyle = new Map();
return;
Expand Down
4 changes: 2 additions & 2 deletions apps/studio/src/lib/editor/styles/autolayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export function parseModeAndValue(value: string): {
mode: LayoutMode;
layoutValue: string;
} {
if (value === 'fit-content') {
return { mode: LayoutMode.Fit, layoutValue: value };
if (value === 'fit-content' || value === 'auto' || value === '') {
return { mode: LayoutMode.Fit, layoutValue: '' };
}
if (value === '100%' || value === 'auto') {
return { mode: LayoutMode.Fill, layoutValue: '100%' };
Expand Down
1 change: 1 addition & 0 deletions apps/studio/src/lib/editor/styles/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export const LayoutGroup = [
// Gap control for spacing
new SingleStyleImpl('gap', '0px', 'Gap', StyleType.Number, {
units: ELEMENT_STYLE_UNITS,
min: 0,
max: 1000,
}),
],
Expand Down
11 changes: 5 additions & 6 deletions apps/studio/src/lib/editor/styles/numberUnit.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { toast } from '@onlook/ui/use-toast';
import type { SingleStyle } from '@/lib/editor/styles/models';
import { toast } from '@onlook/ui/use-toast';

export function stringToParsedValue(
val: string,
Expand All @@ -17,8 +17,8 @@ export function stringToParsedValue(
return { numberVal: num.toString(), unitVal: unit };
}

export function parsedValueToString(floatValue: number | string, unit: string): string {
return `${floatValue}${unit}`;
export function parsedValueToString(num: string, unit: string): string {
return `${num}${unit}`;
}

export const getDefaultUnit = (unit: string): string => {
Expand Down Expand Up @@ -47,8 +47,8 @@ export const handleNumberInputKeyDown = (
const step = e.shiftKey ? 10 : 1;
const delta = e.key === 'ArrowUp' ? step : -step;

const newNumber = Number.parseInt(numberVal) + delta;
const newValue = parsedValueToString(newNumber, newUnit);
const newNumber = parseFloat(numberVal) + delta;
const newValue = parsedValueToString(newNumber.toString(), newUnit);
const { min, max } = elementStyle.params || {};

if (min !== undefined && newNumber < min) {
Expand All @@ -68,7 +68,6 @@ export const handleNumberInputKeyDown = (
});
return;
}

setValue(newValue);
sendStyleUpdate(newValue);
}
Expand Down
48 changes: 48 additions & 0 deletions apps/studio/src/lib/requirements/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { MainChannels } from '@onlook/models/constants';
import type { RequirementsResponse } from '@onlook/models/requirements';
import { makeAutoObservable } from 'mobx';
import { invokeMainChannel } from '../utils';

export class RequirementsManager {
nodeEnabled: boolean | null = null;
gitEnabled: boolean | null = null;
interval: Timer | null = null;

constructor() {
makeAutoObservable(this);
this.listen();
}

get loaded() {
return this.nodeEnabled !== null && this.gitEnabled !== null;
}

get requirementsMet() {
return this.nodeEnabled && this.gitEnabled;
}

async listen() {
this.checkRequirements();
this.interval = setInterval(() => {
this.checkRequirements();
}, 3000);
}

async checkRequirements() {
if (this.requirementsMet && this.interval) {
clearInterval(this.interval);
return;
}
const requirements: RequirementsResponse | null = await invokeMainChannel(
MainChannels.CHECK_REQUIREMENTS,
);

if (!requirements) {
console.error('Failed to check requirements');
return;
}

this.nodeEnabled = requirements.node;
this.gitEnabled = requirements.git;
}
}
1 change: 1 addition & 0 deletions apps/studio/src/lib/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export enum Route {
EDITOR = 'editor',
SIGN_IN = 'signin',
PROJECTS = 'projects',
REQUIREMENTS = 'requirements',
}

export class RouteManager {
Expand Down
Loading

0 comments on commit 9ce03d3

Please sign in to comment.