diff --git a/index.html b/index.html index 9fd88cc..770a67d 100644 --- a/index.html +++ b/index.html @@ -196,7 +196,7 @@
-
+
Editor
@@ -205,8 +205,16 @@ View:
- - + +
diff --git a/project-docs/alpine-migration-plan.md b/project-docs/alpine-migration-plan.md index 7ddfe9f..df2652c 100644 --- a/project-docs/alpine-migration-plan.md +++ b/project-docs/alpine-migration-plan.md @@ -104,26 +104,38 @@ Incremental migration of Astrolabe from vanilla JavaScript to Alpine.js for reac --- -## Phase 3: View Mode Toggle (Draft/Published) +## Phase 3: View Mode Toggle (Draft/Published) ✅ COMPLETE -**Status**: Planned -**Files**: `index.html`, `src/js/snippet-manager.js` +**Status**: Done +**Files**: `index.html`, `src/js/snippet-manager.js`, `src/js/app.js`, `src/js/config.js` -### What to Convert +### What Was Converted -View mode toggle buttons (Draft/Published) currently use manual class manipulation. +- View mode toggle buttons (Draft/Published) with `:class` binding and `@click` handlers +- All references to `currentViewMode` global variable now use Alpine store +- Removed vanilla event listeners from app.js +- Removed `currentViewMode` global variable from config.js ### Implementation Approach -1. Add `viewMode` property to Alpine snippets store (default: 'draft') -2. Convert button HTML to use `:class` binding and `@click` handlers -3. Update `loadSnippetIntoEditor()` to read view mode from Alpine store -4. Remove `updateViewModeUI()` function (no longer needed) +1. Added `viewMode` property to Alpine snippets store (default: 'draft') +2. Converted button HTML to use `:class` binding and `@click` handlers +3. Updated all references to `currentViewMode` to use `Alpine.store('snippets').viewMode` +4. Simplified `updateViewModeUI()` function (now only handles publish/revert button visibility) +5. Removed vanilla event listeners from app.js ### What Stays Vanilla - Editor integration logic - Publish/discard actions +- Publish/revert button visibility logic (handled by `updateViewModeUI`) + +### Key Learnings + +- Alpine store provides clean reactive state for view mode +- Toggle button active states now automatically update via Alpine `:class` binding +- All business logic references updated to use Alpine store instead of global variable +- `updateViewModeUI` simplified but still needed for publish/revert button management --- @@ -248,7 +260,7 @@ Toast notification system with auto-dismiss. 1. ✅ **Phase 1: Snippet Panel** - DONE 2. ✅ **Phase 2: Dataset Manager** - DONE -3. **Phase 3: View Mode Toggle** - Quick win +3. ✅ **Phase 3: View Mode Toggle** - DONE 4. **Phase 4: Settings Modal** - Another modal, builds confidence 5. **Phase 6: Meta Fields** - Before Chart Builder (simpler) 6. **Phase 7: Panel Toggles** - Quick win diff --git a/src/js/app.js b/src/js/app.js index 929b683..afb2251 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -367,14 +367,7 @@ document.addEventListener('DOMContentLoaded', function () { } }); - // View mode toggle buttons - document.getElementById('view-draft').addEventListener('click', () => { - switchViewMode('draft'); - }); - - document.getElementById('view-published').addEventListener('click', () => { - switchViewMode('published'); - }); + // View mode toggle buttons (now handled by Alpine.js in index.html) // Preview fit mode buttons document.getElementById('preview-fit-default').addEventListener('click', () => { @@ -481,7 +474,7 @@ const KeyboardActions = { }, publishDraft: function() { - if (currentViewMode === 'draft' && window.currentSnippetId) { + if (Alpine.store('snippets').viewMode === 'draft' && window.currentSnippetId) { publishDraft(); } }, diff --git a/src/js/config.js b/src/js/config.js index a6fc3a1..4c174f4 100644 --- a/src/js/config.js +++ b/src/js/config.js @@ -4,7 +4,6 @@ const APP_VERSION = '0.3.0'; // Global variables and configuration let editor; // Global editor instance let renderTimeout; // For debouncing -let currentViewMode = 'draft'; // Track current view mode: 'draft' or 'published' // Panel resizing variables let isResizing = false; diff --git a/src/js/snippet-manager.js b/src/js/snippet-manager.js index e17252e..e147a5c 100644 --- a/src/js/snippet-manager.js +++ b/src/js/snippet-manager.js @@ -4,7 +4,8 @@ // Business logic stays in SnippetStorage document.addEventListener('alpine:init', () => { Alpine.store('snippets', { - currentSnippetId: null + currentSnippetId: null, + viewMode: 'draft' // 'draft' or 'published' }); }); @@ -559,7 +560,7 @@ function autoSaveDraft() { if (!window.currentSnippetId || !editor) return; // Only save to draft if we're in draft mode - if (currentViewMode !== 'draft') return; + if (Alpine.store('snippets').viewMode !== 'draft') return; try { const currentSpec = JSON.parse(editor.getValue()); @@ -592,13 +593,13 @@ function debouncedAutoSave() { if (window.isUpdatingEditor) return; // If viewing published and no draft exists, create draft automatically - if (currentViewMode === 'published') { + if (Alpine.store('snippets').viewMode === 'published') { const snippet = getCurrentSnippet(); if (snippet) { const hasDraft = JSON.stringify(snippet.spec) !== JSON.stringify(snippet.draftSpec); if (!hasDraft) { // No draft exists, automatically switch to draft mode - currentViewMode = 'draft'; + Alpine.store('snippets').viewMode = 'draft'; updateViewModeUI(snippet); editor.updateOptions({ readOnly: false }); } @@ -859,7 +860,7 @@ async function extractToDataset() { SnippetStorage.saveSnippet(snippet); // Update editor with new spec - if (editor && currentViewMode === 'draft') { + if (editor && Alpine.store('snippets').viewMode === 'draft') { window.isUpdatingEditor = true; editor.setValue(JSON.stringify(snippet.draftSpec, null, 2)); window.isUpdatingEditor = false; @@ -935,7 +936,7 @@ function loadSnippetIntoEditor(snippet) { const hasDraft = JSON.stringify(snippet.spec) !== JSON.stringify(snippet.draftSpec); - if (currentViewMode === 'draft') { + if (Alpine.store('snippets').viewMode === 'draft') { editor.setValue(JSON.stringify(snippet.draftSpec, null, 2)); editor.updateOptions({ readOnly: false }); } else { @@ -954,19 +955,11 @@ function updateViewModeUI(snippet) { const publishBtn = document.getElementById('publish-btn'); const revertBtn = document.getElementById('revert-btn'); - // Update toggle button states - if (currentViewMode === 'draft') { - draftBtn.classList.add('active'); - publishedBtn.classList.remove('active'); - } else { - draftBtn.classList.remove('active'); - publishedBtn.classList.add('active'); - } - - // Show/hide and enable/disable action buttons based on mode + // Update toggle button states (now handled by Alpine :class binding) + // But we still need to update the action buttons (publish/revert) const hasDraft = JSON.stringify(snippet.spec) !== JSON.stringify(snippet.draftSpec); - if (currentViewMode === 'draft') { + if (Alpine.store('snippets').viewMode === 'draft') { // In draft mode: show both buttons, enable based on draft existence publishBtn.classList.add('visible'); revertBtn.classList.add('visible'); @@ -981,7 +974,7 @@ function updateViewModeUI(snippet) { // Switch view mode function switchViewMode(mode) { - currentViewMode = mode; + Alpine.store('snippets').viewMode = mode; const snippet = getCurrentSnippet(); if (snippet) { loadSnippetIntoEditor(snippet); @@ -1026,7 +1019,7 @@ function revertDraft() { SnippetStorage.saveSnippet(snippet); // Reload editor if in draft view - if (currentViewMode === 'draft') { + if (Alpine.store('snippets').viewMode === 'draft') { loadSnippetIntoEditor(snippet); }