gazesight 0.3.5
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/LICENSE +37 -0
- package/README.md +102 -0
- package/dist/chrome/background-capture-offscreen.html +10 -0
- package/dist/chrome/background-capture-offscreen.js +1 -0
- package/dist/chrome/background.js +62 -0
- package/dist/chrome/content.js +62 -0
- package/dist/chrome/diagnostics-page.js +1 -0
- package/dist/chrome/fullpage-stitch-offscreen.html +10 -0
- package/dist/chrome/fullpage-stitch-offscreen.js +1 -0
- package/dist/chrome/icons/icon-128.png +0 -0
- package/dist/chrome/icons/icon-16.png +0 -0
- package/dist/chrome/icons/icon-32.png +0 -0
- package/dist/chrome/icons/icon-48.png +0 -0
- package/dist/chrome/icons/icon-64.png +0 -0
- package/dist/chrome/icons/icon-96.png +0 -0
- package/dist/chrome/logo_sans_background.png +0 -0
- package/dist/chrome/manifest.json +70 -0
- package/dist/chrome/options.css +66 -0
- package/dist/chrome/options.html +76 -0
- package/dist/chrome/options.js +82 -0
- package/dist/chrome/permission.css +13 -0
- package/dist/chrome/permission.html +15 -0
- package/dist/chrome/permission.js +1 -0
- package/dist/chrome/popup.css +446 -0
- package/dist/chrome/popup.html +191 -0
- package/dist/chrome/popup.js +1 -0
- package/dist/cli/index.js +320 -0
- package/dist/firefox/background.js +62 -0
- package/dist/firefox/content.js +62 -0
- package/dist/firefox/diagnostics-page.js +1 -0
- package/dist/firefox/icons/icon-128.png +0 -0
- package/dist/firefox/icons/icon-16.png +0 -0
- package/dist/firefox/icons/icon-32.png +0 -0
- package/dist/firefox/icons/icon-48.png +0 -0
- package/dist/firefox/icons/icon-64.png +0 -0
- package/dist/firefox/icons/icon-96.png +0 -0
- package/dist/firefox/logo_sans_background.png +0 -0
- package/dist/firefox/manifest.json +90 -0
- package/dist/firefox/options.css +66 -0
- package/dist/firefox/options.html +76 -0
- package/dist/firefox/options.js +82 -0
- package/dist/firefox/permission.css +13 -0
- package/dist/firefox/permission.html +15 -0
- package/dist/firefox/permission.js +1 -0
- package/dist/firefox/popup.css +446 -0
- package/dist/firefox/popup.html +191 -0
- package/dist/firefox/popup.js +1 -0
- package/dist/gazesight-firefox.xpi +0 -0
- package/dist/mcp/index.js +1428 -0
- package/dist/worker/visual-diff.js +642 -0
- package/docs/preview-matrix.csv +6 -0
- package/package.json +130 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
:root { font-family: system-ui, sans-serif; color: #180a69; background: #f4f5ff; }
|
|
2
|
+
body { margin: 0; min-height: 100vh; display: grid; place-items: center; }
|
|
3
|
+
main { width: min(520px, calc(100vw - 48px)); box-sizing: border-box; padding: 38px; border: 1px solid #6848ca; border-radius: 20px; background: #fff; box-shadow: 0 14px 42px #2d15782e; }
|
|
4
|
+
img { width: 54px; height: 54px; object-fit: contain; }
|
|
5
|
+
.eyebrow { margin: 12px 0 4px; color: #645b93; text-transform: uppercase; letter-spacing: 1.2px; font-size: 12px; }
|
|
6
|
+
h1 { margin: 0 0 18px; font-size: 28px; }
|
|
7
|
+
p { line-height: 1.55; color: #4e4778; }
|
|
8
|
+
#status { min-height: 24px; color: #241084; font-weight: 600; }
|
|
9
|
+
.actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 22px; }
|
|
10
|
+
button { padding: 11px 16px; border: 1px solid #c8c6ee; border-radius: 8px; background: #fff; color: #241084; cursor: pointer; font: inherit; }
|
|
11
|
+
button:disabled { opacity: .55; cursor: default; }
|
|
12
|
+
button:focus-visible { outline: 3px solid #7653d6; outline-offset: 3px; }
|
|
13
|
+
.primary { border-color: #4d25b9; background: linear-gradient(110deg, #4d25b9, #4930b3); color: #fff; }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>GazeSight permission</title><link rel="stylesheet" href="permission.css" /></head>
|
|
3
|
+
<body><main><img src="logo_sans_background.png" alt="" /><p class="eyebrow">GazeSight permission</p><h1 id="title">Allow screenshot download?</h1>
|
|
4
|
+
<div id="download-copy"><p>Firefox needs the Downloads permission to save this FAST screenshot into your configured Downloads folder.</p><p>GazeSight cannot choose an arbitrary filesystem path.</p></div>
|
|
5
|
+
<div id="background-copy" hidden>
|
|
6
|
+
<p>Firefox requires the optional “Access your data for all websites” permission for its background-tab screenshot API. This Firefox permission is broad; it is not technically limited to one tab.</p>
|
|
7
|
+
<p>GazeSight keeps Background Capture off by default and internally restricts every operation to the development tab and origin you explicitly selected. A different origin requires you to select the tab again.</p>
|
|
8
|
+
<p>Without this optional permission, foreground capture remains available. Disable Background Capture at any time to revoke it. GazeSight sends page content only to your local MCP connection, never to a GazeSight cloud service.</p>
|
|
9
|
+
</div>
|
|
10
|
+
<div id="continuous-copy" hidden>
|
|
11
|
+
<p>Firefox requires the same optional “Access your data for all websites” permission so GazeSight can stay connected to your selected tab across reloads, same-origin navigation and responsive previews, without asking you to click the icon again each time.</p>
|
|
12
|
+
<p>GazeSight still only acts on the one tab and origin you explicitly selected, plus GazeSight-created preview windows derived from it. Navigating to a different origin always requires selecting the tab again.</p>
|
|
13
|
+
<p>Disable Continuous Access at any time to revoke it. GazeSight sends page content only to your local MCP connection, never to a GazeSight cloud service.</p>
|
|
14
|
+
</div>
|
|
15
|
+
<p id="status" role="status" aria-live="polite"></p><div class="actions"><button id="cancel">Cancel</button><button id="allow" class="primary">Allow and continue</button></div></main><script type="module" src="permission.js"></script></body></html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var z=Object.create;var F=Object.defineProperty;var H=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var G=Object.getPrototypeOf,V=Object.prototype.hasOwnProperty;var K=(g,a)=>()=>(a||g((a={exports:{}}).exports,a),a.exports);var J=(g,a,o,d)=>{if(a&&typeof a=="object"||typeof a=="function")for(let f of Z(a))!V.call(g,f)&&f!==o&&F(g,f,{get:()=>a[f],enumerable:!(d=H(a,f))||d.enumerable});return g};var Q=(g,a,o)=>(o=g!=null?z(G(g)):{},J(a||!g||!g.__esModule?F(o,"default",{value:g,enumerable:!0}):o,g));var _=K((v,I)=>{(function(g,a){if(typeof define=="function"&&define.amd)define("webextension-polyfill",["module"],a);else if(typeof v<"u")a(I);else{var o={exports:{}};a(o),g.browser=o.exports}})(typeof globalThis<"u"?globalThis:typeof self<"u"?self:v,function(g){"use strict";if(!(globalThis.chrome&&globalThis.chrome.runtime&&globalThis.chrome.runtime.id))throw new Error("This script should only be loaded in a browser extension.");if(globalThis.browser&&globalThis.browser.runtime&&globalThis.browser.runtime.id)g.exports=globalThis.browser;else{let a="The message port closed before a response was received.",o=d=>{let f={alarms:{clear:{minArgs:0,maxArgs:1},clearAll:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getAll:{minArgs:0,maxArgs:0}},bookmarks:{create:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},getChildren:{minArgs:1,maxArgs:1},getRecent:{minArgs:1,maxArgs:1},getSubTree:{minArgs:1,maxArgs:1},getTree:{minArgs:0,maxArgs:0},move:{minArgs:2,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeTree:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}},browserAction:{disable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},enable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},getBadgeBackgroundColor:{minArgs:1,maxArgs:1},getBadgeText:{minArgs:1,maxArgs:1},getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},openPopup:{minArgs:0,maxArgs:0},setBadgeBackgroundColor:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setBadgeText:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},browsingData:{remove:{minArgs:2,maxArgs:2},removeCache:{minArgs:1,maxArgs:1},removeCookies:{minArgs:1,maxArgs:1},removeDownloads:{minArgs:1,maxArgs:1},removeFormData:{minArgs:1,maxArgs:1},removeHistory:{minArgs:1,maxArgs:1},removeLocalStorage:{minArgs:1,maxArgs:1},removePasswords:{minArgs:1,maxArgs:1},removePluginData:{minArgs:1,maxArgs:1},settings:{minArgs:0,maxArgs:0}},commands:{getAll:{minArgs:0,maxArgs:0}},contextMenus:{remove:{minArgs:1,maxArgs:1},removeAll:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},cookies:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:1,maxArgs:1},getAllCookieStores:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},devtools:{inspectedWindow:{eval:{minArgs:1,maxArgs:2,singleCallbackArg:!1}},panels:{create:{minArgs:3,maxArgs:3,singleCallbackArg:!0},elements:{createSidebarPane:{minArgs:1,maxArgs:1}}}},downloads:{cancel:{minArgs:1,maxArgs:1},download:{minArgs:1,maxArgs:1},erase:{minArgs:1,maxArgs:1},getFileIcon:{minArgs:1,maxArgs:2},open:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},pause:{minArgs:1,maxArgs:1},removeFile:{minArgs:1,maxArgs:1},resume:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},extension:{isAllowedFileSchemeAccess:{minArgs:0,maxArgs:0},isAllowedIncognitoAccess:{minArgs:0,maxArgs:0}},history:{addUrl:{minArgs:1,maxArgs:1},deleteAll:{minArgs:0,maxArgs:0},deleteRange:{minArgs:1,maxArgs:1},deleteUrl:{minArgs:1,maxArgs:1},getVisits:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1}},i18n:{detectLanguage:{minArgs:1,maxArgs:1},getAcceptLanguages:{minArgs:0,maxArgs:0}},identity:{launchWebAuthFlow:{minArgs:1,maxArgs:1}},idle:{queryState:{minArgs:1,maxArgs:1}},management:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},getSelf:{minArgs:0,maxArgs:0},setEnabled:{minArgs:2,maxArgs:2},uninstallSelf:{minArgs:0,maxArgs:1}},notifications:{clear:{minArgs:1,maxArgs:1},create:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:0},getPermissionLevel:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},pageAction:{getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},hide:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},permissions:{contains:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},request:{minArgs:1,maxArgs:1}},runtime:{getBackgroundPage:{minArgs:0,maxArgs:0},getPlatformInfo:{minArgs:0,maxArgs:0},openOptionsPage:{minArgs:0,maxArgs:0},requestUpdateCheck:{minArgs:0,maxArgs:0},sendMessage:{minArgs:1,maxArgs:3},sendNativeMessage:{minArgs:2,maxArgs:2},setUninstallURL:{minArgs:1,maxArgs:1}},sessions:{getDevices:{minArgs:0,maxArgs:1},getRecentlyClosed:{minArgs:0,maxArgs:1},restore:{minArgs:0,maxArgs:1}},storage:{local:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},managed:{get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1}},sync:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}}},tabs:{captureVisibleTab:{minArgs:0,maxArgs:2},create:{minArgs:1,maxArgs:1},detectLanguage:{minArgs:0,maxArgs:1},discard:{minArgs:0,maxArgs:1},duplicate:{minArgs:1,maxArgs:1},executeScript:{minArgs:1,maxArgs:2},get:{minArgs:1,maxArgs:1},getCurrent:{minArgs:0,maxArgs:0},getZoom:{minArgs:0,maxArgs:1},getZoomSettings:{minArgs:0,maxArgs:1},goBack:{minArgs:0,maxArgs:1},goForward:{minArgs:0,maxArgs:1},highlight:{minArgs:1,maxArgs:1},insertCSS:{minArgs:1,maxArgs:2},move:{minArgs:2,maxArgs:2},query:{minArgs:1,maxArgs:1},reload:{minArgs:0,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeCSS:{minArgs:1,maxArgs:2},sendMessage:{minArgs:2,maxArgs:3},setZoom:{minArgs:1,maxArgs:2},setZoomSettings:{minArgs:1,maxArgs:2},update:{minArgs:1,maxArgs:2}},topSites:{get:{minArgs:0,maxArgs:0}},webNavigation:{getAllFrames:{minArgs:1,maxArgs:1},getFrame:{minArgs:1,maxArgs:1}},webRequest:{handlerBehaviorChanged:{minArgs:0,maxArgs:0}},windows:{create:{minArgs:0,maxArgs:1},get:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:1},getCurrent:{minArgs:0,maxArgs:1},getLastFocused:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}}};if(Object.keys(f).length===0)throw new Error("api-metadata.json has not been included in browser-polyfill");class B extends WeakMap{constructor(s,n=void 0){super(n),this.createItem=s}get(s){return this.has(s)||this.set(s,this.createItem(s)),super.get(s)}}let j=e=>e&&typeof e=="object"&&typeof e.then=="function",L=(e,s)=>(...n)=>{d.runtime.lastError?e.reject(new Error(d.runtime.lastError.message)):s.singleCallbackArg||n.length<=1&&s.singleCallbackArg!==!1?e.resolve(n[0]):e.resolve(n)},w=e=>e==1?"argument":"arguments",q=(e,s)=>function(t,...m){if(m.length<s.minArgs)throw new Error(`Expected at least ${s.minArgs} ${w(s.minArgs)} for ${e}(), got ${m.length}`);if(m.length>s.maxArgs)throw new Error(`Expected at most ${s.maxArgs} ${w(s.maxArgs)} for ${e}(), got ${m.length}`);return new Promise((A,l)=>{if(s.fallbackToNoCallback)try{t[e](...m,L({resolve:A,reject:l},s))}catch(r){console.warn(`${e} API method doesn't seem to support the callback parameter, falling back to call it without a callback: `,r),t[e](...m),s.fallbackToNoCallback=!1,s.noCallback=!0,A()}else s.noCallback?(t[e](...m),A()):t[e](...m,L({resolve:A,reject:l},s))})},R=(e,s,n)=>new Proxy(s,{apply(t,m,A){return n.call(m,e,...A)}}),p=Function.call.bind(Object.prototype.hasOwnProperty),k=(e,s={},n={})=>{let t=Object.create(null),m={has(l,r){return r in e||r in t},get(l,r,c){if(r in t)return t[r];if(!(r in e))return;let i=e[r];if(typeof i=="function")if(typeof s[r]=="function")i=R(e,e[r],s[r]);else if(p(n,r)){let b=q(r,n[r]);i=R(e,e[r],b)}else i=i.bind(e);else if(typeof i=="object"&&i!==null&&(p(s,r)||p(n,r)))i=k(i,s[r],n[r]);else if(p(n,"*"))i=k(i,s[r],n["*"]);else return Object.defineProperty(t,r,{configurable:!0,enumerable:!0,get(){return e[r]},set(b){e[r]=b}}),i;return t[r]=i,i},set(l,r,c,i){return r in t?t[r]=c:e[r]=c,!0},defineProperty(l,r,c){return Reflect.defineProperty(t,r,c)},deleteProperty(l,r){return Reflect.deleteProperty(t,r)}},A=Object.create(e);return new Proxy(A,m)},C=e=>({addListener(s,n,...t){s.addListener(e.get(n),...t)},hasListener(s,n){return s.hasListener(e.get(n))},removeListener(s,n){s.removeListener(e.get(n))}}),W=new B(e=>typeof e!="function"?e:function(n){let t=k(n,{},{getContent:{minArgs:0,maxArgs:0}});e(t)}),N=new B(e=>typeof e!="function"?e:function(n,t,m){let A=!1,l,r=new Promise(h=>{l=function(u){A=!0,h(u)}}),c;try{c=e(n,t,l)}catch(h){c=Promise.reject(h)}let i=c!==!0&&j(c);if(c!==!0&&!i&&!A)return!1;let b=h=>{h.then(u=>{m(u)},u=>{let T;u&&(u instanceof Error||typeof u.message=="string")?T=u.message:T="An unexpected error occurred",m({__mozWebExtensionPolyfillReject__:!0,message:T})}).catch(u=>{console.error("Failed to send onMessage rejected reply",u)})};return b(i?c:r),!0}),U=({reject:e,resolve:s},n)=>{d.runtime.lastError?d.runtime.lastError.message===a?s():e(new Error(d.runtime.lastError.message)):n&&n.__mozWebExtensionPolyfillReject__?e(new Error(n.message)):s(n)},$=(e,s,n,...t)=>{if(t.length<s.minArgs)throw new Error(`Expected at least ${s.minArgs} ${w(s.minArgs)} for ${e}(), got ${t.length}`);if(t.length>s.maxArgs)throw new Error(`Expected at most ${s.maxArgs} ${w(s.maxArgs)} for ${e}(), got ${t.length}`);return new Promise((m,A)=>{let l=U.bind(null,{resolve:m,reject:A});t.push(l),n.sendMessage(...t)})},D={devtools:{network:{onRequestFinished:C(W)}},runtime:{onMessage:C(N),onMessageExternal:C(N),sendMessage:$.bind(null,"sendMessage",{minArgs:1,maxArgs:3})},tabs:{sendMessage:$.bind(null,"sendMessage",{minArgs:2,maxArgs:3})}},E={clear:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}};return f.privacy={network:{"*":E},services:{"*":E},websites:{"*":E}},k(d,D,f)};g.exports=o(chrome)}})});var O=Q(_(),1);globalThis.browser=O.default;var X=new URLSearchParams(location.search),P=X.get("action"),x=P==="background"||P==="continuous"?P:"download",S=document.getElementById("allow"),M=document.getElementById("cancel"),y=document.getElementById("status");x==="background"&&(document.getElementById("title").textContent="Enable background capture?",document.getElementById("download-copy").hidden=!0,document.getElementById("background-copy").hidden=!1);x==="continuous"&&(document.getElementById("title").textContent="Enable continuous access?",document.getElementById("download-copy").hidden=!0,document.getElementById("continuous-copy").hidden=!1);M.addEventListener("click",()=>window.close());S.addEventListener("click",async()=>{S.disabled=!0,M.disabled=!0,y.textContent="Waiting for Chrome permission\u2026";try{if(!(x==="background"?await chrome.permissions.request({permissions:["tabCapture","offscreen"]}):await browser.permissions.request(x==="continuous"?{origins:["<all_urls>"]}:{permissions:["downloads"]}))){x==="background"&&await browser.runtime.sendMessage({type:"gazesight-ui",action:"background-denied"}),x==="continuous"&&await browser.runtime.sendMessage({type:"gazesight-ui",action:"continuous-denied"}),y.textContent="Permission was not granted.";return}let a=x==="background"?"background-enable":x==="continuous"?"continuous-enable":"fast",o=await browser.runtime.sendMessage({type:"gazesight-ui",action:a});if(!o?.ok)throw new Error(o?.error??"Operation failed.");y.textContent=x==="background"?"Background capture enabled.":x==="continuous"?"Continuous access enabled.":`\u2713 Saved to Downloads/${o.value.filename}`,setTimeout(()=>window.close(),1100);return}catch(g){y.textContent=g instanceof Error?g.message:"Operation failed."}finally{S.disabled=!1,M.disabled=!1}});
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
font-family: "Segoe UI", Arial, sans-serif;
|
|
3
|
+
color: #160653;
|
|
4
|
+
background: transparent;
|
|
5
|
+
color-scheme: light;
|
|
6
|
+
--muted: #625a94;
|
|
7
|
+
--line: #dddfff;
|
|
8
|
+
--card-radius: 20px;
|
|
9
|
+
}
|
|
10
|
+
* {
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
body {
|
|
14
|
+
width: 420px;
|
|
15
|
+
margin: 0;
|
|
16
|
+
padding: 0;
|
|
17
|
+
background: transparent;
|
|
18
|
+
}
|
|
19
|
+
.dashboard {
|
|
20
|
+
border: 1px solid #6848ca;
|
|
21
|
+
border-radius: var(--card-radius);
|
|
22
|
+
background: #fff;
|
|
23
|
+
box-shadow: 0 10px 28px rgba(45, 21, 120, 0.22);
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
}
|
|
26
|
+
header {
|
|
27
|
+
height: 81px;
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
gap: 11px;
|
|
31
|
+
padding: 0 24px 10px;
|
|
32
|
+
color: #fff;
|
|
33
|
+
background: linear-gradient(120deg, #4723b0, #38188d);
|
|
34
|
+
box-shadow: inset 0 1px 1px #9f7de9;
|
|
35
|
+
}
|
|
36
|
+
.sight {
|
|
37
|
+
flex: none;
|
|
38
|
+
width: 38px;
|
|
39
|
+
height: 38px;
|
|
40
|
+
object-fit: contain;
|
|
41
|
+
transform: scale(1.18);
|
|
42
|
+
}
|
|
43
|
+
h1 {
|
|
44
|
+
font-size: 25px;
|
|
45
|
+
line-height: 1;
|
|
46
|
+
font-weight: 750;
|
|
47
|
+
letter-spacing: -0.9px;
|
|
48
|
+
margin: 0;
|
|
49
|
+
}
|
|
50
|
+
.connection-pill {
|
|
51
|
+
display: flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
gap: 6px;
|
|
54
|
+
margin-left: auto;
|
|
55
|
+
padding: 6px 9px;
|
|
56
|
+
border: 1px solid #a480ef40;
|
|
57
|
+
border-radius: 20px;
|
|
58
|
+
font-size: 12px;
|
|
59
|
+
white-space: nowrap;
|
|
60
|
+
background: #7351d01a;
|
|
61
|
+
}
|
|
62
|
+
.connection-dot {
|
|
63
|
+
width: 10px;
|
|
64
|
+
height: 10px;
|
|
65
|
+
border-radius: 50%;
|
|
66
|
+
background: #e52d3d;
|
|
67
|
+
flex: none;
|
|
68
|
+
}
|
|
69
|
+
body[data-connected="true"] .connection-dot {
|
|
70
|
+
background: #00c718;
|
|
71
|
+
}
|
|
72
|
+
.paper {
|
|
73
|
+
position: relative;
|
|
74
|
+
margin-top: -13px;
|
|
75
|
+
border-radius: var(--card-radius);
|
|
76
|
+
background: linear-gradient(115deg, #fff, #fcfcff);
|
|
77
|
+
}
|
|
78
|
+
main {
|
|
79
|
+
padding: 13px 14px 0;
|
|
80
|
+
}
|
|
81
|
+
.status {
|
|
82
|
+
display: grid;
|
|
83
|
+
grid-template-columns: 1fr 1fr;
|
|
84
|
+
gap: 10px;
|
|
85
|
+
margin: 0 0 10px;
|
|
86
|
+
}
|
|
87
|
+
.status-card {
|
|
88
|
+
min-width: 0;
|
|
89
|
+
min-height: 59px;
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
gap: 10px;
|
|
93
|
+
padding: 10px;
|
|
94
|
+
border: 1px solid #e3e5ff;
|
|
95
|
+
border-radius: 8px;
|
|
96
|
+
background: #f5f6ffb3;
|
|
97
|
+
}
|
|
98
|
+
.status-card > div {
|
|
99
|
+
display: grid;
|
|
100
|
+
gap: 4px;
|
|
101
|
+
}
|
|
102
|
+
dt,
|
|
103
|
+
.caption {
|
|
104
|
+
color: var(--muted);
|
|
105
|
+
font-size: 9px;
|
|
106
|
+
font-weight: 600;
|
|
107
|
+
letter-spacing: 0.8px;
|
|
108
|
+
text-transform: uppercase;
|
|
109
|
+
}
|
|
110
|
+
dd {
|
|
111
|
+
margin: 0;
|
|
112
|
+
}
|
|
113
|
+
.status dd {
|
|
114
|
+
font-size: 15px;
|
|
115
|
+
font-weight: 700;
|
|
116
|
+
line-height: 1.2;
|
|
117
|
+
}
|
|
118
|
+
.background-capture {
|
|
119
|
+
margin-bottom: 10px;
|
|
120
|
+
padding: 10px 12px;
|
|
121
|
+
border: 1px solid #e3e5ff;
|
|
122
|
+
border-radius: 8px;
|
|
123
|
+
background: #f5f6ffb3;
|
|
124
|
+
}
|
|
125
|
+
.background-heading {
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
justify-content: space-between;
|
|
129
|
+
gap: 12px;
|
|
130
|
+
}
|
|
131
|
+
.background-heading > div {
|
|
132
|
+
display: grid;
|
|
133
|
+
gap: 4px;
|
|
134
|
+
}
|
|
135
|
+
.background-heading strong {
|
|
136
|
+
display: flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
gap: 7px;
|
|
139
|
+
font-size: 14px;
|
|
140
|
+
}
|
|
141
|
+
#background-dot {
|
|
142
|
+
width: 9px;
|
|
143
|
+
height: 9px;
|
|
144
|
+
border: 2px solid #665e94;
|
|
145
|
+
border-radius: 50%;
|
|
146
|
+
}
|
|
147
|
+
body[data-background="enabled"] #background-dot {
|
|
148
|
+
border-color: #00c718;
|
|
149
|
+
background: #00c718;
|
|
150
|
+
}
|
|
151
|
+
#continuous-dot {
|
|
152
|
+
width: 9px;
|
|
153
|
+
height: 9px;
|
|
154
|
+
border: 2px solid #665e94;
|
|
155
|
+
border-radius: 50%;
|
|
156
|
+
}
|
|
157
|
+
body[data-continuous="enabled"] #continuous-dot {
|
|
158
|
+
border-color: #00c718;
|
|
159
|
+
background: #00c718;
|
|
160
|
+
}
|
|
161
|
+
#continuous-toggle {
|
|
162
|
+
min-width: 64px;
|
|
163
|
+
padding: 6px 10px;
|
|
164
|
+
color: #4723b0;
|
|
165
|
+
font-size: 11px;
|
|
166
|
+
font-weight: 700;
|
|
167
|
+
}
|
|
168
|
+
#continuous-description {
|
|
169
|
+
margin: 7px 0 0;
|
|
170
|
+
color: var(--muted);
|
|
171
|
+
font-size: 11px;
|
|
172
|
+
line-height: 1.45;
|
|
173
|
+
}
|
|
174
|
+
#background-toggle {
|
|
175
|
+
min-width: 64px;
|
|
176
|
+
padding: 6px 10px;
|
|
177
|
+
color: #4723b0;
|
|
178
|
+
font-size: 11px;
|
|
179
|
+
font-weight: 700;
|
|
180
|
+
}
|
|
181
|
+
#background-description {
|
|
182
|
+
margin: 7px 0 0;
|
|
183
|
+
color: var(--muted);
|
|
184
|
+
font-size: 11px;
|
|
185
|
+
line-height: 1.45;
|
|
186
|
+
}
|
|
187
|
+
dialog {
|
|
188
|
+
width: 360px;
|
|
189
|
+
padding: 0;
|
|
190
|
+
border: 1px solid #6848ca;
|
|
191
|
+
border-radius: 14px;
|
|
192
|
+
color: #160653;
|
|
193
|
+
box-shadow: 0 14px 40px #210c6250;
|
|
194
|
+
}
|
|
195
|
+
dialog::backdrop {
|
|
196
|
+
background: rgba(20, 6, 83, 0.42);
|
|
197
|
+
}
|
|
198
|
+
dialog form {
|
|
199
|
+
padding: 18px;
|
|
200
|
+
}
|
|
201
|
+
dialog h2 {
|
|
202
|
+
margin: 0 0 10px;
|
|
203
|
+
}
|
|
204
|
+
dialog p {
|
|
205
|
+
color: var(--muted);
|
|
206
|
+
font-size: 12px;
|
|
207
|
+
line-height: 1.5;
|
|
208
|
+
}
|
|
209
|
+
.consent-actions {
|
|
210
|
+
display: flex;
|
|
211
|
+
justify-content: flex-end;
|
|
212
|
+
gap: 8px;
|
|
213
|
+
margin-top: 14px;
|
|
214
|
+
}
|
|
215
|
+
.consent-actions button {
|
|
216
|
+
padding: 8px 10px;
|
|
217
|
+
}
|
|
218
|
+
#background-confirm {
|
|
219
|
+
background: #4723b0;
|
|
220
|
+
border-color: #4723b0;
|
|
221
|
+
color: white;
|
|
222
|
+
}
|
|
223
|
+
.icon {
|
|
224
|
+
width: 20px;
|
|
225
|
+
height: 20px;
|
|
226
|
+
fill: none;
|
|
227
|
+
stroke: currentColor;
|
|
228
|
+
stroke-width: 1.9;
|
|
229
|
+
stroke-linecap: round;
|
|
230
|
+
stroke-linejoin: round;
|
|
231
|
+
flex: none;
|
|
232
|
+
}
|
|
233
|
+
.filled {
|
|
234
|
+
fill: currentColor;
|
|
235
|
+
stroke: none;
|
|
236
|
+
}
|
|
237
|
+
.icon-disc {
|
|
238
|
+
display: flex;
|
|
239
|
+
align-items: center;
|
|
240
|
+
justify-content: center;
|
|
241
|
+
width: 34px;
|
|
242
|
+
height: 34px;
|
|
243
|
+
border-radius: 50%;
|
|
244
|
+
flex: none;
|
|
245
|
+
background: #ebedff;
|
|
246
|
+
}
|
|
247
|
+
.frame {
|
|
248
|
+
padding: 12px 12px 3px;
|
|
249
|
+
border: 1px solid #d7d9ff;
|
|
250
|
+
border-radius: 8px;
|
|
251
|
+
background: #f7f8ffb3;
|
|
252
|
+
}
|
|
253
|
+
.frame .caption {
|
|
254
|
+
display: block;
|
|
255
|
+
line-height: 12px;
|
|
256
|
+
}
|
|
257
|
+
.url-row {
|
|
258
|
+
display: flex;
|
|
259
|
+
align-items: center;
|
|
260
|
+
gap: 8px;
|
|
261
|
+
min-height: 30px;
|
|
262
|
+
margin-top: 2px;
|
|
263
|
+
}
|
|
264
|
+
#url {
|
|
265
|
+
flex: 1;
|
|
266
|
+
min-width: 0;
|
|
267
|
+
margin: 2px 0;
|
|
268
|
+
font-size: 16px;
|
|
269
|
+
font-weight: 600;
|
|
270
|
+
line-height: 1.3;
|
|
271
|
+
overflow-wrap: anywhere;
|
|
272
|
+
}
|
|
273
|
+
#copy-url {
|
|
274
|
+
width: 28px;
|
|
275
|
+
height: 28px;
|
|
276
|
+
padding: 5px;
|
|
277
|
+
border-radius: 6px;
|
|
278
|
+
}
|
|
279
|
+
#copy-url .icon {
|
|
280
|
+
width: 16px;
|
|
281
|
+
height: 16px;
|
|
282
|
+
}
|
|
283
|
+
#viewport {
|
|
284
|
+
margin: 2px 0 0;
|
|
285
|
+
padding-top: 6px;
|
|
286
|
+
border-top: 1px solid #e0e2fc;
|
|
287
|
+
font-size: 12px;
|
|
288
|
+
line-height: 1.5;
|
|
289
|
+
color: var(--muted);
|
|
290
|
+
}
|
|
291
|
+
button {
|
|
292
|
+
font: inherit;
|
|
293
|
+
cursor: pointer;
|
|
294
|
+
border: 1px solid #d6d8ff;
|
|
295
|
+
border-radius: 6px;
|
|
296
|
+
color: inherit;
|
|
297
|
+
background: #fff;
|
|
298
|
+
}
|
|
299
|
+
button:hover {
|
|
300
|
+
background: #f0edff;
|
|
301
|
+
border-color: #ab9adc;
|
|
302
|
+
}
|
|
303
|
+
button:focus-visible {
|
|
304
|
+
outline: 2px solid #7653d6;
|
|
305
|
+
outline-offset: 2px;
|
|
306
|
+
}
|
|
307
|
+
button:disabled {
|
|
308
|
+
cursor: default;
|
|
309
|
+
opacity: 0.55;
|
|
310
|
+
}
|
|
311
|
+
.primary {
|
|
312
|
+
display: flex;
|
|
313
|
+
align-items: center;
|
|
314
|
+
justify-content: center;
|
|
315
|
+
gap: 16px;
|
|
316
|
+
width: 100%;
|
|
317
|
+
height: 45px;
|
|
318
|
+
margin-top: 10px;
|
|
319
|
+
border-color: #6943cb;
|
|
320
|
+
background: linear-gradient(110deg, #4d25b9, #4930b3);
|
|
321
|
+
box-shadow:
|
|
322
|
+
inset 0 1px 1px #9677e0,
|
|
323
|
+
0 4px 9px #4923af15;
|
|
324
|
+
color: #fff;
|
|
325
|
+
font-weight: 700;
|
|
326
|
+
font-size: 17px;
|
|
327
|
+
}
|
|
328
|
+
.primary .icon {
|
|
329
|
+
width: 24px;
|
|
330
|
+
height: 24px;
|
|
331
|
+
stroke-width: 2.5;
|
|
332
|
+
}
|
|
333
|
+
.primary:hover {
|
|
334
|
+
background: linear-gradient(110deg, #542ac6, #5135c3);
|
|
335
|
+
}
|
|
336
|
+
.hint {
|
|
337
|
+
margin: 9px 0 10px;
|
|
338
|
+
color: var(--muted);
|
|
339
|
+
font-size: 12px;
|
|
340
|
+
line-height: 1.45;
|
|
341
|
+
}
|
|
342
|
+
.capture {
|
|
343
|
+
display: grid;
|
|
344
|
+
grid-template-columns: 1fr 1fr;
|
|
345
|
+
gap: 9px;
|
|
346
|
+
}
|
|
347
|
+
.capture button {
|
|
348
|
+
display: flex;
|
|
349
|
+
align-items: center;
|
|
350
|
+
gap: 10px;
|
|
351
|
+
min-height: 58px;
|
|
352
|
+
padding: 9px;
|
|
353
|
+
text-align: left;
|
|
354
|
+
}
|
|
355
|
+
.capture .icon-disc {
|
|
356
|
+
width: 37px;
|
|
357
|
+
height: 37px;
|
|
358
|
+
}
|
|
359
|
+
.capture .icon {
|
|
360
|
+
width: 23px;
|
|
361
|
+
height: 23px;
|
|
362
|
+
}
|
|
363
|
+
.capture strong {
|
|
364
|
+
font-size: 13px;
|
|
365
|
+
letter-spacing: 0.3px;
|
|
366
|
+
}
|
|
367
|
+
.capture small {
|
|
368
|
+
display: block;
|
|
369
|
+
margin-top: 3px;
|
|
370
|
+
color: var(--muted);
|
|
371
|
+
font-size: 11px;
|
|
372
|
+
white-space: nowrap;
|
|
373
|
+
}
|
|
374
|
+
.history {
|
|
375
|
+
margin: 11px 0 0;
|
|
376
|
+
padding: 4px 0 6px;
|
|
377
|
+
border-top: 1px solid #e1e3fc;
|
|
378
|
+
border-bottom: 1px solid #e1e3fc;
|
|
379
|
+
}
|
|
380
|
+
.history > div {
|
|
381
|
+
display: grid;
|
|
382
|
+
grid-template-columns: 29px 88px minmax(0, 1fr);
|
|
383
|
+
gap: 10px;
|
|
384
|
+
align-items: center;
|
|
385
|
+
min-height: 28px;
|
|
386
|
+
}
|
|
387
|
+
.history .icon-disc {
|
|
388
|
+
width: 28px;
|
|
389
|
+
height: 28px;
|
|
390
|
+
}
|
|
391
|
+
.history .icon {
|
|
392
|
+
width: 15px;
|
|
393
|
+
height: 15px;
|
|
394
|
+
}
|
|
395
|
+
.history dd {
|
|
396
|
+
font-size: 12px;
|
|
397
|
+
overflow-wrap: anywhere;
|
|
398
|
+
line-height: 1.5;
|
|
399
|
+
}
|
|
400
|
+
#feedback {
|
|
401
|
+
font-size: 11px;
|
|
402
|
+
color: var(--muted);
|
|
403
|
+
margin: 8px 0 0;
|
|
404
|
+
}
|
|
405
|
+
#feedback:empty {
|
|
406
|
+
display: none;
|
|
407
|
+
}
|
|
408
|
+
footer {
|
|
409
|
+
display: grid;
|
|
410
|
+
grid-template-columns: 1.05fr 0.9fr 1.05fr;
|
|
411
|
+
gap: 8px;
|
|
412
|
+
padding: 11px 14px 15px;
|
|
413
|
+
}
|
|
414
|
+
footer button {
|
|
415
|
+
min-height: 33px;
|
|
416
|
+
display: flex;
|
|
417
|
+
align-items: center;
|
|
418
|
+
justify-content: center;
|
|
419
|
+
gap: 7px;
|
|
420
|
+
padding: 6px;
|
|
421
|
+
font-size: 11px;
|
|
422
|
+
white-space: nowrap;
|
|
423
|
+
}
|
|
424
|
+
footer .icon {
|
|
425
|
+
width: 16px;
|
|
426
|
+
height: 16px;
|
|
427
|
+
}
|
|
428
|
+
h2 {
|
|
429
|
+
font-size: 14px;
|
|
430
|
+
}
|
|
431
|
+
pre {
|
|
432
|
+
white-space: pre-wrap;
|
|
433
|
+
overflow-wrap: anywhere;
|
|
434
|
+
font:
|
|
435
|
+
11px/1.5 Consolas,
|
|
436
|
+
monospace;
|
|
437
|
+
max-height: 180px;
|
|
438
|
+
overflow: auto;
|
|
439
|
+
}
|
|
440
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
441
|
+
button {
|
|
442
|
+
transition:
|
|
443
|
+
background 0.12s,
|
|
444
|
+
border-color 0.12s;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
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" />
|
|
6
|
+
<title>GazeSight</title>
|
|
7
|
+
<link rel="stylesheet" href="popup.css?v=9" />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="dashboard">
|
|
11
|
+
<header>
|
|
12
|
+
<img class="sight" src="logo_sans_background.png" alt="" />
|
|
13
|
+
<h1>GazeSight</h1>
|
|
14
|
+
<span class="connection-pill"
|
|
15
|
+
><span class="connection-dot" aria-hidden="true"></span
|
|
16
|
+
><span id="connection">Disconnected</span></span
|
|
17
|
+
>
|
|
18
|
+
</header>
|
|
19
|
+
<div class="paper">
|
|
20
|
+
<main>
|
|
21
|
+
<dl class="status">
|
|
22
|
+
<div class="status-card">
|
|
23
|
+
<span class="icon-disc"
|
|
24
|
+
><svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
25
|
+
<path
|
|
26
|
+
d="M10 13a5 5 0 0 0 7.54 .54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71 M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"
|
|
27
|
+
/></svg
|
|
28
|
+
></span>
|
|
29
|
+
<div>
|
|
30
|
+
<dt>MCP</dt>
|
|
31
|
+
<dd id="pairing">Not paired</dd>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="status-card">
|
|
35
|
+
<span class="icon-disc"
|
|
36
|
+
><svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
37
|
+
<path
|
|
38
|
+
d="M12 2c3 2 6 3 9 3v7c0 5-5 8-9 10-4-2-9-5-9-10V5c3 0 6-1 9-3Z"
|
|
39
|
+
/></svg
|
|
40
|
+
></span>
|
|
41
|
+
<div>
|
|
42
|
+
<dt>Target</dt>
|
|
43
|
+
<dd id="target">None</dd>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</dl>
|
|
47
|
+
<section
|
|
48
|
+
class="background-capture"
|
|
49
|
+
aria-labelledby="background-title"
|
|
50
|
+
>
|
|
51
|
+
<div class="background-heading">
|
|
52
|
+
<div>
|
|
53
|
+
<span class="caption" id="background-title"
|
|
54
|
+
>Background capture</span
|
|
55
|
+
>
|
|
56
|
+
<strong
|
|
57
|
+
><span id="background-dot" aria-hidden="true"></span
|
|
58
|
+
><span id="background-state">Off</span></strong
|
|
59
|
+
>
|
|
60
|
+
</div>
|
|
61
|
+
<button id="background-toggle" aria-pressed="false">Enable</button>
|
|
62
|
+
</div>
|
|
63
|
+
<p id="background-description">
|
|
64
|
+
Allow GazeSight to keep capturing the selected development tab
|
|
65
|
+
while you work in another tab or application.
|
|
66
|
+
</p>
|
|
67
|
+
</section>
|
|
68
|
+
<section
|
|
69
|
+
class="background-capture"
|
|
70
|
+
aria-labelledby="continuous-title"
|
|
71
|
+
>
|
|
72
|
+
<div class="background-heading">
|
|
73
|
+
<div>
|
|
74
|
+
<span class="caption" id="continuous-title"
|
|
75
|
+
>Continuous access</span
|
|
76
|
+
>
|
|
77
|
+
<strong
|
|
78
|
+
><span id="continuous-dot" aria-hidden="true"></span
|
|
79
|
+
><span id="continuous-state">Off</span></strong
|
|
80
|
+
>
|
|
81
|
+
</div>
|
|
82
|
+
<button id="continuous-toggle" aria-pressed="false">Enable</button>
|
|
83
|
+
</div>
|
|
84
|
+
<p id="continuous-description">
|
|
85
|
+
Keep GazeSight connected to this development tab across
|
|
86
|
+
reloads, navigation and responsive previews, so you don't have
|
|
87
|
+
to reauthorize it every time.
|
|
88
|
+
</p>
|
|
89
|
+
</section>
|
|
90
|
+
<section class="frame" aria-label="Selected target">
|
|
91
|
+
<span class="caption">Current URL</span>
|
|
92
|
+
<div class="url-row">
|
|
93
|
+
<p id="url">No target selected</p>
|
|
94
|
+
<button
|
|
95
|
+
id="copy-url"
|
|
96
|
+
aria-label="Copy current URL"
|
|
97
|
+
title="Copy current URL"
|
|
98
|
+
>
|
|
99
|
+
<svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
100
|
+
<rect x="8" y="7" width="12" height="15" rx="1.5" />
|
|
101
|
+
<path d="M15 3H5a1 1 0 0 0-1 1v13h2" />
|
|
102
|
+
</svg>
|
|
103
|
+
</button>
|
|
104
|
+
</div>
|
|
105
|
+
<p id="viewport">Viewport unavailable</p>
|
|
106
|
+
</section>
|
|
107
|
+
<button id="select" class="primary">
|
|
108
|
+
<svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
109
|
+
<path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12Z" />
|
|
110
|
+
<circle class="filled" cx="12" cy="12" r="3" /></svg
|
|
111
|
+
><span id="select-label">Use this tab</span>
|
|
112
|
+
</button>
|
|
113
|
+
<p class="hint">
|
|
114
|
+
Select the page you want your agent to see.
|
|
115
|
+
<span id="shortcut">Ctrl+Shift+Y</span> also selects or reauthorizes
|
|
116
|
+
a tab.
|
|
117
|
+
</p>
|
|
118
|
+
<div class="capture">
|
|
119
|
+
<button id="fast">
|
|
120
|
+
<span class="icon-disc"
|
|
121
|
+
><svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
122
|
+
<path
|
|
123
|
+
class="filled"
|
|
124
|
+
d="m14 1-12 14h8l-1 8L22 9h-8Z"
|
|
125
|
+
/></svg></span
|
|
126
|
+
><span
|
|
127
|
+
><strong>FAST</strong><small>Immediate capture</small></span
|
|
128
|
+
></button
|
|
129
|
+
><button id="stable">
|
|
130
|
+
<span class="icon-disc"
|
|
131
|
+
><svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
132
|
+
<circle cx="12" cy="12" r="8" />
|
|
133
|
+
<circle class="filled" cx="12" cy="12" r="2.5" />
|
|
134
|
+
<path d="M12 1v3m0 16v3M1 12h3m16 0h3" /></svg></span
|
|
135
|
+
><span
|
|
136
|
+
><strong>STABLE</strong
|
|
137
|
+
><small>Wait for visual quiet</small></span
|
|
138
|
+
>
|
|
139
|
+
</button>
|
|
140
|
+
</div>
|
|
141
|
+
<dl class="history">
|
|
142
|
+
<div>
|
|
143
|
+
<span class="icon-disc"
|
|
144
|
+
><svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
145
|
+
<circle cx="12" cy="12" r="9" />
|
|
146
|
+
<path d="M12 6v6l4 2" /></svg
|
|
147
|
+
></span>
|
|
148
|
+
<dt>Last capture</dt>
|
|
149
|
+
<dd id="last-capture">None yet</dd>
|
|
150
|
+
</div>
|
|
151
|
+
<div>
|
|
152
|
+
<span class="icon-disc"
|
|
153
|
+
><svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
154
|
+
<path d="m12 3 10 18H2Z M12 9v5m0 3v.1" /></svg
|
|
155
|
+
></span>
|
|
156
|
+
<dt>Last error</dt>
|
|
157
|
+
<dd id="last-error">None</dd>
|
|
158
|
+
</div>
|
|
159
|
+
</dl>
|
|
160
|
+
<p id="feedback" role="status" aria-live="polite"></p>
|
|
161
|
+
<section id="diagnostics-panel" hidden>
|
|
162
|
+
<h2>Diagnostics</h2>
|
|
163
|
+
<pre id="diagnostics-output"></pre>
|
|
164
|
+
</section>
|
|
165
|
+
</main>
|
|
166
|
+
<footer>
|
|
167
|
+
<button id="disconnect">
|
|
168
|
+
<svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
169
|
+
<path
|
|
170
|
+
d="M10 13a5 5 0 0 0 7.54 .54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71 M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"
|
|
171
|
+
/></svg
|
|
172
|
+
><span>Disconnect target</span></button
|
|
173
|
+
><button id="settings">
|
|
174
|
+
<svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
175
|
+
<path
|
|
176
|
+
d="m9 3 1-2h4l1 2 1 2 3-1 2 3-2 3v4l2 3-2 3-3-1-1 2-1 2h-4l-1-2-1-2-3 1-2-3 2-3v-4L3 7l2-3 3 1Z"
|
|
177
|
+
/>
|
|
178
|
+
<circle cx="12" cy="12" r="3" /></svg
|
|
179
|
+
><span>Open settings</span></button
|
|
180
|
+
><button id="diagnostics">
|
|
181
|
+
<svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
182
|
+
<path d="M6 2h9l4 4v16H6Z M14 2v5h5M10 11h5m-5 4h5m-5 4h5" /></svg
|
|
183
|
+
><span>Open diagnostics</span>
|
|
184
|
+
</button>
|
|
185
|
+
</footer>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
<script type="module" src="popup.js"></script>
|
|
189
|
+
</body>
|
|
190
|
+
</html>
|
|
191
|
+
|