diff --git a/package-lock.json b/package-lock.json index 020b29d..5d3b85d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "license": "UNLICENSED", "devDependencies": { "@eslint/js": "^10.0.1", - "@plausible-analytics/tracker": "^0.4.5", "@playwright/test": "^1.60.0", "@types/node": "^25.9.1", "eslint": "^10.4.1", @@ -1518,13 +1517,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@plausible-analytics/tracker": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/@plausible-analytics/tracker/-/tracker-0.4.5.tgz", - "integrity": "sha512-6BfAGejXY+YA3Cw6LYT2Zpn4hTxDtPQAawFsYUsQCOg78wIS5C4deAGXTfJffa5VleMWITv5lpJ/EYuQBl1tPA==", - "dev": true, - "license": "MIT" - }, "node_modules/@playwright/test": { "version": "1.60.0", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", diff --git a/package.json b/package.json index aefdc8c..f9c746c 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "typescript": "^6.0.3", "typescript-eslint": "^8.60.0", "vite": "^8.0.14", - "vitest": "^4.1.7", - "@plausible-analytics/tracker": "^0.4.5" + "vitest": "^4.1.7" } } diff --git a/scripts/generate-assets.mjs b/scripts/generate-assets.mjs index 282ea0c..673465f 100644 --- a/scripts/generate-assets.mjs +++ b/scripts/generate-assets.mjs @@ -10,30 +10,21 @@ const sourceDir = path.join(rootDir, 'src/pictures'); const publicPhotoDir = path.join(rootDir, 'public/static/photos'); const generatedDir = path.join(rootDir, 'src/generated'); const catalogPath = path.join(rootDir, 'src/photo-catalog.json'); -// The top width (3200) covers HiDPI/large displays: the frame is shown at up -// to ~2200 CSS px, so a retina viewer needs ~4000+ device px. Sources that are -// smaller aren't upscaled (withoutEnlargement), so we only pay for it where the -// resolution actually exists. -const widths = [480, 960, 1600, 2400, 3200]; +const widths = [480, 960, 1600, 2400]; const formats = [ { type: 'image/avif', extension: 'avif', - options: { quality: 58, effort: 4 }, + options: { quality: 45, effort: 4 }, }, - { type: 'image/webp', extension: 'webp', options: { quality: 82 } }, + { type: 'image/webp', extension: 'webp', options: { quality: 78 } }, { type: 'image/jpeg', extension: 'jpg', - options: { quality: 85, mozjpeg: true, progressive: true }, + options: { quality: 82, mozjpeg: true, progressive: true }, }, ]; -// Variant filenames are keyed by a hash so unchanged files are skipped. The key -// must cover the encoding settings too — otherwise a quality/width change keeps -// serving the stale files because their names never change. -const encodingKey = JSON.stringify({ widths, formats }); - const slugify = (value) => value .replace(/\.[^.]+$/, '') @@ -194,11 +185,7 @@ const generate = async () => { for (const entry of catalog) { const inputPath = path.join(sourceDir, entry.file); const input = await readFile(inputPath); - const hash = createHash('sha256') - .update(input) - .update(encodingKey) - .digest('hex') - .slice(0, 10); + const hash = createHash('sha256').update(input).digest('hex').slice(0, 10); const metadata = await sharp(input).rotate().metadata(); if (!metadata.width || !metadata.height) { diff --git a/src/analytics.ts b/src/analytics.ts deleted file mode 100644 index 6791a27..0000000 --- a/src/analytics.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { - init as plausibleInit, - track as plausibleTrack, - type PlausibleEventOptions, -} from '@plausible-analytics/tracker'; - -const ANALYTICS_AUTO_CAPTURE_PAGEVIEWS = true; -const ANALYTICS_DOMAIN = 'schmelczer.dev/photos'; -const ANALYTICS_ENDPOINT = 'https://stats.schmelczer.dev/status'; -const ANALYTICS_LOGGING = import.meta.env.DEV; - -let isInitialized = false; - -const track = (eventName: string, options: PlausibleEventOptions = {}) => { - try { - plausibleTrack(eventName, options); - } catch (error) { - console.warn(`Could not track analytics event "${eventName}".`, error); - } -}; - -export const initAnalytics = () => { - if (isInitialized) { - return; - } - - try { - plausibleInit({ - domain: ANALYTICS_DOMAIN, - endpoint: ANALYTICS_ENDPOINT, - autoCapturePageviews: ANALYTICS_AUTO_CAPTURE_PAGEVIEWS, - logging: ANALYTICS_LOGGING, - }); - isInitialized = true; - } catch (error) { - console.warn('Could not initialize analytics.', error); - } -}; - -export const trackPhotoView = ({ - photoId, - source, -}: { - photoId: string; - source: string; -}) => { - track('Photo View', { - props: { - photoId, - source, - }, - }); -}; diff --git a/src/index.ts b/src/index.ts index 7a7d316..8ff05be 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,8 @@ import './index.scss'; -import { initAnalytics, trackPhotoView } from './analytics'; import { PhotoGallery, requiredElement } from './photos'; document.documentElement.classList.add('js'); -initAnalytics(); - const gallery = requiredElement('#gallery', HTMLElement); const frame = requiredElement('#frame-content', HTMLElement); const toggle = requiredElement( @@ -17,5 +14,4 @@ new PhotoGallery({ gallery, frame, toggle, - onSelect: trackPhotoView, }); diff --git a/src/photos.ts b/src/photos.ts index b528c99..e29304a 100644 --- a/src/photos.ts +++ b/src/photos.ts @@ -5,13 +5,11 @@ type GalleryOptions = { readonly frame: HTMLElement; readonly toggle: HTMLButtonElement; readonly autoAdvance?: boolean; - readonly onSelect?: (info: { photoId: string; source: string }) => void; }; type SelectOptions = { readonly focusThumbnail?: boolean; readonly pause?: boolean; - readonly source?: string; }; export const requiredElement = ( @@ -120,10 +118,7 @@ export class PhotoGallery { } event.preventDefault(); - this.selectById(thumbnail.dataset.photoId, { - pause: true, - source: 'thumbnail', - }); + this.selectById(thumbnail.dataset.photoId, { pause: true }); }); this.options.gallery.addEventListener('keydown', (event) => { @@ -133,7 +128,6 @@ export class PhotoGallery { this.select(this.selectedIndex - 1, { focusThumbnail: true, pause: true, - source: 'keyboard', }); break; case 'ArrowRight': @@ -141,23 +135,17 @@ export class PhotoGallery { this.select(this.selectedIndex + 1, { focusThumbnail: true, pause: true, - source: 'keyboard', }); break; case 'Home': event.preventDefault(); - this.select(0, { - focusThumbnail: true, - pause: true, - source: 'keyboard', - }); + this.select(0, { focusThumbnail: true, pause: true }); break; case 'End': event.preventDefault(); this.select(this.thumbnails.length - 1, { focusThumbnail: true, pause: true, - source: 'keyboard', }); break; } @@ -214,15 +202,6 @@ export class PhotoGallery { if (options.pause) { this.pauseAutoAdvance(); } - - // Only user-initiated selections carry a source; auto-advance stays - // untracked so the slideshow doesn't flood analytics every few seconds. - if (options.source) { - this.options.onSelect?.({ - photoId: thumbnail.dataset.photoId ?? '', - source: options.source, - }); - } } private updateSelectedThumbnail(index: number, shouldFocus: boolean): void {