diff --git a/.gitignore b/.gitignore index d74f88e..3ddc139 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,8 @@ # OS .DS_Store +# local notes +TODO.md + # protobuf generated -internal/grpc/pb/*.pb.go \ No newline at end of file +internal/grpc/pb/*.pb.goa \ No newline at end of file diff --git a/gui/wails-standalone/README.md b/gui/wails-standalone/README.md new file mode 100644 index 0000000..397b08b --- /dev/null +++ b/gui/wails-standalone/README.md @@ -0,0 +1,19 @@ +# README + +## About + +This is the official Wails Vanilla template. + +You can configure the project by editing `wails.json`. More information about the project settings can be found +here: https://wails.io/docs/reference/project-config + +## Live Development + +To run in live development mode, run `wails dev` in the project directory. This will run a Vite development +server that will provide very fast hot reload of your frontend changes. If you want to develop in a browser +and have access to your Go methods, there is also a dev server that runs on http://localhost:34115. Connect +to this in your browser, and you can call your Go code from devtools. + +## Building + +To build a redistributable, production mode package, use `wails build`. diff --git a/gui/wails-standalone/frontend/dist/assets/index.02c817da.js b/gui/wails-standalone/frontend/dist/assets/index.02c817da.js new file mode 100644 index 0000000..dc2b94c --- /dev/null +++ b/gui/wails-standalone/frontend/dist/assets/index.02c817da.js @@ -0,0 +1 @@ +(function(){const d=document.createElement("link").relList;if(d&&d.supports&&d.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))f(e);new MutationObserver(e=>{for(const n of e)if(n.type==="childList")for(const s of n.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&f(s)}).observe(document,{childList:!0,subtree:!0});function m(e){const n={};return e.integrity&&(n.integrity=e.integrity),e.referrerpolicy&&(n.referrerPolicy=e.referrerpolicy),e.crossorigin==="use-credentials"?n.credentials="include":e.crossorigin==="anonymous"?n.credentials="omit":n.credentials="same-origin",n}function f(e){if(e.ep)return;e.ep=!0;const n=m(e);fetch(e.href,n)}})();function N(){return window.go.main.App.CheckConnection()}function F(){return window.go.main.App.Quit()}function $(a){return window.go.main.App.SetFrequency(a)}const D="/assets/logo-dark.ff9a8bc7.jpg";(function(){const a=document.getElementById("theme-toggle");a.addEventListener("click",()=>{const c=document.body.getAttribute("data-theme")==="light"?"dark":"light";document.body.setAttribute("data-theme",c),a.textContent=c==="light"?"\u263E":"\u2600"});const d=640,m=480,f=312,e=D,n=document.getElementById("intro-overlay"),s=document.querySelector("#intro-overlay .door-left"),l=document.querySelector("#intro-overlay .door-right");function L(){const t=window.innerWidth,c=window.innerHeight,o=Math.max(t/d,c/m),h=d*o,p=m*o,v=(t-h)/2,q=(c-p)/2,W=v+f*o,g=Math.max(0,Math.min(t,W)),_=t-g;s.style.width=g+"px",s.style.backgroundImage=`url(${e})`,s.style.backgroundSize=h+"px "+p+"px",s.style.backgroundPosition=v+"px "+q+"px",l.style.left=g+"px",l.style.width=_+"px",l.style.backgroundImage=`url(${e})`,l.style.backgroundSize=h+"px "+p+"px",l.style.backgroundPosition=v-g+"px "+q+"px"}const b=2100,C=100;function A(){n.style.display="",n.classList.remove("appear","open"),n.offsetWidth,L(),setTimeout(()=>n.classList.add("appear"),C),setTimeout(()=>n.classList.add("open"),b),setTimeout(()=>{n.style.display="none"},b+1170)}window.addEventListener("resize",L),A();const E=document.querySelectorAll(".tab-button"),B=document.querySelectorAll(".tab-content");E.forEach(t=>{t.addEventListener("click",()=>{E.forEach(o=>o.classList.remove("active")),B.forEach(o=>o.classList.remove("active")),t.classList.add("active");const c=t.getAttribute("data-tab");document.getElementById(`tab-${c}`).classList.add("active")})});const w=document.getElementById("btn-check"),S=document.getElementById("btn-freq"),T=document.getElementById("btn-quit"),x=document.getElementById("status-indicator"),I=document.getElementById("status-text"),k=document.getElementById("frequency-label"),y=document.getElementById("frequency-value"),u=document.getElementById("freq-modal"),O=document.getElementById("close-modal"),i=document.getElementById("freq-input"),P=document.getElementById("btn-minus"),M=document.getElementById("btn-plus"),R=document.getElementById("btn-set-freq"),r=document.getElementById("modal-error");w.addEventListener("click",()=>{N().then(t=>{x.classList.remove("indicator-red"),x.classList.add("indicator-green"),I.textContent=`\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E! ${t.status}`,k.textContent="\u0422\u0435\u043A\u0443\u0449\u0430\u044F \u0447\u0430\u0441\u0442\u043E\u0442\u0430:",y.textContent=t.frequency}).catch(t=>{console.error("\u041E\u0448\u0438\u0431\u043A\u0430 CheckConnection:",t),I.textContent="\u041E\u0448\u0438\u0431\u043A\u0430: \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443"})}),S.addEventListener("click",()=>{u.classList.remove("hidden");const t=y.textContent!=="---"?y.textContent:"145";i.value=t,r.classList.add("hidden")}),O.addEventListener("click",()=>{u.classList.add("hidden")}),window.addEventListener("click",t=>{t.target===u&&u.classList.add("hidden")}),P.addEventListener("click",()=>{let t=parseInt(i.value,10)||1;t=Math.max(1,t-1),i.value=t.toString()}),M.addEventListener("click",()=>{let t=parseInt(i.value,10)||1;t+=1,i.value=t.toString()}),R.addEventListener("click",()=>{const t=i.value.trim();if(!/^\d+$/.test(t)){r.textContent="\u0412\u0432\u043E\u0434\u0438\u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0446\u0435\u043B\u044B\u043C \u043F\u043E\u043B\u043E\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C",r.classList.remove("hidden");return}if(parseInt(t,10)<=0){r.textContent="\u0412\u0432\u043E\u0434\u0438\u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0446\u0435\u043B\u044B\u043C \u043F\u043E\u043B\u043E\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C",r.classList.remove("hidden");return}$(t).then(o=>{k.textContent="\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u0430\u044F \u0447\u0430\u0441\u0442\u043E\u0442\u0430:",y.textContent=o,u.classList.add("hidden")}).catch(o=>{r.textContent=o,r.classList.remove("hidden")})}),T.addEventListener("click",()=>{F()})})(); diff --git a/gui/wails-standalone/frontend/dist/assets/index.41fde905.css b/gui/wails-standalone/frontend/dist/assets/index.41fde905.css new file mode 100644 index 0000000..b457202 --- /dev/null +++ b/gui/wails-standalone/frontend/dist/assets/index.41fde905.css @@ -0,0 +1 @@ +*{margin:0;padding:0;box-sizing:border-box}html,body{width:100%;height:100%;display:flex;justify-content:center;align-items:center;font-family:Arial,sans-serif;overflow:hidden}body{background:radial-gradient(circle at 50% 18%,#1a1d24 0%,#0d0f13 70%);transition:background .3s ease}body[data-theme=light]{background:radial-gradient(circle at 50% 18%,#ffffff 0%,#dde1e7 70%)}#theme-toggle{position:fixed;top:16px;right:18px;z-index:500;width:34px;height:34px;border-radius:50%;border:1px solid #333a46;background:#222a37;color:#ccc;cursor:pointer;font-size:14px;display:flex;align-items:center;justify-content:center}body[data-theme=light] #theme-toggle{border-color:#c7cbd1;background:#ffffff;color:#555}#app{width:360px;border-radius:14px;box-shadow:0 8px 28px #0000004d;overflow:hidden;background:#1b1e24;transition:background .3s ease}body[data-theme=light] #app{background:#ffffff}#brand{display:flex;flex-direction:column;align-items:center;padding:26px 24px 16px;gap:6px}.logo-icon{position:relative;width:64px;height:48px;margin-bottom:6px}.logo-icon img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}.logo-icon .logo-dark{mix-blend-mode:screen;display:block}.logo-icon .logo-light{mix-blend-mode:multiply;display:none}body[data-theme=light] .logo-icon .logo-dark{display:none}body[data-theme=light] .logo-icon .logo-light{display:block}#brand h1{color:#eee;font-size:21px;letter-spacing:3.5px;font-weight:700}#brand .tag{color:#7a7f89;font-size:11px;letter-spacing:1.2px}body[data-theme=light] #brand h1{color:#1b1d22}body[data-theme=light] #brand .tag{color:#888d97}.tabs{display:flex;background:transparent}.tabs[hidden]{display:none}.tab-button{flex:1;padding:12px;background:transparent;border:none;cursor:pointer;font-size:14px;color:#9aa0aa;transition:background .2s}.tab-button:hover{background:rgba(255,255,255,.05)}.tab-button.active{color:#eee;border-bottom:2px solid #b8362a;font-weight:700}body[data-theme=light] .tab-button{color:#7a7f89}body[data-theme=light] .tab-button.active{color:#1b1d22}.tab-content{display:none;padding:4px 22px 24px}.tab-content.active{display:block}.buttons-vertical{display:flex;flex-direction:column;gap:10px;margin-bottom:12px}.action-button{padding:11px;font-size:14px;cursor:pointer;border:1px solid #2a2d34;border-radius:8px;background-color:#15171c;color:#e8e8e8;transition:background-color .2s,border-color .2s}.action-button:hover{background-color:#1d2027;border-color:#3a3e46}body[data-theme=light] .action-button{background-color:#fff;border-color:#ccd1d9;color:#22242a}body[data-theme=light] .action-button:hover{background-color:#f0f2f5;border-color:#aeb4bd}.close-button{background-color:#b8362a;color:#fff;border-color:#8f2a20}.close-button:hover{background-color:#c73f31}body[data-theme=light] .close-button{background-color:#e74c3c;border-color:#c0392b;color:#fff}body[data-theme=light] .close-button:hover{background-color:#d8432f}#frequency-panel{display:flex;justify-content:space-between;align-items:center;padding:9px 13px;background-color:#15171c;border:1px solid #2a2d34;border-radius:8px;margin-bottom:9px}#frequency-label{font-weight:700;color:#9aa0aa;font-size:13px}#frequency-value{font-size:17px;color:#f2f2f2}body[data-theme=light] #frequency-panel{background-color:#fff;border-color:#ccd1d9}body[data-theme=light] #frequency-label{color:#7a7f89}body[data-theme=light] #frequency-value{color:#1b1d22}#status-panel{display:flex;align-items:center;gap:9px;padding:9px 13px;background-color:#15171c;border:1px solid #2a2d34;border-radius:8px}body[data-theme=light] #status-panel{background-color:#fff;border-color:#ccd1d9}.indicator{width:14px;height:14px;border-radius:50%;display:inline-block}.indicator-red{background-color:#e74c3c}.indicator-green{background-color:#2ecc71}#status-text{font-size:14px;color:#ddd}body[data-theme=light] #status-text{color:#333}#intro-overlay{position:fixed;inset:0;z-index:1000;background:#000;transform:scale(1.04)}#intro-overlay.appear{animation:introPop .45s cubic-bezier(.2,.9,.3,1) forwards}@keyframes introPop{to{transform:scale(1)}}.door{position:absolute;top:0;bottom:0;overflow:hidden;background-color:#000;background-repeat:no-repeat;transition:transform 1.17s cubic-bezier(.65,0,.35,1)}.door-left,.door-right{left:0}#intro-overlay.open .door-left{transform:translate(-100%)}#intro-overlay.open .door-right{transform:translate(100%)}#intro-overlay.open{transition:opacity .45s ease .65s;opacity:0;pointer-events:none}.modal{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);display:flex;justify-content:center;align-items:center;z-index:100}.modal.hidden{display:none}.modal-content{background:#1b1e24;padding:20px;border-radius:8px;width:300px;box-shadow:0 5px 15px #0006;position:relative;color:#eee}body[data-theme=light] .modal-content{background:#ffffff;color:#222}.close-modal{position:absolute;top:10px;right:15px;font-size:22px;cursor:pointer;color:#999}.close-modal:hover{color:#eee}body[data-theme=light] .close-modal{color:#777}body[data-theme=light] .close-modal:hover{color:#333}.modal-content h3{margin-bottom:15px;text-align:center}.freq-input-group{display:flex;align-items:center;justify-content:center;gap:10px;margin-bottom:15px}.freq-btn{width:40px;height:40px;font-size:20px;background:#b8362a;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background .2s}.freq-btn:hover{background:#c73f31}#freq-input{width:100px;padding:8px;font-size:18px;text-align:center;border:1px solid #444;border-radius:4px;background:#15171c;color:#eee}body[data-theme=light] #freq-input{border-color:#ccc;background:#fff;color:#222}#btn-set-freq{display:block;width:100%;margin-top:10px}.error-msg{color:#e74c3c;margin-top:8px;text-align:center;font-size:14px}.error-msg.hidden{display:none} diff --git a/gui/wails-standalone/frontend/dist/assets/logo-dark.ff9a8bc7.jpg b/gui/wails-standalone/frontend/dist/assets/logo-dark.ff9a8bc7.jpg new file mode 100644 index 0000000..6856a0a Binary files /dev/null and b/gui/wails-standalone/frontend/dist/assets/logo-dark.ff9a8bc7.jpg differ diff --git a/gui/wails-standalone/frontend/dist/assets/logo-light.d5e577a8.png b/gui/wails-standalone/frontend/dist/assets/logo-light.d5e577a8.png new file mode 100644 index 0000000..5c56201 Binary files /dev/null and b/gui/wails-standalone/frontend/dist/assets/logo-light.d5e577a8.png differ diff --git a/gui/wails-standalone/frontend/dist/index.html b/gui/wails-standalone/frontend/dist/index.html new file mode 100644 index 0000000..a5f458f --- /dev/null +++ b/gui/wails-standalone/frontend/dist/index.html @@ -0,0 +1,88 @@ + + + + + + + Спектр + + + + + + + + + +
+
+
+
+ +
+ + +
+
+ ТЭЧ ДМ + ТЭЧ ДМ +
+

