feat: implement elegant slide-in floating control panel for edit mode

Replaced the intrusive blue status bar with a sleek slide-in control panel:

UI/UX Improvements:
- Minimized ribbon (📝 icon) on top-right that slides out to full panel
- Beautiful gradient design with backdrop blur effects
- Smooth CSS transitions with cubic-bezier easing
- Auto-expand on load, then minimize after 2 seconds
- Click outside to close, click ribbon to toggle

Features Combined:
- Status indicators with dynamic icons ( loading,  success,  error)
- Save & Download and Preview buttons in clean grid layout
- Version information in panel header
- Error reporting with expandable details
- Responsive design for mobile devices

Technical Changes:
- Replaced old floating-header with integrated control panel
- Enhanced status update function with visual state management
- Added toggle functionality with click-outside-to-close
- Improved typography and spacing throughout
- Updated test to match new element ID structure

This provides a much cleaner editing experience with better space utilization
while maintaining all previous functionality and adding visual polish.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-25 20:55:45 +02:00
parent 6df6430b72
commit ce7ce0470f
2 changed files with 323 additions and 39 deletions

View File

@@ -396,35 +396,245 @@ class DocumentManager:
body_classes = ' class="markitect-edit-mode"'
editor_css = """
<style>
.markitect-floating-header {
/* Floating Control Panel - Slide-in from right */
.markitect-control-panel {
position: fixed;
top: 0;
left: 0;
right: 0;
background: rgba(255, 255, 255, 0.95);
border-bottom: 1px solid #ddd;
padding: 10px;
top: 20px;
right: -320px;
width: 320px;
background: rgba(255, 255, 255, 0.98);
border: 1px solid #e0e0e0;
border-radius: 12px 0 0 12px;
box-shadow: -4px 0 20px rgba(0, 0, 0, 0.15);
z-index: 1000;
backdrop-filter: blur(5px);
backdrop-filter: blur(10px);
transition: right 0.3s cubic-bezier(0.4, 0, 0.2, 1);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
.markitect-control-panel.expanded {
right: 0;
}
/* Control ribbon - always visible */
.markitect-control-ribbon {
position: absolute;
left: -40px;
top: 0;
width: 40px;
height: 100%;
background: linear-gradient(135deg, #2196f3, #1976d2);
border-radius: 8px 0 0 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 18px;
transition: all 0.3s ease;
}
.markitect-control-ribbon:hover {
background: linear-gradient(135deg, #1976d2, #1565c0);
transform: translateX(-2px);
}
/* Panel content */
.markitect-panel-header {
background: linear-gradient(135deg, #2196f3, #1976d2);
color: white;
padding: 16px 20px;
border-radius: 12px 0 0 0;
position: relative;
}
.markitect-panel-title {
font-weight: 600;
font-size: 16px;
margin: 0 0 4px 0;
}
.markitect-panel-version {
font-size: 12px;
opacity: 0.9;
margin: 0;
}
.markitect-panel-close {
position: absolute;
top: 12px;
right: 16px;
background: none;
border: none;
color: white;
cursor: pointer;
font-size: 20px;
padding: 4px;
border-radius: 4px;
transition: background 0.2s;
}
.markitect-panel-close:hover {
background: rgba(255, 255, 255, 0.2);
}
.markitect-panel-body {
padding: 20px;
}
.markitect-status-section {
margin-bottom: 20px;
}
.markitect-status-indicator {
display: flex;
align-items: center;
padding: 12px;
background: #f8f9fa;
border-radius: 8px;
margin-bottom: 12px;
border-left: 4px solid #4caf50;
}
.markitect-status-indicator.loading {
border-left-color: #ff9800;
}
.markitect-status-indicator.error {
border-left-color: #f44336;
background: #ffebee;
}
.markitect-status-icon {
margin-right: 8px;
font-size: 16px;
}
.markitect-status-text {
flex: 1;
font-size: 14px;
margin: 0;
}
.markitect-controls-section {
border-top: 1px solid #e0e0e0;
padding-top: 20px;
}
.markitect-controls-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 16px;
}
.markitect-control-btn {
display: flex;
align-items: center;
justify-content: center;
padding: 12px 16px;
background: #2196f3;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
text-decoration: none;
}
.markitect-control-btn:hover {
background: #1976d2;
transform: translateY(-1px);
}
.markitect-control-btn.secondary {
background: #757575;
}
.markitect-control-btn.secondary:hover {
background: #616161;
}
.markitect-control-btn .icon {
margin-right: 6px;
}
.markitect-save-info {
font-size: 12px;
color: #666;
background: #f5f5f5;
padding: 8px 12px;
border-radius: 6px;
margin-top: 10px;
}
.markitect-error-details {
display: none;
background: #ffebee;
border: 1px solid #f44336;
border-radius: 8px;
padding: 12px;
margin-top: 12px;
}
.markitect-error-title {
font-weight: bold;
color: #c62828;
margin: 0 0 8px 0;
}
.markitect-error-text {
color: #666;
font-size: 14px;
margin: 0 0 8px 0;
}
.markitect-error-help {
font-size: 12px;
color: #666;
}
/* Content editing styles */
.markitect-section-editable {
border: 1px dashed transparent;
padding: 8px;
margin: 4px 0;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
}
.markitect-section-editable:hover {
border-color: #007acc;
background: rgba(0, 122, 204, 0.05);
}
.edit-mode textarea {
width: 100%;
min-height: 100px;
font-family: monospace;
font-family: 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', monospace;
border: 2px solid #007acc;
border-radius: 4px;
padding: 8px;
border-radius: 6px;
padding: 12px;
font-size: 14px;
line-height: 1.5;
resize: vertical;
}
.edit-mode textarea:focus {
outline: none;
border-color: #1976d2;
box-shadow: 0 0 0 3px rgba(25, 118, 210, 0.1);
}
/* Responsive adjustments */
@media (max-width: 768px) {
.markitect-control-panel {
width: 280px;
right: -280px;
}
}
</style>"""
@@ -445,19 +655,19 @@ class DocumentManager:
}
initializeEditor() {
const header = document.createElement('div');
header.className = 'markitect-floating-header';
header.innerHTML = `
<button onclick="markitectEditor.save()" title="Download edited file with timestamp">💾 Save & Download</button>
<button onclick="markitectEditor.togglePreview()" title="Toggle preview mode">👁️ Preview</button>
<span id="save-status" style="margin-left: 15px; font-size: 0.9em;">Ready</span>
<span style="margin-left: 15px; font-size: 0.8em; color: #666;">
Saves as: filename-edited-YYYY-MM-DD-HH-MM-SS.md
</span>
`;
document.body.insertBefore(header, document.body.firstChild);
// Control panel is already in HTML, just make content editable
this.makeContentEditable();
// Auto-expand control panel briefly to show it's available
setTimeout(() => {
const panel = document.getElementById('markitect-control-panel');
if (panel) {
panel.classList.add('expanded');
setTimeout(() => {
panel.classList.remove('expanded');
}, 2000); // Show for 2 seconds then minimize
}
}, 1000);
}
makeContentEditable() {
@@ -613,7 +823,25 @@ class DocumentManager:
}
}
let markitectEditor;"""
let markitectEditor;
// Control panel toggle functionality
function toggleControlPanel() {
const panel = document.getElementById('markitect-control-panel');
if (panel) {
panel.classList.toggle('expanded');
}
}
// Auto-close panel when clicking outside
document.addEventListener('click', function(event) {
const panel = document.getElementById('markitect-control-panel');
if (panel && panel.classList.contains('expanded')) {
if (!panel.contains(event.target)) {
panel.classList.remove('expanded');
}
}
});"""
# Edit mode status and error reporting section
edit_mode_html = ""
@@ -692,20 +920,58 @@ class DocumentManager:
version_info = "0.3.0"
edit_mode_html = f"""
<div id="markitect-status" style="background: #e3f2fd; border-left: 4px solid #2196f3; padding: 12px; margin-bottom: 20px; font-family: monospace; font-size: 14px;">
<div style="font-weight: bold; color: #1976d2;">📝 Markitect Edit Mode <span style="font-weight: normal; color: #666;">v{version_info}</span></div>
<div id="status-message" style="margin-top: 8px;">Loading edit capabilities...</div>
<div id="error-details" style="display: none; background: #ffebee; border: 1px solid #f44336; padding: 8px; margin-top: 8px; border-radius: 4px;">
<div style="font-weight: bold; color: #c62828;">❌ Edit Mode Failed</div>
<div id="error-text" style="margin-top: 4px; color: #666;"></div>
<details style="margin-top: 8px;">
<summary style="cursor: pointer; color: #1976d2;">🐛 Help us fix this issue</summary>
<div style="margin-top: 8px; font-size: 12px; color: #666;">
Please report this error with your browser info:
<br>📋 Browser: <span id="browser-info"></span>
<br>🔗 Create issue: <a href="https://github.com/anthropics/markitect/issues/new" target="_blank" style="color: #1976d2;">GitHub Issues</a>
<!-- Floating Control Panel -->
<div id="markitect-control-panel" class="markitect-control-panel">
<!-- Control Ribbon - Always Visible -->
<div class="markitect-control-ribbon" onclick="toggleControlPanel()" title="MarkiTect Editor Controls">
📝
</div>
<!-- Panel Header -->
<div class="markitect-panel-header">
<h3 class="markitect-panel-title">📝 MarkiTect Editor</h3>
<p class="markitect-panel-version">v{version_info}</p>
<button class="markitect-panel-close" onclick="toggleControlPanel()" title="Close panel">×</button>
</div>
<!-- Panel Body -->
<div class="markitect-panel-body">
<!-- Status Section -->
<div class="markitect-status-section">
<div id="status-indicator" class="markitect-status-indicator loading">
<span class="markitect-status-icon">⏳</span>
<div class="markitect-status-text" id="status-message">Loading edit capabilities...</div>
</div>
</details>
<!-- Error Details (hidden by default) -->
<div id="error-details" class="markitect-error-details">
<div class="markitect-error-title">❌ Edit Mode Failed</div>
<div class="markitect-error-text" id="error-text"></div>
<div class="markitect-error-help">
📋 Browser: <span id="browser-info"></span><br>
🔗 <a href="https://github.com/anthropics/markitect/issues/new" target="_blank" style="color: #1976d2;">Report Issue</a>
</div>
</div>
</div>
<!-- Controls Section -->
<div class="markitect-controls-section">
<div class="markitect-controls-grid">
<button class="markitect-control-btn" onclick="markitectEditor.save()" title="Download edited content">
<span class="icon">💾</span>
Save & Download
</button>
<button class="markitect-control-btn secondary" onclick="markitectEditor.togglePreview()" title="Toggle preview mode">
<span class="icon">👁️</span>
Preview
</button>
</div>
<div class="markitect-save-info">
<div id="save-status">Ready to save</div>
<div style="margin-top: 4px; opacity: 0.8;">Saves as: filename-edited-YYYY-MM-DD-HH-MM-SS.md</div>
</div>
</div>
</div>
</div>"""
@@ -786,9 +1052,27 @@ class DocumentManager:
// Status update utility
function updateStatus(message, isError = false) {{
const statusMsg = document.getElementById('status-message');
const statusIndicator = document.getElementById('status-indicator');
const statusIcon = document.querySelector('.markitect-status-icon');
if (statusMsg) {{
statusMsg.textContent = message;
statusMsg.style.color = isError ? '#c62828' : '#1976d2';
}}
if (statusIndicator) {{
// Remove all status classes
statusIndicator.classList.remove('loading', 'error');
if (isError) {{
statusIndicator.classList.add('error');
if (statusIcon) statusIcon.textContent = '';
}} else if (message.includes('Loading') || message.includes('Initializing')) {{
statusIndicator.classList.add('loading');
if (statusIcon) statusIcon.textContent = '';
}} else {{
// Success state
if (statusIcon) statusIcon.textContent = '';
}}
}}
}}