reorganize scripts

This commit is contained in:
2025-01-19 01:17:25 +02:00
parent 3015c6e39b
commit 6107c19e04
6 changed files with 304 additions and 309 deletions

149
src/SnippetManager.js Normal file
View File

@@ -0,0 +1,149 @@
export class SnippetManager {
constructor() {
this.currentSnippetId = null;
this.hasUnsavedChanges = false;
this.loadSnippets();
this.setupUI();
}
loadSnippets() {
// Try to load from localStorage
const stored = localStorage.getItem('vegaSnippets');
this.snippets = stored ? JSON.parse(stored) : defaultSnippets;
// Initialize localStorage if empty
if (!stored) {
this.saveToStorage();
}
}
saveToStorage() {
localStorage.setItem('vegaSnippets', JSON.stringify(this.snippets));
}
renderSnippetList() {
const container = document.getElementById('snippet-list');
container.innerHTML = '';
this.snippets.forEach(snippet => {
const div = document.createElement('div');
div.className = `snippet-item ${snippet.id === this.currentSnippetId ? 'active' : ''}`;
div.textContent = snippet.name;
div.onclick = () => this.loadSnippet(snippet.id);
container.appendChild(div);
});
}
loadSnippet(id) {
if (this.hasUnsavedChanges) {
if (!confirm('You have unsaved changes. Do you want to discard them?')) {
return;
}
}
const snippet = this.snippets.find(s => s.id === id);
if (snippet) {
this.currentSnippetId = id;
this.editor.setValue(JSON.stringify(snippet.content, null, 2));
this.hasUnsavedChanges = false;
this.updateSaveButton();
this.renderSnippetList();
}
}
createNewSnippet() {
const name = prompt('Enter snippet name:', 'New Snippet');
if (!name) return;
const id = 'snippet-' + Date.now();
const newSnippet = {
id,
name,
content: {
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "New visualization",
"mark": "bar"
}
};
this.snippets.push(newSnippet);
this.saveToStorage();
this.loadSnippet(id);
}
saveCurrentSnippet() {
if (!this.currentSnippetId) return;
try {
const content = JSON.parse(this.editor.getValue());
const snippetIndex = this.snippets.findIndex(s => s.id === this.currentSnippetId);
if (snippetIndex !== -1) {
this.snippets[snippetIndex].content = content;
this.saveToStorage();
this.hasUnsavedChanges = false;
this.updateSaveButton();
}
} catch (e) {
alert('Invalid JSON in editor');
}
}
updateSaveButton() {
const saveButton = document.getElementById('save-snippet');
saveButton.disabled = !this.hasUnsavedChanges;
}
setupUI() {
// New snippet button
document.getElementById('new-snippet').onclick = () => this.createNewSnippet();
// Save button
document.getElementById('save-snippet').onclick = () => this.saveCurrentSnippet();
// Initial render
this.renderSnippetList();
}
setEditor(editor) {
this.editor = editor;
// Setup change tracking and visualization update
let timeoutId = null;
editor.onDidChangeModelContent(() => {
this.hasUnsavedChanges = true;
this.updateSaveButton();
// Debounce visualization updates
if (timeoutId) clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
try {
const value = editor.getValue();
this.updateVisualization(value);
} catch (e) {
console.error('Invalid JSON:', e);
}
}, 300);
});
// Load first snippet if available
if (this.snippets.length > 0) {
this.loadSnippet(this.snippets[0].id);
}
}
async updateVisualization(spec) {
try {
const parsedSpec = typeof spec === 'string' ? JSON.parse(spec) : spec;
await vegaEmbed('#vis', parsedSpec, {
actions: true, // This adds the export/view source buttons
theme: 'light'
});
} catch (err) {
console.error('Error rendering visualization:', err);
// Optionally show error in the preview panel
document.getElementById('vis').innerHTML =
`<div style="color: red; padding: 1rem;">Error rendering visualization: ${err.message}</div>`;
}
}
}