mirror of
https://github.com/olehomelchenko/astrolabe-nvc.git
synced 2025-12-21 21:22:23 +00:00
236 lines
9.2 KiB
HTML
236 lines
9.2 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Astrolabe - Vega-Lite Snippet Manager</title>
|
||
<link rel="stylesheet" href="src/styles.css">
|
||
|
||
<!-- Monaco Editor -->
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.47.0/min/vs/loader.js"></script>
|
||
</head>
|
||
|
||
<body>
|
||
<!-- Header -->
|
||
<div class="header">
|
||
<div class="header-left">
|
||
<span class="header-icon">🔭</span>
|
||
<span class="header-title">Astrolabe</span>
|
||
</div>
|
||
<div class="header-links">
|
||
<span class="header-link">Import</span>
|
||
<span class="header-link">Export</span>
|
||
<span class="header-link">Help</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="app-container">
|
||
<!-- Toggle Button Strip -->
|
||
<div class="toggle-strip">
|
||
<button class="toggle-btn active" id="toggle-snippets" title="Toggle Snippets Panel">
|
||
📄
|
||
</button>
|
||
<button class="toggle-btn active" id="toggle-editor" title="Toggle Editor Panel">
|
||
✏️
|
||
</button>
|
||
<button class="toggle-btn active" id="toggle-preview" title="Toggle Preview Panel">
|
||
👁️
|
||
</button>
|
||
</div>
|
||
|
||
<div class="main-panels">
|
||
<!-- Snippet Library Panel -->
|
||
<div class="panel snippet-panel" id="snippet-panel">
|
||
<div class="panel-header">
|
||
Snippets
|
||
</div>
|
||
<div class="sort-controls">
|
||
<span class="sort-label">Sort by:</span>
|
||
<button class="sort-btn active" data-sort="modified">
|
||
<span class="sort-text">Modified</span>
|
||
<span class="sort-arrow">⬇</span>
|
||
</button>
|
||
<button class="sort-btn" data-sort="created">
|
||
<span class="sort-text">Created</span>
|
||
<span class="sort-arrow">⬇</span>
|
||
</button>
|
||
<button class="sort-btn" data-sort="name">
|
||
<span class="sort-text">Name</span>
|
||
<span class="sort-arrow">⬇</span>
|
||
</button>
|
||
</div>
|
||
<div class="search-controls">
|
||
<input type="text" id="snippet-search" placeholder="Search snippets..." />
|
||
<button class="search-clear-btn" id="search-clear" title="Clear search">×</button>
|
||
</div>
|
||
<div class="panel-content">
|
||
<ul class="snippet-list">
|
||
<!-- Dynamically populated by renderSnippetList() -->
|
||
</ul>
|
||
<div class="placeholder">
|
||
Click to select a snippet
|
||
</div>
|
||
<div class="snippet-meta" id="snippet-meta" style="display: none;">
|
||
<div class="meta-header">Name</div>
|
||
<input type="text" id="snippet-name" placeholder="Snippet name..." />
|
||
|
||
<div class="meta-header">Comment</div>
|
||
<textarea id="snippet-comment" placeholder="Add a comment..." rows="3"></textarea>
|
||
|
||
<div class="meta-info">
|
||
<div class="meta-info-item">
|
||
<span class="meta-info-label">Created:</span>
|
||
<span id="snippet-created"></span>
|
||
</div>
|
||
<div class="meta-info-item">
|
||
<span class="meta-info-label">Modified:</span>
|
||
<span id="snippet-modified"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="meta-actions">
|
||
<button class="meta-btn" id="duplicate-btn">Duplicate</button>
|
||
<button class="meta-btn delete-btn" id="delete-btn">Delete</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Resize Handle 1 -->
|
||
<div class="resize-handle" id="resize-handle-1"></div>
|
||
|
||
<!-- Editor Panel -->
|
||
<div class="panel editor-panel" id="editor-panel">
|
||
<div class="panel-header">
|
||
Editor
|
||
</div>
|
||
<div class="panel-content">
|
||
<div id="monaco-editor" style="height: 100%; width: 100%;"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Resize Handle 2 -->
|
||
<div class="resize-handle" id="resize-handle-2"></div>
|
||
|
||
<!-- Preview Panel -->
|
||
<div class="panel preview-panel" id="preview-panel">
|
||
<div class="panel-header">
|
||
Preview
|
||
</div>
|
||
<div class="panel-content">
|
||
<div id="vega-preview" style="height: 100%; width: 100%; overflow: auto;"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="src/js/config.js"></script>
|
||
<script src="src/js/snippet-manager.js"></script>
|
||
<script src="src/js/panel-manager.js"></script>
|
||
<script src="src/js/editor.js"></script>
|
||
<script src="src/js/app.js"></script>
|
||
|
||
<script>
|
||
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
// Initialize snippet storage and render list
|
||
initializeSnippetsStorage();
|
||
|
||
// Initialize sort controls
|
||
initializeSortControls();
|
||
|
||
// Initialize search controls
|
||
initializeSearchControls();
|
||
|
||
renderSnippetList();
|
||
|
||
// Load saved layout
|
||
loadLayoutFromStorage();
|
||
|
||
// Initialize resize functionality
|
||
initializeResize();
|
||
|
||
// Initialize Monaco Editor
|
||
require.config({ paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.47.0/min/vs' } });
|
||
require(['vs/editor/editor.main'], async function () {
|
||
// Fetch actual Vega-Lite schema JSON for better validation
|
||
let vegaLiteSchema;
|
||
try {
|
||
const response = await fetch('https://vega.github.io/schema/vega-lite/v5.json');
|
||
vegaLiteSchema = await response.json();
|
||
} catch (error) {
|
||
vegaLiteSchema = null;
|
||
}
|
||
|
||
// Configure JSON language with actual schema
|
||
if (vegaLiteSchema) {
|
||
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
|
||
validate: true,
|
||
schemas: [{
|
||
uri: "https://vega.github.io/schema/vega-lite/v5.json",
|
||
fileMatch: ["*"], // Associate with all files
|
||
schema: vegaLiteSchema
|
||
}]
|
||
});
|
||
}
|
||
|
||
// Load Vega libraries before creating editor
|
||
await loadVegaLibraries();
|
||
|
||
// Create the editor with improved configuration
|
||
editor = monaco.editor.create(document.getElementById('monaco-editor'), {
|
||
value: JSON.stringify(sampleSpec, null, 2),
|
||
language: 'json',
|
||
theme: 'vs-light',
|
||
fontSize: 12,
|
||
minimap: { enabled: false },
|
||
scrollBeyondLastLine: false,
|
||
automaticLayout: true,
|
||
wordWrap: 'on',
|
||
formatOnPaste: true,
|
||
formatOnType: true
|
||
});
|
||
|
||
// Add debounced auto-render on editor change
|
||
editor.onDidChangeModelContent(() => {
|
||
debouncedRender();
|
||
});
|
||
|
||
// Initial render
|
||
renderVisualization();
|
||
|
||
// Initialize auto-save functionality
|
||
initializeAutoSave();
|
||
});
|
||
|
||
// Enhanced toggle functionality with memory and expansion
|
||
const toggleButtons = document.querySelectorAll('.toggle-btn');
|
||
toggleButtons.forEach(button => {
|
||
button.addEventListener('click', function () {
|
||
const panelId = this.id.replace('toggle-', ''); // Remove 'toggle-' prefix
|
||
togglePanel(panelId);
|
||
});
|
||
});
|
||
|
||
// Snippet selection is now handled by snippet-manager.js
|
||
|
||
// Header link handlers
|
||
const headerLinks = document.querySelectorAll('.header-link');
|
||
headerLinks.forEach(link => {
|
||
link.addEventListener('click', function () {
|
||
const linkText = this.textContent.trim();
|
||
switch (linkText) {
|
||
case 'Import':
|
||
case 'Export':
|
||
case 'Help':
|
||
// TODO: Implement in future phases
|
||
break;
|
||
}
|
||
});
|
||
});
|
||
});
|
||
</script>
|
||
</body>
|
||
|
||
</html> |