СПЕКТР

+
видеоприёмник · панель управления
+
+ + + + + +
+
+ + + +
+ + +
+ Текущая частота: + --- +
+ + +
+ + Нет соединения +
+
+ +
+

Здесь будет проводиться сканирование доступных частот!

+
+ +
+

О программе: Версия 0.01, сделано на Wails в тэч дм!

+
+
+ + + + + + + diff --git a/gui/wails-standalone/frontend/index.html b/gui/wails-standalone/frontend/index.html new file mode 100644 index 0000000..0c7e040 --- /dev/null +++ b/gui/wails-standalone/frontend/index.html @@ -0,0 +1,86 @@ + + + + + + + Спектр + + + + + + + +
+
+
+
+ +
+ + +
+
+ ТЭЧ ДМ + ТЭЧ ДМ +
+

СПЕКТР

+
видеоприёмник · панель управления
+
+ + + + + +
+
+ + + +
+ + +
+ Текущая частота: + --- +
+ + +
+ + Нет соединения +
+
+ +
+

Здесь будет проводиться сканирование доступных частот!

+
+ +
+

О программе: Версия 0.01, сделано на Wails в тэч дм!

+
+
+ + + + + + + diff --git a/gui/wails-standalone/frontend/package-lock.json b/gui/wails-standalone/frontend/package-lock.json new file mode 100644 index 0000000..062fb25 --- /dev/null +++ b/gui/wails-standalone/frontend/package-lock.json @@ -0,0 +1,664 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "devDependencies": { + "vite": "^3.0.7" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "2.80.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.80.0.tgz", + "integrity": "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/vite": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.11.tgz", + "integrity": "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.15.9", + "postcss": "^8.4.18", + "resolve": "^1.22.1", + "rollup": "^2.79.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + } + } +} diff --git a/gui/wails-standalone/frontend/package.json b/gui/wails-standalone/frontend/package.json new file mode 100644 index 0000000..a031aa9 --- /dev/null +++ b/gui/wails-standalone/frontend/package.json @@ -0,0 +1,13 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "node ./node_modules/vite/bin/vite.js", + "build": "node ./node_modules/vite/bin/vite.js build", + "preview": "vite preview" + }, + "devDependencies": { + "vite": "^3.0.7" + } +} \ No newline at end of file diff --git a/gui/wails-standalone/frontend/src/app.css b/gui/wails-standalone/frontend/src/app.css new file mode 100644 index 0000000..59d06f6 --- /dev/null +++ b/gui/wails-standalone/frontend/src/app.css @@ -0,0 +1,54 @@ +#logo { + display: block; + width: 50%; + height: 50%; + margin: auto; + padding: 10% 0 0; + background-position: center; + background-repeat: no-repeat; + background-size: 100% 100%; + background-origin: content-box; +} + +.result { + height: 20px; + line-height: 20px; + margin: 1.5rem auto; +} + +.input-box .btn { + width: 60px; + height: 30px; + line-height: 30px; + border-radius: 3px; + border: none; + margin: 0 0 0 20px; + padding: 0 8px; + cursor: pointer; +} + +.input-box .btn:hover { + background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); + color: #333333; +} + +.input-box .input { + border: none; + border-radius: 3px; + outline: none; + height: 30px; + line-height: 30px; + padding: 0 10px; + background-color: rgba(240, 240, 240, 1); + -webkit-font-smoothing: antialiased; +} + +.input-box .input:hover { + border: none; + background-color: rgba(255, 255, 255, 1); +} + +.input-box .input:focus { + border: none; + background-color: rgba(255, 255, 255, 1); +} \ No newline at end of file diff --git a/gui/wails-standalone/frontend/src/assets/fonts/OFL.txt b/gui/wails-standalone/frontend/src/assets/fonts/OFL.txt new file mode 100644 index 0000000..9cac04c --- /dev/null +++ b/gui/wails-standalone/frontend/src/assets/fonts/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/gui/wails-standalone/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/gui/wails-standalone/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 new file mode 100644 index 0000000..2f9cc59 Binary files /dev/null and b/gui/wails-standalone/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 differ diff --git a/gui/wails-standalone/frontend/src/assets/images/logo-dark.jpg b/gui/wails-standalone/frontend/src/assets/images/logo-dark.jpg new file mode 100644 index 0000000..6856a0a Binary files /dev/null and b/gui/wails-standalone/frontend/src/assets/images/logo-dark.jpg differ diff --git a/gui/wails-standalone/frontend/src/assets/images/logo-light.png b/gui/wails-standalone/frontend/src/assets/images/logo-light.png new file mode 100644 index 0000000..5c56201 Binary files /dev/null and b/gui/wails-standalone/frontend/src/assets/images/logo-light.png differ diff --git a/gui/wails-standalone/frontend/src/assets/images/logo-universal.png b/gui/wails-standalone/frontend/src/assets/images/logo-universal.png new file mode 100644 index 0000000..d63303b Binary files /dev/null and b/gui/wails-standalone/frontend/src/assets/images/logo-universal.png differ diff --git a/gui/wails-standalone/frontend/src/main.js b/gui/wails-standalone/frontend/src/main.js new file mode 100644 index 0000000..05e467e --- /dev/null +++ b/gui/wails-standalone/frontend/src/main.js @@ -0,0 +1,189 @@ +import { + CheckConnection, + SetFrequency, + Quit, +} from "../wailsjs/go/main/App"; + +// импорт через ES-модуль, а не строкой-путём — иначе vite не подставит +// правильный хэшированный путь в собранном билде (сломается в проде) +import logoDarkUrl from "./assets/images/logo-dark.jpg"; + +(function() { + // === Тема (тёмная/светлая) === + const themeToggle = document.getElementById('theme-toggle'); + themeToggle.addEventListener('click', () => { + const cur = document.body.getAttribute('data-theme'); + const next = cur === 'light' ? 'dark' : 'light'; + document.body.setAttribute('data-theme', next); + themeToggle.textContent = next === 'light' ? '☾' : '☀'; + }); + + // === Интро при запуске (лого "двери" разъезжаются) === + const NATURAL_W = 640, NATURAL_H = 480; + const AXIS_X = 312; // ось раздела — середина носа черепа / верхнего зубца шестерни + const LOGO_DARK_URL = logoDarkUrl; + + const introOverlay = document.getElementById('intro-overlay'); + const doorLeft = document.querySelector('#intro-overlay .door-left'); + const doorRight = document.querySelector('#intro-overlay .door-right'); + + function layoutDoors() { + const W = window.innerWidth; + const H = window.innerHeight; + const scale = Math.max(W / NATURAL_W, H / NATURAL_H); // object-fit: cover на весь размер окна + const renderW = NATURAL_W * scale; + const renderH = NATURAL_H * scale; + const offsetX = (W - renderW) / 2; + const offsetY = (H - renderH) / 2; + const axisDisplayX = offsetX + AXIS_X * scale; + + const leftW = Math.max(0, Math.min(W, axisDisplayX)); + const rightW = W - leftW; + + doorLeft.style.width = leftW + 'px'; + doorLeft.style.backgroundImage = `url(${LOGO_DARK_URL})`; + doorLeft.style.backgroundSize = renderW + 'px ' + renderH + 'px'; + doorLeft.style.backgroundPosition = offsetX + 'px ' + offsetY + 'px'; + + doorRight.style.left = leftW + 'px'; + doorRight.style.width = rightW + 'px'; + doorRight.style.backgroundImage = `url(${LOGO_DARK_URL})`; + doorRight.style.backgroundSize = renderW + 'px ' + renderH + 'px'; + doorRight.style.backgroundPosition = (offsetX - leftW) + 'px ' + offsetY + 'px'; + } + + const OPEN_AT = 2100; // момент начала разъезда дверей от старта интро, мс + const APPEAR_START = 100; + const APPEAR_DUR = 450; + + function playIntro() { + introOverlay.style.display = ''; + introOverlay.classList.remove('appear', 'open'); + void introOverlay.offsetWidth; // reflow reset + layoutDoors(); + + setTimeout(() => introOverlay.classList.add('appear'), APPEAR_START); + setTimeout(() => introOverlay.classList.add('open'), OPEN_AT); + // прячем оверлей из потока/кликов после того как двери разъехались и погасли + setTimeout(() => { introOverlay.style.display = 'none'; }, OPEN_AT + 1170); + } + + window.addEventListener('resize', layoutDoors); + playIntro(); // main.js подключён как type="module" — DOM уже готов на этот момент + + // === Переключение вкладок === + const tabButtons = document.querySelectorAll('.tab-button'); + const tabContents = document.querySelectorAll('.tab-content'); + + tabButtons.forEach(button => { + button.addEventListener('click', () => { + tabButtons.forEach(btn => btn.classList.remove('active')); + tabContents.forEach(content => content.classList.remove('active')); + button.classList.add('active'); + const tabId = button.getAttribute('data-tab'); + document.getElementById(`tab-${tabId}`).classList.add('active'); + }); + }); + + // === Элементы интерфейса === + const btnCheck = document.getElementById('btn-check'); + const btnFreq = document.getElementById('btn-freq'); + const btnQuit = document.getElementById('btn-quit'); + const statusIndicator = document.getElementById('status-indicator'); + const statusText = document.getElementById('status-text'); + const freqLabel = document.getElementById('frequency-label'); + const freqValue = document.getElementById('frequency-value'); + + // Модальное окно + const modal = document.getElementById('freq-modal'); + const closeModal = document.getElementById('close-modal'); + const freqInput = document.getElementById('freq-input'); + const btnMinus = document.getElementById('btn-minus'); + const btnPlus = document.getElementById('btn-plus'); + const btnSetFreq = document.getElementById('btn-set-freq'); + const modalError = document.getElementById('modal-error'); + + // === Проверка подключения === + btnCheck.addEventListener('click', () => { + CheckConnection() + .then((response) => { + // Обновление индикатора соединения + statusIndicator.classList.remove('indicator-red'); + statusIndicator.classList.add('indicator-green'); + statusText.textContent = `Соединение установлено! ${response.status}`; + + // Обновление панели частоты (текущая) + freqLabel.textContent = 'Текущая частота:'; + freqValue.textContent = response.frequency; + }) + .catch((err) => { + console.error('Ошибка CheckConnection:', err); + statusText.textContent = 'Ошибка: не удалось выполнить проверку'; + }); + }); + + // === Установка частоты (открытие модального окна) === + btnFreq.addEventListener('click', () => { + modal.classList.remove('hidden'); + // Показываем текущую частоту из панели (или 145) + const current = freqValue.textContent !== '---' ? freqValue.textContent : '145'; + freqInput.value = current; + modalError.classList.add('hidden'); + }); + + // Закрытие модального окна + closeModal.addEventListener('click', () => { + modal.classList.add('hidden'); + }); + window.addEventListener('click', (e) => { + if (e.target === modal) { + modal.classList.add('hidden'); + } + }); + + // Кнопки +/- для изменения значения на 1 + btnMinus.addEventListener('click', () => { + let val = parseInt(freqInput.value, 10) || 1; + val = Math.max(1, val - 1); // минимум 1 + freqInput.value = val.toString(); + }); + btnPlus.addEventListener('click', () => { + let val = parseInt(freqInput.value, 10) || 1; + val += 1; + freqInput.value = val.toString(); + }); + + // Кнопка "Установить" + btnSetFreq.addEventListener('click', () => { + const inputVal = freqInput.value.trim(); + // Проверка: только цифры + if (!/^\d+$/.test(inputVal)) { + modalError.textContent = 'Вводимое значение должно быть целым положительным числом'; + modalError.classList.remove('hidden'); + return; + } + const num = parseInt(inputVal, 10); + if (num <= 0) { + modalError.textContent = 'Вводимое значение должно быть целым положительным числом'; + modalError.classList.remove('hidden'); + return; + } + + SetFrequency(inputVal) + .then((newFreq) => { + // Обновляем панель частоты + freqLabel.textContent = 'Установленная частота:'; + freqValue.textContent = newFreq; + modal.classList.add('hidden'); + }) + .catch((err) => { + modalError.textContent = err; + modalError.classList.remove('hidden'); + }); + }); + + // === Закрыть приложение === + btnQuit.addEventListener('click', () => { + Quit(); + }); +})(); \ No newline at end of file diff --git a/gui/wails-standalone/frontend/src/style.css b/gui/wails-standalone/frontend/src/style.css new file mode 100644 index 0000000..fb0ca91 --- /dev/null +++ b/gui/wails-standalone/frontend/src/style.css @@ -0,0 +1,343 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html, body { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + font-family: Arial, sans-serif; + overflow: hidden; +} + +/* ===================== ТЕМА (тёмная/светлая) ===================== */ +body { + background: radial-gradient(circle at 50% 18%, #1a1d24 0%, #0d0f13 70%); + transition: background 0.3s ease; +} +body[data-theme="light"] { + background: radial-gradient(circle at 50% 18%, #ffffff 0%, #dde1e7 70%); +} + +#theme-toggle { + position: fixed; + top: 16px; right: 18px; + z-index: 500; + width: 34px; height: 34px; + border-radius: 50%; + border: 1px solid #333a46; + background: #222a37; + color: #ccc; + cursor: pointer; + font-size: 14px; + display: flex; align-items: center; justify-content: center; +} +body[data-theme="light"] #theme-toggle { + border-color: #c7cbd1; + background: #ffffff; + color: #555; +} + +/* ===================== КАРТОЧКА ПРИЛОЖЕНИЯ ===================== */ +#app { + width: 360px; + border-radius: 14px; + box-shadow: 0 8px 28px rgba(0, 0, 0, 0.3); + overflow: hidden; + background: #1b1e24; + transition: background 0.3s ease; +} +body[data-theme="light"] #app { + background: #ffffff; +} + +/* ---- бренд-блок ---- */ +#brand { + display: flex; flex-direction: column; align-items: center; + padding: 26px 24px 16px; + gap: 6px; +} +.logo-icon { + position: relative; + width: 64px; height: 48px; /* пропорции 640:480 исходного лого */ + margin-bottom: 6px; +} +.logo-icon img { + position: absolute; inset: 0; + width: 100%; height: 100%; + object-fit: contain; +} +.logo-icon .logo-dark { mix-blend-mode: screen; display: block; } +.logo-icon .logo-light { mix-blend-mode: multiply; display: none; } +body[data-theme="light"] .logo-icon .logo-dark { display: none; } +body[data-theme="light"] .logo-icon .logo-light { display: block; } + +#brand h1 { + color: #eeeeee; + font-size: 21px; + letter-spacing: 3.5px; + font-weight: 700; +} +#brand .tag { + color: #7a7f89; + font-size: 11px; + letter-spacing: 1.2px; +} +body[data-theme="light"] #brand h1 { color: #1b1d22; } +body[data-theme="light"] #brand .tag { color: #888d97; } + +/* Панель вкладок (пока скрыта атрибутом hidden в HTML) */ +.tabs { + display: flex; + background: transparent; +} +.tabs[hidden] { + display: none; /* без этого .tabs{display:flex} выше перебивает атрибут hidden */ +} +.tab-button { + flex: 1; + padding: 12px; + background: transparent; + border: none; + cursor: pointer; + font-size: 14px; + color: #9aa0aa; + transition: background 0.2s; +} +.tab-button:hover { background: rgba(255,255,255,0.05); } +.tab-button.active { + color: #eee; + border-bottom: 2px solid #b8362a; + font-weight: bold; +} +body[data-theme="light"] .tab-button { color: #7a7f89; } +body[data-theme="light"] .tab-button.active { color: #1b1d22; } + +/* Содержимое вкладок */ +.tab-content { display: none; padding: 4px 22px 24px; } +.tab-content.active { display: block; } + +/* Вертикально расположенные кнопки */ +.buttons-vertical { + display: flex; + flex-direction: column; + gap: 10px; + margin-bottom: 12px; +} + +.action-button { + padding: 11px; + font-size: 14px; + cursor: pointer; + border: 1px solid #2a2d34; + border-radius: 8px; + background-color: #15171c; + color: #e8e8e8; + transition: background-color 0.2s, border-color 0.2s; +} +.action-button:hover { + background-color: #1d2027; + border-color: #3a3e46; +} +body[data-theme="light"] .action-button { + background-color: #ffffff; + border-color: #ccd1d9; + color: #22242a; +} +body[data-theme="light"] .action-button:hover { + background-color: #f0f2f5; + border-color: #aeb4bd; +} + +.close-button { + background-color: #b8362a; + color: white; + border-color: #8f2a20; +} +.close-button:hover { background-color: #c73f31; } +body[data-theme="light"] .close-button { + background-color: #e74c3c; + border-color: #c0392b; + color: #fff; +} +body[data-theme="light"] .close-button:hover { background-color: #d8432f; } + +/* Панель частоты */ +#frequency-panel { + display: flex; + justify-content: space-between; + align-items: center; + padding: 9px 13px; + background-color: #15171c; + border: 1px solid #2a2d34; + border-radius: 8px; + margin-bottom: 9px; +} +#frequency-label { font-weight: bold; color: #9aa0aa; font-size: 13px; } +#frequency-value { font-size: 17px; color: #f2f2f2; } +body[data-theme="light"] #frequency-panel { background-color: #ffffff; border-color: #ccd1d9; } +body[data-theme="light"] #frequency-label { color: #7a7f89; } +body[data-theme="light"] #frequency-value { color: #1b1d22; } + +/* Панель статуса */ +#status-panel { + display: flex; + align-items: center; + gap: 9px; + padding: 9px 13px; + background-color: #15171c; + border: 1px solid #2a2d34; + border-radius: 8px; +} +body[data-theme="light"] #status-panel { background-color: #ffffff; border-color: #ccd1d9; } + +.indicator { + width: 14px; + height: 14px; + border-radius: 50%; + display: inline-block; +} +.indicator-red { background-color: #e74c3c; } +.indicator-green { background-color: #2ecc71; } + +#status-text { font-size: 14px; color: #ddd; } +body[data-theme="light"] #status-text { color: #333; } + +/* ===================== ИНТРО (двери) ===================== */ +#intro-overlay { + position: fixed; + inset: 0; + z-index: 1000; + background: #000; /* подстраховка: перекрывает всё, даже пока JS ещё не выставил размеры дверей */ + transform: scale(1.04); +} +#intro-overlay.appear { + animation: introPop 0.45s cubic-bezier(.2,.9,.3,1) forwards; +} +@keyframes introPop { to { transform: scale(1); } } + +.door { + position: absolute; + top: 0; bottom: 0; + overflow: hidden; + background-color: #000; + background-repeat: no-repeat; + transition: transform 1.17s cubic-bezier(.65,0,.35,1); +} +.door-left { left: 0; } +.door-right { left: 0; } /* left/width выставляются из JS под реальный размер окна */ + +#intro-overlay.open .door-left { transform: translateX(-100%); } +#intro-overlay.open .door-right { transform: translateX(100%); } +#intro-overlay.open { + transition: opacity 0.45s ease 0.65s; + opacity: 0; + pointer-events: none; +} + +/* Модальное окно */ +.modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0,0,0,0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 100; +} + +.modal.hidden { + display: none; +} + +.modal-content { + background: #1b1e24; + padding: 20px; + border-radius: 8px; + width: 300px; + box-shadow: 0 5px 15px rgba(0,0,0,0.4); + position: relative; + color: #eee; +} +body[data-theme="light"] .modal-content { + background: #ffffff; + color: #222; +} + +.close-modal { + position: absolute; + top: 10px; + right: 15px; + font-size: 22px; + cursor: pointer; + color: #999; +} +.close-modal:hover { color: #eee; } +body[data-theme="light"] .close-modal { color: #777; } +body[data-theme="light"] .close-modal:hover { color: #333; } + +.modal-content h3 { + margin-bottom: 15px; + text-align: center; +} + +.freq-input-group { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + margin-bottom: 15px; +} + +.freq-btn { + width: 40px; + height: 40px; + font-size: 20px; + background: #b8362a; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + transition: background 0.2s; +} +.freq-btn:hover { background: #c73f31; } + +#freq-input { + width: 100px; + padding: 8px; + font-size: 18px; + text-align: center; + border: 1px solid #444; + border-radius: 4px; + background: #15171c; + color: #eee; +} +body[data-theme="light"] #freq-input { + border-color: #ccc; + background: #fff; + color: #222; +} + +#btn-set-freq { + display: block; + width: 100%; + margin-top: 10px; +} + +.error-msg { + color: #e74c3c; + margin-top: 8px; + text-align: center; + font-size: 14px; +} + +.error-msg.hidden { + display: none; +} diff --git a/gui/wails-standalone/frontend/wailsjs/go/main/App.d.ts b/gui/wails-standalone/frontend/wailsjs/go/main/App.d.ts new file mode 100755 index 0000000..677227e --- /dev/null +++ b/gui/wails-standalone/frontend/wailsjs/go/main/App.d.ts @@ -0,0 +1,9 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT +import {main} from '../models'; + +export function CheckConnection():Promise; + +export function Quit():Promise; + +export function SetFrequency(arg1:string):Promise; diff --git a/gui/wails-standalone/frontend/wailsjs/go/main/App.js b/gui/wails-standalone/frontend/wailsjs/go/main/App.js new file mode 100755 index 0000000..5839bb1 --- /dev/null +++ b/gui/wails-standalone/frontend/wailsjs/go/main/App.js @@ -0,0 +1,15 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export function CheckConnection() { + return window['go']['main']['App']['CheckConnection'](); +} + +export function Quit() { + return window['go']['main']['App']['Quit'](); +} + +export function SetFrequency(arg1) { + return window['go']['main']['App']['SetFrequency'](arg1); +} diff --git a/gui/wails-standalone/frontend/wailsjs/go/models.ts b/gui/wails-standalone/frontend/wailsjs/go/models.ts new file mode 100755 index 0000000..29e2d9b --- /dev/null +++ b/gui/wails-standalone/frontend/wailsjs/go/models.ts @@ -0,0 +1,19 @@ +export namespace main { + + export class DeviceResponse { + status: string; + frequency: string; + + static createFrom(source: any = {}) { + return new DeviceResponse(source); + } + + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.status = source["status"]; + this.frequency = source["frequency"]; + } + } + +} + diff --git a/gui/wails-standalone/frontend/wailsjs/runtime/package.json b/gui/wails-standalone/frontend/wailsjs/runtime/package.json new file mode 100644 index 0000000..1e7c8a5 --- /dev/null +++ b/gui/wails-standalone/frontend/wailsjs/runtime/package.json @@ -0,0 +1,24 @@ +{ + "name": "@wailsapp/runtime", + "version": "2.0.0", + "description": "Wails Javascript runtime library", + "main": "runtime.js", + "types": "runtime.d.ts", + "scripts": { + }, + "repository": { + "type": "git", + "url": "git+https://github.com/wailsapp/wails.git" + }, + "keywords": [ + "Wails", + "Javascript", + "Go" + ], + "author": "Lea Anthony ", + "license": "MIT", + "bugs": { + "url": "https://github.com/wailsapp/wails/issues" + }, + "homepage": "https://github.com/wailsapp/wails#readme" +} diff --git a/gui/wails-standalone/frontend/wailsjs/runtime/runtime.d.ts b/gui/wails-standalone/frontend/wailsjs/runtime/runtime.d.ts new file mode 100644 index 0000000..3bbea84 --- /dev/null +++ b/gui/wails-standalone/frontend/wailsjs/runtime/runtime.d.ts @@ -0,0 +1,330 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +export interface Position { + x: number; + y: number; +} + +export interface Size { + w: number; + h: number; +} + +export interface Screen { + isCurrent: boolean; + isPrimary: boolean; + width : number + height : number +} + +// Environment information such as platform, buildtype, ... +export interface EnvironmentInfo { + buildType: string; + platform: string; + arch: string; +} + +// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) +// emits the given event. Optional data may be passed with the event. +// This will trigger any event listeners. +export function EventsEmit(eventName: string, ...data: any): void; + +// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. +export function EventsOn(eventName: string, callback: (...data: any) => void): () => void; + +// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) +// sets up a listener for the given event name, but will only trigger a given number times. +export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void; + +// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) +// sets up a listener for the given event name, but will only trigger once. +export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void; + +// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff) +// unregisters the listener for the given event name. +export function EventsOff(eventName: string, ...additionalEventNames: string[]): void; + +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all listeners. +export function EventsOffAll(): void; + +// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) +// logs the given message as a raw message +export function LogPrint(message: string): void; + +// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) +// logs the given message at the `trace` log level. +export function LogTrace(message: string): void; + +// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) +// logs the given message at the `debug` log level. +export function LogDebug(message: string): void; + +// [LogError](https://wails.io/docs/reference/runtime/log#logerror) +// logs the given message at the `error` log level. +export function LogError(message: string): void; + +// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) +// logs the given message at the `fatal` log level. +// The application will quit after calling this method. +export function LogFatal(message: string): void; + +// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) +// logs the given message at the `info` log level. +export function LogInfo(message: string): void; + +// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) +// logs the given message at the `warning` log level. +export function LogWarning(message: string): void; + +// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) +// Forces a reload by the main application as well as connected browsers. +export function WindowReload(): void; + +// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) +// Reloads the application frontend. +export function WindowReloadApp(): void; + +// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) +// Sets the window AlwaysOnTop or not on top. +export function WindowSetAlwaysOnTop(b: boolean): void; + +// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) +// *Windows only* +// Sets window theme to system default (dark/light). +export function WindowSetSystemDefaultTheme(): void; + +// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) +// *Windows only* +// Sets window to light theme. +export function WindowSetLightTheme(): void; + +// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) +// *Windows only* +// Sets window to dark theme. +export function WindowSetDarkTheme(): void; + +// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) +// Centers the window on the monitor the window is currently on. +export function WindowCenter(): void; + +// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) +// Sets the text in the window title bar. +export function WindowSetTitle(title: string): void; + +// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) +// Makes the window full screen. +export function WindowFullscreen(): void; + +// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) +// Restores the previous window dimensions and position prior to full screen. +export function WindowUnfullscreen(): void; + +// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen) +// Returns the state of the window, i.e. whether the window is in full screen mode or not. +export function WindowIsFullscreen(): Promise; + +// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) +// Sets the width and height of the window. +export function WindowSetSize(width: number, height: number): void; + +// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) +// Gets the width and height of the window. +export function WindowGetSize(): Promise; + +// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) +// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. +// Setting a size of 0,0 will disable this constraint. +export function WindowSetMaxSize(width: number, height: number): void; + +// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) +// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. +// Setting a size of 0,0 will disable this constraint. +export function WindowSetMinSize(width: number, height: number): void; + +// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) +// Sets the window position relative to the monitor the window is currently on. +export function WindowSetPosition(x: number, y: number): void; + +// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) +// Gets the window position relative to the monitor the window is currently on. +export function WindowGetPosition(): Promise; + +// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) +// Hides the window. +export function WindowHide(): void; + +// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) +// Shows the window, if it is currently hidden. +export function WindowShow(): void; + +// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) +// Maximises the window to fill the screen. +export function WindowMaximise(): void; + +// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) +// Toggles between Maximised and UnMaximised. +export function WindowToggleMaximise(): void; + +// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) +// Restores the window to the dimensions and position prior to maximising. +export function WindowUnmaximise(): void; + +// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised) +// Returns the state of the window, i.e. whether the window is maximised or not. +export function WindowIsMaximised(): Promise; + +// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) +// Minimises the window. +export function WindowMinimise(): void; + +// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) +// Restores the window to the dimensions and position prior to minimising. +export function WindowUnminimise(): void; + +// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised) +// Returns the state of the window, i.e. whether the window is minimised or not. +export function WindowIsMinimised(): Promise; + +// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal) +// Returns the state of the window, i.e. whether the window is normal or not. +export function WindowIsNormal(): Promise; + +// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) +// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. +export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; + +// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) +// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. +export function ScreenGetAll(): Promise; + +// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) +// Opens the given URL in the system browser. +export function BrowserOpenURL(url: string): void; + +// [Environment](https://wails.io/docs/reference/runtime/intro#environment) +// Returns information about the environment +export function Environment(): Promise; + +// [Quit](https://wails.io/docs/reference/runtime/intro#quit) +// Quits the application. +export function Quit(): void; + +// [Hide](https://wails.io/docs/reference/runtime/intro#hide) +// Hides the application. +export function Hide(): void; + +// [Show](https://wails.io/docs/reference/runtime/intro#show) +// Shows the application. +export function Show(): void; + +// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext) +// Returns the current text stored on clipboard +export function ClipboardGetText(): Promise; + +// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext) +// Sets a text on the clipboard +export function ClipboardSetText(text: string): Promise; + +// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop) +// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. +export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void + +// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff) +// OnFileDropOff removes the drag and drop listeners and handlers. +export function OnFileDropOff() :void + +// Check if the file path resolver is available +export function CanResolveFilePaths(): boolean; + +// Resolves file paths for an array of files +export function ResolveFilePaths(files: File[]): void + +// Notification types +export interface NotificationOptions { + id: string; + title: string; + subtitle?: string; // macOS and Linux only + body?: string; + categoryId?: string; + data?: { [key: string]: any }; +} + +export interface NotificationAction { + id?: string; + title?: string; + destructive?: boolean; // macOS-specific +} + +export interface NotificationCategory { + id?: string; + actions?: NotificationAction[]; + hasReplyField?: boolean; + replyPlaceholder?: string; + replyButtonTitle?: string; +} + +// [InitializeNotifications](https://wails.io/docs/reference/runtime/notification#initializenotifications) +// Initializes the notification service for the application. +// This must be called before sending any notifications. +export function InitializeNotifications(): Promise; + +// [CleanupNotifications](https://wails.io/docs/reference/runtime/notification#cleanupnotifications) +// Cleans up notification resources and releases any held connections. +export function CleanupNotifications(): Promise; + +// [IsNotificationAvailable](https://wails.io/docs/reference/runtime/notification#isnotificationavailable) +// Checks if notifications are available on the current platform. +export function IsNotificationAvailable(): Promise; + +// [RequestNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#requestnotificationauthorization) +// Requests notification authorization from the user (macOS only). +export function RequestNotificationAuthorization(): Promise; + +// [CheckNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#checknotificationauthorization) +// Checks the current notification authorization status (macOS only). +export function CheckNotificationAuthorization(): Promise; + +// [SendNotification](https://wails.io/docs/reference/runtime/notification#sendnotification) +// Sends a basic notification with the given options. +export function SendNotification(options: NotificationOptions): Promise; + +// [SendNotificationWithActions](https://wails.io/docs/reference/runtime/notification#sendnotificationwithactions) +// Sends a notification with action buttons. Requires a registered category. +export function SendNotificationWithActions(options: NotificationOptions): Promise; + +// [RegisterNotificationCategory](https://wails.io/docs/reference/runtime/notification#registernotificationcategory) +// Registers a notification category that can be used with SendNotificationWithActions. +export function RegisterNotificationCategory(category: NotificationCategory): Promise; + +// [RemoveNotificationCategory](https://wails.io/docs/reference/runtime/notification#removenotificationcategory) +// Removes a previously registered notification category. +export function RemoveNotificationCategory(categoryId: string): Promise; + +// [RemoveAllPendingNotifications](https://wails.io/docs/reference/runtime/notification#removeallpendingnotifications) +// Removes all pending notifications from the notification center. +export function RemoveAllPendingNotifications(): Promise; + +// [RemovePendingNotification](https://wails.io/docs/reference/runtime/notification#removependingnotification) +// Removes a specific pending notification by its identifier. +export function RemovePendingNotification(identifier: string): Promise; + +// [RemoveAllDeliveredNotifications](https://wails.io/docs/reference/runtime/notification#removealldeliverednotifications) +// Removes all delivered notifications from the notification center. +export function RemoveAllDeliveredNotifications(): Promise; + +// [RemoveDeliveredNotification](https://wails.io/docs/reference/runtime/notification#removedeliverednotification) +// Removes a specific delivered notification by its identifier. +export function RemoveDeliveredNotification(identifier: string): Promise; + +// [RemoveNotification](https://wails.io/docs/reference/runtime/notification#removenotification) +// Removes a notification by its identifier (cross-platform convenience function). +export function RemoveNotification(identifier: string): Promise; \ No newline at end of file diff --git a/gui/wails-standalone/frontend/wailsjs/runtime/runtime.js b/gui/wails-standalone/frontend/wailsjs/runtime/runtime.js new file mode 100644 index 0000000..556621e --- /dev/null +++ b/gui/wails-standalone/frontend/wailsjs/runtime/runtime.js @@ -0,0 +1,298 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +export function LogPrint(message) { + window.runtime.LogPrint(message); +} + +export function LogTrace(message) { + window.runtime.LogTrace(message); +} + +export function LogDebug(message) { + window.runtime.LogDebug(message); +} + +export function LogInfo(message) { + window.runtime.LogInfo(message); +} + +export function LogWarning(message) { + window.runtime.LogWarning(message); +} + +export function LogError(message) { + window.runtime.LogError(message); +} + +export function LogFatal(message) { + window.runtime.LogFatal(message); +} + +export function EventsOnMultiple(eventName, callback, maxCallbacks) { + return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); +} + +export function EventsOn(eventName, callback) { + return EventsOnMultiple(eventName, callback, -1); +} + +export function EventsOff(eventName, ...additionalEventNames) { + return window.runtime.EventsOff(eventName, ...additionalEventNames); +} + +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + +export function EventsOnce(eventName, callback) { + return EventsOnMultiple(eventName, callback, 1); +} + +export function EventsEmit(eventName) { + let args = [eventName].slice.call(arguments); + return window.runtime.EventsEmit.apply(null, args); +} + +export function WindowReload() { + window.runtime.WindowReload(); +} + +export function WindowReloadApp() { + window.runtime.WindowReloadApp(); +} + +export function WindowSetAlwaysOnTop(b) { + window.runtime.WindowSetAlwaysOnTop(b); +} + +export function WindowSetSystemDefaultTheme() { + window.runtime.WindowSetSystemDefaultTheme(); +} + +export function WindowSetLightTheme() { + window.runtime.WindowSetLightTheme(); +} + +export function WindowSetDarkTheme() { + window.runtime.WindowSetDarkTheme(); +} + +export function WindowCenter() { + window.runtime.WindowCenter(); +} + +export function WindowSetTitle(title) { + window.runtime.WindowSetTitle(title); +} + +export function WindowFullscreen() { + window.runtime.WindowFullscreen(); +} + +export function WindowUnfullscreen() { + window.runtime.WindowUnfullscreen(); +} + +export function WindowIsFullscreen() { + return window.runtime.WindowIsFullscreen(); +} + +export function WindowGetSize() { + return window.runtime.WindowGetSize(); +} + +export function WindowSetSize(width, height) { + window.runtime.WindowSetSize(width, height); +} + +export function WindowSetMaxSize(width, height) { + window.runtime.WindowSetMaxSize(width, height); +} + +export function WindowSetMinSize(width, height) { + window.runtime.WindowSetMinSize(width, height); +} + +export function WindowSetPosition(x, y) { + window.runtime.WindowSetPosition(x, y); +} + +export function WindowGetPosition() { + return window.runtime.WindowGetPosition(); +} + +export function WindowHide() { + window.runtime.WindowHide(); +} + +export function WindowShow() { + window.runtime.WindowShow(); +} + +export function WindowMaximise() { + window.runtime.WindowMaximise(); +} + +export function WindowToggleMaximise() { + window.runtime.WindowToggleMaximise(); +} + +export function WindowUnmaximise() { + window.runtime.WindowUnmaximise(); +} + +export function WindowIsMaximised() { + return window.runtime.WindowIsMaximised(); +} + +export function WindowMinimise() { + window.runtime.WindowMinimise(); +} + +export function WindowUnminimise() { + window.runtime.WindowUnminimise(); +} + +export function WindowSetBackgroundColour(R, G, B, A) { + window.runtime.WindowSetBackgroundColour(R, G, B, A); +} + +export function ScreenGetAll() { + return window.runtime.ScreenGetAll(); +} + +export function WindowIsMinimised() { + return window.runtime.WindowIsMinimised(); +} + +export function WindowIsNormal() { + return window.runtime.WindowIsNormal(); +} + +export function BrowserOpenURL(url) { + window.runtime.BrowserOpenURL(url); +} + +export function Environment() { + return window.runtime.Environment(); +} + +export function Quit() { + window.runtime.Quit(); +} + +export function Hide() { + window.runtime.Hide(); +} + +export function Show() { + window.runtime.Show(); +} + +export function ClipboardGetText() { + return window.runtime.ClipboardGetText(); +} + +export function ClipboardSetText(text) { + return window.runtime.ClipboardSetText(text); +} + +/** + * Callback for OnFileDrop returns a slice of file path strings when a drop is finished. + * + * @export + * @callback OnFileDropCallback + * @param {number} x - x coordinate of the drop + * @param {number} y - y coordinate of the drop + * @param {string[]} paths - A list of file paths. + */ + +/** + * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. + * + * @export + * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished. + * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target) + */ +export function OnFileDrop(callback, useDropTarget) { + return window.runtime.OnFileDrop(callback, useDropTarget); +} + +/** + * OnFileDropOff removes the drag and drop listeners and handlers. + */ +export function OnFileDropOff() { + return window.runtime.OnFileDropOff(); +} + +export function CanResolveFilePaths() { + return window.runtime.CanResolveFilePaths(); +} + +export function ResolveFilePaths(files) { + return window.runtime.ResolveFilePaths(files); +} + +export function InitializeNotifications() { + return window.runtime.InitializeNotifications(); +} + +export function CleanupNotifications() { + return window.runtime.CleanupNotifications(); +} + +export function IsNotificationAvailable() { + return window.runtime.IsNotificationAvailable(); +} + +export function RequestNotificationAuthorization() { + return window.runtime.RequestNotificationAuthorization(); +} + +export function CheckNotificationAuthorization() { + return window.runtime.CheckNotificationAuthorization(); +} + +export function SendNotification(options) { + return window.runtime.SendNotification(options); +} + +export function SendNotificationWithActions(options) { + return window.runtime.SendNotificationWithActions(options); +} + +export function RegisterNotificationCategory(category) { + return window.runtime.RegisterNotificationCategory(category); +} + +export function RemoveNotificationCategory(categoryId) { + return window.runtime.RemoveNotificationCategory(categoryId); +} + +export function RemoveAllPendingNotifications() { + return window.runtime.RemoveAllPendingNotifications(); +} + +export function RemovePendingNotification(identifier) { + return window.runtime.RemovePendingNotification(identifier); +} + +export function RemoveAllDeliveredNotifications() { + return window.runtime.RemoveAllDeliveredNotifications(); +} + +export function RemoveDeliveredNotification(identifier) { + return window.runtime.RemoveDeliveredNotification(identifier); +} + +export function RemoveNotification(identifier) { + return window.runtime.RemoveNotification(identifier); +} \ No newline at end of file diff --git a/gui/wails/frontend/dist/assets/index.02c817da.js b/gui/wails/frontend/dist/assets/index.02c817da.js new file mode 100644 index 0000000..dc2b94c --- /dev/null +++ b/gui/wails/frontend/dist/assets/index.02c817da.js @@ -0,0 +1 @@ +(function(){const d=document.createElement("link").relList;if(d&&d.supports&&d.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))f(e);new MutationObserver(e=>{for(const n of e)if(n.type==="childList")for(const s of n.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&f(s)}).observe(document,{childList:!0,subtree:!0});function m(e){const n={};return e.integrity&&(n.integrity=e.integrity),e.referrerpolicy&&(n.referrerPolicy=e.referrerpolicy),e.crossorigin==="use-credentials"?n.credentials="include":e.crossorigin==="anonymous"?n.credentials="omit":n.credentials="same-origin",n}function f(e){if(e.ep)return;e.ep=!0;const n=m(e);fetch(e.href,n)}})();function N(){return window.go.main.App.CheckConnection()}function F(){return window.go.main.App.Quit()}function $(a){return window.go.main.App.SetFrequency(a)}const D="/assets/logo-dark.ff9a8bc7.jpg";(function(){const a=document.getElementById("theme-toggle");a.addEventListener("click",()=>{const c=document.body.getAttribute("data-theme")==="light"?"dark":"light";document.body.setAttribute("data-theme",c),a.textContent=c==="light"?"\u263E":"\u2600"});const d=640,m=480,f=312,e=D,n=document.getElementById("intro-overlay"),s=document.querySelector("#intro-overlay .door-left"),l=document.querySelector("#intro-overlay .door-right");function L(){const t=window.innerWidth,c=window.innerHeight,o=Math.max(t/d,c/m),h=d*o,p=m*o,v=(t-h)/2,q=(c-p)/2,W=v+f*o,g=Math.max(0,Math.min(t,W)),_=t-g;s.style.width=g+"px",s.style.backgroundImage=`url(${e})`,s.style.backgroundSize=h+"px "+p+"px",s.style.backgroundPosition=v+"px "+q+"px",l.style.left=g+"px",l.style.width=_+"px",l.style.backgroundImage=`url(${e})`,l.style.backgroundSize=h+"px "+p+"px",l.style.backgroundPosition=v-g+"px "+q+"px"}const b=2100,C=100;function A(){n.style.display="",n.classList.remove("appear","open"),n.offsetWidth,L(),setTimeout(()=>n.classList.add("appear"),C),setTimeout(()=>n.classList.add("open"),b),setTimeout(()=>{n.style.display="none"},b+1170)}window.addEventListener("resize",L),A();const E=document.querySelectorAll(".tab-button"),B=document.querySelectorAll(".tab-content");E.forEach(t=>{t.addEventListener("click",()=>{E.forEach(o=>o.classList.remove("active")),B.forEach(o=>o.classList.remove("active")),t.classList.add("active");const c=t.getAttribute("data-tab");document.getElementById(`tab-${c}`).classList.add("active")})});const w=document.getElementById("btn-check"),S=document.getElementById("btn-freq"),T=document.getElementById("btn-quit"),x=document.getElementById("status-indicator"),I=document.getElementById("status-text"),k=document.getElementById("frequency-label"),y=document.getElementById("frequency-value"),u=document.getElementById("freq-modal"),O=document.getElementById("close-modal"),i=document.getElementById("freq-input"),P=document.getElementById("btn-minus"),M=document.getElementById("btn-plus"),R=document.getElementById("btn-set-freq"),r=document.getElementById("modal-error");w.addEventListener("click",()=>{N().then(t=>{x.classList.remove("indicator-red"),x.classList.add("indicator-green"),I.textContent=`\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E! ${t.status}`,k.textContent="\u0422\u0435\u043A\u0443\u0449\u0430\u044F \u0447\u0430\u0441\u0442\u043E\u0442\u0430:",y.textContent=t.frequency}).catch(t=>{console.error("\u041E\u0448\u0438\u0431\u043A\u0430 CheckConnection:",t),I.textContent="\u041E\u0448\u0438\u0431\u043A\u0430: \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443"})}),S.addEventListener("click",()=>{u.classList.remove("hidden");const t=y.textContent!=="---"?y.textContent:"145";i.value=t,r.classList.add("hidden")}),O.addEventListener("click",()=>{u.classList.add("hidden")}),window.addEventListener("click",t=>{t.target===u&&u.classList.add("hidden")}),P.addEventListener("click",()=>{let t=parseInt(i.value,10)||1;t=Math.max(1,t-1),i.value=t.toString()}),M.addEventListener("click",()=>{let t=parseInt(i.value,10)||1;t+=1,i.value=t.toString()}),R.addEventListener("click",()=>{const t=i.value.trim();if(!/^\d+$/.test(t)){r.textContent="\u0412\u0432\u043E\u0434\u0438\u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0446\u0435\u043B\u044B\u043C \u043F\u043E\u043B\u043E\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C",r.classList.remove("hidden");return}if(parseInt(t,10)<=0){r.textContent="\u0412\u0432\u043E\u0434\u0438\u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0446\u0435\u043B\u044B\u043C \u043F\u043E\u043B\u043E\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C",r.classList.remove("hidden");return}$(t).then(o=>{k.textContent="\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u0430\u044F \u0447\u0430\u0441\u0442\u043E\u0442\u0430:",y.textContent=o,u.classList.add("hidden")}).catch(o=>{r.textContent=o,r.classList.remove("hidden")})}),T.addEventListener("click",()=>{F()})})(); diff --git a/gui/wails/frontend/dist/assets/index.41fde905.css b/gui/wails/frontend/dist/assets/index.41fde905.css new file mode 100644 index 0000000..b457202 --- /dev/null +++ b/gui/wails/frontend/dist/assets/index.41fde905.css @@ -0,0 +1 @@ +*{margin:0;padding:0;box-sizing:border-box}html,body{width:100%;height:100%;display:flex;justify-content:center;align-items:center;font-family:Arial,sans-serif;overflow:hidden}body{background:radial-gradient(circle at 50% 18%,#1a1d24 0%,#0d0f13 70%);transition:background .3s ease}body[data-theme=light]{background:radial-gradient(circle at 50% 18%,#ffffff 0%,#dde1e7 70%)}#theme-toggle{position:fixed;top:16px;right:18px;z-index:500;width:34px;height:34px;border-radius:50%;border:1px solid #333a46;background:#222a37;color:#ccc;cursor:pointer;font-size:14px;display:flex;align-items:center;justify-content:center}body[data-theme=light] #theme-toggle{border-color:#c7cbd1;background:#ffffff;color:#555}#app{width:360px;border-radius:14px;box-shadow:0 8px 28px #0000004d;overflow:hidden;background:#1b1e24;transition:background .3s ease}body[data-theme=light] #app{background:#ffffff}#brand{display:flex;flex-direction:column;align-items:center;padding:26px 24px 16px;gap:6px}.logo-icon{position:relative;width:64px;height:48px;margin-bottom:6px}.logo-icon img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}.logo-icon .logo-dark{mix-blend-mode:screen;display:block}.logo-icon .logo-light{mix-blend-mode:multiply;display:none}body[data-theme=light] .logo-icon .logo-dark{display:none}body[data-theme=light] .logo-icon .logo-light{display:block}#brand h1{color:#eee;font-size:21px;letter-spacing:3.5px;font-weight:700}#brand .tag{color:#7a7f89;font-size:11px;letter-spacing:1.2px}body[data-theme=light] #brand h1{color:#1b1d22}body[data-theme=light] #brand .tag{color:#888d97}.tabs{display:flex;background:transparent}.tabs[hidden]{display:none}.tab-button{flex:1;padding:12px;background:transparent;border:none;cursor:pointer;font-size:14px;color:#9aa0aa;transition:background .2s}.tab-button:hover{background:rgba(255,255,255,.05)}.tab-button.active{color:#eee;border-bottom:2px solid #b8362a;font-weight:700}body[data-theme=light] .tab-button{color:#7a7f89}body[data-theme=light] .tab-button.active{color:#1b1d22}.tab-content{display:none;padding:4px 22px 24px}.tab-content.active{display:block}.buttons-vertical{display:flex;flex-direction:column;gap:10px;margin-bottom:12px}.action-button{padding:11px;font-size:14px;cursor:pointer;border:1px solid #2a2d34;border-radius:8px;background-color:#15171c;color:#e8e8e8;transition:background-color .2s,border-color .2s}.action-button:hover{background-color:#1d2027;border-color:#3a3e46}body[data-theme=light] .action-button{background-color:#fff;border-color:#ccd1d9;color:#22242a}body[data-theme=light] .action-button:hover{background-color:#f0f2f5;border-color:#aeb4bd}.close-button{background-color:#b8362a;color:#fff;border-color:#8f2a20}.close-button:hover{background-color:#c73f31}body[data-theme=light] .close-button{background-color:#e74c3c;border-color:#c0392b;color:#fff}body[data-theme=light] .close-button:hover{background-color:#d8432f}#frequency-panel{display:flex;justify-content:space-between;align-items:center;padding:9px 13px;background-color:#15171c;border:1px solid #2a2d34;border-radius:8px;margin-bottom:9px}#frequency-label{font-weight:700;color:#9aa0aa;font-size:13px}#frequency-value{font-size:17px;color:#f2f2f2}body[data-theme=light] #frequency-panel{background-color:#fff;border-color:#ccd1d9}body[data-theme=light] #frequency-label{color:#7a7f89}body[data-theme=light] #frequency-value{color:#1b1d22}#status-panel{display:flex;align-items:center;gap:9px;padding:9px 13px;background-color:#15171c;border:1px solid #2a2d34;border-radius:8px}body[data-theme=light] #status-panel{background-color:#fff;border-color:#ccd1d9}.indicator{width:14px;height:14px;border-radius:50%;display:inline-block}.indicator-red{background-color:#e74c3c}.indicator-green{background-color:#2ecc71}#status-text{font-size:14px;color:#ddd}body[data-theme=light] #status-text{color:#333}#intro-overlay{position:fixed;inset:0;z-index:1000;background:#000;transform:scale(1.04)}#intro-overlay.appear{animation:introPop .45s cubic-bezier(.2,.9,.3,1) forwards}@keyframes introPop{to{transform:scale(1)}}.door{position:absolute;top:0;bottom:0;overflow:hidden;background-color:#000;background-repeat:no-repeat;transition:transform 1.17s cubic-bezier(.65,0,.35,1)}.door-left,.door-right{left:0}#intro-overlay.open .door-left{transform:translate(-100%)}#intro-overlay.open .door-right{transform:translate(100%)}#intro-overlay.open{transition:opacity .45s ease .65s;opacity:0;pointer-events:none}.modal{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);display:flex;justify-content:center;align-items:center;z-index:100}.modal.hidden{display:none}.modal-content{background:#1b1e24;padding:20px;border-radius:8px;width:300px;box-shadow:0 5px 15px #0006;position:relative;color:#eee}body[data-theme=light] .modal-content{background:#ffffff;color:#222}.close-modal{position:absolute;top:10px;right:15px;font-size:22px;cursor:pointer;color:#999}.close-modal:hover{color:#eee}body[data-theme=light] .close-modal{color:#777}body[data-theme=light] .close-modal:hover{color:#333}.modal-content h3{margin-bottom:15px;text-align:center}.freq-input-group{display:flex;align-items:center;justify-content:center;gap:10px;margin-bottom:15px}.freq-btn{width:40px;height:40px;font-size:20px;background:#b8362a;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background .2s}.freq-btn:hover{background:#c73f31}#freq-input{width:100px;padding:8px;font-size:18px;text-align:center;border:1px solid #444;border-radius:4px;background:#15171c;color:#eee}body[data-theme=light] #freq-input{border-color:#ccc;background:#fff;color:#222}#btn-set-freq{display:block;width:100%;margin-top:10px}.error-msg{color:#e74c3c;margin-top:8px;text-align:center;font-size:14px}.error-msg.hidden{display:none} diff --git a/gui/wails/frontend/dist/assets/index.448f6f10.css b/gui/wails/frontend/dist/assets/index.448f6f10.css deleted file mode 100644 index 7d45c33..0000000 --- a/gui/wails/frontend/dist/assets/index.448f6f10.css +++ /dev/null @@ -1 +0,0 @@ -*{margin:0;padding:0;box-sizing:border-box}html,body{width:100%;height:100%;display:flex;justify-content:center;align-items:center;background-color:#f0f0f0;font-family:Arial,sans-serif}#app{width:400px;background:white;border-radius:8px;box-shadow:0 2px 10px #0000001a;overflow:hidden}.tabs{display:flex;background:#e9e9e9}.tab-button{flex:1;padding:12px;background:transparent;border:none;cursor:pointer;font-size:16px;transition:background .2s}.tab-button:hover{background:#dcdcdc}.tab-button.active{background:white;border-bottom:3px solid #3498db;font-weight:700}.tab-content{display:none;padding:20px}.tab-content.active{display:block}.buttons-vertical{display:flex;flex-direction:column;gap:12px;margin-bottom:20px}.action-button{padding:12px;font-size:16px;cursor:pointer;border:1px solid #bbb;border-radius:6px;background-color:#f8f8f8;transition:background-color .2s,border-color .2s}.action-button:hover{background-color:#e2e6ea;border-color:#999}.close-button{background-color:#e74c3c;color:#fff;border-color:#c0392b}.close-button:hover{background-color:#c0392b}#frequency-panel{display:flex;justify-content:space-between;align-items:center;padding:10px 14px;background-color:#f9f9f9;border:1px solid #ddd;border-radius:6px;margin-bottom:10px}#frequency-label{font-weight:700;color:#555}#frequency-value{font-size:18px;color:#2c3e50}#status-panel{display:flex;align-items:center;gap:10px;padding:10px 14px;background-color:#f9f9f9;border:1px solid #ddd;border-radius:6px}.indicator{width:16px;height:16px;border-radius:50%;display:inline-block}.indicator-red{background-color:#e74c3c}.indicator-green{background-color:#2ecc71}#status-text{font-size:16px;color:#333}.modal{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.4);display:flex;justify-content:center;align-items:center;z-index:100}.modal.hidden{display:none}.modal-content{background:white;padding:20px;border-radius:8px;width:300px;box-shadow:0 5px 15px #0000004d;position:relative}.close-modal{position:absolute;top:10px;right:15px;font-size:22px;cursor:pointer;color:#777}.close-modal:hover{color:#333}.modal-content h3{margin-bottom:15px;text-align:center}.freq-input-group{display:flex;align-items:center;justify-content:center;gap:10px;margin-bottom:15px}.freq-btn{width:40px;height:40px;font-size:20px;background:#3498db;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background .2s}.freq-btn:hover{background:#2980b9}#freq-input{width:100px;padding:8px;font-size:18px;text-align:center;border:1px solid #ccc;border-radius:4px}#btn-set-freq{display:block;width:100%;margin-top:10px}.error-msg{color:#e74c3c;margin-top:8px;text-align:center;font-size:14px}.error-msg.hidden{display:none} diff --git a/gui/wails/frontend/dist/assets/index.cb23cfd6.js b/gui/wails/frontend/dist/assets/index.cb23cfd6.js deleted file mode 100644 index a1a33c0..0000000 --- a/gui/wails/frontend/dist/assets/index.cb23cfd6.js +++ /dev/null @@ -1 +0,0 @@ -(function(){const i=document.createElement("link").relList;if(i&&i.supports&&i.supports("modulepreload"))return;for(const t of document.querySelectorAll('link[rel="modulepreload"]'))a(t);new MutationObserver(t=>{for(const n of t)if(n.type==="childList")for(const s of n.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&a(s)}).observe(document,{childList:!0,subtree:!0});function m(t){const n={};return t.integrity&&(n.integrity=t.integrity),t.referrerpolicy&&(n.referrerPolicy=t.referrerpolicy),t.crossorigin==="use-credentials"?n.credentials="include":t.crossorigin==="anonymous"?n.credentials="omit":n.credentials="same-origin",n}function a(t){if(t.ep)return;t.ep=!0;const n=m(t);fetch(t.href,n)}})();function h(){return window.go.main.App.CheckConnection()}function b(){return window.go.main.App.Quit()}function p(d){return window.go.main.App.SetFrequency(d)}(function(){const d=document.querySelectorAll(".tab-button"),i=document.querySelectorAll(".tab-content");d.forEach(e=>{e.addEventListener("click",()=>{d.forEach(c=>c.classList.remove("active")),i.forEach(c=>c.classList.remove("active")),e.classList.add("active");const y=e.getAttribute("data-tab");document.getElementById(`tab-${y}`).classList.add("active")})});const m=document.getElementById("btn-check"),a=document.getElementById("btn-freq"),t=document.getElementById("btn-quit"),n=document.getElementById("status-indicator"),s=document.getElementById("status-text"),f=document.getElementById("frequency-label"),u=document.getElementById("frequency-value"),l=document.getElementById("freq-modal"),g=document.getElementById("close-modal"),r=document.getElementById("freq-input"),v=document.getElementById("btn-minus"),E=document.getElementById("btn-plus"),L=document.getElementById("btn-set-freq"),o=document.getElementById("modal-error");m.addEventListener("click",()=>{h().then(e=>{n.classList.remove("indicator-red"),n.classList.add("indicator-green"),s.textContent=`\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E! ${e.status}`,f.textContent="\u0422\u0435\u043A\u0443\u0449\u0430\u044F \u0447\u0430\u0441\u0442\u043E\u0442\u0430:",u.textContent=e.frequency}).catch(e=>{console.error("\u041E\u0448\u0438\u0431\u043A\u0430 CheckConnection:",e),s.textContent="\u041E\u0448\u0438\u0431\u043A\u0430: \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443"})}),a.addEventListener("click",()=>{l.classList.remove("hidden");const e=u.textContent!=="---"?u.textContent:"145";r.value=e,o.classList.add("hidden")}),g.addEventListener("click",()=>{l.classList.add("hidden")}),window.addEventListener("click",e=>{e.target===l&&l.classList.add("hidden")}),v.addEventListener("click",()=>{let e=parseInt(r.value,10)||1;e=Math.max(1,e-1),r.value=e.toString()}),E.addEventListener("click",()=>{let e=parseInt(r.value,10)||1;e+=1,r.value=e.toString()}),L.addEventListener("click",()=>{const e=r.value.trim();if(!/^\d+$/.test(e)){o.textContent="\u0412\u0432\u043E\u0434\u0438\u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0446\u0435\u043B\u044B\u043C \u043F\u043E\u043B\u043E\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C",o.classList.remove("hidden");return}if(parseInt(e,10)<=0){o.textContent="\u0412\u0432\u043E\u0434\u0438\u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0446\u0435\u043B\u044B\u043C \u043F\u043E\u043B\u043E\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C",o.classList.remove("hidden");return}p(e).then(c=>{f.textContent="\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u0430\u044F \u0447\u0430\u0441\u0442\u043E\u0442\u0430:",u.textContent=c,l.classList.add("hidden")}).catch(c=>{o.textContent=c,o.classList.remove("hidden")})}),t.addEventListener("click",()=>{b()})})(); diff --git a/gui/wails/frontend/dist/assets/logo-dark.ff9a8bc7.jpg b/gui/wails/frontend/dist/assets/logo-dark.ff9a8bc7.jpg new file mode 100644 index 0000000..6856a0a Binary files /dev/null and b/gui/wails/frontend/dist/assets/logo-dark.ff9a8bc7.jpg differ diff --git a/gui/wails/frontend/dist/assets/logo-light.d5e577a8.png b/gui/wails/frontend/dist/assets/logo-light.d5e577a8.png new file mode 100644 index 0000000..5c56201 Binary files /dev/null and b/gui/wails/frontend/dist/assets/logo-light.d5e577a8.png differ diff --git a/gui/wails/frontend/dist/index.html b/gui/wails/frontend/dist/index.html index b3c31d6..a5f458f 100644 --- a/gui/wails/frontend/dist/index.html +++ b/gui/wails/frontend/dist/index.html @@ -4,14 +4,35 @@ - Тест (Спектр) - - + Спектр + + - + + + + + + +
+
+
+
+
- -
+ + +
+
+ ТЭЧ ДМ + ТЭЧ ДМ +
+

СПЕКТР

+
видеоприёмник · панель управления
+
+ + +