Skip to content

Commit c084a26

Browse files
committed
feat(analytics): integrate global Umami tracking and instrument site-wide events
1 parent 3b522bb commit c084a26

9 files changed

Lines changed: 52 additions & 13 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ jobs:
3636
- name: Build
3737
run: npm run build
3838
env:
39-
PUBLIC_UMAMI_SRC: https://cloud.umami.is/script.js
40-
PUBLIC_UMAMI_WEBSITE_ID: ${{ vars.PUBLIC_UMAMI_WEBSITE_ID }}
4139
PUBLIC_WEB3FORMS_ACCESS_KEY: ${{ secrets.PUBLIC_WEB3FORMS_ACCESS_KEY }}
4240
- name: Upload artifact
4341
uses: actions/upload-pages-artifact@v3

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,10 @@ Crear `.env` en la raíz (no se commitea):
110110

111111
```env
112112
PUBLIC_WEB3FORMS_ACCESS_KEY=tu-access-key-aqui
113-
# Opcional — analytics Umami
114-
PUBLIC_UMAMI_WEBSITE_ID=
115-
PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js
116113
```
117114

115+
Umami queda configurado directamente en `src/layouts/BaseLayout.astro` con el tracking code público del sitio.
116+
118117
---
119118

120119
## Despliegue

docs/arquitecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ Ver [runbook de la escena](runbooks/minigame.md).
147147
- Sitemap automático y RSS
148148
- OG image generada en build (`scripts/generate-og-image.mjs``public/og-image.webp`)
149149
- Accesibilidad: skip link, ARIA, `prefers-reduced-motion`, focus visible
150-
- Analytics opcional: Umami vía variables `PUBLIC_UMAMI_*`
150+
- Analytics: Umami global en `BaseLayout` con tracking code público hardcodeado
151151

152152
## Estándares de desarrollo
153153

docs/runbooks/deploy-github-pages.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ En GitHub: **Actions** → **Deploy to GitHub Pages** → **Run workflow**.
4646
## Variables de entorno en CI
4747

4848
- `PUBLIC_WEB3FORMS_ACCESS_KEY`: configurar como secret si se usa Web3Forms.
49-
- `PUBLIC_UMAMI_WEBSITE_ID`: configurar como variable de Actions si se usa Umami.
50-
- `PUBLIC_UMAMI_SRC`: queda definido en el workflow como `https://cloud.umami.is/script.js`; no necesita secret.
49+
- Umami ya queda configurado por defecto con `https://cloud.umami.is/script.js` y el website id del sitio; no necesita secret.
5150

5251
## Debug
5352

docs/runbooks/layouts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Responsabilidades:
1818
- `Footer` con prop `theme`
1919
- `SocialDock` (variantes `mobile` y `desktop`) — componente en `src/components/global/SocialDock.astro`
2020
- Script de scroll reveal (`src/utils/reveal.ts`)
21-
- Umami opcional si existen `PUBLIC_UMAMI_WEBSITE_ID` y `PUBLIC_UMAMI_SRC`
21+
- Umami se inyecta globalmente con `https://cloud.umami.is/script.js`, `data-website-id` y `data-domains="osbgx.dev"`
2222

2323
## Temas
2424

