Designer and editor magic button UI, tasks UI improvements
This commit is contained in:
parent
d96c546c6a
commit
3f95c4645d
7 changed files with 490 additions and 183 deletions
|
|
@ -97,6 +97,146 @@
|
||||||
transition: all 0.15s;
|
transition: all 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbar-btn.magic {
|
||||||
|
background: linear-gradient(135deg, var(--accent-purple), var(--accent-blue));
|
||||||
|
border-color: var(--accent-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-btn.magic:hover {
|
||||||
|
background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple));
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-panel {
|
||||||
|
position: fixed;
|
||||||
|
right: 20px;
|
||||||
|
bottom: 60px;
|
||||||
|
width: 380px;
|
||||||
|
max-height: 500px;
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
|
||||||
|
z-index: 1000;
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-panel.visible {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-header {
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
background: linear-gradient(135deg, rgba(203,166,247,0.1), rgba(137,180,250,0.1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-header svg {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
color: var(--accent-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-header h3 {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-close {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-close:hover {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-loading {
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-loading .spinner {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border: 3px solid var(--border-color);
|
||||||
|
border-top-color: var(--accent-purple);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
margin: 0 auto 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-suggestion {
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-suggestion-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-suggestion-icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-suggestion-icon.ux { background: rgba(166,227,161,0.2); color: var(--accent-green); }
|
||||||
|
.magic-suggestion-icon.perf { background: rgba(249,226,175,0.2); color: var(--accent-yellow); }
|
||||||
|
.magic-suggestion-icon.a11y { background: rgba(137,180,250,0.2); color: var(--accent-blue); }
|
||||||
|
.magic-suggestion-icon.feature { background: rgba(203,166,247,0.2); color: var(--accent-purple); }
|
||||||
|
|
||||||
|
.magic-suggestion-title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-suggestion-desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-suggestion-apply {
|
||||||
|
margin-top: 10px;
|
||||||
|
background: var(--accent-purple);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-suggestion-apply:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
.toolbar-btn:hover {
|
.toolbar-btn:hover {
|
||||||
background: var(--border-color);
|
background: var(--border-color);
|
||||||
}
|
}
|
||||||
|
|
@ -845,6 +985,17 @@
|
||||||
</svg>
|
</svg>
|
||||||
Export
|
Export
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<div class="toolbar-separator"></div>
|
||||||
|
|
||||||
|
<button class="toolbar-btn magic" id="btn-magic"
|
||||||
|
onclick="showMagicPanel()"
|
||||||
|
title="AI Improvements (Ctrl+M)">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"/>
|
||||||
|
</svg>
|
||||||
|
Magic
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -1111,6 +1262,28 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Magic AI Panel -->
|
||||||
|
<div class="magic-panel" id="magic-panel">
|
||||||
|
<div class="magic-header">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"/>
|
||||||
|
</svg>
|
||||||
|
<h3>AI Improvements</h3>
|
||||||
|
<button class="magic-close" onclick="hideMagicPanel()">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
|
||||||
|
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||||
|
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="magic-content" id="magic-content">
|
||||||
|
<div class="magic-loading">
|
||||||
|
<div class="spinner"></div>
|
||||||
|
<p>Analyzing your dialog...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Properties Panel -->
|
<!-- Properties Panel -->
|
||||||
<aside class="properties-panel" id="properties-panel">
|
<aside class="properties-panel" id="properties-panel">
|
||||||
<div class="properties-header">
|
<div class="properties-header">
|
||||||
|
|
@ -2126,6 +2299,122 @@
|
||||||
document.getElementById('selected-file').value = fileItem.dataset.path;
|
document.getElementById('selected-file').value = fileItem.dataset.path;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function showMagicPanel() {
|
||||||
|
const panel = document.getElementById('magic-panel');
|
||||||
|
panel.classList.add('visible');
|
||||||
|
analyzeMagicSuggestions();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideMagicPanel() {
|
||||||
|
document.getElementById('magic-panel').classList.remove('visible');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function analyzeMagicSuggestions() {
|
||||||
|
const content = document.getElementById('magic-content');
|
||||||
|
content.innerHTML = '<div class="magic-loading"><div class="spinner"></div><p>Analyzing your dialog...</p></div>';
|
||||||
|
|
||||||
|
const nodes = Array.from(state.nodes.values());
|
||||||
|
const dialogData = {
|
||||||
|
nodes: nodes.map(n => ({ type: n.type, fields: n.fields })),
|
||||||
|
connections: state.connections.length,
|
||||||
|
filename: document.getElementById('current-filename').value || 'untitled'
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/v1/designer/magic', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(dialogData)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const suggestions = await response.json();
|
||||||
|
renderMagicSuggestions(suggestions);
|
||||||
|
} else {
|
||||||
|
renderFallbackSuggestions(dialogData);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
renderFallbackSuggestions(dialogData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderFallbackSuggestions(dialogData) {
|
||||||
|
const suggestions = [];
|
||||||
|
const nodes = dialogData.nodes;
|
||||||
|
|
||||||
|
if (!nodes.some(n => n.type === 'HEAR')) {
|
||||||
|
suggestions.push({
|
||||||
|
type: 'ux',
|
||||||
|
title: 'Add User Input',
|
||||||
|
description: 'Your dialog has no HEAR nodes. Consider adding user input to make it interactive.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodes.filter(n => n.type === 'TALK').length > 5) {
|
||||||
|
suggestions.push({
|
||||||
|
type: 'ux',
|
||||||
|
title: 'Break Up Long Responses',
|
||||||
|
description: 'You have many TALK nodes. Consider grouping related messages or using a menu.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nodes.some(n => n.type === 'IF' || n.type === 'SWITCH')) {
|
||||||
|
suggestions.push({
|
||||||
|
type: 'feature',
|
||||||
|
title: 'Add Decision Logic',
|
||||||
|
description: 'Add IF or SWITCH nodes to handle different user responses dynamically.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogData.connections < nodes.length - 1 && nodes.length > 1) {
|
||||||
|
suggestions.push({
|
||||||
|
type: 'perf',
|
||||||
|
title: 'Check Connections',
|
||||||
|
description: 'Some nodes may not be connected. Ensure all nodes flow properly.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestions.push({
|
||||||
|
type: 'a11y',
|
||||||
|
title: 'Use Clear Language',
|
||||||
|
description: 'Keep messages short and clear. Avoid jargon for better accessibility.'
|
||||||
|
});
|
||||||
|
|
||||||
|
renderMagicSuggestions(suggestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderMagicSuggestions(suggestions) {
|
||||||
|
const content = document.getElementById('magic-content');
|
||||||
|
if (!suggestions || suggestions.length === 0) {
|
||||||
|
content.innerHTML = '<p style="text-align:center;color:var(--text-secondary);padding:40px;">Your dialog looks great! No suggestions at this time.</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const icons = {
|
||||||
|
ux: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>',
|
||||||
|
perf: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>',
|
||||||
|
a11y: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>',
|
||||||
|
feature: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"/></svg>'
|
||||||
|
};
|
||||||
|
|
||||||
|
content.innerHTML = suggestions.map(s => `
|
||||||
|
<div class="magic-suggestion">
|
||||||
|
<div class="magic-suggestion-header">
|
||||||
|
<div class="magic-suggestion-icon ${s.type}">${icons[s.type] || icons.feature}</div>
|
||||||
|
<span class="magic-suggestion-title">${s.title}</span>
|
||||||
|
</div>
|
||||||
|
<p class="magic-suggestion-desc">${s.description}</p>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.ctrlKey && e.key === 'm') {
|
||||||
|
e.preventDefault();
|
||||||
|
showMagicPanel();
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,98 @@
|
||||||
background: var(--accent-hover);
|
background: var(--accent-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-magic {
|
||||||
|
background: linear-gradient(135deg, #8b5cf6, #3b82f6);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-magic:hover {
|
||||||
|
background: linear-gradient(135deg, #3b82f6, #8b5cf6);
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-panel {
|
||||||
|
position: fixed;
|
||||||
|
right: 20px;
|
||||||
|
bottom: 60px;
|
||||||
|
width: 400px;
|
||||||
|
max-height: 500px;
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
|
||||||
|
z-index: 1000;
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-panel.visible {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-header {
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background: linear-gradient(135deg, rgba(139,92,246,0.1), rgba(59,130,246,0.1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-header h3 {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-close {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-loading {
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-result {
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-result pre {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.magic-apply-btn {
|
||||||
|
background: var(--success);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-small {
|
.btn-small {
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
@ -379,6 +471,12 @@
|
||||||
hx-swap="innerHTML">
|
hx-swap="innerHTML">
|
||||||
{ } Format
|
{ } Format
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn btn-small btn-magic"
|
||||||
|
onclick="showMagicPanel()"
|
||||||
|
title="AI Improvements (Ctrl+M)">
|
||||||
|
✨ Magic
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="toolbar-group" id="csv-tools" style="display: none;">
|
<div class="toolbar-group" id="csv-tools" style="display: none;">
|
||||||
|
|
@ -399,6 +497,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Magic AI Panel -->
|
||||||
|
<div class="magic-panel" id="magic-panel">
|
||||||
|
<div class="magic-header">
|
||||||
|
<h3>✨ AI Improvements</h3>
|
||||||
|
<button class="magic-close" onclick="hideMagicPanel()">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="magic-content" id="magic-content">
|
||||||
|
<div class="magic-loading">Analyzing code...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Editor Content - loaded via HTMX based on file type -->
|
<!-- Editor Content - loaded via HTMX based on file type -->
|
||||||
<div class="editor-content" id="editor-content">
|
<div class="editor-content" id="editor-content">
|
||||||
<!-- Text Editor (default) -->
|
<!-- Text Editor (default) -->
|
||||||
|
|
@ -514,6 +623,87 @@
|
||||||
htmx.trigger(document.querySelector('[hx-post="/api/v1/editor/save"]'), 'click');
|
htmx.trigger(document.querySelector('[hx-post="/api/v1/editor/save"]'), 'click');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
function showMagicPanel() {
|
||||||
|
document.getElementById('magic-panel').classList.add('visible');
|
||||||
|
runMagicAnalysis();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideMagicPanel() {
|
||||||
|
document.getElementById('magic-panel').classList.remove('visible');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runMagicAnalysis() {
|
||||||
|
const content = document.getElementById('magic-content');
|
||||||
|
const code = document.getElementById('text-editor').value;
|
||||||
|
|
||||||
|
if (!code.trim()) {
|
||||||
|
content.innerHTML = '<p style="color:var(--text-secondary);text-align:center;padding:40px;">No code to analyze. Start typing or open a file.</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
content.innerHTML = '<div class="magic-loading">✨ Analyzing your code...</div>';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/v1/editor/magic', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ code: code })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const result = await response.json();
|
||||||
|
renderMagicResult(result);
|
||||||
|
} else {
|
||||||
|
content.innerHTML = '<p style="color:var(--error);padding:20px;">Failed to analyze. Try again.</p>';
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
content.innerHTML = '<p style="color:var(--error);padding:20px;">Error connecting to AI service.</p>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderMagicResult(result) {
|
||||||
|
const content = document.getElementById('magic-content');
|
||||||
|
if (result.improved_code) {
|
||||||
|
content.innerHTML = `
|
||||||
|
<div class="magic-result">
|
||||||
|
<p><strong>Suggested improvements:</strong></p>
|
||||||
|
<p style="color:var(--text-secondary);margin:8px 0;">${result.explanation || 'Improved code structure and patterns.'}</p>
|
||||||
|
<pre>${escapeHtml(result.improved_code)}</pre>
|
||||||
|
<button class="magic-apply-btn" onclick="applyMagicCode()">Apply Changes</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
window.magicImprovedCode = result.improved_code;
|
||||||
|
} else if (result.suggestions) {
|
||||||
|
content.innerHTML = result.suggestions.map(s => `
|
||||||
|
<div class="magic-result">
|
||||||
|
<p><strong>${s.title}</strong></p>
|
||||||
|
<p style="color:var(--text-secondary);">${s.description}</p>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
} else {
|
||||||
|
content.innerHTML = '<p style="padding:20px;">Your code looks good! No suggestions at this time.</p>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyMagicCode() {
|
||||||
|
if (window.magicImprovedCode) {
|
||||||
|
document.getElementById('text-editor').value = window.magicImprovedCode;
|
||||||
|
hideMagicPanel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(text) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.textContent = text;
|
||||||
|
return div.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.ctrlKey && e.key === 'm') {
|
||||||
|
e.preventDefault();
|
||||||
|
showMagicPanel();
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
background: linear-gradient(135deg, #f59e0b, #d97706);
|
background: #f59e0b;
|
||||||
color: #000;
|
color: #000;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
|
|
@ -107,7 +107,7 @@
|
||||||
============================================================================= */
|
============================================================================= */
|
||||||
|
|
||||||
.intent-section {
|
.intent-section {
|
||||||
background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(168, 85, 247, 0.1));
|
background: rgba(99, 102, 241, 0.1);
|
||||||
border: 1px solid rgba(99, 102, 241, 0.2);
|
border: 1px solid rgba(99, 102, 241, 0.2);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
|
|
@ -201,7 +201,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 12px 24px;
|
padding: 12px 24px;
|
||||||
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
background: #6366f1;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
|
|
@ -698,7 +698,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: linear-gradient(135deg, #22c55e, #16a34a);
|
background: #22c55e;
|
||||||
border: none;
|
border: none;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
@ -1012,7 +1012,7 @@
|
||||||
|
|
||||||
.progress-fill {
|
.progress-fill {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: linear-gradient(90deg, #6366f1, #8b5cf6);
|
background: #6366f1;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
transition: width 0.3s ease;
|
transition: width 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
<span class="section-icon">💡</span>
|
<span class="section-icon">💡</span>
|
||||||
<h2>What would you like to accomplish?</h2>
|
<h2>What would you like to accomplish?</h2>
|
||||||
</div>
|
</div>
|
||||||
<form class="intent-form" id="intent-form" hx-post="/api/autotask/create" hx-target="#compilation-result" hx-indicator="#compile-spinner">
|
<form class="intent-form" id="intent-form" hx-post="/api/autotask/create" hx-ext="json-enc" hx-target="#compilation-result" hx-indicator="#compile-spinner">
|
||||||
<div class="intent-input-wrapper">
|
<div class="intent-input-wrapper">
|
||||||
<textarea
|
<textarea
|
||||||
name="intent"
|
name="intent"
|
||||||
|
|
|
||||||
|
|
@ -57,20 +57,7 @@
|
||||||
</svg>
|
</svg>
|
||||||
<span class="notification-count">3</span>
|
<span class="notification-count">3</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn-new-intent">
|
|
||||||
<svg
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
>
|
|
||||||
<line x1="12" y1="5" x2="12" y2="19" />
|
|
||||||
<line x1="5" y1="12" x2="19" y2="12" />
|
|
||||||
</svg>
|
|
||||||
New Intent
|
|
||||||
</button>
|
|
||||||
<button class="icon-button" title="Settings">
|
<button class="icon-button" title="Settings">
|
||||||
<svg
|
<svg
|
||||||
width="18"
|
width="18"
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
.intent-input-section {
|
.intent-input-section {
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
background: linear-gradient(135deg, var(--primary) 0%, #764ba2 100%);
|
background: var(--surface);
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -392,7 +392,7 @@
|
||||||
.topbar-avatar {
|
.topbar-avatar {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
background: linear-gradient(135deg, var(--primary), #a5d622);
|
background: var(--primary);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -1306,7 +1306,7 @@
|
||||||
|
|
||||||
.goal-progress-fill {
|
.goal-progress-fill {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: linear-gradient(90deg, var(--primary), var(--success));
|
background: var(--primary);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
transition: width 0.5s ease;
|
transition: width 0.5s ease;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
id="quick-intent-btn"
|
id="quick-intent-btn"
|
||||||
class="btn-create-run"
|
class="btn-create-run"
|
||||||
hx-post="/api/autotask/create"
|
hx-post="/api/autotask/create"
|
||||||
|
hx-ext="json-enc"
|
||||||
hx-include="#quick-intent-input"
|
hx-include="#quick-intent-input"
|
||||||
hx-target="#intent-result"
|
hx-target="#intent-result"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
|
|
@ -45,24 +46,6 @@
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
>Loading...</span
|
>Loading...</span
|
||||||
></h1>
|
></h1>
|
||||||
<button
|
|
||||||
class="btn-new-intent"
|
|
||||||
onclick="showNewIntentModal()"
|
|
||||||
title="Create new intent"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
>
|
|
||||||
<line x1="12" y1="5" x2="12" y2="19" />
|
|
||||||
<line x1="5" y1="12" x2="19" y2="12" />
|
|
||||||
</svg>
|
|
||||||
New Intent
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Status Filter Pills -->
|
<!-- Status Filter Pills -->
|
||||||
|
|
@ -542,137 +525,6 @@
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<!-- New Intent Modal -->
|
<!-- New Intent Modal -->
|
||||||
<div class="modal-overlay" id="newIntentModal">
|
|
||||||
<div class="modal">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h3>Create New Intent</h3>
|
|
||||||
<button class="modal-close" onclick="closeNewIntentModal()">
|
|
||||||
<svg
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
>
|
|
||||||
<line x1="18" y1="6" x2="6" y2="18" />
|
|
||||||
<line x1="6" y1="6" x2="18" y2="18" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form
|
|
||||||
id="newIntentForm"
|
|
||||||
hx-post="/api/tasks"
|
|
||||||
hx-ext="json-enc"
|
|
||||||
hx-target="#task-list"
|
|
||||||
hx-swap="afterbegin"
|
|
||||||
hx-on::after-request="if(event.detail.successful) { closeNewIntentModal(); htmx.trigger(document.body, 'taskCreated'); }"
|
|
||||||
>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label" for="intentTitle"
|
|
||||||
>Intent (Natural Language)</label
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="form-input"
|
|
||||||
id="intentTitle"
|
|
||||||
name="title"
|
|
||||||
placeholder="e.g., cria app de agendamento, quando IBM mudar avisa, todo dia 9h resumo..."
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<p class="form-hint">
|
|
||||||
Describe what you want: create apps, schedule tasks, monitor changes, or set goals.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label" for="intentDescription"
|
|
||||||
>Additional Details (Optional)</label
|
|
||||||
>
|
|
||||||
<textarea
|
|
||||||
class="form-input"
|
|
||||||
id="intentDescription"
|
|
||||||
name="description"
|
|
||||||
rows="3"
|
|
||||||
placeholder="Add more context: tables needed, fields, triggers, etc."
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label" for="intentDueDate"
|
|
||||||
>Due Date (Optional)</label
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="datetime-local"
|
|
||||||
class="form-input"
|
|
||||||
id="intentDueDate"
|
|
||||||
name="due_date"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label" for="intentPriority"
|
|
||||||
>Priority</label
|
|
||||||
>
|
|
||||||
<select
|
|
||||||
class="form-input"
|
|
||||||
id="intentPriority"
|
|
||||||
name="priority"
|
|
||||||
>
|
|
||||||
<option value="normal">Normal</option>
|
|
||||||
<option value="high">High</option>
|
|
||||||
<option value="urgent">Urgent</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label" for="intentType"
|
|
||||||
>Intent Type (Auto-detected)</label
|
|
||||||
>
|
|
||||||
<select
|
|
||||||
class="form-input"
|
|
||||||
id="intentType"
|
|
||||||
name="intent_type"
|
|
||||||
>
|
|
||||||
<option value="auto">Auto-detect</option>
|
|
||||||
<option value="app">📱 App - Create HTMX app</option>
|
|
||||||
<option value="table">🗃️ Table - Define new table</option>
|
|
||||||
<option value="todo">✅ Todo - Simple task</option>
|
|
||||||
<option value="goal">🎯 Goal - Autonomous goal</option>
|
|
||||||
<option value="schedule">⏰ Schedule - Recurring task</option>
|
|
||||||
<option value="monitor">👁️ Monitor - Watch for changes</option>
|
|
||||||
<option value="tool">🔧 Tool - Voice/chat command</option>
|
|
||||||
<option value="action">⚡ Action - Execute immediately</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-info-box">
|
|
||||||
<strong>🗄️ Bot Database Architecture:</strong>
|
|
||||||
<ul>
|
|
||||||
<li>All apps share the same database tables</li>
|
|
||||||
<li>Tables are defined in <code>.gbdialog/tables.bas</code></li>
|
|
||||||
<li>Schedulers, tools, and monitors are shared resources</li>
|
|
||||||
<li>Use <code>FIND x IN table</code> to query data</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
class="decision-btn decision-btn-secondary</strong>"
|
|
||||||
onclick="closeNewIntentModal()"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="decision-btn decision-btn-primary"
|
|
||||||
type="submit"
|
|
||||||
form="newIntentForm"
|
|
||||||
>
|
|
||||||
Create Intent
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Edit Tables Modal -->
|
<!-- Edit Tables Modal -->
|
||||||
<div class="modal-overlay" id="editTablesModal">
|
<div class="modal-overlay" id="editTablesModal">
|
||||||
<div class="modal modal-large">
|
<div class="modal modal-large">
|
||||||
|
|
@ -731,17 +583,6 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
// New Intent Modal functions
|
|
||||||
function showNewIntentModal() {
|
|
||||||
document.getElementById("newIntentModal").classList.add("show");
|
|
||||||
document.getElementById("intentTitle").focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeNewIntentModal() {
|
|
||||||
document.getElementById("newIntentModal").classList.remove("show");
|
|
||||||
document.getElementById("newIntentForm").reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Edit Tables Modal functions
|
// Edit Tables Modal functions
|
||||||
function showEditTablesModal() {
|
function showEditTablesModal() {
|
||||||
document.getElementById("editTablesModal").classList.add("show");
|
document.getElementById("editTablesModal").classList.add("show");
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue