diff options
Diffstat (limited to 'static')
| -rw-r--r-- | static/css/styles.css | 120 | ||||
| -rw-r--r-- | static/js/app.js | 135 |
2 files changed, 255 insertions, 0 deletions
diff --git a/static/css/styles.css b/static/css/styles.css new file mode 100644 index 0000000..9c26cab --- /dev/null +++ b/static/css/styles.css @@ -0,0 +1,120 @@ +:root { + --light-white: #FFFFFF; + --dark-white: #EFFFFF; + --light-black: #181818; + --dark-black: #000000; + + --light-green: #27AE60; + --dark-green: #27AE60; + --light-yellow: #F1C40F; + --dark-yellow: #F1C40F; + --light-red: #E74C3C; + --dark-red: #E74C3C; +} + +html { + background-color: var(--light-black); +} + +@media (prefers-color-scheme: light) { + html { + background-color: var(--light-white); + } + .message.loading, + .message.warning { + border-color: var(--light-yellow); + } + .message.success { + border-color: var(--light-green); + } + .message.error { + border-color: var(--light-red); + } + .connection.loading { + border-color: var(--light-yellow); + } + + .connection.active { + border-color: var(--light-green); + } +} + +body { + font-family: "PT Sans", "Kohinoor Bangla", sans-serif; + max-width: 1024px; + min-width: 375px; + margin: 0 auto; + float: none; + font-size: 18px; +} + +header { + text-align: center; + font-style: normal; + .header__title { + font-size: 32px; + margin-bottom: -16px; + margin-top: 36px; + clear: right; + } +} + +main { + margin: 32px; +} + +.status { + min-height: 160px; +} + +.status__header, +.connections__header { +} + +.message { + font-family: monospace; + font-size: 14px; + line-height: 1.5; + border-style: solid; + border-width: 1px; + border-left-width: 14px; + padding: 14px; + white-space: pre-line; +} + +.message.loading, +.message.warning { + border-color: var(--dark-yellow); +} +.message.success { + border-color: var(--dark-green); +} +.message.error { + border-color: var(--dark-red); +} + +.connections__container { + width: 100%; +} +.connection { + font-family: monospace; + font-size: 14px; + cursor: pointer; + border: 1px solid; + padding: 1rem; + margin-top: 1rem; + margin-bottom: 1rem; +} +.connection.loading { + border-left-width: 14px; + border-color: var(--dark-yellow); +} + +.connection.active { + border-left-width: 14px; + border-color: var(--dark-green); +} + +footer { + margin: 32px; +} diff --git a/static/js/app.js b/static/js/app.js new file mode 100644 index 0000000..db8ed8a --- /dev/null +++ b/static/js/app.js @@ -0,0 +1,135 @@ +// Application state and configuration +const App = { + apiBase: "/api", + elements: { + connectionList: document.getElementById('connections__container'), + statusArea: document.getElementById('status__container'), + messageArea: document.getElementById('notifications__container') + } +}; + +// Utility functions +const Utils = { + // Show message to user + renderError(element, message) { + Utils.renderMessage(element, message, "error"); + }, + renderWarning(element, message) { + Utils.renderMessage(element, message, "warning"); + }, + renderSuccess(element, message) { + Utils.renderMessage(element, message, "success"); + }, + renderMessage(element, message, type = '') { + element.innerHTML = ` + <div class="message ${type}">${message}</div> + `; + }, + // Make API calls with proper error handling + async apiCall(endpoint, options = {}) { + try { + const response = await fetch(`${App.apiBase}${endpoint}`, { + headers: { + 'Content-Type': 'application/json', + ...options.headers + }, + ...options + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.error || `HTTP ${response.status}`); + } + + if (!data.success) { + throw new Error(data.error || 'API request failed'); + } + + return data.data; + } catch (error) { + console.error('API call failed:', error); + throw error; + } + } +}; + +// Connection management +const ConnectionManager = { + // Load and display all connections + async loadConnections() { + try { + const connections = await Utils.apiCall('/connections'); + this.renderConnections(connections); + } catch (error) { + Utils.renderError(App.elements.connectionList, + `Failed to load connections: ${error.message}`); + } + }, + + // Render connections to the DOM + renderConnections(connections) { + if (!connections || connections.length === 0) { + Utils.renderWarning(App.elements.connectionList, + "No WireGuard connections found in /etc/wireguard/"); + return; + } + + const html = connections.map(conn => ` + <div class="connection ${conn.active ? 'active' : ''}" + data-connection="${conn.name}" + onclick="ConnectionManager.toggleConnection('${conn.name}')"> + <div class="connection__name ${conn.active ? 'active' : ''}">${conn.name}</div> + </div> + `).join(''); + App.elements.connectionList.innerHTML = html; + }, + + // Toggle connection state + async toggleConnection(name) { + const connection = document.querySelector(`[data-connection="${name}"]`); + + try { + connection.disabled = true; + connection.textContent = 'Processing...'; + connection.className = "connection loading" + + await Utils.apiCall('/connections/toggle', { + method: 'POST', + body: JSON.stringify({ name }) + }); + await this.loadConnections(); // Refresh the list + await StatusManager.loadStatus(); // Refresh the status + Utils.renderSuccess(App.elements.messageArea, `No Errors Found.`); + } catch (error) { + Utils.renderError(App.elements.messageArea, `Failed to toggle ${name}: ${error.message}`); + connection.disabled = false; + connection.textContent = name; + connection.className = "connection" + } + } +}; + +// Status management +const StatusManager = { + // Load and display WireGuard status + async loadStatus() { + try { + const statusData = await Utils.apiCall('/status'); + const statusText = statusData.status; + if (statusText) { + Utils.renderSuccess(App.elements.statusArea, statusText); + } else { + Utils.renderWarning(App.elements.statusArea, "No active connections."); + } + } catch (error) { + Utils.renderError(App.elements.statusArea, error.message); + } + }, +}; + +// Initialize the application +document.addEventListener('DOMContentLoaded', () => { + StatusManager.loadStatus(); + ConnectionManager.loadConnections(); +}); |