src/layouts/BaseLayout.astro

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ const pagePath = normalizedBasePath && Astro.url.pathname.startsWith(normalizedB
2121
? Astro.url.pathname.slice(normalizedBasePath.length) || '/'
2222
: Astro.url.pathname;
2323
const canonicalUrl = pagePath === '/' ? `${siteUrl}/` : `${siteUrl}${pagePath}`;
24+
const umamiScriptSrc = 'https://cloud.umami.is/script.js';
25+
const umamiWebsiteId = '6e3a6b76-7d7b-4d38-94f4-dfd2e65fe86e';
2426
const fullName = 'Osmar Bogarín';
2527
const jobTitle = 'Data Engineer & Consultant';
2628
const sameAs = [contactInfo.linkedin, contactInfo.github, contactInfo.instagram, contactInfo.x];
@@ -106,9 +108,35 @@ const ldGraph = JSON.stringify({ '@context': 'https://schema.org', '@graph': [ld
106108
<meta name="twitter:site" content={contactInfo.xHandle} />
107109
<meta name="twitter:creator" content={contactInfo.xHandle} />
108110
<script type="application/ld+json" set:html={ldGraph}></script>
109-
{import.meta.env.PUBLIC_UMAMI_WEBSITE_ID && import.meta.env.PUBLIC_UMAMI_SRC && (
110-
<script defer src={import.meta.env.PUBLIC_UMAMI_SRC} data-website-id={import.meta.env.PUBLIC_UMAMI_WEBSITE_ID}></script>
111-
)}
111+
<script defer src={umamiScriptSrc} data-website-id={umamiWebsiteId} data-domains="osbgx.dev"></script>
112+
<script is:inline>
113+
(() => {
114+
if (window.__osbgxAnalyticsReady) return;
115+
window.__osbgxAnalyticsReady = true;
116+
117+
window.osbgxTrack = (eventName, eventData = {}) => {
118+
const track = () => window.umami?.track?.(eventName, eventData);
119+
if (window.umami?.track) {
120+
track();
121+
return;
122+
}
123+
window.setTimeout(track, 600);
124+
};
125+
126+
let firstPageLoad = true;
127+
document.addEventListener('astro:page-load', () => {
128+
if (firstPageLoad) {
129+
firstPageLoad = false;
130+
return;
131+
}
132+
window.osbgxTrack('astro_page_view', {
133+
path: window.location.pathname,
134+
url: window.location.href,
135+
title: document.title,
136+
});
137+
});
138+
})();
139+
</script>
112140
</head>
113141
<body class="pt-16">
114142
<a href="#main-content" class="skip-link">Saltar al contenido principal</a>

src/scripts/about.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,16 @@ document.addEventListener('astro:page-load', () => {
225225
}
226226

227227
document.querySelectorAll('.dev-lore-tab').forEach(tab => {
228-
tab.addEventListener('click', () => activateDevLoreCategory(tab.dataset.category || 'all'));
228+
tab.addEventListener('click', () => {
229+
const category = tab.dataset.category || 'all';
230+
(window as any).osbgxTrack?.('about_dev_lore_filter', { category });
231+
activateDevLoreCategory(category);
232+
});
229233
});
230234
document.querySelectorAll('.dev-lore-more').forEach(btn => {
231235
btn.addEventListener('click', () => {
232236
const group = btn.closest('.dev-lore-group');
237+
(window as any).osbgxTrack?.('about_dev_lore_expand', { group: btn.dataset.group || 'lore' });
233238
group?.querySelectorAll('.dev-lore-card-extra').forEach(card => card.classList.add('is-visible'));
234239
btn.classList.add('is-hidden');
235240
discovery.codex.add(`expanded:${btn.dataset.group || 'lore'}`);
@@ -255,6 +260,7 @@ document.addEventListener('astro:page-load', () => {
255260
hotspot.addEventListener('click', () => {
256261
const item = (hotspot as HTMLElement).dataset.roomItem;
257262
const sectionId = (hotspot as HTMLElement).dataset.targetSection || hotspotReactionMap[item || ''] || 'room';
263+
(window as any).osbgxTrack?.('about_room_hotspot_click', { item: item || 'unknown', section: sectionId });
258264
sfxSelect();
259265
hotspot.classList.remove('is-active');
260266
void (hotspot as HTMLElement).offsetWidth;
@@ -313,6 +319,7 @@ document.addEventListener('astro:page-load', () => {
313319
e.preventDefault();
314320
const targetId = link.getAttribute('href')?.slice(1);
315321
if (!targetId) return;
322+
(window as any).osbgxTrack?.('about_hero_nav_click', { section: targetId });
316323
cancelGuidedTour();
317324
sfxSelect();
318325
nav.openSection(targetId, { scroll: true });
@@ -336,6 +343,7 @@ document.addEventListener('astro:page-load', () => {
336343
cancelGuidedTour();
337344
sfxSelect();
338345
const targetId = link.getAttribute('href').slice(1);
346+
(window as any).osbgxTrack?.('about_quick_nav_click', { section: targetId });
339347
const section = document.getElementById(targetId);
340348
if (section) {
341349
const trigger = section.querySelector<HTMLElement>('.accordion-trigger');
@@ -361,6 +369,7 @@ document.addEventListener('astro:page-load', () => {
361369
const mobileMapToggle = document.querySelector<HTMLElement>('[data-mobile-map-toggle]');
362370
mobileMapToggle?.addEventListener('click', () => {
363371
const open = !quickNav.classList.contains('is-mobile-open');
372+
(window as any).osbgxTrack?.('about_mobile_map_toggle', { open });
364373
quickNav.classList.toggle('is-mobile-open', open);
365374
mobileMapToggle.setAttribute('aria-expanded', open ? 'true' : 'false');
366375
mobileMapToggle.textContent = open ? 'CLOSE' : 'MAP';
@@ -381,13 +390,15 @@ document.addEventListener('astro:page-load', () => {
381390
const quietReadButton = document.querySelector<HTMLElement>('[data-quiet-read]');
382391
quietReadButton?.addEventListener('click', () => {
383392
const next = !document.body.classList.contains('quiet-read');
393+
(window as any).osbgxTrack?.('about_quiet_read_toggle', { enabled: next });
384394
setQuietRead(next);
385395
updateBubble(next ? 'Quiet Read activo. Menos ruido, misma historia.' : 'Quiet Read desactivado. Los efectos vuelven al save file.');
386396
updateAvatarStatus(next ? 'LV.23 · QUIET READ · LOW FX' : 'LV.23 · FULL FX · SAVE FILE ACTIVE');
387397
});
388398

389399
/* ── 21. Reset ── */
390400
document.getElementById('discovery-reset')?.addEventListener('click', () => {
401+
(window as any).osbgxTrack?.('about_save_reset');
391402
store.reset();
392403
try { window.localStorage.removeItem('about-mvp-v3-intro-dismissed'); } catch (_) { /* ignore */ }
393404
try { window.localStorage.removeItem(CAT_CLICKS_KEY); } catch (_) { /* ignore */ }

src/scripts/about/intro.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,14 @@ export function initIntroInteractions(options: IntroOptions) {
6565
btn.addEventListener('click', () => {
6666
const action = btn.dataset.startAction;
6767
if (action === 'fast') {
68+
(window as any).osbgxTrack?.('about_intro_fast_read');
6869
const fastPanel = document.getElementById('press-start-fast');
6970
const introActions = btn.closest('.press-start-actions');
7071
if (fastPanel) fastPanel.hidden = false;
7172
if (introActions) introActions.hidden = true;
7273
updateBubble('fast');
7374
} else {
75+
(window as any).osbgxTrack?.('about_intro_enter_profile', { action });
7476
closePressStartOverlay({ openRoom: action === 'fast-room' });
7577
}
7678
});

src/scripts/about/section-nav.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export function initSectionNav(
8686
if (indicator) indicator.textContent = isOpen ? '▼' : '▶';
8787
if (isOpen) {
8888
const sid = trigger.parentElement?.id;
89+
if (sid) (window as any).osbgxTrack?.('about_section_open', { section: sid });
8990
const wasNew = sid ? !discovery.sections.has(sid) : false;
9091
deps.sfxOpen(sid);
9192
const rect = trigger.getBoundingClientRect();
@@ -104,6 +105,7 @@ export function initSectionNav(
104105
function openSection(sectionId: string, options: { scroll?: boolean } = {}) {
105106
const section = document.getElementById(sectionId);
106107
if (!section) return;
108+
(window as any).osbgxTrack?.('about_section_navigate', { section: sectionId, scroll: Boolean(options.scroll) });
107109
const trigger = section.querySelector<HTMLElement>('.accordion-trigger');
108110
const panel = section.querySelector('.accordion-panel');
109111
if (trigger && panel && !panel.classList.contains('open')) toggle(trigger, true);

0 commit comments

Comments
 (0)