@kudoai/chatgpt.js 3.4.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/chatgpt.js +27 -23
- package/dist/chatgpt.min.js +3 -3
- package/docs/README.md +7 -6
- package/docs/SECURITY.md +1 -3
- package/docs/USERGUIDE.md +3 -3
- package/package.json +1 -1
- package/starters/chrome/extension/components/icons.js +4 -5
- package/starters/chrome/extension/components/modals.js +92 -65
- package/starters/chrome/extension/content.js +29 -42
- package/starters/chrome/extension/lib/chatgpt.js +27 -23
- package/starters/chrome/extension/lib/dom.js +9 -2
- package/starters/chrome/extension/lib/settings.js +1 -1
- package/starters/chrome/extension/manifest.json +2 -5
- package/starters/chrome/extension/popup/controller.js +14 -12
- package/starters/chrome/extension/popup/style.css +24 -10
- package/starters/chrome/extension/service-worker.js +6 -3
- package/starters/greasemonkey/chatgpt.js-greasemonkey-starter.user.js +4 -4
|
@@ -99,7 +99,8 @@ const chatgpt = {
|
|
|
99
99
|
chatgpt.draggableElem = event.currentTarget
|
|
100
100
|
chatgpt.draggableElem.style.cursor = 'grabbing'
|
|
101
101
|
event.preventDefault(); // prevent sub-elems like icons being draggable
|
|
102
|
-
['mousemove', 'mouseup'].forEach(
|
|
102
|
+
['mousemove', 'mouseup'].forEach(eventType =>
|
|
103
|
+
document.addEventListener(eventType, handlers.drag[eventType]))
|
|
103
104
|
const draggableElemRect = chatgpt.draggableElem.getBoundingClientRect()
|
|
104
105
|
handlers.drag.offsetX = event.clientX - draggableElemRect.left +21
|
|
105
106
|
handlers.drag.offsetY = event.clientY - draggableElemRect.top +12
|
|
@@ -114,8 +115,8 @@ const chatgpt = {
|
|
|
114
115
|
|
|
115
116
|
mouseup() { // remove listeners, reset chatgpt.draggableElem
|
|
116
117
|
chatgpt.draggableElem.style.cursor = 'inherit';
|
|
117
|
-
['mousemove', 'mouseup'].forEach(
|
|
118
|
-
document.removeEventListener(
|
|
118
|
+
['mousemove', 'mouseup'].forEach(eventType =>
|
|
119
|
+
document.removeEventListener(eventType, handlers.drag[eventType]))
|
|
119
120
|
chatgpt.draggableElem = null
|
|
120
121
|
}
|
|
121
122
|
}
|
|
@@ -130,7 +131,7 @@ const chatgpt = {
|
|
|
130
131
|
modalMessage = document.createElement('p');
|
|
131
132
|
|
|
132
133
|
// Create/append/update modal style (if missing or outdated)
|
|
133
|
-
const thisUpdated =
|
|
134
|
+
const thisUpdated = 1735475757891 // timestamp of last edit for this file's `modalStyle`
|
|
134
135
|
let modalStyle = document.querySelector('#chatgpt-modal-style'); // try to select existing style
|
|
135
136
|
if (!modalStyle || parseInt(modalStyle.getAttribute('last-updated'), 10) < thisUpdated) { // if missing or outdated
|
|
136
137
|
if (!modalStyle) { // outright missing, create/id/attr/append it first
|
|
@@ -163,6 +164,7 @@ const chatgpt = {
|
|
|
163
164
|
+ ' -webkit-user-select: none ; -moz-user-select: none ; -ms-user-select: none ; user-select: none ; }'
|
|
164
165
|
+ '.chatgpt-modal h2 { margin-bottom: 9px }'
|
|
165
166
|
+ `.chatgpt-modal a { color: ${ scheme == 'dark' ? '#00cfff' : '#1e9ebb' }}`
|
|
167
|
+
+ '.chatgpt-modal a:hover { text-decoration: underline }'
|
|
166
168
|
+ '.chatgpt-modal.animated > div { z-index: 13456 ; opacity: 0.98 ; transform: translateX(0) translateY(0) }'
|
|
167
169
|
+ '@keyframes alert-zoom-fade-out {'
|
|
168
170
|
+ '0% { opacity: 1 } 50% { opacity: 0.25 ; transform: scale(1.05) }'
|
|
@@ -193,12 +195,12 @@ const chatgpt = {
|
|
|
193
195
|
+ '.chatgpt-modal .checkbox-group label {'
|
|
194
196
|
+ 'font-size: .7rem ; margin: -.04rem 0 0px .3rem ;'
|
|
195
197
|
+ `color: ${ scheme == 'dark' ? '#e1e1e1' : '#1e1e1e' }}`
|
|
196
|
-
+ '.chatgpt-modal input[type=
|
|
198
|
+
+ '.chatgpt-modal input[type=checkbox] { transform: scale(0.7) ;'
|
|
197
199
|
+ `border: 1px solid ${ scheme == 'dark' ? 'white' : 'black' }}`
|
|
198
|
-
+ '.chatgpt-modal input[type=
|
|
200
|
+
+ '.chatgpt-modal input[type=checkbox]:checked {'
|
|
199
201
|
+ `border: 1px solid ${ scheme == 'dark' ? 'white' : 'black' } ;`
|
|
200
202
|
+ 'background-color: black ; position: inherit }'
|
|
201
|
-
+ '.chatgpt-modal input[type=
|
|
203
|
+
+ '.chatgpt-modal input[type=checkbox]:focus { outline: none ; box-shadow: none }'
|
|
202
204
|
);
|
|
203
205
|
}
|
|
204
206
|
|
|
@@ -314,7 +316,7 @@ const chatgpt = {
|
|
|
314
316
|
}, 500);
|
|
315
317
|
}
|
|
316
318
|
|
|
317
|
-
},
|
|
319
|
+
}, 155);
|
|
318
320
|
};
|
|
319
321
|
|
|
320
322
|
return modalContainer.id; // if assignment used
|
|
@@ -455,7 +457,7 @@ const chatgpt = {
|
|
|
455
457
|
async isIdle(timeout = null) {
|
|
456
458
|
const obsConfig = { childList: true, subtree: true },
|
|
457
459
|
selectors = { msgDiv: 'div[data-message-author-role]',
|
|
458
|
-
replyDiv: 'div[data-message-author-role=
|
|
460
|
+
replyDiv: 'div[data-message-author-role=assistant]' };
|
|
459
461
|
|
|
460
462
|
// Create promises
|
|
461
463
|
const timeoutPromise = timeout ? new Promise(resolve => setTimeout(() => resolve(false), timeout)) : null;
|
|
@@ -620,7 +622,7 @@ const chatgpt = {
|
|
|
620
622
|
filename = `${ parsedHtml.querySelector('title').textContent || 'ChatGPT conversation' }.html`;
|
|
621
623
|
|
|
622
624
|
// Convert relative CSS paths to absolute ones
|
|
623
|
-
const cssLinks = parsedHtml.querySelectorAll('link[rel=
|
|
625
|
+
const cssLinks = parsedHtml.querySelectorAll('link[rel=stylesheet]');
|
|
624
626
|
cssLinks.forEach(link => {
|
|
625
627
|
const href = link.getAttribute('href');
|
|
626
628
|
if (href?.startsWith('/')) link.setAttribute('href', 'https://chat.openai.com' + href);
|
|
@@ -932,7 +934,7 @@ const chatgpt = {
|
|
|
932
934
|
getLastResponse() { return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest'); },
|
|
933
935
|
|
|
934
936
|
getNewChatButton() {
|
|
935
|
-
return document.querySelector('button[data-testid*=
|
|
937
|
+
return document.querySelector('button[data-testid*=new-chat-button], button:has([d^="M15.6729"])'); },
|
|
936
938
|
|
|
937
939
|
getNewChatLink() { return document.querySelector('nav a[href="/"]'); },
|
|
938
940
|
getRegenerateButton() { return document.querySelector('button:has([d^="M3.06957"])'); },
|
|
@@ -949,8 +951,8 @@ const chatgpt = {
|
|
|
949
951
|
getResponseFromAPI(chatToGet, responseToGet) { return chatgpt.response.getFromAPI(chatToGet, responseToGet); },
|
|
950
952
|
getResponseFromDOM(pos) { return chatgpt.response.getFromDOM(pos); },
|
|
951
953
|
getScrollToBottomButton() { return document.querySelector('button:has([d^="M12 21C11.7348"])'); },
|
|
952
|
-
getSendButton() { return document.querySelector('[data-testid=
|
|
953
|
-
getStopButton() { return document.querySelector('button[data-testid=
|
|
954
|
+
getSendButton() { return document.querySelector('[data-testid=send-button]'); },
|
|
955
|
+
getStopButton() { return document.querySelector('button[data-testid=stop-button]'); },
|
|
954
956
|
|
|
955
957
|
getUserLanguage() {
|
|
956
958
|
return navigator.languages[0] || navigator.language || navigator.browserLanguage ||
|
|
@@ -1211,7 +1213,7 @@ const chatgpt = {
|
|
|
1211
1213
|
}
|
|
1212
1214
|
|
|
1213
1215
|
const addElementsToMenu = () => {
|
|
1214
|
-
const optionButtons = document.querySelectorAll('a[role=
|
|
1216
|
+
const optionButtons = document.querySelectorAll('a[role=menuitem]');
|
|
1215
1217
|
let cssClasses;
|
|
1216
1218
|
|
|
1217
1219
|
for (const navLink of optionButtons)
|
|
@@ -1230,7 +1232,7 @@ const chatgpt = {
|
|
|
1230
1232
|
};
|
|
1231
1233
|
|
|
1232
1234
|
this.elements.push(newElement);
|
|
1233
|
-
const menuBtn = document.querySelector('nav button[id*=
|
|
1235
|
+
const menuBtn = document.querySelector('nav button[id*=headless]');
|
|
1234
1236
|
if (!this.addedEvent) { // to prevent adding more than one event
|
|
1235
1237
|
menuBtn?.addEventListener('click', () => { setTimeout(addElementsToMenu, 25); });
|
|
1236
1238
|
this.addedEvent = true; }
|
|
@@ -1239,12 +1241,12 @@ const chatgpt = {
|
|
|
1239
1241
|
},
|
|
1240
1242
|
|
|
1241
1243
|
close() {
|
|
1242
|
-
try { document.querySelector('nav [id*=
|
|
1244
|
+
try { document.querySelector('nav [id*=menu-button][aria-expanded=true]').click(); }
|
|
1243
1245
|
catch (err) { console.error(err.message); }
|
|
1244
1246
|
},
|
|
1245
1247
|
|
|
1246
1248
|
open() {
|
|
1247
|
-
try { document.querySelector('nav [id*=
|
|
1249
|
+
try { document.querySelector('nav [id*=menu-button][aria-expanded=false]').click(); }
|
|
1248
1250
|
catch (err) { console.error(err.message); }
|
|
1249
1251
|
}
|
|
1250
1252
|
},
|
|
@@ -1285,7 +1287,7 @@ const chatgpt = {
|
|
|
1285
1287
|
+ (notificationDiv.isRight ? 'Right' : 'Left');
|
|
1286
1288
|
|
|
1287
1289
|
// Create/append/update notification style (if missing or outdated)
|
|
1288
|
-
const thisUpdated =
|
|
1290
|
+
const thisUpdated = 1735475527153 // timestamp of last edit for this file's `notifStyle`
|
|
1289
1291
|
let notifStyle = document.querySelector('#chatgpt-notif-style'); // try to select existing style
|
|
1290
1292
|
if (!notifStyle || parseInt(notifStyle.getAttribute('last-updated'), 10) < thisUpdated) { // if missing or outdated
|
|
1291
1293
|
if (!notifStyle) { // outright missing, create/id/attr/append it first
|
|
@@ -1295,6 +1297,8 @@ const chatgpt = {
|
|
|
1295
1297
|
}
|
|
1296
1298
|
notifStyle.innerText = ( // update prev/new style contents
|
|
1297
1299
|
'.chatgpt-notif {'
|
|
1300
|
+
+ 'font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC",'
|
|
1301
|
+
+ '"Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", sans-serif ;'
|
|
1298
1302
|
+ '.no-mobile-tap-outline { outline: none ; -webkit-tap-highlight-color: transparent }'
|
|
1299
1303
|
+ 'background-color: black ; padding: 10px 13px 10px 18px ; border-radius: 11px ; border: 1px solid #f5f5f7 ;' // bubble style
|
|
1300
1304
|
+ 'opacity: 0 ; position: fixed ; z-index: 9999 ; font-size: 1.8rem ; color: white ;' // visibility
|
|
@@ -1518,7 +1522,7 @@ const chatgpt = {
|
|
|
1518
1522
|
},
|
|
1519
1523
|
|
|
1520
1524
|
getFromDOM(pos) {
|
|
1521
|
-
const responseDivs = document.querySelectorAll('div[data-message-author-role=
|
|
1525
|
+
const responseDivs = document.querySelectorAll('div[data-message-author-role=assistant]'),
|
|
1522
1526
|
strPos = pos.toString().toLowerCase();
|
|
1523
1527
|
let response = '';
|
|
1524
1528
|
if (!responseDivs.length) return console.error('No conversation found!');
|
|
@@ -1825,7 +1829,7 @@ const chatgpt = {
|
|
|
1825
1829
|
isOff() { return !this.isOn(); },
|
|
1826
1830
|
isOn() {
|
|
1827
1831
|
const sidebar = (() => {
|
|
1828
|
-
return chatgpt.sidebar.exists() ? document.querySelector('[class*=
|
|
1832
|
+
return chatgpt.sidebar.exists() ? document.querySelector('[class*=sidebar]') : null; })();
|
|
1829
1833
|
if (!sidebar) { console.error('Sidebar element not found!'); return false; }
|
|
1830
1834
|
else return chatgpt.browser.isMobile() ?
|
|
1831
1835
|
document.documentElement.style.overflow == 'hidden'
|
|
@@ -1833,7 +1837,7 @@ const chatgpt = {
|
|
|
1833
1837
|
},
|
|
1834
1838
|
|
|
1835
1839
|
toggle() {
|
|
1836
|
-
const sidebarToggle = document.querySelector('button[data-testid*=
|
|
1840
|
+
const sidebarToggle = document.querySelector('button[data-testid*=sidebar-button]');
|
|
1837
1841
|
if (!sidebarToggle) console.error('Sidebar toggle not found!');
|
|
1838
1842
|
sidebarToggle.click();
|
|
1839
1843
|
},
|
|
@@ -1943,8 +1947,8 @@ const cjsBtnActions = ['click', 'get'], cjsTargetTypes = [ 'button', 'link', 'di
|
|
|
1943
1947
|
for (const btnAction of cjsBtnActions) {
|
|
1944
1948
|
chatgpt[btnAction + 'Button'] = function handleButton(buttonIdentifier) {
|
|
1945
1949
|
const button = /^[.#]/.test(buttonIdentifier) ? document.querySelector(buttonIdentifier)
|
|
1946
|
-
: /send/i.test(buttonIdentifier) ? document.querySelector('form button[class*=
|
|
1947
|
-
: /scroll/i.test(buttonIdentifier) ? document.querySelector('button[class*=
|
|
1950
|
+
: /send/i.test(buttonIdentifier) ? document.querySelector('form button[class*=bottom]')
|
|
1951
|
+
: /scroll/i.test(buttonIdentifier) ? document.querySelector('button[class*=cursor]')
|
|
1948
1952
|
: (function() { // get via text content
|
|
1949
1953
|
for (const button of document.querySelectorAll('button')) { // try buttons
|
|
1950
1954
|
if (button.textContent.toLowerCase().includes(buttonIdentifier.toLowerCase())) {
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
window.dom = {
|
|
2
|
+
|
|
3
|
+
imports: {
|
|
4
|
+
import(deps) { // { env) }
|
|
5
|
+
for (const depName in deps) this[depName] = deps[depName] }
|
|
6
|
+
},
|
|
7
|
+
|
|
2
8
|
create: {
|
|
3
9
|
elem(elemType, attrs = {}) {
|
|
4
10
|
const elem = document.createElement(elemType)
|
|
@@ -13,14 +19,15 @@ window.dom = {
|
|
|
13
19
|
}
|
|
14
20
|
},
|
|
15
21
|
|
|
16
|
-
fillStarryBG(targetNode) { // requires https://assets.aiwebextensions.com/styles/css/<black|white
|
|
22
|
+
fillStarryBG(targetNode) { // requires https://assets.aiwebextensions.com/styles/rising-stars/css/<black|white>.min.css
|
|
23
|
+
if (targetNode.querySelector('[id*=stars]')) return
|
|
17
24
|
const starsDivsContainer = document.createElement('div')
|
|
18
25
|
starsDivsContainer.style.cssText = 'position: absolute ; top: 0 ; left: 0 ;' // hug targetNode's top-left corner
|
|
19
26
|
+ 'height: 100% ; width: 100% ; border-radius: 15px ; overflow: clip ;' // bound innards exactly by targetNode
|
|
20
27
|
+ 'z-index: -1'; // allow interactive elems to be clicked
|
|
21
28
|
['sm', 'med', 'lg'].forEach(starSize => {
|
|
22
29
|
const starsDiv = document.createElement('div')
|
|
23
|
-
starsDiv.id = `${
|
|
30
|
+
starsDiv.id = `${ this.imports.env.ui.scheme == 'dark' ? 'white' : 'black' }-stars-${starSize}`
|
|
24
31
|
starsDivsContainer.append(starsDiv)
|
|
25
32
|
})
|
|
26
33
|
targetNode.prepend(starsDivsContainer)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "ChatGPT Extension",
|
|
4
4
|
"short_name": "ChatGPT 🧩",
|
|
5
5
|
"description": "A Chromium extension template to start using chatgpt.js like a boss!",
|
|
6
|
-
"version": "2024.12.
|
|
6
|
+
"version": "2024.12.29",
|
|
7
7
|
"author": "KudoAI",
|
|
8
8
|
"homepage_url": "https://github.com/KudoAI/chatgpt.js-chrome-starter",
|
|
9
9
|
"icons": {
|
|
@@ -18,10 +18,7 @@
|
|
|
18
18
|
"matches": [ "<all_urls>" ],
|
|
19
19
|
"resources": [ "components/modals.js", "lib/chatgpt.js", "lib/dom.js", "lib/settings.js" ]
|
|
20
20
|
}],
|
|
21
|
-
"content_scripts": [{
|
|
22
|
-
"matches": [ "https://chatgpt.com/*" ],
|
|
23
|
-
"js": [ "content.js" ]
|
|
24
|
-
}],
|
|
21
|
+
"content_scripts": [{ "matches": [ "https://chatgpt.com/*" ], "js": [ "content.js" ] }],
|
|
25
22
|
"background": { "service_worker": "service-worker.js" },
|
|
26
23
|
"minimum_chrome_version": "88"
|
|
27
24
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
// Import APP data
|
|
12
12
|
const { app } = await chrome.storage.sync.get('app')
|
|
13
|
-
icons.
|
|
13
|
+
icons.imports.import({ app }) // for src's using app.urls.assetHost
|
|
14
14
|
|
|
15
15
|
// Define FUNCTIONS
|
|
16
16
|
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
|
|
56
56
|
// Create CHILD menu entries on chatgpt.com
|
|
57
57
|
if (env.site == 'chatgpt') {
|
|
58
|
-
await settings.load(settings.
|
|
58
|
+
await settings.load(Object.keys(settings.controls))
|
|
59
59
|
|
|
60
60
|
// Create/insert child section
|
|
61
61
|
const togglesDiv = dom.create.elem('div', { class: 'menu' })
|
|
@@ -65,9 +65,10 @@
|
|
|
65
65
|
Object.keys(settings.controls).forEach(key => {
|
|
66
66
|
|
|
67
67
|
// Init elems
|
|
68
|
-
const menuItemDiv = dom.create.elem('div', {
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
const menuItemDiv = dom.create.elem('div', {
|
|
69
|
+
class: 'menu-item menu-area', title: settings.controls[key].helptip || '' })
|
|
70
|
+
const menuLabel = dom.create.elem('label', { class: 'menu-icon' })
|
|
71
|
+
const menuLabelSpan = dom.create.elem('span')
|
|
71
72
|
let menuInput, menuSlider
|
|
72
73
|
menuLabelSpan.textContent = settings.controls[key].label
|
|
73
74
|
if (settings.controls[key].type == 'toggle') {
|
|
@@ -92,7 +93,8 @@
|
|
|
92
93
|
event.stopImmediatePropagation()
|
|
93
94
|
menuInput.onchange = () => {
|
|
94
95
|
settings.save(key, !config[key]) ; sync.configToUI({ updatedKey: key })
|
|
95
|
-
notify(`${settings.controls[key].label} ${
|
|
96
|
+
notify(`${settings.controls[key].label} ${
|
|
97
|
+
/disabled|hidden/i.test(key) != config[key] ? 'ON' : 'OFF' }`)
|
|
96
98
|
}
|
|
97
99
|
} else if (settings.controls[key].type == 'prompt') {
|
|
98
100
|
// custom logic for each prompt based on key name
|
|
@@ -103,16 +105,16 @@
|
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
// Create/append FOOTER container
|
|
106
|
-
const footer =
|
|
107
|
-
document.body.append(footer)
|
|
108
|
+
const footer = dom.create.elem('footer') ; document.body.append(footer)
|
|
108
109
|
|
|
109
110
|
// Create/append CHATGPT.JS footer logo
|
|
110
111
|
const cjsDiv = dom.create.elem('div', { class: 'chatgpt-js' })
|
|
111
112
|
const cjsLogo = dom.create.elem('img', {
|
|
112
113
|
title: 'Powered by chatgpt.js',
|
|
113
|
-
src: `${app.urls.cjsMediaHost}/images/badges/powered-by-chatgpt.js-faded.png?
|
|
114
|
+
src: `${app.urls.cjsMediaHost}/images/badges/powered-by-chatgpt.js-faded.png?b2a1975` })
|
|
114
115
|
cjsLogo.onmouseover = cjsLogo.onmouseout = event => cjsLogo.src = `${
|
|
115
|
-
app.urls.cjsMediaHost}/images/badges/powered-by-chatgpt.js${
|
|
116
|
+
app.urls.cjsMediaHost}/images/badges/powered-by-chatgpt.js${
|
|
117
|
+
event.type == 'mouseover' ? '' : '-faded' }.png?b2a1975`
|
|
116
118
|
cjsLogo.onclick = () => chrome.tabs.create({ url: app.urls.chatgptJS })
|
|
117
119
|
cjsDiv.append(cjsLogo) ; footer.append(cjsDiv)
|
|
118
120
|
|
|
@@ -132,7 +134,7 @@
|
|
|
132
134
|
moreExtensionsSpan.onclick = () => { chrome.tabs.create({ url: app.urls.relatedExtensions }) ; close() }
|
|
133
135
|
moreExtensionsSpan.append(moreExtensionsIcon) ; footer.append(moreExtensionsSpan)
|
|
134
136
|
|
|
135
|
-
//
|
|
136
|
-
document.querySelectorAll('[class^=
|
|
137
|
+
// Remove loading spinner
|
|
138
|
+
document.querySelectorAll('[class^=loading]').forEach(elem => elem.remove())
|
|
137
139
|
|
|
138
140
|
})()
|
|
@@ -4,20 +4,35 @@ body { width: max-content ; margin: 0 ; overflow: clip }
|
|
|
4
4
|
|
|
5
5
|
/* General font */
|
|
6
6
|
body, button, input, select, textarea {
|
|
7
|
-
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
7
|
+
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
8
|
+
"PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", sans-serif ;
|
|
8
9
|
font-size: .905rem ; user-select: none
|
|
9
10
|
}
|
|
10
11
|
a { color: #999 ; text-decoration: none }
|
|
11
12
|
a:focus, a:hover { text-decoration: underline ; color: inherit }
|
|
12
13
|
|
|
13
|
-
/*
|
|
14
|
-
.loading-bg {
|
|
14
|
+
/* Loader */
|
|
15
|
+
.loading-bg {
|
|
16
|
+
background-color: white ; width: 100% ; height: 100% ; position: absolute ; z-index: 1111 ;
|
|
17
|
+
display: inline-grid ; align-content: center ; justify-content: center /* center spinner */
|
|
18
|
+
}
|
|
15
19
|
.loading-spinner {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
width: 11px ; aspect-ratio: 1 ; border-radius: 50% ; border: 5px solid #000 ;
|
|
21
|
+
animation: loader-move-head-tail 0.8s infinite linear alternate, loader-rotate 1.6s infinite linear
|
|
22
|
+
}
|
|
23
|
+
@keyframes loader-move-head-tail {
|
|
24
|
+
0% { clip-path: polygon(50% 50%, 0 0, 50% 0, 50% 0, 50% 0, 50% 0, 50% 0) }
|
|
25
|
+
12.5% { clip-path: polygon(50% 50%, 0 0, 50% 0, 100% 0, 100% 0, 100% 0, 100% 0) }
|
|
26
|
+
25% { clip-path: polygon(50% 50%, 0 0, 50% 0, 100% 0, 100% 100%, 100% 100%, 100% 100%) }
|
|
27
|
+
50% { clip-path: polygon(50% 50%, 0 0, 50% 0, 100% 0, 100% 100%, 50% 100%, 0 100%) }
|
|
28
|
+
62.5% { clip-path: polygon(50% 50%, 100% 0, 100% 0%, 100% 0, 100% 100%, 50% 100%, 0 100%) }
|
|
29
|
+
75% { clip-path: polygon(50% 50%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 50% 100%, 0 100%) }
|
|
30
|
+
100% { clip-path: polygon(50% 50%, 50% 100%, 50% 100%, 50% 100%, 50% 100%, 50% 100%, 0 100%) }
|
|
19
31
|
}
|
|
20
|
-
@keyframes
|
|
32
|
+
@keyframes loader-rotate {
|
|
33
|
+
0% { transform: scaleY(1) rotate(0deg) } 49.99% { transform: scaleY(1) rotate(135deg) }
|
|
34
|
+
50% { transform: scaleY(-1) rotate(0deg) } 100% { transform: scaleY(-1) rotate(-135deg) }
|
|
35
|
+
}
|
|
21
36
|
|
|
22
37
|
/* Header */
|
|
23
38
|
.menu-header {
|
|
@@ -36,8 +51,7 @@ a:focus, a:hover { text-decoration: underline ; color: inherit }
|
|
|
36
51
|
.menu-icon { padding: 8px }
|
|
37
52
|
.menu-area:focus, .menu-area:hover { /* add hover color/cursor */
|
|
38
53
|
color: var(--bg) ; background: rgb(100, 149, 237) ; cursor: pointer }
|
|
39
|
-
.menu-item:hover .
|
|
40
|
-
.menu-item:hover .menu-icon { filter: none } /* ...but not non-toggle icons */
|
|
54
|
+
.menu-item:hover span:not(.slider) { filter: invert(1) } /* invert setting labels on hover */
|
|
41
55
|
.menu-item > label > .slider { transform: scale(0.95) ; top: 1px } /* make child toggles smaller */
|
|
42
56
|
.menu-prompt { margin-left: 2px } /* align non-toggle items */
|
|
43
57
|
|
|
@@ -52,7 +66,7 @@ a:focus, a:hover { text-decoration: underline ; color: inherit }
|
|
|
52
66
|
border: 1px solid black ; border-radius: 50% ; background-color: white ; content: ""
|
|
53
67
|
}
|
|
54
68
|
.toggle-switch input[type="checkbox"]:checked + .slider { background-color: black } /* color active slider */
|
|
55
|
-
.toggle-switch input[type="checkbox"]:checked + .slider::before { transform: translateX(9px) } /*
|
|
69
|
+
.toggle-switch input[type="checkbox"]:checked + .slider::before { transform: translateX(9px) } /* toggle knob right */
|
|
56
70
|
|
|
57
71
|
/* Footer */
|
|
58
72
|
footer { font-size: 12px ; text-align: center ; color: #999 ; background: #f5f5f5 ; height: 40px ; line-height: 40px }
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// Init APP data
|
|
2
2
|
const app = {
|
|
3
|
-
|
|
3
|
+
version: chrome.runtime.getManifest().version, symbol: '🤖', cssPrefix: 'chatgpt-extension',
|
|
4
|
+
author: { name: 'KudoAI', url: 'https://kudoai.com' },
|
|
4
5
|
urls: {
|
|
5
6
|
assetHost: 'https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js-chrome-starter',
|
|
7
|
+
chatgptJS: 'https://chatgptjs.org',
|
|
6
8
|
cjsMediaHost: 'https://media.chatgptjs.org',
|
|
9
|
+
contributors: 'https://docs.chatgptjs.org/#-contributors',
|
|
7
10
|
gitHub: 'https://github.com/KudoAI/chatgpt.js-chrome-starter',
|
|
8
11
|
relatedExtensions: 'https://aiwebextensions.com',
|
|
9
12
|
support: 'https://github.com/KudoAI/chatgpt.js-chrome-starter/issues'
|
|
@@ -11,13 +14,13 @@ const app = {
|
|
|
11
14
|
}
|
|
12
15
|
chrome.storage.sync.set({ app }) // save to Chrome storage
|
|
13
16
|
|
|
14
|
-
// Launch
|
|
17
|
+
// Launch CHATGPT on install
|
|
15
18
|
chrome.runtime.onInstalled.addListener(details => {
|
|
16
19
|
if (details.reason == 'install')
|
|
17
20
|
chrome.tabs.create({ url: 'https://chatgpt.com/' })
|
|
18
21
|
})
|
|
19
22
|
|
|
20
|
-
// Sync
|
|
23
|
+
// Sync SETTINGS to activated tabs
|
|
21
24
|
chrome.tabs.onActivated.addListener(activeInfo =>
|
|
22
25
|
chrome.tabs.sendMessage(activeInfo.tabId, { action: 'syncConfigToUI' }))
|
|
23
26
|
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
// @description A Greasemonkey template to start using chatgpt.js like a boss
|
|
4
4
|
// @author chatgpt.js
|
|
5
5
|
// @namespace https://chatgpt.js.org
|
|
6
|
-
// @version 2024.12.
|
|
6
|
+
// @version 2024.12.29
|
|
7
7
|
// @license MIT
|
|
8
|
-
// @icon https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.
|
|
9
|
-
// @icon64 https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.
|
|
8
|
+
// @icon https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.5.0/starters/greasemonkey/media/images/icons/robot/icon48.png
|
|
9
|
+
// @icon64 https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.5.0/starters/greasemonkey/media/images/icons/robot/icon64.png
|
|
10
10
|
// @match *://chatgpt.com/*
|
|
11
11
|
// @match *://chat.openai.com/*
|
|
12
|
-
// @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.
|
|
12
|
+
// @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.5.0/dist/chatgpt.min.js
|
|
13
13
|
// @grant GM_getValue
|
|
14
14
|
// @grant GM_setValue
|
|
15
15
|
// @noframes
|