From 91bf399ebcbb2a73486802a11ef0b76d388a870a Mon Sep 17 00:00:00 2001 From: mkelvers Date: Tue, 26 May 2026 22:35:02 +0200 Subject: [PATCH] fix: remove inline onclick --- static/anime.ts | 23 +++++++++++++++++ static/discover.ts | 53 +++++++++++++++++++++++++++++++++++++++ static/dropdown.ts | 22 ++++++++++++++++ templates/anime.gohtml | 12 +-------- templates/browse.gohtml | 4 +-- templates/discover.gohtml | 40 +---------------------------- 6 files changed, 102 insertions(+), 52 deletions(-) diff --git a/static/anime.ts b/static/anime.ts index 4df914b..31fda8c 100644 --- a/static/anime.ts +++ b/static/anime.ts @@ -1,5 +1,28 @@ import { parseClassList } from './utils'; +const initSynopsisToggle = (): void => { + document.addEventListener('click', e => { + const target = e.target; + if (!(target instanceof Element)) return; + + const btn = target.closest('[data-synopsis-toggle]'); + if (!btn) return; + const container = document.getElementById('synopsis-container'); + if (!container) return; + + const isClamped = container.classList.contains('line-clamp-6'); + if (isClamped) { + container.classList.remove('line-clamp-6'); + btn.textContent = 'Show less'; + return; + } + container.classList.add('line-clamp-6'); + btn.textContent = 'Read more'; + }); +}; + +initSynopsisToggle(); + const setDropdownMenuState = (menu: HTMLElement, isOpen: boolean): void => { // data attributes store the class lists to add/remove const openClasses = parseClassList(menu.getAttribute('data-dropdown-open-classes')); diff --git a/static/discover.ts b/static/discover.ts index fceeb18..5ca087f 100644 --- a/static/discover.ts +++ b/static/discover.ts @@ -41,3 +41,56 @@ const initDiscoverTabs = (): void => { }; initDiscoverTabs(); + +const initSurpriseMe = (): void => { + let isFetchingRandom = false; + + const onClick = async (): Promise => { + if (isFetchingRandom) return; + + const btn = document.getElementById('surprise-btn') as HTMLButtonElement | null; + if (!btn) return; + isFetchingRandom = true; + + const spinner = document.getElementById('surprise-spinner'); + const text = document.getElementById('surprise-text'); + const icon = document.getElementById('surprise-icon'); + + btn.disabled = true; + spinner?.classList.remove('hidden'); + icon?.classList.add('hidden'); + if (text) text.textContent = 'Picking…'; + + try { + const res = await fetch(`/api/jikan/random/anime?t=${Date.now()}`, { cache: 'no-store' }); + if (!res.ok) throw new Error('Failed to fetch random anime'); + const json = (await res.json()) as unknown; + const data = (json as { data?: unknown }).data as { mal_id?: unknown } | undefined; + const malId = typeof data?.mal_id === 'number' ? data.mal_id : 0; + if (malId > 0) { + window.location.href = `/anime/${malId}`; + return; + } + throw new Error('Random anime missing mal_id'); + } catch (error) { + console.error(error); + alert('Could not pick a random anime right now. Please try again.'); + } finally { + isFetchingRandom = false; + btn.disabled = false; + spinner?.classList.add('hidden'); + icon?.classList.remove('hidden'); + if (text) text.textContent = 'Surprise Me'; + } + }; + + document.addEventListener('click', e => { + const target = e.target; + if (!(target instanceof Element)) return; + const surprise = target.closest('[data-surprise-me]'); + if (!surprise) return; + void onClick(); + }); +}; + +initSurpriseMe(); diff --git a/static/dropdown.ts b/static/dropdown.ts index c932c2c..c4b496e 100644 --- a/static/dropdown.ts +++ b/static/dropdown.ts @@ -64,3 +64,25 @@ class UIDropdown extends HTMLElement { } customElements.define('ui-dropdown', UIDropdown); + +const initStudioDropdown = (): void => { + document.addEventListener('click', e => { + const target = e.target; + if (!(target instanceof Element)) return; + + const btn = target.closest('button[data-studio-select]'); + if (!btn) return; + + const input = document.getElementById('studio-input') as HTMLInputElement | null; + const form = document.getElementById('browse-search-form') as HTMLFormElement | null; + if (!input || !form) return; + + input.value = btn.dataset.studioSelect ?? ''; + form.requestSubmit(); + + const dropdown = btn.closest('ui-dropdown') as { close?: () => void } | null; + dropdown?.close?.(); + }); +}; + +initStudioDropdown(); diff --git a/templates/anime.gohtml b/templates/anime.gohtml index 04bd87f..3123da3 100644 --- a/templates/anime.gohtml +++ b/templates/anime.gohtml @@ -147,17 +147,7 @@

Synopsis

{{if $anime.Synopsis}}{{$anime.Synopsis}}{{else}}No synopsis available.{{end}}

{{if and $anime.Synopsis (gt (len $anime.Synopsis) 400)}} - {{end}} diff --git a/templates/browse.gohtml b/templates/browse.gohtml index 8e7e59b..2fcc5e1 100644 --- a/templates/browse.gohtml +++ b/templates/browse.gohtml @@ -47,12 +47,12 @@ {{define "studio_dropdown_items"}} {{if eq .Page 1}} - {{end}} {{range .StudioItems}} - {{end}} diff --git a/templates/discover.gohtml b/templates/discover.gohtml index 2058825..569eec7 100644 --- a/templates/discover.gohtml +++ b/templates/discover.gohtml @@ -1,43 +1,5 @@ {{define "title"}}Discover{{end}} {{define "content"}} - -
@@ -49,8 +11,8 @@