From 2a898f57a47b4d6717c187f7e161be56dd216c53 Mon Sep 17 00:00:00 2001 From: Patryk Zdunowski Date: Wed, 22 Apr 2026 01:32:32 +0200 Subject: [PATCH 1/3] feat(studio): initial commit - vscode workbench --- apps/studio/index.html | 13 + apps/studio/package.json | 70 + apps/studio/src/App.tsx | 133 ++ apps/studio/src/components/Sash.tsx | 33 + apps/studio/src/features/ai.ts | 115 ++ apps/studio/src/hooks/useResizable.ts | 60 + apps/studio/src/main.tsx | 10 + apps/studio/src/setup.ts | 266 +++ apps/studio/src/style.css | 88 + apps/studio/src/types.d.ts | 6 + apps/studio/tsconfig.json | 17 + apps/studio/vite.config.ts | 70 + pnpm-lock.yaml | 2368 ++++++++++++++++++++++--- pnpm-workspace.yaml | 1 + 14 files changed, 3001 insertions(+), 249 deletions(-) create mode 100644 apps/studio/index.html create mode 100644 apps/studio/package.json create mode 100644 apps/studio/src/App.tsx create mode 100644 apps/studio/src/components/Sash.tsx create mode 100644 apps/studio/src/features/ai.ts create mode 100644 apps/studio/src/hooks/useResizable.ts create mode 100644 apps/studio/src/main.tsx create mode 100644 apps/studio/src/setup.ts create mode 100644 apps/studio/src/style.css create mode 100644 apps/studio/src/types.d.ts create mode 100644 apps/studio/tsconfig.json create mode 100644 apps/studio/vite.config.ts diff --git a/apps/studio/index.html b/apps/studio/index.html new file mode 100644 index 00000000..7e7b46db --- /dev/null +++ b/apps/studio/index.html @@ -0,0 +1,13 @@ + + + + + + xyd studio + + + +
+ + + diff --git a/apps/studio/package.json b/apps/studio/package.json new file mode 100644 index 00000000..2e095323 --- /dev/null +++ b/apps/studio/package.json @@ -0,0 +1,70 @@ +{ + "name": "@xyd-js/studio", + "version": "0.0.0-prealpha.1", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@codingame/monaco-vscode-ai-service-override": "~30.0.1", + "@codingame/monaco-vscode-api": "~30.0.1", + "@codingame/monaco-vscode-chat-service-override": "~30.0.1", + "@codingame/monaco-vscode-configuration-service-override": "~30.0.1", + "@codingame/monaco-vscode-editor-service-override": "~30.0.1", + "@codingame/monaco-vscode-extensions-service-override": "~30.0.1", + "@codingame/monaco-vscode-extension-gallery-service-override": "~30.0.1", + "@codingame/monaco-vscode-files-service-override": "~30.0.1", + "@codingame/monaco-vscode-keybindings-service-override": "~30.0.1", + "@codingame/monaco-vscode-language-detection-worker-service-override": "~30.0.1", + "@codingame/monaco-vscode-languages-service-override": "~30.0.1", + "@codingame/monaco-vscode-lifecycle-service-override": "~30.0.1", + "@codingame/monaco-vscode-localization-service-override": "~30.0.1", + "@codingame/monaco-vscode-model-service-override": "~30.0.1", + "@codingame/monaco-vscode-notifications-service-override": "~30.0.1", + "@codingame/monaco-vscode-quickaccess-service-override": "~30.0.1", + "@codingame/monaco-vscode-search-service-override": "~30.0.1", + "@codingame/monaco-vscode-snippets-service-override": "~30.0.1", + "@codingame/monaco-vscode-storage-service-override": "~30.0.1", + "@codingame/monaco-vscode-textmate-service-override": "~30.0.1", + "@codingame/monaco-vscode-theme-defaults-default-extension": "~30.0.1", + "@codingame/monaco-vscode-theme-service-override": "~30.0.1", + "@codingame/monaco-vscode-views-service-override": "~30.0.1", + "@codingame/monaco-vscode-workbench-service-override": "~30.0.1", + "@codingame/monaco-vscode-explorer-service-override": "~30.0.1", + "@codingame/monaco-vscode-terminal-service-override": "~30.0.1", + "@codingame/monaco-vscode-view-status-bar-service-override": "~30.0.1", + "@codingame/monaco-vscode-view-title-bar-service-override": "~30.0.1", + "@codingame/monaco-vscode-view-banner-service-override": "~30.0.1", + "@codingame/monaco-vscode-output-service-override": "~30.0.1", + "@codingame/monaco-vscode-markers-service-override": "~30.0.1", + "@codingame/monaco-vscode-log-service-override": "~30.0.1", + "@codingame/monaco-vscode-dialogs-service-override": "~30.0.1", + "@codingame/monaco-vscode-environment-service-override": "~30.0.1", + "@codingame/monaco-vscode-javascript-default-extension": "~30.0.1", + "@codingame/monaco-vscode-typescript-basics-default-extension": "~30.0.1", + "@codingame/monaco-vscode-json-default-extension": "~30.0.1", + "@codingame/monaco-vscode-css-default-extension": "~30.0.1", + "@codingame/monaco-vscode-html-default-extension": "~30.0.1", + "@codingame/monaco-vscode-markdown-basics-default-extension": "~30.0.1", + "@codingame/monaco-vscode-yaml-default-extension": "~30.0.1", + "@codingame/monaco-vscode-standalone-languages": "~30.0.1", + "@codingame/monaco-vscode-standalone-typescript-language-features": "~30.0.1", + "@codingame/monaco-vscode-standalone-json-language-features": "~30.0.1", + "@codingame/monaco-vscode-standalone-css-language-features": "~30.0.1", + "@codingame/monaco-vscode-standalone-html-language-features": "~30.0.1", + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~30.0.1", + "vscode": "npm:@codingame/monaco-vscode-extension-api@~30.0.1", + "react": "^19.1.0", + "react-dom": "^19.1.0" + }, + "devDependencies": { + "@types/react": "^19.1.2", + "@types/react-dom": "^19.1.2", + "@vitejs/plugin-react": "^6.0.1", + "typescript": "^5.6.2", + "vite": "^8.0.9" + } +} diff --git a/apps/studio/src/App.tsx b/apps/studio/src/App.tsx new file mode 100644 index 00000000..19ddb381 --- /dev/null +++ b/apps/studio/src/App.tsx @@ -0,0 +1,133 @@ +import { useEffect, useRef, useState } from 'react' +import { + attachPart, + renderEditorPart, + renderSidebarPart, + renderStatusBarPart, + renderPanelPart, + renderActivitybarPar, + renderAuxiliaryPart, + Parts, +} from '@codingame/monaco-vscode-views-service-override' +import { getService, ICommandService } from '@codingame/monaco-vscode-api/services' +import { ensureServicesInitialized, monaco } from './setup' +import { registerAiChat } from './features/ai' +import { useResizable } from './hooks/useResizable' +import { Sash } from './components/Sash' + +// Theme defaults +import '@codingame/monaco-vscode-theme-defaults-default-extension' + +// Language extensions +import '@codingame/monaco-vscode-javascript-default-extension' +import '@codingame/monaco-vscode-typescript-basics-default-extension' +import '@codingame/monaco-vscode-json-default-extension' +import '@codingame/monaco-vscode-css-default-extension' +import '@codingame/monaco-vscode-html-default-extension' +import '@codingame/monaco-vscode-markdown-basics-default-extension' +import '@codingame/monaco-vscode-yaml-default-extension' + +// Standalone language features +import '@codingame/monaco-vscode-standalone-typescript-language-features' +import '@codingame/monaco-vscode-standalone-json-language-features' +import '@codingame/monaco-vscode-standalone-css-language-features' +import '@codingame/monaco-vscode-standalone-html-language-features' + +export function App() { + const [ready, setReady] = useState(false) + const [error, setError] = useState(null) + + const titlebarRef = useRef(null) + const activitybarRef = useRef(null) + const sidebarRef = useRef(null) + const editorRef = useRef(null) + const panelRef = useRef(null) + const auxiliarybarRef = useRef(null) + const statusbarRef = useRef(null) + + const sidebarResize = useResizable('horizontal', sidebarRef, { min: 100, max: 600 }) + const panelResize = useResizable('vertical', panelRef, { min: 50, max: 600, invert: true }) + const auxiliaryResize = useResizable('horizontal', auxiliarybarRef, { min: 100, max: 600, invert: true }) + + useEffect(() => { + let disposed = false + + ;(async () => { + try { + await ensureServicesInitialized() + if (disposed) return + await registerAiChat() + setReady(true) + } catch (e: any) { + console.error('[xyd studio] init failed:', e) + setError(e.message || String(e)) + } + })() + + return () => { disposed = true } + }, []) + + useEffect(() => { + if (!ready) return + + const disposables: Array<{ dispose(): void }> = [] + + const tryRender = (name: string, fn: () => { dispose(): void } | void) => { + try { + const d = fn() + if (d) disposables.push(d) + } catch (e) { + console.warn(`[xyd studio] ${name} failed:`, e) + } + } + + tryRender('titlebar', () => attachPart(Parts.TITLEBAR_PART, titlebarRef.current!)) + tryRender('activitybar', () => renderActivitybarPar(activitybarRef.current!)) + tryRender('sidebar', () => renderSidebarPart(sidebarRef.current!)) + tryRender('editor', () => renderEditorPart(editorRef.current!)) + tryRender('panel', () => renderPanelPart(panelRef.current!)) + tryRender('auxiliarybar', () => renderAuxiliaryPart(auxiliarybarRef.current!)) + tryRender('statusbar', () => renderStatusBarPart(statusbarRef.current!)) + + // Open explorer and default file + ;(async () => { + try { + const commandService = await getService(ICommandService) + await commandService.executeCommand('workbench.view.explorer') + await commandService.executeCommand( + 'vscode.open', + monaco.Uri.file('/workspace/docs.json') + ) + } catch (e) { + console.warn('[xyd studio] Failed to open explorer/file:', e) + } + })() + + return () => { + disposables.forEach((d) => d.dispose()) + } + }, [ready]) + + if (error) { + return
{error}
+ } + + return ( +
+
+
+
+