init commit
This commit is contained in:
152
frontend/index.html
Normal file
152
frontend/index.html
Normal file
@@ -0,0 +1,152 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>kettuRay</title>
|
||||
<link rel="stylesheet" href="/src/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
|
||||
<!-- Custom title bar -->
|
||||
<div class="titlebar" data-wails-drag>
|
||||
<span class="titlebar-title">kettuRay <span class="titlebar-sub">by @khton</span></span>
|
||||
<div class="titlebar-actions">
|
||||
<button class="icon-btn" id="minimizeBtn" title="Minimize to tray">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/>
|
||||
<line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main content column -->
|
||||
<div id="mainCol">
|
||||
|
||||
<!-- Status card -->
|
||||
<div class="status-card">
|
||||
<div class="status-top">
|
||||
<span id="stateDot" class="state-dot disconnected"></span>
|
||||
<span id="stateText" class="state-text">Disconnected</span>
|
||||
</div>
|
||||
<div id="selectedName" class="status-name">not selected</div>
|
||||
<div class="status-meta">
|
||||
<span id="protoBadgeStatus" class="proto-badge" style="display:none"></span>
|
||||
<span id="pingStatus" class="ping-status"></span>
|
||||
<span id="latencyStatus" class="latency-status"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Configs header -->
|
||||
<div class="section-header" style="margin-top:18px">
|
||||
<span class="section-title">Configurations</span>
|
||||
<div class="header-actions">
|
||||
<button class="icon-btn" id="pingAllBtn" title="Ping all">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="10" cy="12" r="2"/><path d="M13.4 10.6 L19 5"/><path d="M15.6 2.7a10 10 0 1 0 5.7 5.7"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="icon-btn" id="addLinkBtn" title="Add manually">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M15 7h2a5 5 0 0 1 0 10h-2m-6 0H7A5 5 0 0 1 7 7h2"/>
|
||||
<line x1="8" y1="12" x2="16" y2="12"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="icon-btn" id="addClipboardBtn" title="Add from clipboard">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>
|
||||
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Link input panel (hidden by default) -->
|
||||
<div id="linkInputPanel" class="link-input-panel hidden">
|
||||
<input type="text" id="linkInputBox" placeholder="vless:// or trojan://..." spellcheck="false" autocomplete="off" />
|
||||
<button id="submitLinkBtn" class="add-btn">+</button>
|
||||
</div>
|
||||
|
||||
<!-- Config list -->
|
||||
<div id="configList" class="config-list">
|
||||
<div id="emptyState" class="empty-state">
|
||||
No configurations.<br>Copy a link and add it from the clipboard.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom controls -->
|
||||
<div class="bottom-bar">
|
||||
<div class="bottom-left">
|
||||
<button class="icon-btn" id="settingsBtn" title="Settings">
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path id="settingsChevron" d="M2,1 L7,6 L2,11"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button id="connectBtn" class="solid-btn green" style="display:none">Start</button>
|
||||
<button id="disconnectBtn" class="solid-btn red" style="display:none">Stop</button>
|
||||
<button id="logBtn" class="solid-btn gray">Log</button>
|
||||
</div>
|
||||
<div class="bottom-right">
|
||||
<button id="exitBtn" class="exit-btn">Exit</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings panel (hidden by default) -->
|
||||
<div id="settingsPanel" class="settings-panel hidden">
|
||||
<div class="settings-card">
|
||||
<label class="toggle-row">
|
||||
<span class="toggle-wrap">
|
||||
<input type="checkbox" id="runOnStartup" />
|
||||
<span class="toggle-track"><span class="toggle-knob"></span></span>
|
||||
</span>
|
||||
<span class="toggle-label">Run on startup</span>
|
||||
</label>
|
||||
<label class="toggle-row">
|
||||
<span class="toggle-wrap">
|
||||
<input type="checkbox" id="autoConnect" />
|
||||
<span class="toggle-track"><span class="toggle-knob"></span></span>
|
||||
</span>
|
||||
<span class="toggle-label">Auto-connect VPN</span>
|
||||
</label>
|
||||
<label class="toggle-row" style="margin-bottom:0">
|
||||
<span class="toggle-wrap">
|
||||
<input type="checkbox" id="autoReconnect" />
|
||||
<span class="toggle-track"><span class="toggle-knob"></span></span>
|
||||
</span>
|
||||
<span class="toggle-label">Auto-reconnect</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Log sidebar -->
|
||||
<div id="logCol" class="log-col hidden">
|
||||
<div class="log-header">
|
||||
<span class="section-title">Logs</span>
|
||||
<div class="header-actions">
|
||||
<button class="icon-btn small" id="copyLogsBtn">Copy</button>
|
||||
<button class="icon-btn small" id="clearLogsBtn">Clear</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="logArea" class="log-area"></div>
|
||||
</div>
|
||||
|
||||
<!-- Toast notification -->
|
||||
<div id="toast" class="toast hidden"></div>
|
||||
|
||||
<!-- Context menu -->
|
||||
<div id="ctxMenu" class="ctx-menu hidden">
|
||||
<div class="ctx-item" id="ctxCopyLink">Copy Link</div>
|
||||
<div class="ctx-separator"></div>
|
||||
<div class="ctx-item danger" id="ctxDelete">Delete</div>
|
||||
</div>
|
||||
|
||||
<!-- Notification stack -->
|
||||
<div id="notifStack" class="notif-stack"></div>
|
||||
</div>
|
||||
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
1143
frontend/package-lock.json
generated
Normal file
1143
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
frontend/package.json
Normal file
12
frontend/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "ketturay-frontend",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^6.0.0"
|
||||
}
|
||||
}
|
||||
1
frontend/package.json.md5
Normal file
1
frontend/package.json.md5
Normal file
@@ -0,0 +1 @@
|
||||
51c73c9dd7c8a498b3e4e7db2243affe
|
||||
477
frontend/src/main.js
Normal file
477
frontend/src/main.js
Normal file
@@ -0,0 +1,477 @@
|
||||
import {
|
||||
GetConfigs, AddConfig, DeleteConfig,
|
||||
SetSelectedConfig, GetSelectedConfigID,
|
||||
Connect, Disconnect, GetState,
|
||||
PingAll,
|
||||
GetSettings, SaveSettings,
|
||||
ResizeWindow, HideWindow,
|
||||
} from '../wailsjs/go/main/App.js';
|
||||
import { EventsOn, Quit } from '../wailsjs/runtime/runtime.js';
|
||||
|
||||
// ── DOM refs ──────────────────────────────────────────────────────────────────
|
||||
const stateDot = document.getElementById('stateDot');
|
||||
const stateText = document.getElementById('stateText');
|
||||
const selectedName = document.getElementById('selectedName');
|
||||
const protoBadge = document.getElementById('protoBadgeStatus');
|
||||
const pingStatus = document.getElementById('pingStatus');
|
||||
const latencyStatus = document.getElementById('latencyStatus');
|
||||
|
||||
const pingAllBtn = document.getElementById('pingAllBtn');
|
||||
const addLinkBtn = document.getElementById('addLinkBtn');
|
||||
const addClipboardBtn= document.getElementById('addClipboardBtn');
|
||||
const linkInputPanel = document.getElementById('linkInputPanel');
|
||||
const linkInputBox = document.getElementById('linkInputBox');
|
||||
const submitLinkBtn = document.getElementById('submitLinkBtn');
|
||||
|
||||
const configList = document.getElementById('configList');
|
||||
const emptyState = document.getElementById('emptyState');
|
||||
|
||||
const connectBtn = document.getElementById('connectBtn');
|
||||
const disconnectBtn = document.getElementById('disconnectBtn');
|
||||
const logBtn = document.getElementById('logBtn');
|
||||
const settingsBtn = document.getElementById('settingsBtn');
|
||||
const exitBtn = document.getElementById('exitBtn');
|
||||
const minimizeBtn = document.getElementById('minimizeBtn');
|
||||
|
||||
const settingsPanel = document.getElementById('settingsPanel');
|
||||
const settingsChevron= document.getElementById('settingsChevron');
|
||||
const runOnStartup = document.getElementById('runOnStartup');
|
||||
const autoConnect = document.getElementById('autoConnect');
|
||||
const autoReconnect = document.getElementById('autoReconnect');
|
||||
|
||||
const logCol = document.getElementById('logCol');
|
||||
const logArea = document.getElementById('logArea');
|
||||
const copyLogsBtn = document.getElementById('copyLogsBtn');
|
||||
const clearLogsBtn = document.getElementById('clearLogsBtn');
|
||||
|
||||
const toast = document.getElementById('toast');
|
||||
const ctxMenu = document.getElementById('ctxMenu');
|
||||
const ctxCopyLink = document.getElementById('ctxCopyLink');
|
||||
const ctxDelete = document.getElementById('ctxDelete');
|
||||
|
||||
// ── State ─────────────────────────────────────────────────────────────────────
|
||||
let currentState = 'Disconnected';
|
||||
let selectedID = '';
|
||||
let configs = [];
|
||||
let logExpanded = false;
|
||||
let settingsExpanded= false;
|
||||
let linkPanelOpen = false;
|
||||
let ctxTargetID = null;
|
||||
let deleteConfirmTimeout = null;
|
||||
|
||||
// Window heights
|
||||
const BASE_H = 500;
|
||||
const SETTINGS_H = 80; // extra height for settings panel
|
||||
const BASE_W = 360;
|
||||
const LOG_W = 360;
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
function currentWindowSize() {
|
||||
const h = BASE_H + (settingsExpanded ? SETTINGS_H : 0);
|
||||
const w = BASE_W + (logExpanded ? LOG_W : 0);
|
||||
return { w, h };
|
||||
}
|
||||
|
||||
function applyWindowSize() {
|
||||
const { w, h } = currentWindowSize();
|
||||
ResizeWindow(w, h);
|
||||
}
|
||||
|
||||
// ── State UI ──────────────────────────────────────────────────────────────────
|
||||
function updateStateUI(state) {
|
||||
currentState = state;
|
||||
const s = state.toLowerCase();
|
||||
stateDot.className = 'state-dot ' + s;
|
||||
stateText.textContent = state;
|
||||
|
||||
connectBtn.style.display = 'none';
|
||||
disconnectBtn.style.display = 'none';
|
||||
|
||||
switch (state) {
|
||||
case 'Disconnected':
|
||||
case 'Error':
|
||||
connectBtn.style.display = 'inline-flex';
|
||||
connectBtn.disabled = !selectedID;
|
||||
break;
|
||||
case 'Connecting':
|
||||
disconnectBtn.style.display = 'inline-flex';
|
||||
disconnectBtn.disabled = false;
|
||||
break;
|
||||
case 'Connected':
|
||||
disconnectBtn.style.display = 'inline-flex';
|
||||
disconnectBtn.disabled = false;
|
||||
break;
|
||||
case 'Disconnecting':
|
||||
disconnectBtn.style.display = 'inline-flex';
|
||||
disconnectBtn.disabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Config list rendering ─────────────────────────────────────────────────────
|
||||
function renderConfigs() {
|
||||
// Remove all config items but keep emptyState
|
||||
configList.querySelectorAll('.config-item').forEach(el => el.remove());
|
||||
|
||||
emptyState.style.display = configs.length === 0 ? 'block' : 'none';
|
||||
|
||||
for (const cfg of configs) {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'config-item' + (cfg.id === selectedID ? ' selected' : '');
|
||||
item.dataset.id = cfg.id;
|
||||
|
||||
const name = document.createElement('span');
|
||||
name.className = 'config-name';
|
||||
name.textContent = cfg.name;
|
||||
|
||||
const proto = document.createElement('span');
|
||||
proto.className = 'config-proto ' + cfg.protocolType;
|
||||
proto.textContent = cfg.protocolType;
|
||||
|
||||
const menuBtn = document.createElement('button');
|
||||
menuBtn.className = 'config-menu-btn';
|
||||
menuBtn.textContent = '⋮';
|
||||
menuBtn.addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
openCtxMenu(cfg.id, menuBtn);
|
||||
});
|
||||
|
||||
item.appendChild(name);
|
||||
if (cfg.ping) {
|
||||
const pingBadge = document.createElement('span');
|
||||
pingBadge.className = 'config-ping';
|
||||
pingBadge.textContent = cfg.ping;
|
||||
pingBadge.style.borderColor = cfg.pingColor;
|
||||
pingBadge.style.color = cfg.pingColor;
|
||||
item.appendChild(pingBadge);
|
||||
}
|
||||
item.appendChild(proto);
|
||||
item.appendChild(menuBtn);
|
||||
|
||||
// Single click → select
|
||||
item.addEventListener('click', () => selectConfig(cfg.id));
|
||||
// Double click → connect
|
||||
item.addEventListener('dblclick', async () => {
|
||||
selectConfig(cfg.id);
|
||||
if (currentState === 'Connected' || currentState === 'Connecting') {
|
||||
await Disconnect();
|
||||
}
|
||||
Connect(cfg.id);
|
||||
});
|
||||
|
||||
configList.insertBefore(item, emptyState);
|
||||
}
|
||||
|
||||
updateStatusCard();
|
||||
}
|
||||
|
||||
function selectConfig(id) {
|
||||
selectedID = id;
|
||||
SetSelectedConfig(id);
|
||||
|
||||
configList.querySelectorAll('.config-item').forEach(el => {
|
||||
el.classList.toggle('selected', el.dataset.id === id);
|
||||
});
|
||||
|
||||
connectBtn.disabled = false;
|
||||
updateStatusCard();
|
||||
}
|
||||
|
||||
function updateStatusCard() {
|
||||
const cfg = configs.find(c => c.id === selectedID);
|
||||
if (!cfg) {
|
||||
selectedName.textContent = 'not selected';
|
||||
protoBadge.style.display = 'none';
|
||||
pingStatus.textContent = 'timeout';
|
||||
pingStatus.style.color = '#E53935';
|
||||
latencyStatus.textContent = '';
|
||||
return;
|
||||
}
|
||||
|
||||
selectedName.textContent = cfg.name;
|
||||
|
||||
if (currentState === 'Connected') {
|
||||
protoBadge.style.display = 'none';
|
||||
pingStatus.textContent = 'connected';
|
||||
pingStatus.style.color = '#4CAF50';
|
||||
} else {
|
||||
protoBadge.textContent = cfg.protocolType;
|
||||
protoBadge.className = 'proto-badge ' + cfg.protocolType;
|
||||
protoBadge.style.display = '';
|
||||
pingStatus.textContent = cfg.protocolType;
|
||||
pingStatus.style.color = '#666';
|
||||
latencyStatus.textContent = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Update just ping badge for one config (from ping-update event)
|
||||
function updatePingBadge(id, pingText, pingColor) {
|
||||
const cfg = configs.find(c => c.id === id);
|
||||
if (cfg) {
|
||||
cfg.ping = pingText;
|
||||
cfg.pingColor = pingColor;
|
||||
}
|
||||
|
||||
const item = configList.querySelector(`[data-id="${id}"]`);
|
||||
if (!item) return;
|
||||
|
||||
let badge = item.querySelector('.config-ping');
|
||||
if (!pingText) {
|
||||
if (badge) badge.remove();
|
||||
return;
|
||||
}
|
||||
if (!badge) {
|
||||
badge = document.createElement('span');
|
||||
badge.className = 'config-ping';
|
||||
const proto = item.querySelector('.config-proto');
|
||||
item.insertBefore(badge, proto);
|
||||
}
|
||||
badge.textContent = pingText;
|
||||
badge.style.borderColor = pingColor;
|
||||
badge.style.color = pingColor;
|
||||
}
|
||||
|
||||
// ── Context menu ──────────────────────────────────────────────────────────────
|
||||
function openCtxMenu(id, anchor) {
|
||||
ctxTargetID = id;
|
||||
ctxDelete.textContent = 'Delete';
|
||||
ctxDelete.className = 'ctx-item danger';
|
||||
if (deleteConfirmTimeout) { clearTimeout(deleteConfirmTimeout); deleteConfirmTimeout = null; }
|
||||
|
||||
ctxMenu.classList.remove('hidden');
|
||||
const rect = anchor.getBoundingClientRect();
|
||||
ctxMenu.style.top = rect.bottom + 4 + 'px';
|
||||
ctxMenu.style.left = Math.min(rect.left, window.innerWidth - 150) + 'px';
|
||||
}
|
||||
|
||||
function closeCtxMenu() {
|
||||
ctxMenu.classList.add('hidden');
|
||||
ctxTargetID = null;
|
||||
}
|
||||
|
||||
ctxCopyLink.addEventListener('click', () => {
|
||||
const cfg = configs.find(c => c.id === ctxTargetID);
|
||||
if (cfg) {
|
||||
navigator.clipboard.writeText(cfg.link);
|
||||
showToast('Link copied!', false);
|
||||
}
|
||||
closeCtxMenu();
|
||||
});
|
||||
|
||||
ctxDelete.addEventListener('click', () => {
|
||||
if (ctxDelete.textContent !== 'Are you sure?') {
|
||||
ctxDelete.textContent = 'Are you sure?';
|
||||
ctxDelete.className = 'ctx-item danger';
|
||||
deleteConfirmTimeout = setTimeout(() => {
|
||||
ctxDelete.textContent = 'Delete';
|
||||
deleteConfirmTimeout = null;
|
||||
}, 3000);
|
||||
return;
|
||||
}
|
||||
const id = ctxTargetID;
|
||||
closeCtxMenu();
|
||||
DeleteConfig(id);
|
||||
configs = configs.filter(c => c.id !== id);
|
||||
if (selectedID === id) {
|
||||
selectedID = configs.length > 0 ? configs[0].id : '';
|
||||
if (selectedID) SetSelectedConfig(selectedID);
|
||||
}
|
||||
renderConfigs();
|
||||
});
|
||||
|
||||
document.addEventListener('click', e => {
|
||||
if (!ctxMenu.contains(e.target)) closeCtxMenu();
|
||||
});
|
||||
|
||||
// ── Link input panel ──────────────────────────────────────────────────────────
|
||||
addLinkBtn.addEventListener('click', () => {
|
||||
linkPanelOpen = !linkPanelOpen;
|
||||
linkInputPanel.classList.toggle('hidden', !linkPanelOpen);
|
||||
if (linkPanelOpen) linkInputBox.focus();
|
||||
});
|
||||
|
||||
submitLinkBtn.addEventListener('click', submitLink);
|
||||
linkInputBox.addEventListener('keydown', e => { if (e.key === 'Enter') submitLink(); });
|
||||
|
||||
async function submitLink() {
|
||||
const link = linkInputBox.value.trim();
|
||||
if (!link) { showToast('Enter a link', true); return; }
|
||||
|
||||
const err = await AddConfig(link);
|
||||
if (err) { showToast(err, true); return; }
|
||||
|
||||
linkInputBox.value = '';
|
||||
linkPanelOpen = false;
|
||||
linkInputPanel.classList.add('hidden');
|
||||
|
||||
const fresh = await GetConfigs();
|
||||
configs = fresh;
|
||||
// Select newly added
|
||||
if (fresh.length > 0) selectConfig(fresh[fresh.length - 1].id);
|
||||
renderConfigs();
|
||||
showToast('Configuration added', false);
|
||||
}
|
||||
|
||||
addClipboardBtn.addEventListener('click', async () => {
|
||||
try {
|
||||
const text = await navigator.clipboard.readText();
|
||||
if (!text) { showToast('Clipboard is empty', true); return; }
|
||||
const err = await AddConfig(text.trim());
|
||||
if (err) { showToast(err, true); return; }
|
||||
|
||||
const fresh = await GetConfigs();
|
||||
configs = fresh;
|
||||
if (fresh.length > 0) selectConfig(fresh[fresh.length - 1].id);
|
||||
renderConfigs();
|
||||
showToast('Configuration added', false);
|
||||
} catch {
|
||||
showToast('Clipboard access denied', true);
|
||||
}
|
||||
});
|
||||
|
||||
// ── Connect / Disconnect ──────────────────────────────────────────────────────
|
||||
connectBtn.addEventListener('click', () => {
|
||||
if (!selectedID) return;
|
||||
Connect(selectedID);
|
||||
});
|
||||
|
||||
disconnectBtn.addEventListener('click', () => {
|
||||
Disconnect();
|
||||
});
|
||||
|
||||
// ── Ping all ──────────────────────────────────────────────────────────────────
|
||||
pingAllBtn.addEventListener('click', () => {
|
||||
pingAllBtn.disabled = true;
|
||||
PingAll();
|
||||
setTimeout(() => { pingAllBtn.disabled = false; }, 5000);
|
||||
});
|
||||
|
||||
// ── Log panel ─────────────────────────────────────────────────────────────────
|
||||
logBtn.addEventListener('click', () => {
|
||||
logExpanded = !logExpanded;
|
||||
logCol.classList.toggle('hidden', !logExpanded);
|
||||
applyWindowSize();
|
||||
});
|
||||
|
||||
copyLogsBtn.addEventListener('click', () => {
|
||||
navigator.clipboard.writeText(logArea.innerText);
|
||||
copyLogsBtn.textContent = 'Copied!';
|
||||
setTimeout(() => { copyLogsBtn.textContent = 'Copy'; }, 1500);
|
||||
});
|
||||
|
||||
clearLogsBtn.addEventListener('click', () => { logArea.innerHTML = ''; });
|
||||
|
||||
function appendLog(source, message) {
|
||||
const line = document.createElement('div');
|
||||
line.className = 'log-line';
|
||||
const isErr = /\bERROR\b|\bFATAL\b|\[ERR\]/.test(message) && !/\bINFO\b|\bWARN\b/.test(message);
|
||||
if (isErr) line.classList.add('err');
|
||||
const ts = new Date().toLocaleTimeString();
|
||||
line.textContent = `[${ts}] [${source}] ${message}`;
|
||||
logArea.appendChild(line);
|
||||
logArea.scrollTop = logArea.scrollHeight;
|
||||
}
|
||||
|
||||
// ── Settings panel ────────────────────────────────────────────────────────────
|
||||
settingsBtn.addEventListener('click', () => {
|
||||
settingsExpanded = !settingsExpanded;
|
||||
settingsPanel.classList.toggle('hidden', !settingsExpanded);
|
||||
settingsChevron.setAttribute('d', settingsExpanded ? 'M1,2 L6,7 L11,2' : 'M2,1 L7,6 L2,11');
|
||||
applyWindowSize();
|
||||
});
|
||||
|
||||
function saveSettings() {
|
||||
SaveSettings(runOnStartup.checked, autoConnect.checked, autoReconnect.checked);
|
||||
}
|
||||
runOnStartup.addEventListener('change', saveSettings);
|
||||
autoConnect.addEventListener('change', saveSettings);
|
||||
autoReconnect.addEventListener('change', saveSettings);
|
||||
|
||||
// ── Window controls ───────────────────────────────────────────────────────────
|
||||
minimizeBtn.addEventListener('click', () => HideWindow());
|
||||
exitBtn.addEventListener('click', () => Quit());
|
||||
|
||||
// ── Toast ─────────────────────────────────────────────────────────────────────
|
||||
let toastTimeout;
|
||||
function showToast(msg, isError) {
|
||||
clearTimeout(toastTimeout);
|
||||
toast.textContent = msg;
|
||||
toast.className = 'toast' + (isError ? '' : ' green');
|
||||
// force reflow
|
||||
toast.offsetHeight;
|
||||
toast.classList.add('show');
|
||||
toastTimeout = setTimeout(() => toast.classList.remove('show'), 3000);
|
||||
}
|
||||
|
||||
// ── Wails events ──────────────────────────────────────────────────────────────
|
||||
EventsOn('state-changed', state => {
|
||||
updateStateUI(state);
|
||||
updateStatusCard();
|
||||
});
|
||||
|
||||
EventsOn('log', (source, message) => {
|
||||
appendLog(source, message);
|
||||
});
|
||||
|
||||
EventsOn('ping-update', (id, pingText, pingColor) => {
|
||||
updatePingBadge(id, pingText, pingColor);
|
||||
if (id === selectedID) updateStatusCard();
|
||||
});
|
||||
|
||||
EventsOn('toast', (msg, isError) => showToast(msg, isError));
|
||||
|
||||
// ── Custom notifications ──────────────────────────────────────────────────────
|
||||
const notifStack = document.getElementById('notifStack');
|
||||
|
||||
function showNotification(message, dotColor) {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'notif-item';
|
||||
|
||||
const dot = document.createElement('span');
|
||||
dot.className = 'notif-dot';
|
||||
dot.style.background = dotColor;
|
||||
|
||||
const text = document.createElement('span');
|
||||
text.className = 'notif-text';
|
||||
text.textContent = message;
|
||||
|
||||
item.appendChild(dot);
|
||||
item.appendChild(text);
|
||||
notifStack.appendChild(item);
|
||||
|
||||
// Auto-dismiss after 4s
|
||||
setTimeout(() => {
|
||||
item.classList.add('out');
|
||||
item.addEventListener('animationend', () => item.remove());
|
||||
}, 4000);
|
||||
}
|
||||
|
||||
EventsOn('notification', (msg, dotColor) => showNotification(msg, dotColor));
|
||||
|
||||
// ── Init ──────────────────────────────────────────────────────────────────────
|
||||
async function init() {
|
||||
try {
|
||||
configs = await GetConfigs() || [];
|
||||
const state = await GetState();
|
||||
selectedID = await GetSelectedConfigID();
|
||||
|
||||
const settings = await GetSettings();
|
||||
runOnStartup.checked = settings.RunOnStartup;
|
||||
autoConnect.checked = settings.AutoConnect;
|
||||
autoReconnect.checked = settings.AutoReconnect;
|
||||
|
||||
renderConfigs();
|
||||
updateStateUI(state);
|
||||
} catch (e) {
|
||||
console.error('init error:', e);
|
||||
// Retry after a short delay
|
||||
setTimeout(init, 500);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for Wails runtime to be fully ready before calling Go bindings
|
||||
document.addEventListener('wails:loaded', () => init());
|
||||
// Fallback in case the event already fired
|
||||
if (window?.go?.main?.App?.GetConfigs) {
|
||||
init();
|
||||
}
|
||||
494
frontend/src/style.css
Normal file
494
frontend/src/style.css
Normal file
@@ -0,0 +1,494 @@
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
body {
|
||||
font-family: "Segoe UI", Inter, Roboto, sans-serif;
|
||||
background: #1e1e1e;
|
||||
color: #dedede;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
border: 1px solid #333;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Titlebar ── */
|
||||
.titlebar {
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 8px 0 15px;
|
||||
z-index: 100;
|
||||
background: transparent;
|
||||
--wails-draggable: drag;
|
||||
}
|
||||
.titlebar-title {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
pointer-events: none;
|
||||
}
|
||||
.titlebar-sub { font-weight: 400; }
|
||||
.titlebar-actions { display: flex; gap: 2px; --wails-draggable: no-drag; }
|
||||
|
||||
/* ── Main column ── */
|
||||
#mainCol {
|
||||
width: 360px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 40px 15px 15px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Status card ── */
|
||||
.status-card {
|
||||
background: #2b2b2b;
|
||||
border-radius: 8px;
|
||||
padding: 14px 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.status-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.state-dot {
|
||||
width: 14px; height: 14px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
.state-dot.disconnected { background: #E53935; }
|
||||
.state-dot.connecting { background: #FDD835; }
|
||||
.state-dot.connected { background: #4CAF50; }
|
||||
.state-dot.disconnecting{ background: #FDD835; }
|
||||
.state-dot.error { background: #b71c1c; }
|
||||
|
||||
.state-text {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
}
|
||||
.status-name {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #aaa;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
}
|
||||
.status-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
margin-top: 4px;
|
||||
min-height: 18px;
|
||||
}
|
||||
.ping-status {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
}
|
||||
.latency-status {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: #4CAF50;
|
||||
}
|
||||
.proto-badge {
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #888;
|
||||
color: #888;
|
||||
line-height: 1;
|
||||
}
|
||||
.proto-badge.VLESS { border-color: #00E676; color: #00E676; }
|
||||
.proto-badge.TROJAN { border-color: #00BFFF; color: #00BFFF; }
|
||||
|
||||
/* ── Section header ── */
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 5px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #555;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.header-actions { display: flex; gap: 2px; }
|
||||
|
||||
/* ── Link input panel ── */
|
||||
.link-input-panel {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
margin-bottom: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.link-input-panel.hidden { display: none; }
|
||||
.link-input-panel input {
|
||||
flex: 1;
|
||||
background: #222;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 6px 10px;
|
||||
color: #ccc;
|
||||
font-size: 12px;
|
||||
font-family: "Consolas", monospace;
|
||||
outline: none;
|
||||
}
|
||||
.add-btn {
|
||||
background: #4CAF50;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
width: 30px;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.15s;
|
||||
line-height: 1;
|
||||
}
|
||||
.add-btn:hover { opacity: 0.8; }
|
||||
|
||||
/* ── Config list ── */
|
||||
.config-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #555 transparent;
|
||||
min-height: 0;
|
||||
}
|
||||
.config-list::-webkit-scrollbar { width: 6px; }
|
||||
.config-list::-webkit-scrollbar-thumb { background: #555; border-radius: 3px; }
|
||||
.config-list::-webkit-scrollbar-track { background: transparent; }
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
color: #555;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.config-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.12s;
|
||||
}
|
||||
.config-item:hover { background: #2a2a2a; }
|
||||
.config-item.selected { background: #2f2f2f; }
|
||||
|
||||
.config-name {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #eee;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.config-ping {
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
padding: 2px 5px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.config-proto {
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #888;
|
||||
color: #888;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.config-proto.VLESS { border-color: #00E676; color: #00E676; }
|
||||
.config-proto.TROJAN { border-color: #00BFFF; color: #00BFFF; }
|
||||
|
||||
.config-menu-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #888;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
transition: background 0.12s, color 0.12s;
|
||||
}
|
||||
.config-menu-btn:hover { background: #333; color: #fff; }
|
||||
|
||||
/* ── Bottom bar ── */
|
||||
.bottom-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.bottom-left { display: flex; align-items: center; gap: 8px; }
|
||||
.bottom-right { display: flex; align-items: center; }
|
||||
|
||||
/* ── Buttons ── */
|
||||
.icon-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #777;
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background 0.12s, color 0.12s;
|
||||
line-height: 1;
|
||||
}
|
||||
.icon-btn:hover { background: #333; color: #fff; }
|
||||
.icon-btn.small { font-size: 11px; padding: 3px 7px; }
|
||||
|
||||
.solid-btn {
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
padding: 8px 15px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
.solid-btn:hover { opacity: 0.8; }
|
||||
.solid-btn:disabled{ opacity: 0.4; cursor: not-allowed; }
|
||||
.solid-btn.green { background: #4CAF50; }
|
||||
.solid-btn.red { background: #E53935; }
|
||||
.solid-btn.gray { background: #404040; }
|
||||
|
||||
.exit-btn {
|
||||
background: transparent;
|
||||
border: 1px solid #E53935;
|
||||
color: #E53935;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.exit-btn:hover { background: #E5393520; }
|
||||
|
||||
/* ── Settings panel ── */
|
||||
.settings-panel { flex-shrink: 0; margin-top: 15px; }
|
||||
.settings-panel.hidden { display: none; }
|
||||
|
||||
.settings-card {
|
||||
background: #2b2b2b;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
.toggle-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.toggle-row input[type="checkbox"] { display: none; }
|
||||
.toggle-wrap { flex-shrink: 0; }
|
||||
.toggle-track {
|
||||
display: block;
|
||||
width: 40px; height: 20px;
|
||||
background: #4d4d4d;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.toggle-knob {
|
||||
display: block;
|
||||
width: 16px; height: 16px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 2px; left: 2px;
|
||||
transition: left 0.2s;
|
||||
}
|
||||
input[type="checkbox"]:checked ~ .toggle-track { background: #4CAF50; }
|
||||
input[type="checkbox"]:checked ~ .toggle-track .toggle-knob { left: 22px; }
|
||||
.toggle-label { font-size: 13px; color: #dedede; }
|
||||
|
||||
/* ── Log sidebar ── */
|
||||
.log-col {
|
||||
width: 360px;
|
||||
flex-shrink: 0;
|
||||
border-left: 1px solid #333;
|
||||
background: #161616;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 40px 15px 15px;
|
||||
}
|
||||
.log-col.hidden { display: none; }
|
||||
|
||||
.log-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.log-area {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
font-family: "Consolas", "Courier New", monospace;
|
||||
font-size: 11px;
|
||||
line-height: 1.6;
|
||||
color: #a1e7b2;
|
||||
user-select: text;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #444 transparent;
|
||||
word-break: break-all;
|
||||
}
|
||||
.log-area::-webkit-scrollbar { width: 6px; }
|
||||
.log-area::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; }
|
||||
|
||||
.log-line { white-space: pre-wrap; }
|
||||
.log-line.err { color: #ef9a9a; }
|
||||
|
||||
/* ── Toast ── */
|
||||
.toast {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(-10px);
|
||||
background: #b71c1c;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
padding: 10px 16px;
|
||||
border-radius: 8px;
|
||||
z-index: 200;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s, transform 0.3s;
|
||||
white-space: nowrap;
|
||||
max-width: 300px;
|
||||
text-align: center;
|
||||
}
|
||||
.toast.show {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
.toast.green { background: #2e7d32; }
|
||||
|
||||
/* ── Context menu ── */
|
||||
.ctx-menu {
|
||||
position: fixed;
|
||||
background: #252525;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 6px;
|
||||
padding: 3px;
|
||||
z-index: 300;
|
||||
min-width: 130px;
|
||||
}
|
||||
.ctx-menu.hidden { display: none; }
|
||||
.ctx-item {
|
||||
padding: 6px 12px;
|
||||
font-size: 13px;
|
||||
color: #ddd;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.1s;
|
||||
}
|
||||
.ctx-item:hover { background: #3a3a3a; color: #fff; }
|
||||
.ctx-item.danger { color: #E53935; }
|
||||
.ctx-item.danger:hover { background: #3a1a1a; }
|
||||
.ctx-separator {
|
||||
height: 1px;
|
||||
background: #3a3a3a;
|
||||
margin: 3px 5px;
|
||||
}
|
||||
|
||||
/* ── Custom notifications ── */
|
||||
.notif-stack {
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
left: 16px;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
gap: 8px;
|
||||
z-index: 500;
|
||||
pointer-events: none;
|
||||
}
|
||||
.notif-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
background: #161b2e;
|
||||
border: 1px solid #252d45;
|
||||
border-radius: 10px;
|
||||
padding: 10px 18px;
|
||||
min-width: 200px;
|
||||
max-width: 320px;
|
||||
pointer-events: auto;
|
||||
opacity: 0;
|
||||
transform: translateY(12px);
|
||||
animation: notifIn 0.3s ease forwards;
|
||||
}
|
||||
.notif-item.out {
|
||||
animation: notifOut 0.3s ease forwards;
|
||||
}
|
||||
.notif-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.notif-text {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #e0e0e0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@keyframes notifIn {
|
||||
from { opacity: 0; transform: translateY(12px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
@keyframes notifOut {
|
||||
from { opacity: 1; transform: translateY(0); }
|
||||
to { opacity: 0; transform: translateY(-8px); }
|
||||
}
|
||||
11
frontend/vite.config.js
Normal file
11
frontend/vite.config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
emptyOutDir: true,
|
||||
rollupOptions: {
|
||||
input: 'index.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
30
frontend/wailsjs/go/main/App.d.ts
vendored
Normal file
30
frontend/wailsjs/go/main/App.d.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
import {main} from '../models';
|
||||
import {core} from '../models';
|
||||
|
||||
export function AddConfig(arg1:string):Promise<string>;
|
||||
|
||||
export function Connect(arg1:string):Promise<void>;
|
||||
|
||||
export function DeleteConfig(arg1:string):Promise<void>;
|
||||
|
||||
export function Disconnect():Promise<void>;
|
||||
|
||||
export function GetConfigs():Promise<Array<main.VpnConfigItem>>;
|
||||
|
||||
export function GetSelectedConfigID():Promise<string>;
|
||||
|
||||
export function GetSettings():Promise<core.AppSettings>;
|
||||
|
||||
export function GetState():Promise<string>;
|
||||
|
||||
export function HideWindow():Promise<void>;
|
||||
|
||||
export function PingAll():Promise<void>;
|
||||
|
||||
export function ResizeWindow(arg1:number,arg2:number):Promise<void>;
|
||||
|
||||
export function SaveSettings(arg1:boolean,arg2:boolean,arg3:boolean):Promise<void>;
|
||||
|
||||
export function SetSelectedConfig(arg1:string):Promise<void>;
|
||||
55
frontend/wailsjs/go/main/App.js
Normal file
55
frontend/wailsjs/go/main/App.js
Normal file
@@ -0,0 +1,55 @@
|
||||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export function AddConfig(arg1) {
|
||||
return window['go']['main']['App']['AddConfig'](arg1);
|
||||
}
|
||||
|
||||
export function Connect(arg1) {
|
||||
return window['go']['main']['App']['Connect'](arg1);
|
||||
}
|
||||
|
||||
export function DeleteConfig(arg1) {
|
||||
return window['go']['main']['App']['DeleteConfig'](arg1);
|
||||
}
|
||||
|
||||
export function Disconnect() {
|
||||
return window['go']['main']['App']['Disconnect']();
|
||||
}
|
||||
|
||||
export function GetConfigs() {
|
||||
return window['go']['main']['App']['GetConfigs']();
|
||||
}
|
||||
|
||||
export function GetSelectedConfigID() {
|
||||
return window['go']['main']['App']['GetSelectedConfigID']();
|
||||
}
|
||||
|
||||
export function GetSettings() {
|
||||
return window['go']['main']['App']['GetSettings']();
|
||||
}
|
||||
|
||||
export function GetState() {
|
||||
return window['go']['main']['App']['GetState']();
|
||||
}
|
||||
|
||||
export function HideWindow() {
|
||||
return window['go']['main']['App']['HideWindow']();
|
||||
}
|
||||
|
||||
export function PingAll() {
|
||||
return window['go']['main']['App']['PingAll']();
|
||||
}
|
||||
|
||||
export function ResizeWindow(arg1, arg2) {
|
||||
return window['go']['main']['App']['ResizeWindow'](arg1, arg2);
|
||||
}
|
||||
|
||||
export function SaveSettings(arg1, arg2, arg3) {
|
||||
return window['go']['main']['App']['SaveSettings'](arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
export function SetSelectedConfig(arg1) {
|
||||
return window['go']['main']['App']['SetSelectedConfig'](arg1);
|
||||
}
|
||||
50
frontend/wailsjs/go/models.ts
Normal file
50
frontend/wailsjs/go/models.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
export namespace core {
|
||||
|
||||
export class AppSettings {
|
||||
RunOnStartup: boolean;
|
||||
AutoConnect: boolean;
|
||||
AutoReconnect: boolean;
|
||||
LastConfigId?: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new AppSettings(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.RunOnStartup = source["RunOnStartup"];
|
||||
this.AutoConnect = source["AutoConnect"];
|
||||
this.AutoReconnect = source["AutoReconnect"];
|
||||
this.LastConfigId = source["LastConfigId"];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace main {
|
||||
|
||||
export class VpnConfigItem {
|
||||
id: string;
|
||||
name: string;
|
||||
link: string;
|
||||
protocolType: string;
|
||||
ping: string;
|
||||
pingColor: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new VpnConfigItem(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.id = source["id"];
|
||||
this.name = source["name"];
|
||||
this.link = source["link"];
|
||||
this.protocolType = source["protocolType"];
|
||||
this.ping = source["ping"];
|
||||
this.pingColor = source["pingColor"];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
24
frontend/wailsjs/runtime/package.json
Normal file
24
frontend/wailsjs/runtime/package.json
Normal file
@@ -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 <lea.anthony@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/wailsapp/wails/issues"
|
||||
},
|
||||
"homepage": "https://github.com/wailsapp/wails#readme"
|
||||
}
|
||||
330
frontend/wailsjs/runtime/runtime.d.ts
vendored
Normal file
330
frontend/wailsjs/runtime/runtime.d.ts
vendored
Normal file
@@ -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<boolean>;
|
||||
|
||||
// [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<Size>;
|
||||
|
||||
// [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<Position>;
|
||||
|
||||
// [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<boolean>;
|
||||
|
||||
// [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<boolean>;
|
||||
|
||||
// [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<boolean>;
|
||||
|
||||
// [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<Screen[]>;
|
||||
|
||||
// [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<EnvironmentInfo>;
|
||||
|
||||
// [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<string>;
|
||||
|
||||
// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext)
|
||||
// Sets a text on the clipboard
|
||||
export function ClipboardSetText(text: string): Promise<boolean>;
|
||||
|
||||
// [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<void>;
|
||||
|
||||
// [CleanupNotifications](https://wails.io/docs/reference/runtime/notification#cleanupnotifications)
|
||||
// Cleans up notification resources and releases any held connections.
|
||||
export function CleanupNotifications(): Promise<void>;
|
||||
|
||||
// [IsNotificationAvailable](https://wails.io/docs/reference/runtime/notification#isnotificationavailable)
|
||||
// Checks if notifications are available on the current platform.
|
||||
export function IsNotificationAvailable(): Promise<boolean>;
|
||||
|
||||
// [RequestNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#requestnotificationauthorization)
|
||||
// Requests notification authorization from the user (macOS only).
|
||||
export function RequestNotificationAuthorization(): Promise<boolean>;
|
||||
|
||||
// [CheckNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#checknotificationauthorization)
|
||||
// Checks the current notification authorization status (macOS only).
|
||||
export function CheckNotificationAuthorization(): Promise<boolean>;
|
||||
|
||||
// [SendNotification](https://wails.io/docs/reference/runtime/notification#sendnotification)
|
||||
// Sends a basic notification with the given options.
|
||||
export function SendNotification(options: NotificationOptions): Promise<void>;
|
||||
|
||||
// [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<void>;
|
||||
|
||||
// [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<void>;
|
||||
|
||||
// [RemoveNotificationCategory](https://wails.io/docs/reference/runtime/notification#removenotificationcategory)
|
||||
// Removes a previously registered notification category.
|
||||
export function RemoveNotificationCategory(categoryId: string): Promise<void>;
|
||||
|
||||
// [RemoveAllPendingNotifications](https://wails.io/docs/reference/runtime/notification#removeallpendingnotifications)
|
||||
// Removes all pending notifications from the notification center.
|
||||
export function RemoveAllPendingNotifications(): Promise<void>;
|
||||
|
||||
// [RemovePendingNotification](https://wails.io/docs/reference/runtime/notification#removependingnotification)
|
||||
// Removes a specific pending notification by its identifier.
|
||||
export function RemovePendingNotification(identifier: string): Promise<void>;
|
||||
|
||||
// [RemoveAllDeliveredNotifications](https://wails.io/docs/reference/runtime/notification#removealldeliverednotifications)
|
||||
// Removes all delivered notifications from the notification center.
|
||||
export function RemoveAllDeliveredNotifications(): Promise<void>;
|
||||
|
||||
// [RemoveDeliveredNotification](https://wails.io/docs/reference/runtime/notification#removedeliverednotification)
|
||||
// Removes a specific delivered notification by its identifier.
|
||||
export function RemoveDeliveredNotification(identifier: string): Promise<void>;
|
||||
|
||||
// [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<void>;
|
||||
298
frontend/wailsjs/runtime/runtime.js
Normal file
298
frontend/wailsjs/runtime/runtime.js
Normal file
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user