From f9699d174c24a96258d404046f5fa87a682c93a4 Mon Sep 17 00:00:00 2001 From: Jess Frazelle Date: Sun, 25 Aug 2024 12:56:11 -0700 Subject: [PATCH] header changes and open new window for double click in finder macos (#3652) * header changes and open new window for double click in finder macos Signed-off-by: Jess Frazelle * cleanup Signed-off-by: Jess Frazelle * add protocols Signed-off-by: Jess Frazelle * updates Signed-off-by: Jess Frazelle * extend with info.plist Signed-off-by: Jess Frazelle * fixes Signed-off-by: Jess Frazelle --------- Signed-off-by: Jess Frazelle --- Info.plist | 344 ++++++++++++++++++++++++++ forge.config.ts | 7 + src/components/AppHeader.module.css | 17 ++ src/components/ProjectSidebarMenu.tsx | 11 +- src/main.ts | 85 +++++-- 5 files changed, 440 insertions(+), 24 deletions(-) create mode 100644 Info.plist diff --git a/Info.plist b/Info.plist new file mode 100644 index 000000000..1c4eea6ce --- /dev/null +++ b/Info.plist @@ -0,0 +1,344 @@ + + + + + CFBundleDocumentTypes + + + LSItemContentTypes + + dev.zoo.kcl + + CFBundleTypeName + KCL + CFBundleTypeRole + Editor + LSTypeIsPackage + + LSHandlerRank + Owner + + + LSItemContentTypes + + dev.zoo.toml + + CFBundleTypeName + TOML + CFBundleTypeRole + Editor + LSTypeIsPackage + + LSHandlerRank + Default + + + LSItemContentTypes + + dev.zoo.gltf + + CFBundleTypeName + glTF + CFBundleTypeRole + Editor + LSTypeIsPackage + + LSHandlerRank + Default + + + LSItemContentTypes + + dev.zoo.glb + + CFBundleTypeName + glb + CFBundleTypeRole + Editor + LSTypeIsPackage + + LSHandlerRank + Default + + + LSItemContentTypes + + dev.zoo.step + + CFBundleTypeName + STEP + CFBundleTypeRole + Editor + LSTypeIsPackage + + LSHandlerRank + Default + + + LSItemContentTypes + + dev.zoo.fbx + + CFBundleTypeName + FBX + CFBundleTypeRole + Editor + LSTypeIsPackage + + LSHandlerRank + Default + + + LSItemContentTypes + + dev.zoo.sldprt + + CFBundleTypeName + Solidworks Part + CFBundleTypeRole + Viewer + LSTypeIsPackage + + LSHandlerRank + Default + + + LSItemContentTypes + + public.geometry-definition-format + + CFBundleTypeName + OBJ + CFBundleTypeRole + Editor + LSTypeIsPackage + + LSHandlerRank + Default + + + LSItemContentTypes + + public.polygon-file-format + + CFBundleTypeName + PLY + CFBundleTypeRole + Editor + LSTypeIsPackage + + LSHandlerRank + Default + + + LSItemContentTypes + + public.standard-tesselated-geometry-format + + CFBundleTypeName + STL + CFBundleTypeRole + Editor + LSTypeIsPackage + + LSHandlerRank + Default + + + LSItemContentTypes + + public.folder + + CFBundleTypeName + Folders + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + + + UTExportedTypeDeclarations + + + UTTypeIdentifier + dev.zoo.kcl + UTTypeReferenceURL + https://zoo.dev/docs/kcl + UTTypeConformsTo + + public.source-code + public.data + public.text + public.plain-text + public.3d-content + public.script + + UTTypeDescription + KCL (KittyCAD Language) document + UTTypeTagSpecification + + public.filename-extension + + kcl + + public.mime-type + + text/vnd.zoo.kcl + + + + + UTTypeIdentifier + dev.zoo.gltf + UTTypeReferenceURL + https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html + UTTypeConformsTo + + public.data + public.text + public.plain-text + public.3d-content + public.json + + UTTypeDescription + Graphics Library Transmission Format (glTF) + UTTypeTagSpecification + + public.filename-extension + + gltf + + public.mime-type + + model/gltf+json + + + + + UTTypeIdentifier + dev.zoo.glb + UTTypeReferenceURL + https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html + UTTypeConformsTo + + public.data + public.3d-content + + UTTypeDescription + Graphics Library Transmission Format (glTF) binary + UTTypeTagSpecification + + public.filename-extension + + glb + + public.mime-type + + model/gltf-binary + + + + + UTTypeIdentifier + dev.zoo.step + UTTypeReferenceURL + https://www.loc.gov/preservation/digital/formats/fdd/fdd000448.shtml + UTTypeConformsTo + + public.data + public.3d-content + public.text + public.plain-text + + UTTypeDescription + STEP-file, ISO 10303-21 + UTTypeTagSpecification + + public.filename-extension + + step + stp + + public.mime-type + + model/step + + + + + UTTypeIdentifier + dev.zoo.sldprt + UTTypeReferenceURL + https://docs.fileformat.com/cad/sldprt/ + UTTypeConformsTo + + public.data + public.3d-content + + UTTypeDescription + Solidworks Part + UTTypeTagSpecification + + public.filename-extension + + sldprt + + public.mime-type + + model/vnd.solidworks.sldprt + + + + + UTTypeIdentifier + dev.zoo.fbx + UTTypeReferenceURL + https://en.wikipedia.org/wiki/FBX + UTTypeConformsTo + + public.data + public.3d-content + + UTTypeDescription + Autodesk Filmbox (FBX) format + UTTypeTagSpecification + + public.filename-extension + + fbx + fbxb + + public.mime-type + + model/vnd.autodesk.fbx + + + + + UTTypeIdentifier + dev.zoo.toml + UTTypeReferenceURL + https://toml.io/en/ + UTTypeConformsTo + + public.data + public.text + public.plain-text + + UTTypeDescription + Tom's Obvious Minimal Language + UTTypeTagSpecification + + public.filename-extension + + kcl + + public.mime-type + + text/toml + + + + + + diff --git a/forge.config.ts b/forge.config.ts index 143d29004..53f8b96ea 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -23,6 +23,13 @@ const config: ForgeConfig = { undefined, executableName: 'zoo-modeling-app', icon: path.resolve(rootDir, 'assets', 'icon'), + protocols: [ + { + name: 'Zoo Studio', + schemes: ['zoo-studio'], + }, + ], + extendInfo: 'Info.plist', // Information for file associations. }, rebuildConfig: {}, makers: [ diff --git a/src/components/AppHeader.module.css b/src/components/AppHeader.module.css index 272f2fd90..f986adeaa 100644 --- a/src/components/AppHeader.module.css +++ b/src/components/AppHeader.module.css @@ -4,4 +4,21 @@ */ .header { grid-template-columns: 1fr auto 1fr; + -webkit-app-region: drag; /* Make the header of the app draggable */ +} + +.header button { + -webkit-app-region: no-drag; /* Make the button not draggable */ +} + +.header a { + -webkit-app-region: no-drag; /* Make the link not draggable */ +} + +.header textarea { + -webkit-app-region: no-drag; /* Make the textarea not draggable */ +} + +.header input { + -webkit-app-region: no-drag; /* Make the input not draggable */ } diff --git a/src/components/ProjectSidebarMenu.tsx b/src/components/ProjectSidebarMenu.tsx index 827c33b71..986da7890 100644 --- a/src/components/ProjectSidebarMenu.tsx +++ b/src/components/ProjectSidebarMenu.tsx @@ -25,8 +25,17 @@ const ProjectSidebarMenu = ({ project?: IndexLoaderData['project'] file?: IndexLoaderData['file'] }) => { + // Make room for traffic lights on desktop left side. + // TODO: make sure this doesn't look like shit on Linux or Windows + const trafficLightsOffset = + isDesktop() && window.electron.os.isMac ? 'ml-20' : '' return ( -
+
{enableMenu ? ( diff --git a/src/main.ts b/src/main.ts index 2ccb539d2..8d28a0d36 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,7 +2,7 @@ // template that ElectronJS provides. import dotenv from 'dotenv' -import { app, BrowserWindow, ipcMain, dialog, shell } from 'electron' +import { app, BrowserWindow, protocol, ipcMain, dialog, shell } from 'electron' import path from 'path' import { Issuer } from 'openid-client' import { Bonjour, Service } from 'bonjour-service' @@ -11,6 +11,8 @@ import * as kittycad from '@kittycad/lib/import' import minimist from 'minimist' import getCurrentProjectFile from 'lib/getCurrentProjectFile' +let mainWindow: BrowserWindow | null = null + // Check the command line arguments for a project path const args = parseCLIArgs() @@ -27,12 +29,40 @@ if (require('electron-squirrel-startup')) { app.quit() } -// Global app listeners -// Must be done before ready event -registerListeners() +const ZOO_STUDIO_PROTOCOL = 'zoo-studio' -const createWindow = () => { - const mainWindow = new BrowserWindow({ +/// Register our application to handle all "electron-fiddle://" protocols. +if (process.defaultApp) { + if (process.argv.length >= 2) { + app.setAsDefaultProtocolClient(ZOO_STUDIO_PROTOCOL, process.execPath, [ + path.resolve(process.argv[1]), + ]) + } +} else { + app.setAsDefaultProtocolClient(ZOO_STUDIO_PROTOCOL) +} + +// Register custom schemes with privileges. +protocol.registerSchemesAsPrivileged([ + { + scheme: ZOO_STUDIO_PROTOCOL, + privileges: { + standard: true, + secure: true, + supportFetchAPI: true, + corsEnabled: true, + allowServiceWorkers: true, + codeCache: true, + }, + }, +]) + +// Global app listeners +// Must be done before ready event. +registerStartupListeners() + +const createWindow = (): BrowserWindow => { + const newWindow = new BrowserWindow({ autoHideMenuBar: true, show: false, width: 1800, @@ -44,13 +74,15 @@ const createWindow = () => { preload: path.join(__dirname, './preload.js'), }, icon: path.resolve(process.cwd(), 'assets', 'icon.png'), + frame: false, + titleBarStyle: 'hiddenInset', }) // and load the index.html of the app. if (MAIN_WINDOW_VITE_DEV_SERVER_URL) { - mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL) + newWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL) } else { - mainWindow.loadFile( + newWindow.loadFile( path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`) ) } @@ -58,7 +90,9 @@ const createWindow = () => { // Open the DevTools. // mainWindow.webContents.openDevTools() - mainWindow.show() + newWindow.show() + + return newWindow } // Quit when all windows are closed, except on macOS. There, it's common @@ -73,7 +107,10 @@ app.on('window-all-closed', () => { // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. -app.on('ready', createWindow) +app.on('ready', (event, data) => { + // Create the mainWindow + mainWindow = createWindow() +}) // For now there is no good reason to separate these out to another file(s) // There is just not enough code to warrant it and further abstracts everything @@ -189,16 +226,13 @@ ipcMain.handle('loadProjectAtStartup', async () => { global['macOpenFiles'] = macOpenFilesEmpty // macOS: open-url events that were received before the app is ready - const getOpenUrls: string[] = ((global as any).getOpenUrls() || - []) as string[] + const getOpenUrls: string[] = (global as any).getOpenUrls if (getOpenUrls && getOpenUrls.length > 0) { projectPath = getOpenUrls[0] // We only do one project at a } // Reset this so we don't accidentally use it again. // @ts-ignore - global['getOpenUrls'] = function () { - return [] - } + global['getOpenUrls'] = [] // Check if we have a project path in the command line arguments // If we do, we will load the project at that path @@ -231,7 +265,7 @@ function parseCLIArgs(): minimist.ParsedArgs { return minimist(process.argv, {}) } -function registerListeners() { +function registerStartupListeners() { /** * macOS: when someone drops a file to the not-yet running VSCode, the open-file event fires even before * the app-ready event. We listen very early for open-file and remember this upon startup as path to open. @@ -240,13 +274,21 @@ function registerListeners() { // @ts-ignore global['macOpenFiles'] = macOpenFiles app.on('open-file', function (event, path) { + event.preventDefault() + macOpenFiles.push(path) + // If we have a mainWindow, lets open another window. + if (mainWindow) { + createWindow() + } }) /** * macOS: react to open-url requests. */ const openUrls: string[] = [] + // @ts-ignore + global['openUrls'] = openUrls const onOpenUrl = function ( event: { preventDefault: () => void }, url: string @@ -254,16 +296,13 @@ function registerListeners() { event.preventDefault() openUrls.push(url) + // If we have a mainWindow, lets open another window. + if (mainWindow) { + createWindow() + } } app.on('will-finish-launching', function () { app.on('open-url', onOpenUrl) }) - - // @ts-ignore - global['getOpenUrls'] = function () { - app.removeListener('open-url', onOpenUrl) - - return openUrls - } }