beatmatchr/Desktop/YabaiPro/rule-editor.html
BusyBee3333 7694d965c9 feat: Add structured signal editor with app dropdown and action builder
- Add AppDiscovery provider for running app enumeration
- Implement AppDropdownView with auto-launch functionality
- Create SignalAction models for 40+ yabai commands
- Build ActionBuilderView with nested parameter controls
- Add LiveShellPreview for real-time shell command generation
- Implement ActionValidator for conflict detection
- Add migration parser for existing raw action strings
- Include feature flag for safe rollout
- Maintain full backward compatibility
2025-12-31 01:44:13 -05:00

197 lines
6.3 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 20px;
background: #f5f5f7;
color: #333;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: 500;
}
input, select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
box-sizing: border-box;
}
input:focus, select:focus {
outline: none;
border-color: #007aff;
box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.2);
}
.checkbox-group {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.checkbox-group input[type="checkbox"] {
width: auto;
margin-right: 8px;
}
.button-group {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 20px;
}
button {
padding: 8px 16px;
border: none;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
}
.save-btn {
background: #007aff;
color: white;
}
.cancel-btn {
background: #f5f5f5;
color: #333;
border: 1px solid #ddd;
}
button:hover {
opacity: 0.9;
}
.section {
background: white;
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
h3 {
margin-top: 0;
margin-bottom: 10px;
color: #666;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
</style>
</head>
<body>
<div class="section">
<h3>Matching Criteria</h3>
<div class="form-group">
<label for="app">Application:</label>
<input type="text" id="app" placeholder="e.g., Safari, Chrome">
</div>
<div class="form-group">
<label for="title">Window Title:</label>
<input type="text" id="title" placeholder="e.g., contains text">
</div>
<div class="form-group">
<label for="role">Role:</label>
<select id="role">
<option value="">Any</option>
<option value="AXWindow">Window</option>
<option value="AXDialog">Dialog</option>
<option value="AXSheet">Sheet</option>
</select>
</div>
<div class="form-group">
<label for="subrole">Subrole:</label>
<select id="subrole">
<option value="">Any</option>
<option value="AXStandardWindow">Standard Window</option>
<option value="AXDialog">Dialog</option>
<option value="AXSystemDialog">System Dialog</option>
</select>
</div>
</div>
<div class="section">
<h3>Actions</h3>
<div class="checkbox-group">
<input type="checkbox" id="manage" checked>
<label for="manage">Manage window</label>
</div>
<div class="checkbox-group">
<input type="checkbox" id="sticky">
<label for="sticky">Sticky window</label>
</div>
<div class="checkbox-group">
<input type="checkbox" id="mouse_follows_focus">
<label for="mouse_follows_focus">Mouse follows focus</label>
</div>
<div class="form-group">
<label for="layer">Layer:</label>
<select id="layer">
<option value="below">Below</option>
<option value="normal">Normal</option>
<option value="above">Above</option>
</select>
</div>
<div class="form-group">
<label for="opacity">Opacity:</label>
<input type="number" id="opacity" min="0.0" max="1.0" step="0.1" value="1.0">
</div>
<div class="checkbox-group">
<input type="checkbox" id="border">
<label for="border">Show border</label>
</div>
</div>
<div class="button-group">
<button class="cancel-btn" onclick="cancelRule()">Cancel</button>
<button class="save-btn" onclick="saveRule()">Create Rule</button>
</div>
<script>
// Focus first input field on load
document.getElementById('app').focus();
// Load existing rule data if editing
window.onload = function() {
// This would be populated with existing rule data
console.log('Rule editor loaded');
};
function saveRule() {
const rule = {
app: document.getElementById('app').value || null,
title: document.getElementById('title').value || null,
role: document.getElementById('role').value || null,
subrole: document.getElementById('subrole').value || null,
manage: document.getElementById('manage').checked,
sticky: document.getElementById('sticky').checked,
mouse_follows_focus: document.getElementById('mouse_follows_focus').checked,
layer: document.getElementById('layer').value,
opacity: parseFloat(document.getElementById('opacity').value),
border: document.getElementById('border').checked
};
// Send to native app
window.webkit.messageHandlers.saveRule.postMessage(rule);
}
function cancelRule() {
window.webkit.messageHandlers.cancelRule.postMessage({});
}
// Handle Enter key in inputs
document.addEventListener('keydown', function(e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
saveRule();
} else if (e.key === 'Escape') {
e.preventDefault();
cancelRule();
}
});
</script>
</body>
</html>