- 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
197 lines
6.3 KiB
HTML
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>
|