mirror of
https://github.com/olehomelchenko/astrolabe-nvc.git
synced 2025-12-21 21:22:23 +00:00
init
This commit is contained in:
51
CLAUDE.md
Normal file
51
CLAUDE.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
Astrolabe is a lightweight, browser-based snippet manager for Vega-Lite visualizations. It's designed as a local-first application with minimal dependencies - vanilla JavaScript, no build tools, and direct CDN imports.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- **Frontend-only**: Pure HTML/CSS/JavaScript with no build process
|
||||||
|
- **Storage**: localStorage (initial), planned migration to IndexedDB for scale
|
||||||
|
- **Key Dependencies**: Monaco Editor and Vega-Embed loaded via CDN
|
||||||
|
- **Structure**: Three-panel resizable interface (snippet library, editor, preview)
|
||||||
|
|
||||||
|
## Development Commands
|
||||||
|
|
||||||
|
This project uses no build tools or package managers. Development is done by:
|
||||||
|
- Opening `index.html` directly in a browser
|
||||||
|
- Using browser dev tools for debugging
|
||||||
|
- No npm, yarn, or build commands needed
|
||||||
|
|
||||||
|
## Core Data Model
|
||||||
|
|
||||||
|
The application centers around two main entities:
|
||||||
|
- **Snippets**: `{id, name, created, modified, spec, draftSpec, comment, tags[], datasetRefs[], published}`
|
||||||
|
- **Datasets**: `{id, name, created, modified, data, format, size}`
|
||||||
|
|
||||||
|
## Development Phases
|
||||||
|
|
||||||
|
The project follows a structured 14-phase development plan (see docs/dev-plan.md):
|
||||||
|
- Phase 0: Storage architecture design
|
||||||
|
- Phase 1-4: Basic UI layout and editor integration
|
||||||
|
- Phase 5-7: Data persistence and draft/publish workflow
|
||||||
|
- Phase 8-12: Polish and advanced features
|
||||||
|
- Phase 13-14: Future enhancements (search, cloud sync)
|
||||||
|
|
||||||
|
**Current Status**: Phase 0 - Storage Architecture Design
|
||||||
|
|
||||||
|
## Key Design Principles
|
||||||
|
|
||||||
|
- **Lean**: No frameworks, no build step, minimal dependencies
|
||||||
|
- **Local-first**: All data stored in browser initially
|
||||||
|
- **Developer-friendly**: Full JSON schema support with Monaco Editor
|
||||||
|
- **Safe experimentation**: Draft/published workflow prevents data loss
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
Currently minimal:
|
||||||
|
- `docs/dev-plan.md` - Complete development roadmap
|
||||||
|
- Future: `index.html`, CSS, and JavaScript files in root
|
||||||
264
docs/dev-plan.md
Normal file
264
docs/dev-plan.md
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
# Astrolabe
|
||||||
|
|
||||||
|
**A lightweight, browser-based snippet manager for Vega-Lite visualizations**
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Astrolabe is a focused tool for managing, editing, and previewing Vega-Lite visualization specifications. Unlike full-featured visualization editors, Astrolabe emphasizes efficient snippet management with a clean, resizable three-panel interface: snippet library, Monaco editor with schema-aware autocomplete, and live preview.
|
||||||
|
|
||||||
|
## End Goals
|
||||||
|
|
||||||
|
- **Local-first**: All data stored in browser (localStorage initially, IndexedDB for scale)
|
||||||
|
- **Minimal dependencies**: Vanilla JavaScript, no build tools, direct CDN imports
|
||||||
|
- **Developer-friendly**: Full JSON schema support, syntax validation, and intellisense
|
||||||
|
- **Version-aware**: Draft/published workflow for safe experimentation
|
||||||
|
- **Dataset management**: Separate storage for datasets with reference system
|
||||||
|
- **Extensible**: Clean architecture for future cloud sync and authentication
|
||||||
|
|
||||||
|
## Core Features
|
||||||
|
|
||||||
|
- Resizable three-panel layout with show/hide toggles
|
||||||
|
- Auto-saving draft system with explicit publishing
|
||||||
|
- Snippet duplication, renaming, deletion
|
||||||
|
- Storage monitoring and size tracking
|
||||||
|
- Export/import functionality
|
||||||
|
- Dataset library and management
|
||||||
|
- (Future) Authentication and cloud synchronization
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development Roadmap
|
||||||
|
|
||||||
|
### **Phase 0: Storage Architecture Design** ✅ **COMPLETE**
|
||||||
|
**Goal**: Define data structures that accommodate full feature set
|
||||||
|
|
||||||
|
- [x] Design snippet schema: `{id, name, created, modified, spec, draftSpec, comment, tags[], datasetRefs[], meta}`
|
||||||
|
- [x] Design dataset schema: `{id, name, created, modified, data, format, rowCount, columnCount, size, columns, comment, tags, meta}`
|
||||||
|
- [x] Design settings schema: `{panelWidths[], panelVisibility[], autoSaveDelay, meta}`
|
||||||
|
- [x] Plan localStorage key structure and namespacing
|
||||||
|
- [x] Define upgrade/migration path for schema changes
|
||||||
|
- [x] Document storage architecture decisions (see storage-examples.md)
|
||||||
|
|
||||||
|
**Deliverable**: Documented data model that supports all planned features
|
||||||
|
|
||||||
|
**Key Decisions Made**:
|
||||||
|
- ID generation: `Date.now() + random numbers` for uniqueness
|
||||||
|
- Auto-naming: ISO datetime format for default snippet names
|
||||||
|
- Draft/published workflow: separate `spec` and `draftSpec` fields
|
||||||
|
- Computed metadata: automatic calculation of size, rowCount, columns for datasets
|
||||||
|
- Extensibility: `meta` field in all schemas for future enhancements
|
||||||
|
- Settings persistence: panel state and UI preferences stored locally
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 1: Static HTML Structure**
|
||||||
|
**Goal**: Basic three-panel layout with placeholder content
|
||||||
|
|
||||||
|
- [ ] Create `index.html` with basic structure
|
||||||
|
- [ ] Add minimal CSS for three-column flexbox layout
|
||||||
|
- [ ] Add placeholder divs for: snippet list, editor, preview
|
||||||
|
- [ ] Add vertical toggle button strip on far right (3 buttons)
|
||||||
|
- [ ] Test that layout renders at correct proportions
|
||||||
|
|
||||||
|
**Deliverable**: Static page with three visible sections + toggle buttons
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 2: Resizable Panels**
|
||||||
|
**Goal**: Make panels draggable to resize
|
||||||
|
|
||||||
|
- [ ] Add resize handles/dividers between panels
|
||||||
|
- [ ] Implement vanilla JS drag handlers for horizontal resizing
|
||||||
|
- [ ] Store panel widths in localStorage (restore on load)
|
||||||
|
- [ ] Implement toggle button logic to show/hide each panel
|
||||||
|
- [ ] Handle edge cases (minimum widths, hiding panels)
|
||||||
|
|
||||||
|
**Deliverable**: Fully interactive layout with resizable and toggleable panels
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 3: Monaco Editor Integration**
|
||||||
|
**Goal**: Working code editor with Vega-Lite schema
|
||||||
|
|
||||||
|
- [ ] Load Monaco Editor from CDN
|
||||||
|
- [ ] Initialize Monaco in the middle panel
|
||||||
|
- [ ] Configure JSON mode with Vega-Lite schema URL for autocomplete
|
||||||
|
- [ ] Add a test Vega-Lite spec as default content
|
||||||
|
- [ ] Verify schema validation and autocomplete works
|
||||||
|
|
||||||
|
**Deliverable**: Working editor with intellisense for Vega-Lite
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 4: Vega-Lite Rendering**
|
||||||
|
**Goal**: Live preview of visualizations
|
||||||
|
|
||||||
|
- [ ] Load Vega-Embed from CDN
|
||||||
|
- [ ] Create render function that takes spec from editor
|
||||||
|
- [ ] Add debounced auto-render on editor change
|
||||||
|
- [ ] Display rendered chart in right panel
|
||||||
|
- [ ] Handle rendering errors gracefully (show in preview panel)
|
||||||
|
|
||||||
|
**Deliverable**: Editor → live chart pipeline working with auto-refresh
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 5: Data Model + LocalStorage**
|
||||||
|
**Goal**: Persist snippets and load them on page refresh
|
||||||
|
|
||||||
|
- [ ] Implement storage wrapper using Phase 0 schema
|
||||||
|
- [ ] Create localStorage functions (save, load, list, delete)
|
||||||
|
- [ ] Initialize with a default example snippet if storage is empty
|
||||||
|
- [ ] Populate snippet list panel from localStorage
|
||||||
|
- [ ] Handle localStorage errors/quota exceeded
|
||||||
|
|
||||||
|
**Deliverable**: Snippets persist across page reloads
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 6: Snippet Selection & Basic CRUD**
|
||||||
|
**Goal**: Core snippet management
|
||||||
|
|
||||||
|
- [ ] Click snippet in list → load into editor + render
|
||||||
|
- [ ] Highlight selected snippet in list
|
||||||
|
- [ ] **Create**: "New Snippet" button → generates datetime name
|
||||||
|
- [ ] **Duplicate**: Duplicate button creates copy with timestamp suffix
|
||||||
|
- [ ] **Delete**: Delete button per snippet (with confirmation)
|
||||||
|
- [ ] **Rename**: Inline or modal rename functionality
|
||||||
|
- [ ] Auto-save draft on editor change (debounced)
|
||||||
|
- [ ] Add comment/meta text field (below snippet list or in sidebar)
|
||||||
|
|
||||||
|
**Deliverable**: Complete basic CRUD with auto-saving drafts
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 7: Draft/Published Workflow**
|
||||||
|
**Goal**: Safe experimentation without losing working versions
|
||||||
|
|
||||||
|
- [ ] Add "Published" badge/indicator to snippet list items
|
||||||
|
- [ ] Add "Publish" button in editor UI
|
||||||
|
- [ ] Toggle between viewing draft vs published version
|
||||||
|
- [ ] On publish: copy `draftSpec` → `spec`, update `published` timestamp
|
||||||
|
- [ ] Visual indicator in editor showing draft vs published state
|
||||||
|
- [ ] Option to revert draft to last published version
|
||||||
|
- [ ] Prevent accidental data loss with clear state indication
|
||||||
|
|
||||||
|
**Deliverable**: Git-like draft/staged workflow for specs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 8: Storage Monitoring**
|
||||||
|
**Goal**: Show storage usage and limits
|
||||||
|
|
||||||
|
- [ ] Calculate total localStorage usage
|
||||||
|
- [ ] Display as progress bar or text (e.g., "2.3 MB / ~5 MB")
|
||||||
|
- [ ] Show individual snippet sizes in list
|
||||||
|
- [ ] Add warning indicator when approaching 80% capacity
|
||||||
|
- [ ] Display draft vs published size differences
|
||||||
|
|
||||||
|
**Deliverable**: User can see storage consumption
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 9: Export/Import**
|
||||||
|
**Goal**: Portability and backup
|
||||||
|
|
||||||
|
- [ ] Export single snippet as JSON file (include metadata)
|
||||||
|
- [ ] Export all snippets as JSON bundle
|
||||||
|
- [ ] Import snippets from JSON (with conflict resolution)
|
||||||
|
- [ ] Drag-and-drop import
|
||||||
|
- [ ] Export published vs draft options
|
||||||
|
|
||||||
|
**Deliverable**: Full backup/restore capability
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 10: Dataset Management - Part 1**
|
||||||
|
**Goal**: Separate dataset storage infrastructure
|
||||||
|
|
||||||
|
- [ ] Implement dataset storage schema from Phase 0
|
||||||
|
- [ ] Create dataset CRUD operations
|
||||||
|
- [ ] Add dataset library panel/modal
|
||||||
|
- [ ] List all stored datasets with metadata
|
||||||
|
- [ ] Add/delete/rename datasets
|
||||||
|
- [ ] Display dataset size and row counts
|
||||||
|
|
||||||
|
**Deliverable**: Basic dataset storage separate from snippets
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 11: Dataset Management - Part 2**
|
||||||
|
**Goal**: Reference datasets from specs
|
||||||
|
|
||||||
|
- [ ] Detect inline data in Vega-Lite specs
|
||||||
|
- [ ] "Extract to dataset" feature for inline data
|
||||||
|
- [ ] Replace inline data with dataset references
|
||||||
|
- [ ] Auto-resolve dataset references when rendering
|
||||||
|
- [ ] Update snippet UI to show linked datasets
|
||||||
|
- [ ] Handle missing dataset references gracefully
|
||||||
|
|
||||||
|
**Deliverable**: Specs can reference shared datasets
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 12: Polish & UX Refinements**
|
||||||
|
**Goal**: Professional feel and usability
|
||||||
|
|
||||||
|
- [ ] Improved visual design (minimal but polished CSS)
|
||||||
|
- [ ] Keyboard shortcuts (Ctrl+S to publish, Ctrl+N for new, etc.)
|
||||||
|
- [ ] Better error messages and validation feedback
|
||||||
|
- [ ] Loading states for rendering
|
||||||
|
- [ ] Empty states (no snippets, no datasets)
|
||||||
|
- [ ] Tooltips for buttons and features
|
||||||
|
- [ ] Cross-browser testing (Chrome, Firefox, Safari)
|
||||||
|
|
||||||
|
**Deliverable**: Polished, production-ready MVP
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 13: Advanced Snippet Features**
|
||||||
|
**Goal**: Power user functionality
|
||||||
|
|
||||||
|
- [ ] Search/filter snippets by name, comment, tags
|
||||||
|
- [ ] Sort options (name, date created, modified, size)
|
||||||
|
- [ ] Basic tagging system
|
||||||
|
- [ ] Snippet templates/starter library
|
||||||
|
- [ ] Bulk operations (delete multiple, export selected)
|
||||||
|
|
||||||
|
**Deliverable**: Enhanced snippet discovery and organization
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Phase 14: Authentication & Backend** _(Future)_
|
||||||
|
**Goal**: Multi-device sync and sharing
|
||||||
|
|
||||||
|
- [ ] Design minimal backend API
|
||||||
|
- [ ] User authentication (email/password or OAuth)
|
||||||
|
- [ ] Sync localStorage ↔ cloud storage
|
||||||
|
- [ ] Conflict resolution strategy
|
||||||
|
- [ ] Share snippets via URL
|
||||||
|
- [ ] Public snippet gallery (optional)
|
||||||
|
|
||||||
|
**Deliverable**: Cloud-backed, multi-device Astrolabe
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Technical Stack
|
||||||
|
|
||||||
|
- **Frontend**: Vanilla JavaScript (ES6+), HTML5, CSS3
|
||||||
|
- **Editor**: Monaco Editor (via CDN)
|
||||||
|
- **Visualization**: Vega-Embed (includes Vega & Vega-Lite)
|
||||||
|
- **Storage**: LocalStorage → IndexedDB (when needed)
|
||||||
|
- **Backend** _(future)_: TBD (minimal REST API)
|
||||||
|
|
||||||
|
## Development Principles
|
||||||
|
|
||||||
|
- **Iterative**: Each phase produces working, testable functionality
|
||||||
|
- **Lean**: No frameworks, no build step, minimal dependencies
|
||||||
|
- **Data-first**: Storage schema designed upfront for extensibility
|
||||||
|
- **User-focused**: Auto-save, clear state, forgiving UX
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Current Phase**: Phase 1 - Static HTML Structure
|
||||||
|
**Status**: Ready to begin implementation
|
||||||
92
docs/storage-examples.md
Normal file
92
docs/storage-examples.md
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
|
||||||
|
|
||||||
|
Snippet example:
|
||||||
|
```json
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 1760200058.123123, // Date.now() + random numbers
|
||||||
|
name: "2025-10-13_14-23-45", // auto-populated
|
||||||
|
created: "2025-10-13T14:23:45.123Z",
|
||||||
|
modified: "2025-10-13T14:25:30.456Z",
|
||||||
|
|
||||||
|
spec: {
|
||||||
|
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
||||||
|
"data": {"values": [...]},
|
||||||
|
"mark": "bar",
|
||||||
|
"encoding": {
|
||||||
|
"x": {"field": "category", "type": "nominal"},
|
||||||
|
"y": {"field": "value", "type": "quantitative"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
draftSpec: {
|
||||||
|
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
||||||
|
"data": {"values": [...]},
|
||||||
|
"mark": "bar",
|
||||||
|
"encoding": {
|
||||||
|
"x": {"field": "category", "type": "nominal"},
|
||||||
|
"y": {"field": "value", "type": "quantitative"},
|
||||||
|
"color": {"field": "category", "type": "nominal"} // draft addition
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
comment: "SELECT category, SUM(value) FROM sales GROUP BY category",
|
||||||
|
tags: [],
|
||||||
|
datasetRefs: [],
|
||||||
|
meta: {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Dataset example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
// Core identity
|
||||||
|
id: 1760200058.123123, // Date.now() + random numbers
|
||||||
|
name: "sales_2024_q1", // editable
|
||||||
|
|
||||||
|
// Timestamps
|
||||||
|
created: 1760200058, // timestamp
|
||||||
|
modified: 1760304958 //timestamp,
|
||||||
|
|
||||||
|
// Data (stored as-is, format-agnostic)
|
||||||
|
data: [
|
||||||
|
{"category": "A", "value": 100},
|
||||||
|
{"category": "B", "value": 200}
|
||||||
|
],
|
||||||
|
format: "json", // "json" | "csv" | "tsv" (for future import/export)
|
||||||
|
|
||||||
|
// Computed on save
|
||||||
|
rowCount: 2,
|
||||||
|
columnCount: 2,
|
||||||
|
size: 78, // bytes: JSON.stringify(data).length
|
||||||
|
columns: ["category", "value"], // inferred from first row
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
comment: "",
|
||||||
|
tags: [],
|
||||||
|
|
||||||
|
// Extensibility
|
||||||
|
meta: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Settings example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
// UI State
|
||||||
|
panelWidths: [25, 25, 50], // % for [list, editor, preview]
|
||||||
|
panelVisibility: [true, true, true],
|
||||||
|
|
||||||
|
// App behavior (empty for MVP, but structure exists)
|
||||||
|
autoSaveDelay: 1000,
|
||||||
|
|
||||||
|
// Extensibility
|
||||||
|
meta: {}
|
||||||
|
}
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user