MP-Server/web_templates.py
Josh Knapp 9f3484dff2 Big Update
This update will need to get cleaned up, but for right now we are doing testing.
2025-06-01 12:38:41 -07:00

292 lines
6.2 KiB
Python

# HTML templates for the web interface
INDEX_HTML = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MacroPad Web Interface</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #2e2e2e;
color: #ffffff;
}
.header-container {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
h1 {
color: #007acc;
margin: 0;
}
.refresh-button {
background-color: #505050;
color: white;
border: none;
border-radius: 8px;
padding: 10px 15px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s;
display: flex;
align-items: center;
}
.refresh-button:hover {
background-color: #007acc;
}
.refresh-button svg {
margin-right: 5px;
}
.tab-container {
margin-bottom: 20px;
border-bottom: 2px solid #404040;
}
.tab-list {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin-bottom: 0;
}
.tab-button {
background-color: #404040;
color: #ffffff;
border: none;
border-radius: 8px 8px 0 0;
padding: 10px 15px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.3s;
border-bottom: 3px solid transparent;
}
.tab-button:hover {
background-color: #505050;
}
.tab-button.active {
background-color: #007acc;
border-bottom-color: #007acc;
}
.macro-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 15px;
margin-top: 20px;
}
.macro-button {
background-color: #505050;
color: white;
border: none;
border-radius: 8px;
padding: 15px 10px;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100px;
}
.macro-button:hover, .macro-button:active {
background-color: #007acc;
}
.macro-button img {
max-width: 64px;
max-height: 64px;
margin-bottom: 10px;
}
.status {
text-align: center;
margin: 20px 0;
padding: 10px;
border-radius: 5px;
}
.success {
background-color: #4CAF50;
color: white;
display: none;
}
.error {
background-color: #f44336;
color: white;
display: none;
}
@media (max-width: 600px) {
.macro-grid {
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}
.macro-button {
padding: 10px 5px;
font-size: 14px;
}
h1 {
font-size: 24px;
}
.refresh-button {
padding: 8px 12px;
font-size: 14px;
}
.tab-button {
padding: 8px 12px;
font-size: 12px;
}
}
</style>
</head>
<body>
<div class="header-container">
<h1>MacroPad Web Interface</h1>
<button class="refresh-button" onclick="loadTabs()">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/>
<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/>
</svg>
Refresh
</button>
</div>
<div class="status success" id="success-status">Macro executed successfully!</div>
<div class="status error" id="error-status">Failed to execute macro</div>
<div class="tab-container">
<div class="tab-list" id="tab-list">
<!-- Tabs will be loaded here -->
</div>
</div>
<div class="macro-grid" id="macro-grid">
<!-- Macros will be loaded here -->
</div>
<script>
let currentTab = 'All';
let allMacros = {};
document.addEventListener('DOMContentLoaded', function() {
loadTabs();
});
function loadTabs() {
fetch('/api/tabs')
.then(response => response.json())
.then(tabs => {
const tabList = document.getElementById('tab-list');
tabList.innerHTML = '';
tabs.forEach(tab => {
const button = document.createElement('button');
button.className = 'tab-button';
button.textContent = tab;
button.onclick = function() { switchTab(tab); };
if (tab === currentTab) {
button.classList.add('active');
}
tabList.appendChild(button);
});
// Load macros for current tab
loadMacros(currentTab);
})
.catch(error => {
console.error('Error loading tabs:', error);
});
}
function switchTab(tabName) {
currentTab = tabName;
// Update tab button states
const tabButtons = document.querySelectorAll('.tab-button');
tabButtons.forEach(button => {
button.classList.remove('active');
if (button.textContent === tabName) {
button.classList.add('active');
}
});
// Load macros for selected tab
loadMacros(tabName);
}
function loadMacros(tab = 'All') {
const url = tab === 'All' ? '/api/macros' : `/api/macros/${encodeURIComponent(tab)}`;
fetch(url)
.then(response => response.json())
.then(macros => {
allMacros = macros;
displayMacros(macros);
})
.catch(error => {
console.error('Error loading macros:', error);
});
}
function displayMacros(macros) {
const macroGrid = document.getElementById('macro-grid');
macroGrid.innerHTML = '';
if (Object.keys(macros).length === 0) {
macroGrid.innerHTML = '<p style="grid-column: 1 / -1; text-align: center;">No macros in this category.</p>';
return;
}
for (const [macroId, macro] of Object.entries(macros)) {
const button = document.createElement('button');
button.className = 'macro-button';
button.onclick = function() { executeMacro(macroId); };
// Add image if available
if (macro.image_path) {
const img = document.createElement('img');
img.src = `/api/image/${encodeURIComponent(macro.image_path)}`;
img.alt = macro.name;
img.onerror = function() {
this.style.display = 'none';
};
button.appendChild(img);
}
const text = document.createTextNode(macro.name);
button.appendChild(text);
macroGrid.appendChild(button);
}
}
function executeMacro(macroId) {
fetch('/api/execute', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ macro_id: macroId })
})
.then(response => response.json())
.then(data => {
const successStatus = document.getElementById('success-status');
const errorStatus = document.getElementById('error-status');
if (data.success) {
successStatus.style.display = 'block';
errorStatus.style.display = 'none';
setTimeout(() => { successStatus.style.display = 'none'; }, 2000);
} else {
errorStatus.style.display = 'block';
successStatus.style.display = 'none';
setTimeout(() => { errorStatus.style.display = 'none'; }, 2000);
}
})
.catch(error => {
console.error('Error executing macro:', error);
const errorStatus = document.getElementById('error-status');
errorStatus.style.display = 'block';
setTimeout(() => { errorStatus.style.display = 'none'; }, 2000);
});
}
</script>
</body>
</html>
'''