├── .gitignore
├── README.md
├── forge.config.js
├── images
├── OpenAI_Logo.svg
├── icon.icns
├── icon.png
├── icon@2x.icns
├── icon@2x.png
├── newiconTemplate.png
├── newiconTemplate@2x.png
└── screenshot.jpeg
├── index.css
├── index.html
├── index.js
├── package-lock.json
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 | .DS_Store
18 |
19 | # Directory for instrumented libs generated by jscoverage/JSCover
20 | lib-cov
21 |
22 | # Coverage directory used by tools like istanbul
23 | coverage
24 | *.lcov
25 |
26 | # nyc test coverage
27 | .nyc_output
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # TypeScript cache
43 | *.tsbuildinfo
44 |
45 | # Optional npm cache directory
46 | .npm
47 |
48 | # Optional eslint cache
49 | .eslintcache
50 |
51 | # Optional REPL history
52 | .node_repl_history
53 |
54 | # Output of 'npm pack'
55 | *.tgz
56 |
57 | # Yarn Integrity file
58 | .yarn-integrity
59 |
60 | # dotenv environment variables file
61 | .env
62 | .env.test
63 |
64 | # parcel-bundler cache (https://parceljs.org/)
65 | .cache
66 |
67 | # next.js build output
68 | .next
69 |
70 | # nuxt.js build output
71 | .nuxt
72 |
73 | # vuepress build output
74 | .vuepress/dist
75 |
76 | # Serverless directories
77 | .serverless/
78 |
79 | # FuseBox cache
80 | .fusebox/
81 |
82 | # DynamoDB Local files
83 | .dynamodb/
84 |
85 | # Webpack
86 | .webpack/
87 |
88 | # Electron-Forge
89 | out/
90 |
91 | .env
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ⭐ Building in AI? My new project is an [open-source toolkit for AI devs](https://github.com/llmonitor/llmonitor), a star would mean the world ⭐
2 |
3 | ---
4 |
5 | # ChatGPT for desktop
6 |
7 | This is a simple app that makes ChatGPT live in your menubar.
8 |
9 | You can use Cmd+Shift+G (Mac) or Ctrl+Shift+G (Win) to quickly open it from anywhere.
10 |
11 | Download:
12 |
13 | - [Mac Arm64 .dmg](https://github.com/vincelwt/chatgpt-mac/releases/download/v0.0.5/ChatGPT-0.0.5-arm64.dmg)
14 | - [Mac Intel .dmg](https://github.com/vincelwt/chatgpt-mac/releases/download/v0.0.5/ChatGPT-0.0.5-x64.dmg)
15 |
16 | No Windows binaries currently offered. Clone the repo, npm install electron-forge and run.
17 |
18 |
19 |
20 |
21 |
22 | ## Credit
23 |
24 | All credit and copyrights goes to OpenAI.
25 |
26 | ## Author
27 |
28 | You can find me on Twitter [@vincelwt](https://twitter.com/vincelwt).
29 |
--------------------------------------------------------------------------------
/forge.config.js:
--------------------------------------------------------------------------------
1 | const { parsed } = require("dotenv").config();
2 | module.exports = {
3 | packagerConfig: {
4 | name: "ChatGPT",
5 | executableName: "ChatGPT",
6 | icon: "images/icon",
7 | appBundleId: "com.vincelwt.chatgptmac",
8 | extendInfo: {
9 | LSUIElement: "true",
10 | },
11 | osxSign: {
12 | hardenedRuntime: false,
13 | gatekeeperAssess: false,
14 | identity: "Developer ID Application: Lyser.io Ltd (R4PF6TTR6Z)",
15 | },
16 | osxNotarize: {
17 | appBundleId: "com.vincelwt.chatgptmac",
18 |
19 | tool: "notarytool",
20 | appleId: parsed.APPLE_ID,
21 | appleIdPassword: parsed.APPLE_PASSWORD,
22 | teamId: parsed.APPLE_TEAM_ID,
23 | },
24 | },
25 | publishers: [
26 | {
27 | name: "@electron-forge/publisher-github",
28 | config: {
29 | repository: {
30 | owner: "vincelwt",
31 | name: "chatgpt-mac",
32 | },
33 | prerelease: true,
34 | },
35 | },
36 | ],
37 |
38 | rebuildConfig: {},
39 | makers: [
40 | {
41 | name: "@electron-forge/maker-squirrel",
42 | config: {},
43 | },
44 | {
45 | name: "@electron-forge/maker-dmg",
46 | platforms: ["darwin"],
47 | config: {},
48 | },
49 | {
50 | name: "@electron-forge/maker-deb",
51 | config: {},
52 | },
53 | {
54 | name: "@electron-forge/maker-rpm",
55 | config: {},
56 | },
57 | ],
58 | };
59 |
--------------------------------------------------------------------------------
/images/OpenAI_Logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/images/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincelwt/chatgpt-mac/5b9df7cbee5fc2a73d10800c4f6293a52176fe8a/images/icon.icns
--------------------------------------------------------------------------------
/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincelwt/chatgpt-mac/5b9df7cbee5fc2a73d10800c4f6293a52176fe8a/images/icon.png
--------------------------------------------------------------------------------
/images/icon@2x.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincelwt/chatgpt-mac/5b9df7cbee5fc2a73d10800c4f6293a52176fe8a/images/icon@2x.icns
--------------------------------------------------------------------------------
/images/icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincelwt/chatgpt-mac/5b9df7cbee5fc2a73d10800c4f6293a52176fe8a/images/icon@2x.png
--------------------------------------------------------------------------------
/images/newiconTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincelwt/chatgpt-mac/5b9df7cbee5fc2a73d10800c4f6293a52176fe8a/images/newiconTemplate.png
--------------------------------------------------------------------------------
/images/newiconTemplate@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincelwt/chatgpt-mac/5b9df7cbee5fc2a73d10800c4f6293a52176fe8a/images/newiconTemplate@2x.png
--------------------------------------------------------------------------------
/images/screenshot.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincelwt/chatgpt-mac/5b9df7cbee5fc2a73d10800c4f6293a52176fe8a/images/screenshot.jpeg
--------------------------------------------------------------------------------
/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
3 | Arial, sans-serif;
4 | padding: 0;
5 | margin: 0;
6 | overflow: hidden;
7 | }
8 |
9 | :root {
10 | /* account for the arrow */
11 | --actual-height: calc(100vh - 12px);
12 | }
13 |
14 | .myarrow {
15 | position: relative;
16 | /* padding-top: 12px; */
17 | padding: 12px 0 0 0 ;
18 | }
19 |
20 | .myarrow:before {
21 | content: '';
22 | height: 0;
23 | width: 0;
24 | border-width: 0 8px 12px 8px;
25 | border-style: solid;
26 | border-color: transparent transparent white transparent;
27 | position: absolute;
28 |
29 | top: 0;
30 | left: 50%;
31 | transform: translateX(-50%);
32 | }
33 |
34 | @media (prefers-color-scheme: dark) {
35 | .myarrow:before {
36 | border-color: transparent transparent #343541 transparent !important;
37 | }
38 | }
39 |
40 | .page {
41 | background: #eeeeee;
42 | width: 100%;
43 | height: 100vh;
44 | margin-top: 12px;
45 | margin: 0 auto;
46 | position: relative;
47 | }
48 |
49 | .darwin.page {
50 | border-radius: 8px;
51 | overflow: hidden;
52 | }
53 |
54 | webview {
55 | /* overflow: hidden; */
56 | position: absolute;
57 | top: 0;
58 | left: 0;
59 | width: 100%;
60 | height: calc(100vh - 12px);
61 | display: inline-flex !important;
62 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ChatGPT
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | require("update-electron-app")();
2 |
3 | const { menubar } = require("menubar");
4 | const Nucleus = require("nucleus-analytics");
5 |
6 | const path = require("path");
7 | const {
8 | app,
9 | nativeImage,
10 | Tray,
11 | Menu,
12 | globalShortcut,
13 | shell,
14 | } = require("electron");
15 | const contextMenu = require("electron-context-menu");
16 |
17 | const image = nativeImage.createFromPath(
18 | path.join(__dirname, `images/newiconTemplate.png`)
19 | );
20 |
21 | app.on("ready", () => {
22 | Nucleus.init("638d9ccf4a5ed2dae43ce122");
23 |
24 | const tray = new Tray(image);
25 |
26 | const mb = menubar({
27 | browserWindow: {
28 | icon: image,
29 | transparent: path.join(__dirname, `images/iconApp.png`),
30 | webPreferences: {
31 | webviewTag: true,
32 | // nativeWindowOpen: true,
33 | },
34 | width: 450,
35 | height: 550,
36 | },
37 | tray,
38 | showOnAllWorkspaces: true,
39 | preloadWindow: true,
40 | showDockIcon: false,
41 | icon: image,
42 | });
43 |
44 | mb.on("ready", () => {
45 | const { window } = mb;
46 |
47 |
48 | if (process.platform !== "darwin") {
49 | window.setSkipTaskbar(true);
50 | } else {
51 | app.dock.hide();
52 | }
53 |
54 | const contextMenuTemplate = [
55 | // add links to github repo and vince's twitter
56 | {
57 | label: "Quit",
58 | accelerator: "Command+Q",
59 | click: () => {
60 | app.quit();
61 | },
62 | },
63 | {
64 | label: "Reload",
65 | accelerator: "Command+R",
66 | click: () => {
67 | window.reload();
68 | },
69 | },
70 | {
71 | label: "Open in browser",
72 | click: () => {
73 | shell.openExternal("https://chat.openai.com/chat");
74 | },
75 | },
76 | {
77 | type: "separator",
78 | },
79 | {
80 | label: "View on GitHub",
81 | click: () => {
82 | shell.openExternal("https://github.com/vincelwt/chatgpt-mac");
83 | },
84 | },
85 | {
86 | label: "Author on Twitter",
87 | click: () => {
88 | shell.openExternal("https://twitter.com/vincelwt");
89 | },
90 | },
91 | ];
92 |
93 | tray.on("right-click", () => {
94 | mb.tray.popUpContextMenu(Menu.buildFromTemplate(contextMenuTemplate));
95 | });
96 |
97 | tray.on("click", (e) => {
98 | //check if ctrl or meta key is pressed while clicking
99 | e.ctrlKey || e.metaKey
100 | ? mb.tray.popUpContextMenu(Menu.buildFromTemplate(contextMenuTemplate))
101 | : null;
102 | });
103 | const menu = new Menu();
104 |
105 | globalShortcut.register("CommandOrControl+Shift+g", () => {
106 | if (window.isVisible()) {
107 | mb.hideWindow();
108 | } else {
109 | mb.showWindow();
110 | if (process.platform == "darwin") {
111 | mb.app.show();
112 | }
113 | mb.app.focus();
114 | }
115 | });
116 |
117 | Menu.setApplicationMenu(menu);
118 |
119 | // open devtools
120 | // window.webContents.openDevTools();
121 |
122 | console.log("Menubar app is ready.");
123 | });
124 |
125 | app.on("web-contents-created", (e, contents) => {
126 | if (contents.getType() == "webview") {
127 | // open link with external browser in webview
128 | contents.on("new-window", (e, url) => {
129 | e.preventDefault();
130 | shell.openExternal(url);
131 | });
132 | // set context menu in webview
133 | contextMenu({
134 | window: contents,
135 | });
136 |
137 | // we can't set the native app menu with "menubar" so need to manually register these events
138 | // register cmd+c/cmd+v events
139 | contents.on("before-input-event", (event, input) => {
140 | const { control, meta, key } = input;
141 | if (!control && !meta) return;
142 | if (key === "c") contents.copy();
143 | if (key === "v") contents.paste();
144 | if (key === "a") contents.selectAll();
145 | if (key === "z") contents.undo();
146 | if (key === "y") contents.redo();
147 | if (key === "q") app.quit();
148 | if (key === "r") contents.reload();
149 | });
150 | }
151 | });
152 |
153 | if (process.platform == "darwin") {
154 | // restore focus to previous app on hiding
155 | mb.on("after-hide", () => {
156 | mb.app.hide();
157 | });
158 | }
159 |
160 | // open links in new window
161 | // app.on("web-contents-created", (event, contents) => {
162 | // contents.on("will-navigate", (event, navigationUrl) => {
163 | // event.preventDefault();
164 | // shell.openExternal(navigationUrl);
165 | // });
166 | // });
167 |
168 | // prevent background flickering
169 | app.commandLine.appendSwitch(
170 | "disable-backgrounding-occluded-windows",
171 | "true"
172 | );
173 | });
174 |
175 | // Quit when all windows are closed, except on macOS. There, it's common
176 | // for applications and their menu bar to stay active until the user quits
177 | // explicitly with Cmd + Q.
178 | app.on("window-all-closed", () => {
179 | if (process.platform !== "darwin") {
180 | app.quit();
181 | }
182 | });
183 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincelwt/chatgpt-mac/5b9df7cbee5fc2a73d10800c4f6293a52176fe8a/package-lock.json
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chatgpt-mac",
3 | "productName": "chatgpt-mac",
4 | "version": "0.0.5",
5 | "description": "Menubar app for ChatGPT",
6 | "main": "index.js",
7 | "scripts": {
8 | "start": "electron-forge start",
9 | "package": "electron-forge package --arch arm64,x64",
10 | "make": " electron-forge make --arch arm64,x64",
11 | "publish": "electron-forge publish --arch arm64,x64",
12 | "lint": "echo \"No linting configured\""
13 | },
14 | "keywords": [
15 | "chatgpt",
16 | "openai",
17 | "mac"
18 | ],
19 | "author": {
20 | "name": "Vince Loewe",
21 | "email": "vince@lyser.io"
22 | },
23 | "license": "MIT",
24 | "dependencies": {
25 | "electron-context-menu": "^3.6.0",
26 | "menubar": "^9.2.3",
27 | "nucleus-analytics": "^4.0.3",
28 | "update-electron-app": "^2.0.1"
29 | },
30 | "repository": {
31 | "type": "git",
32 | "url": "https://github.com/vincelwt/chatgpt-mac"
33 | },
34 | "devDependencies": {
35 | "@electron-forge/cli": "^6.0.4",
36 | "@electron-forge/maker-deb": "^6.0.4",
37 | "@electron-forge/maker-dmg": "^6.0.4",
38 | "@electron-forge/maker-rpm": "^6.0.4",
39 | "@electron-forge/maker-squirrel": "^6.0.4",
40 | "@electron-forge/maker-zip": "^6.0.4",
41 | "@electron-forge/publisher-github": "^6.0.4",
42 | "dotenv": "^16.0.3",
43 | "electron": "^21.0.0",
44 | "electron-squirrel-startup": "^1.0.0"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------