bloby-bot 0.22.5 → 0.22.7
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/dist-bloby/assets/{bloby-DvSkie1b.js → bloby-DRKZrgq5.js} +76 -76
- package/dist-bloby/assets/globals-D723zY1K.css +2 -0
- package/dist-bloby/assets/{highlighted-body-OFNGDK62-BbEkUgTM.js → highlighted-body-OFNGDK62-2gSfFQnP.js} +1 -1
- package/dist-bloby/assets/mermaid-GHXKKRXX-vCq54mVZ.js +1 -0
- package/dist-bloby/assets/{onboard-8MWxCQSm.js → onboard-UT8t4BUn.js} +1 -1
- package/dist-bloby/bloby.html +3 -3
- package/dist-bloby/onboard.html +3 -3
- package/package.json +1 -1
- package/supervisor/chat/src/components/Chat/BlobyImageCard.tsx +63 -0
- package/supervisor/chat/src/components/Chat/ImageLightbox.tsx +33 -8
- package/supervisor/chat/src/components/Chat/MessageBubble.tsx +48 -30
- package/dist-bloby/assets/globals-b7xkhPEo.css +0 -2
- package/dist-bloby/assets/mermaid-GHXKKRXX-C0VBooMz.js +0 -1
- package/workspace/skills/chrome-extension/.claude-plugin/plugin.json +0 -6
- package/workspace/skills/chrome-extension/SKILL.md +0 -181
- package/workspace/skills/chrome-extension/background.js +0 -182
- package/workspace/skills/chrome-extension/content-script.js +0 -309
- package/workspace/skills/chrome-extension/content-style.css +0 -86
- package/workspace/skills/chrome-extension/icons/icon-128.png +0 -0
- package/workspace/skills/chrome-extension/icons/icon-16.png +0 -0
- package/workspace/skills/chrome-extension/icons/icon-48.png +0 -0
- package/workspace/skills/chrome-extension/manifest.json +0 -47
- package/workspace/skills/chrome-extension/panel/panel.html +0 -36
- package/workspace/skills/chrome-extension/panel/panel.js +0 -123
- package/workspace/skills/chrome-extension/popup/popup.css +0 -124
- package/workspace/skills/chrome-extension/popup/popup.html +0 -47
- package/workspace/skills/chrome-extension/popup/popup.js +0 -115
- package/workspace/skills/chrome-extension/skill.json +0 -15
- /package/dist-bloby/assets/{globals-VdwDxdso.js → globals-BFNdjQrL.js} +0 -0
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/* Bloby Chrome Extension — Bubble & Panel Styles */
|
|
2
|
-
|
|
3
|
-
#bloby-ext-bubble {
|
|
4
|
-
position: fixed;
|
|
5
|
-
bottom: 24px;
|
|
6
|
-
right: 24px;
|
|
7
|
-
width: 60px;
|
|
8
|
-
height: 60px;
|
|
9
|
-
border-radius: 50%;
|
|
10
|
-
background: linear-gradient(135deg, #04D1FE, #AF27E3, #FB4072);
|
|
11
|
-
cursor: pointer;
|
|
12
|
-
z-index: 2147483646;
|
|
13
|
-
display: flex;
|
|
14
|
-
align-items: center;
|
|
15
|
-
justify-content: center;
|
|
16
|
-
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
|
17
|
-
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
#bloby-ext-bubble:hover {
|
|
21
|
-
transform: scale(1.08);
|
|
22
|
-
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
#bloby-ext-bubble:active {
|
|
26
|
-
transform: scale(0.95);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.bloby-ext-bubble-dot {
|
|
30
|
-
width: 24px;
|
|
31
|
-
height: 24px;
|
|
32
|
-
border-radius: 50%;
|
|
33
|
-
background: rgba(255, 255, 255, 0.9);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/* Panel */
|
|
37
|
-
#bloby-ext-panel {
|
|
38
|
-
position: fixed;
|
|
39
|
-
top: 0;
|
|
40
|
-
right: 0;
|
|
41
|
-
bottom: 0;
|
|
42
|
-
width: 420px;
|
|
43
|
-
z-index: 2147483647;
|
|
44
|
-
transform: translateX(100%);
|
|
45
|
-
transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
46
|
-
box-shadow: -4px 0 24px rgba(0, 0, 0, 0.3);
|
|
47
|
-
border-left: 1px solid #3a3a3a;
|
|
48
|
-
background: #212121;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
#bloby-ext-panel.bloby-ext-panel-open {
|
|
52
|
-
transform: translateX(0);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/* Mobile: full width */
|
|
56
|
-
@media (max-width: 480px) {
|
|
57
|
-
#bloby-ext-panel {
|
|
58
|
-
width: 100vw;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
#bloby-ext-iframe {
|
|
63
|
-
width: 100%;
|
|
64
|
-
height: 100%;
|
|
65
|
-
border: none;
|
|
66
|
-
background: #212121;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/* Backdrop */
|
|
70
|
-
#bloby-ext-backdrop {
|
|
71
|
-
position: fixed;
|
|
72
|
-
top: 0;
|
|
73
|
-
left: 0;
|
|
74
|
-
right: 0;
|
|
75
|
-
bottom: 0;
|
|
76
|
-
background: rgba(0, 0, 0, 0.4);
|
|
77
|
-
z-index: 2147483645;
|
|
78
|
-
opacity: 0;
|
|
79
|
-
pointer-events: none;
|
|
80
|
-
transition: opacity 0.25s ease;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
#bloby-ext-backdrop.bloby-ext-backdrop-visible {
|
|
84
|
-
opacity: 1;
|
|
85
|
-
pointer-events: auto;
|
|
86
|
-
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"manifest_version": 3,
|
|
3
|
-
"name": "Bloby",
|
|
4
|
-
"version": "0.1.0",
|
|
5
|
-
"description": "Your AI agent, on every page. Chat with Bloby from anywhere.",
|
|
6
|
-
"permissions": [
|
|
7
|
-
"storage",
|
|
8
|
-
"activeTab",
|
|
9
|
-
"declarativeNetRequest"
|
|
10
|
-
],
|
|
11
|
-
"host_permissions": [
|
|
12
|
-
"https://*.bloby.bot/*",
|
|
13
|
-
"https://*.my.bloby.bot/*",
|
|
14
|
-
"https://*.trycloudflare.com/*"
|
|
15
|
-
],
|
|
16
|
-
"action": {
|
|
17
|
-
"default_popup": "popup/popup.html",
|
|
18
|
-
"default_icon": {
|
|
19
|
-
"16": "icons/icon-16.png",
|
|
20
|
-
"48": "icons/icon-48.png",
|
|
21
|
-
"128": "icons/icon-128.png"
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
"background": {
|
|
25
|
-
"service_worker": "background.js",
|
|
26
|
-
"type": "module"
|
|
27
|
-
},
|
|
28
|
-
"content_scripts": [
|
|
29
|
-
{
|
|
30
|
-
"matches": ["<all_urls>"],
|
|
31
|
-
"js": ["content-script.js"],
|
|
32
|
-
"css": ["content-style.css"],
|
|
33
|
-
"run_at": "document_idle"
|
|
34
|
-
}
|
|
35
|
-
],
|
|
36
|
-
"web_accessible_resources": [
|
|
37
|
-
{
|
|
38
|
-
"resources": ["panel/panel.html", "panel/panel.js", "assets/*", "icons/*"],
|
|
39
|
-
"matches": ["<all_urls>"]
|
|
40
|
-
}
|
|
41
|
-
],
|
|
42
|
-
"icons": {
|
|
43
|
-
"16": "icons/icon-16.png",
|
|
44
|
-
"48": "icons/icon-48.png",
|
|
45
|
-
"128": "icons/icon-128.png"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
6
|
-
<title>Bloby</title>
|
|
7
|
-
<style>
|
|
8
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
-
body { background: #212121; width: 100%; height: 100vh; overflow: hidden; }
|
|
10
|
-
iframe { width: 100%; height: 100%; border: none; }
|
|
11
|
-
.loading {
|
|
12
|
-
display: flex; align-items: center; justify-content: center;
|
|
13
|
-
height: 100vh; color: #a1a1aa; font-family: system-ui, sans-serif;
|
|
14
|
-
font-size: 14px; flex-direction: column; gap: 8px;
|
|
15
|
-
}
|
|
16
|
-
.loading .dots span {
|
|
17
|
-
display: inline-block; width: 6px; height: 6px; border-radius: 50%;
|
|
18
|
-
background: #a1a1aa; margin: 0 3px; animation: bounce 1s infinite;
|
|
19
|
-
}
|
|
20
|
-
.loading .dots span:nth-child(2) { animation-delay: 0.15s; }
|
|
21
|
-
.loading .dots span:nth-child(3) { animation-delay: 0.3s; }
|
|
22
|
-
@keyframes bounce {
|
|
23
|
-
0%, 80%, 100% { transform: scale(0); }
|
|
24
|
-
40% { transform: scale(1); }
|
|
25
|
-
}
|
|
26
|
-
.debug { font-size: 11px; color: #52525b; max-width: 90%; word-break: break-all; }
|
|
27
|
-
</style>
|
|
28
|
-
</head>
|
|
29
|
-
<body>
|
|
30
|
-
<div class="loading" id="loading">
|
|
31
|
-
<div class="dots"><span></span><span></span><span></span></div>
|
|
32
|
-
<div class="debug" id="debug"></div>
|
|
33
|
-
</div>
|
|
34
|
-
<script src="panel.js"></script>
|
|
35
|
-
</body>
|
|
36
|
-
</html>
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Panel page — loads the Bloby chat in an iframe and bridges page context.
|
|
3
|
-
*
|
|
4
|
-
* Architecture:
|
|
5
|
-
* Content script (host page) ↔ Panel (this page) ↔ Chat iframe (Bloby server)
|
|
6
|
-
*
|
|
7
|
-
* The panel:
|
|
8
|
-
* 1. Loads the Bloby chat in an iframe
|
|
9
|
-
* 2. Requests page context from the content script
|
|
10
|
-
* 3. Injects context into outgoing chat messages
|
|
11
|
-
* 4. Forwards ExtensionAction commands from chat to content script
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const debug = document.getElementById('debug');
|
|
15
|
-
function log(msg) {
|
|
16
|
-
console.log('[bloby-panel] ' + msg);
|
|
17
|
-
if (debug) debug.textContent = msg;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
let chatIframe = null;
|
|
21
|
-
let currentPageContext = null;
|
|
22
|
-
|
|
23
|
-
(async () => {
|
|
24
|
-
try {
|
|
25
|
-
log('Reading config...');
|
|
26
|
-
const data = await chrome.storage.local.get(['serverUrl', 'authToken']);
|
|
27
|
-
|
|
28
|
-
if (!data.serverUrl) {
|
|
29
|
-
document.getElementById('loading').innerHTML =
|
|
30
|
-
'<span style="color:#ef4444">Not paired. Click the Bloby icon in the toolbar to set up.</span>';
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let chatUrl = data.serverUrl + '/bloby/';
|
|
35
|
-
if (data.authToken) {
|
|
36
|
-
chatUrl += '?token=' + data.authToken;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Add a marker so the chat app knows it's inside the extension
|
|
40
|
-
chatUrl += (chatUrl.includes('?') ? '&' : '?') + 'ext=1';
|
|
41
|
-
|
|
42
|
-
log('Loading: ' + chatUrl);
|
|
43
|
-
|
|
44
|
-
chatIframe = document.createElement('iframe');
|
|
45
|
-
chatIframe.id = 'bloby-chat-iframe';
|
|
46
|
-
chatIframe.src = chatUrl;
|
|
47
|
-
chatIframe.allow = 'microphone';
|
|
48
|
-
chatIframe.style.cssText = 'width:100%;height:100%;border:none;';
|
|
49
|
-
|
|
50
|
-
chatIframe.onload = () => {
|
|
51
|
-
log('Chat loaded!');
|
|
52
|
-
document.getElementById('loading').style.display = 'none';
|
|
53
|
-
// Request initial page context from content script
|
|
54
|
-
requestPageContext();
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
document.body.appendChild(chatIframe);
|
|
58
|
-
|
|
59
|
-
setTimeout(() => {
|
|
60
|
-
if (document.getElementById('loading').style.display !== 'none') {
|
|
61
|
-
log('Timeout loading chat');
|
|
62
|
-
}
|
|
63
|
-
}, 15000);
|
|
64
|
-
|
|
65
|
-
} catch (err) {
|
|
66
|
-
log('Error: ' + err.message);
|
|
67
|
-
}
|
|
68
|
-
})();
|
|
69
|
-
|
|
70
|
-
// ── Page Context ───────────────────────────────────────────────────────────
|
|
71
|
-
|
|
72
|
-
function requestPageContext() {
|
|
73
|
-
// Ask the content script (parent of this panel) for page context
|
|
74
|
-
window.parent.postMessage({ type: 'bloby:get-page-context' }, '*');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// ── Message Handling ───────────────────────────────────────────────────────
|
|
78
|
-
|
|
79
|
-
window.addEventListener('message', (event) => {
|
|
80
|
-
const msg = event.data;
|
|
81
|
-
if (!msg?.type) return;
|
|
82
|
-
|
|
83
|
-
// Context response from content script
|
|
84
|
-
if (msg.type === 'bloby:page-context') {
|
|
85
|
-
currentPageContext = msg.context;
|
|
86
|
-
log('Page context received: ' + (msg.context?.url || 'none'));
|
|
87
|
-
|
|
88
|
-
// Forward to chat iframe so it can use it
|
|
89
|
-
if (chatIframe?.contentWindow) {
|
|
90
|
-
chatIframe.contentWindow.postMessage({
|
|
91
|
-
type: 'bloby:page-context',
|
|
92
|
-
context: msg.context,
|
|
93
|
-
}, '*');
|
|
94
|
-
}
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Action result from content script → forward to chat
|
|
99
|
-
if (msg.type === 'bloby:action-result') {
|
|
100
|
-
if (chatIframe?.contentWindow) {
|
|
101
|
-
chatIframe.contentWindow.postMessage(msg, '*');
|
|
102
|
-
}
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Close request from chat iframe → forward to content script
|
|
107
|
-
if (msg.type === 'bloby:close') {
|
|
108
|
-
window.parent.postMessage({ type: 'bloby:close' }, '*');
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Extension action from chat iframe → forward to content script
|
|
113
|
-
if (msg.type === 'bloby:extension-action') {
|
|
114
|
-
window.parent.postMessage(msg, '*');
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Chat requests fresh page context
|
|
119
|
-
if (msg.type === 'bloby:request-context') {
|
|
120
|
-
requestPageContext();
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
});
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
* {
|
|
2
|
-
margin: 0;
|
|
3
|
-
padding: 0;
|
|
4
|
-
box-sizing: border-box;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
body {
|
|
8
|
-
width: 320px;
|
|
9
|
-
min-height: 280px;
|
|
10
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
11
|
-
background: #0a0a0b;
|
|
12
|
-
color: #e4e4e7;
|
|
13
|
-
padding: 32px 24px;
|
|
14
|
-
text-align: center;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.logo {
|
|
18
|
-
display: flex;
|
|
19
|
-
justify-content: center;
|
|
20
|
-
margin-bottom: 20px;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.logo-dot {
|
|
24
|
-
width: 48px;
|
|
25
|
-
height: 48px;
|
|
26
|
-
border-radius: 50%;
|
|
27
|
-
background: linear-gradient(135deg, #04D1FE, #AF27E3, #FB4072);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.logo-dot.connected {
|
|
31
|
-
box-shadow: 0 0 20px rgba(4, 209, 254, 0.4);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
h1 {
|
|
35
|
-
font-size: 18px;
|
|
36
|
-
font-weight: 600;
|
|
37
|
-
margin-bottom: 6px;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.subtitle {
|
|
41
|
-
font-size: 13px;
|
|
42
|
-
color: #71717a;
|
|
43
|
-
margin-bottom: 24px;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/* Code Input */
|
|
47
|
-
.code-input {
|
|
48
|
-
display: flex;
|
|
49
|
-
gap: 8px;
|
|
50
|
-
justify-content: center;
|
|
51
|
-
margin-bottom: 16px;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.code-input input {
|
|
55
|
-
width: 40px;
|
|
56
|
-
height: 48px;
|
|
57
|
-
border: 2px solid #27272a;
|
|
58
|
-
border-radius: 10px;
|
|
59
|
-
background: #18181b;
|
|
60
|
-
color: #e4e4e7;
|
|
61
|
-
font-size: 22px;
|
|
62
|
-
font-weight: 600;
|
|
63
|
-
text-align: center;
|
|
64
|
-
outline: none;
|
|
65
|
-
transition: border-color 0.15s;
|
|
66
|
-
caret-color: transparent;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.code-input input:focus {
|
|
70
|
-
border-color: #AF27E3;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.code-input input.filled {
|
|
74
|
-
border-color: #04D1FE;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.error {
|
|
78
|
-
color: #ef4444;
|
|
79
|
-
font-size: 13px;
|
|
80
|
-
min-height: 18px;
|
|
81
|
-
margin-bottom: 8px;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.pairing {
|
|
85
|
-
color: #a1a1aa;
|
|
86
|
-
font-size: 13px;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/* Connected Screen */
|
|
90
|
-
.status-badge {
|
|
91
|
-
display: inline-flex;
|
|
92
|
-
align-items: center;
|
|
93
|
-
gap: 6px;
|
|
94
|
-
background: #18181b;
|
|
95
|
-
border: 1px solid #27272a;
|
|
96
|
-
border-radius: 999px;
|
|
97
|
-
padding: 6px 14px;
|
|
98
|
-
font-size: 13px;
|
|
99
|
-
color: #a1a1aa;
|
|
100
|
-
margin-bottom: 20px;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
.status-dot {
|
|
104
|
-
width: 8px;
|
|
105
|
-
height: 8px;
|
|
106
|
-
border-radius: 50%;
|
|
107
|
-
background: #22c55e;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.btn-disconnect {
|
|
111
|
-
background: none;
|
|
112
|
-
border: 1px solid #27272a;
|
|
113
|
-
border-radius: 8px;
|
|
114
|
-
color: #71717a;
|
|
115
|
-
padding: 8px 16px;
|
|
116
|
-
font-size: 13px;
|
|
117
|
-
cursor: pointer;
|
|
118
|
-
transition: all 0.15s;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
.btn-disconnect:hover {
|
|
122
|
-
border-color: #ef4444;
|
|
123
|
-
color: #ef4444;
|
|
124
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Bloby</title>
|
|
7
|
-
<link rel="stylesheet" href="popup.css">
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<!-- Pairing Screen -->
|
|
11
|
-
<div id="pair-screen">
|
|
12
|
-
<div class="logo">
|
|
13
|
-
<div class="logo-dot"></div>
|
|
14
|
-
</div>
|
|
15
|
-
<h1>Connect to Bloby</h1>
|
|
16
|
-
<p class="subtitle">Ask your Bloby for a pairing code</p>
|
|
17
|
-
|
|
18
|
-
<div class="code-input" id="code-input">
|
|
19
|
-
<input type="text" maxlength="1" pattern="[0-9]" inputmode="numeric" autofocus>
|
|
20
|
-
<input type="text" maxlength="1" pattern="[0-9]" inputmode="numeric">
|
|
21
|
-
<input type="text" maxlength="1" pattern="[0-9]" inputmode="numeric">
|
|
22
|
-
<input type="text" maxlength="1" pattern="[0-9]" inputmode="numeric">
|
|
23
|
-
<input type="text" maxlength="1" pattern="[0-9]" inputmode="numeric">
|
|
24
|
-
<input type="text" maxlength="1" pattern="[0-9]" inputmode="numeric">
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
<div id="error" class="error"></div>
|
|
28
|
-
<div id="pairing" class="pairing" style="display:none">Connecting...</div>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<!-- Connected Screen -->
|
|
32
|
-
<div id="connected-screen" style="display:none">
|
|
33
|
-
<div class="logo">
|
|
34
|
-
<div class="logo-dot connected"></div>
|
|
35
|
-
</div>
|
|
36
|
-
<h1 id="connected-name">Connected</h1>
|
|
37
|
-
<p class="subtitle" id="connected-url"></p>
|
|
38
|
-
<div class="status-badge">
|
|
39
|
-
<span class="status-dot"></span>
|
|
40
|
-
<span id="status-text">Connected</span>
|
|
41
|
-
</div>
|
|
42
|
-
<button id="disconnect-btn" class="btn-disconnect">Disconnect</button>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
<script src="popup.js"></script>
|
|
46
|
-
</body>
|
|
47
|
-
</html>
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bloby Chrome Extension — Popup
|
|
3
|
-
*
|
|
4
|
-
* Shows either:
|
|
5
|
-
* - Pairing screen: 6-digit code input to connect to a Bloby instance
|
|
6
|
-
* - Connected screen: status + disconnect button
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const pairScreen = document.getElementById('pair-screen');
|
|
10
|
-
const connectedScreen = document.getElementById('connected-screen');
|
|
11
|
-
const errorEl = document.getElementById('error');
|
|
12
|
-
const pairingEl = document.getElementById('pairing');
|
|
13
|
-
const inputs = document.querySelectorAll('.code-input input');
|
|
14
|
-
|
|
15
|
-
// ── Init: check current state ──────────────────────────────────────────────
|
|
16
|
-
|
|
17
|
-
chrome.runtime.sendMessage({ type: 'bloby:get-state' }, (state) => {
|
|
18
|
-
if (state?.paired) {
|
|
19
|
-
showConnected(state);
|
|
20
|
-
} else {
|
|
21
|
-
showPairing();
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// ── Pairing Screen ─────────────────────────────────────────────────────────
|
|
26
|
-
|
|
27
|
-
function showPairing() {
|
|
28
|
-
pairScreen.style.display = 'block';
|
|
29
|
-
connectedScreen.style.display = 'none';
|
|
30
|
-
inputs[0].focus();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Auto-advance between code inputs
|
|
34
|
-
inputs.forEach((input, i) => {
|
|
35
|
-
input.addEventListener('input', (e) => {
|
|
36
|
-
const val = e.target.value.replace(/\D/g, '');
|
|
37
|
-
e.target.value = val;
|
|
38
|
-
|
|
39
|
-
if (val) {
|
|
40
|
-
e.target.classList.add('filled');
|
|
41
|
-
if (i < inputs.length - 1) {
|
|
42
|
-
inputs[i + 1].focus();
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Check if all filled
|
|
47
|
-
const code = Array.from(inputs).map((inp) => inp.value).join('');
|
|
48
|
-
if (code.length === 6) {
|
|
49
|
-
submitCode(code);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
input.addEventListener('keydown', (e) => {
|
|
54
|
-
if (e.key === 'Backspace' && !e.target.value && i > 0) {
|
|
55
|
-
inputs[i - 1].focus();
|
|
56
|
-
inputs[i - 1].value = '';
|
|
57
|
-
inputs[i - 1].classList.remove('filled');
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// Handle paste
|
|
62
|
-
input.addEventListener('paste', (e) => {
|
|
63
|
-
e.preventDefault();
|
|
64
|
-
const pasted = (e.clipboardData.getData('text') || '').replace(/\D/g, '').slice(0, 6);
|
|
65
|
-
pasted.split('').forEach((char, j) => {
|
|
66
|
-
if (inputs[j]) {
|
|
67
|
-
inputs[j].value = char;
|
|
68
|
-
inputs[j].classList.add('filled');
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
if (pasted.length === 6) {
|
|
72
|
-
submitCode(pasted);
|
|
73
|
-
} else if (pasted.length > 0) {
|
|
74
|
-
inputs[Math.min(pasted.length, 5)].focus();
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
async function submitCode(code) {
|
|
80
|
-
errorEl.textContent = '';
|
|
81
|
-
pairingEl.style.display = 'block';
|
|
82
|
-
inputs.forEach((inp) => { inp.disabled = true; });
|
|
83
|
-
|
|
84
|
-
chrome.runtime.sendMessage({ type: 'bloby:pair', code }, (result) => {
|
|
85
|
-
pairingEl.style.display = 'none';
|
|
86
|
-
|
|
87
|
-
if (result?.success) {
|
|
88
|
-
showConnected({
|
|
89
|
-
config: { serverUrl: result.serverUrl, username: result.username },
|
|
90
|
-
connected: true,
|
|
91
|
-
});
|
|
92
|
-
} else {
|
|
93
|
-
errorEl.textContent = result?.error || 'Pairing failed';
|
|
94
|
-
inputs.forEach((inp) => { inp.disabled = false; inp.value = ''; inp.classList.remove('filled'); });
|
|
95
|
-
inputs[0].focus();
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// ── Connected Screen ───────────────────────────────────────────────────────
|
|
101
|
-
|
|
102
|
-
function showConnected(state) {
|
|
103
|
-
pairScreen.style.display = 'none';
|
|
104
|
-
connectedScreen.style.display = 'block';
|
|
105
|
-
|
|
106
|
-
document.getElementById('connected-name').textContent = state.config?.username || 'Connected';
|
|
107
|
-
document.getElementById('connected-url').textContent = state.config?.serverUrl || '';
|
|
108
|
-
document.getElementById('status-text').textContent = state.connected ? 'Connected' : 'Offline';
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
document.getElementById('disconnect-btn').addEventListener('click', () => {
|
|
112
|
-
chrome.runtime.sendMessage({ type: 'bloby:unpair' }, () => {
|
|
113
|
-
showPairing();
|
|
114
|
-
});
|
|
115
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "chrome-extension",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"bloby_human": "Bruno Bertapeli",
|
|
5
|
-
"bloby": "bloby-bruno",
|
|
6
|
-
"author": "newbot-official",
|
|
7
|
-
"description": "Bloby on every webpage. Browse with your AI agent — transcribe videos, compare prices, summarize articles, and more.",
|
|
8
|
-
"type": "skill",
|
|
9
|
-
"depends": [],
|
|
10
|
-
"env_keys": [],
|
|
11
|
-
"has_telemetry": false,
|
|
12
|
-
"size": "32KB",
|
|
13
|
-
"contains_binaries": false,
|
|
14
|
-
"tags": ["chrome", "extension", "browser", "productivity", "assistant"]
|
|
15
|
-
}
|
|
File without changes
|