Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions apps/web/src/pods/toolbar/components/new-button/new-button.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import { NewIcon } from '#common/components/icons/new-button.components';
import classes from '#pods/toolbar/toolbar.pod.module.css';
import { isVSCodeEnv } from '#common/utils/env.utils';
import { sendToExtension } from '#common/utils/vscode-bridge.utils';
import { useCanvasContext } from '#core/providers';
import { ToolbarButton } from '../toolbar-button';
import classes from '#pods/toolbar/toolbar.pod.module.css';
import { APP_MESSAGE_TYPE } from '@lemoncode/quickmock-bridge-protocol';
import { SHORTCUTS } from '../../shortcut/shortcut.const';
import { ToolbarButton } from '../toolbar-button';

export const NewButton = () => {
const { createNewFullDocument: clearCanvas } = useCanvasContext();

const handleClick = () => {
if (isVSCodeEnv()) {
sendToExtension({ type: APP_MESSAGE_TYPE.NEW_FILE });
return;
}
clearCanvas();
};

Expand Down
1 change: 1 addition & 0 deletions packages/bridge-protocol/src/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export const APP_MESSAGE_TYPE = {
SAVE: 'qm:save',
RENDER_COMPLETE: 'qm:render-complete',
WEBVIEW_READY: 'WEBVIEW_READY',
NEW_FILE: 'qm:new-file',
} as const;
3 changes: 2 additions & 1 deletion packages/bridge-protocol/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export type AppMessage =
| {
type: typeof APP_MESSAGE_TYPE.RENDER_COMPLETE;
payload?: ContentBbox;
};
}
| { type: typeof APP_MESSAGE_TYPE.NEW_FILE };

export type PayloadOf<U extends { type: string }, T extends U['type']> =
Extract<U, { type: T }> extends { payload: infer P } ? P : undefined;
10 changes: 10 additions & 0 deletions packages/vscode-extension/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# @lemoncode/quickmock-vscode-extension

## 0.2.0

### Minor Changes

- 3cd4892: Toolbar's **New** button now creates a real `.qm` file when running inside the VS Code extension instead of just clearing the canvas.

### Patch Changes

- b7f9cf1: Fix editor failing to load files opened from outside the workspace. The webview HTML was assigned before registering `onDidReceiveMessage`, causing a race where the initial `READY` / `WEBVIEW_READY` message from the app could be lost and the file content never delivered. The listener is now registered before the HTML assignment.

## 0.1.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/vscode-extension/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "quickmock",
"version": "0.1.0",
"version": "0.2.0",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
Expand Down
11 changes: 0 additions & 11 deletions packages/vscode-extension/src/commands/new-wireframe.ts

This file was deleted.

2 changes: 2 additions & 0 deletions packages/vscode-extension/src/commands/new-wireframe/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './new-wireframe.id';
export * from './new-wireframe.command';
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as vscode from 'vscode';
import { QUICKMOCK_NEW_WIREFRAME_COMMAND_ID } from './new-wireframe.id';
import { handleNewWireframe } from './new-wireframe.handler';

export const registerNewWireframeCommand = (
context: vscode.ExtensionContext
): void => {
context.subscriptions.push(
vscode.commands.registerCommand(
QUICKMOCK_NEW_WIREFRAME_COMMAND_ID,
handleNewWireframe
)
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { getPrimaryWorkspaceFolder } from '#core';
import { writeFile } from '#editor/document';
import * as vscode from 'vscode';
import {
createEmptyQuickMockContent,
DEFAULT_QUICKMOCK_FILE_NAME,
QUICKMOCK_FILE_EXTENSION,
} from './new-wireframe.template';

const CUSTOM_EDITOR_VIEW_TYPE = 'quickmock.editor';

const pickSaveTarget = async (): Promise<vscode.Uri | undefined> => {
const folder = getPrimaryWorkspaceFolder();
const defaultUri = folder
? vscode.Uri.joinPath(folder.uri, DEFAULT_QUICKMOCK_FILE_NAME)
: undefined;

return vscode.window.showSaveDialog({
defaultUri,
filters: { 'QuickMock Wireframe': [QUICKMOCK_FILE_EXTENSION] },
saveLabel: 'Create',
title: 'Create QuickMock File',
});
};

export const handleNewWireframe = async (): Promise<void> => {
const target = await pickSaveTarget();
if (!target) return;

try {
await writeFile(target, createEmptyQuickMockContent());
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
vscode.window.showErrorMessage(
`Failed to create QuickMock file: ${message}`
);
return;
}

await vscode.commands.executeCommand(
'vscode.openWith',
target,
CUSTOM_EDITOR_VIEW_TYPE
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const QUICKMOCK_NEW_WIREFRAME_COMMAND_ID = 'quickmock.newWireframe';
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const TEMPLATE_VERSION = '0.1';
const DEFAULT_CANVAS_SIZE = { width: 1920, height: 1080 };

export const QUICKMOCK_FILE_EXTENSION = 'qm';
export const DEFAULT_QUICKMOCK_FILE_NAME = `untitled.${QUICKMOCK_FILE_EXTENSION}`;

export const createEmptyQuickMockContent = (): string =>
JSON.stringify(
{
version: TEMPLATE_VERSION,
pages: [{ id: 'page-1', name: 'Page 1', shapes: [] }],
customColors: [],
size: DEFAULT_CANVAS_SIZE,
},
null,
2
);
6 changes: 6 additions & 0 deletions packages/vscode-extension/src/editor/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
HOST_MESSAGE_TYPE,
type HostMessage,
} from '@lemoncode/quickmock-bridge-protocol';
import * as vscode from 'vscode';
import { QUICKMOCK_NEW_WIREFRAME_COMMAND_ID } from '#commands';
import { type QuickMockDocument, writeFile } from './document';

type PostMessageFn = (msg: HostMessage) => void;
Expand Down Expand Up @@ -41,5 +43,9 @@ export const handleWebviewMessage = async (
await writeFile(doc.uri, doc.content);
postMessage({ type: HOST_MESSAGE_TYPE.SAVED });
break;

case APP_MESSAGE_TYPE.NEW_FILE:
await vscode.commands.executeCommand(QUICKMOCK_NEW_WIREFRAME_COMMAND_ID);
break;
}
};
11 changes: 6 additions & 5 deletions packages/vscode-extension/src/editor/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,19 @@ export class QuickMockEditorProvider implements vscode.CustomEditorProvider<Quic
enableScripts: true,
localResourceRoots: [this.extensionUri],
};
panel.webview.html = getHtml(
panel.webview,
this.extensionUri,
getEditorAppUrl()
);

panel.webview.onDidReceiveMessage(async (msg: AppMessage) => {
await handleWebviewMessage(msg, doc, reply =>
panel.webview.postMessage(reply satisfies HostMessage)
);
documentRegistry.set(doc.uri.fsPath, doc.content);
});

panel.webview.html = getHtml(
panel.webview,
this.extensionUri,
getEditorAppUrl()
);
}

private broadcast(doc: QuickMockDocument, msg: HostMessage): void {
Expand Down
Loading