feat: integrate GoatCounter analytics for event tracking across modals and snippets

This commit is contained in:
2025-10-16 22:59:54 +03:00
parent 8b056b66e7
commit e7d3669772
5 changed files with 65 additions and 0 deletions

View File

@@ -534,6 +534,11 @@
<script src="src/js/panel-manager.js"></script>
<script src="src/js/editor.js"></script>
<script src="src/js/app.js"></script>
<!-- GoatCounter Analytics -->
<script data-goatcounter="https://astrolabe.goatcounter.com/count"
data-goatcounter-settings='{"allow_local": true}'
async src="//gc.zgo.at/count.js"></script>
</body>
</html>

View File

@@ -468,6 +468,8 @@ function openHelpModal() {
const modal = document.getElementById('help-modal');
if (modal) {
modal.style.display = 'flex';
// Track event
Analytics.track('modal-help', 'Open Help modal');
}
}
@@ -483,6 +485,8 @@ function openDonateModal() {
const modal = document.getElementById('donate-modal');
if (modal) {
modal.style.display = 'flex';
// Track event
Analytics.track('modal-donate', 'Open Donate modal');
}
}

View File

@@ -210,6 +210,20 @@ const Toast = {
}
};
// Analytics utility: Track events with GoatCounter
const Analytics = {
track(eventName, title) {
// Only track if GoatCounter is loaded
if (window.goatcounter && window.goatcounter.count) {
window.goatcounter.count({
path: eventName,
title: title || eventName,
event: true,
});
}
}
};
// Shared utility: Format bytes for display
function formatBytes(bytes) {
if (bytes === null || bytes === undefined) return 'N/A';

View File

@@ -785,6 +785,9 @@ function openDatasetManager(updateURL = true) {
if (updateURL) {
URLState.update({ view: 'datasets', snippetId: null, datasetId: null });
}
// Track event
Analytics.track('modal-datasets', 'Open Dataset Manager');
}
// Close dataset manager modal
@@ -1139,6 +1142,9 @@ async function saveNewDataset() {
hideNewDatasetForm();
await renderDatasetList();
// Track event
Analytics.track('dataset-create', `Create dataset (${source})`);
} catch (error) {
errorEl.textContent = `Failed to save dataset: ${error.message}`;
}
@@ -1167,6 +1173,9 @@ async function deleteCurrentDataset() {
// Show success message
Toast.success('Dataset deleted');
// Track event
Analytics.track('dataset-delete', 'Delete dataset');
}
}
@@ -1295,6 +1304,9 @@ async function exportCurrentDataset() {
// Show success message
Toast.success(`Dataset "${dataset.name}" exported successfully`);
// Track event
Analytics.track('dataset-export', `Export dataset (${dataset.format})`);
} catch (error) {
Toast.error(`Failed to export dataset: ${error.message}`);
}
@@ -1394,6 +1406,9 @@ async function importDatasetFromFile(fileInput) {
Toast.success(`Dataset "${datasetName}" imported successfully!`);
}
// Track event
Analytics.track('dataset-import', `Import dataset (${format})`);
} catch (error) {
Toast.error(`Failed to import dataset: ${error.message}`);
} finally {

View File

@@ -835,6 +835,9 @@ function createNewSnippet() {
renderSnippetList();
selectSnippet(newSnippet.id);
// Track event
Analytics.track('snippet-create', 'Create new snippet');
return newSnippet;
}
@@ -859,6 +862,9 @@ function duplicateSnippet(snippetId) {
// Show success message
Toast.success('Snippet duplicated successfully');
// Track event
Analytics.track('snippet-duplicate', 'Duplicate snippet');
return newSnippet;
}
@@ -881,6 +887,9 @@ function createSnippetFromDataset(datasetName) {
renderSnippetList();
selectSnippet(newSnippet.id);
// Track event
Analytics.track('snippet-from-dataset', 'Create snippet from dataset');
return newSnippet;
}
@@ -992,6 +1001,9 @@ async function extractToDataset() {
// Show success message
Toast.success(`Dataset "${datasetName}" created successfully!`);
// Track event
Analytics.track('dataset-extract', 'Extract inline data to dataset');
} catch (error) {
errorEl.textContent = `Failed to create dataset: ${error.message}`;
}
@@ -1032,6 +1044,9 @@ function deleteSnippet(snippetId) {
// Show success message
Toast.success('Snippet deleted');
// Track event
Analytics.track('snippet-delete', 'Delete snippet');
return true;
}
@@ -1121,6 +1136,9 @@ function publishDraft() {
// Show success message
Toast.success('Snippet published successfully!');
// Track event
Analytics.track('snippet-publish', 'Publish draft');
}
// Revert draft to published spec
@@ -1146,6 +1164,9 @@ function revertDraft() {
// Show success message
Toast.success('Draft reverted to published version');
// Track event
Analytics.track('snippet-revert', 'Revert draft');
}
}
@@ -1212,6 +1233,9 @@ function exportSnippets() {
// Show success message
Toast.success(`Exported ${snippets.length} snippet${snippets.length !== 1 ? 's' : ''}`);
// Track event
Analytics.track('snippets-export', `Export ${snippets.length} snippets`);
}
// Normalize external snippet format to Astrolabe format
@@ -1296,6 +1320,9 @@ function importSnippets(fileInput) {
if (SnippetStorage.saveSnippets(existingSnippets)) {
Toast.success(`Successfully imported ${importedCount} snippet${importedCount !== 1 ? 's' : ''}`);
renderSnippetList();
// Track event
Analytics.track('snippets-import', `Import ${importedCount} snippets`);
}
} catch (error) {