feat: url state management

This commit is contained in:
2025-10-15 17:47:21 +03:00
parent 173d8eb2b8
commit 5776f7e910
6 changed files with 228 additions and 18 deletions

View File

@@ -15,10 +15,12 @@ document.addEventListener('DOMContentLoaded', function () {
// Update storage monitor
updateStorageMonitor();
// Auto-select first snippet on page load
const firstSnippet = SnippetStorage.listSnippets()[0];
if (firstSnippet) {
selectSnippet(firstSnippet.id);
// Auto-select first snippet on page load (only if no hash in URL)
if (!window.location.hash) {
const firstSnippet = SnippetStorage.listSnippets()[0];
if (firstSnippet) {
selectSnippet(firstSnippet.id);
}
}
// Load saved layout
@@ -79,6 +81,9 @@ document.addEventListener('DOMContentLoaded', function () {
// Initialize auto-save functionality
initializeAutoSave();
// Initialize URL state management AFTER editor is ready
initializeURLStateManagement();
});
// Toggle panel buttons
@@ -194,3 +199,43 @@ document.addEventListener('DOMContentLoaded', function () {
document.getElementById('publish-btn').addEventListener('click', publishDraft);
document.getElementById('revert-btn').addEventListener('click', revertDraft);
});
// Handle URL hash changes (browser back/forward)
function handleURLStateChange() {
const state = URLState.parse();
if (state.view === 'datasets') {
// Open dataset modal
openDatasetManager(false); // Don't update URL
if (state.datasetId === 'new') {
// Show new dataset form
showNewDatasetForm(false);
} else if (state.datasetId) {
// Extract numeric ID from "dataset-123456"
const numericId = parseFloat(state.datasetId.replace('dataset-', ''));
selectDataset(numericId, false);
}
} else if (state.snippetId) {
// Close dataset modal if open
const modal = document.getElementById('dataset-modal');
if (modal && modal.style.display === 'flex') {
closeDatasetManager(false);
}
// Select snippet
const numericId = parseFloat(state.snippetId.replace('snippet-', ''));
selectSnippet(numericId, false);
}
}
// Initialize URL state management
function initializeURLStateManagement() {
// Handle hashchange event for back/forward navigation
window.addEventListener('hashchange', handleURLStateChange);
// Check if there's a hash in the URL on page load
if (window.location.hash) {
handleURLStateChange();
}
}

View File

@@ -16,6 +16,75 @@ let panelMemory = {
previewWidth: '25%'
};
// URL State Management
const URLState = {
// Parse current hash into state object
parse() {
const hash = window.location.hash.slice(1); // Remove '#'
if (!hash) return { view: 'snippets', snippetId: null, datasetId: null };
const parts = hash.split('/');
// #snippet-123456
if (hash.startsWith('snippet-')) {
return { view: 'snippets', snippetId: hash, datasetId: null };
}
// #datasets
if (parts[0] === 'datasets') {
if (parts.length === 1) {
return { view: 'datasets', snippetId: null, datasetId: null };
}
// #datasets/new
if (parts[1] === 'new') {
return { view: 'datasets', snippetId: null, datasetId: 'new' };
}
// #datasets/dataset-123456
if (parts[1].startsWith('dataset-')) {
return { view: 'datasets', snippetId: null, datasetId: parts[1] };
}
}
return { view: 'snippets', snippetId: null, datasetId: null };
},
// Update URL hash without triggering hashchange
update(state, replaceState = false) {
let hash = '';
if (state.view === 'datasets') {
if (state.datasetId === 'new') {
hash = '#datasets/new';
} else if (state.datasetId) {
// Add 'dataset-' prefix if not already present
const datasetId = typeof state.datasetId === 'string' && state.datasetId.startsWith('dataset-')
? state.datasetId
: `dataset-${state.datasetId}`;
hash = `#datasets/${datasetId}`;
} else {
hash = '#datasets';
}
} else if (state.snippetId) {
// Add 'snippet-' prefix if not already present
const snippetId = typeof state.snippetId === 'string' && state.snippetId.startsWith('snippet-')
? state.snippetId
: `snippet-${state.snippetId}`;
hash = `#${snippetId}`;
}
if (replaceState) {
window.history.replaceState(null, '', hash || '#');
} else {
window.location.hash = hash;
}
},
// Clear hash
clear() {
window.history.replaceState(null, '', window.location.pathname);
}
};
// Settings storage
const AppSettings = {
STORAGE_KEY: 'astrolabe-settings',

View File

@@ -315,7 +315,7 @@ async function renderDatasetList() {
}
// Select a dataset and show details
async function selectDataset(datasetId) {
async function selectDataset(datasetId, updateURL = true) {
const dataset = await DatasetStorage.getDataset(datasetId);
if (!dataset) return;
@@ -361,20 +361,39 @@ async function selectDataset(datasetId) {
// Store current dataset ID
window.currentDatasetId = datasetId;
// Update URL state (URLState.update will add 'dataset-' prefix)
if (updateURL) {
URLState.update({ view: 'datasets', snippetId: null, datasetId: datasetId });
}
}
// Open dataset manager modal
function openDatasetManager() {
function openDatasetManager(updateURL = true) {
const modal = document.getElementById('dataset-modal');
modal.style.display = 'flex';
renderDatasetList();
// Update URL state
if (updateURL) {
URLState.update({ view: 'datasets', snippetId: null, datasetId: null });
}
}
// Close dataset manager modal
function closeDatasetManager() {
function closeDatasetManager(updateURL = true) {
const modal = document.getElementById('dataset-modal');
modal.style.display = 'none';
window.currentDatasetId = null;
// Update URL state - restore snippet if one is selected
if (updateURL) {
if (window.currentSnippetId) {
URLState.update({ view: 'snippets', snippetId: window.currentSnippetId, datasetId: null });
} else {
URLState.clear();
}
}
}
// Auto-detect data format from pasted content
@@ -552,7 +571,7 @@ function hideDetectionConfirmation() {
}
// Show new dataset form
function showNewDatasetForm() {
function showNewDatasetForm(updateURL = true) {
document.getElementById('dataset-list-view').style.display = 'none';
document.getElementById('dataset-form-view').style.display = 'block';
document.getElementById('dataset-form-name').value = '';
@@ -563,6 +582,11 @@ function showNewDatasetForm() {
// Hide detection confirmation
hideDetectionConfirmation();
// Update URL state
if (updateURL) {
URLState.update({ view: 'datasets', snippetId: null, datasetId: 'new' });
}
// Add paste handler if not already added
if (!window.datasetListenersAdded) {
const inputEl = document.getElementById('dataset-form-input');

View File

@@ -460,7 +460,7 @@ function attachSnippetEventListeners() {
}
// Select and load a snippet into the editor
function selectSnippet(snippetId) {
function selectSnippet(snippetId, updateURL = true) {
const snippet = SnippetStorage.getSnippet(snippetId);
if (!snippet) return;
@@ -500,6 +500,11 @@ function selectSnippet(snippetId) {
// Store currently selected snippet ID globally
window.currentSnippetId = snippetId;
// Update URL state (URLState.update will add 'snippet-' prefix)
if (updateURL) {
URLState.update({ view: 'snippets', snippetId: snippetId, datasetId: null });
}
}
// Auto-save functionality